write
系统调用为例,因为它是您问题中的一个。正如您所看到的,第一个参数是有符号整数,通常是由open
系统调用返回的文件描述符。这些文件描述符也可能已从父进程继承而来,就像通常发生在前三个文件描述符(0=stdin,1=stdout,2=stderr)中一样。第二个参数是指向缓冲区的指针,第三个参数是缓冲区的大小(作为无符号整数)。最后,该函数返回有符号整数,即写入的字节数,或者是错误的负数。int $0x80
方法。
对于int $0x80
方法,您需要按照顺序将系统调用号放在%eax
中,并将参数放在%ebx
、%ecx
、%edx
、%esi
、%edi
和%ebp
中。然后调用int $0x80
,系统调用的返回值在%eax
中。请注意,此返回值与参考文献中所示的不同;参考文献显示C库如何返回它,但系统调用在出错时返回-errno
(例如-EINVAL
)。C库将把这个值移动到errno
并在这种情况下返回-1
。有关更多详细信息,请参见syscalls(2)和intro(2)。
write
的例子中,您需要将write
系统调用号放入%eax
中,第一个参数(文件描述符号)放入%ebx
中,第二个参数(指向字符串的指针)放入%ecx
中,第三个参数(字符串的长度)放入%edx
中。系统调用将在%eax
中返回写入的字节数或错误号的负值(如果返回值介于-1和-4095之间,则为负数的错误号)。
最后,如何找到系统调用号?它们可以在/usr/include/linux/unistd.h
中找到。在我的系统上,这只包括/usr/include/asm/unistd.h
,最终包括/usr/include/asm/unistd_32.h
,因此数字就在那里(对于write
,您可以看到__NR_write
是4
)。对于错误号也是同样的,它们来自/usr/include/linux/errno.h
(在我的系统上,经过追踪包含链,我发现第一个错误号在/usr/include/asm-generic/errno-base.h
中,其余在/usr/include/asm-generic/errno.h
中)。对于使用其他常量或结构的系统调用,它们的文档会告诉您应查找哪些头文件以找到相应的定义。
int $0x80
是最古老和最慢的方法。更新的处理器有特殊的系统调用指令,速度更快。为了使用它们,内核提供了一个虚拟动态共享对象(vDSO
;它类似于共享库,但仅在内存中),其中包含一个函数,您可以调用该函数以使用最佳的硬件可用方法进行系统调用。它还提供了一些特殊函数,可以获取当前时间,甚至无需进行系统调用,以及其他一些功能。当然,如果您不使用动态链接器,则使用起来可能会有点困难。vsyscall
,它类似于vDSO
,但使用固定地址的单个页面。这种方法已被弃用,在使用最新的内核时会在系统日志中产生警告,可以在引导时禁用,甚至可能在将来被删除。不要使用它。如果你下载了网页(就像第二段所建议的那样)和内核源代码,你可以点击“源码”列中的链接,直接转到实现系统调用的源文件。你可以阅读它们的C签名,看看每个参数是用来做什么的。
如果你只是想要快速参考,每个系统调用都有一个C库接口,名称与sys_
相同。例如,你可以查看{{link1:man 2 lseek
}}来获取关于sys_lseek
参数的信息:
off_t lseek(int fd, off_t offset, int whence);
正如您所看到的,这些参数与您的 HTML 表格中的参数匹配:
%ebx %ecx %edx
unsigned int off_t unsigned int