In previous versions of GCC, the symbol offsets reported by objdump
matched the ones used during the actual execution of the code. For example:
$ cat example.c
#include <stdio.h>
int g_someGlobal = 0;
int main()
{
printf("%d\n", g_someGlobal);
return 0;
}
$ gcc-6 -v
...
gcc version 6.1.1 20160802 (Debian 6.1.1-11)
$ gcc-6 -O0 -g -o example example.c
$ objdump -x example | grep Global
...
080496f4 g O .bss 00000004 g_someGlobal
...
And indeed, when running the binary, the actual address of the symbol used during execution is the same one as that reported by objdump:
$ gdb ./example
...
(gdb) start
Temporary breakpoint 1, main () at example.c:10
10 printf("%d\n", g_someGlobal);
(gdb) p/x &g_someGlobal
$1 = 0x80496f4
Unfortunately, repeating the same sequence of commands in the recently released Debian Stretch, this happens instead:
$ gcc-6 -v
...
gcc version 6.3.0 20170415 (Debian 6.3.0-14)
$ gcc-6 -O0 -g -o example example.c
$ objdump -x example | grep Global
00002020 g O .bss 00000004 g_someGlobal
The symbol offset now seems to be a much smaller value - which...
$ gdb ./example
...
(gdb) start
...
Temporary breakpoint 1, main () at example.c:7
7 printf("%d\n", g_someGlobal);
(gdb) p/x &g_someGlobal
$1 = 0x80002020
...no longer matches with the one used at runtime.
Am I making a mistake here? Has the usage of the tools changed in the meantime? If not, what is the reasoning behind this change?
Regardless - in theory there must be a way to get the "expected run-time offset" of the .bss segment that hosts the variable (objdump
does report which section it will be placed in, so the final run-time position could be calculated by adding the .bss
offset). In my preliminary attempts to do so, I have not found a way to get this, though:
$ readelf --sections example | grep bss
[26] .bss NOBITS 0000201c 00101c 000008 00 WA 0 0 4
This doesn't seem to report the "shift" of 0x80000000 that seems to happen to .bss
-hosted variables in this example.
(Even if that is a "magic constant" for this new execution environment, does that apply to the .data
variables, too? And to be honest, I hate magic values - previously, whatever came out of objdump -x
was accurate, regardless of where the symbols resided...)
Any information to resolve this most welcome. Ideally, I'd like to reproduce the old behavior of objdump -x
- i.e. to statically (NOT at run-time) get the value of the run-time address of a symbol, from the ELF that hosts it.
UPDATE: I did a custom compile (from sources) of GCC7.1.0, and this is no longer reproducible. Perhaps this was a regression in GCC 6.3 (the version packaged in Debian Stretch)...
The reason is that Debian's gcc package is built with --enable-default-pie
. In a PIE executable, the ELF segments can be loaded at an arbitrary (as long as it's properly aligned) base address, usually chosen randomly by the loader. The symbol addresses you see in the ELF file are offsets relative to the base address it's loaded at, rather than absolute virtual addresses.
If you don't want/need PIE, you can add -no-pie
to link command line to get link-time determined addresses like you're used to.