[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