堆栈,内存堆和汇编代码的关系

时间:2019-01-22 01:25:35

标签: c++ assembly stack heap-memory

我试图更详细地了解C / C ++代码的编译过程及其内存管理。假设以下代码:

#include <iostream>

int main() {
    int a = 5;
    int *b = (int *) malloc(40);
    return 0;
}

我知道ab将在堆栈上创建,并且b的值(它指向的内存)将在堆上。

编译为汇编的代码如下:

    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $40, %eax
    movl    %eax, %edi
    movl    $0, -4(%rbp)
    movl    $5, -8(%rbp)
    callq   _malloc
    xorl    %ecx, %ecx
    movq    %rax, -16(%rbp)
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq

我的问题是

a is on the stack (memory)在这里是什么意思?根据以上程序集,a直接嵌入到指令$5, -8(%rbp)中,没有引用存储位置。如果它在内存中,那么a的地址是什么?

我知道_malloc在堆(内存)上创建40个字节并返回第一个内存地址,但是我看不到堆栈是如何填充的,除了要获取的指令本身之外,这里与内存没有任何交互形成它。

2 个答案:

答案 0 :(得分:2)

  

堆栈(内存)在这里是什么意思?

这意味着由变量命名的对象存储在称为堆栈的存储区中,也称为调用堆栈。调用堆栈包含函数的本地自动变量。

movl    $5, -8(%rbp)

rbp是帧指针。它指向调用堆栈的当前框架。该指令将常量5移动到由rbp指向的内存中,偏移量为-8个字节。换句话说,该指令将初始化变量a,该变量位于堆栈上。

  

如果它在内存中,那么a的地址是什么?

a的地址似乎是rbp - 8,其中rbp是存储在帧指针中的地址。在C ++领域中,可以使用addressof运算符获取地址。


堆栈(与内存有关),框架 rbp 等均未定义由C ++语言编写。这些词在特定的CPU体系结构的上下文中具有含义。

答案 1 :(得分:1)

没有什么能说明a会出现在堆栈中。编译器有权将其放置在所需位置。特别是,如果不需要将其放置在任何地方,则不必这样做。

将变量a放入5后就不再使用了,因此,一个不错的优化程序将把该行完全丢弃。

但是,在您的特定情况下,在我看来a确实在堆栈中。它距离%rbp中的帧指针-8个字节。也就是说,a的地址为-8(%rbp),即“寄存器rbp中的值减去8”,这非常接近堆栈的顶部。

获取更多详细信息。堆栈存在于内存中。我们假设堆栈在内存中向下增长(这是常规做法),以便堆栈的“顶部”朝着较小的地址增长。有一个“堆栈指针”指向堆栈的顶部,即添加到堆栈中的最后一件事的地址(我在这里一般地说)。

要分配N个字节的堆栈空间,所需要做的就是从堆栈指针中减去N。生成的代码通常在一条指令中执行此操作,因为它知道输入功能所需的总空间。为了释放该空间,代码可以(a)添加N,或(b)恢复堆栈指针的预减值,该值已保存在某个地方。该选择实际上是定义了有关编译器系统如何管理堆栈的更详细的细节。

在堆栈管理中可能会使用辅助寄存器。常见的是拥有一个“帧指针”,这是%rbp在此处扮演的角色。