【问题标题】:How to understand this AT&T i386 assembly code snippet? [duplicate]如何理解这个 AT&T i386 汇编代码片段? [复制]
【发布时间】:2020-08-19 17:11:03
【问题描述】:

请查看以下代码sn-ps:

int& sum(int& num1, int& num2) {
    num1++;
    num2++;
}

00000000 <_Z3sumRiS_>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   e8 fc ff ff ff          call   4 <_Z3sumRiS_+0x4>    // why here is a jump
   8:   05 01 00 00 00          add    $0x1,%eax     

   // why 0x8, my understanding is there are in total 3 parameters
   // num2 -- 0xc(%ebp), num1 -- 0x8(%ebp), this -- 0x4(%ebp)
   // am I right????
   d:   8b 45 08                mov    0x8(%ebp),%eax

  10:   8b 00                   mov    (%eax),%eax
  12:   8d 50 01                lea    0x1(%eax),%edx        // what the heck is this?
  15:   8b 45 08                mov    0x8(%ebp),%eax
  18:   89 10                   mov    %edx,(%eax)
  1a:   8b 45 0c                mov    0xc(%ebp),%eax
  1d:   8b 00                   mov    (%eax),%eax
  1f:   8d 50 01                lea    0x1(%eax),%edx
  22:   8b 45 0c                mov    0xc(%ebp),%eax
  25:   89 10                   mov    %edx,(%eax)
  27:   90                      nop
  28:   5d                      pop    %ebp
  29:   c3                      ret    

我需要弄清楚它的每一行的含义,我有点困惑。

【问题讨论】:

  • 这不是 C++ 成员函数,因此没有 this 参数。保存的 EBP 上方的栈槽是返回地址。此外,它具有未定义的行为,因为您脱离了非void 函数的末尾。 GCC -O0 似乎是故意评估返回值寄存器中具有副作用的最后一个表达式,所以如果你只关心 gcc -O0,这个 sort of works as returning num2++。它已完全损坏,无法用于任何其他用途。
  • @PeterCordes 那是一段 C++ 代码。我把它当作一种体验。故意没有返回值。
  • 对于what the heck is this?lea 0x1(%eax),%edx加载eax指向的值,加一,然后将结果存入edx。 IOW,这是您的num1++; 的一部分 - 随后的内存存储完成了它。
  • 查看具有未定义行为的代码的编译器输出可能会令人困惑,我不建议您首先使用它。请参阅 How to remove "noise" from GCC/clang assembly output? - godbolt.org 可以将源代码行与 asm 块匹配。
  • 另外,call / add 是因为这是一个 32 位 PIE,并且禁用优化的 GCC 正在编写代码以获取指向 GOT 的指针。而且您正在查看 .o 的反汇编,因此链接器尚未填充偏移量。使用objdump -drwC(最好使用-Mintel,除非你真的喜欢AT&T语法)。或者更好的是,查看编译器 asm 输出而不是从二进制反汇编。

标签: assembly 32-bit att i386


【解决方案1】:
   3:   e8 fc ff ff ff          call   4 <_Z3sumRiS_+0x4>

这不是调用的真正目的地,而是链接器将填写的内容。如果您运行objdump -dr sum.o,您会发现它实际上是对__x86.get_pc_thunk.ax 的调用。以下add 相同,设置指向 GOT 的指针。 (这个函数不需要,但是你编译时没有优化,-fpie默认开启。)

更多详情请关注Why does gcc generates strange code without flag -fno-pie?


System V i386 ABI,第 2.2.2 节讲述了堆栈帧的结构。

所以你的堆栈框架看起来像这样:

0xc  |      num2      |
0x8  |      num1      |
0x4  | return address |
0x0  | previous %ebp  |  <-- %ebp

对于剩余的说明,这里是一步一步的分析。

// as num1 and num2 are references, they represents address in assembly
   d:   8b 45 08                mov    0x8(%ebp),%eax        // load num1 to %eax
  10:   8b 00                   mov    (%eax),%eax           // load *num1 to %eax
  12:   8d 50 01                lea    0x1(%eax),%edx        // put *num1 + 1 into %edx
  15:   8b 45 08                mov    0x8(%ebp),%eax        // load num1 to %eax
  18:   89 10                   mov    %edx,(%eax)           // save *num1 + 1 at num1
  1a:   8b 45 0c                mov    0xc(%ebp),%eax        // same as above
  1d:   8b 00                   mov    (%eax),%eax
  1f:   8d 50 01                lea    0x1(%eax),%edx
  22:   8b 45 0c                mov    0xc(%ebp),%eax
  25:   89 10                   mov    %edx,(%eax)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-12
    相关资源
    最近更新 更多