做一些基本的反汇编,并注意到缓冲区被给予额外的缓冲区空间,虽然我在教程中看到的使用相同的代码,但只给予正确的(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。
1条答案
按热度按时间sr4lhrrt1#
500不是16的倍数。
x86 - 64 ABI(应用程序二进制接口)要求每当
call
指令将要发生时,堆栈指针必须是16的倍数。(由于call
压入8字节返回地址,这意味着当控制到达被调用函数的第一条指令时,堆栈指针总是与8模16全等。)对于所示的代码,编译器通过增加其在sub
指令中使用的值,使其成为16的倍数,来方便地实现此要求。x86 - 32 ABI没有做这个要求,所以视频中使用的编译器没有理由增加堆栈帧的大小。
请注意,您似乎编译代码时没有进行优化,我在-O2中得到了这个代码:
堆栈调整 * 仍然 * 比数组的大小稍大,但不像您所拥有的那么大,也不再是16的倍数;不同之处在于,在优化开启的情况下,消除了帧指针,因此不需要保存和恢复%rbp,且因此堆栈指针在
sub
指令的点处不是16的倍数。(顺便说一句,没有任何地方要求堆栈帧尽可能小。"实现质量"规定它应该尽可能小,但由于各种原因,编译器错过这个目标是很常见的。在我优化的代码转储中,我看不出
sub
和add
的立即数 * 为什么不能 * 是0x1f8(504)。