gpt4 book ai didi

c - 堆栈变量的寻址

转载 作者:太空狗 更新时间:2023-10-29 16:49:16 25 4
gpt4 key购买 nike

我正在 X86_64 上的 GDB 中分析以下(非常简单的)C 程序的反汇编。

int main()
{
int a = 5;
int b = a + 6;
return 0;
}

我知道在 X86_64 中堆栈会向下增长。即栈顶的地址比栈底的地址低。上述程序的汇编程序如下:

Dump of assembler code for function main:
0x0000000000400474 <+0>: push %rbp
0x0000000000400475 <+1>: mov %rsp,%rbp
0x0000000000400478 <+4>: movl $0x5,-0x8(%rbp)
0x000000000040047f <+11>: mov -0x8(%rbp),%eax
0x0000000000400482 <+14>: add $0x6,%eax
0x0000000000400485 <+17>: mov %eax,-0x4(%rbp)
0x0000000000400488 <+20>: mov $0x0,%eax
0x000000000040048d <+25>: leaveq
0x000000000040048e <+26>: retq
End of assembler dump.

我的理解是:

  1. 我们将基指针压入堆栈。
  2. 然后我们将堆栈指针的值复制到基指针。
  3. 然后我们将值 5 复制到地址 -0x8(%rbp)。因为在 int 中是 4 个字节,这不应该在堆栈中的下一个地址 -0x4(%rbp) 而不是 -0x8(%rbp) 吗?
  4. 然后我们将变量a的值复制到%eax,加6然后将值复制到地址-0x4(%rbp)

使用此图形作为引用:


(来源:thegreenplace.net)

看起来堆栈包含以下内容:

|--------------|
| rbp | <-- %rbp
| 11 | <-- -0x4(%rbp)
| 5 | <-- -0x8(%rbp)

当我期待这个时:

|--------------|
| rbp | <-- %rbp
| 5 | <-- -0x4(%rbp)
| 11 | <-- -0x8(%rbp)

7-understanding-c-by-learning-assembly 中似乎就是这种情况他们在哪里显示程序集:

(gdb) disassemble
Dump of assembler code for function main:
0x0000000100000f50 <main+0>: push %rbp
0x0000000100000f51 <main+1>: mov %rsp,%rbp
0x0000000100000f54 <main+4>: mov $0x0,%eax
0x0000000100000f59 <main+9>: movl $0x0,-0x4(%rbp)
0x0000000100000f60 <main+16>: movl $0x5,-0x8(%rbp)
0x0000000100000f67 <main+23>: mov -0x8(%rbp),%ecx
0x0000000100000f6a <main+26>: add $0x6,%ecx
0x0000000100000f70 <main+32>: mov %ecx,-0xc(%rbp)
0x0000000100000f73 <main+35>: pop %rbp
0x0000000100000f74 <main+36>: retq
End of assembler dump.

a明确声明和初始化时,为什么b的值被放入堆栈中比a更高的内存地址第一?

最佳答案

b 的值被放在堆栈上,只要编译器愿意。你对它没有影响。你不应该。编译器的次要版本之间的顺序可能会发生变化,因为某些内部数据结构已更改或某些代码已重新排列。一些编译器甚至会故意随机化不同编译的堆栈布局,因为这会使某些错误更难被利用。

事实上,编译器可能根本不使用堆栈。没有必要。这是在启用了一些优化的情况下编译的同一程序的反汇编:

$ cat > foo.c
int main()
{
int a = 5;
int b = a + 6;
return 0;
}
$ cc -O -c foo.c
$ objdump -S foo.o

foo.o: file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
0: 31 c0 xor %eax,%eax
2: c3 retq
$

通过一些简单的优化,编译器发现您没有使用变量“b”,因此无需计算它。正因为如此,您也不使用变量“a”,因此无需分配它。只有没有优化的编译(或非常糟糕的编译器)才会将任何东西放在堆栈上。即使您使用这些值,基本优化也会将它们放入寄存器,因为接触堆栈的代价很高。

关于c - 堆栈变量的寻址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27247387/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com