Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do common section variables only show up in object file not the executable?

I'm trying to understand more about the "common" section of an executable and I noticed that when doing an objdump on compiled code, I can see variables placed in the common code only on object files (*.o) not on executables.

Why is that?

//test.c

int i[1000];
int main(){return 0;}

build command:

> gcc -g0 -fcommon -c test.c
> gcc -g0 -fcommon test.c

objdump shows i in the common section in the symbol table:

> objdump -x test.o
  ...
  SYMBOL TABLE:
  ...
  00000fa0    O   *COM*   00000020  i

Unless I run it on the executable:

> objdump -x a.out
  ...
  SYMBOL TABLE:
  ...
  0804a040 g  O   .bss    00000fa0  i

If I rebuild the object file with the -fno-common flag instead it shows up in the .bss segment just like it does on the executable. Does the final executable not have this "COMMON" section?

like image 969
Mike Avatar asked Feb 12 '13 19:02

Mike


1 Answers

The common section is something that the linker knows about. It basically puts all the common content into one of the three or four actual sections that [a typical] executable has (code or text, data, bss - sometimes there is a rodata as well).

So, your variable ends up in .bss in this case, as they are not initialized.

From gcc manual on -fcommon/-fno-common

In C code, controls the placement of uninitialized global variables. Unix C compilers have traditionally permitted multiple definitions of such variables in different compilation units by placing the variables in a common block. This is the behavior specified by -fcommon, and is the default for GCC on most targets. On the other hand, this behavior is not required by ISO C, and on some targets may carry a speed or code size penalty on variable references. The -fno-common option specifies that the compiler should place uninitialized global variables in the data section of the object file, rather than generating them as common blocks. This has the effect that if the same variable is declared (without extern) in two different compilations, you get a multiple-definition error when you link them. In this case, you must compile with -fcommon instead. Compiling with -fno-common is useful on targets for which it provides better performance, or if you wish to verify that the program will work on other systems that always treat uninitialized variable declarations this way.

So, -fno-common or -fcommon will only make a difference if there is more than one global variable called i [and they should be of the same size, or your program becomes invalid, which is one grade worse than undefined behaviour!]

like image 145
Mats Petersson Avatar answered Sep 18 '22 02:09

Mats Petersson