深入理解程序的结构

 程序是被分成段加以管理的,在程序被加载到内存中运行之前,各段是放在程序文件中的。
    当程序文件中所需的段被加载到内存中后,将通过运行指令来处理相应的数据。有些数据来源于程序文件中的段,有些是自动生成的。
1、段
    1.1、指令段
         .text 段:
              由于处理器只能识别数据和指令。所以不论采用什么高级语言编写程序,都得被编译器转化成为处理器所能识别的数据和机器指令。而编译后的机器指令都被存放在 .text 段。
              从 C 源程序角度来看,.text 段中存放的是函数的机器指令实现。
              如果处理器有内存管理单元,在可执行程序被加载到内存以后,通常会将 .text 段设置为只读,以防代码不会因为程序出错而被修改。

    1.2、数据段
         处理器所需加工的数据是放在 .data、.bss 和 .rdata 段的,也可以来自堆和栈。
         通过以下,.data 和 .bss 两个数据段所存放数据的区别:
         section1.c
  
  
  1. #include <stdio.h>
  2. int main()
  3. {
  4. return 0;
  5. }
         理结果:
[root@localhost huge12]# gcc -g -c section1.c 
[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
   
   
  1. #include <stdio.h>
  2. int a = 0x77778888
  3. int b = 0;
  4. int main()
  5. {
  6. return 0;
  7. }
         处理结果:
[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
         从处理结果:
  1.  .data 和 .bss 段有了变化,由于在 section2.c 中新增了两个变量,对于初始化不为 0 的变量存放在 .data 段对于初始化为 0 或 不初始化的全局变量存放在 .data 段
  2. .bss 段不存放在程序文件中
  3. 由于 .bss 段中的变量不需要初始化成特定值(0除外),所以不需要在程序文件中保存其内容,好处是能减小程序文件的大小而节省存储空间
  4. 对于 .data 段内数据的初始化,是引导加载器加载程序时,通过将程序文件中 .data 段的数据复制到所对应的内存地址空间,从而一次性地完成所有变量的初始化

         在一个函数内定义非静态变量(即局部变量)时,变量的内存空间是被分配在栈上的,那么加了 static 后的内存空间与全局变量是一样的。
         section3.c
   
   
  1. #include <stdio.h>
  2. int main()
  3. {
  4. static int a = 0x77778888;
  5. static int b = 0;
  6. return 0;
  7. }
         处理结果:
[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
   
   
  1. #include <stdio.h>
  2. char str[] = "hello world!";
  3. int main()
  4. {
  5. return 0;
  6. }
         处理结果:
[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做一些修改:
   
   
  1. #include <stdio.h>
  2. const char str[] = "hello world!";
  3. int main()
  4. {
  5. return 0;
  6. }
         处理结果:
[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 段通常也会采用内存管理单元进行只读保护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值