汇编语言如何运作?

时间:2013-11-25 10:03:52

标签: c assembly x86 gdb disassembly

我正在学习装配,我有这个汇编代码并且很难理解它可以让某人澄清它吗?

Dump of assembler code for function main:
0x080483ed <+0>:    push   ebp
0x080483ee <+1>:    mov    ebp,esp
0x080483f0 <+3>:    sub    esp,0x10
0x080483f3 <+6>:    mov    DWORD PTR [ebp-0x8],0x0
0x080483fa <+13>:   mov    eax,DWORD PTR [ebp-0x8]
0x080483fd <+16>:   add    eax,0x1
0x08048400 <+19>:   mov    DWORD PTR [ebp-0x4],eax
0x08048403 <+22>:   leave  
0x08048404 <+23>:   ret

到目前为止,我理解的知识如下:

ebp注册表中推送一些内容(不知道是什么)。然后将esp注册的内容移到ebp(我认为ebp的数据应该被覆盖),然后从esp中减去10并将其存储在{{1}中(该函数将占用10个字节,此reg从未再次使用,因此无需执行此操作)。现在将值0分配给指向小于esp的8个字节的地址。

现在将该地址存储到注册ebp中。现在将eax指向的值加1(前一个值丢失)。现在将eax值存储在eax上,然后留到[ebp-0x4]的返回地址。

以下是上述程序的C代码:

main

现在,有人可以弄清楚我是否错了,而且我也不理解int main(){ int x=0; int y = x+1; } at&lt; + 13&gt;它会为地址mov添加1,但这是ebp-0x8的地址,因此,int x不再包含0.我错在哪里?

2 个答案:

答案 0 :(得分:13)

首先,push ebp然后mov ebp, esp是在程序开始时常见的两条指令。 ESP寄存器是堆栈顶部的指示器 - 因此随着堆栈的增长或收缩而不断变化。 EBP在这里是一个帮助注册。首先,我们在堆栈上推送ebp的内容。然后我们将ESP(当前堆栈顶部地址)复制到ebp - 这就是为什么当我们引用堆栈上的其他项目时,我们使用ebp的常量值(而不是更改esp之一)。

 sub esp, 0x10 ; means we reserve 16 bytes on the stack (0x10 is 16 in hex) 

现在真正有趣:

 mov    DWORD PTR [ebp-0x8],0x0 ; remember ebp was showing on the stack
                                ; top BEFORE reserving 16 bytes.
                                ; DWORD PTR means Double-word property which is 32 bits.
                                ; so the whole instruction means
                                ; "move 0 to the 32 bits of the stack in a place which 
                                ; starts with the adress ebp-8.
                                ; this is our`int x = 0`

 mov    eax,DWORD PTR [ebp-0x8] ; send x to EAX register.
 add    eax,0x1`                ; add 1 to the eax register
 mov    DWORD PTR [ebp-0x4],eax ; send the result (which is in eax) to the stack adress
                                ; [ebp-4]
 leave                          ; Cleanup stack (reverse the "mov ebp, esp" from above).
 ret                            ; let's say this instruction returns to the program, (it's slightly more
                                ; complicated than that)

希望这有帮助! :)

答案 1 :(得分:5)

0x080483ed <+0>:    push   ebp
0x080483ee <+1>:    mov    ebp,esp

设置堆栈框架。保存旧的基指针并将堆栈的顶部设置为新的基指针。这允许相对于ebp(基指针)引用此函数中的局部变量和参数。这样做的好处是它的值是稳定的,不像esp受push es和pop s的影响。

0x080483f0 <+3>:    sub    esp,0x10

在x86平台上,堆栈“向下”增长。一般来说,这意味着esp的值(内存中的地址)低于ebp。当ebp == esp堆栈没有为局部变量保留任何内存时。这并不意味着它是“空的” - 例如,堆栈的常见用法是[ebp+0x8]。在这种情况下,代码在堆栈上查找之前在调用之前推送的内容(这可能是stdcall约定中的参数)。

在这种情况下,堆栈扩展了16个字节。在这种情况下,保留的空间超出alignment目的所需的空间:

0x080483f3 <+6>:    mov    DWORD PTR [ebp-0x8],0x0

[ebp-0x8]处的4个字节初始化为值0.这是您的x局部变量。

0x080483fa <+13>:   mov    eax,DWORD PTR [ebp-0x8]

[ebp-0x8]处的4个字节被移动到寄存器。算术操作码不能与两个存储器操作数一起操作。在执行算术之前,需要先将数据移动到寄存器。 eax现在保留了x变量的值。

0x080483fd <+16>:   add    eax,0x1

eax的值增加,因此它现在保持值x + 1

0x08048400 <+19>:   mov    DWORD PTR [ebp-0x4],eax

将计算出的值存储在堆栈中。请注意,本地变量现在是[ebp-0x4] - 这是您的y变量。

0x08048403 <+22>:   leave  

销毁堆栈帧。基本上映射到pop ebp并恢复旧的堆栈基指针。

0x08048404 <+23>:   ret 

弹出堆栈顶部,将值视为返回地址,并将程序指针(eip)设置为此值。返回地址通常在执行到此函数的call指令之后直接保存指令的地址。