图说 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个字节,占个位。
以上就是我对各个段的实验总结,如果不对请斧正。