我刚开始学习装配。这是来自gdb的转储,用于打印hello ranjit的简单程序。
Dump of assembler code for function main:
0x080483b4 <+0>: push %ebp
0x080483b5 <+1>: mov %esp,%ebp
0x080483b7 <+3>: sub $0x4,%esp
=> 0x080483ba <+6>: movl $0x8048490,(%esp)
0x080483c1 <+13>: call 0x80482f0 <puts@plt>
0x080483c6 <+18>: leave
0x080483c7 <+19>: ret
我的问题是:
操作系统:ubuntu 10,编译器:gcc
答案 0 :(得分:5)
ebp
用作Intel处理器中的帧指针(假设您正在使用使用帧的调用约定)。
它提供了一个已知的参考点,用于定位传入的参数(一方面)和局部变量(另一方面),无论你在函数处于活动状态时如何处理堆栈指针。
序列:
push %ebp ; save callers frame pointer
mov %esp,%ebp ; create a new frame pointer
sub $N,%esp ; make space for locals
保存前一个堆栈帧(调用者)的帧指针,加载一个新的帧指针,然后调整堆栈以保存当前“堆栈级别”的内容。
由于在设置框架之前已经推送了参数,因此可以使用[bp+N]
访问它们,其中N
是合适的偏移量。
同样,因为本地人是在框架指针“下”创建的,所以可以使用[bp-N]
访问它们。
leave
指令是单个指令,它撤消该堆栈帧。您曾经不得不手动完成,但英特尔推出了更快的方法来完成它。它在功能上等同于:
mov %ebp, %esp ; restore the old stack pointer
pop %ebp ; and frame pointer
(旧的,手动的方式)。
如果我错过了某些内容,请逐一回答问题:
开始新框架。见上文。
事实并非如此。 esp
已复制到ebp
。这是AT&amp; T表示法(%reg
是一个死的赠品),其中(其中包括)源和目标操作数相对于英特尔表示法交换。
见上文(2)的回答。你从esp
减去4,而不是相反。
这是一个传递给0x80482f0
函数的参数。它没有加载到esp
中,而是加载到esp
指向的内存中。换句话说,它被推到了堆栈上。由于被调用的函数是puts
(见下面的(5)),它将是您想要puts
编辑的字符串的地址。
地址后<>
中的函数名称。它调用puts
函数(可能是标准库中的函数,但不保证)。有关PLT的说明,请参阅here。
我已经解释过上面的leave
在退出之前展开当前的堆栈帧。 ret
只是从当前函数返回。如果当前的功能是main
,那么它将返回到C启动代码。
答案 1 :(得分:0)
在我的职业生涯中,我学习了几种汇编语言,你没有提到它,但它看起来像Intel x86(PaxDiablo指出的分段存储模型)。但是,自上世纪以来我没有使用过装配(幸运的是我!)。以下是您的一些答案: