【发布时间】:2017-03-14 02:21:28
【问题描述】:
我正在像这样在 OS X(32 位)上执行系统调用:
push 123
mov eax, 1
sub esp, 4
int 0x80
我不太明白sub esp, 4 的差距。
我在某处读到 BSD 及其衍生产品总是存在这种差距,但找不到原因。
我的第一个想法是堆栈对齐,但事实并非如此,因为该行随处可见,而且据我所知 OS X 需要 16 字节堆栈对齐(这里也不是这种情况) .
您知道需要执行 sub esp, 4 的背后隐藏着什么吗?或者可以指出我正确描述它的资源吗?
【问题讨论】:
-
这是因为你要调用一个函数,那是返回地址的空间。让我找到副本。
-
首先需要调用,因为该文章中给出的原因是设计决策。他们(内核开发人员)总是打算通过函数调用 int 0x80,因此他们必须考虑出现在参数之前的额外返回地址。当在汇编器中写出 CALL/RET 只是额外的噪音时,就会发生这种情况,因此汇编器开发人员将一个值(与什么值无关)压入堆栈以充当返回的占位符地址然后做
int 0x80. -
原因是为了隐藏这是一个特殊的系统调用的事实。对于应用程序来说,它应该看起来像一个普通的函数调用。此外,实现可能会酌情使用
int 0x80或syscall/sysenter。为了避免复制参数,操作系统会考虑返回地址。如果您不使用call,则必须伪造此返回地址。 -
所以换一种说法:使系统调用的 libc 包装函数更高效,因为它们可以在不复制 args 的情况下执行
int 0x80。在 Unix/Linux 系统中,像read(2)这样的系统调用实际上是围绕内核调用的库包装函数,而不是扩展为 inline-asm 的宏。