可执行程序中的段 (C专家编程)

昨天看《C专家编程》,其中第六章第二节给出一个编程挑战,本来觉得是很容易的问题,结果结果出乎我的意料。废话不多说,先看题目

查看可执行文件终的段

  1. 编译“Hello world”程序,在可执行文件终执行ls -l,得到文件的总体大小。运行size得到各段的大小。
  2. 增加一个全局的int[1000]数组声明,重新编译,再用上面的命令得到总体及各个段的大小,注意前后的区别。
  3. 现在,在数组的声明中增加初始值。这将使数组从BSS段转到数据段。重复上面的测量,注意各段前后大小的变化。

按照我之前的了解,2的BSS段会比1多4×1000=4000字节,3的DATA段比1和2的多4000字节。而实际情况呢?让我们用实验来看看

hello world 1

#include <stdio.h>

int main(void)
{
    printf("Hello World!\n");
    return 0;
}
2015-11-24 23-18-28屏幕截图.png-49kB
2015-11-24 23-18-28屏幕截图.png-49kB

可以看出:

text data bss
1137 280 4

hello world 2

#include <stdio.h>

int a[1000];
int main(void)
{
    printf("Hello World!\n");
    return 0;
}
2015-11-24 23-13-47屏幕截图.png-50.7kB
2015-11-24 23-13-47屏幕截图.png-50.7kB

可以看出:

text data bss
1137 280 4032

这里BSS大小为4032,比刚开始想的还多出了28个字节,这是怎么回事?

hello world 3

#include <stdio.h>

int a[1000]={1};
int main(void)
{
    printf("Hello World!\n");
    return 0;
}
2015-11-24 23-20-30屏幕截图.png-50.2kB
2015-11-24 23-20-30屏幕截图.png-50.2kB

可以看出:

text data bss
1137 4304 4

这里DATA大小为4304,4304-280=4024,比刚开始想的还多出了24个字节,这又是怎么回事?

分析

这里我把三个目标文件用nm程序打印出详细的段信息。

yiltoncent@yiltoncent-GA-MA785GM-US2H:~/ctest/expert_c_programming_deep_c_secrets$ nm -s ch6_2_1.o
0804a020 B __bss_start
0804a020 b completed.7181
0804a018 D __data_start
0804a018 W data_start
08048360 t deregister_tm_clones
080483d0 t __do_global_dtors_aux
08049f0c t __do_global_dtors_aux_fini_array_entry
0804a01c D __dso_handle
08049f14 d _DYNAMIC
0804a020 D _edata
0804a024 B _end
080484b4 T _fini
080484c8 R _fp_hw
080483f0 t frame_dummy
08049f08 t __frame_dummy_init_array_entry
080485d4 r __FRAME_END__
0804a000 d _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
080482b0 T _init
08049f0c t __init_array_end
08049f08 t __init_array_start
080484cc R _IO_stdin_used
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
08049f10 d __JCR_END__
08049f10 d __JCR_LIST__
         w _Jv_RegisterClasses
080484b0 T __libc_csu_fini
08048450 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
0804841b T main
         U puts@@GLIBC_2.0
08048390 t register_tm_clones
08048320 T _start
0804a020 D __TMC_END__
08048350 T __x86.get_pc_thunk.bx
yiltoncent@yiltoncent-GA-MA785GM-US2H:~/ctest/expert_c_programming_deep_c_secrets$ nm -s ch6_2_2.o
0804a040 B a
0804a020 B __bss_start
0804a020 b completed.7181
0804a018 D __data_start
0804a018 W data_start
08048360 t deregister_tm_clones
080483d0 t __do_global_dtors_aux
08049f0c t __do_global_dtors_aux_fini_array_entry
0804a01c D __dso_handle
08049f14 d _DYNAMIC
0804a020 D _edata
0804afe0 B _end
080484b4 T _fini
080484c8 R _fp_hw
080483f0 t frame_dummy
08049f08 t __frame_dummy_init_array_entry
080485d4 r __FRAME_END__
0804a000 d _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
080482b0 T _init
08049f0c t __init_array_end
08049f08 t __init_array_start
080484cc R _IO_stdin_used
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
08049f10 d __JCR_END__
08049f10 d __JCR_LIST__
         w _Jv_RegisterClasses
080484b0 T __libc_csu_fini
08048450 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
0804841b T main
         U puts@@GLIBC_2.0
08048390 t register_tm_clones
08048320 T _start
0804a020 D __TMC_END__
08048350 T __x86.get_pc_thunk.bx
yiltoncent@yiltoncent-GA-MA785GM-US2H:~/ctest/expert_c_programming_deep_c_secrets$ nm -s ch6_2_3.o
0804a040 D a
0804afe0 B __bss_start
0804afe0 b completed.7181
0804a020 D __data_start
0804a020 W data_start
08048360 t deregister_tm_clones
080483d0 t __do_global_dtors_aux
08049f0c t __do_global_dtors_aux_fini_array_entry
0804a024 D __dso_handle
08049f14 d _DYNAMIC
0804afe0 D _edata
0804afe4 B _end
080484b4 T _fini
080484c8 R _fp_hw
080483f0 t frame_dummy
08049f08 t __frame_dummy_init_array_entry
080485d4 r __FRAME_END__
0804a000 d _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
080482b0 T _init
08049f0c t __init_array_end
08049f08 t __init_array_start
080484cc R _IO_stdin_used
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
08049f10 d __JCR_END__
08049f10 d __JCR_LIST__
         w _Jv_RegisterClasses 080484b0 T __libc_csu_fini
08048450 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
0804841b T main
         U puts@@GLIBC_2.0
08048390 t register_tm_clones
08048320 T _start
0804afe0 D __TMC_END__
08048350 T __x86.get_pc_thunk.bx

对比1和2,我们关注BSS段,注意上面每一行的中间,B就表示BSS段。
如下,对于1,注意__bss_start_end的地址。

yiltoncent@yiltoncent-GA-MA785GM-US2H:~/ctest/expert_c_programming_deep_c_secrets$ nm -s ch6_2_1.o
0804a020 B __bss_start
0804a020 b completed.7181
0804a018 D __data_start
0804a018 W data_start
08048360 t deregister_tm_clones
080483d0 t __do_global_dtors_aux
08049f0c t __do_global_dtors_aux_fini_array_entry
0804a01c D __dso_handle
08049f14 d _DYNAMIC
0804a020 D _edata
0804a024 B _end

计算0x804a024 - 0x804a020 = 4,正好是BSS的大小。

如下,对于2,注意__bss_start_end的地址。

yiltoncent@yiltoncent-GA-MA785GM-US2H:~/ctest/expert_c_programming_deep_c_secrets$ nm -s ch6_2_2.o
0804a040 B a
0804a020 B __bss_start
0804a020 b completed.7181
0804a018 D __data_start
0804a018 W data_start
08048360 t deregister_tm_clones
080483d0 t __do_global_dtors_aux
08049f0c t __do_global_dtors_aux_fini_array_entry
0804a01c D __dso_handle
08049f14 d _DYNAMIC
0804a020 D _edata
0804afe0 B _end

计算0804afe0 - 0804a020 = 0xfc0 = 4032,也正好是BSS的大小。同时请注意上面另外一个符号a,其地址是0x0804a040,与__bss_start相差大小正好为0x20 = 32个字节。编译输出为何要预留32个字节,用来干什么?

最终解决

最终问题搞清楚还是在《程序员的自我修养》的启示下,里面第三章第三节使用objdump工具分析目标文件。因此我也对1和2进行了分析。

ch6_2_1.o:     文件格式 elf32-i386

节:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  08048154  08048154  00000154  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  08048168  08048168  00000168  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  08048188  08048188  00000188  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     00000020  080481ac  080481ac  000001ac  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000050  080481cc  080481cc  000001cc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       0000004a  0804821c  0804821c  0000021c  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000000a  08048266  08048266  00000266  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  08048270  08048270  00000270  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rel.dyn      00000008  08048290  08048290  00000290  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.plt      00000018  08048298  08048298  00000298  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000023  080482b0  080482b0  000002b0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000040  080482e0  080482e0  000002e0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         00000192  08048320  08048320  00000320  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .fini         00000014  080484b4  080484b4  000004b4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .rodata       00000015  080484c8  080484c8  000004c8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame_hdr 0000002c  080484e0  080484e0  000004e0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     000000cc  0804850c  0804850c  0000050c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .init_array   00000004  08049f08  08049f08  00000f08  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 18 .fini_array   00000004  08049f0c  08049f0c  00000f0c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .jcr          00000004  08049f10  08049f10  00000f10  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .dynamic      000000e8  08049f14  08049f14  00000f14  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got          00000004  08049ffc  08049ffc  00000ffc  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got.plt      00000018  0804a000  0804a000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000008  0804a018  0804a018  00001018  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          00000004  0804a020  0804a020  00001020  2**0
                  ALLOC
 25 .comment      00000052  00000000  00000000  00001020  2**0
                  CONTENTS, READONLY

ch6_2_2.o:     文件格式 elf32-i386

节:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  08048154  08048154  00000154  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  08048168  08048168  00000168  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  08048188  08048188  00000188  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     00000020  080481ac  080481ac  000001ac  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000050  080481cc  080481cc  000001cc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       0000004a  0804821c  0804821c  0000021c  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000000a  08048266  08048266  00000266  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  08048270  08048270  00000270  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rel.dyn      00000008  08048290  08048290  00000290  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.plt      00000018  08048298  08048298  00000298  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000023  080482b0  080482b0  000002b0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000040  080482e0  080482e0  000002e0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         00000192  08048320  08048320  00000320  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .fini         00000014  080484b4  080484b4  000004b4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .rodata       00000015  080484c8  080484c8  000004c8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame_hdr 0000002c  080484e0  080484e0  000004e0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     000000cc  0804850c  0804850c  0000050c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .init_array   00000004  08049f08  08049f08  00000f08  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 18 .fini_array   00000004  08049f0c  08049f0c  00000f0c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .jcr          00000004  08049f10  08049f10  00000f10  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .dynamic      000000e8  08049f14  08049f14  00000f14  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got          00000004  08049ffc  08049ffc  00000ffc  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got.plt      00000018  0804a000  0804a000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000008  0804a018  0804a018  00001018  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          00000fc0  0804a020  0804a020  00001020  2**5
                  ALLOC
 25 .comment      00000052  00000000  00000000  00001020  2**0
                  CONTENTS, READONLY

注意第53行和110行。对于1来说,BSS段本来就没有,只是留一个符号,占用四个字节,对齐方式是2^0 = 1。而对于2来说,BSS段里面有4000字节的大小,加上本来就有的4个字节,就是4004字节大小。但其对齐方式是2^5 = 32,所以4004字节被扩展成4032个字节以满足对齐条件。究其原因为何是32字节对齐,应该跟CPU的缓存机制有关吧。

关于DATA段的讨论,以后再继续,但上述思路应该是没问题的,可以参考借鉴。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容