我正在学习装配,我有这个汇编代码并且很难理解它可以让某人澄清它吗?
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.我错在哪里?
答案 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
指令之后直接保存指令的地址。