[llvm-branch-commits] [lld] [lld-macho] Match ld64 for arm64e TLV bootstrap binds and map files (PR #234004)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Oct 21 10:47:57 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-macho
Author: Oskar Wirga (oskarwirga)
<details>
<summary>Changes</summary>
Two small arm64e changes:
1. Sign the arm64e TLV bootstrap pointer as ld64 does. The first word of a thread-local variable descriptor is bound to `__tlv_bootstrap`, which dyld replaces with a pointer to `tlv_get_addr` that TLV accesses call with `blraaz`. On arm64e, write that bind as an auth'd bind with the IA key and no diversity, even though the object asks for a plain pointer.
2. List arm64e `__auth_got` entries in the map file. The map file printed the entries of `__got` but not those of `__auth_got`, which holds the targets of the stubs and the personalities.
Assisted-by: Claude
---
Full diff: https://github.com/llvm/llvm-project/pull/234004.diff
6 Files Affected:
- (modified) lld/MachO/InputSection.cpp (+16-1)
- (modified) lld/MachO/InputSection.h (+2)
- (modified) lld/MachO/MapFile.cpp (+11-6)
- (modified) lld/MachO/Writer.cpp (+2-1)
- (added) lld/test/MachO/arm64e-map.s (+36)
- (added) lld/test/MachO/arm64e-tlv-bootstrap.s (+30)
``````````diff
diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp
index 24e9283d05db5..a1fbd48b9044a 100644
--- a/lld/MachO/InputSection.cpp
+++ b/lld/MachO/InputSection.cpp
@@ -271,7 +271,10 @@ void ConcatInputSection::writeTo(uint8_t *buf) {
!target->hasAttr(r.type, RelocAttrBits::AUTH)) {
referentVA -= firstTLVDataSection->addr;
} else if (needsFixup) {
- writeChainedFixup(loc, referentSym, r.getAddend(), r.getAuthInfo());
+ const AuthInfo *auth = r.getAuthInfo();
+ if (!auth)
+ auth = getImplicitAuthInfo(this, referentSym);
+ writeChainedFixup(loc, referentSym, r.getAddend(), auth);
continue;
}
} else if (auto *referentIsec = r.referent.dyn_cast<InputSection *>()) {
@@ -420,6 +423,18 @@ bool macho::usesAuthGot(const InputSection *isec) {
return config->arch() == AK_arm64e && isEhFrameSection(isec);
}
+const AuthInfo *macho::getImplicitAuthInfo(const InputSection *isec,
+ const Symbol *sym) {
+ // The only pointer bound from a TLV descriptor is its thunk, which TLV
+ // accesses call with blraaz.
+ static constexpr AuthInfo tlvThunk = {/*diversity=*/0, PtrAuthKeyIA,
+ /*addrDiv=*/false};
+ if (config->arch() == AK_arm64e && isThreadLocalVariables(isec->getFlags()) &&
+ needsBinding(sym))
+ return &tlvThunk;
+ return nullptr;
+}
+
bool macho::isGccExceptTabSection(const InputSection *isec) {
return isec->getName() == section_names::gccExceptTab &&
isec->getSegName() == segment_names::text;
diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h
index abb130b4c363e..47e32429ea49b 100644
--- a/lld/MachO/InputSection.h
+++ b/lld/MachO/InputSection.h
@@ -311,6 +311,8 @@ bool isSelRefsSection(const InputSection *);
bool isEhFrameSection(const InputSection *);
bool isGccExceptTabSection(const InputSection *);
bool usesAuthGot(const InputSection *);
+const AuthInfo *getImplicitAuthInfo(const InputSection *isec,
+ const Symbol *sym);
extern std::vector<ConcatInputSection *> inputSections;
// This is used as a counter for specyfing input order for input sections
diff --git a/lld/MachO/MapFile.cpp b/lld/MachO/MapFile.cpp
index 93d0e87a402a1..d85e19fc09bae 100644
--- a/lld/MachO/MapFile.cpp
+++ b/lld/MachO/MapFile.cpp
@@ -149,15 +149,15 @@ static void printObjCStubsEntries(raw_fd_ostream &os,
<< sym->getName() << '\n';
}
-static void printNonLazyPointerSection(raw_fd_ostream &os, GotSection *osec) {
+// For printing the entries of the __got and __auth_got sections.
+static void printNonLazyPointer(raw_fd_ostream &os, uint64_t va,
+ const Symbol *sym) {
// ld64 considers stubs to belong to particular files, but considers GOT
// entries to be linker-synthesized. Not sure why they made that decision, but
// I think we can follow suit unless there's demand for better symbol-to-file
// associations.
- for (const Symbol *sym : osec->getEntries())
- os << format("0x%08llX\t0x%08zX\t[ 0] non-lazy-pointer-to-local: %s\n",
- osec->addr + sym->gotIndex * target->wordSize,
- target->wordSize, sym->getName().str().data());
+ os << format("0x%08llX\t0x%08zX\t[ 0] non-lazy-pointer-to-local: %s\n", va,
+ target->wordSize, sym->getName().str().data());
}
static uint64_t getSymSizeForMap(Defined *sym) {
@@ -273,7 +273,12 @@ void macho::writeMapFile() {
os << format("0x%08llX\t0x%08llX\t[ 0] helper helper\n", osec->addr,
osec->getSize());
} else if (osec == in.got) {
- printNonLazyPointerSection(os, in.got);
+ for (const Symbol *sym : in.got->getEntries())
+ printNonLazyPointer(
+ os, in.got->addr + sym->gotIndex * target->wordSize, sym);
+ } else if (in.authGot && osec == in.authGot) {
+ for (const Symbol *sym : in.authGot->getEntries())
+ printNonLazyPointer(os, in.authGot->getVA(sym), sym);
} else if (osec == in.objcMethList) {
printIsecArrSyms(in.objcMethList->getInputs());
}
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 97db232fbfcbb..bb556c17c52be 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -704,7 +704,8 @@ static void prepareSymbolRelocation(Symbol *sym, const InputSection *isec,
if (isAuth ||
!(isThreadLocalVariables(isec->getFlags()) && isa<Defined>(sym)))
addNonLazyBindingEntries(sym, isec, r.offset, r.getAddend(),
- /*forceOutlineAuth=*/isAuth);
+ /*forceOutlineAuth=*/isAuth ||
+ getImplicitAuthInfo(isec, sym));
}
}
diff --git a/lld/test/MachO/arm64e-map.s b/lld/test/MachO/arm64e-map.s
new file mode 100644
index 0000000000000..c751368c06d04
--- /dev/null
+++ b/lld/test/MachO/arm64e-map.s
@@ -0,0 +1,36 @@
+# REQUIRES: aarch64
+## The map file lists the entries of arm64e's __auth_got like those of __got.
+
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=arm64e-apple-macos -o %t/foo.o %t/foo.s
+# RUN: llvm-mc -filetype=obj -triple=arm64e-apple-macos -o %t/test.o %t/test.s
+# RUN: %lld -arch arm64e -platform_version macos 13.0 13.0 -dylib \
+# RUN: -install_name @executable_path/libfoo.dylib %t/foo.o -o %t/libfoo.dylib
+# RUN: %lld -arch arm64e -platform_version macos 13.0 13.0 %t/test.o \
+# RUN: %t/libfoo.dylib -map %t/map -o %t/test
+# RUN: llvm-objdump --macho --section-headers %t/test > %t/out
+# RUN: cat %t/map >> %t/out
+# RUN: FileCheck %s < %t/out
+
+# CHECK: __auth_got {{[0-9a-f]+}} {{0*}}[[#%x,AUTH_GOT:]] DATA
+# CHECK: __got {{[0-9a-f]+}} {{0*}}[[#%x,GOT:]] DATA
+# CHECK-LABEL: # Sections:
+# CHECK: 0x[[#%X,AUTH_GOT]] 0x00000008 __DATA_CONST __auth_got
+# CHECK: 0x[[#%X,GOT]] 0x00000008 __DATA_CONST __got
+# CHECK-LABEL: # Symbols:
+# CHECK: 0x[[#%X,AUTH_GOT]] 0x00000008 [ 0] non-lazy-pointer-to-local: _foo
+# CHECK: 0x[[#%X,GOT]] 0x00000008 [ 0] non-lazy-pointer-to-local: _foo
+
+#--- foo.s
+.globl _foo
+_foo:
+ ret
+
+#--- test.s
+.globl _main
+.p2align 2
+_main:
+ bl _foo
+ adrp x0, _foo at GOTPAGE
+ ldr x0, [x0, _foo at GOTPAGEOFF]
+ ret
diff --git a/lld/test/MachO/arm64e-tlv-bootstrap.s b/lld/test/MachO/arm64e-tlv-bootstrap.s
new file mode 100644
index 0000000000000..44c0cd98db2ab
--- /dev/null
+++ b/lld/test/MachO/arm64e-tlv-bootstrap.s
@@ -0,0 +1,30 @@
+# REQUIRES: aarch64
+## On arm64e, the thunk pointer of a thread-local variable descriptor, a bind to
+## __tlv_bootstrap, is an authenticated bind with the IA key and no diversity,
+## because TLV accesses call it with blraaz. On arm64 it is a plain bind.
+
+# RUN: llvm-mc -filetype=obj -triple=arm64e-apple-macos -o %t-arm64e.o %s
+# RUN: %lld -arch arm64e -platform_version macos 13.0 13.0 -dylib %t-arm64e.o \
+# RUN: -o %t-arm64e.dylib
+# RUN: llvm-objdump --macho --dyld-info %t-arm64e.dylib | \
+# RUN: FileCheck %s --check-prefix=ARM64E
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o %t-arm64.o %s
+# RUN: %lld -arch arm64 -platform_version macos 13.0 13.0 -dylib %t-arm64.o \
+# RUN: -o %t-arm64.dylib
+# RUN: llvm-objdump --macho --dyld-info %t-arm64.dylib | \
+# RUN: FileCheck %s --check-prefix=ARM64
+
+# ARM64E: __DATA __thread_vars 0x{{[0-9A-F]+}} 0x{{[0-9A-F]+}} bind 0x0000 false IA 0x0 libSystem __tlv_bootstrap
+# ARM64: __DATA __thread_vars 0x{{[0-9A-F]+}} 0x{{[0-9A-F]+}} bind 0x0 libSystem __tlv_bootstrap
+
+.section __DATA,__thread_data,thread_local_regular
+.p2align 2
+_tv$tlv$init:
+ .long 5
+
+.section __DATA,__thread_vars,thread_local_variables
+.globl _tv
+_tv:
+ .quad __tlv_bootstrap
+ .quad 0
+ .quad _tv$tlv$init
``````````
</details>
https://github.com/llvm/llvm-project/pull/234004
More information about the llvm-branch-commits
mailing list