需要帮助了解如何使用添加esp来弹出堆栈,12

时间:2017-11-12 23:41:18

标签: assembly x86 nasm

我对这个装配程序有疑问:

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个字节"另外,是否有必要在最后弹出堆叠?

1 个答案:

答案 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中加载以前的值。在这种情况下,不需要其中一个