assembly x86-32和x64程序集堆栈分配在固定大小缓冲区和未优化C(GCC)中的差异

xt0899hw  于 2023-02-08  发布在  其他
关注(0)|答案(1)|浏览(113)

做一些基本的反汇编,并注意到缓冲区被给予额外的缓冲区空间,虽然我在教程中看到的使用相同的代码,但只给予正确的(500)字符长度。这是为什么?
我的代码:

#include <stdio.h>
#include <string.h>

int main (int argc, char** argv){
    char buffer[500];
    strcpy(buffer, argv[1]);
    return 0;
}

用GCC编译,分解后的代码为:

0x0000000000001139 <+0>:     push   %rbp
   0x000000000000113a <+1>:     mov    %rsp,%rbp
   0x000000000000113d <+4>:     sub    $0x210,%rsp
   0x0000000000001144 <+11>:    mov    %edi,-0x204(%rbp)
   0x000000000000114a <+17>:    mov    %rsi,-0x210(%rbp)
   0x0000000000001151 <+24>:    mov    -0x210(%rbp),%rax
   0x0000000000001158 <+31>:    add    $0x8,%rax
   0x000000000000115c <+35>:    mov    (%rax),%rdx
   0x000000000000115f <+38>:    lea    -0x200(%rbp),%rax
   0x0000000000001166 <+45>:    mov    %rdx,%rsi
   0x0000000000001169 <+48>:    mov    %rax,%rdi
   0x000000000000116c <+51>:    call   0x1030 <strcpy@plt>
   0x0000000000001171 <+56>:    mov    $0x0,%eax
   0x0000000000001176 <+61>:    leave  
   0x0000000000001177 <+62>:    ret

然而,这个视频https://www.youtube.com/watch?v=1S0aBV-Waeo显然只分配了500字节

为什么是这样的情况下,我可以看到这里唯一的区别是一个是32位和另一个(我的)是在x86 - 64。

sr4lhrrt

sr4lhrrt1#

500不是16的倍数。
x86 - 64 ABI(应用程序二进制接口)要求每当call指令将要发生时,堆栈指针必须是16的倍数。(由于call压入8字节返回地址,这意味着当控制到达被调用函数的第一条指令时,堆栈指针总是与8模16全等。)对于所示的代码,编译器通过增加其在sub指令中使用的值,使其成为16的倍数,来方便地实现此要求。
x86 - 32 ABI没有做这个要求,所以视频中使用的编译器没有理由增加堆栈帧的大小。
请注意,您似乎编译代码时没有进行优化,我在-O2中得到了这个代码:

0x0000000000000000 <+0>:     sub    $0x208,%rsp
   0x0000000000000007 <+7>:     mov    0x8(%rsi),%rsi
   0x000000000000000b <+11>:    mov    %rsp,%rdi
   0x000000000000000e <+14>:    call   <strcpy@PLT>
   0x0000000000000013 <+19>:    xor    %eax,%eax
   0x0000000000000015 <+21>:    add    $0x208,%rsp
   0x000000000000001c <+28>:    ret

堆栈调整 * 仍然 * 比数组的大小稍大,但不像您所拥有的那么大,也不再是16的倍数;不同之处在于,在优化开启的情况下,消除了帧指针,因此不需要保存和恢复%rbp,且因此堆栈指针在sub指令的点处不是16的倍数。
(顺便说一句,没有任何地方要求堆栈帧尽可能小。"实现质量"规定它应该尽可能小,但由于各种原因,编译器错过这个目标是很常见的。在我优化的代码转储中,我看不出subadd的立即数 * 为什么不能 * 是0x1f8(504)。

相关问题