我对这个装配程序有疑问:
extern printf ; the C function, to be called
SECTION .data ; Data section, initialized variables
a: dd 5 ; int a=5;
fmt: db "a=%d, eax=%d",10,0 ; The printf format, '\n','0'
SECTION .text ; Code section.
global main ; the standard gcc entry point
main: ; the program label for the entry point
push ebp ; calling convention
mov ebp, esp
mov eax, [a] ; put a from store into register
add eax, 2 ; a+2
push eax ; value of a+2
push dword [a] ; value of variable a
push dword fmt ; address of ctrl string
call printf ; Call C function
add esp, 12 ; pop stack 3 times = 4 bytes
mov esp, ebp ; returning convention
pop ebp ; same as "leave" op
mov eax,0 ; normal (no error) return value
ret ; return
我看到它接近结束时弹出堆栈3次,等于4个字节。但是,我不明白为什么需要在最后弹出堆栈,以及12如何相当于" 3次= 4个字节"另外,是否有必要在最后弹出堆叠?
答案 0 :(得分:1)
当你调用(子)函数时,CPU需要将值保存在何处跳回;它使用了这个
的堆栈所以当你输入函数时,堆栈的最高值是返回地址
此代码将另外12个字节添加到堆栈
push eax ; value of a+2
push dword [a] ; value of variable a
push dword fmt ; address of ctrl string
这些推送中的每一个将4个字节写入[ESP],并减去ESP的4个字节(减法因为堆栈向下增长)。在你ret
回到你的被调用者之前,你必须摆脱堆栈上的这12个字节。简单的方法是,他在他的代码中做了什么:
add esp, 12 ; pop stack 3 times = 4 bytes
另一方面,该功能将EBP中的当前ESP保存在函数顶部(这会创建一个新的堆栈框架')
push ebp ; calling convention
mov ebp, esp
这样做是为了能够解析被调用者的函数参数和你可能为[EBP +/- offset]保留位置的局部变量,并且它使你能够恢复整个堆栈只需再次加载前一个值:
mov esp, ebp ; returning convention
pop ebp ; same as "leave" op
注意:在此代码中,堆栈被清理两次。 (将ESP添加12(从系统调用获取的值中清除堆栈作为参数),再次从EBP中加载以前的值。在这种情况下,不需要其中一个