[lld] [lld-macho] Print Objective-C stubs in map files (PR #225302)
Kyungwoo Lee via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 22 22:28:39 PDT 2026
https://github.com/kyulee-com updated https://github.com/llvm/llvm-project/pull/225302
>From 7c894abcca958dc97768165d9f451921d2394ddb Mon Sep 17 00:00:00 2001
From: Kyungwoo Lee <kyulee at meta.com>
Date: Mon, 21 Sep 2026 20:51:10 -0700
Subject: [PATCH 1/3] [lld-macho] Print Objective-C stubs in map files
Match ld-prime by listing synthesized Objective-C message-send stubs in Mach-O map files, including their final addresses and mode-specific sizes.
---
lld/MachO/MapFile.cpp | 10 ++++++++++
lld/MachO/SyntheticSections.h | 1 +
lld/test/MachO/arm64-objc-stubs-dead.s | 20 ++++++++++++++------
lld/test/MachO/arm64-objc-stubs.s | 16 ++++++++++++++--
4 files changed, 39 insertions(+), 8 deletions(-)
diff --git a/lld/MachO/MapFile.cpp b/lld/MachO/MapFile.cpp
index 29ebcdcf9a832d..ab9f2d1daf53b0 100644
--- a/lld/MachO/MapFile.cpp
+++ b/lld/MachO/MapFile.cpp
@@ -141,6 +141,14 @@ static void printStubsEntries(
sym->getName().str().data());
}
+// For printing the contents of the __objc_stubs section.
+static void printObjCStubsEntries(raw_fd_ostream &os,
+ const ObjCStubsSection *osec) {
+ for (const Defined *sym : osec->getSymbols())
+ os << format("0x%08llX\t0x%08llX\t[ 0] %s\n", sym->getVA(), sym->size,
+ sym->getName().str().data());
+}
+
static void printNonLazyPointerSection(raw_fd_ostream &os,
NonLazyPointerSectionBase *osec) {
// ld64 considers stubs to belong to particular files, but considers GOT
@@ -257,6 +265,8 @@ void macho::writeMapFile() {
osec->addr, osec->getSize());
} else if (osec == in.stubs) {
printStubsEntries(os, readerToFileOrdinal, osec, target->stubSize);
+ } else if (osec == in.objcStubs) {
+ printObjCStubsEntries(os, in.objcStubs);
} else if (osec == in.lazyPointers) {
printStubsEntries(os, readerToFileOrdinal, osec, target->wordSize);
} else if (osec == in.stubHelper) {
diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index 9acbd73d277e81..1b5c4e13f8fa95 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -345,6 +345,7 @@ class ObjCStubsSection final : public SyntheticSection {
static constexpr llvm::StringLiteral symbolPrefix = "_objc_msgSend$";
static bool isObjCStubSymbol(Symbol *sym);
static StringRef getMethname(Symbol *sym);
+ ArrayRef<Defined *> getSymbols() const { return symbols; }
/// Stably sort the stubs by \p priorities and reassign their offsets. Must
/// run before addresses are assigned.
diff --git a/lld/test/MachO/arm64-objc-stubs-dead.s b/lld/test/MachO/arm64-objc-stubs-dead.s
index 5dcb171c17eac5..2639db073d83a6 100644
--- a/lld/test/MachO/arm64-objc-stubs-dead.s
+++ b/lld/test/MachO/arm64-objc-stubs-dead.s
@@ -4,24 +4,32 @@
# RUN: %lld -arch arm64 -lSystem -U _objc_msgSend -o %t.out %t.o
# RUN: llvm-nm %t.out | FileCheck %s
-# RUN: %lld -arch arm64 -lSystem -U _objc_msgSend -dead_strip -o %t.out %t.o
-# RUN: llvm-nm %t.out | FileCheck %s --check-prefix=DEAD
+# RUN: %lld -arch arm64 -lSystem -U _objc_msgSend -dead_strip -o %t.out %t.o -map %t.map
+# RUN: llvm-nm %t.out | FileCheck %s --check-prefix=DEAD \
+# RUN: --implicit-check-not=_foo --implicit-check-not='_objc_msgSend$deadsel'
+# RUN: FileCheck %s --check-prefix=DEAD-MAP \
+# RUN: --implicit-check-not='_objc_msgSend$deadsel' < %t.map
# CHECK: _foo
-# CHECK: _objc_msgSend$length
+# CHECK: _objc_msgSend$deadsel
+# CHECK: _objc_msgSend$livesel
-# DEAD-NOT: _foo
-# DEAD-NOT: _objc_msgSend$length
+# DEAD: _objc_msgSend$livesel
+
+# DEAD-MAP: 0x[[#%.8X,OBJC_STUBS:]] 0x00000020 __TEXT __objc_stubs
+# DEAD-MAP-LABEL: # Symbols:
+# DEAD-MAP: 0x[[#OBJC_STUBS]] 0x00000020 [ 0] _objc_msgSend$livesel
.section __TEXT,__text
.globl _foo
_foo:
- bl _objc_msgSend$length
+ bl _objc_msgSend$deadsel
ret
.globl _main
_main:
+ bl _objc_msgSend$livesel
ret
.subsections_via_symbols
diff --git a/lld/test/MachO/arm64-objc-stubs.s b/lld/test/MachO/arm64-objc-stubs.s
index da25b1292faa65..53cf3ebc119f86 100644
--- a/lld/test/MachO/arm64-objc-stubs.s
+++ b/lld/test/MachO/arm64-objc-stubs.s
@@ -1,16 +1,18 @@
# REQUIRES: aarch64
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t.o
-# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -U _external_func
+# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -U _external_func -map %t.map
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
+# RUN: FileCheck %s --check-prefix=MAP < %t.map
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -dead_strip -U _external_func
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_fast -U _external_func
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s
# RUN: llvm-otool -l %t.out | FileCheck %s --check-prefix=FASTALIGN
-# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_small -U _external_func
+# RUN: %lld -arch arm64 -lSystem -o %t.out %t.o -objc_stubs_small -U _external_func -map %t.small.map
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out | FileCheck %s --check-prefix=SMALL
# RUN: llvm-otool -l %t.out | FileCheck %s --check-prefix=SMALLALIGN
+# RUN: FileCheck %s --check-prefix=SMALLMAP < %t.small.map
# RUN: llvm-objdump --section-headers %t.out | FileCheck %s --check-prefix=SECTIONS
# CHECK: Contents of (__TEXT,__objc_stubs) section
@@ -37,6 +39,16 @@
# CHECK-EMPTY:
+# MAP: 0x[[#%.8X,OBJC_STUBS:]] 0x00000040 __TEXT __objc_stubs
+# MAP: # Symbols:
+# MAP-DAG: 0x[[#OBJC_STUBS]] 0x00000020 [ 0] _objc_msgSend$foo
+# MAP-DAG: 0x[[#OBJC_STUBS+0x20]] 0x00000020 [ 0] _objc_msgSend$length
+
+# SMALLMAP: 0x[[#%.8X,OBJC_STUBS:]] 0x00000018 __TEXT __objc_stubs
+# SMALLMAP: # Symbols:
+# SMALLMAP-DAG: 0x[[#OBJC_STUBS]] 0x0000000C [ 0] _objc_msgSend$foo
+# SMALLMAP-DAG: 0x[[#OBJC_STUBS+0xC]] 0x0000000C [ 0] _objc_msgSend$length
+
# FASTALIGN: sectname __objc_stubs
# FASTALIGN-NEXT: segname __TEXT
# FASTALIGN-NEXT: addr
>From c3754f1e7b77f3e692c23bda357451396f27d8ec Mon Sep 17 00:00:00 2001
From: Kyungwoo Lee <kyulee at meta.com>
Date: Tue, 22 Sep 2026 15:29:56 -0700
Subject: [PATCH 2/3] Address ellishg's feedback
---
lld/MachO/MapFile.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lld/MachO/MapFile.cpp b/lld/MachO/MapFile.cpp
index ab9f2d1daf53b0..8d65f39afe8f1e 100644
--- a/lld/MachO/MapFile.cpp
+++ b/lld/MachO/MapFile.cpp
@@ -145,8 +145,8 @@ static void printStubsEntries(
static void printObjCStubsEntries(raw_fd_ostream &os,
const ObjCStubsSection *osec) {
for (const Defined *sym : osec->getSymbols())
- os << format("0x%08llX\t0x%08llX\t[ 0] %s\n", sym->getVA(), sym->size,
- sym->getName().str().data());
+ os << format("0x%08llX\t0x%08llX\t[ 0] ", sym->getVA(), sym->size)
+ << sym->getName() << '\n';
}
static void printNonLazyPointerSection(raw_fd_ostream &os,
>From 3073b4a00414778c15668af2289460962c597e9d Mon Sep 17 00:00:00 2001
From: Kyungwoo Lee <kyulee at meta.com>
Date: Tue, 22 Sep 2026 22:17:21 -0700
Subject: [PATCH 3/3] Address carlocab's feedback
---
lld/test/MachO/objc-stubs-order-file.s | 9 ++++++++-
lld/test/MachO/x86-64-objc-stubs.s | 8 +++++++-
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/lld/test/MachO/objc-stubs-order-file.s b/lld/test/MachO/objc-stubs-order-file.s
index 66fbaaaf4ea8a3..6881bb44b282ed 100644
--- a/lld/test/MachO/objc-stubs-order-file.s
+++ b/lld/test/MachO/objc-stubs-order-file.s
@@ -16,9 +16,10 @@
## _hot is ordered first, so the stub it calls moves ahead of the others, which
## keep their relative order.
# RUN: %lld -arch arm64 -e _main -U _objc_msgSend -o %t/ordered.out %t/a.o \
-# RUN: -objc_stubs_small -order_file %t/order
+# RUN: -objc_stubs_small -order_file %t/order -map %t/ordered.map
# RUN: llvm-objdump --no-show-raw-insn --section=__TEXT,__objc_stubs --macho \
# RUN: %t/ordered.out | FileCheck %s --check-prefix=ORDERED
+# RUN: FileCheck %s --check-prefix=MAP < %t/ordered.map
# RUN: %lld -arch arm64 -e _main -U _objc_msgSend -o %t/fast.out %t/a.o \
# RUN: -objc_stubs_fast -order_file %t/order
@@ -47,6 +48,12 @@
# ORDERED: _objc_msgSend$cold:
# ORDERED: _objc_msgSend$mild:
+# MAP: 0x[[#%.8X,OBJC_STUBS:]] 0x00000024 __TEXT __objc_stubs
+# MAP-LABEL: # Symbols:
+# MAP: 0x[[#OBJC_STUBS]] 0x0000000C [ 0] _objc_msgSend$hot
+# MAP-NEXT: 0x[[#OBJC_STUBS+0xC]] 0x0000000C [ 0] _objc_msgSend$cold
+# MAP-NEXT: 0x[[#OBJC_STUBS+0x18]] 0x0000000C [ 0] _objc_msgSend$mild
+
#--- a.s
.text
.globl _cold
diff --git a/lld/test/MachO/x86-64-objc-stubs.s b/lld/test/MachO/x86-64-objc-stubs.s
index a8bf5de9fe03d3..49a1164247f1da 100644
--- a/lld/test/MachO/x86-64-objc-stubs.s
+++ b/lld/test/MachO/x86-64-objc-stubs.s
@@ -1,11 +1,12 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
-# RUN: %lld -arch x86_64 -lSystem -o %t.out %t.o
+# RUN: %lld -arch x86_64 -lSystem -o %t.out %t.o -map %t.map
# RUN: llvm-objdump --macho --section-headers %t.out > %t.txt
# RUN: llvm-otool -vs __DATA __objc_selrefs %t.out >> %t.txt
# RUN: llvm-otool -vs __TEXT __objc_stubs %t.out >> %t.txt
# RUN: FileCheck %s < %t.txt
+# RUN: FileCheck %s --check-prefix=MAP < %t.map
# RUN: %no-fatal-warnings-lld -arch x86_64 -lSystem -o %t.out %t.o -objc_stubs_small 2>&1 | FileCheck %s --check-prefix=WARNING
# WARNING: warning: -objc_stubs_small is not yet implemented, defaulting to -objc_stubs_fast
@@ -49,6 +50,11 @@
# CHECK-EMPTY:
+# MAP: 0x[[#%.8X,OBJC_STUBS:]] 0x0000001A __TEXT __objc_stubs
+# MAP-LABEL: # Symbols:
+# MAP: 0x[[#OBJC_STUBS]] 0x0000000D [ 0] _objc_msgSend$foo
+# MAP-NEXT: 0x[[#OBJC_STUBS+0xD]] 0x0000000D [ 0] _objc_msgSend$length
+
.section __TEXT,__objc_methname,cstring_literals
lselref1:
.asciz "foo"
More information about the llvm-commits
mailing list