[U-Boot] armv8 relocation questions

Jeroen Hofstee dasuboot at myspectrum.nl
Mon May 19 20:10:05 CEST 2014


Hello Wolfgang,

On ma, 2014-05-19 at 14:33 +0200, Wolfgang Denk wrote:
> Dear Jeroen,
> 
> In message <1400485047.1998.17.camel at yellow> you wrote:
> > 
> > > > "ADRP Xd, label
> > > ...
> > > > And apparently gcc choose to use it as such. Since the instructions in
> > > 
> > > Where exactly does it chose to do so?
> > 
> > In the code emitter which decide to use the following instructions to
> > look up a label, as mentioned by David [1]. Since it only uses _part of_
> > the pc, it introduces the need to have the relocation offset be a
> > multiple of 4k.  
> > 
> >      adrp  x0,  ...
> >      add   x0, x0, 0x30
> 
> No.  I mean: to which exact lines of U-Boot C source code will be
> translated into that?
> 
> I mean, from what has been discussed here that would be the relocation
> loop, right?  And there this should not happen, as we deal with random
> addresses.  So I wonder if this is either a coding error in the armv8
> related assembler code, or a compiler bug, or something else?
> 

mm, forget about U-Boot for a second and please consider the following,
complicated, program:

#include <stdio.h>

int main(int c, char *argv[])
{
	puts("Hello World");
	return 0;
}

compiled with `aarch64-linux-gnu-gcc -g -Wall hello.c` results in:

int main(int c, char *argv[])
{
  400590:	a9be7bfd 	stp	x29, x30, [sp,#-32]!
  400594:	910003fd 	mov	x29, sp
  400598:	b90013a0 	str	w0, [x29,#16]
  40059c:	f9000fa1 	str	x1, [x29,#24]
	puts("Hello World");
  4005a0:	90000000 	adrp	x0, 400000 <_init-0x3b8>
  4005a4:	91194000 	add	x0, x0, #0x650
  4005a8:	97ffff9e 	bl	400420 <puts at plt>
	return 0;
  4005ac:	52800000 	mov	w0, #0x0                   	// #0
}
  4005b0:	a8c27bfd 	ldp	x29, x30, [sp],#32
  4005b4:	d65f03c0 	ret


Notice the adrp and hardcoded offset to load the location of the
argument. The 90000000 decodes to adrp x0, 0, the value of the program
counter with its lower 12bits cleared -> which is the 400000 when not
being relocated. Then the harcoded 650 offset is added to point to: 

Contents of section .rodata:
400648 01000200 00000000 48656c6c 6f20576f  ........Hello Wo
400658 726c6400 00000000                    rld.....

----
Now suppose the code is moved 0x20 up, then the adrp will still return
400000, the constant #0x650 it still added, but Hello World is now at
400670 and it won't work.

If 0x1000 (4k) is added, the adrp sets 401000, the fixed 650 is added
again and properly points to the repositioned "Hello World". This will
work for any multiple of 4k.


> > >  I cannot understand why that
> > > should be a problem for _start, but not for any of the other symbols
> > > we're relocating?
> > 
> > It is not a problem of _start. Any label / symbol which is looked up
> > with only the adrp + compile time offset will be incorrect if the
> > relocation offset is not n * 4k. It just that moving _start around makes
> > the relocation offset not obey this requirement.
> 
> Well, in this case relocation can never work correctly, so we're back
> at my question above: bad assembly code of the armv8 port, or a
> compiler bug?

Relocation will work fine, as long as (relocation_offset % 4096) == 0.
Note that this is only about the offset, the label / symbol itself can
be aligned to anything, since the hardcoded "add" will take care of that
part.

> 
> The question is - where does such code get emitted?  Is it generated
> from C code, or manually created assembly?
> 
It is generated, there are no literal adrp instructions in U-boot.
As far as I understand it, it is a compiler feature..

Regards,
Jeroen





More information about the U-Boot mailing list