你如何解释这个反汇编清单?

How would you explain this disassembly listing?

我有一个简单的 C 语言函数,在单独的文件中 string.c:

void var_init(){
    char *hello = "Hello";
}

编译为:

gcc -ffreestanding -c string.c -o string.o

然后我使用命令

objdump -d string.o

查看反汇编列表。我得到的是:

string.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <var_init>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 8d 05 00 00 00 00    lea    0x0(%rip),%rax        # b <var_init+0xb>
   b:   48 89 45 f8             mov    %rax,-0x8(%rbp)
   f:   90                      nop
  10:   5d                      pop    %rbp
  11:   c3                      retq

我迷失了对这个清单的理解。 "Writing OS from scratch"这本书说了一些旧的反汇编并略微揭开了其中的谜团,但他们的清单完全不同,我什至没有看到像作者所说的那样将数据解释为我的代码。

这个命令

lea    0x0(%rip),%rax

将字符串文字的地址存储在寄存器rax中。

还有这个命令

mov    %rax,-0x8(%rbp)

将寄存器 rax 中的地址复制到分配的堆栈内存中。从堆栈中的偏移量可以看出地址占用8个字节-0x8.

这个存储只是因为你在调试模式下编译才会发生;它通常会被优化掉。接下来发生的事情是局部变量(在堆栈指针下方的 中)被有效地丢弃,因为函数拆除了它的堆栈框架和 returns.

您正在查看的 material 可能包括一个 sub , %rsp 或类似的分配 space 给低于 RBP 的当地人,然后再分配 space ; x86-64 System V ABI 在叶函数中不需要它(不调用任何其他函数);他们可以只使用阅读区。 (另见 ). Or compile with gcc -mno-red-zone, which you probably want anyway for freestanding code: Why can't kernel code use a Red Zone

然后它恢复调用者 RBP 的保存值(早先设置为帧指针;请注意,space 本地的地址是相对于 RBP 寻址的)。

pop    %rbp

并退出,有效地将 return 地址弹出到 RIP

retq

除了@VladfromMoscow 的解释外,我只是认为发帖者查看编译为程序集时会发生什么而不是使用 objdump 查看它可能会有所帮助,因为这样可以更清楚地看到数据 ( IMO) 和 RIP 相对寻址可能更有意义。

gcc -S x.s

产量

    .file   "x.c"
    .text
    .section    .rodata
.LC0:
    .string "Hello"
    .text
    .globl  var_init
    .type   var_init, @function
var_init:
.LFB0:
    pushq   %rbp
    movq    %rsp, %rbp
    leaq    .LC0(%rip), %rax
    movq    %rax, -8(%rbp)
    nop
    popq    %rbp
    ret
.LFE0:
    .size   var_init, .-var_init
    .ident  "GCC: (Alpine 8.3.0) 8.3.0"
    .section    .note.GNU-stack,"",@progbits