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