我想从汇编调用nanosleep之类的东西,只使用SVC调用,但如何使用我所拥有的有限信息来实现这一点并不明显,下面是macos系统调用签名列表:https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master
我试着弄清楚C调用nanosleep时会做什么,我可以把它简化成这样:
struct timespec { long tv_sec; long tv_nsec; };
int nanosleep(const struct timespec *__rqtp, struct timespec *__rmtp)
__asm("_" "nanosleep" );
int main() {
struct timespec remaining, request = { 3, 1 };
int response = nanosleep(&request, &remaining); }
我不确定__asm
是做什么的,因为它看起来不像汇编。无论如何,我在苹果的libc源代码中找到了nanosleep
的实现。它依赖于对clock_get_time
的调用,而这在libc中没有定义。我在XNU源代码中找到了对clock_get_time
的提及,但这是在一个.defs文件中,我不知道它是什么,它似乎也没有实现。
无论如何,是否有关于SVC调用的更好的文档,或者我可以在哪里找到libc SVC实现的程序集?
任何信息或想法都非常感谢。
1条答案
按热度按时间bqucvtff1#
首先,让我们把问题的标题去掉,从汇编调用
nanosleep
的方式如下:您只需要使用libc实现,对于大多数情况,您真的不应该深入到更深的层次,因为a)在arm 64上,操作系统强制您链接libSystem(因此链接libc),b)因为达尔文内核ABI(s)不稳定。
也就是说,让我们看看它是如何工作的引擎盖下。
在latest Libc source drop中,我们发现
nanosleep
在gen/nanosleep.c
中实际上有两种实现:一个用于#if __DARWIN_UNIX03
,使用clock_get_time
,另一个用于另一种情况,使用mach_absolute_time
和mach_wait_until
。生产中实际使用的是前者:最后得到
/usr/lib/system/libsystem_c.dylib
(由/usr/lib/libSystem.B.dylib
重新导出)。我们可以使用dlopen
/dlsym
转储字节,从dyld_shared_cache中提取dylib,或者从ramdisk中获取它来查看程序集:我不认为这是你真的想自己实现的东西。
但是不管怎样,您注意到它使用了
clock_get_time
,而clock_get_time
并没有在那个库中定义,实际上clock_get_time
在/usr/lib/system/libsystem_kernel.dylib
中:同样,这可能是您不希望自己在汇编中实现的东西。
但是这个实现是从哪里来的呢?您已经发现XNU只包含一个
.defs
文件。(Mach接口生成器)定义文件,可用于生成客户端和服务器端代码。为此,您可以使用Xcode附带的mig
实用程序(也称为open source)。对于clocks文件,调用类似于以下内容:这将生成一个
clock.h
,clockServer.c
和clockUser.c
.我们只关心最后一个,因为它包含clock_get_time
的用户级代码:(我在这里省略了
__MIG_check__Reply__clock_get_time_t
,但是它是在同一个文件中生成的,就在那个函数的上面。)这里需要注意的一点是对
mach_msg
的调用。在程序集中,我们可以看到mach_msg2_internal
被调用,但生成的代码只是调用mach_msg
。如果你按原样使用该代码,并尝试在macOS 13或iOS 16上运行它,它不会起作用。这种情况的原因与达尔文的内部安全机制以及苹果操作系统最新主要版本中的缓解措施密切相关。如果你“We“我们对不久前Luca Todesco covered that in hix Hexacon presentation背后的故事很感兴趣。但是通过将
-DKERNEL_SERVER=1
传递给mig
,我们实际上让它在文件的开头为我们生成了一个小存根:mach_msg2
也没有在公共SDK中定义(并且不是任何库中的符号),但是我们可以从XNU源代码中的osfmk/mach/message.h
一起窃取:然后通过
mach_msg2_internal
,mach_msg2_internal
在libsyscall/mach/mach_msg.c
中定义并编译为libsystem_kernel.dylib
,然后向下调用mach_msg2_trap
,最后,svc
发生在mach_msg2_trap
中:我猜你现在可以在macOS 13或iOS 16上构建自己的
nanosleep
了。不过它在之前的版本上不起作用(你必须在那里使用普通的mach_msg
),而且在这些版本上起作用的实现在macOS 13和iOS 16上也不起作用,所以你可能真的不应该这样做。调用libc实现就行了。