Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -258,6 +258,42 @@ return Expr & (~static_cast(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 static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P, @@ -375,10 +411,20 @@ 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(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(A)) - getAArch64Page(P); } llvm_unreachable("Invalid expression"); Index: test/ELF/aarch64-undefined-weak.s =================================================================== --- /dev/null +++ test/ELF/aarch64-undefined-weak.s @@ -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 Index: test/ELF/arm-thumb-no-undefined-thunk.s =================================================================== --- test/ELF/arm-thumb-no-undefined-thunk.s +++ test/ELF/arm-thumb-no-undefined-thunk.s @@ -18,6 +18,7 @@ // 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 Index: test/ELF/arm-thumb-undefined-weak.s =================================================================== --- /dev/null +++ test/ELF/arm-thumb-undefined-weak.s @@ -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 Index: test/ELF/arm-undefined-weak.s =================================================================== --- /dev/null +++ test/ELF/arm-undefined-weak.s @@ -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 +