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


_______________________________________________
linaro-toolchain mailing list
linaro-toolchain@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-toolchain

Reply via email to