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 @@ -34,6 +34,7 @@ RelExpr getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const override; RelType getDynRel(RelType type) const override; + int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; void writeGotPlt(uint8_t *buf, const Symbol &s) const override; void writePltHeader(uint8_t *buf) const override; void writePlt(uint8_t *buf, const Symbol &sym, @@ -194,6 +195,17 @@ return R_AARCH64_NONE; } +int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const { + switch (type) { + case R_AARCH64_TLSDESC: + return read64(buf + 8); + default: + internalLinkerError(getErrorLocation(buf), + "cannot read addend for relocation " + toString(type)); + return 0; + } +} + void AArch64::writeGotPlt(uint8_t *buf, const Symbol &) const { write64(buf, in.plt->getVA()); } @@ -467,6 +479,10 @@ case R_AARCH64_TLSDESC_ADD_LO12: or32AArch64Imm(loc, val); break; + case R_AARCH64_TLSDESC: + // For R_AARCH64_TLSDESC the addend is stored in the second 64-bit word. + write64(loc + 8, val); + break; default: llvm_unreachable("unknown relocation"); } diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -200,11 +200,8 @@ config->shared) { if (in.got->addDynTlsEntry(sym)) { uint64_t off = in.got->getGlobalDynOffset(sym); - mainPart->relaDyn->addReloc({target->tlsDescRel, in.got, off, - sym.isPreemptible - ? DynamicReloc::AgainstSymbol - : DynamicReloc::AddendOnlyWithTargetVA, - sym, 0, R_ABS}); + mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible( + target->tlsDescRel, in.got, off, sym, target->tlsDescRel); } if (expr != R_TLSDESC_CALL) c.relocations.push_back({expr, type, offset, addend, &sym}); @@ -1107,11 +1104,9 @@ addRelativeReloc(in.got, off, sym, 0, R_ABS, target->symbolicRel); return; } - mainPart->relaDyn->addReloc( - sym.isPreemptible ? DynamicReloc::AgainstSymbol - : DynamicReloc::AddendOnlyWithTargetVA, - sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, sym, 0, - sym.isPreemptible ? R_ADDEND : R_ABS, target->symbolicRel); + mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible( + sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, sym, + target->symbolicRel); } // Return true if we can define a symbol in the executable that diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -531,6 +531,12 @@ void addRelativeReloc(RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, Symbol &sym, int64_t addend, RelType addendRelType, RelExpr expr); + /// Add a dynamic relocation using the target address of \p sym as the addend + /// if \p sym is non-preemptible. Otherwise add a relocation against \p sym. + void addAddendOnlyRelocIfNonPreemptible(RelType dynType, + InputSectionBase *isec, + uint64_t offsetInSec, Symbol &sym, + RelType addendRelType); void addReloc(DynamicReloc::Kind kind, RelType dynType, InputSectionBase *inputSec, uint64_t offsetInSec, Symbol &sym, int64_t addend, RelExpr expr, RelType addendRelType); diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1625,6 +1625,18 @@ sym, addend, expr, addendRelType); } +void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible( + RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, Symbol &sym, + RelType addendRelType) { + // No need to write an addend to the section for preemptible symbols. + if (sym.isPreemptible) + addReloc({dynType, isec, offsetInSec, DynamicReloc::AgainstSymbol, sym, 0, + R_ABS}); + else + addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, offsetInSec, + sym, 0, R_ABS, addendRelType); +} + void RelocationBaseSection::addReloc(DynamicReloc::Kind kind, RelType dynType, InputSectionBase *inputSec, uint64_t offsetInSec, Symbol &sym, diff --git a/lld/test/ELF/aarch64-tlsdesc-zrel.s b/lld/test/ELF/aarch64-tlsdesc-zrel.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/aarch64-tlsdesc-zrel.s @@ -0,0 +1,60 @@ +/// Check that we write addends for AArch64 TLSDESC relocations with -z rel +/// See https://bugs.llvm.org/show_bug.cgi?id=47009 +// REQUIRES: aarch64 +// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t-rela.so +// RUN: llvm-readobj -W -r -x .got %t-rela.so | FileCheck %s --check-prefixes=RELA,RELA-NO-ADDENDS +// RUN: ld.lld -shared %t.o -o %t-rela-addends.so --apply-dynamic-relocs +// RUN: llvm-readobj -W -r -x .got %t-rela-addends.so | FileCheck %s --check-prefixes=RELA,RELA-WITH-ADDENDS + +// RELA: Relocations [ +// RELA-NEXT: Section (5) .rela.dyn { +// RELA-NEXT: 0x20340 R_AARCH64_TLSDESC - 0x0 +// RELA-NEXT: 0x20350 R_AARCH64_TLSDESC - 0x4 +// RELA-NEXT: } +// RELA-NEXT: ] +// RELA-NEXT: Hex dump of section '.got': +// RELA-NEXT: 0x00020340 00000000 00000000 00000000 00000000 +// RELA-NO-ADDENDS-NEXT: 0x00020350 00000000 00000000 00000000 00000000 +// RELA-WITH-ADDENDS-NEXT: 0x00020350 00000000 00000000 04000000 00000000 +/// Addend 0x4 for R_AARCH64_TLSDESC -----^ +// RELA-EMPTY: + +// RUN: ld.lld -shared %t.o -o %t-rel.so -z rel +// RUN: llvm-readobj -W -r -x .got %t-rel.so | FileCheck %s --check-prefix=REL +// REL: Relocations [ +// REL-NEXT: Section (5) .rel.dyn { +// REL-NEXT: 0x20330 R_AARCH64_TLSDESC -{{$}} +// REL-NEXT: 0x20340 R_AARCH64_TLSDESC -{{$}} +// REL-NEXT: } +// REL-NEXT: ] +// REL-NEXT: Hex dump of section '.got': +// REL-NEXT: 0x00020330 00000000 00000000 00000000 00000000 +// REL-NEXT: 0x00020340 00000000 00000000 04000000 00000000 +/// Addend 0x4 for R_AARCH64_TLSDESC -----^ +// REL-EMPTY: + + .text +foo: + adrp x0, :tlsdesc:x + ldr x1, [x0, :tlsdesc_lo12:x] + add x0, x0, :tlsdesc_lo12:x + .tlsdesccall x + blr x1 + adrp x0, :tlsdesc:y + ldr x1, [x0, :tlsdesc_lo12:y] + add x0, x0, :tlsdesc_lo12:y + .tlsdesccall y + blr x1 + ret + + .section .tbss,"awT",@nobits + .p2align 2 + .hidden x +x: + .word 0 + + .p2align 2 + .hidden y +y: + .word 0