https://blog.csdn.net/ywcpig/article/details/52303745
在冯诺依曼的体系结构中,一个进程必须有:代码段,堆栈段,数据段。
进程的虚拟地址空间图示如下:
堆栈段:
1. 为函数内部的局部变量提供存储空间。
2. 进行函数调用时,存储“过程活动记录”。
3. 用作暂时存储区。如计算一个很长的算术表达式时,可以将部分计算结果压入堆栈。
数据段(静态存储区):
包括BSS段(Block Started by Symbol)的数据段。BSS段存储未初始化或初始化为0的全局变量、静态变量,具体体现为一个占位符,并不给该段的数据分配空间,只是记录数据所需空间的大小。数据段存储经过初始化的全局和静态变量。
[cpp] view plain copy #define DEBUG "debug" int space[1024][1024]; int data = 1; int no_data = 0; int main() { char *a = DEBUG; return 1; } 使用nm查看后 [cpp] view plain copy 0000000000600660 d _DYNAMIC 00000000006007f8 d _GLOBAL_OFFSET_TABLE_ 0000000000400578 R _IO_stdin_used w _Jv_RegisterClasses 0000000000600640 d __CTOR_END__ 0000000000600638 d __CTOR_LIST__ 0000000000600650 D __DTOR_END__ 0000000000600648 d __DTOR_LIST__ 0000000000400630 r __FRAME_END__ 0000000000600658 d __JCR_END__ 0000000000600658 d __JCR_LIST__ 0000000000600820 A __bss_start 0000000000600818 D __data_start 0000000000400530 t __do_global_ctors_aux 00000000004003e0 t __do_global_dtors_aux 0000000000400580 R __dso_handle w __gmon_start__ 0000000000600634 d __init_array_end 0000000000600634 d __init_array_start 0000000000400490 T __libc_csu_fini 00000000004004a0 T __libc_csu_init U __libc_start_main@@GLIBC_2.2.5 0000000000600820 A _edata 0000000000a00840 A _end 0000000000400568 T _fini 0000000000400358 T _init 0000000000400390 T _start 00000000004003bc t call_gmon_start 0000000000600820 b completed.6347 000000000060081c D data 0000000000600818 W data_start 0000000000600828 b dtor_idx.6349 0000000000400450 t frame_dummy 0000000000400474 T main 0000000000600830 B no_data 0000000000600840 B space 可以看到变量data被分配在data段,而被初始化为0的no_data被分配在了BSS段。
.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化。
注意:.data和.bss在加载时合并到一个Segment(Data Segment)中,这个Segment是可读可写的。
代码段:
又称为文本段。存储可执行文件的指令;也有可能包含一些只读的常数变量,例如字符串常量等。
.rodata段:存放只读数据,比如printf语句中的格式字符串和开关语句的跳转表。也就是你所说的常量区。例如,全局作用域中的 const int ival = 10,ival存放在.rodata段;再如,函数局部作用域中的printf("Hello world %d\n", c);语句中的格式字符串"Hello world %d\n",也存放在.rodata段。
但是注意并不是所有的常量都是放在常量数据段的,其特殊情况如下:1)有些立即数与指令编译在一起直接放在代码段。
[cpp] view plain copy int main() { int a = 10; return 1; } a是常量,但是它没有被放入常量区,而是在指令中直接通过立即数赋值2)对于字符串常量,编译器会去掉重复的常量,让程序的每个字符串常量只有一份。
[cpp] view plain copy char *str = "123456789"; char *str1 = "helloworld"; int main() { char* a = "helloworld"; char b[10] = "helloworld"; return 1; }汇编代码如下:
[cpp] view plain copy .file "hello.c" .globl str .section .rodata .LC0: .string "123456789" .data .align 8 .type str, @object .size str, 8 str: .quad .LC0 .globl str1 .section .rodata .LC1: .string "helloworld" .data .align 8 .type str1, @object .size str1, 8 str1: .quad .LC1 .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movq $.LC1, -8(%rbp) movl $1819043176, -32(%rbp) movl $1919907695, -28(%rbp) movw $25708, -24(%rbp) movl $1,
