Assembly BSD堆栈清理

Assembly BSD堆栈清理,assembly,stack,calling-convention,Assembly,Stack,Calling Convention,我正在学习汇编语言,对调用约定和堆栈清理有疑问 因为我使用的是OSX,所以我需要对系统调用使用BSD调用约定,如下所示 SECTION .text push StringLen ; Push string length push MyString ; Push the string push 0x1 ; Push the file descriptor (stdout) mov eax, 4 ; Push the system call (

我正在学习汇编语言,对调用约定和堆栈清理有疑问

因为我使用的是OSX,所以我需要对系统调用使用BSD调用约定,如下所示

SECTION .text
    push StringLen ; Push string length 
    push MyString  ; Push the string
    push 0x1       ; Push the file descriptor (stdout)
    mov eax, 4     ; Push the system call (sys_write)
    int 0x80       ; Call kernel dispatcher
    add esp, 0x10  ; Clean up stack 16 bytes for 4DWORDS

    mov eax, 1
    mov ebx, 0
    int 0x80       ; System exit
我的问题是,
addesp,0x10
是否被认为是清理堆栈的良好实践?我已经做过实验,在清理之后,这些值似乎仍然在堆栈上,但是当推送另一个值时会被覆盖,例如

    add esp, 0x10  ; Clean up stack 16 bytes for 4DWORDS
    push 0x1A      ; New push overwrites the previous stack values
我相信这在一个小程序中不会造成很大的差异,但是在一个大程序中,如果它从未被覆盖,它不是浪费了空间吗

但是在一个大的系统中,如果它从未被覆盖,它不是浪费了空间吗


不,这不是浪费空间。堆栈空间的16个字节将一次又一次地被重用。

是的,这种传递参数并清除它们的方法很好。但是,代码中存在一个问题:您只有三个推送,但减去16个字节。移动到
eax
不算作推送,因为它不会更改
esp

这在这个小程序中可能无关紧要,但在任何大小合适的程序中都会崩溃。因此,修复0x10到0x0C添加一个
推eax
子esp,4
,以使其平衡并符合BSD调用约定的要求

另一种方法是预先保留堆栈空间,并使用
mov
s来设置参数,而不是
push
es

编辑:根据(额外推送)修复代码

如您所见,它避免了在函数体的大部分时间内更改
ESP
,但它使代码更大、更详细。由于不能
mov
内存对内存,因此必须使用临时寄存器来存储变量


出于某种原因,这种传递参数的方式是GCC的默认方式,会导致相当可观的代码膨胀。

那么您认为这是清理堆栈的一种好方法吗?我只是想在早期坚持好的技术。@JamesParker:这可能是最好的方法。你有没有其他你认为更优越的选择?没有,一点也没有。我只是想和一些有经验的程序员核实一下,而不是把一篇文章当作真理。谢谢你的帮助。很有趣。我在我的代码中推了EAX,但不小心把它复制错了,谢谢你指出了这一点。啊,我没有意识到BSD调用约定需要它。修正了代码。正如您所见,《FreeBSD指南》实际上也使用了推送功能,因此它完全符合犹太规范:)
SECTION .text
    ; we only need 12 bytes (3 args) but BSD ABI needs one extra stack slot
    sub esp, 0x10  
    mov  eax, StringLen
    mov  [esp-C], eax
    mov  eax, StringLen
    mov  [esp-8], eax
    mov  dword [esp-4], 0x1 ; file descriptor (stdout)
    mov  eax, 4     ; system call number (sys_write)
    int  0x80       ; make the syscall

    mov dword [esp-4], 0 ; exit code
    mov eax, 1      ; system call number (sys_exit)
    int 0x80       ; System exit

    ; unreachable in this case but necessary for returning functions
    add esp, 0x10  ; restore the stack at the end of the function