转:程序内存空间(代码段、数据段、堆栈段)

xiaoxiao2021-02-28  67

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, 
转载请注明原文地址: https://www.6miu.com/read-2627056.html

最新回复(0)