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。
LEA 将指向字符串文字的指针放入寄存器,作为 puts 的第一个 arg。您要查找的搜索词是“调用约定”和/或 ABI。(还有 RIP 相对寻址)。 为什么静态变量的地址是相对于指令指针的?
代码和数据之间的小偏移(仅+0xa2
)是因为该.rodata
部分被链接到与 相同的 ELF 段中.text
,并且您的程序很小。(较新的 gcc + ld 版本会将它放在一个单独的页面中,因此它可以是不可执行的。)
编译器无法mov edi, address
在 Linux PIE 可执行文件中使用更短、更高效的位置无关代码。它会这样做gcc -fno-pie -no-pie
mov eax,0
return 0
在main
C99 和 C++ 保证的末尾实现隐式。EAX 是所有调用约定中的返回值寄存器。
如果您不使用gcc -O2
或更高版本,您将不会获得像 xor-zeroing ( xor eax,eax
)这样的窥视孔优化。