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

The relation of Stack, Memory Heap and assembly code

本文关键字:代码 关系 汇编 内存 堆栈      更新时间:2023-10-16

我试图更详细地了解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个字节,并返回了第一个内存地址,但我看不出堆栈是如何填充的,除了从中提取的指令本身之外,这里没有与内存的交互。

堆栈(内存)上的is在这里意味着什么?

这意味着由变量命名的对象存储在称为堆栈的内存部分,也称为调用堆栈。调用堆栈包含函数的局部自动变量。

movl    $5, -8(%rbp)

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

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

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


堆栈(与内存有关)、framerbp等都不是由C++语言定义的。这些词在特定CPU体系结构的上下文中具有意义。

语言中没有任何内容表明a将在堆栈上。编译器有权把它放在任何它想放的地方;特别是,如果它不需要把它放在任何地方,它就不必。

变量a在放入5之后就再也不用了,所以一个好的优化器会完全放弃这一行。

然而,在您的特定情况下,在我看来a确实在堆栈中。它位于%rbp中的帧指针外-8字节处。也就是说,a的地址是-8(%rbp),或者"寄存器rbp中的值,减去8",这非常接近堆栈的顶部。

获取更多详细信息。堆栈存在于内存中。让我们假设堆栈在内存中向下增长(这是传统的),这样堆栈的"顶部"就会向更小的地址增长。有一个指向堆栈顶部的"堆栈指针",即添加到堆栈中的最后一个东西的地址(我在这里只是泛泛地说)。

要分配N个字节的堆栈空间,所需要的就是从堆栈指针中减去N。生成的代码通常在一条指令中完成这一操作,因为它知道所输入函数所需的总空间。为了释放该空间,代码可以(a)添加N,或者(b)恢复堆栈指针的减法前值,该值已保存在某个位置。选择实际上是定义了编译器系统希望如何管理堆栈的更精细的细节。

堆栈管理中可能会用到一些辅助寄存器。一个常见的是有一个"框架指针",这是%rbp在这里所扮演的角色。