二进制分析-栈

x86只有8个通用寄存此供使用(eax, ebx, ecx, edx, ebp, esp, esi, edi)。x64将它们扩展为64位(前缀由“e”变更为“r”),
并且新增了8个寄存器(r8, r9, r10, r11, r12, r13, r14, r15)。
由于x86下一些寄存器有特殊的用途和意义而不是真正意义上的“通用”(尤其是ebp和esp寄存器),
使得这些新增的特性产生的效用远不止是变大变多。

从ABI来看,函数开始的6个整数或指针类型的参数将通过寄存器传递参数,
第一个参数保存在rdi中,第二个保存在rsi中,接下来依次保存在rdx,rcx,r8,r9。
从第7个参数开始,接下来的所有参数都将通过栈传递。

值得注意的是,生成的汇编代码中函数 printf()被替换成了 puts(),这是因为当 printf()只有单一
参数时,与 puts()是十分类似的,于是 GCC 的优化策略就将其替换以提高性能。
leave # (mov esp, ebp; pop ebp)

对于 x86-64 的程序,前 6 个参数分别通过 rdi、rsi、rdx、rcx、r8 和 r9 进行传递,剩余参数才像
x86 一样从后向前依次压栈。除此之外,我们还发现 func()没有下移 rsp 开辟栈空间的操作,导致 rbp
和 rsp 的值是相同的,其实这是一项编译优化:根据 AMD64 ABI 文档的描述,rsp 以下 128 字节的
区域被称为 red zone,这是一块被保留的内存,不会被信号或者中断所修改。于是,func()作为叶子
函数就可以在不调整栈指针的情况下,使用这块内存保存临时数据。
在更极端的优化下,rbp 作为栈基址其实也是可以省略的,编译器完全可以使用 rsp 来代替,从
而减少指令数量。GCC 编译时添加参数“-fomit-frame-pointer”即可。
https://bbs.pediy.com/thread-200575.htm

原文地址:https://www.cnblogs.com/CSE-kun/p/14841518.html