Question

Wikipedia mentions that "the bss section typically includes all uninitialized variables declared at file scope." Given the following file:

int uninit;

int main() {
    uninit = 1;
    return 0;
}

When I compile this to an executable I see the bss segment filled properly:

$ gcc prog1.c -o prog1
$ size prog1
text       data     bss     dec     hex filename
1115        552       8    1675     68b prog1

However if I compile it as an object file I don't see the bss segment (I'd expect it to be 4):

$ gcc -c prog1.c
$ size prog1.o 
text       data     bss     dec     hex filename
  72          0       0      72      48 prog1.o

Is there something obvious I am missing?

I am using gcc version 4.8.1.

Was it helpful?

Solution

If we use readelf -s to look at the symbol table, we'll see:

$ readelf -s prog1.o

Symbol table '.symtab' contains 10 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS bss.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     8: 0000000000000004     4 OBJECT  GLOBAL DEFAULT  COM uninit      <<<<
     9: 0000000000000000    16 FUNC    GLOBAL DEFAULT    1 main

We see that your uninit symbol ("variable") is, at this stage, a "common" symbol. It has not yet been "assigned" to the BSS.

See this question for more information on "common" symbols: What does "COM" means in the Ndx column of the .symtab section?

Once your final executable is linked together, it will be put in the BSS as you expected.


You can bypass this behavior by passing the -fno-common flag to GCC:

$ gcc -fno-common -c bss.c
$ size bss.o
   text    data     bss     dec     hex filename
     72       0       4      76      4c bss.o

Instead, you could mark uninit as static. This way, the compiler will know that no other .o file can refer to it, so it will not be a "common" symbol. Instead, it will be placed into the BSS immediately, as you expected:

$ cat bss.c
static int uninit;

int main() {
    uninit = 1;
    return 0;
}
$ gcc -c bss.c 
$ size bss.o
   text    data     bss     dec     hex filename
     72       0       4      76      4c bss.o
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top