您的位置:首页 > 运维架构 > Linux

深入理解程序的结构

2016-07-17 18:47 387 查看
 程序是被分成段加以管理的,在程序被加载到内存中运行之前,各段是放在程序文件中的。

    当程序文件中所需的段被加载到内存中后,将通过运行指令来处理相应的数据。有些数据来源于程序文件中的段,有些是自动生成的。

1、段

    1.1、指令段

        .text 段:

            由于处理器只能识别数据和指令。所以不论采用什么高级语言编写程序,都得被编译器转化成为处理器所能识别的数据和机器指令。而编译后的机器指令都被存放在 .text 段。

            从 C 源程序角度来看,.text 段中存放的是函数的机器指令实现。

            如果处理器有内存管理单元,在可执行程序被加载到内存以后,通常会将 .text 段设置为只读,以防代码不会因为程序出错而被修改。

    1.2、数据段

        处理器所需加工的数据是放在 .data、.bss 和 .rdata 段的,也可以来自堆和栈。

        通过以下,.data 和 .bss 两个数据段所存放数据的区别:

        section1.c

#include <stdio.h>


int main()

{

return 0;

}


        处理结果:

[root@localhost huge12]# gcc -g -c section1.c 
4000
[root@localhost huge12]# strip section1.o
[root@localhost huge12]# objdump -h section1.o

section1.o:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000019  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000050  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000050  2**2
                  ALLOC
  3 .comment      0000002e  00000000  00000000  00000050  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  0000007e  2**0
                  CONTENTS, READONLY
        由上可看出,此时在没有任何数据的情况下,.data 和 .bss 段的大小为 0.

        

        section2.c

#include <stdio.h>


int a = 0x77778888

int b = 0;


int main()

{

return 0;

}


        处理结果:

[root@localhost huge12]# gcc -g -c section2.c 
[root@localhost huge12]# strip section2.o
[root@localhost huge12]# objdump -h section2.o

section2.o:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000019  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  00000000  00000000  00000050  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  00000000  00000000  00000054  2**2
                  ALLOC
  3 .comment      0000002e  00000000  00000000  00000054  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  00000082  2**0
                  CONTENTS, READONLY
        从处理结果:

 .data 和 .bss 段有了变化,由于在 section2.c 中新增了两个变量,对于初始化不为 0 的变量存放在 .data 段,对于初始化为 0 或 不初始化的全局变量存放在
.data 段。

.bss 段不存放在程序文件中
由于 .bss 段中的变量不需要初始化成特定值(0除外),所以不需要在程序文件中保存其内容,好处是能减小程序文件的大小而节省存储空间
对于 .data 段内数据的初始化,是引导加载器加载程序时,通过将程序文件中 .data 段的数据复制到所对应的内存地址空间,从而一次性地完成所有变量的初始化

        在一个函数内定义非静态变量(即局部变量)时,变量的内存空间是被分配在栈上的,那么加了 static 后的内存空间与全局变量是一样的。

        section3.c

#include <stdio.h>


int main()

{


static int a = 0x77778888;

static int b = 0;


return 0;

}


        处理结果:

[root@localhost huge12]# gcc -g -c section3.c 
[root@localhost huge12]# strip section3.o
[root@localhost huge12]# objdump -h section3.o

section3.o:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000019  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  00000000  00000000  00000050  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  00000000  00000000  00000054  2**2
                  ALLOC
  3 .comment      0000002e  00000000  00000000  00000054  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  00000082  2**0
                  CONTENTS, READONLY

        下面再来看一看字符串全局变量:

        section4.c

#include <stdio.h>


char str[] = "hello world!";


int main()

{

return 0;

}


        处理结果:

[root@localhost huge12]# gcc -g -c section4.c
[root@localhost huge12]# strip section4.o
[root@localhost huge12]# objdump -h section4.o

section4.o:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000019  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         0000000d  00000000  00000000  00000050  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000060  2**2
                  ALLOC
  3 .comment      0000002e  00000000  00000000  00000060  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  0000008e  2**0
                  CONTENTS, READONLY

    下面再对section4.c做一些修改:

#include <stdio.h>


const char str[] = "hello world!";


int main()

{

return 0;

}


        处理结果:

[root@localhost huge12]# gcc -g -c section4.c
[root@localhost huge12]# strip section4.o
[root@localhost huge12]# objdump -h section4.o

section4.o:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000019  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000050  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000050  2**2
                  ALLOC
  3 .rodata       0000000d  00000000  00000000  00000050  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .comment      0000002e  00000000  00000000  0000005d  2**0
                  CONTENTS, READONLY
  5 .note.GNU-stack 00000000  00000000  00000000  0000008b  2**0
                  CONTENTS, READONLY
        对比你会发现:.rodata 存放的是只读的已初始化变量,与 .data 段不同,对于有内存管理单元的系统, .rodata 段通常也会采用内存管理单元进行只读保护。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息