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