我需要一些参考但是很好的参考,可能有一些很好的例子。我需要它因为我开始使用NASM汇编程序在汇编中编写代码。我有这个参考:
http://bluemaster.iu.hio.no/edu/dark/lin-asm/syscalls.html
这是非常好用的,但它有很多限制,因为它没有解释其他寄存器中的字段。例如,如果我使用写入系统调用,我知道我应该在EAX寄存器中放置1,并且ECX可能是指向字符串的指针,但是EBX和EDX呢?我想要解释一下,EBX确定输入(stdin为0,其他为1等),EDX是要输入的字符串的长度等等。我希望你理解我想要的东西,我找不到任何这样的材料,所以这就是我在这里写的原因。 提前谢谢。
答案 0 :(得分:10)
Linux中的标准编程语言是C.因此,系统调用的最佳描述将它们显示为要调用的C函数。鉴于它们作为C函数的描述以及如何将它们映射到汇编中的实际系统调用的知识,您将能够轻松地使用任何系统调用。
首先,您需要一个对C程序员看来的所有系统调用的引用。我所知道的最好的是Linux man-pages project,特别是system calls部分。
我们以write
系统调用为例,因为它是您问题中的一个。如您所见,第一个参数是有符号整数,通常是open
系统调用返回的文件描述符。这些文件描述符也可以从父进程继承,通常发生在前三个文件描述符中(0 = stdin,1 = stdout,2 = stderr)。第二个参数是指向缓冲区的指针,第三个参数是缓冲区的大小(作为无符号整数)。最后,该函数返回一个有符号整数,即写入的字节数,或错误的负数。
现在,如何将其映射到实际的系统调用?有许多方法可以在32位x86上进行系统调用(根据您的寄存器名称,这可能是您正在使用的);请注意,它在64位x86上完全不同(确保您在32位模式下组装并链接32位可执行文件;请参阅this question以获取其他方法可能出错的示例)。 32位x86中最古老,最简单和最慢的是int $0x80
方法。
对于int $0x80
方法,您将系统调用号码放在%eax
中,参数放在%ebx
,%ecx
,%edx
,{{1按此顺序,},%esi
和%edi
。然后调用%ebp
,系统调用的返回值在int $0x80
。请注意,此返回值与引用所示的不同;该引用显示了C库将如何返回它,但系统调用在出错时返回%eax
(例如-errno
)。在这种情况下,C库会将其移至-EINVAL
并返回errno
。有关详细信息,请参阅syscalls(2)和intro(2)。
因此,在-1
示例中,您将write
系统调用号放在write
中,第一个参数(文件描述符号)在%eax
中,第二个%ebx
中的参数(指向字符串的指针),以及%ecx
中的第三个参数(字符串的长度)。系统调用将在%edx
中返回写入的字节数或否定的错误号(如果返回值介于-1和-4095之间,则它是一个否定的错误号)。
最后,您如何找到系统呼叫号码?他们可以在%eax
找到。在我的系统上,这只包含/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
类似,但在固定地址使用单个页面。不推荐使用此方法,如果您使用的是最新的内核,则会在系统日志中出现警告,可能会在更新的内核上启动时禁用,并且将来可能会被删除。不要使用它。
答案 1 :(得分:0)
如果您下载该网页(如第二段中所示)并下载内核源代码,您可以单击“源”列中的链接,然后直接转到实现系统调用的源文件。您可以阅读他们的C签名,以查看每个参数的用途。
如果您只是在寻找快速参考,那么每个系统调用都有一个C库接口,其名称相同,加上sys_
。因此,举例来说,您可以查看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