没有推动就从堆栈中弹出

时间:2011-08-24 11:54:17

标签: assembly stack

我现在正在学习高级汇编语言,并且一直在讨论堆栈的概念。我认为我理解得很好,但在实践中我有一些问题。

堆栈增长,ESP寄存器始终指向堆栈的顶部...低内存中的地址。如果某些东西被推入堆栈,那么ESP应该减少。

EBP被用作帧指针,据我所知,应该总是超过ESP。

然而,通过以下计划:

stdout.put(esp, nl);
stdout.put(ebp, nl);
push(ike);
stdout.put(esp, nl);
stdout.put(ebp, nl);
push(ike);
stdout.put(esp, nl);
stdout.put(ebp, nl);
pop(eax);
pop(eax);
pop(eax);
pop(eax);
stdout.put(esp, nl);
stdout.put(ebp, nl);

似乎并非如此。看输出:

0018FF6C 0018FF70

0018FF68 0018FF70

0018FF64 0018FF70

0018FF74 0018FF70

EBP始终相同,第一次推送时ESP减少4个字节,第二次按下则减少4个字节。

在此之后我很困惑。在我的前两次弹出后,ESP应该回到它开始的地方。如果我没有把任何东西推到堆栈上,我怎么能再做两次弹出?我突然出现了什么?

EAX的进一步弹出和打印显示一些数字,然后是0,然后是更多的数字。所以,我肯定会弹出一些东西......但是什么呢?我的程序存储器属于哪个部分,为什么没有受到影响?

为什么EBP根本不受影响?

另外,为什么ESP减少了4个字节,而不是8?

如果有人能帮助我理解这一点,我将非常感激。

2 个答案:

答案 0 :(得分:1)

EBP不会被推/弹指令修改,它是手动设置的,所以除非你自己更改它,否则它将保持不变。

IKE的推送导致4字节的更改,所以显然你在这里处于32位模式。

EAX(32位)的4个弹出将导致16字节(10h)的变化,就像它们一样。

不确定这里有什么问题。似乎按照我的预期工作?

答案 1 :(得分:0)

除了你推送和弹出的东西之外,堆栈还用于保存每个函数的堆栈帧(即局部变量),返回地址,旧ebp(特别是当前ebp所在的位置)和函数的参数。所以你弹出的是你的功能的堆栈框架 如果你反汇编一个程序,你会看到:

push    param3          ; suppose func takes 3 parameters, they're
push    param2          ; pushed in reversed order (C-style)
push    param1
call    func            ; call pushes also the return address, i.e. the
                        ; address of the instrucion after the call

...

func:
push   ebp              ; this is done for preserving the caller's stack frame
mov    ebp, esp         ; now we set up the beginning of func's stack frame
sub    esp, smth.       ; and its width, enough to fit all func's variables

此时堆栈将类似于:

        00000058:    arg3
        00000054:    arg2
        00000050:    arg1
        0000004c:    return address
 ebp -> 00000048:    caller's ebp
        ...          ...               -
        00000034:    random stuff       |  func's stack frame, random because they
        00000030:    random stuff       |  are uninitialized
 esp -> 0000002c:    random stuff      - 

最后,您只需按下4个字节,因为这是您机器的字大小,这样您就可以保存整个寄存器。一次性拍摄