[lld] r286353 - [ELF] ARM and AArch64 undefined weak reference values
Peter Smith via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 10 07:27:38 PST 2016
Hello,
I've had a chance to check over R_AARCH64_ADR_PREL_PG_HI21 to weak
references. From what I can tell no code-generator should ever use
that relocation to a weak reference as I don't think that there is any
sensible value that a linker can return that will work in all cases.
Testing out what gcc and llvm actually do, I see that with non
position-independent code:
- gcc uses R_AARCH64_ADR_PREL_PG_HI21 + R_AARCH64_LDST64_ABS_LO12_NC
to a local literal pool that has a R_AARCH64_ABS64 relocation to the
weak reference.
- llvm uses R_AARCH64_ADR_GOT_PAGE and R_AARCH64_LD64_GOT_LO12_NC to a
linker generated GOT entry.
These approaches avoid a R_AARCH64_ADR_PREL_PG_HI21 relocation to the
weak reference so I don't think that anything needs changing in llvm.
One small difference between ld.bfd and lld is that lld hard codes the
GOT location to 0 if the weak reference isn't defined at static link
time, whereas ld.bfd puts the weak reference into the dynamic symbol
table with a R_AARCH64_GLOB_DAT relocation. The only thing I can see
that could realistically exploit this behaviour would be if a program
dlopens a shared library before lazy symbol resolution of the weak
reference.
Peter
On 9 November 2016 at 15:17, Peter Smith <peter.smith at linaro.org> wrote:
> From C Code the recommended way is with inline assembler asm(".global
> reference"). ARM's proprietary compiler armcc has a #pragma import
> <symbol> [1] which will embed a reference directly, the asm(".global
> reference") is the recommended replacement.
>
> You raise an interesting point about ADRP and the
> R_AARCH64_ADR_PREL_PG_HI21 as while it is relative it can't
> necessarily return the address of the place either. I'll need to do
> some more thinking as I have my suspicions that neither the old or the
> new way is quite right. I think that what should happen is the linker
> always creates a GOT slot for the weak reference that can ADRP +
> follow up instruction can always guarantee to access, if the weak
> reference is unresolved the GOT slot contains 0.
>
> [1] http://infocenter.arm.com/help/topic/com.arm.doc.dui0472m/chr1359124987739.html
>
> On 9 November 2016 at 14:22, Rafael EspĂndola
> <rafael.espindola at gmail.com> wrote:
>> This is quite interesting. How are these references produced? Directly
>> writing assembly? I wonder if
>> AArch64Subtarget::ClassifyGlobalReference should be changed in any
>> way:
>>
>> // The small code mode's direct accesses use ADRP, which cannot necessarily
>> // produce the value 0 (if the code is above 4GB).
>> if (TM.getCodeModel() == CodeModel::Small && GV->hasExternalWeakLinkage())
>> return AArch64II::MO_GOT;
>>
>> Cheers,
>> Rafael
>>
>>
>>
>> On 9 November 2016 at 05:22, Peter Smith via llvm-commits
>> <llvm-commits at lists.llvm.org> wrote:
>>> Author: psmith
>>> Date: Wed Nov 9 04:22:29 2016
>>> New Revision: 286353
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=286353&view=rev
>>> Log:
>>> [ELF] ARM and AArch64 undefined weak reference values
>>>
>>> The ARM 32 and 64-bit ABI does not use 0 for undefined weak references
>>> that are used in PC relative relocations. In particular:
>>> - A branch relocation to an undefined weak resolves to the next
>>> instruction. Effectively making the branch a no-op
>>> - In all other cases the symbol resolves to the place so that S + A - P
>>> resolves to A.
>>>
>>> Differential Revision: https://reviews.llvm.org/D26240
>>>
>>>
>>> Added:
>>> lld/trunk/test/ELF/aarch64-undefined-weak.s (with props)
>>> lld/trunk/test/ELF/arm-thumb-undefined-weak.s (with props)
>>> lld/trunk/test/ELF/arm-undefined-weak.s (with props)
>>> Modified:
>>> lld/trunk/ELF/InputSection.cpp
>>> lld/trunk/test/ELF/arm-thumb-no-undefined-thunk.s
>>>
>>> Modified: lld/trunk/ELF/InputSection.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=286353&r1=286352&r2=286353&view=diff
>>> ==============================================================================
>>> --- lld/trunk/ELF/InputSection.cpp (original)
>>> +++ lld/trunk/ELF/InputSection.cpp Wed Nov 9 04:22:29 2016
>>> @@ -258,6 +258,42 @@ static uint64_t getAArch64Page(uint64_t
>>> return Expr & (~static_cast<uint64_t>(0xFFF));
>>> }
>>>
>>> +static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type,
>>> + uint32_t A,
>>> + uint32_t P) {
>>> + switch (Type) {
>>> + case R_ARM_THM_JUMP11:
>>> + return P + 2;
>>> + case R_ARM_CALL:
>>> + case R_ARM_JUMP24:
>>> + case R_ARM_PC24:
>>> + case R_ARM_PLT32:
>>> + case R_ARM_PREL31:
>>> + case R_ARM_THM_JUMP19:
>>> + case R_ARM_THM_JUMP24:
>>> + return P + 4;
>>> + case R_ARM_THM_CALL:
>>> + // We don't want an interworking BLX to ARM
>>> + return P + 5;
>>> + default:
>>> + return A;
>>> + }
>>> +}
>>> +
>>> +static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type,
>>> + uint64_t A,
>>> + uint64_t P) {
>>> + switch (Type) {
>>> + case R_AARCH64_CALL26:
>>> + case R_AARCH64_CONDBR19:
>>> + case R_AARCH64_JUMP26:
>>> + case R_AARCH64_TSTBR14:
>>> + return P + 4;
>>> + default:
>>> + return A;
>>> + }
>>> +}
>>> +
>>> template <class ELFT>
>>> static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
>>> typename ELFT::uint P,
>>> @@ -373,10 +409,20 @@ static typename ELFT::uint getSymVA(uint
>>> return SymVA - P;
>>> }
>>> case R_PC:
>>> + if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) {
>>> + // On ARM and AArch64 a branch to an undefined weak resolves to the
>>> + // next instruction, otherwise the place.
>>> + if (Config->EMachine == EM_ARM)
>>> + return getARMUndefinedRelativeWeakVA(Type, A, P);
>>> + if (Config->EMachine == EM_AARCH64)
>>> + return getAArch64UndefinedRelativeWeakVA(Type, A, P);
>>> + }
>>> case R_RELAX_GOT_PC:
>>> return Body.getVA<ELFT>(A) - P;
>>> case R_PLT_PAGE_PC:
>>> case R_PAGE_PC:
>>> + if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
>>> + return getAArch64Page(A);
>>> return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
>>> }
>>> llvm_unreachable("Invalid expression");
>>>
>>> Added: lld/trunk/test/ELF/aarch64-undefined-weak.s
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/aarch64-undefined-weak.s?rev=286353&view=auto
>>> ==============================================================================
>>> --- lld/trunk/test/ELF/aarch64-undefined-weak.s (added)
>>> +++ lld/trunk/test/ELF/aarch64-undefined-weak.s Wed Nov 9 04:22:29 2016
>>> @@ -0,0 +1,45 @@
>>> +// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t
>>> +// RUN: ld.lld %t -o %t2 2>&1
>>> +// RUN: llvm-objdump -triple=aarch64-none-linux -d %t2 | FileCheck %s
>>> +// REQUIRES: aarch64
>>> +
>>> +// Check that the ARM 64-bit ABI rules for undefined weak symbols are applied.
>>> +// Branch instructions are resolved to the next instruction. Undefined
>>> +// Symbols in relative are resolved to the place so S - P + A = A.
>>> +
>>> + .weak target
>>> +
>>> + .text
>>> + .global _start
>>> +_start:
>>> +// R_AARCH64_JUMP26
>>> + b target
>>> +// R_AARCH64_CALL26
>>> + bl target
>>> +// R_AARCH64_CONDBR19
>>> + b.eq target
>>> +// R_AARCH64_TSTBR14
>>> + cbz x1, target
>>> +// R_AARCH64_ADR_PREL_LO21
>>> + adr x0, target
>>> +// R_AARCH64_ADR_PREL_PG_HI21
>>> + adrp x0, target
>>> +// R_AARCH64_PREL32
>>> + .word target - .
>>> +// R_AARCH64_PREL64
>>> + .xword target - .
>>> +// R_AARCH64_PREL16
>>> + .hword target - .
>>> +
>>> +// CHECK: Disassembly of section .text:
>>> +// 131076 = 0x20004
>>> +// CHECK: 20000: 01 80 00 14 b #131076
>>> +// CHECK-NEXT: 20004: 02 80 00 94 bl #131080
>>> +// CHECK-NEXT: 20008: 60 00 10 54 b.eq #131084
>>> +// CHECK-NEXT: 2000c: 81 00 10 b4 cbz x1, #131088
>>> +// CHECK-NEXT: 20010: 00 00 00 10 adr x0, #0
>>> +// CHECK-NEXT: 20014: 00 00 00 90 adrp x0, #0
>>> +// CHECK: 20018: 00 00 00 00 .word 0x00000000
>>> +// CHECK-NEXT: 2001c: 00 00 00 00 .word 0x00000000
>>> +// CHECK-NEXT: 20020: 00 00 00 00 .word 0x00000000
>>> +// CHECK-NEXT: 20024: 00 00 .short 0x0000
>>>
>>> Propchange: lld/trunk/test/ELF/aarch64-undefined-weak.s
>>> ------------------------------------------------------------------------------
>>> svn:eol-style = native
>>>
>>> Propchange: lld/trunk/test/ELF/aarch64-undefined-weak.s
>>> ------------------------------------------------------------------------------
>>> svn:keywords = Rev Date Author URL Id
>>>
>>> Modified: lld/trunk/test/ELF/arm-thumb-no-undefined-thunk.s
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thumb-no-undefined-thunk.s?rev=286353&r1=286352&r2=286353&view=diff
>>> ==============================================================================
>>> --- lld/trunk/test/ELF/arm-thumb-no-undefined-thunk.s (original)
>>> +++ lld/trunk/test/ELF/arm-thumb-no-undefined-thunk.s Wed Nov 9 04:22:29 2016
>>> @@ -18,6 +18,7 @@ _start:
>>>
>>> // CHECK: Disassembly of section .text:
>>> // CHECK-NEXT: _start:
>>> -// CHECK-NEXT: 11000: ee f7 fe ef blx #-69636
>>> -// CHECK-NEXT: 11004: ee f7 fc bf b.w #-69640
>>> -// CHECK-NEXT: 11008: ee f7 fa bf b.w #-69644
>>> +// 69636 = 0x11004 = next instruction
>>> +// CHECK: 11000: 11 f0 02 f8 bl #69636
>>> +// CHECK-NEXT: 11004: 11 f0 04 b8 b.w #69640
>>> +// CHECK-NEXT: 11008: 11 f0 06 b8 b.w #69644
>>>
>>> Added: lld/trunk/test/ELF/arm-thumb-undefined-weak.s
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thumb-undefined-weak.s?rev=286353&view=auto
>>> ==============================================================================
>>> --- lld/trunk/test/ELF/arm-thumb-undefined-weak.s (added)
>>> +++ lld/trunk/test/ELF/arm-thumb-undefined-weak.s Wed Nov 9 04:22:29 2016
>>> @@ -0,0 +1,38 @@
>>> +// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
>>> +// RUN: ld.lld %t -o %t2 2>&1
>>> +// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t2 | FileCheck %s
>>> +// REQUIRES: arm
>>> +
>>> +// Check that the ARM ABI rules for undefined weak symbols are applied.
>>> +// Branch instructions are resolved to the next instruction. Relative
>>> +// relocations are resolved to the place.
>>> +
>>> + .syntax unified
>>> +
>>> + .weak target
>>> +
>>> + .text
>>> + .global _start
>>> +_start:
>>> +// R_ARM_THM_JUMP19
>>> + beq.w target
>>> +// R_ARM_THM_JUMP24
>>> + b.w target
>>> +// R_ARM_THM_CALL
>>> + bl target
>>> +// R_ARM_THM_CALL with exchange
>>> + blx target
>>> +// R_ARM_THM_MOVT_PREL
>>> + movt r0, :upper16:target - .
>>> +// R_ARM_THM_MOVW_PREL_NC
>>> + movw r0, :lower16:target - .
>>> +
>>> +// CHECK: Disassembly of section .text:
>>> +// 69636 = 0x11004
>>> +// CHECK: 11000: 11 f0 02 80 beq.w #69636
>>> +// CHECK-NEXT: 11004: 11 f0 04 b8 b.w #69640
>>> +// CHECK-NEXT: 11008: 11 f0 06 f8 bl #69644
>>> +// blx is transformed into bl so we don't change state
>>> +// CHECK-NEXT: 1100c: 11 f0 08 f8 bl #69648
>>> +// CHECK-NEXT: 11010: c0 f2 00 00 movt r0, #0
>>> +// CHECK-NEXT: 11014: 40 f2 00 00 movw r0, #0
>>>
>>> Propchange: lld/trunk/test/ELF/arm-thumb-undefined-weak.s
>>> ------------------------------------------------------------------------------
>>> svn:eol-style = native
>>>
>>> Propchange: lld/trunk/test/ELF/arm-thumb-undefined-weak.s
>>> ------------------------------------------------------------------------------
>>> svn:keywords = Rev Date Author URL Id
>>>
>>> Added: lld/trunk/test/ELF/arm-undefined-weak.s
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-undefined-weak.s?rev=286353&view=auto
>>> ==============================================================================
>>> --- lld/trunk/test/ELF/arm-undefined-weak.s (added)
>>> +++ lld/trunk/test/ELF/arm-undefined-weak.s Wed Nov 9 04:22:29 2016
>>> @@ -0,0 +1,39 @@
>>> +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
>>> +// RUN: ld.lld %t -o %t2 2>&1
>>> +// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t2 | FileCheck %s
>>> +// REQUIRES: arm
>>> +
>>> +// Check that the ARM ABI rules for undefined weak symbols are applied.
>>> +// Branch instructions are resolved to the next instruction. Undefined
>>> +// Symbols in relative are resolved to the place so S - P + A = A.
>>> +
>>> + .syntax unified
>>> +
>>> + .weak target
>>> +
>>> + .text
>>> + .global _start
>>> +_start:
>>> +// R_ARM_JUMP24
>>> + b target
>>> +// R_ARM_CALL
>>> + bl target
>>> +// R_ARM_CALL with exchange
>>> + blx target
>>> +// R_ARM_MOVT_PREL
>>> + movt r0, :upper16:target - .
>>> +// R_ARM_MOVW_PREL_NC
>>> + movw r0, :lower16:target - .
>>> +// R_ARM_REL32
>>> + .word target - .
>>> +
>>> +// CHECK: Disassembly of section .text:
>>> +// 69636 = 0x11004
>>> +// CHECK: 11000: 01 44 00 ea b #69636
>>> +// CHECK-NEXT: 11004: 02 44 00 eb bl #69640
>>> +// blx is transformed into bl so we don't change state
>>> +// CHECK-NEXT: 11008: 03 44 00 eb bl #69644
>>> +// CHECK-NEXT: 1100c: 00 00 40 e3 movt r0, #0
>>> +// CHECK-NEXT: 11010: 00 00 00 e3 movw r0, #0
>>> +// CHECK: 11014: 00 00 00 00 .word 0x00000000
>>> +
>>>
>>> Propchange: lld/trunk/test/ELF/arm-undefined-weak.s
>>> ------------------------------------------------------------------------------
>>> svn:eol-style = native
>>>
>>> Propchange: lld/trunk/test/ELF/arm-undefined-weak.s
>>> ------------------------------------------------------------------------------
>>> svn:keywords = Rev Date Author URL Id
>>>
>>>
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list