[lld] [PAC][lld][AArch64][ELF] Support signed GOT (PR #96169)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 20 04:27:23 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld-elf

Author: Daniil Kovalev (kovdan01)

<details>
<summary>Changes</summary>

Depends on #<!-- -->96164

Support `R_AARCH64_AUTH_ADR_GOT_PAGE`, `R_AARCH64_AUTH_GOT_LO12_NC` and `R_AARCH64_AUTH_GOT_ADD_LO12_NC` GOT-generating relocations. For preemptible symbols, dynamic relocation `R_AARCH64_AUTH_GLOB_DAT` is emitted. Otherwise, we unconditionally emit `R_AARCH64_AUTH_RELATIVE` dynamic relocation since pointers in signed GOT needs to be signed during dynamic link time.

---
Full diff: https://github.com/llvm/llvm-project/pull/96169.diff


8 Files Affected:

- (modified) lld/ELF/Arch/AArch64.cpp (+9) 
- (modified) lld/ELF/InputSection.cpp (+2) 
- (modified) lld/ELF/Relocations.cpp (+33-9) 
- (modified) lld/ELF/Relocations.h (+2) 
- (modified) lld/ELF/Symbols.h (+1) 
- (modified) lld/ELF/SyntheticSections.cpp (+19) 
- (modified) lld/ELF/SyntheticSections.h (+5) 
- (added) lld/test/ELF/aarch64-auth-got-relocations.s (+94) 


``````````diff
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 47e6ea1ff7756..45d21e777f2d8 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -169,11 +169,16 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
   case R_AARCH64_LD64_GOT_LO12_NC:
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
     return R_GOT;
+  case R_AARCH64_AUTH_GOT_LO12_NC:
+  case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
+    return R_AARCH64_AUTH_GOT;
   case R_AARCH64_LD64_GOTPAGE_LO15:
     return R_AARCH64_GOT_PAGE;
   case R_AARCH64_ADR_GOT_PAGE:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
     return R_AARCH64_GOT_PAGE_PC;
+  case R_AARCH64_AUTH_ADR_GOT_PAGE:
+    return R_AARCH64_AUTH_GOT_PAGE_PC;
   case R_AARCH64_GOTPCREL32:
   case R_AARCH64_GOT_LD_PREL19:
     return R_GOT_PC;
@@ -225,6 +230,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
     return read64(buf + 8);
   case R_AARCH64_NONE:
   case R_AARCH64_GLOB_DAT:
+  case R_AARCH64_AUTH_GLOB_DAT:
   case R_AARCH64_JUMP_SLOT:
     return 0;
   case R_AARCH64_ABS16:
@@ -430,9 +436,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
     write64(loc, val);
     break;
   case R_AARCH64_ADD_ABS_LO12_NC:
+  case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
     or32AArch64Imm(loc, val);
     break;
   case R_AARCH64_ADR_GOT_PAGE:
+  case R_AARCH64_AUTH_ADR_GOT_PAGE:
   case R_AARCH64_ADR_PREL_PG_HI21:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
   case R_AARCH64_TLSDESC_ADR_PAGE21:
@@ -482,6 +490,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
     break;
   case R_AARCH64_LDST64_ABS_LO12_NC:
   case R_AARCH64_LD64_GOT_LO12_NC:
+  case R_AARCH64_AUTH_GOT_LO12_NC:
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
   case R_AARCH64_TLSDESC_LD64_LO12:
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index be12218d9948c..f3b54e7f72855 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -694,6 +694,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
   case R_ARM_SBREL:
     return sym.getVA(a) - getARMStaticBase(sym);
   case R_GOT:
+  case R_AARCH64_AUTH_GOT:
   case R_RELAX_TLS_GD_TO_IE_ABS:
     return sym.getGotVA() + a;
   case R_LOONGARCH_GOT:
@@ -721,6 +722,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
   case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
     return sym.getGotOffset() + a;
   case R_AARCH64_GOT_PAGE_PC:
+  case R_AARCH64_AUTH_GOT_PAGE_PC:
   case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
     return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(p);
   case R_AARCH64_GOT_PAGE:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 1b08339e3996a..5840b8ead5af0 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -209,8 +209,9 @@ static bool needsPlt(RelExpr expr) {
 }
 
 bool lld::elf::needsGot(RelExpr expr) {
-  return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
-               R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
+  return oneof<R_GOT, R_AARCH64_AUTH_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+               R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
+               R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
                R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
       expr);
 }
@@ -924,13 +925,25 @@ void elf::addGotEntry(Symbol &sym) {
 
   // If preemptible, emit a GLOB_DAT relocation.
   if (sym.isPreemptible) {
-    mainPart->relaDyn->addReloc({target->gotRel, in.got.get(), off,
+    RelType gotRel = target->gotRel;
+    if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+      assert(config->emachine == EM_AARCH64);
+      gotRel = R_AARCH64_AUTH_GLOB_DAT;
+    }
+    mainPart->relaDyn->addReloc({gotRel, in.got.get(), off,
                                  DynamicReloc::AgainstSymbol, sym, 0, R_ABS});
     return;
   }
 
   // Otherwise, the value is either a link-time constant or the load base
-  // plus a constant.
+  // plus a constant. Signed GOT requires dynamic relocation.
+  if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+    in.got->getPartition().relaDyn->addReloc(
+        {R_AARCH64_AUTH_RELATIVE, in.got.get(), off,
+         DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
+    return;
+  }
+
   if (!config->isPic || isAbsolute(sym))
     in.got->addConstant({R_ABS, target->symbolicRel, off, 0, &sym});
   else
@@ -983,10 +996,11 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
   // These expressions always compute a constant
   if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE,
             R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
-            R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
-            R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC,
-            R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
-            R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
+            R_AARCH64_GOT_PAGE_PC, R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC,
+            R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
+            R_GOTPLT_GOTREL, R_GOTPLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
+            R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE,
+            R_AARCH64_AUTH_GOT, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
             R_LOONGARCH_GOT_PAGE_PC>(e))
     return true;
 
@@ -1099,7 +1113,17 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
     } else if (!sym.isTls() || config->emachine != EM_LOONGARCH) {
       // Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which
       // case the NEEDS_GOT flag shouldn't get set.
-      sym.setFlags(NEEDS_GOT);
+      bool needsGotAuth =
+          (expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC);
+      if (!sym.hasFlag(NEEDS_GOT)) {
+        sym.setFlags(NEEDS_GOT);
+        if (needsGotAuth)
+          sym.setFlags(NEEDS_GOT_AUTH);
+      } else if (needsGotAuth != sym.hasFlag(NEEDS_GOT_AUTH)) {
+        fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() +
+              "' requested, but only one type of GOT entry per symbol is "
+              "supported");
+      }
     }
   } else if (needsPlt(expr)) {
     sym.setFlags(NEEDS_PLT);
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index e299d23dd7db3..fb1973b19f485 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -83,7 +83,9 @@ enum RelExpr {
   // of a relocation type, there are some relocations whose semantics are
   // unique to a target. Such relocation are marked with R_<TARGET_NAME>.
   R_AARCH64_GOT_PAGE_PC,
+  R_AARCH64_AUTH_GOT_PAGE_PC,
   R_AARCH64_GOT_PAGE,
+  R_AARCH64_AUTH_GOT,
   R_AARCH64_PAGE_PC,
   R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
   R_AARCH64_TLSDESC_PAGE,
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index c65c5d6cd0dca..c8aa3d937af0e 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -54,6 +54,7 @@ enum {
   NEEDS_TLSGD_TO_IE = 1 << 6,
   NEEDS_GOT_DTPREL = 1 << 7,
   NEEDS_TLSIE = 1 << 8,
+  NEEDS_GOT_AUTH = 1 << 9,
 };
 
 // Some index properties of a symbol are stored separately in this auxiliary
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index cc423d152e912..b4212b4962634 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -655,6 +655,10 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
 void GotSection::addEntry(const Symbol &sym) {
   assert(sym.auxIdx == symAux.size() - 1);
   symAux.back().gotIdx = numEntries++;
+  if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+    assert(config->emachine == EM_AARCH64);
+    authEntries.push_back({(numEntries - 1) * config->wordsize, sym.isFunc()});
+  }
 }
 
 bool GotSection::addTlsDescEntry(const Symbol &sym) {
@@ -718,6 +722,21 @@ void GotSection::writeTo(uint8_t *buf) {
     return;
   target->writeGotHeader(buf);
   target->relocateAlloc(*this, buf);
+  for (const AuthEntryInfo &authEntry : authEntries) {
+    // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema
+    //   Signed GOT entries use the IA key for symbols of type STT_FUNC and the
+    //   DA key for all other symbol types, with the address of the GOT entry as
+    //   the modifier. The static linker must encode the signing schema into the
+    //   GOT slot.
+    //
+    // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#encoding-the-signing-schema
+    //   If address diversity is set and the discriminator
+    //   is 0 then modifier = Place
+    uint8_t *dest = buf + authEntry.offset;
+    uint64_t key = authEntry.isSymbolFunc ? /*IA*/ 0b00 : /*DA*/ 0b10;
+    uint64_t addrDiversity = 1;
+    write64(dest, (addrDiversity << 63) | (key << 60));
+  }
 }
 
 static uint64_t getMipsPageAddr(uint64_t addr) {
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 34949025a45f7..7cc6a34c5dc8a 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -131,6 +131,11 @@ class GotSection final : public SyntheticSection {
   size_t numEntries = 0;
   uint32_t tlsIndexOff = -1;
   uint64_t size = 0;
+  struct AuthEntryInfo {
+    size_t offset;
+    bool isSymbolFunc;
+  };
+  SmallVector<AuthEntryInfo> authEntries;
 };
 
 // .note.GNU-stack section.
diff --git a/lld/test/ELF/aarch64-auth-got-relocations.s b/lld/test/ELF/aarch64-auth-got-relocations.s
new file mode 100644
index 0000000000000..f04e3d953388c
--- /dev/null
+++ b/lld/test/ELF/aarch64-auth-got-relocations.s
@@ -0,0 +1,94 @@
+# REQUIRES: aarch64
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %p/Inputs/shared.s -o a.o
+# RUN: ld.lld -shared a.o -o a.so
+
+#--- ok.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux ok.s -o ok.o
+
+# RUN: ld.lld ok.o a.so -pie -o external
+# RUN: llvm-readelf -r -S -x .got external | FileCheck %s --check-prefix=EXTERNAL
+
+# RUN: ld.lld ok.o a.o -pie -o local
+# RUN: llvm-readelf -r -S -x .got -s local | FileCheck %s --check-prefix=LOCAL
+
+# EXTERNAL:      Offset            Info             Type                    Symbol's Value   Symbol's Name + Addend
+# EXTERNAL-NEXT: 0000000000020380  000000010000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
+# EXTERNAL-NEXT: 0000000000020388  000000020000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 zed + 0
+
+## Symbol's values for bar and zed are equal since they contain no content (see Inputs/shared.s)
+# LOCAL:         Offset            Info             Type                    Symbol's Value   Symbol's Name + Addend
+# LOCAL-NEXT:    0000000000020320  0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+# LOCAL-NEXT:    0000000000020328  0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+
+# EXTERNAL:      Hex dump of section '.got':
+# EXTERNAL-NEXT: 0x00020380 00000000 00000080 00000000 000000a0
+#                                          ^^
+#                                          0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+#                                                            ^^
+#                                                            0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# LOCAL: Symbol table '.symtab' contains {{.*}} entries:
+# LOCAL:    Num:    Value          Size Type    Bind   Vis       Ndx Name
+# LOCAL:         0000000000010260     0 FUNC    GLOBAL DEFAULT     6 bar
+# LOCAL:         0000000000010260     0 NOTYPE  GLOBAL DEFAULT     6 zed
+
+# LOCAL:         Hex dump of section '.got':
+# LOCAL-NEXT:    0x00020320 00000000 00000080 00000000 000000a0
+#                                          ^^
+#                                          0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+#                                                            ^^
+#                                                            0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# RUN: llvm-objdump -d external | FileCheck %s --check-prefix=EXTERNAL-ASM
+
+# EXTERNAL-ASM:      <_start>:
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr  x0, [x0, #0x380]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add  x1, x1, #0x380
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr  x0, [x0, #0x388]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add  x1, x1, #0x388
+
+# RUN: llvm-objdump -d local | FileCheck %s --check-prefix=LOCAL-ASM
+
+# LOCAL-ASM:         <_start>:
+# LOCAL-ASM-NEXT:    adrp x0, 0x20000
+# LOCAL-ASM-NEXT:    ldr  x0, [x0, #0x320]
+# LOCAL-ASM-NEXT:    adrp x1, 0x20000
+# LOCAL-ASM-NEXT:    add  x1, x1, #0x320
+# LOCAL-ASM-NEXT:    adrp x0, 0x20000
+# LOCAL-ASM-NEXT:    ldr  x0, [x0, #0x328]
+# LOCAL-ASM-NEXT:    adrp x1, 0x20000
+# LOCAL-ASM-NEXT:    add  x1, x1, #0x328
+
+.globl _start
+_start:
+  adrp x0, :got_auth:bar
+  ldr  x0, [x0, :got_auth_lo12:bar]
+  adrp x1, :got_auth:bar
+  add  x1, x1, :got_auth_lo12:bar
+  adrp x0, :got_auth:zed
+  ldr  x0, [x0, :got_auth_lo12:zed]
+  adrp x1, :got_auth:zed
+  add  x1, x1, :got_auth_lo12:zed
+
+#--- err.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux err.s -o err.o
+
+# RUN: not ld.lld err.o a.so -pie -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+# ERR: error: both AUTH and non-AUTH GOT entries for 'bar' requested, but only one type of GOT entry per symbol is supported
+
+.globl _start
+_start:
+  adrp x0, :got_auth:bar
+  ldr  x0, [x0, :got_auth_lo12:bar]
+  adrp x0, :got:bar
+  ldr  x0, [x0, :got_lo12:bar]

``````````

</details>


https://github.com/llvm/llvm-project/pull/96169


More information about the llvm-commits mailing list