[lld] 417d2d7 - [PAC][lld][AArch64][ELF] Support signed GOT (#113815)

via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 16 23:23:05 PST 2024


Author: Daniil Kovalev
Date: 2024-12-17T10:23:01+03:00
New Revision: 417d2d7ce694acfa09a7d950cf1c5c41796eb313

URL: https://github.com/llvm/llvm-project/commit/417d2d7ce694acfa09a7d950cf1c5c41796eb313
DIFF: https://github.com/llvm/llvm-project/commit/417d2d7ce694acfa09a7d950cf1c5c41796eb313.diff

LOG: [PAC][lld][AArch64][ELF] Support signed GOT (#113815)

Depends on #113811

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.

Added: 
    lld/test/ELF/aarch64-got-relocations-pauth.s

Modified: 
    lld/ELF/Arch/AArch64.cpp
    lld/ELF/InputSection.cpp
    lld/ELF/Relocations.cpp
    lld/ELF/Relocations.h
    lld/ELF/Symbols.h
    lld/ELF/SyntheticSections.cpp
    lld/ELF/SyntheticSections.h

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 99fc750486e4b4..9571e0e9566fc3 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -202,11 +202,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_LD64_GOT_LO12_NC:
+  case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
+    return RE_AARCH64_AUTH_GOT;
   case R_AARCH64_LD64_GOTPAGE_LO15:
     return RE_AARCH64_GOT_PAGE;
   case R_AARCH64_ADR_GOT_PAGE:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
     return RE_AARCH64_GOT_PAGE_PC;
+  case R_AARCH64_AUTH_ADR_GOT_PAGE:
+    return RE_AARCH64_AUTH_GOT_PAGE_PC;
   case R_AARCH64_GOTPCREL32:
   case R_AARCH64_GOT_LD_PREL19:
     return R_GOT_PC;
@@ -258,6 +263,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
     return read64(ctx, 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:
@@ -528,9 +534,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
       write32(ctx, loc, val);
     break;
   case R_AARCH64_ADD_ABS_LO12_NC:
+  case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
     write32Imm12(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:
@@ -580,6 +588,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_LD64_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 7e76bae19fc6a2..26dc5c606f57f9 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -783,6 +783,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   case RE_ARM_SBREL:
     return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
   case R_GOT:
+  case RE_AARCH64_AUTH_GOT:
   case R_RELAX_TLS_GD_TO_IE_ABS:
     return r.sym->getGotVA(ctx) + a;
   case RE_LOONGARCH_GOT:
@@ -810,6 +811,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
     return r.sym->getGotOffset(ctx) + a;
   case RE_AARCH64_GOT_PAGE_PC:
+  case RE_AARCH64_AUTH_GOT_PAGE_PC:
   case RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
     return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
   case RE_AARCH64_GOT_PAGE:

diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 41c04b29034563..07cbdb7806fde1 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -197,8 +197,9 @@ static bool needsPlt(RelExpr expr) {
 }
 
 bool lld::elf::needsGot(RelExpr expr) {
-  return oneof<R_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE, RE_MIPS_GOT_OFF,
-               RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
+  return oneof<R_GOT, RE_AARCH64_AUTH_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE,
+               RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC,
+               RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
                RE_AARCH64_GOT_PAGE, RE_LOONGARCH_GOT, RE_LOONGARCH_GOT_PAGE_PC>(
       expr);
 }
@@ -910,6 +911,25 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
                      ctx.target->symbolicRel);
 }
 
+static void addGotAuthEntry(Ctx &ctx, Symbol &sym) {
+  ctx.in.got->addEntry(sym);
+  ctx.in.got->addAuthEntry(sym);
+  uint64_t off = sym.getGotOffset(ctx);
+
+  // If preemptible, emit a GLOB_DAT relocation.
+  if (sym.isPreemptible) {
+    ctx.mainPart->relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(),
+                                     off, DynamicReloc::AgainstSymbol, sym, 0,
+                                     R_ABS});
+    return;
+  }
+
+  // Signed GOT requires dynamic relocation.
+  ctx.in.got->getPartition(ctx).relaDyn->addReloc(
+      {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
+       DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
+}
+
 static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) {
   ctx.in.got->addEntry(sym);
   uint64_t off = sym.getGotOffset(ctx);
@@ -956,11 +976,12 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
   // These expressions always compute a constant
   if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, RE_MIPS_GOT_LOCAL_PAGE,
             RE_MIPS_GOTREL, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32,
-            RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+            RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC,
+            RE_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, RE_PPC32_PLTREL, RE_PPC64_CALL_PLT,
             RE_PPC64_RELAX_TOC, RE_RISCV_ADD, RE_AARCH64_GOT_PAGE,
-            RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
+            RE_AARCH64_AUTH_GOT, RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
             RE_LOONGARCH_GOT_PAGE_PC>(e))
     return true;
 
@@ -1075,7 +1096,10 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
     } else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
       // Many LoongArch TLS relocs reuse the RE_LOONGARCH_GOT type, in which
       // case the NEEDS_GOT flag shouldn't get set.
-      sym.setFlags(NEEDS_GOT);
+      if (expr == RE_AARCH64_AUTH_GOT || expr == RE_AARCH64_AUTH_GOT_PAGE_PC)
+        sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
+      else
+        sym.setFlags(NEEDS_GOT | NEEDS_GOT_NONAUTH);
     }
   } else if (needsPlt(expr)) {
     sym.setFlags(NEEDS_PLT);
@@ -1750,8 +1774,11 @@ static bool handleNonPreemptibleIfunc(Ctx &ctx, Symbol &sym, uint16_t flags) {
     // don't try to call the PLT as if it were an ifunc resolver.
     d.type = STT_FUNC;
 
-    if (flags & NEEDS_GOT)
+    if (flags & NEEDS_GOT) {
+      assert(!(flags & NEEDS_GOT_AUTH) &&
+             "R_AARCH64_AUTH_IRELATIVE is not supported yet");
       addGotEntry(ctx, sym);
+    }
   } else if (flags & NEEDS_GOT) {
     // Redirect GOT accesses to point to the Igot.
     sym.gotInIgot = true;
@@ -1772,8 +1799,19 @@ void elf::postScanRelocations(Ctx &ctx) {
       return;
     sym.allocateAux(ctx);
 
-    if (flags & NEEDS_GOT)
-      addGotEntry(ctx, sym);
+    if (flags & NEEDS_GOT) {
+      if ((flags & NEEDS_GOT_AUTH) && (flags & NEEDS_GOT_NONAUTH)) {
+        auto diag = Err(ctx);
+        diag << "both AUTH and non-AUTH GOT entries for '" << sym.getName()
+             << "' requested, but only one type of GOT entry per symbol is "
+                "supported";
+        return;
+      }
+      if (flags & NEEDS_GOT_AUTH)
+        addGotAuthEntry(ctx, sym);
+      else
+        addGotEntry(ctx, sym);
+    }
     if (flags & NEEDS_PLT)
       addPltEntry(ctx, *ctx.in.plt, *ctx.in.gotPlt, *ctx.in.relaPlt,
                   ctx.target->pltRel, sym);

diff  --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 7ca203257ea876..d993ab77adc3cc 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -92,7 +92,9 @@ enum RelExpr {
   // of a relocation type, there are some relocations whose semantics are
   // unique to a target. Such relocation are marked with RE_<TARGET_NAME>.
   RE_AARCH64_GOT_PAGE_PC,
+  RE_AARCH64_AUTH_GOT_PAGE_PC,
   RE_AARCH64_GOT_PAGE,
+  RE_AARCH64_AUTH_GOT,
   RE_AARCH64_PAGE_PC,
   RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
   RE_AARCH64_TLSDESC_PAGE,

diff  --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index fac957a7248856..a59faf1037cb2f 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -51,6 +51,8 @@ enum {
   NEEDS_TLSGD_TO_IE = 1 << 6,
   NEEDS_GOT_DTPREL = 1 << 7,
   NEEDS_TLSIE = 1 << 8,
+  NEEDS_GOT_AUTH = 1 << 9,
+  NEEDS_GOT_NONAUTH = 1 << 10,
 };
 
 // The base class for real symbol classes.

diff  --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index c8a05e4b9c3cc6..baa7a083404fe7 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -670,6 +670,10 @@ void GotSection::addEntry(const Symbol &sym) {
   ctx.symAux.back().gotIdx = numEntries++;
 }
 
+void GotSection::addAuthEntry(const Symbol &sym) {
+  authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
+}
+
 bool GotSection::addTlsDescEntry(const Symbol &sym) {
   assert(sym.auxIdx == ctx.symAux.size() - 1);
   ctx.symAux.back().tlsDescIdx = numEntries;
@@ -732,6 +736,21 @@ void GotSection::writeTo(uint8_t *buf) {
     return;
   ctx.target->writeGotHeader(buf);
   ctx.target->relocateAlloc(*this, buf);
+  for (const AuthEntryInfo &authEntry : authEntries) {
+    // https://github.com/ARM-software/abi-aa/blob/2024Q3/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/2024Q3/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(ctx, 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 132513cbd3b796..9fcee3b481af08 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -112,6 +112,7 @@ class GotSection final : public SyntheticSection {
 
   void addConstant(const Relocation &r);
   void addEntry(const Symbol &sym);
+  void addAuthEntry(const Symbol &sym);
   bool addTlsDescEntry(const Symbol &sym);
   bool addDynTlsEntry(const Symbol &sym);
   bool addTlsIndex();
@@ -131,6 +132,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, 0> authEntries;
 };
 
 // .note.GNU-stack section.

diff  --git a/lld/test/ELF/aarch64-got-relocations-pauth.s b/lld/test/ELF/aarch64-got-relocations-pauth.s
new file mode 100644
index 00000000000000..4456fe3ad7714b
--- /dev/null
+++ b/lld/test/ELF/aarch64-got-relocations-pauth.s
@@ -0,0 +1,90 @@
+# REQUIRES: aarch64
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %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 ok.s -o ok.o
+
+# RUN: ld.lld ok.o a.so -pie -o ok1
+# RUN: llvm-readelf -r -S -x .got ok1 | FileCheck %s --check-prefix=OK1
+
+# RUN: ld.lld ok.o a.o -pie -o ok2
+# RUN: llvm-readelf -r -S -x .got -s ok2 | FileCheck %s --check-prefix=OK2
+
+# OK1:      Offset            Info             Type                    Symbol's Value   Symbol's Name + Addend
+# OK1-NEXT: 0000000000020380  0000000100000412 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
+# OK1-NEXT: 0000000000020388  0000000200000412 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)
+# OK2:         Offset            Info             Type                    Symbol's Value   Symbol's Name + Addend
+# OK2-NEXT:    0000000000020320  0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+# OK2-NEXT:    0000000000020328  0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+
+# OK1:      Hex dump of section '.got':
+# OK1-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
+
+# OK2: Symbol table '.symtab' contains {{.*}} entries:
+# OK2:    Num:    Value          Size Type    Bind   Vis       Ndx Name
+# OK2:         0000000000010260     0 FUNC    GLOBAL DEFAULT     6 bar
+# OK2:         0000000000010260     0 NOTYPE  GLOBAL DEFAULT     6 zed
+
+# OK2:         Hex dump of section '.got':
+# OK2-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 ok1 | FileCheck %s --check-prefix=OK1-ASM
+
+# OK1-ASM:      <_start>:
+# OK1-ASM-NEXT: adrp x0, 0x20000
+# OK1-ASM-NEXT: ldr  x0, [x0, #0x380]
+# OK1-ASM-NEXT: adrp x1, 0x20000
+# OK1-ASM-NEXT: add  x1, x1, #0x380
+# OK1-ASM-NEXT: adrp x0, 0x20000
+# OK1-ASM-NEXT: ldr  x0, [x0, #0x388]
+# OK1-ASM-NEXT: adrp x1, 0x20000
+# OK1-ASM-NEXT: add  x1, x1, #0x388
+
+# RUN: llvm-objdump -d ok2 | FileCheck %s --check-prefix=OK2-ASM
+
+# OK2-ASM:         <_start>:
+# OK2-ASM-NEXT:    adrp x0, 0x20000
+# OK2-ASM-NEXT:    ldr  x0, [x0, #0x320]
+# OK2-ASM-NEXT:    adrp x1, 0x20000
+# OK2-ASM-NEXT:    add  x1, x1, #0x320
+# OK2-ASM-NEXT:    adrp x0, 0x20000
+# OK2-ASM-NEXT:    ldr  x0, [x0, #0x328]
+# OK2-ASM-NEXT:    adrp x1, 0x20000
+# OK2-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 err.s -o err.o
+# RUN: not ld.lld err.o a.so -pie 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
+# 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]


        


More information about the llvm-commits mailing list