方法调用后使用EBP指针

时间:2013-12-16 03:55:38

标签: assembly x86

我写了一个简单的代码来理解汇编代码。如下:

    int sum(int a, int b){
        int res = a+b;
    }

在main函数中,我调用了sum-function。 所以,我得到汇编代码(我只在这里采用sum函数的一部分)4

    push ebp,
    mov ebp, esp
    sub esp, 16
    mov eax, DWORD PTR[ebp + 12]
    mov edx, DWORD PTR[ebp + 8]
    add eax, edx
    mov DWORD PTR [ebp-4], eax
    mov eax, DWORD PTR [ebp-4]
    leave

现在回答我的问题。我有两个问题: 首先,有没有理由为什么sum参数的值,例如sum(5,4),在ebp + 12和ebp + 8中得分,结果在ebp-4中?为什么我们这样做?是永远相同还是随机选择?

第二,我们所拥有的部分:

    mov DWORD PTR [ebp-4], eax
    mov eax, DWORD PTR [ebp-4]

为什么我们首先在ebp-4中执行结果,然后在离开函数之前再次在eax中执行结果? 还有原因吗?

2 个答案:

答案 0 :(得分:2)

这通常是在x86系统中如何创建堆栈帧。

来电者会将此转换为...

push b
push a
call sum

当每个项目被推入堆栈时,堆栈会逐渐减少。也就是说,堆栈指针寄存器递减四(4)个字节(在32位模式下),并将该项复制到堆栈指针寄存器指向的存储单元。

此时,'call'指令已经发出,我们现在处于被调用例程的开始处。如果我们想要访问我们的参数,我们可以像

那样访问它们
[esp + 4]   - parameter 'a'
[esp + 8]   - parameter 'b'

然而,在我们为局部变量和东西划分空间之后,这可能会变得笨拙。因此,除堆栈指针寄存器外,我们还使用stackbase-pointer寄存器。但是,我们希望stackbase-pointer寄存器设置为当前帧,而不是前一个函数。因此,我们将旧的保存在堆栈上(这会修改堆栈上参数的偏移量),然后将当前堆栈指针寄存器复制到堆栈库指针寄存器。

push ebp        ; save previous stackbase-pointer register
mov  ebp, esp   ; ebp = esp

全部放在一起。使用stackbase-pointer registe

访问参数
[ebp + 12]  - parameter 'b'
[ebp + 8]   - parameter 'a'
[ebp + 4]   - return address
[ebp + 0]   - saved stackbase-pointer register

来源: What is stack frame in assembly?

答案 1 :(得分:0)

您可以通过查找以下关键字来查找此信息:

  • 调用约定
  • FASTCALL
  • STDCALL

那时,一个16位字参数将在EAX中与AX(和32位一)一起传递。回报也是AX / EAX。 64位参数(或2个参数将在EDX:EAX中)并返回相同的参数。这是一个典型的FASTCALL调用约定(我相信旧的Pascal正在使用)

现在对于C / C ++来说,fastcall通常不会被使用(可能因为它不那么便携)。大多数东西都使用了堆栈,这就是EBP的用武之地。 EBP是您的基本堆栈指针-4,-8,-12只是本地堆栈中存储和返回参数的偏移指针。

以下是一些链接: http://en.wikibooks.org/wiki/X86_Disassembly/Calling_Convention_Examples http://en.wikipedia.org/wiki/X86_calling_conventions