[ELF][AArch64] Write addends for TLSDESC relocations with -z rel
authorAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Fri, 9 Jul 2021 09:15:16 +0000 (10:15 +0100)
committerAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Fri, 9 Jul 2021 09:41:41 +0000 (10:41 +0100)
Since D100490 this case is diagnosed for -z rel. This commit implements
R_AARCH64_TLSDESC cases for AArch64::getImplicitAddend() and
AArch64::relocate(). However, there are probably further relocation types
that need to be handled for full support of -z rel.

Fixes https://bugs.llvm.org/show_bug.cgi?id=47009

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D100544

lld/ELF/Arch/AArch64.cpp
lld/ELF/Relocations.cpp
lld/ELF/SyntheticSections.cpp
lld/ELF/SyntheticSections.h
lld/test/ELF/aarch64-tlsdesc-zrel.s [new file with mode: 0644]

index 58da44a..c1ab0e9 100644 (file)
@@ -34,6 +34,7 @@ public:
   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 @@ RelType AArch64::getDynRel(RelType type) const {
   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 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
   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");
   }
index 7e44e2d..e3cc210 100644 (file)
@@ -200,11 +200,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
       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 @@ static void addGotEntry(Symbol &sym) {
     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
index a969ced..55cd271 100644 (file)
@@ -1625,6 +1625,18 @@ void RelocationBaseSection::addRelativeReloc(
            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,
index ddf7e8d..bc24922 100644 (file)
@@ -531,6 +531,12 @@ public:
   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/test/ELF/aarch64-tlsdesc-zrel.s b/lld/test/ELF/aarch64-tlsdesc-zrel.s
new file mode 100644 (file)
index 0000000..f9f69c4
--- /dev/null
@@ -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