可執(zhí)行程序中的段 (C專家編程)

昨天看《C專家編程》,其中第六章第二節(jié)給出一個(gè)編程挑戰(zhàn),本來覺得是很容易的問題,結(jié)果結(jié)果出乎我的意料。廢話不多說,先看題目

查看可執(zhí)行文件終的段

  1. 編譯“Hello world”程序,在可執(zhí)行文件終執(zhí)行l(wèi)s -l,得到文件的總體大小。運(yùn)行size得到各段的大小。
  2. 增加一個(gè)全局的int[1000]數(shù)組聲明,重新編譯,再用上面的命令得到總體及各個(gè)段的大小,注意前后的區(qū)別。
  3. 現(xiàn)在,在數(shù)組的聲明中增加初始值。這將使數(shù)組從BSS段轉(zhuǎn)到數(shù)據(jù)段。重復(fù)上面的測量,注意各段前后大小的變化。

按照我之前的了解,2的BSS段會(huì)比1多4×1000=4000字節(jié),3的DATA段比1和2的多4000字節(jié)。而實(shí)際情況呢?讓我們用實(shí)驗(yàn)來看看

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個(gè)字節(jié),這是怎么回事?

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個(gè)字節(jié),這又是怎么回事?

分析

這里我把三個(gè)目標(biāo)文件用nm程序打印出詳細(xì)的段信息。

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

對(duì)比1和2,我們關(guān)注BSS段,注意上面每一行的中間,B就表示BSS段。
如下,對(duì)于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

計(jì)算0x804a024 - 0x804a020 = 4,正好是BSS的大小。

如下,對(duì)于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

計(jì)算0804afe0 - 0804a020 = 0xfc0 = 4032,也正好是BSS的大小。同時(shí)請(qǐng)注意上面另外一個(gè)符號(hào)a,其地址是0x0804a040,與__bss_start相差大小正好為0x20 = 32個(gè)字節(jié)。編譯輸出為何要預(yù)留32個(gè)字節(jié),用來干什么?

最終解決

最終問題搞清楚還是在《程序員的自我修養(yǎng)》的啟示下,里面第三章第三節(jié)使用objdump工具分析目標(biāo)文件。因此我也對(duì)1和2進(jìn)行了分析。

ch6_2_1.o:     文件格式 elf32-i386

節(jié):
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

節(jié):
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行。對(duì)于1來說,BSS段本來就沒有,只是留一個(gè)符號(hào),占用四個(gè)字節(jié),對(duì)齊方式是2^0 = 1。而對(duì)于2來說,BSS段里面有4000字節(jié)的大小,加上本來就有的4個(gè)字節(jié),就是4004字節(jié)大小。但其對(duì)齊方式是2^5 = 32,所以4004字節(jié)被擴(kuò)展成4032個(gè)字節(jié)以滿足對(duì)齊條件。究其原因?yàn)楹问?2字節(jié)對(duì)齊,應(yīng)該跟CPU的緩存機(jī)制有關(guān)吧。

關(guān)于DATA段的討論,以后再繼續(xù),但上述思路應(yīng)該是沒問題的,可以參考借鑒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 2016年國慶假期終于把此書過完,整理筆記和體會(huì)于此。 關(guān)于書名 書名源于俄羅斯的演員斯坦尼斯拉夫斯基創(chuàng)作的《演員...
    李劍飛的簡書閱讀 7,434評(píng)論 2 65
  • 一、溫故而知新 1. 內(nèi)存不夠怎么辦 內(nèi)存簡單分配策略的問題地址空間不隔離內(nèi)存使用效率低程序運(yùn)行的地址不確定 關(guān)于...
    SeanCST閱讀 8,107評(píng)論 0 27
  • 1. C++基礎(chǔ)知識(shí)點(diǎn) 1.1 有符號(hào)類型和無符號(hào)類型 當(dāng)我們賦給無符號(hào)類型一個(gè)超出它表示范圍的值時(shí),結(jié)果是初始值...
    Mr希靈閱讀 18,158評(píng)論 3 82
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,502評(píng)論 19 139
  • 前記:本文于2010年4月第一次語文考試出現(xiàn)在我等試卷。 讓我如何收集你一路散落的白發(fā),一絲一縷編織成割剪不斷的牽...
    蘇安公子閱讀 255評(píng)論 0 1

友情鏈接更多精彩內(nèi)容