forked from OSchip/llvm-project
[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 llvm-svn: 286353
This commit is contained in:
parent
222fd13e3f
commit
8339bbd759
|
@ -258,6 +258,42 @@ static uint64_t getAArch64Page(uint64_t Expr) {
|
|||
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(uint32_t Type, typename ELFT::uint A,
|
|||
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");
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue