• [转]C程序内存区域分配(5个段作用)


    [转]C程序内存区域分配(5个段作用)  

    2012-08-10 14:45:32|  分类: C++基础|字号 订阅

     
     
    参考:
    http://www.360doc.com/content/11/0330/21/1317564_105977930.shtml
    http://hi.baidu.com/bitcore/blog/item/77c521c65f4512d7d10060eb.html
    http://apps.hi.baidu.com/share/detail/22734757
    http://my.oschina.net/alphajay/blog/3870

    一、C语言可执行代码结构
     名称 内容
    代码段  可执行代码、字符串常量
    数据段  已初始化全局变量、已初始化全局静态变量、局部静态变量、常量数据
    BSS段  未初始化全局变量,未初始化全局静态变量
     局部变量、函数参数
     动态内存分配

            一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务)在存储(没有调入到内存运行)时拥有3个部分,分别是代码段(text)、数据段(data)和BSS段。这3个部分一起组成了该可执行程序的文件。

            (1)代码段(text segment):存放CPU执行的机器指令。通常代码段是可共享的,这使得需要频繁被执行的程序只需要在内存中拥有一份拷贝即可。代码段也通常是只读的,这样可以防止其他程序意外地修改其指令。另外,代码段还规划了局部数据所申请的内存空间信息。

            代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

            (2)数据段(data segment):或称全局初始化数据段/静态数据段(initialized data segment/data segment)。该段包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据。

            (3)未初始化数据段:亦称BSS(Block Started by Symbol)。该段存入的是全局未初始化变量、静态未初始化变量。

            而当程序被加载到内存单元时,则需要另外两个域:堆域和栈域。图1-1所示为可执行代码存储态和运行态的结构对照图。一个正在运行的C程序占用的内存区域分为代码段、初始化数据段、未初始化数据段(BSS)、堆、栈5个部分。


    C语言中的5个段作用 - myswirl - 漩涡的窝

    图1-1  C语言可执行代码结构

          (4)栈段(stack):存放函数的参数值、局部变量的值,以及在进行任务切换时存放当前任务的上下文内容。

          (5)堆段(heap):用于动态内存分配,即使用malloc/free系列函数来管理的内存空间。

         在将应用程序加载到内存空间执行时,操作系统负责代码段、数据段和BSS段的加载,并将在内存中为这些段分配空间。栈段亦由操作系统分配和管理,而不需要程序员显示地管理;堆段由程序员自己管理,即显示地申请和释放空间。

        另外,可执行程序在运行时具有相应的程序属性。在有操作系统支持时,这些属性页由操作系统管理和维护。

    二、例子演示,代码段、数据段和BSS段存储变量类型

    #include <stdio.h>
    const int    g_A       = 10;            //代码段
    int            g_B       = 20;            //数据段
    static int    g_C       = 30;            //数据段
    static int    g_D;                    //BSS段
    int            g_E;                    //BSS段
    char        *p1;                    //BSS段

    void main( )
    {
        int            local_A;            //栈
        static int    local_C = 0;        //数据段
        static int    local_D;            //数据段
        
        char        *p3 = "123456";     //123456在代码段,p3在栈上

        p1 = (char *)malloc( 10 );      //堆,分配得来得10字节的区域在堆区
        strcpy( p1, "123456" );         //123456{post.content}放在常量区,编译器可能会将它与p3所指向 的"123456"优化成一块
        printf(" ");
        printf( "代码段,全局初始化变量, 只读const,  g_A,     addr:0x%08x ", &g_A);
        printf(" ");
        printf( "数据段,全局变量,       初始化      g_B,     addr:0x%08x ", &g_B);
        printf( "数据段,静态全局变量,   初始化,     g_C,     addr:0x%08x ", &g_C);
        printf(" ");
        printf( "BSS段, 全局变量,       未初始化    g_E,     addr:0x%08x ", &g_E, g_E );    
        printf( "BSS段, 静态全局变量,   未初始化,   g_D,     addr:0x%08x ", &g_D );
        printf( "BSS段, 静态局部变量,   初始化,     local_C, addr:0x%08x ", &local_C);
        printf( "BSS段, 静态局部变量,   未初始化,   local_D, addr:0x%08x ", &local_D);
        printf(" ");
        printf( "栈,    局部变量,                   local_A, addr:0x%08x ", &local_A );
        printf(" ");
        printf( "堆,    malloc分配内存,             p1,      addr:0x%08x ", p1 );
    }

    C程序内存区域分配(5个段作用) - myswirl - 漩涡的窝
    注意:
    编译时需要-g选项,这样才可以看elf信息;
    readelf -a MemoryAssign > 1.txt
    可执行程序MemoryAssign的信息导出到文本文件1.txt中,查看1.txt 
    C程序内存区域分配(5个段作用) - myswirl - 漩涡的窝
     
    C程序内存区域分配(5个段作用) - myswirl - 漩涡的窝
     

    问题1:可执行文件大小由什么决定?

    可执行文件在存储时分为代码段、数据段和BSS段三个部分。

    【例一】
    程序1:
    int ar[30000];
    void main()
    {
        ......

    程序2:
    int ar[300000] =  {1, 2, 3, 4, 5, 6 };
    void main()
    {
        ......

    发现程序2编译之后所得的.exe文件比程序1的要大得多。当下甚为不解,于是手工编译了一下,并使用了/FAs编译选项来查看了一下其各自的.asm,发现在程序1.asm中ar的定义如下:
    _BSS SEGMENT
         ?ar@@3PAHA DD 0493e0H DUP (?)    ; ar
    _BSS ENDS 
    而在程序2.asm中,ar被定义为:
    _DATA SEGMENT
         ?ar@@3PAHA DD 01H     ; ar
                    DD 02H
                    DD 03H
                    ORG $+1199988
    _DATA ENDS 
    区别很明显,一个位于.bss段,而另一个位于.data段,两者的区别在于:全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间。

    .bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化,因此造成了上述情况。

    C程序内存区域分配(5个段作用) - myswirl - 漩涡的窝
    可以看到可执行文件“2”大小为122K,可执行文件“1”大小为4.8K,用size命令查看二进制可执行文件结构情况。
     
  • 相关阅读:
    通过Xshell连接CentOS虚拟机
    Linux学习笔记
    JAVA学习摘要
    4k 对齐,你准备好了吗?
    图片种子制作方法,利用图片上传附件
    利用京东服务免费打造属于自己的网站
    PE制作实录 —— 补充说明
    PE制作实录 —— 定义我的 PE 工具箱
    浏览器 — 各项基准测试
    Windows 8.1 归档 —— Step 3 软件的选择与安装
  • 原文地址:https://www.cnblogs.com/mrblue/p/3348564.html
Copyright © 2020-2023  润新知