为什么BSD系统在执行系统调用时需要sub esp,4



我在OS X(32位)上执行一个系统调用,像这样:

push 123
mov eax, 1
sub esp, 4
int 0x80

我不太明白sub esp, 4的差距。

我在某个地方读到BSD和它的衍生产品总是有这个差距,但找不到一个解释。

我的第一个想法是堆栈对齐,但事实并非如此,因为这一行无处不在,据我所知OS X需要16字节的堆栈对齐(这也不是这里的情况)。

你知道在需要做sub esp, 4的背后隐藏着什么吗?或者你能给我指出适当描述它的资源吗?

(社区维基,因为我只是总结评论)

BSD这样做是为了使用于系统调用的libc包装函数更有效,因为它们可以只执行int 0x80而不复制参数。它为CALL推送给包装器函数的返回地址留下了空间。

在Unix/Linux系统中,像read(2)这样的系统调用实际上是围绕内核调用的库包装函数,而不是扩展为内联asm的宏。


Linux用另一种方式解决了这个问题:在寄存器中传递所有的系统调用参数。我猜这意味着32位包装器函数必须从堆栈中加载所有的参数,但至少它们不必被内核存储和重新读取。

x86-64系统调用ABI与函数调用约定更加兼容:只需要一个mov r10, rcx,因为System V函数调用约定在寄存器中传递参数(并且选择的系统调用寄存器尽可能与之匹配,除了syscall指令本身会破坏RCX和R11,因此内核无法看到原始值)

请参阅x86标签wiki,了解有关调用约定的更多信息,以及到abi的链接。

最新更新