汇编:在调用函数之前加载有效地址的目的?

Tar*_*bud 3 c assembly x86-64 disassembly

源代码:

 int main()
    {
      int i;
      for(i=0, i < 10; i++)
      {
        printf("Hello World!\n");
      }
    }
Run Code Online (Sandbox Code Playgroud)

转储函数的 Intel 语法 x86 汇编代码main

  1.  0x000055555555463a <+0>:     push   rbp
  2.  0x000055555555463b <+1>:     mov    rbp,rsp 
  3.  0x000055555555463e <+4>:     sub    rsp,0x10
  4.  0x0000555555554642 <+8>:     mov    DWORD PTR [rbp-0x4],0x0
  5.  0x0000555555554649 <+15>:    jmp    0x55555555465b <main+33>
  6.  0x000055555555464b <+17>:    lea    rdi,[rip+0xa2]    # 0x5555555546f4
  7.  0x0000555555554652 <+24>:    call   0x555555554510 <puts@plt>
  8.  0x0000555555554657 <+29>:    add    DWORD PTR [rbp-0x4],0x1
  9.  0x000055555555465b <+33>:    cmp    DWORD PTR [rbp-0x4],0x9
  10. 0x000055555555465f <+37>:    jle    0x55555555464b <main+17>
  11. 0x0000555555554661 <+39>:    mov    eax,0x0
  12. 0x0000555555554666 <+44>:    leave  
  13. 0x0000555555554667 <+45>:    ret    
Run Code Online (Sandbox Code Playgroud)

我目前正在研究“Hacking, The Art of Exploitation 2nd Edition by Jon Erickson”,我刚刚开始解决组装问题。

我有一些关于将提供的 C 代码翻译成汇编的问题,但我主要想知道我的第一个问题。

第一个问题:第 6 行的目的是什么?( lea rdi,[rip+0xa2]).

我目前的工作理论是,这用于保存下一条指令将跳转到的位置,以跟踪正在发生的事情。我相信这一行与printf源 C 代码中的函数相关。

所以本质上,它将rip+0xa2( 0x5555555546f4)的有效地址加载到寄存器中rdi,以简单地跟踪它将跳转到printf函数的位置?

第二个问题:第11行的目的是什么?( mov eax,0x0?) 我没有看到寄存器的先前使用,EAX并且不确定为什么需要将其设置为 0。

Pet*_*des 7

LEA 将指向字符串文字的指针放入寄存器,作为 puts 的第一个 arg。您要查找的搜索词是“调用约定”和/或 ABI。(还有 RIP 相对寻址)。 为什么静态变量的地址是相对于指令指针的?

代码和数据之间的小偏移(仅+0xa2)是因为该.rodata部分被链接到与 相同的 ELF 段中.text,并且您的程序很小。(较新的 gcc + ld 版本会将它放在一个单独的页面中,因此它可以是不可执行的。)

编译器无法mov edi, address在 Linux PIE 可执行文件中使用更短、更高效的位置无关代码。它会这样做gcc -fno-pie -no-pie

mov eax,0return 0mainC99 和 C++ 保证的末尾实现隐式。EAX 是所有调用约定中的返回值寄存器。

如果您不使用gcc -O2或更高版本,您将不会获得像 xor-zeroing ( xor eax,eax)这样的窥视孔优化。