圖說 bss段 text段 data段 rodata段 棧 堆
1.理論上程序編譯出來後,各個段的分佈
程序在執行後,虛擬內存分佈,如下圖:
下面從低地址到高地址,先分別說明下每個段的意義:
1.受保護區
受保護區
,是用戶(程序猿)不能訪問的地址,一般爲 0-4k。
我們平時寫程序的,初始化一個指針
char *p = NULL;
這個NULL
就是指向的受保護區,0
地址。
2.txt段
.txt段
是代碼段,比如我們的程序源碼就放在這塊區域
當然,如果有動態鏈接庫,庫代碼不是放在這裏的,是放在共享庫裏的。
這裏面的地址是絕對地址。
3.rodata段
.rodata段
是 只讀數據段,比如我們用const
修飾的值就是放在這個區域的。
const int a[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
table a 就是放在 .rodata
段的
4.data段
.data段
是數據段,存放了已經初始化的全局變量,以及初始化全局靜態變量,初始化的局部靜態變量等。
int g_init_v = 1;
static int static_init_v = 1;
static int static_uinit_v;
初始化的全局變量,已經初始化和未初始化的靜態變量都在這個段,初始化的局部靜態變量。
5.bss段
.bss段 是未初始化的全局變量以及未初始化的靜態局部變量。
int g_uinit_v;
6.堆
堆
,程序員可以用來分配內存的空間,使用malloc
分配。
/* mallloc */
int *malloc_v = malloc(10);
在創建進程的時候,會爲進程分配多大的堆。
7.共享庫
共享庫
,在調用了共享庫的可執行程序裏面,共享庫放在這個位置。
前面有寫過一篇文章,如果需要,可以看看共享庫的製作與使用。
https://blog.csdn.net/acdefghb/article/details/105774084
8.棧
棧
,程序執行過程中,程序用來存放臨時變量和函數返回值的區域。
由系統分配和回收。
在進程創建的時候,每個進程/線程都有自己獨立的棧空間。
9.命令行和環境變量
環境變量:就是我們linux的環境變量,env
命令行參數,比如
int main(int argc, char *argv[])
這裏面argv所帶的參數。
2.利用下面的例子說明
//memery_test_n.c
#include <stdio.h>
#include <stdlib.h>
/* 初始化全局變量 */
int g_init_v = 1;
/* 未初始化全局變量 */
int g_uinit_v;
/* 初始化靜態全局變量 */
static int g_s_init_v = 1;
/* 未初始化靜態全局變量 */
static int g_s_uinit_v;
/* 初始化全局數組 並用const 修飾 */
const int g_table1_init[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
/* 初始化全局變量 不用const 修飾 */
int g_table2_init[] = {11, 21, 31, 41, 51, 61, 71, 81, 91, 101};
/* 全局字符串 */
char *g_str = "hello, world!";
int main()
{
/* 初始化的局部變量 */
int l_init_v = 2;
/* 未初始化的局部變量 */
int l_uinit_v;
/* 初始化的局部靜態變量 */
static int l_s_init_v = 2;
/* 未初始化的局部靜態變量 */
static int l_s_uinit_v;
/* 局部字符串 */
char *l_str = "nihao,sijie";
/* 局部數組 */
int l_table[] = {22, 32, 42, 52, 62, 72};
/* mallloc */
int *malloc_v = malloc(10);
return 0;
}
先用反彙編來查看下生成的.o
文件
gcc -c memery_test_n.c
然後用objdump -h
將elf文件的各個段信息打印出來。
objdump -h memery_test_n.o
得到如下結果,這個是對elf文件的內容查看
這裏需要對elf文件有一定的瞭解,這裏主要要知道這幾個項
項目 | Value |
---|---|
Name | 段名字 |
Size | 段大小 |
File off | 在elf文件中的位置 |
個各段的意義在這裏展開講,這篇文章就太長了,後面單獨講下 elf 的文件結構。我們這裏還是把注意力放在 .txt .data .bss .rodata
段上
這裏簡單畫下這幾個段在elf文件的位置:
這個大概就是elf文件中幾個段的分佈位置。
如何查看每個程序中每個變量在那個位置呢,我們用下面這條命令查看
objdump -d -s memery_test_n.o > dump1.txt
打開dump1.txt
memery_test_n.o: file format elf64-x86-64
Contents of section .text:
0000 554889e5 4883ec40 64488b04 25280000 UH..H..@dH..%(..
0010 00488945 f831c0c7 45cc0200 0000488d .H.E.1..E.....H.
0020 05000000 00488945 d0c745e0 16000000 .....H.E..E.....
0030 c745e420 000000c7 45e82a00 0000c745 .E. ....E.*....E
0040 ec340000 00c745f0 3e000000 c745f448 .4....E.>....E.H
0050 000000bf 0a000000 e8000000 00488945 .............H.E
0060 d8ebfe ...
Contents of section .data:
0000 01000000 01000000 00000000 00000000 ................
0010 00000000 00000000 00000000 00000000 ................
0020 0b000000 15000000 1f000000 29000000 ............)...
0030 33000000 3d000000 47000000 51000000 3...=...G...Q...
0040 5b000000 65000000 02000000 [...e.......
Contents of section .rodata:
0000 01000000 02000000 03000000 04000000 ................
0010 05000000 06000000 07000000 08000000 ................
0020 09000000 0a000000 68656c6c 6f2c2077 ........hello, w
0030 6f726c64 21006e69 68616f2c 73696a69 orld!.nihao,siji
0040 6500 e.
Contents of section .data.rel.local:
0000 00000000 00000000 ........
Contents of section .comment:
0000 00474343 3a202855 62756e74 7520372e .GCC: (Ubuntu 7.
0010 352e302d 33756275 6e747531 7e31382e 5.0-3ubuntu1~18.
0020 30342920 372e352e 3000 04) 7.5.0.
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 01781001 .........zR..x..
0010 1b0c0708 90010000 1c000000 1c000000 ................
0020 00000000 63000000 00410e10 8602430d ....c....A....C.
0030 06000000 00000000 ........
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 40 sub $0x40,%rsp
8: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
f: 00 00
11: 48 89 45 f8 mov %rax,-0x8(%rbp)
15: 31 c0 xor %eax,%eax
17: c7 45 cc 02 00 00 00 movl $0x2,-0x34(%rbp)
1e: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # 25 <main+0x25>
25: 48 89 45 d0 mov %rax,-0x30(%rbp)
29: c7 45 e0 16 00 00 00 movl $0x16,-0x20(%rbp)
30: c7 45 e4 20 00 00 00 movl $0x20,-0x1c(%rbp)
37: c7 45 e8 2a 00 00 00 movl $0x2a,-0x18(%rbp)
3e: c7 45 ec 34 00 00 00 movl $0x34,-0x14(%rbp)
45: c7 45 f0 3e 00 00 00 movl $0x3e,-0x10(%rbp)
4c: c7 45 f4 48 00 00 00 movl $0x48,-0xc(%rbp)
53: bf 0a 00 00 00 mov $0xa,%edi
58: e8 00 00 00 00 callq 5d <main+0x5d>
5d: 48 89 45 d8 mov %rax,-0x28(%rbp)
61: eb fe jmp 61 <main+0x61>
來分析下這個反彙編文件:
1.分析.txt段
dump文件的內容一共分爲3部分,
第一部是序列,一行表示16個16進制的數;
第二部分是用16進製表示的內容;
第三部分是ASCII碼的顯示。
在分析內容的時候發現,就是我們寫的main函數,對比字節是完全一樣。
所以得出第一個結論,.txt裏面存放是的代碼
即.txt段是存放代碼的段,簡稱代碼段
2.分析.data段
先在反彙編裏面遭到.data段,並分析其在程序中對應的值,至少這些值是可以確定的:
從圖片可以看出,這些值是初始化的全局變量和初始化的全局靜態變量以及初始化的局部靜態變量。
所以得出了.data的存儲數據內容爲初始化的全局變量和初始化的全局靜態變量以及初始化的局部靜態變量
。
c
先在反彙編裏面遭到.data段,並分析其在程序中對應的值:
從圖片可以看出,.rodata存取的數據包括,const修飾的數據,全局以及局部的字符串;
所以得出了.rodata的存儲數據內容爲const修飾的數據,全局以及局部的字符串
。
4.分析.bss段
在反匯編出來的文件中沒有看到bss段內容,但在elf文件的各段信息中,是存在bss段的,爲啥在dump出來的具體數據的時候沒看到bss段呢?
在來看看bss段的屬性:
bss段是ALLOC屬性,而.txt/.data/.rodata都有CONTENTS屬性。
CONTENTS表示在該段在文件中存在,所以bss段在elf文件中是不存在的。
可以用size
命令來看看.o
文件
看到bss段有8個字節,而我們代碼中的這兩個變量:
/* 未初始化全局變量 */
int g_uinit_v;
/* 未初始化的局部靜態變量 */
static int l_s_uinit_v;
兩個變量正好是8個字節,符合預期的。
其實更準確的說發是.bss段是爲這兩個變量預留了8個字節,佔個位。
以上就是我對各個段的實驗總結,如果不對請斧正。