Question on compressed vmlinux .got and .bss sections
Dave Martin
dave.martin at linaro.org
Tue Apr 19 15:23:09 UTC 2011
On Tue, Apr 19, 2011 at 06:13:01PM +0800, Shawn Guo wrote:
> Hi toolchain, kernel folks,
>
> I'm seeing an interesting thing on .got and .bss sections of
> arch/arm/boot/compressed/vmlinux, and really need your expertise to
> shed some lights.
>
> I have an uninitialized variable 'uart_base' defined in misc.c.
>
> static unsigned long uart_base;
[...]
I think this is explained by position-independence and symbol
preemption issues.
The boot/compressed stuff is built with -fpic to make it position-
independent, but to GCC this also means "might get dynamically linked".
This means that if uart_base is a global symbol, the compiler/linker
have to cope with allowing it to be overriden from another shared
library at dynamic link time.
Here's the code:
$ objdump -tdr arch/arm/boot/compressed/misc.o
[...]
00000008 g O .bss 00000004 uart_base
[...]
Disassembly of section .text:
00000000 <putc>:
0: 4b11 ldr r3, [pc, #68] ; (48 <putc+0x48>)
2: 4a12 ldr r2, [pc, #72] ; (4c <putc+0x4c>)
4: 447b add r3, pc
6: b430 push {r4, r5}
8: 5899 ldr r1, [r3, r2]
[...]
48: 00000040 .word 0x00000040
48: R_ARM_GOTPC _GLOBAL_OFFSET_TABLE_
4c: 00000000 .word 0x00000000
4c: R_ARM_GOT32 uart_base
[...]
As a side-effect, this causes the address of uart_base to appear
in the GOT, since this is where the dynamic linker would patch
the symbol address if overriding it with a symbol at another location.
Of course, for building the kernel this is all pointless
because there will be no dynamic linking. But GCC has no concept
of position-independent code in a non-dynamic-linking environment.
GCC can be persuaded to optimise away most of the GOT references
by passing -fvisibility=protected or -fvisibility=hidden.
If uart_base is _not_ global (as in the original code), it
will never be preempted, since by definition only global
symbols can ever be preempted during dynamic linking.
So the reference can be fixed up in a purely pc-relative way at link
time, and the actual address of uart_base may not appear on the
resulting image at all: here's the generated code:
$ objdump -td arch/arm/boot/compressed/vmlinux
003bdb40 l O .bss 00000004 uart_base
[...]
00000700 <putc>:
700: 4b0f ldr r3, [pc, #60] ; (740 <putc+0x40>)
702: b410 push {r4}
704: 447b add r3, pc
[...]
740: 003bd438 .word 0x003bd438
That 0x3bd438 is the reference to uart_base; i.e.,
0x3bdb40 - <address of the "add r3, pc" instruction> - 4
If uart_base _is_ global but we also pass -fvisibility=hidden
to the compiler, then the generated code is once again fully
pc-relative, and the address of uart_base does not appear
as a literal word in the resulting image.
Hopefully this explains what's going on, but what are you trying
to achieve exactly?
Cheers
---Dave
More information about the linaro-kernel
mailing list