【问题标题】:Understanding disassembled C code: dec %eax and movl $0x0,-0x8(%ebp)了解反汇编的 C 代码:dec %eax 和 movl $0x0,-0x8(%ebp)
【发布时间】:2019-11-20 06:41:13
【问题描述】:

我试图理解一段反汇编代码中的行,如下所示。我想知道以下内容:

  • dec %eax : 为什么 eax 寄存器被递减? eax寄存器的初始值是多少?
  • movl $0x0,-0x8(%ebp) : 为什么我们要将值 0x0 移到堆栈上? movl 不存储 32 位值(4 个字节)吗?如果是这样,为什么将值存储在基指针下方 8 个字节而不是 4 个字节?

这是反汇编的二进制文件:

Contents of section .text:
 0000 554889e5 48c745f8 00000000 905dc3    UH..H.E......]. 
Contents of section .rodata:
 0000 48656c6c 6f00                        Hello.          
Contents of section .comment:
 0000 00474343 3a202855 62756e74 7520352e  .GCC: (Ubuntu 5.
 0010 342e302d 36756275 6e747531 7e31362e  4.0-6ubuntu1~16.
 0020 30342e31 30292035 2e342e30 20323031  04.10) 5.4.0 201
 0030 36303630 3900                        60609.          
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 1c000000 1c000000  ................
 0020 00000000 0f000000 00410e10 8602430d  .........A....C.
 0030 064a0c07 08000000                    .J......        

Disassembly of section .text:
0000000000000000 <my_function>:
   0:   55                      push   %ebp
   1:   48                      dec    %eax
   2:   89 e5                   mov    %esp,%ebp
   4:   48                      dec    %eax
   5:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp)
   c:   90                      nop
   d:   5d                      pop    %ebp
   e:   c3                      ret    

这是 C 代码:

void my_function () { 
   char* my_string = "Hello";
}

【问题讨论】:

  • 你的函数没有效果。我发布版本可能会完全消除它。

标签: assembly x86 disassembly att


【解决方案1】:

您正在反汇编 64 位代码,就像它是 32 位代码一样。仅存在于 64 位代码中的 REX.W 前缀是 32 位代码中的 DEC EAX 指令。

【讨论】:

  • 我恢复了我的编辑,因为我意识到我基本上已经写了一个完整的答案。所以我把它发布为我自己的。开始编辑时,我并没有打算写那么多。
【解决方案2】:

您正在反汇编 64 位代码,就好像它是 32 位代码一样。这通常是不可能的,除非您专门覆盖您的反汇编程序或使用 objcopy 或其他东西将 64 位机器代码复制到 32 位 ELF 目标文件中。

x86-64 将 0x40..f 字节重新用作 REX 前缀,而不是 inc/dec 的 1 字节编码。 DEC EAX 实际上是一个 REX.W 前缀,所以指令是 mov %rsp, %rbp 用于正常的帧指针设置。

这也解释了堆栈指针下方红色区域的前 8 个字节的使用。 (x86-64 System V 有一个红色区域,i386 System V 没有;它会在存储在其下方之前移动 ESP。)它解释了指针的 -8 而不是 -4,因为 x86-64 有 8 -字节指针。


0 字节是因为您正在反汇编未链接的 .o。这 4 个字节的零将被链接器填充为字符串的绝对地址。

GCC 在这里使用mov r/m64, sign_extended_imm32 来存储一个指向内存的 8 字节指针,使用 32 位绝对地址作为立即数。

要将其放入寄存器中,我们将获得非 PIE 可执行文件的普通 mov r32, imm32(隐式零扩展至 64 位)。但是这段代码(使用默认的-O0“调试模式”)需要内存中的整个 8 字节指针。它仍然可以使用 32 位绝对地址而不是 RIP 相对 LEA 到寄存器 + 单独存储中,但它必须显式符号扩展为 64 位。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-18
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 2013-10-05
    相关资源
    最近更新 更多