如果您使用默认的 GCC 选项(而不是像 Linux 内核使用的 -mregparm=3)将 C 编译成 32 位代码,那么在函数入口处,第一个参数位于返回地址上方的堆栈上(@987654322 @),但是在你 push 任何东西或移动 ESP 之后,偏移量会发生变化。
您可以在设置传统堆栈指针后使用[ebp+8](即使 ESP 会在函数期间更改)。
例如,int asm_function(int) 可以实现为:
;bits 32 ; unneeded, nasm -felf32 implies this.
global asm_function ; include asm_function in ELF .o symbol table for linking
section .text
asm_function:
push ebp
mov ebp, esp
mov eax, [ebp+8] ; return the first argument
mov esp, ebp
pop ebp
ret
对于之后的每个参数,只需简单地添加另一个4(即,对于第二个参数,使用[ebp+12])。如您所见,将 EBP 设置为帧指针会为小函数增加很多开销。
一些非 ELF 系统/ABI 在 C 符号名称前加上前导下划线,因此您应该声明 asm_function 和 _asm_function 以使您的代码在这些 ABI 中大致等效,如下所示:
global _asm_function
global asm_function ; make both names of the function global
section .text
_asm_function:
asm_function: ; make both symbols point to the same place
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov esp, ebp
pop ebp
ret