看起来这是一些设置商店的代码,位于main
开始部分。
函数开始:将基础帧指针保存在堆栈上(稍后leave
指令需要用到):
0x08048414 <+0>: push ebp
现在,我们将栈指针对齐到16字节的边界,因为编译器(出于某种原因)需要这样。可能是因为它总是希望16字节对齐的帧,或者局部变量需要16字节对齐(也许有人使用了
uint128_t
,或者正在使用一个使用
gcc向量扩展的类型)。基本上,由于结果始终小于或等于当前堆栈指针,并且栈向下增长,因此只需丢弃一些字节,直到它到达16字节对齐点即可。
0x08048415 <+1>: mov ebp,esp
0x08048417 <+3>: and esp,0xfffffff0
接下来,我们从堆栈指针中减去16,创建16字节的本地变量空间。
0x0804841a <+6>: sub esp,0x10
puts((const char*)0x8048510);
0x0804841d <+9>: mov DWORD PTR [esp],0x8048510
0x08048424 <+16>: call 0x8048320 <puts@plt>
system((const char*)0x8048520);
0x08048429 <+21>: mov DWORD PTR [esp],0x8048520
0x08048430 <+28>: call 0x8048330 <system@plt>
退出函数(参见关于
leave
的
另一个答案):
0x08048435 <+33>: leave
0x08048436 <+34>: ret
“丢弃字节”的例子:假设在main
函数开始时,esp = 0x123C。代码的第一行:
0x08048414 <+0>: push ebp
0x08048415 <+1>: mov ebp,esp
结果在这个内存映射中:
0x123C: (start of stack frame of calling function)
0x1238: (old ebp value) <-- esp, ebp
然后:
0x08048417 <+3>: and esp,0xfffffff0
将ESP的最后4位强制为0,这样做的目的是:
0x123C: (start of stack frame of calling function)
0x1238: (old ebp value) <-- ebp
0x1234: (undefined)
0x1230: (undefined) <-- esp
在这个阶段,程序员无法依赖于esp
和ebp
之间有一定数量的内存可用;因此,该内存被废弃并未被使用。
最后,程序分配了16个字节的栈(局部)存储空间:
接下来,我们从堆栈指针中减去16,创建出16个字节的局部变量空间:
0x0804841a <+6>: sub esp,0x10
给我们提供了这张地图:
0x123C: (start of stack frame of calling function)
0x1238: (old ebp value) <-- ebp
0x1234: (undefined)
0x1230: (undefined)
0x123C: (undefined local space)
0x1238: (undefined local space)
0x1234: (undefined local space)
0x1230: (undefined local space) <-- esp
在这一点上,程序可以确定esp
指向16个字节的内存,并且这些内存是按16字节对齐的。