正确恢复被调用者保存的寄存器

Correctly restoring callee-saved registers

我试图正确理解我在哪里以及如何推送和弹出被调用者保存的寄存器,例如 ebx onto/off 堆栈以恢复它们供以后使用。

此代码是否正确恢复了 ebx 寄存器?

global main
extern printf

section .text:

print:
    mov     eax, 0x1
    add     eax, ebx

    push    eax
    push    message
    call    printf
    add     esp, 8
    ret

main:
    mov     ebx, 0x1
    push    ebx
    call    print
    pop     ebx
    ret

message db "result = %d", 10, 0       

像这样使用后直接弹出ebx吗?:

global main
extern printf

section .text:

print:
    push    ebx
    mov     ebx, 0x1
    mov     eax, 0x1
    add     eax, ebx

    push    eax
    push    message
    call    printf
    add     esp, 8
    pop     ebx
    ret
main:
    call print
    ret

message db "result = %d", 10, 0       

两种方式都可以,但第二种方式更传统一些。

规则是这样的:当编译器生成调用函数的代码时,它假定调用后ebx 的内容与调用前相同。在您的程序中,唯一适用的情况是调用 main 的启动代码。对于您的代码的两个版本,ebxmain returns 时的值与输入时的值相同,因此一切正常。

如果您的程序中有一个调用 print 的 C 函数,那么第一个版本会很糟糕,需要第二个版本。但是在第一个版本中,print 仅从您的 hand-coded main 函数调用,并且您知道 print 会破坏 ebx 而您是采取适当的措施来保存和恢复它,这样就可以了。

换句话说,在第一版代码中,print不符合标准的C调用约定。但由于您实际上从未从 C 代码中调用它,所以这不一定是个问题。在第二个版本中,它确实符合,这可能在美学上更好,并且维护起来可能不那么混乱。