[lld] 9dffcd2 - [PAC][lld] Properly handle `.relr.auth.dyn` -> `.rela.dyn` movement (#195649)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 11 22:29:43 PDT 2026


Author: Daniil Kovalev
Date: 2026-07-11T22:29:38-07:00
New Revision: 9dffcd2752af16a09eeb4131f90a1a0fe2b76a1f

URL: https://github.com/llvm/llvm-project/commit/9dffcd2752af16a09eeb4131f90a1a0fe2b76a1f
DIFF: https://github.com/llvm/llvm-project/commit/9dffcd2752af16a09eeb4131f90a1a0fe2b76a1f.diff

LOG: [PAC][lld] Properly handle `.relr.auth.dyn` -> `.rela.dyn` movement (#195649)

Address the following issues reported in #171475:

1. Proper adjustment of `__rela_iplt_end` address if a move from
`.relr.auth.dyn` to `.rela.dyn` took place

2. Set `__rela_iplt_start` properly if prior to such movement from
`.relr.auth.dyn`, the `.rela.dyn` was empty

3. Allocate enough space for both RELA* and AARCH64_AUTH_RELR* tags in
the `.dynamic` section in case we end up with both `.relr.auth.dyn` and
`.rela.dyn`. If one of the sections becomes empty - just pad the
`.dynamic` section with null tags in the end.

Resolves #171475

---------

Co-authored-by: Jessica Clarke <jrtc27 at jrtc27.com>

Added: 
    

Modified: 
    lld/ELF/Writer.cpp
    lld/test/ELF/aarch64-reloc-pauth.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 49d3f903b3743..21b67cae86578 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -826,6 +826,22 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
       addOptionalRegular(ctx, name, ctx.out.elfHeader.get(), 0, STV_HIDDEN);
 }
 
+static bool updateRelIpltSymbols(Ctx &ctx) {
+  if (ctx.sym.relaIpltStart) {
+    auto &dyn = getIRelativeSection(ctx);
+    if (dyn.isNeeded()) {
+      SectionBase *oldSec = ctx.sym.relaIpltEnd->section;
+      uint64_t oldVal = ctx.sym.relaIpltEnd->value;
+      ctx.sym.relaIpltStart->section = &dyn;
+      ctx.sym.relaIpltEnd->section = &dyn;
+      ctx.sym.relaIpltEnd->value = dyn.getSize();
+      return (oldSec != ctx.sym.relaIpltEnd->section ||
+              oldVal != ctx.sym.relaIpltEnd->value);
+    }
+  }
+  return false;
+}
+
 // This function generates assignments for predefined symbols (e.g. _end or
 // _etext) and inserts them into the commands sequence to be processed at the
 // appropriate time. This ensures that the value is going to be correct by the
@@ -844,14 +860,7 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
 
   // .rela_iplt_{start,end} mark the start and the end of the section containing
   // IRELATIVE relocations.
-  if (ctx.sym.relaIpltStart) {
-    auto &dyn = getIRelativeSection(ctx);
-    if (dyn.isNeeded()) {
-      ctx.sym.relaIpltStart->section = &dyn;
-      ctx.sym.relaIpltEnd->section = &dyn;
-      ctx.sym.relaIpltEnd->value = dyn.getSize();
-    }
-  }
+  (void)updateRelIpltSymbols(ctx);
 
   PhdrEntry *last = nullptr;
   OutputSection *lastRO = nullptr;
@@ -1577,6 +1586,18 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
       changed |= ctx.in.relrDyn->updateAllocSize(ctx);
     if (ctx.in.relrAuthDyn)
       changed |= ctx.in.relrAuthDyn->updateAllocSize(ctx);
+    if (ctx.in.relrAuthDyn && ctx.in.dynamic && ctx.in.dynamic->getParent()) {
+      size_t oldSize = ctx.in.dynamic->getSize();
+      finalizeSynthetic(ctx, ctx.in.dynamic.get());
+      changed |= (oldSize != ctx.in.dynamic->getSize());
+    }
+
+    // .rela_iplt_{start,end} mark the start and the end of the section
+    // containing IRELATIVE relocations. Update them on each iteration because
+    // they might be affected by the above move of relocations from
+    // .relr.auth.dyn to .rela.dyn.
+    changed |= updateRelIpltSymbols(ctx);
+
     if (ctx.in.memtagGlobalDescriptors)
       changed |= ctx.in.memtagGlobalDescriptors->updateAllocSize(ctx);
     if (ctx.in.ehFrameHdr && ctx.in.ehFrameHdr->isNeeded())
@@ -1766,7 +1787,8 @@ static void removeUnusedSyntheticSections(Ctx &ctx) {
         // Conservatively keep .rela.dyn. .relr.auth.dyn can be made empty, but
         // we would fail to remove it here.
         if (ctx.arg.emachine == EM_AARCH64 && ctx.arg.relrPackDynRelocs &&
-            sec == ctx.in.relaDyn.get())
+            sec == ctx.in.relaDyn.get() && ctx.in.relrAuthDyn &&
+            ctx.in.relrAuthDyn->isNeeded())
           return false;
         unused.insert(sec);
         return true;

diff  --git a/lld/test/ELF/aarch64-reloc-pauth.s b/lld/test/ELF/aarch64-reloc-pauth.s
index 6b4d23d37babc..9a7ba0869560f 100644
--- a/lld/test/ELF/aarch64-reloc-pauth.s
+++ b/lld/test/ELF/aarch64-reloc-pauth.s
@@ -41,17 +41,22 @@
 # NOPIE-NEXT: }
 
 # RUN: ld.lld -pie -z pack-relative-relocs main.o a.so -o main.pie
-# RUN: llvm-readelf -S -d -r -x .test main.pie | FileCheck --check-prefixes=RELR,HEX %s
+# RUN: llvm-readelf -S -d -r -x .dynamic -x .test main.pie | FileCheck --check-prefixes=RELR,HEX %s
 
 # RELR:      Section Headers:
 # RELR-NEXT: Name Type Address Off Size ES Flg Lk Inf Al
 # RELR:      .rela.dyn RELA {{0*}}[[ADDR1:.+]] {{0*}}[[ADDR1]] 000090 18 A 1 0 8
 # RELR:      .relr.auth.dyn AARCH64_AUTH_RELR {{0*}}[[ADDR2:.+]] {{0*}}[[ADDR2]] 000018 08 A 0 0 8
 
-# RELR:      Dynamic section at offset {{.+}} contains 16 entries
-# RELR:      0x0000000070000012 (AARCH64_AUTH_RELR) 0x[[ADDR2]]
-# RELR-NEXT: 0x0000000070000011 (AARCH64_AUTH_RELRSZ) 24 (bytes)
+# RELR:      Dynamic section at offset 0x340 contains 16 entries
+# RELR:      0x0000000000000007 (RELA)                 0x[[ADDR1]]
+# RELR-NEXT: 0x0000000000000008 (RELASZ)               144 (bytes)
+# RELR-NEXT: 0x0000000000000009 (RELAENT)              24 (bytes)
+# RELR-NEXT: 0x0000000070000012 (AARCH64_AUTH_RELR)    0x[[ADDR2]]
+# RELR-NEXT: 0x0000000070000011 (AARCH64_AUTH_RELRSZ)  24 (bytes)
 # RELR-NEXT: 0x0000000070000013 (AARCH64_AUTH_RELRENT) 8 (bytes)
+# RELR:      0x0000000000000000 (NULL)                 0x0
+# RELR-EMPTY:
 
 ## Decoded SHT_RELR section is same as UNPACKED,
 ## but contains only the relative relocations.
@@ -74,6 +79,10 @@
 # RELR-NEXT:  0000000000030458 $d + 0x18
 # RELR-NEXT: 0002: 0000000000030492 0000000000030492 $d + 0x52
 
+# HEX:      Hex dump of section '.dynamic':
+# HEX:      0x00020430 00000000 00000000 00000000 00000000
+# HEX-EMPTY:
+
 # HEX:      Hex dump of section '.test':
 # HEX-NEXT: 0x00030440 01000000 2a000020 42040300 2b000000
 ##                     ^^^^^^^^ Implicit val = 1 = __ehdr_start + 1
@@ -145,20 +154,25 @@
 
 # RUN: llvm-mc -filetype=obj -triple=aarch64 empty-relr.s -o empty-relr.o
 # RUN: ld.lld -pie -z pack-relative-relocs empty-relr.o -o empty-relr
-# RUN: llvm-readelf -S -d -r empty-relr | FileCheck --check-prefixes=EMPTY-RELR %s
+# RUN: llvm-readelf -S -d -r -x.dynamic empty-relr | FileCheck --check-prefixes=EMPTY-RELR %s
 
 # EMPTY-RELR:      Section Headers:
 # EMPTY-RELR-NEXT: Name Type Address Off Size ES Flg Lk Inf Al
 # EMPTY-RELR:      .rela.dyn RELA {{0*}}[[ADDR1:.+]] {{0*}}[[ADDR1]] 000018 18 A 0 0 8
 # EMPTY-RELR:      .relr.auth.dyn AARCH64_AUTH_RELR {{0*}}[[ADDR2:.+]] {{0*}}[[ADDR2]] 000000 08 A 0 0 8
 
-# EMPTY-RELR:      Dynamic section at offset {{.+}} contains 12 entries
+# EMPTY-RELR:      Dynamic section at offset 0x260 contains 12 entries
+# EMPTY-RELR-NOT:  (RELR)
+# EMPTY-RELR-NOT:  (RELRSZ)
+# EMPTY-RELR-NOT:  (RELRENT)
 # EMPTY-RELR-NOT:  (AARCH64_AUTH_RELR)
 # EMPTY-RELR-NOT:  (AARCH64_AUTH_RELRSZ)
 # EMPTY-RELR-NOT:  (AARCH64_AUTH_RELRENT)
 # EMPTY-RELR:      0x0000000000000007 (RELA) 0x[[ADDR1]]
 # EMPTY-RELR-NEXT: 0x0000000000000008 (RELASZ) 24 (bytes)
 # EMPTY-RELR-NEXT: 0x0000000000000009 (RELAENT) 24 (bytes)
+# EMPTY-RELR:      0x0000000000000000 (NULL) 0x0
+# EMPTY-RELR-EMPTY:
 
 # EMPTY-RELR:      Relocation section '.rela.dyn' at offset {{.+}} contains 1 entries:
 # EMPTY-RELR-NEXT:     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
@@ -167,6 +181,13 @@
 # EMPTY-RELR-NEXT: Relocation section '.relr.auth.dyn' at offset {{.+}} contains 0 entries:
 # EMPTY-RELR-NEXT: Index: Entry Address Symbolic Address
 
+## The .dynamic section has enough space pre-allocated for the case when both
+## .rela.dyn and .relr.auth.dyn sections are present. Since .relr.auth.dyn becomes
+## empty for this test, this space is filled with NULL tags.
+# EMPTY-RELR:      Hex dump of section '.dynamic':
+# EMPTY-RELR:      0x00020310 00000000 00000000 00000000 00000000
+# EMPTY-RELR-EMPTY:
+
 .section .test, "aw"
 .p2align 3
 .quad (.test + 0x7FFFFFFF)@AUTH(da,42)
@@ -179,7 +200,7 @@
 
 # RUN: llvm-mc -filetype=obj -triple=aarch64 empty-rela.s -o empty-rela.o
 # RUN: ld.lld -pie -z pack-relative-relocs empty-rela.o -o empty-rela
-# RUN: llvm-readelf -S -d -r empty-rela | FileCheck --check-prefixes=EMPTY-RELA %s
+# RUN: llvm-readelf -S -d -r -x.dynamic empty-rela | FileCheck --check-prefixes=EMPTY-RELA %s
 # RUN: ld.lld -r -z pack-relative-relocs empty-rela.o -o empty-rela.ro
 # RUN: llvm-readelf -S empty-rela.ro | FileCheck --check-prefixes=EMPTY-RELA-RO %s
 
@@ -188,13 +209,18 @@
 # EMPTY-RELA:      .rela.dyn RELA {{0*}}[[ADDR1:.+]] {{0*}}[[ADDR1]] 000000 18 A 0 0 8
 # EMPTY-RELA:      .relr.auth.dyn AARCH64_AUTH_RELR {{0*}}[[ADDR2:.+]] {{0*}}[[ADDR2]] 000008 08 A 0 0 8
 
-# EMPTY-RELA:      Dynamic section at offset {{.+}} contains 12 entries
+# EMPTY-RELA:      Dynamic section at offset 0x250 contains 12 entries
 # EMPTY-RELA-NOT:  (RELR)
 # EMPTY-RELA-NOT:  (RELRSZ)
 # EMPTY-RELA-NOT:  (RELRENT)
+# EMPTY-RELA-NOT:  (RELA)
+# EMPTY-RELA-NOT:  (RELASZ)
+# EMPTY-RELA-NOT:  (RELAENT)
 # EMPTY-RELA:      0x0000000070000012 (AARCH64_AUTH_RELR) 0x[[ADDR2]]
 # EMPTY-RELA-NEXT: 0x0000000070000011 (AARCH64_AUTH_RELRSZ) 8 (bytes)
 # EMPTY-RELA-NEXT: 0x0000000070000013 (AARCH64_AUTH_RELRENT) 8 (bytes)
+# EMPTY-RELA:      0x0000000000000000 (NULL) 0x0
+# EMPTY-RELA-EMPTY:
 
 # EMPTY-RELA:      Relocation section '.rela.dyn' at offset {{.+}} contains 0 entries:
 # EMPTY-RELA-NEXT:     Offset             Info             Type               Symbol's Value  Symbol's Name
@@ -203,8 +229,106 @@
 # EMPTY-RELA-NEXT: Index: Entry Address Symbolic Address
 # EMPTY-RELA-NEXT: 0000: 0000000000030310 0000000000030310 $d
 
+## The .dynamic section has enough space pre-allocated for the case when both
+## .rela.dyn and .relr.auth.dyn sections are present. Since .rela.dyn becomes
+## empty for this test, this space is filled with NULL tags.
+# EMPTY-RELA:      Hex dump of section '.dynamic':
+# EMPTY-RELA:      0x00020300 00000000 00000000 00000000 00000000
+# EMPTY-RELA-EMPTY:
+
 # EMPTY-RELA-RO-NOT: .rela.dyn
 
 .section .test, "aw"
 .p2align 3
 .quad (.test + 0x12345678)@AUTH(da,42)
+
+#--- dynamic-section-growth.s
+
+## .relr.auth.dyn relocations that do not fit 32 bits are moved to .rela.dyn.
+## If some relocations are moved to the previously empty .rela.dyn and some stay
+## in .relr.auth.dyn, the dynamic section needs to contain tags for both these
+## sections and have enough space for storing these tags.
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 dynamic-section-growth.s -o dynamic-section-growth.o
+# RUN: ld.lld -shared -z pack-relative-relocs dynamic-section-growth.o -o dynamic-section-growth.so
+# RUN: llvm-readelf -S -d -r -x.dynamic dynamic-section-growth.so | FileCheck --check-prefix=DYN-GROW %s
+
+# DYN-GROW:     .rela.dyn         RELA            0000000000000248 000248 000018 18   A  0   0  8
+# DYN-GROW:     .relr.auth.dyn    AARCH64_AUTH_RELR 0000000000000260 000260 000008 08   A  0   0  8
+# DYN-GROW:     .dynamic          DYNAMIC         0000000000020268 000268 0000d0 10  WA  4   0  8
+
+# DYN-GROW:      Dynamic section at offset 0x268 contains 13 entries:
+# DYN-GROW:      0x0000000000000007 (RELA)                 0x248
+# DYN-GROW-NEXT: 0x0000000000000008 (RELASZ)               24 (bytes)
+# DYN-GROW-NEXT: 0x0000000000000009 (RELAENT)              24 (bytes)
+# DYN-GROW-NEXT: 0x0000000070000012 (AARCH64_AUTH_RELR)    0x260
+# DYN-GROW-NEXT: 0x0000000070000011 (AARCH64_AUTH_RELRSZ)  8 (bytes)
+# DYN-GROW-NEXT: 0x0000000070000013 (AARCH64_AUTH_RELRENT) 8 (bytes)
+# DYN-GROW:      0x0000000000000000 (NULL)                 0x0
+# DYN-GROW-EMPTY:
+
+# DYN-GROW:      Relocation section '.rela.dyn' at offset 0x248 contains 1 entries:
+# DYN-GROW-NEXT:     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
+# DYN-GROW-NEXT: 0000000000030340  0000000000000411 R_AARCH64_AUTH_RELATIVE           100030338
+# DYN-GROW-EMPTY:
+
+# DYN-GROW:      Relocation section '.relr.auth.dyn' at offset 0x260 contains 1 entries:
+# DYN-GROW-NEXT: Index: Entry            Address           Symbolic Address
+# DYN-GROW-NEXT: 0000:  0000000000030338 0000000000030338  foo
+# DYN-GROW-EMPTY:
+
+# DYN-GROW:      Hex dump of section '.dynamic':
+# DYN-GROW:      0x00020328 00000000 00000000 00000000 00000000
+# DYN-GROW-EMPTY:
+
+.data
+.balign 8
+foo:
+## Can stay in .relr.auth.dyn
+.quad foo at AUTH(da,42)
+## Will be moved to .rela.dyn
+.quad foo+0x100000000 at AUTH(da,42)
+
+#--- rela-iplt-end.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 rela-iplt-end.s -o rela-iplt-end.o
+# RUN: ld.lld -z pack-relative-relocs rela-iplt-end.o -o rela-iplt-end
+# RUN: llvm-readelf -S -s rela-iplt-end | FileCheck --check-prefix=IPLT-END %s
+
+## Ensure that the end address covers 0x30 bytes for both relocations.
+# IPLT-END:      .rela.dyn         RELA            00000000002001c8 0001c8 000030 18   A  0   0  8
+# IPLT-END:      00000000002001c8     0 NOTYPE  LOCAL  HIDDEN      1 __rela_iplt_start
+# IPLT-END-NEXT: 00000000002001f8     0 NOTYPE  LOCAL  HIDDEN      1 __rela_iplt_end
+
+adrp x0, __rela_iplt_start
+adrp x0, __rela_iplt_end
+
+.data
+.balign 8
+foo:
+## Will be moved to .rela.dyn
+.quad foo+0x100000000 at AUTH(da,42)
+
+## Extra relocation in a section with alignment 1 to force it into .rela.dyn up-front.
+.section .data.rel.ro, "aw"
+.quad foo at AUTH(da,42)
+
+#--- rela-iplt-start.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 rela-iplt-start.s -o rela-iplt-start.o
+# RUN: ld.lld -z pack-relative-relocs rela-iplt-start.o -o rela-iplt-start
+# RUN: llvm-readelf -S -s rela-iplt-start | FileCheck --check-prefix=IPLT-START %s
+
+## Ensure that the __rela_iplt* addresses are properly set given that initially .rela.dyn is empty (before moving relocs from .relr.auth.dyn).
+# IPLT-START:      .rela.dyn         RELA            0000000000200158 000158 000018 18   A  0   0  8
+# IPLT-START:      0000000000200158     0 NOTYPE  LOCAL  HIDDEN      1 __rela_iplt_start
+# IPLT-START-NEXT: 0000000000200170     0 NOTYPE  LOCAL  HIDDEN      1 __rela_iplt_end
+
+adrp x0, __rela_iplt_start
+adrp x0, __rela_iplt_end
+
+.data
+.balign 8
+foo:
+## Will be moved to .rela.dyn
+.quad foo+0x100000000 at AUTH(da,42)


        


More information about the llvm-commits mailing list