顯示具有 bss 標籤的文章。 顯示所有文章
顯示具有 bss 標籤的文章。 顯示所有文章

2025年5月9日 星期五

bss section (2) - 在 linux 下測試 bss

the 1st edition: 20120304
the 2nd edition: 20250505
env: in 32bit linux, 64 bit 似乎有點不同??

在沒有 os 的環境下搞懂 bss 有點麻煩嗎?這次提供在 os 環境下, 看看 bss。首先找出 bss 開始和結束的地方。先來看看 default linker script。

list 1. ld --verbose
  1 GNU ld (GNU Binutils for Debian) 2.22
  2   Supported emulations:
  3    elf_i386
  4    i386linux
  5    elf32_x86_64
  6    elf_x86_64
  7    elf_l1om
  8    elf_k1om
  9 using internal linker script:
 10 ==================================================
 11 /* Script for -z combreloc: combine and sort reloc sections */
 12 OUTPUT_FORMAT("elf32-i386", "elf32-i386",
 13        "elf32-i386")
 14 OUTPUT_ARCH(i386)
 15 ENTRY(_start)
 16 SEARCH_DIR("/usr/i486-linux-gnu/lib32"); SEARCH_DIR("=/usr/local/lib32"); 
SEARCH_DIR("=/lib32"); SEARCH_DIR("=/usr/lib32"); 
SEARCH_DIR("=/usr/local/lib/i386-linux-gnu"); SEARCH_DIR("=/usr/local/lib"); 
SEARCH_DIR("=/lib/i386-linux-gnu"); SEARCH_DIR("=/lib"); 
SEARCH_DIR("=/usr/lib/i386-linux-gnu"); SEARCH_DIR("=/usr/lib");
 17 SECTIONS
 18 {
 19   /* Read-only sections, merged into text segment: */
 20   PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); 
. = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS;
 21   .interp         : { *(.interp) }
 22   .note.gnu.build-id : { *(.note.gnu.build-id) }
 23   .hash           : { *(.hash) }
 24   .gnu.hash       : { *(.gnu.hash) }
 25   .dynsym         : { *(.dynsym) }
 26   .dynstr         : { *(.dynstr) }
 27   .gnu.version    : { *(.gnu.version) }
 28   .gnu.version_d  : { *(.gnu.version_d) }
 29   .gnu.version_r  : { *(.gnu.version_r) }
 30   .rel.dyn        :
 31     {
 32       *(.rel.init)
 33       *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
 34       *(.rel.fini)
 35       *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
 36       *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
 37       *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
 38       *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
 39       *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
 40       *(.rel.ctors)
 41       *(.rel.dtors)
 42       *(.rel.got)
 43       *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
 44       *(.rel.ifunc)
 45     }
 46   .rel.plt        :
 47     {
 48       *(.rel.plt)
 49       PROVIDE_HIDDEN (__rel_iplt_start = .);
 50       *(.rel.iplt)
 51       PROVIDE_HIDDEN (__rel_iplt_end = .);
 52     }
 53   .init           :
 54   {
 55     KEEP (*(.init))
 56   } =0x90909090
 57   .plt            : { *(.plt) *(.iplt) }
 58   .text           :
 59   {
 60     *(.text.unlikely .text.*_unlikely)
 61     *(.text.exit .text.exit.*)
 62     *(.text.startup .text.startup.*)
 63     *(.text.hot .text.hot.*)
 64     *(.text .stub .text.* .gnu.linkonce.t.*)
 65     /* .gnu.warning sections are handled specially by elf32.em.  */
 66     *(.gnu.warning)
 67   } =0x90909090
 68   .fini           :
 69   {
 70     KEEP (*(.fini))
 71   } =0x90909090
 72   PROVIDE (__etext = .);
 73   PROVIDE (_etext = .);
 74   PROVIDE (etext = .);
 75   .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
 76   .rodata1        : { *(.rodata1) }
 77   .eh_frame_hdr : { *(.eh_frame_hdr) }
 78   .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
 79   .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table
 80   .gcc_except_table.*) }
 81   /* These sections are generated by the Sun/Oracle C++ compiler.  */
 82   .exception_ranges   : ONLY_IF_RO { *(.exception_ranges
 83   .exception_ranges*) }
 84   /* Adjust the address for the data segment.  We want to adjust up to
 85      the same address within the page on the next page up.  */
 86   . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) 
& (CONSTANT (MAXPAGESIZE) - 1)); 
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
 87   /* Exception handling  */
 88   .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
 89   .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
 90   .exception_ranges   : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
 91   /* Thread Local Storage sections  */
 92   .tdata   : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
 93   .tbss    : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
 94   .preinit_array     :
 95   {
 96     PROVIDE_HIDDEN (__preinit_array_start = .);
 97     KEEP (*(.preinit_array))
 98     PROVIDE_HIDDEN (__preinit_array_end = .);
 99   }
100   .init_array     :
101   {
102     PROVIDE_HIDDEN (__init_array_start = .);
103     KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
104     KEEP (*(.init_array))
105     KEEP (*(EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
106     PROVIDE_HIDDEN (__init_array_end = .);
107   }
108   .fini_array     :
109   {
110     PROVIDE_HIDDEN (__fini_array_start = .);
111     KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
112     KEEP (*(.fini_array))
113     KEEP (*(EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
114     PROVIDE_HIDDEN (__fini_array_end = .);
115   }
116   .ctors          :
117   {
118     /* gcc uses crtbegin.o to find the start of
119        the constructors, so we make sure it is
120        first.  Because this is a wildcard, it
121        doesn't matter if the user does not
122        actually link against crtbegin.o; the
123        linker won't look for a file to match a
124        wildcard.  The wildcard also means that it
125        doesn't matter which directory crtbegin.o
126        is in.  */
127     KEEP (*crtbegin.o(.ctors))
128     KEEP (*crtbegin?.o(.ctors))
129     /* We don't want to include the .ctor section from
130        the crtend.o file until after the sorted ctors.
131        The .ctor section from the crtend file contains the
132        end of ctors marker and it must be last */
133     KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
134     KEEP (*(SORT(.ctors.*)))
135     KEEP (*(.ctors))
136   }
137   .dtors          :
138   {
139     KEEP (*crtbegin.o(.dtors))
140     KEEP (*crtbegin?.o(.dtors))
141     KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
142     KEEP (*(SORT(.dtors.*)))
143     KEEP (*(.dtors))
144   }
145   .jcr            : { KEEP (*(.jcr)) }
146   .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) 
*(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
147   .dynamic        : { *(.dynamic) }
148   .got            : { *(.got) *(.igot) }
149   . = DATA_SEGMENT_RELRO_END (12, .);
150   .got.plt        : { *(.got.plt)  *(.igot.plt) }
151   .data           :
152   {
153     *(.data .data.* .gnu.linkonce.d.*)
154     SORT(CONSTRUCTORS)
155   }
156   .data1          : { *(.data1) }
157   _edata = .; PROVIDE (edata = .);
158   __bss_start = .;
159   .bss            :
160   {
161    *(.dynbss)
162    *(.bss .bss.* .gnu.linkonce.b.*)
163    *(COMMON)
164    /* Align here to ensure that the .bss section occupies space up to
165       _end.  Align after .bss to ensure correct alignment even if the
166       .bss section disappears because there are no input sections.
167       FIXME: Why do we need it? When there is no .bss section, we don't
168       pad the .data section.  */
169    . = ALIGN(. != 0 ? 32 / 8 : 1);
170   }
171   . = ALIGN(32 / 8);
172   . = ALIGN(32 / 8);
173   _end = .; PROVIDE (end = .);
174   . = DATA_SEGMENT_END (.);
175   /* Stabs debugging sections.  */
176   .stab          0 : { *(.stab) }
177   .stabstr       0 : { *(.stabstr) }
178   .stab.excl     0 : { *(.stab.excl) }
179   .stab.exclstr  0 : { *(.stab.exclstr) }
180   .stab.index    0 : { *(.stab.index) }
181   .stab.indexstr 0 : { *(.stab.indexstr) }
182   .comment       0 : { *(.comment) }
183   /* DWARF debug sections.
184      Symbols in the DWARF debugging sections are relative to the beginning
185      of the section so we begin them at 0.  */
186   /* DWARF 1 */
187   .debug          0 : { *(.debug) }
188   .line           0 : { *(.line) }
189   /* GNU DWARF 1 extensions */
190   .debug_srcinfo  0 : { *(.debug_srcinfo) }
191   .debug_sfnames  0 : { *(.debug_sfnames) }
192   /* DWARF 1.1 and DWARF 2 */
193   .debug_aranges  0 : { *(.debug_aranges) }
194   .debug_pubnames 0 : { *(.debug_pubnames) }
195   /* DWARF 2 */
196   .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
197   .debug_abbrev   0 : { *(.debug_abbrev) }
198   .debug_line     0 : { *(.debug_line) }
199   .debug_frame    0 : { *(.debug_frame) }
200   .debug_str      0 : { *(.debug_str) }
201   .debug_loc      0 : { *(.debug_loc) }
202   .debug_macinfo  0 : { *(.debug_macinfo) }
203   /* SGI/MIPS DWARF 2 extensions */
204   .debug_weaknames 0 : { *(.debug_weaknames) }
205   .debug_funcnames 0 : { *(.debug_funcnames) }
206   .debug_typenames 0 : { *(.debug_typenames) }
207   .debug_varnames  0 : { *(.debug_varnames) }
208   /* DWARF 3 */
209   .debug_pubtypes 0 : { *(.debug_pubtypes) }
210   .debug_ranges   0 : { *(.debug_ranges) }
211   .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
212   /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
213 }
214 
215 
216 ==================================================

我知道很長, 我和你一樣大部份有看沒有懂, 只看 list 1. L158 ~ L173 就好。

158   __bss_start = .;
159   .bss            :
160   {
161    *(.dynbss)
162    *(.bss .bss.* .gnu.linkonce.b.*)
163    *(COMMON)
164    /* Align here to ensure that the .bss section occupies space up to
165       _end.  Align after .bss to ensure correct alignment even if the
166       .bss section disappears because there are no input sections.
167       FIXME: Why do we need it? When there is no .bss section, we don't
168       pad the .data section.  */
169    . = ALIGN(. != 0 ? 32 / 8 : 1);
170   }
171   . = ALIGN(32 / 8);
172   . = ALIGN(32 / 8);
173   _end = .; PROVIDE (end = .);

_end, __bss_start 這兩個 symbol 就是 bss section 的開始和結束。先來看看程式執行結果。

i: 0x8049734
i: 0x8049738
&__bss_start: 0x8049734
&_end: 0x804973c
ABCDEF: 11223344

bss 從  0x8049734 ~ 0x804973c 佔了 8 byte。

b.c L3 ABCDEF 不是預期的 0。表示成功改變 bss 這個區域。這應該簡單多了, 而且也可以馬上在 linux 上實驗。

另外有的人可能會因為 b.c L3 的寫法好像沒給變數初值, 改用 L4 的寫法, 指定了 0 就以為是以 0 為初值, 在這個例子上, 就算這樣寫, ABCDEF 一樣是 11223344。

b.s int ABCDED=0;
        .text
        .globl  ABCDEF
        .bss
        .align 4
        .type   ABCDEF, @object
        .size   ABCDEF, 4
ABCDEF:
        .zero   4

有趣的是, 如果是給 1, int ABCDEF = 1; 則 ABCDEF 的初值就還是1, 因為這時候 ABCDEF 就不放在 bss section 而是放在 data section。

b.s int ABCDEF=1;
        .text
        .globl  ABCDEF
        .data
        .align 4
        .type   ABCDEF, @object
        .size   ABCDEF, 4
ABCDEF:
        .long   1

b.c
 1 #include <stdio.h>
 2 
 3 int ABCDEF;
 4 //int ABCDEF = 0;
 5 extern int _end;
 6 extern int __bss_start;
 7 
 8 void fill_bss(void)
 9 {
10   int *i=0;
11   for (i = &__bss_start ; i != &_end ; ++i)
12   {
13     printf("i: %p\n", i);
14     *i = 0x11223344;
15   }
16 
17 }
18 
19 int main(void)
20 {
21   fill_bss();
22   printf("&__bss_start: %p\n", &__bss_start);
23   printf("&_end: %p\n", &_end);
24   printf("ABCDEF: %x\n", ABCDEF);
25   return 0;
26 }

看看 elf 裡頭的資訊:
[26] .bss NOBITS 08049734 000734 000008 00  WA  0   0  4
63: 08049738     4 OBJECT  GLOBAL DEFAULT   26 ABCDEF
bss 佔 8 byte, ABCDEF 則位於 0x08049738

source code:
git clone git@github.com:descent/progs.git'
cd bss

ref:
linux kernel 完全剖析 (3.5.4 p 96)

2016年12月14日 星期三

bss section (1)

the 1st edition: 20120229 (3)
the 2nd edition: 20161214 (3)

之前在《bss section (0)》留下來的問題要在這篇解答。

先來看看 b.c, 這程式很簡單, b.c L6 int i; 會放在 bss, p() 會把 c=i+1 用 itoa() 轉成 string 印出。預期得到 1, 因為在 C 中, 教科書都告訴我們 int i; 雖然沒有初值, 但 c 會初始為 0, 這不是憑空得來的, 裡頭有魔法, 讓我們來惡搞一下 bss 吧!

這是 bare-metal 程式, 和一般程式的編譯以及執行方式有些不同。

b.c
 1 asm(".code16gcc\n");
 2 
 3 typedef unsigned char u8;
 4 typedef unsigned int u32;
 5 
 6 int i;
 7 char* itoa(int n, char* str);
 8 
 9 void print(const char   *s)
10 {
11   while(*s)
12   {
13     __asm__ __volatile__ ("int  $0x10" : : "a"(0x0E00 | *s), "b"(7)); 
14     s++;
15   }
16 }
17 
18 int p()
19 {
20   int c=i+1;
21   char arr[6]="a";
22   char *s = arr;
23   
24   //const char *str="test";
25   //volatile u8 *video_addr = (u8*)0xB8000;
26   //asm("movw $0xb000 %gs");
27   //*video_addr = 'a';
28   s = itoa(c, s);
29   print(s);
30   return c;
31 }
32 
33 #if 1
34 char* itoa(int n, char* str)
35 {
36   char digit[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
37   char* p=str;
38   char* head=str;
39   int radix = 10;
40 
41 //  if(!p || radix < 2 || radix > 36)
42 //    return p;
43   if (n==0)
44   {
45     *p++='0';
46     *p=0;
47     return str;
48   }
50   if (radix == 10 && n < 0)
51   {
52     *p++='-';
53     n= -n;
54   }
56   while(n)
57   {
58     *p++=digit[n%radix];
59     n/=radix;
60   }
61   *p=0;
63   for (--p; head < p ; ++head, --p)
64   {
65     char temp=*head;
66     *head=*p;
67     *p=temp;
68   }
70   return str;
71 }
72 #endif
73 

c_init.s
 1 .code16
 2 .extern __bss_start__
 3 .extern __bss_end__
 4 
 5 .text
 6 .global _start
 7 _start:
 8   mov %cs, %ax
 9   mov %ax, %ds
10   mov %ax, %es
11 
12 # setup stack
13   mov %ax, %ss
14   mov $0xffff, %sp
15 
16 #  call disp_str
17   call init_bss_asm
18   call p
19 #  call disp_str2
20   jmp .
41 
42 
43 # init bss
44 init_bss_asm:
45   movw $__bss_end__, %di    /* Destination */
46   movw $__bss_start__, %si   /* Source */
47   movw $0x0, %ax
48   movw %ax, %gs
49   jmp 2f
50 1:
51   movw %si, %ax
52   movb $0x1, %gs:(%eax)
53   add $1, %si
54   
55 2:
56   cmpw %di, %si
57   jne 1b
58   ret
59 

編譯/執行方式
as --32 -o c_init.o c_init.s
gcc -std=c99 -fno-stack-protector -m32 -ffreestanding -fno-builtin -g -Iinclude -I../include -fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables -Os -c b.c
ld -m elf_i386 -nostdlib -g -o c_init.elf -Tbss.lds c_init.o b.o 
objcopy -R .pdr -R .comment -R.note -S -O binary c_init.elf c_init.bin

c_init.bin 為要執行的 bin 檔

dd if=c_init.bin of=boot.img bs=512 count=1
dd if=/dev/zero of=boot.img skip=1 seek=1 bs=512 count=2879

透過 qemu 執行
qemu-system-i386 -fda boot.img 

由 c_init.s _start 開始執行, 執行 init_bss_asm 呼叫 p(), p() 把 i+1 印出來。i 位於 bss, 所以應該看到 1 被印出來 (fig 1), 不過執行結果是 16843010, 怎麼不是 1, 我又搞錯了嗎? 非也, 這是刻意營造的結果, 我把 bss 初始為 0x01010101 , 加上 0x1 後為 0x01010102 = 十進位 16843010。 因為受限於開機磁區的 512 byte 限制, 所以編譯這段程式碼需要加上 -Os, 讓它可以小於 512 byte。

我加入以下選項, 讓 gcc 不要產生 .eh_frame section, .eh_frame section 對 bare-metal 用處不大, 還佔了 0x8c 的空間。

-fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables
.eh_frame, .eh_frame_hdr -

ref: how to remove that trash

之前用 gcc 4.x 好像不會產生 .eh_frame section, 這次用 gcc 5.4 就需要這些選項來避免產生 .eh_frame section。

fig 1

初始化 bss, c_init.s L17 call init_bss_asm 把 0x1 copy 到這個 bss 區域 (c_init.s L52), bss 開頭和結束可由 Linker Scripts 得知, bss.lds L18, L23 可以看到 __bss_start__, __bss_end__, 這就是 c_init.s 用到的那兩個變數, 神奇吧!「還可以這樣用的哦!」gnu toolchain 實在太 ... 厲害了。當然在 Linker Scripts 直接指定一個位址也可以, 不過這樣用比較帥 (帥阿! 老皮), 也比較方便。

bss 區的變數不會存放在執行檔裡, 需要靠 c runtime library 來初始化, 我們能痛快的使用這些變數, 便是這些初始化程式碼的功勞。

沒有初始值或是初始值為 0 的 static, global 變數, 就是放在 bss。

bss.lds
 1 ENTRY(_start)
 2 
 3 SECTIONS
 4 {
 5   . = 0x7c00;
 6   .text :
 7   {
 8     *(.text)
 9   }
10   .= ALIGN(32);
11 
12   .data :
13   {
14     *(.data)
15   }
16 
17   .= ALIGN(32);
18   __bss_start__ =.;
19   .bss :
20   {
21     *(.bss)
22   }
23   __bss_end__ = .;
24 
25   .sig : AT(0x7DFE)
26   {
27     SHORT(0xaa55);
28   }
29 /*
30   .asig : AT(0x7e50)
31   {
32     SHORT(0xefab);
33   }
34   .bsig : AT(0x7f50)
35   {
36     SHORT(0xefab);
37   }
38 */
39     /DISCARD/ :
40     {
41         *(.note*);
42         *(.iplt*);
43         *(.igot*);
44         *(.rel*);
45         *(.comment);
46 /* add any unwanted sections spewed out by your version of gcc and flags here */
47     }
48 
49 }

list 5 L88 i 為於 0x7d60, 而 list 5 L27 指出的 .bss 從 0x7d60 開始, 總共 4 byte, 剛好就是 i 的位址。

0x7d60 位於 .bss 區, 長度4 byte, 自然就是 int i 佔據的大小。若你不相信, 把 bochs run 一次, 反組譯後就可得証。

list 5. readelf -a c_init.elf
 1 ELF Header:
 2   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
 3   Class:                             ELF32
 4   Data:                              2's complement, little endian
 5   Version:                           1 (current)
 6   OS/ABI:                            UNIX - System V
 7   ABI Version:                       0
 8   Type:                              EXEC (Executable file)
 9   Machine:                           Intel 80386
10   Version:                           0x1
11   Entry point address:               0x7c00
12   Start of program headers:          52 (bytes into file)
13   Start of section headers:          5692 (bytes into file)
14   Flags:                             0x0
15   Size of this header:               52 (bytes)
16   Size of program headers:           32 (bytes)
17   Number of program headers:         3
18   Size of section headers:           40 (bytes)
19   Number of section headers:         16
20   Section header string table index: 13
21 
22 Section Headers:
23   [Nr] Name           Type      Addr     Off    Size   ES Flg Lk Inf Al
24   [ 0]                NULL      00000000 000000 000000 00      0   0  0
25   [ 1] .text          PROGBITS  00007c00 000c00 000138 00  AX  0   0  1
26   [ 2] .rodata.str1.1 PROGBITS  00007d38 000d38 000025 01 AMS  0   0  1
27   [ 3] .bss           NOBITS    00007d60 000d5d 000004 00  WA  0   0  4
28   [ 4] .sig           PROGBITS  00007d64 000d64 000002 00  WA  0   0  1
29   [ 5] .debug_info    PROGBITS  00000000 000d66 00017e 00      0   0  1
30   [ 6] .debug_abbrev  PROGBITS  00000000 000ee4 000128 00      0   0  1
31   [ 7] .debug_loc     PROGBITS  00000000 00100c 000162 00      0   0  1
32   [ 8] .debug_aranges PROGBITS  00000000 00116e 000020 00      0   0  1
33   [ 9] .debug_ranges  PROGBITS  00000000 00118e 000018 00      0   0  1
34   [10] .debug_line    PROGBITS  00000000 0011a6 00007c 00      0   0  1
35   [11] .debug_str     PROGBITS  00000000 001222 000131 01  MS  0   0  1
36   [12] .debug_frame   PROGBITS  00000000 001354 00008c 00      0   0  4
37   [13] .shstrtab      STRTAB    00000000 00159b 0000a0 00      0   0  1
38   [14] .symtab        SYMTAB    00000000 0013e0 000170 10     15  16  4
39   [15] .strtab        STRTAB    00000000 001550 00004b 00      0   0  1
40 Key to Flags:
41   W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
42   L (link order), O (extra OS processing required), G (group), T (TLS),
43   C (compressed), x (unknown), o (OS specific), E (exclude),
44   p (processor specific)
45 
46 There are no section groups in this file.
47 
48 Program Headers:
49   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
50   LOAD           0x000000 0x00007000 0x00007000 0x00d5d 0x00d64 RWE 0x1000
51   LOAD           0x000d64 0x00007d64 0x00007dfe 0x00002 0x00002 RW  0x1000
52   GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10
53 
54  Section to Segment mapping:
55   Segment Sections...
56    00     .text .rodata.str1.1 .bss 
57    01     .sig 
58    02     
59 
60 There is no dynamic section in this file.
61 
62 There are no relocations in this file.
63 
64 The decoding of unwind sections for machine type Intel 80386 is not currently supported.
65 
66 Symbol table '.symtab' contains 23 entries:
67    Num:    Value  Size Type    Bind   Vis      Ndx Name
68      0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
69      1: 00007c00     0 SECTION LOCAL  DEFAULT    1 
70      2: 00007d38     0 SECTION LOCAL  DEFAULT    2 
71      3: 00007d60     0 SECTION LOCAL  DEFAULT    3 
72      4: 00007d64     0 SECTION LOCAL  DEFAULT    4 
73      5: 00000000     0 SECTION LOCAL  DEFAULT    5 
74      6: 00000000     0 SECTION LOCAL  DEFAULT    6 
75      7: 00000000     0 SECTION LOCAL  DEFAULT    7 
76      8: 00000000     0 SECTION LOCAL  DEFAULT    8 
77      9: 00000000     0 SECTION LOCAL  DEFAULT    9 
78     10: 00000000     0 SECTION LOCAL  DEFAULT   10 
79     11: 00000000     0 SECTION LOCAL  DEFAULT   11 
80     12: 00000000     0 SECTION LOCAL  DEFAULT   12 
81     13: 00000000     0 FILE    LOCAL  DEFAULT  ABS c_init.o
82     14: 00007c13     0 NOTYPE  LOCAL  DEFAULT    1 init_bss_asm
83     15: 00000000     0 FILE    LOCAL  DEFAULT  ABS b.c
84     16: 00007c2f    36 FUNC    GLOBAL DEFAULT    1 print
85     17: 00007cf5    67 FUNC    GLOBAL DEFAULT    1 p
86     18: 00007d60     0 NOTYPE  GLOBAL DEFAULT    3 __bss_start__
87     19: 00007c53   162 FUNC    GLOBAL DEFAULT    1 itoa
88     20: 00007d60     4 OBJECT  GLOBAL DEFAULT    3 i
89     21: 00007d64     0 NOTYPE  GLOBAL DEFAULT    3 __bss_end__
90     22: 00007c00     0 NOTYPE  GLOBAL DEFAULT    1 _start
91 
92 No version information found in this file.

以上為 x86 真實模式下的 bss 環境。那麼在 x86 保護模式下呢? 原理是一樣的, 就算是 arm 也是一樣, 只是切入保護模式後 segment register 要改用 selector, 確認使用的 selector:offset 是 bss 區域即可。這說來簡單, 我可花了不少時間才搞清楚:
  1. selector:offset
  2. 程式整個載入位址
  3. 整個程式的定址空間
用組合語言來初始化 bss 不太好, 我後來寫了 c 語言的版本, 可攜性較高。在 OS 環境的庇護下寫程式, 真是很幸福, 不需要知道很多事情; 也很不幸, 因為有很多事情被遮蔽起來, 讓我們無法了解細節。

ref:

2012年8月17日 星期五

bss initialize issue

different g++ version - different global object ctor implementation ~^.^~ g++ 4.4, 4.6, 4.7 最後提到的問題終於解決了。

一直以為把 init .bss section 搞定了, 結果那段 code 有很大的問題。

a.asm
 1 # init bss
 2 init_bss_asm:
 3   movw $__bss_end__, %di    /* Destination */
 4   movw $__bss_start__, %si   /* Source */
 5   movw %ds, %bx
 6   movw %bx, %es
 7   jmp 2f
 8 1:
 9   mov $0, %eax
10   movw %si, %ax
11   movb $0x0, %es:(%eax)
12   add $1, %si
13 
14 
15   # wait key
16 #  xor %eax,%eax
17 #  int $0x16
18 
19 
20 2:
21   cmpw %di, %si
22   jne 1b
23 
24   ret
25 
26 

10   movw %si, %ax
11   movb $0x0, %es:(%eax)

沒有注意到 eax 可能會是 0x1234%si 這樣的值, 單純的以為會是 0x0000%si, 補上
 
 9   mov $0, %eax

就搞定了。好啦!我知道這樣很遜, 有個  movxx 的指令一行就搞定, 就查不到妹 ...

那你可能有疑問? 為什麼不寫成

10   movw %si, %ax
11   movb $0x0, %es:(%ax)

就好了。

因為 gas 不讓這樣的寫法通過。 原因: 不知道。

g++ -static -m32  -g -Wall -Wextra -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -fno-exceptions -fno-rtti -fno-stack-protector -c cpp_init.s
cpp_init.S: Assembler messages:
cpp_init.S:129: Error: `%es:(%ax)' is not a valid base/index expression
make: *** [cpp_init.o] Error 1

不懂 ...

除了使用 linker script 還可以在 ld 命令列指定 bss, data, text 的位址。

man ld
   --section-start=sectionname=org
           Locate a section in the output file at the absolute address given by
           org.  You may use this option as many times as necessary to locate
           multiple sections in the command line.  org must be a single 
           hexadecimal integer; for compatibility with other linkers, 
           you may omit the leading 0x usually associated with 
           hexadecimal values.  Note: there should be no white space 
           between sectionname, the equals sign ("="), and org.
   -Tbss=org
       -Tdata=org
       -Ttext=org
           Same as --section-start, with ".bss", ".data" or ".text" as 
           the sectionname.

2012年2月17日 星期五

bss section (0)

the 1st edition: 20120217 (5)
the 2nd edition: 20161215 (4)

bss.c
1 int i;
2 
3 int main(void)
4 {
5   i = 1;
6   return 0;
7 }

gcc -g -o bss bss.c

list 0 L128 ~ 130
128   i = 1;
129  80483d7: c7 05 18 a0 04 08 01  movl   $0x1,0x804a018
130  80483de: 00 00 00

i 變數會放在 bss section, 而在 linux 下, 這個 bss 位址為 0804a018, 所以 int = 1 就是把 1 寫 4 byte (00 00 00 01) 到 0804a018 這裡就對了。

list 0. objdump -dS bss
  1
  2 bss:     file format elf32-i386
  3
  4
  5 Disassembly of section .init:
  6

121 080483d4 <main>:
122 int i;
123
124 int main(void)
125 {
126  80483d4: 55                    push   %ebp
127  80483d5: 89 e5                 mov    %esp,%ebp
128   i = 1;
129  80483d7: c7 05 18 a0 04 08 01  movl   $0x1,0x804a018
130  80483de: 00 00 00
131   return 0;
132  80483e1: b8 00 00 00 00        mov    $0x0,%eax
133 }

list 1. L50, L208

 50  [26] .bss   NOBITS  0804a010 001010 00000c 00  WA  0   0  4
208  69: 0804a018  4 OBJECT  GLOBAL DEFAULT   26 i

bss section 始於 0804a010 長度為 c, L 208 指出變數 i 位址為 0804a018, 和上述的組合語言程式碼相呼應。

list 1. readelf -a bss
  1 ELF Header:
  2   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  3   Class:                             ELF32
  4   Data:                              2's complement, little endian
  5   Version:                           1 (current)
  6   OS/ABI:                            UNIX - System V
  7   ABI Version:                       0
  8   Type:                              EXEC (Executable file)
  9   Machine:                           Intel 80386
 10   Version:                           0x1
 11   Entry point address:               0x8048320
 12   Start of program headers:          52 (bytes into file)
 13   Start of section headers:          4932 (bytes into file)
 14   Flags:                             0x0
 15   Size of this header:               52 (bytes)
 16   Size of program headers:           32 (bytes)
 17   Number of program headers:         9
 18   Size of section headers:           40 (bytes)
 19   Number of section headers:         39
 20   Section header string table index: 36
 21
 22 Section Headers:
 23   [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
 24   [ 0]                   NULL            00000000 000000 000000 00      0   0  0
 25   [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
 26   [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
 27   [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
 28   [ 4] .hash             HASH            080481ac 0001ac 000024 04   A  6   0  4
 29   [ 5] .gnu.hash         GNU_HASH        080481d0 0001d0 000020 04   A  6   0  4
 30   [ 6] .dynsym           DYNSYM          080481f0 0001f0 000040 10   A  7   1  4
 31   [ 7] .dynstr           STRTAB          08048230 000230 000045 00   A  0   0  1
 32   [ 8] .gnu.version      VERSYM          08048276 000276 000008 02   A  6   0  2
 33   [ 9] .gnu.version_r    VERNEED         08048280 000280 000020 00   A  7   1  4
 34   [10] .rel.dyn          REL             080482a0 0002a0 000008 08   A  6   0  4
 35   [11] .rel.plt          REL             080482a8 0002a8 000010 08   A  6  13  4
 36   [12] .init             PROGBITS        080482b8 0002b8 000030 00  AX  0   0  4
 37   [13] .plt              PROGBITS        080482f0 0002f0 000030 04  AX  0   0 16
 38   [14] .text             PROGBITS        08048320 000320 00016c 00  AX  0   0 16
 39   [15] .fini             PROGBITS        0804848c 00048c 00001c 00  AX  0   0  4
 40   [16] .rodata           PROGBITS        080484a8 0004a8 000008 00   A  0   0  4
 41   [17] .eh_frame_hdr     PROGBITS        080484b0 0004b0 000014 00   A  0   0  4
 42   [18] .eh_frame         PROGBITS        080484c4 0004c4 000040 00   A  0   0  4
 43   [19] .ctors            PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4
 44   [20] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
 45   [21] .jcr              PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4
 46   [22] .dynamic          DYNAMIC         08049f20 000f20 0000d0 08  WA  7   0  4
 47   [23] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
 48   [24] .got.plt          PROGBITS        08049ff4 000ff4 000014 04  WA  0   0  4
 49   [25] .data             PROGBITS        0804a008 001008 000008 00  WA  0   0  4
 50   [26] .bss              NOBITS          0804a010 001010 00000c 00  WA  0   0  4
 51   [27] .comment          PROGBITS        00000000 001010 000023 01  MS  0   0  1
 52   [28] .debug_aranges    PROGBITS        00000000 001033 000020 00      0   0  1
 53   [29] .debug_pubnames   PROGBITS        00000000 001053 000021 00      0   0  1
 54   [30] .debug_info       PROGBITS        00000000 001074 000056 00      0   0  1
 55   [31] .debug_abbrev     PROGBITS        00000000 0010ca 000047 00      0   0  1
 56   [32] .debug_line       PROGBITS        00000000 001111 000036 00      0   0  1
 57   [33] .debug_frame      PROGBITS        00000000 001148 00002c 00      0   0  4
 58   [34] .debug_str        PROGBITS        00000000 001174 00003e 01  MS  0   0  1
 59   [35] .debug_loc        PROGBITS        00000000 0011b2 00002c 00      0   0  1
 60   [36] .shstrtab         STRTAB          00000000 0011de 000164 00      0   0  1
 61   [37] .symtab           SYMTAB          00000000 00195c 0004a0 10     38  54  4
 62   [38] .strtab           STRTAB          00000000 001dfc 0001eb 00      0   0  1
 63 Key to Flags:
 64   W (write), A (alloc), X (execute), M (merge), S (strings)
 65   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
 66   O (extra OS processing required) o (OS specific), p (processor specific)
 67
137 Symbol table '.symtab' contains 74 entries:
138    Num:    Value  Size Type    Bind   Vis      Ndx Name
139      0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
140      1: 08048154     0 SECTION LOCAL  DEFAULT    1
141      2: 08048168     0 SECTION LOCAL  DEFAULT    2
142      3: 08048188     0 SECTION LOCAL  DEFAULT    3
143      4: 080481ac     0 SECTION LOCAL  DEFAULT    4
144      5: 080481d0     0 SECTION LOCAL  DEFAULT    5
145      6: 080481f0     0 SECTION LOCAL  DEFAULT    6
146      7: 08048230     0 SECTION LOCAL  DEFAULT    7
147      8: 08048276     0 SECTION LOCAL  DEFAULT    8
148      9: 08048280     0 SECTION LOCAL  DEFAULT    9
149     10: 080482a0     0 SECTION LOCAL  DEFAULT   10
150     11: 080482a8     0 SECTION LOCAL  DEFAULT   11
151     12: 080482b8     0 SECTION LOCAL  DEFAULT   12
152     13: 080482f0     0 SECTION LOCAL  DEFAULT   13
153     14: 08048320     0 SECTION LOCAL  DEFAULT   14
154     15: 0804848c     0 SECTION LOCAL  DEFAULT   15
155     16: 080484a8     0 SECTION LOCAL  DEFAULT   16
156     17: 080484b0     0 SECTION LOCAL  DEFAULT   17
157     18: 080484c4     0 SECTION LOCAL  DEFAULT   18
158     19: 08049f0c     0 SECTION LOCAL  DEFAULT   19
159     20: 08049f14     0 SECTION LOCAL  DEFAULT   20
160     21: 08049f1c     0 SECTION LOCAL  DEFAULT   21
161     22: 08049f20     0 SECTION LOCAL  DEFAULT   22
162     23: 08049ff0     0 SECTION LOCAL  DEFAULT   23
163     24: 08049ff4     0 SECTION LOCAL  DEFAULT   24
164     25: 0804a008     0 SECTION LOCAL  DEFAULT   25
165     26: 0804a010     0 SECTION LOCAL  DEFAULT   26
166     27: 00000000     0 SECTION LOCAL  DEFAULT   27
167     28: 00000000     0 SECTION LOCAL  DEFAULT   28
168     29: 00000000     0 SECTION LOCAL  DEFAULT   29
169     30: 00000000     0 SECTION LOCAL  DEFAULT   30
170     31: 00000000     0 SECTION LOCAL  DEFAULT   31
171     32: 00000000     0 SECTION LOCAL  DEFAULT   32
172     33: 00000000     0 SECTION LOCAL  DEFAULT   33
173     34: 00000000     0 SECTION LOCAL  DEFAULT   34
174     35: 00000000     0 SECTION LOCAL  DEFAULT   35
175     36: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
176     37: 08049f0c     0 OBJECT  LOCAL  DEFAULT   19 __CTOR_LIST__
177     38: 08049f14     0 OBJECT  LOCAL  DEFAULT   20 __DTOR_LIST__
178     39: 08049f1c     0 OBJECT  LOCAL  DEFAULT   21 __JCR_LIST__
179     40: 08048350     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
180     41: 0804a010     1 OBJECT  LOCAL  DEFAULT   26 completed.7021
181     42: 0804a014     4 OBJECT  LOCAL  DEFAULT   26 dtor_idx.7023
182     43: 080483b0     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
183     44: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
184     45: 08049f10     0 OBJECT  LOCAL  DEFAULT   19 __CTOR_END__
185     46: 08048500     0 OBJECT  LOCAL  DEFAULT   18 __FRAME_END__
186     47: 08049f1c     0 OBJECT  LOCAL  DEFAULT   21 __JCR_END__
187     48: 08048460     0 FUNC    LOCAL  DEFAULT   14 __do_global_ctors_aux
188     49: 00000000     0 FILE    LOCAL  DEFAULT  ABS bss.c
189     50: 08049f0c     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_end
190     51: 08049f20     0 OBJECT  LOCAL  DEFAULT   22 _DYNAMIC
191     52: 08049f0c     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_start
192     53: 08049ff4     0 OBJECT  LOCAL  DEFAULT   24 _GLOBAL_OFFSET_TABLE_
193     54: 080483f0     5 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
194     55: 0804845a     0 FUNC    GLOBAL HIDDEN    14 __i686.get_pc_thunk.bx
195     56: 0804a008     0 NOTYPE  WEAK   DEFAULT   25 data_start
196     57: 0804a010     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
197     58: 0804848c     0 FUNC    GLOBAL DEFAULT   15 _fini
198     59: 08049f18     0 OBJECT  GLOBAL HIDDEN    20 __DTOR_END__
199     60: 0804a008     0 NOTYPE  GLOBAL DEFAULT   25 __data_start
200     61: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
201     62: 0804a00c     0 OBJECT  GLOBAL HIDDEN    25 __dso_handle
202     63: 080484ac     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
203     64: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
204     65: 08048400    90 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
205     66: 0804a01c     0 NOTYPE  GLOBAL DEFAULT  ABS _end
206     67: 08048320     0 FUNC    GLOBAL DEFAULT   14 _start
207     68: 080484a8     4 OBJECT  GLOBAL DEFAULT   16 _fp_hw
208     69: 0804a018     4 OBJECT  GLOBAL DEFAULT   26 i
209     70: 0804a010     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
210     71: 080483d4    20 FUNC    GLOBAL DEFAULT   14 main
211     72: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
212     73: 080482b8     0 FUNC    GLOBAL DEFAULT   12 _init
213
214 Histogram for bucket list length (total of 3 buckets):
215  Length  Number     % of total  Coverage
216       0  0          (  0.0%)
217       1  3          (100.0%)    100.0%
218

那 bss 區域怎麼來呢? 在作業系統裡頭有作業系統幫忙處理, 若程式不是由作業系統載入, 而是全部都要自己來要怎麼辦? 由誰來初始化呢? 若是沒有 bss 區域, 用了放在 bss 裡頭的變數, 那會怎樣?

我還在研究中 ...
bss section (1)》有了答案。

ref: linux c 編程 - 一站式學習 (p 237)