Shu*_*ham 4 c assembly x86-64 stack-memory
这是我的源代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 500
int main(int argc, char** argv)
{
if (argc != 2)
exit(1);
char str[MAX];
strcpy(str, argv[1]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我disas使用并得到了以下结果main:gdb
Dump of assembler code for function main:
0x0000000000001145 <+0>: push %rbp
0x0000000000001146 <+1>: mov %rsp,%rbp
0x0000000000001149 <+4>: sub $0x210,%rsp
.
.
.
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)
这里值得注意的是:
0x0000000000001149 <+4>: sub $0x210,%rsp
我的问题是-
为什么会出现$0x210(528 字节),而它应该是$0x1f4(500 字节),正如我所要求的?
我猜你正在使用 gcc 并在没有优化的情况下进行编译,就像这样 (godbolt)。
这里发生了一些事情:
首先,在不进行优化的情况下进行编译时,编译器会尝试确保每个局部变量在内存中都有一个地址,以便调试器可以轻松地检查或修改它。这包括函数参数,这些参数在 x86-64 上以其他方式在寄存器中传递。因此编译器需要分配额外的堆栈空间,其中argc和argv参数可以“溢出”。您可以在程序集的第 5 行和第 6 行看到溢出:
movl %edi, -516(%rbp)
movq %rsi, -528(%rbp)
Run Code Online (Sandbox Code Playgroud)
如果您仔细观察,您可能会注意到,编译器通过将argc(from %edi) 放置在原本可用的地址-516(%rbp)处,浪费了 4 个字节。-520(%rbp)还不完全清楚为什么,但毕竟它没有优化!这样我们就得到了 516 字节。
另一个问题是 x86-64 ABI 需要 16 字节堆栈对齐;请参阅为什么 x86-64 / AMD64 System V ABI 强制执行 16 字节堆栈对齐?。在这种情况下,长话短说,这意味着我们的堆栈调整需要是 16 字节的倍数。(返回地址和推送地址rbp会再添加 16 个字节,这不会干扰这种对齐。)因此,我们的 516 必须向上舍入到下一个 16 的倍数,即 528。
如果编译器更加小心,没有浪费 和 之间的 4 个字节argc,argv我们可能只得到 512 个字节。不过,使用 528 的好处之一是缓冲区str最终以 16 字节对齐。这对于 的数组来说不是必需的char,其最小对齐方式仅为 1,但它可以提高字符串函数(例如strcpy使用快速 SIMD 算法)的效率。我不确定编译器是故意这样做还是只是巧合。
| 归档时间: |
|
| 查看次数: |
354 次 |
| 最近记录: |