Bug 25406 - [ARM] pcrel relocations referencing STB_GLOBAL symbols are resolved at assembly time
Summary: [ARM] pcrel relocations referencing STB_GLOBAL symbols are resolved at assemb...
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Reported: 2020-01-17 04:17 UTC by Fangrui Song
Modified: 2020-04-21 14:43 UTC (History)
3 users (show)

See Also:
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description Fangrui Song 2020-01-17 04:17:44 UTC
% cat pcrel-global.s
.syntax unified

.globl foo
ldrd r0, r1, foo @ arm_pcrel_10_unscaled
vldr d0, foo     @ arm_pcrel_10
adr r2, foo      @ arm_adr_pcrel_12
ldr r0, foo      @ arm_ldst_pcrel_12


.globl bar
adr r0, bar      @ thumb_adr_pcrel_10
adr.w r0, bar    @ t2_adr_pcrel_12
ldr.w pc, bar    @ t2_ldst_pcrel_12

% arm-linux-gnueabi-as -mfpu=vfp pcrel-global.s -o /tmp/c/a.o
% readelf -r /tmp/c/a.o

There are no relocations in this file.

If the definitions of foo and bar are deleted, each instruction can issue an error.

STB_GLOBAL STV_DEFAULT symbols can be preemptible (if in a shared object). Should relocations be emitted? On many other architectures, relocations will be emitted.
Comment 1 Richard Earnshaw 2020-04-15 09:23:30 UTC
Relocations wouldn't help if they were to another shared object.  They would guarantee to be more than the offset range supported by those instructions.
Comment 2 Tamar Christina 2020-04-15 18:16:12 UTC
To add to what Richard said having the assembler emits much better error messages for these cases.

If we emitted the relocations here and have the linker resolve them when not -shared the error would be a generic truncation error.

Ultimately you wouldn't want to write code like this using pcrel instructions if you want to write PIC code.

I'm also worried about previously working code that can fail if it now ends up in a shared object with relocation and it's preempted by another symbol which will more than likely be out of range.

So I also don't think we should emit relocations here.
Comment 3 Fangrui Song 2020-04-15 19:01:20 UTC
Alternatively, we can reject such non-STB_LOCAL labels when they may be preemptible. The scheme will still be consistent with the rest of ELF models and architectures.
Comment 4 Tamar Christina 2020-04-20 17:17:20 UTC
(In reply to Fangrui Song from comment #3)
> Alternatively, we can reject such non-STB_LOCAL labels when they may be
> preemptible. The scheme will still be consistent with the rest of ELF models
> and architectures.

Wouldn't this then not accomplish what you wanted initially which was make them pre-emptible?

Following the LLVM discussion it seems they have decided to leave it as is for Arm but not revert the Thumb patch that made them pre-emptible.

That seems a bit arbitrary.. 

As far as I can tell the ELF standard says it "can" be pre-empted, not that it must be.  And with such small ranges is there an actual use case for them to be?
Comment 5 Peter Smith 2020-04-21 14:43:55 UTC
Just to mention our thoughts from the Arm side for what we'd like to see in GCC and LLVM. In summary we'd like LLVM to match the GNU behaviour. There is scope for a better error message in GNU as when the ADR/LDR fixup cannot be resolved at assembly time.

The relocation ranges for ADR and LDR are tiny, in general they cannot be expected to reach anything outside the section that they are defined in. There is no dynamic relocation that can be used to resolve to a preempted definition.

- ADR and LDR should be resolved at assembly time within the same section, even if it is a global default visibility symbol.
- A specific assembly time error if ADR and LDR if the symbol is defined outside the same section.
- It is user error if code uses ADR or LDR to a global default visibility symbol and that symbol is preempted at runtime [1].

There are two possible alternatives:
1.) ADR and LDR to global default visibility symbol is an error message.
2.) ADR and LDR to global default visibility symbol produces a relocation and the linker gives an error message in a shared context.

Our view is that alternative 1 risks breaking too much legacy code, particularly in embedded code, which in some cases rebuilding can involve an expensive revalidation. Option 2 allows the error message to occur only when it is needed, however the linker error message that would result (relocation overflow) which would also occur for a cross-section reference is not easy for the author to track down. With the risk of ADR or LDR being used in a shared context seen as very low, we'd prefer to keep the existing GCC behaviour and update LLVM to match.

An example of code that is not suitable for a shared library [1]
 .global foo
 .type foo, %function
 adr r0, foo // resolved at assembly time to foo in this shared library
 bx lr

 .word foo // Potential dynamic relocation, to default visibility symbol foo, 
           // could be preempted to point to some other definition of foo, this
           // may result in problems if these definitions need to be the same.