[PATCH] arm64: Add support for bigger u-boot when CONFIG_POSITION_INDEPENDENT=y

André Przywara andre.przywara at arm.com
Wed Sep 2 17:18:48 CEST 2020


On 02/09/2020 15:53, Edgar E. Iglesias wrote:
> On Wed, Sep 02, 2020 at 03:43:08PM +0100, Andr� Przywara wrote:
>> On 02/09/2020 12:15, Michal Simek wrote:

Hi,

>>
>>> From: "Edgar E. Iglesias" <edgar.iglesias at xilinx.com>
>>>
>>> When U-Boot binary exceeds 1MB with CONFIG_POSITION_INDEPENDENT=y
>>> compilation error is shown:
>>> /mnt/disk/u-boot/arch/arm/cpu/armv8/start.S:71:(.text+0x3c): relocation
>>> truncated to fit: R_AARCH64_ADR_PREL_LO21 against symbol `__rel_dyn_end'
>>> defined in .bss_start section in u-boot.
>>>
>>> It is caused by adr instruction which permits the calculation of any byte
>>> address within +- 1MB of the current PC.
>>> Because U-Boot is bigger then 1MB calculation is failing.
>>>
>>> The patch is using adrp/add instructions where adrp shifts a signed, 21-bit
>>> immediate left by 12 bits (4k page), adds it to the value of the program
>>> counter with the bottom 12 bits cleared to zero. Then add instruction
>>> provides the lower 12 bits which is offset within 4k page.
>>> These two instructions together compose full 32bit offset which should be
>>> more then enough to cover the whole u-boot size.
>>>
>>> Signed-off-by: Edgar E. Iglesias <edgar.iglesias at xilinx.com>
>>> Signed-off-by: Michal Simek <michal.simek at xilinx.com>
>>
>> It's a bit scary that you need more than 1MB, but indeed what you do
>> below is the canonical pattern to get the full range of PC relative
>> addressing (this is used heavily in Trusted Firmware, for instance).
>>
>> The only thing to keep in mind is that this assumes that the load
>> address of the binary is 4K aligned, so that the low 12 bits of the
>> symbol stay the same. I wonder if we should enforce this somehow? But
>> the load address is not controlled by the build process (the whole
>> purpose of PIE), so that's not doable just in the build system?
> 
> There shouldn't be any need for 4K alignment. Could you elaborate on
> why you think there is?

That seems to be slightly tricky, and I tried to get some confirmation,
but here goes my reasoning. Maybe you can confirm this:

- adrp takes the relative offset, but only of the upper 20 bits (because
that's all we can encode). It clears the lower 12 bits of the register.
- the "add" is not PC relative anymore, so it just takes the lower 12
bits of the "absolute" linker symbol.
So this assumes that the lower 12 bits of the actual address in memory
and the lower 12 bits of the linker's view match.
An example:
00024: adrp x0, SYMBOL
00028: add  x0, x0, :lo12:SYMBOL

SYMBOL:
42058: ...

The toolchain will generate:
	adrp x0, #0x42; add x0, x0, #0x058

Now you load the code to 0x8000.0800 (NOT 4K aligned). SYMBOL is now at
0x80042858.
The adrp will use the PC (0x8000.0824) & ~0xfff + offs => 0x8004.2000.
The add will just add 0x58, so you end up with x0 being 0x80042058,
which is not the right address.

Does this make sense?

> Perhaps the commit message is a little confusing. The toolchain will
> compute the pc-relative offset from this particular location to the
> symbol and apply the relocations accordingly.

Yes, but the PC relative offset applies only to the upper 20 bits,
because it's only adrp that has PC relative semantics.

Cheers,
Andre

>>
>> Shall we at least document this? I guess typical load address are
>> actually quite well aligned, so it might not be an issue in practice.
>>
>> Cheers,
>> Andre
>>
>>> ---
>>>
>>>  arch/arm/cpu/armv8/start.S | 6 ++++--
>>>  1 file changed, 4 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
>>> index 002698b501c3..52cf1230c205 100644
>>> --- a/arch/arm/cpu/armv8/start.S
>>> +++ b/arch/arm/cpu/armv8/start.S
>>> @@ -67,8 +67,10 @@ pie_fixup:
>>>  	adr	x0, _start		/* x0 <- Runtime value of _start */
>>>  	ldr	x1, _TEXT_BASE		/* x1 <- Linked value of _start */
>>>  	sub	x9, x0, x1		/* x9 <- Run-vs-link offset */
>>> -	adr	x2, __rel_dyn_start	/* x2 <- Runtime &__rel_dyn_start */
>>> -	adr	x3, __rel_dyn_end	/* x3 <- Runtime &__rel_dyn_end */
>>> +	adrp    x2, __rel_dyn_start     /* x2 <- Runtime &__rel_dyn_start */
>>> +	add     x2, x2, #:lo12:__rel_dyn_start
>>> +	adrp    x3, __rel_dyn_end       /* x3 <- Runtime &__rel_dyn_end */
>>> +	add     x3, x3, #:lo12:__rel_dyn_end
>>>  pie_fix_loop:
>>>  	ldp	x0, x1, [x2], #16	/* (x0, x1) <- (Link location, fixup) */
>>>  	ldr	x4, [x2], #8		/* x4 <- addend */
>>>
>>



More information about the U-Boot mailing list