有人可以解释一些简单的汇编代码吗?

时间:2011-06-22 05:49:00

标签: linux assembly gdb

我刚开始学习装配。这是来自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    

我的问题是:

  1. 为什么每次在程序启动时将ebp推入堆栈?运行此程序所需的ebp是什么?
  2. 在第二行中为什么ebp被复制到esp?
  3. 我根本无法获得第三条线。我对SUB语法的了解是“sub dest,source”,但是这里如何从4减去esp并存储在4?
  4. 这个值是多少“$ 0x8048490”?为什么它被转移到esp,为什么这个时间是esp在括号中关闭?它是否表示与没有括号的esp不同的东西?
  5. 下一行是对函数的调用,但这是什么“0x80482f0”?
  6. 什么是离开和退出(也许ret意味着返回lib c。)?
  7. 操作系统:ubuntu 10,编译器:gcc

2 个答案:

答案 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

(旧的,手动的方式)。

如果我错过了某些内容,请逐一回答问题:

  1. 开始新框架。见上文。

  2. 事实并非如此。 esp已复制到ebp。这是AT&amp; T表示法(%reg是一个死的赠品),其中(其中包括)源和目标操作数相对于英特尔表示法交换。

  3. 见上文(2)的回答。你从esp减去4,而不是相反。

  4. 这是一个传递给0x80482f0函数的参数。它没有加载到esp中,而是加载到esp指向的内存中。换句话说,它被推到了堆栈上。由于被调用的函数是puts(见下面的(5)),它将是您想要puts编辑的字符串的地址。

  5. 地址后<>中的函数名称。它调用puts函数(可能是标准库中的函数,但不保证)。有关PLT的说明,请参阅here

  6. 我已经解释过上面的leave在退出之前展开当前的堆栈帧。 ret只是从当前函数返回。如果当前的功能是main,那么它将返回到C启动代码。

答案 1 :(得分:0)

在我的职业生涯中,我学习了几种汇编语言,你没有提到它,但它看起来像Intel x86(PaxDiablo指出的分段存储模型)。但是,自上世纪以来我没有使用过装配(幸运的是我!)。以下是您的一些答案:

  1. EBP寄存器在开始时被压入堆栈,因为我们在例程的其他操作中需要它。您不希望仅丢弃其原始值,从而破坏应用程序其余部分的完整性。
  2. 如果我没记错的话(我可能错了,很长一段时间)就是另一种方式,我们正在移动%esp INTO%ebp,记得我们把它保存在上一行吗?现在我们正在存储一些新的价值,而不会破坏原来的价值。
  3. 实际上他们正在从%esp寄存器的内容中提取四(4)个值。结果值不会存储在“四”上,而是存储在%esp上。如果%esp在SUB之后有0xFFF8,它将包含0xFFF4。如果我的记忆能为我服务,我认为这被称为“立即”。这里发生了什么(我估计)是计算内存地址(少4个字节)。
  4. 价值$ 0x8048490我不知道。但是,它不会被移动到INTO%esp中,而是移动到%esp内容所指向的地址中。这就是为什么符号是(%esp)而不是%esp。这是我职业生涯中出现的所有汇编语言的常用符号。另一方面,如果右操作数只是%esp,则该值将被移动到%esp寄存器中。基本上%esp寄存器的内容用于寻址。
  5. 这是一个固定值,右边的字符串让我觉得这个值实际上是puts()(Put String)编译器库例程的地址。
  6. “离开”是一种相当于“pop%ebp”的说明。记住我们在开始时保存了%ebp的内容,现在我们已经完成了将它恢复到寄存器中的例程,以便调用者返回其上下文。 “ret”指令是例程的最后一条指令,它“返回”给调用者。