堆栈变量的寻址

10 c assembly stack gdb disassembly

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

int main()
{
    int a = 5;
    int b = a + 6;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

据我所知,在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.
Run Code Online (Sandbox Code Playgroud)

我明白那个:

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

使用此图形作为参考:

http://eli.thegreenplace.net/images/2011/08/x64_frame_nonleaf.png

它看起来像堆栈具有以下内容:

|--------------|
|      rbp     | <-- %rbp
|      11      | <-- -0x4(%rbp)
|      5       | <-- -0x8(%rbp)
Run Code Online (Sandbox Code Playgroud)

当我期待这个:

|--------------|
|      rbp     | <-- %rbp
|      5       | <-- -0x4(%rbp)
|      11      | <-- -0x8(%rbp)
Run Code Online (Sandbox Code Playgroud)

这似乎是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.
Run Code Online (Sandbox Code Playgroud)

为什么值b被放入堆栈中的一个更高的内存地址比aa被明确宣布,并首先初始化?

Art*_*Art 7

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
$
Run Code Online (Sandbox Code Playgroud)

通过一些简单的优化,编译器发现你不使用变量'b',所以不需要计算它.因此你不使用变量'a',所以不需要分配它.只有没有优化的编译(或非常糟糕的编译器)才会在此处放置任何内容.即使您使用这些值,基本优化也会将它们放入寄存器中,因为触摸堆栈非常昂贵.