[lld] ec5a61a - [lld][MachO] Add `--warn-missing-subsections-via-symbols` flag (#221464)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 10 15:52:33 PDT 2026
Author: Dave MacLachlan
Date: 2026-09-10T15:52:28-07:00
New Revision: ec5a61a1454082773a9071c8a9db0472306a2517
URL: https://github.com/llvm/llvm-project/commit/ec5a61a1454082773a9071c8a9db0472306a2517
DIFF: https://github.com/llvm/llvm-project/commit/ec5a61a1454082773a9071c8a9db0472306a2517.diff
LOG: [lld][MachO] Add `--warn-missing-subsections-via-symbols` flag (#221464)
This change introduces:
* `--warn-missing-subsections-via-symbols`: Warns when an input object
file with non-empty sections is missing `MH_SUBSECTIONS_VIA_SYMBOLS`.
* `--no-warn-missing-subsections-via-symbols`: Disables the warning
(default).
Also adds documentation and lit tests.
Object files missing `MH_SUBSECTIONS_VIA_SYMBOLS` can prevent
dead-stripping and subsection splitting.
We have seen a number of cases where we are compiling assembly, and this
allows us to track them down.
Added:
lld/test/MachO/warn-missing-subsections-via-symbols.s
Modified:
lld/MachO/Config.h
lld/MachO/Driver.cpp
lld/MachO/InputFiles.cpp
lld/MachO/Options.td
lld/docs/MachO/ld64-vs-lld.md
lld/docs/ReleaseNotes.md
Removed:
################################################################################
diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index b90fa18780a8a..a939d7789a758 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -224,6 +224,7 @@ struct Configuration {
llvm::StringRef csProfilePath;
bool pgoWarnMismatch;
bool warnThinArchiveMissingMembers;
+ bool warnMissingSubsectionsViaSymbols = false;
bool disableVerify;
bool separateCstringLiteralSections;
bool tailMergeStrings;
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 92d841dfd3ade..8edaff6e38657 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -2077,6 +2077,9 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
config->warnThinArchiveMissingMembers =
args.hasFlag(OPT_warn_thin_archive_missing_members,
OPT_no_warn_thin_archive_missing_members, true);
+ config->warnMissingSubsectionsViaSymbols =
+ args.hasFlag(OPT_warn_missing_subsections_via_symbols,
+ OPT_no_warn_missing_subsections_via_symbols, false);
config->generateUuid = !args.hasArg(OPT_no_uuid);
config->disableVerify = args.hasArg(OPT_disable_verify);
config->separateCstringLiteralSections =
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 5279eb0e1fea7..8faac4b0614a5 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -1054,6 +1054,9 @@ template <class LP> void ObjFile::parse() {
c->nsyms);
const char *strtab = reinterpret_cast<const char *>(buf) + c->stroff;
bool subsectionsViaSymbols = hdr->flags & MH_SUBSECTIONS_VIA_SYMBOLS;
+ if (config->warnMissingSubsectionsViaSymbols && !subsectionsViaSymbols &&
+ !sectionHeaders.empty())
+ warn(toString(this) + ": missing MH_SUBSECTIONS_VIA_SYMBOLS");
parseSymbols<LP>(sectionHeaders, nList, strtab, subsectionsViaSymbols);
}
diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 0e1faaff139f1..32b6ce0a64a07 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -219,6 +219,9 @@ defm pgo_warn_mismatch: BB<"pgo-warn-mismatch",
defm warn_thin_archive_missing_members : BB<"warn-thin-archive-missing-members",
"Warn on missing object files referenced by thin archives (default)",
"Do not warn on missing object files referenced by thin archives">, Group<grp_lld>;
+defm warn_missing_subsections_via_symbols : BB<"warn-missing-subsections-via-symbols",
+ "Warn if an input object file is missing MH_SUBSECTIONS_VIA_SYMBOLS",
+ "Do not warn if an input object file is missing MH_SUBSECTIONS_VIA_SYMBOLS (default)">, Group<grp_lld>;
// This is a complete Options.td compiled from Apple's ld(1) manpage
// dated 2018-03-07 and cross checked with ld64 source code in repo
diff --git a/lld/docs/MachO/ld64-vs-lld.md b/lld/docs/MachO/ld64-vs-lld.md
index 33be2e41dbe61..0097ce6aa567e 100644
--- a/lld/docs/MachO/ld64-vs-lld.md
+++ b/lld/docs/MachO/ld64-vs-lld.md
@@ -52,3 +52,37 @@ environment variable. LLD flips this default to prefer hermetic builds, but
allows disabling this behavior by setting `ZERO_AR_DATE=0`. Any other value
of `ZERO_AR_DATE` will be ignored.
+## Subsections via Symbols and `--warn-missing-subsections-via-symbols`
+
+In Mach-O object files, the `MH_SUBSECTIONS_VIA_SYMBOLS` header flag (emitted via
+the `.subsections_via_symbols` assembly directive) indicates that sections can be
+divided into independent subsections along symbol boundaries.
+
+When an object file is missing `MH_SUBSECTIONS_VIA_SYMBOLS`:
+- LLD treats each section in that object file as a single monolithic block rather
+ than splitting it into individual symbol-level subsections.
+- **Dead code stripping (`-dead_strip`)**: Unreferenced functions or data in that
+ file cannot be stripped individually. If any symbol in the section is live, the
+ entire section is retained in the output binary.
+- **Identical Code Folding (ICF) and Section Ordering**: Functions cannot be
+ individually deduplicated or reordered via `-order_file`.
+- **Branch range extension thunks**: On architectures with limited direct branch
+ ranges (such as ARM64's $\pm 128\text{ MB}$ limit for `b` / `bl`), large
+ monolithic sections cannot have branch thunk islands inserted within them. In
+ large binaries, this can lead to thunk range overruns (e.g. `relocation
+ R_AARCH64_CALL26 out of range`).
+
+Handwritten assembly files frequently omit `.subsections_via_symbols`. To help
+identify object files causing dead-stripping or layout issues, LLD provides:
+- `--warn-missing-subsections-via-symbols`: Emits a warning when an input object
+ file with non-empty sections is missing `MH_SUBSECTIONS_VIA_SYMBOLS`.
+- `--no-warn-missing-subsections-via-symbols`: Disables the warning (default).
+
+To resolve the warning and allow subsection splitting, add `.subsections_via_symbols`
+to the assembly source:
+```asm
+#if defined(__APPLE__)
+.subsections_via_symbols
+#endif
+```
+
diff --git a/lld/docs/ReleaseNotes.md b/lld/docs/ReleaseNotes.md
index 00c9f5c85af8f..827d09bec5776 100644
--- a/lld/docs/ReleaseNotes.md
+++ b/lld/docs/ReleaseNotes.md
@@ -41,6 +41,11 @@ from the [LLVM releases web site](https://llvm.org/releases/).
call them, so that stubs reached from prioritized code are laid out together.
This applies whenever section priorities exist, such as with `-order_file`.
+* Added `--warn-missing-subsections-via-symbols` and
+ `--no-warn-missing-subsections-via-symbols` to lld to warn when input object
+ files lack the `MH_SUBSECTIONS_VIA_SYMBOLS` flag, which prevents
+ dead-stripping and subsection splitting.
+
### WebAssembly Improvements
* Added support for resolving and merging common data symbols (allocating them
diff --git a/lld/test/MachO/warn-missing-subsections-via-symbols.s b/lld/test/MachO/warn-missing-subsections-via-symbols.s
new file mode 100644
index 0000000000000..52ff5f505759d
--- /dev/null
+++ b/lld/test/MachO/warn-missing-subsections-via-symbols.s
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/no_subsections.s -o %t/no_subsections.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/with_subsections.s -o %t/with_subsections.o
+
+## Default: no warning (even under -fatal_warnings)
+# RUN: %lld -dylib %t/no_subsections.o -o /dev/null 2>&1 | count 0
+
+## Warn when flag is passed
+# RUN: %no-fatal-warnings-lld -dylib %t/no_subsections.o --warn-missing-subsections-via-symbols -o /dev/null 2>&1 \
+# RUN: | FileCheck %s --check-prefix=WARN
+
+## Overridden by --no-warn-missing-subsections-via-symbols
+# RUN: %lld -dylib %t/no_subsections.o --warn-missing-subsections-via-symbols \
+# RUN: --no-warn-missing-subsections-via-symbols -o /dev/null 2>&1 | count 0
+
+## Object with .subsections_via_symbols should not trigger a warning even when flag is passed
+# RUN: %lld -dylib %t/with_subsections.o --warn-missing-subsections-via-symbols -o /dev/null 2>&1 | count 0
+
+# WARN: warning: {{.*}}no_subsections.o: missing MH_SUBSECTIONS_VIA_SYMBOLS
+
+#--- no_subsections.s
+.text
+.globl _foo
+_foo:
+ ret
+
+#--- with_subsections.s
+.text
+.globl _bar
+_bar:
+ ret
+.subsections_via_symbols
More information about the llvm-commits
mailing list