C++

「C++」 可执行文件与加载

Posted by Dawn-K's Blog on February 22, 2023

编译后文件的结构

加载

程序的内存布局

注意,这是说的进程,要和可重定向文件和可执行文件的结构分开。

linux x86-64 中,代码段总是从地址 0x400000 开始,

  • bss 段 (bss segment) 通常是指用来存放程序中未初始化的全局变量的一块内存区域。
  • 数据段 (data segment) 通常是指用来存放程序中已初始化的全局变量的一块内存区域。
  • 代码区:存放函数体二进制代码,由操作系统进行管理的。这部分是共享的而且是只读的。
  • 栈区:由编译器自动分配释放,函数的参数值,局部变量。栈帧
  • 堆区:程序员分配和释放,若不释放,程序结束时由操作系统回收
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
High Addresses ---> .----------------------.
                    |                      |   Kernel space, 1GB for Linux,
                    |      Environment     |   2GB for Windows by default.
     2^48-1 ->      |----------------------|
                    |                      |   Functions and variable are declared
                    |         STACK        |   on the stack.
base pointer ->     | - - - - - - - - - - -|
                    |           |          |
                    |           v          |
                    |                      |
                    |                      |   The stack grows down into unused space
                    |         Empty        |   while the heap grows up. 
                    |                      |
                    |           ^          |
                    |           |          |
                    | - - - - - - - - - - -|
                    |   other memory maps  |   Other memory maps do occur here, such 
                    |                      |   as dynamic libraries, and different memory
                    |                      |   allocate)
                    |----------------------|
                    |                      |   
                    |                      |   
                    |                      |   
                    |           ^          |
                    |           |          |
 brk point ->       | - - - - - - - - - - -|   Dynamic memory is declared on the heap
                    |          HEAP        |
                    |                      |
                    |----------------------|
                    |          BSS         |   Uninitialized data (BSS)
                    |----------------------|   
                    |          Data        |   Initialized data (DS)
                    |----------------------|
                    |          Text        |   Binary code
  0x400000    ----> |----------------------|
                    |                      |
Low Addresses ----> '----------------------'

动态存储区

其中栈区和堆区是动态存储区。

栈区

  • 栈区是连续的内存区域,大小是固定的,生长方向从高到低,能从栈上获得的空间较小,操作系统底层对栈这种数据结构提供了支持,因此速度很快,且不会有碎片。Linux 默认是 8M 左右,可以调整。
  • 栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是 thread safe 的。每个 C++对象的数据成员也存在在栈中,每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换 SS/ESP 寄存器。
  • SP(栈指针)寄存器跟踪栈的顶部。

堆区

  • 堆区是不连续的,系统采用空闲链表的方式来管理空闲内存的地址,堆的大小受限于操作系统的大小。频繁的 new/delete 会造成大量碎片,使程序效率降低。
  • 堆是属于进程的。 TODO: brk, sbrk

静态存储区

内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。

BSS 段

历史原因,在汇编中曾有 block started by symbol . 程序开始执行前,内核将此段中的数据初始化为0或者空指针。

Data 段

.data 已初始化的全局和静态变量。

代码区

.text 已经编译好的机器代码。这个段是只读的,并且是可共享的,也就是多个进程可以共享一个代码副本以节省内存。