diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -126,6 +126,7 @@ case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: + case R_AARCH64_PLT32: return R_PLT_PC; case R_AARCH64_PREL16: case R_AARCH64_PREL32: @@ -244,7 +245,8 @@ // ELF for the ARM 64-bit architecture, section Call and Jump relocations // only permits range extension thunks for R_AARCH64_CALL26 and // R_AARCH64_JUMP26 relocation types. - if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26) + if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 && + type != R_AARCH64_PLT32) return false; uint64_t dst = expr == R_PLT_PC ? s.getPltVA() : s.getVA(a); return !inBranchRange(type, branchAddr, dst); @@ -258,11 +260,13 @@ } bool AArch64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { - if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26) + if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 && + type != R_AARCH64_PLT32) return true; // The AArch64 call and unconditional branch instructions have a range of - // +/- 128 MiB. - uint64_t range = 128 * 1024 * 1024; + // +/- 128 MiB. The PLT32 relocation supports a range up to +/- 2 GiB. + uint64_t range = + type == R_AARCH64_PLT32 ? (UINT64_C(1) << 31) : (128 * 1024 * 1024); if (dst > src) { // Immediate of branch is signed. range -= 4; @@ -325,6 +329,10 @@ checkIntUInt(loc, val, 32, rel); write32le(loc, val); break; + case R_AARCH64_PLT32: + checkInt(loc, val, 32, rel); + write32le(loc, val); + break; case R_AARCH64_ABS64: case R_AARCH64_PREL64: write64le(loc, val); diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -556,6 +556,7 @@ case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: case R_AARCH64_LD_PREL_LO19: + case R_AARCH64_PLT32: return p + a; } llvm_unreachable("AArch64 pc-relative relocation expected\n"); diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -838,7 +838,8 @@ Thunk::~Thunk() = default; static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) { - if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26) + if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 && + type != R_AARCH64_PLT32) fatal("unrecognized relocation type"); if (config->picThunk) return make(s, a); diff --git a/lld/test/ELF/aarch64-range-thunk-extension-plt32.s b/lld/test/ELF/aarch64-range-thunk-extension-plt32.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/aarch64-range-thunk-extension-plt32.s @@ -0,0 +1,36 @@ +// REQUIRES: aarch64 +// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o +// RUN: echo "SECTIONS { \ +// RUN: .text.1 0x10000 : { *(.text.1) } \ +// RUN: .text.2 0x200000000 : AT(0x20000) { *(.text.2) } \ +// RUN: } " > %t.script +// RUN: ld.lld --script %t.script %t.o -o %t +// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex %t | FileCheck %s + +// The word should be an offset to the range extension thunk. +// CHECK-LABEL: <_start>: +// CHECK-NEXT: 10000: 04 00 00 00 .word 0x00000004 + +// The thunk redirects to the address of callee. +// CHECK-LABEL: <__AArch64AbsLongThunk_callee>: +// CHECK-NEXT: 10004: ldr x16, 0x1000c <$d> +// CHECK-NEXT: 10008: br x16 + +// CHECK-LABEL: <$d>: +// CHECK-NEXT: 1000c: 00 00 00 00 .word 0x00000000 +// CHECK-NEXT: 10010: 02 00 00 00 .word 0x00000002 + +// CHECK-LABEL: : +// CHECK-NEXT: 200000000: ret + + .section .text.1, "ax", %progbits + .global _start + .type _start, %function +_start: + .word callee@PLT - . + + .section .text.2, "ax", %progbits + .global callee + .type callee, %function +callee: + ret diff --git a/lld/test/ELF/aarch64-reloc-plt32.s b/lld/test/ELF/aarch64-reloc-plt32.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/aarch64-reloc-plt32.s @@ -0,0 +1,32 @@ +// REQUIRES: aarch64 +// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=aarch64 %S/Inputs/abs255.s -o %t255.o +// RUN: llvm-mc -filetype=obj -triple=aarch64 %S/Inputs/abs256.s -o %t256.o +// RUN: llvm-mc -filetype=obj -triple=aarch64 %S/Inputs/abs257.s -o %t257.o + +/// Check for overflow with a R_AACH64_PLT32 relocation. + +// RUN: ld.lld -z max-page-size=4096 %t.o %t256.o -o %t2 +// RUN: llvm-objdump -s --section=.data %t2 | FileCheck %s + +// CHECK: Contents of section .data: +/// 202158: S = 0x100, A = 0x80202057, P = 0x202158 +/// S + A - P = 0xffffff7f +/// 20215c: S = 0x100, A = -0x7fdfdfa4, P = 0x20215c +/// S + A - P = 0x80000000 +/// 202160: S = 0x100, A = 0, P = 0x202160 +/// S + A - P = 0xffdfdfa0 +// CHECK-NEXT: 202158 ffffff7f 00000080 a0dfdfff + +// RUN: not ld.lld -z max-page-size=4096 %t.o %t255.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=OVERFLOW1 +// OVERFLOW1: relocation R_AARCH64_PLT32 out of range: -2147483649 is not in [-2147483648, 2147483647]; references foo + +// RUN: not ld.lld -z max-page-size=4096 %t.o %t257.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=OVERFLOW2 +// OVERFLOW2: relocation R_AARCH64_PLT32 out of range: 2147483648 is not in [-2147483648, 2147483647]; references foo + + .globl _start + _start: +.data + .word foo@PLT - . + 2149589079 + .word foo@PLT - . - 2145378212 + .word foo@PLT - . diff --git a/lld/test/ELF/aarch64-undefined-weak.s b/lld/test/ELF/aarch64-undefined-weak.s --- a/lld/test/ELF/aarch64-undefined-weak.s +++ b/lld/test/ELF/aarch64-undefined-weak.s @@ -33,6 +33,8 @@ .xword target - . // R_AARCH64_PREL16 .hword target - . +// R_AARCH64_PLT32 + .word target@PLT - . // CHECK: Disassembly of section .text: // CHECK-EMPTY: @@ -47,4 +49,5 @@ // CHECK: 1001013c: 00 00 00 00 .word 0x00000000 // CHECK-NEXT: 10010140: 00 00 00 00 .word 0x00000000 // CHECK-NEXT: 10010144: 00 00 00 00 .word 0x00000000 -// CHECK-NEXT: 10010148: 00 00 .short 0x0000 +// CHECK-NEXT: 10010148: 00 00 00 00 .word 0x00000000 +// CHECK-NEXT: 1001014c: 00 00 .short 0x0000