【问题标题】:Assembly stack 3 functions汇编堆栈 3 个函数
【发布时间】:2016-10-07 07:48:57
【问题描述】:
aduna2:

.LFB0:
.cfi_startproc
    push    ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
    mov ebp, esp
.cfi_def_cfa_register 5
    sub esp, 16
    mov DWORD PTR [ebp-4], 10
    mov eax, DWORD PTR [ebp+12]
    mov edx, DWORD PTR [ebp+8]
    add edx, eax
    mov eax, DWORD PTR [ebp+16]
    add edx, eax
    mov eax, DWORD PTR [ebp-4]
    add eax, edx
    leave

aduna:

.LFB1:
.cfi_startproc
    push    ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
    mov ebp, esp
.cfi_def_cfa_register 5
    sub esp, 28
    mov DWORD PTR [ebp-4], 7
    mov eax, DWORD PTR [ebp-4]
    mov DWORD PTR [esp+8], eax
    mov eax, DWORD PTR [ebp+12]
    mov DWORD PTR [esp+4], eax
    mov eax, DWORD PTR [ebp+8]
    mov DWORD PTR [esp], eax
    call    aduna2
    leave

main:

.LFB2:
.cfi_startproc
    push    ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
    mov ebp, esp
.cfi_def_cfa_register 5
    and esp, -16
    sub esp, 16
    mov DWORD PTR [esp+4], 6
    mov DWORD PTR [esp], 5
    call    aduna
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:.LC0
    call    printf
    leave

我在这段代码中有以下问题:主要是我无法弄清楚当 sub esp 16 相对于 ebp 时 esp 的去向。我在“adunare”和“adunare2”中有这个问题。我无法弄清楚它相对于 ebp 的位置。我无法弄清楚为这个程序绘制一个堆栈,因为我所有的堆栈都在“adunare2”中卡住了我得到 ebp+8,ebp+12,ebp+16。给我看一个会很有帮助,因为我不明白发生了什么。并且在每次调用时都会插入一个返回地址?如果在“adunare2”中是,如何使用 +8,+12,+16 获得提到的参数?

这里是c代码:

#include<stdio.h>

int aduna2(int a,int b,int c) 
{
    int d=10;
    return a+b+c+d;
}

int aduna(int a,int b)
{
    int c=7;
    return aduna2(a,b,c);
}

int main()
{
    printf("%d\n",aduna(5,6));
}

【问题讨论】:

  • 那个反汇编看起来不完整。 (我希望retleave 之后)。你是如何得到的?这不是一些“智能”的反汇编输出吗?使用编译器列表或正常反汇编。

标签: assembly x86


【解决方案1】:

即使从不完整的反汇编来看,我想我也可以回答“在 aduna 之前,main 与 stack 有什么关系”:

main:
    ; store old ebp value into stack (to restore it before return)
    push  ebp
    mov   ebp, esp   ; copy current value of esp to ebp

此时esp和ebp的值相同,指向当前栈顶,假设是0x0054,那么(栈)内存是这样的:

address | value
-----------------
0x0050  | ????
0x0054  | old_ebp           <- esp/ebp pointing here
0x0058  | return address to "main" caller
0x005C  | whatever was already in stack before calling main

然后代码继续为“aduna”函数准备参数:

    and   esp, -16     ; -16 = 0xFFFFFFF0 -> makes esp 16B aligned
       ; esp here is 0x0050
    sub   esp, 16      ; make room at top of stack for 16B, esp = 0x0040
       ; store the arguments into the stack
    mov   DWORD PTR [esp+4], 6   ; at 0x0044 goes value 6
    mov   DWORD PTR [esp], 5     ; at 0x0040 goes value 5
    call  aduna                  ; call aduna

现在进入 aduna 后,ebp/esp 和堆栈内存如下所示:

ebp = still 0x0054, nothing did modify it
esp = 0x003C (call did pust return address at top of stack)

address | value
-----------------
0x0038  | ????
0x003C  | return address to instruction after "call aduna" <- esp
0x0040  | 5
0x0044  | 6
0x0048  | ????
0x004C  | ????
0x0050  | ????
0x0054  | old_ebp           <- ebp pointing here
0x0058  | return address to "main" caller
0x005C  | whatever was already in stack before calling main

aduna以序言代码push ebpmov ebp, esp开头,所以栈顶会有一点变化:

address | value
-----------------
0x0038  | 0x0054  <- both esp and ebp pointing here (= 0x0038)
0x003C  | return address to instruction after "call aduna"
0x0040  | 5
0x0044  | 6

所以mov eax, DWORD PTR [ebp+12] 将获取地址 0x0044 (0x38 + 0x0C = 0x44),其中存储了 6 个。ebp+8 指向值 5。esp/ebp 中的其余部分组合在 aduna 的下方,到局部变量(驻留在内存的“堆栈”部分),我不打算描述,因为一旦你理解了这个初始部分,你应该也能够破译它的其余部分。

对于leave,请查看指令集手册(它确实更改了espebp)。缺少的ret 也很重要,同时更改esp

【讨论】:

    猜你喜欢
    • 2016-03-14
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 2016-10-04
    • 2012-04-05
    • 1970-01-01
    相关资源
    最近更新 更多