5

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?

Mike
  • 47,263
  • 29
  • 113
  • 177

1 Answers1

6

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!]

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • ok... so what's the point of the common section then? with both `fcommon` and `fno-common` the end result is the uninitialized variables end up in the executable's .bss segment; or does it exist for the same reason that you wrote `"[a typical]"`? meaning there are exceptions – Mike Feb 12 '13 at 19:32
  • 2
    @Mike But the compiler doesn't know about that -it's the linkers job to figure this out. With targets (and executable formats) that provide a .bss section, the bss section is normally allocated and initialized at runtime. On targets that do not have that capability, the common sections end up in the executable, and if you have a global array of 10Mb, your executable ends up being 10Mb big. This also allow you to write your own linker scripts, and place those common sections where you want them. -fno-common have other uses, which the gcc man page explains though. – nos Feb 12 '13 at 19:35
  • I said "a typical" because it is possible to add extra sections in some architectures, and these sections can be assigned all manner of attributes as well. Not all compilers, linkers, etc will support that, and `gcc` is able to run on a large number of systems, with a large number of OS architectures. I didn't want someone to point out that on OS glurf, with linker X, you have sections called ..., etc. – Mats Petersson Feb 12 '13 at 19:41
  • AFAIK, if there are two globals named `i` in two different object files compiled with `-fno-common` and you try to link them, the linker will just error out. – netcoder Feb 12 '13 at 19:43
  • I'm not sure what I observed, but Valgrind lights up light a Christmas tree when attempting to test some programs on Apple platforms. Apple either (1) places some initialized globals in common, or (2) performs lazy initialization on the section they are in. The only way I could stop the Valgrind findings was to add `__attribute__((section ("__DATA,__data")))` (equivalent to `__attribute__((section ("nocommon")))`) on the problem variables. We should probably add `-fno-common` to the command line. – jww Feb 12 '17 at 05:11