[llvm] [llvm-size] Fix --totals option for Mach-O files (PR #157904)
Ryan Mansfield via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 12 11:25:12 PDT 2025
https://github.com/rjmansfield updated https://github.com/llvm/llvm-project/pull/157904
>From 117ac71069d0651e8f4f0b1df9373f85b791816b Mon Sep 17 00:00:00 2001
From: Ryan Mansfield <ryan_mansfield at apple.com>
Date: Wed, 10 Sep 2025 12:55:14 -0400
Subject: [PATCH 1/2] [llvm-size] Fix --totals option for Mach-O files
The --totals option was not working for Mach-O files because the Darwin
segment size calculation skipped the totals accumulation.
---
llvm/test/tools/llvm-size/totals.test | 148 ++++++++++++++++++++++++++
llvm/tools/llvm-size/llvm-size.cpp | 43 ++++++--
2 files changed, 181 insertions(+), 10 deletions(-)
diff --git a/llvm/test/tools/llvm-size/totals.test b/llvm/test/tools/llvm-size/totals.test
index 6f97dc18fee78..b4ca1f6f2f77f 100644
--- a/llvm/test/tools/llvm-size/totals.test
+++ b/llvm/test/tools/llvm-size/totals.test
@@ -16,6 +16,16 @@
# CHECK-NEXT: [[FILE2]]
# CHECK-NEXT: 18 36 72 126 7e (TOTALS)
+# RUN: yaml2obj %s --docnum=3 -o %t-macho.o
+# RUN: yaml2obj %s --docnum=4 -o %t-macho2.o
+# RUN: llvm-size --totals %t-macho.o %t-macho2.o \
+# RUN: | FileCheck %s --check-prefix=MACHO-CHECK --strict-whitespace --match-full-lines --implicit-check-not={{.}} -DFILE1=%t-macho.o -DFILE2=%t-macho2.o
+
+# MACHO-CHECK:__TEXT __DATA __OBJC others dec hex
+# MACHO-CHECK-NEXT:20 100 0 32 152 98 [[FILE1]]
+# MACHO-CHECK-NEXT:20 200 0 32 252 fc [[FILE2]]
+# MACHO-CHECK-NEXT:40 300 0 64 404 194 (TOTALS)
+
--- !ELF
FileHeader:
Class: ELFCLASS64
@@ -55,3 +65,141 @@ Sections:
Type: SHT_NOBITS
Flags: [SHF_ALLOC, SHF_WRITE]
Size: 32
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x100000C
+ cpusubtype: 0x0
+ filetype: 0x1
+ ncmds: 2
+ sizeofcmds: 352
+ flags: 0x2000
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 312
+ segname: ''
+ vmaddr: 0
+ vmsize: 152
+ fileoff: 384
+ filesize: 152
+ maxprot: 7
+ initprot: 7
+ nsects: 3
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0x0
+ size: 20
+ offset: 0x180
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000400
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - sectname: __data
+ segname: __DATA
+ addr: 0x18
+ size: 100
+ offset: 0x198
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - sectname: __compact_unwind
+ segname: __LD
+ addr: 0x20
+ size: 32
+ offset: 0x200
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x2000000
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 3
+ version: 68157696
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x100000C
+ cpusubtype: 0x0
+ filetype: 0x1
+ ncmds: 2
+ sizeofcmds: 352
+ flags: 0x2000
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 312
+ segname: ''
+ vmaddr: 0
+ vmsize: 252
+ fileoff: 384
+ filesize: 252
+ maxprot: 7
+ initprot: 7
+ nsects: 3
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0x0
+ size: 20
+ offset: 0x180
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000400
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - sectname: __data
+ segname: __DATA
+ addr: 0x18
+ size: 200
+ offset: 0x198
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - sectname: __compact_unwind
+ segname: __LD
+ addr: 0x20
+ size: 32
+ offset: 0x260
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x2000000
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 3
+ version: 68157696
diff --git a/llvm/tools/llvm-size/llvm-size.cpp b/llvm/tools/llvm-size/llvm-size.cpp
index afb6b2386218e..acc7843ffac8b 100644
--- a/llvm/tools/llvm-size/llvm-size.cpp
+++ b/llvm/tools/llvm-size/llvm-size.cpp
@@ -78,6 +78,7 @@ static OutputFormatTy OutputFormat;
static bool DarwinLongFormat;
static RadixTy Radix = RadixTy::decimal;
static bool TotalSizes;
+static bool HasMachOFiles = false;
static std::vector<std::string> InputFilenames;
@@ -92,6 +93,10 @@ static uint64_t TotalObjectData = 0;
static uint64_t TotalObjectBss = 0;
static uint64_t TotalObjectTotal = 0;
+// Darwin-specific totals
+static uint64_t TotalObjectObjc = 0;
+static uint64_t TotalObjectOthers = 0;
+
static void error(const Twine &Message, StringRef File = "") {
HadError = true;
if (File.empty())
@@ -283,6 +288,7 @@ static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
uint64_t total_data = 0;
uint64_t total_objc = 0;
uint64_t total_others = 0;
+ HasMachOFiles = true;
for (const auto &Load : MachO->load_commands()) {
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
@@ -340,6 +346,14 @@ static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
}
uint64_t total = total_text + total_data + total_objc + total_others;
+ if (TotalSizes) {
+ TotalObjectText += total_text;
+ TotalObjectData += total_data;
+ TotalObjectObjc += total_objc;
+ TotalObjectOthers += total_others;
+ TotalObjectTotal += total;
+ }
+
if (!BerkeleyHeaderPrinted) {
outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
BerkeleyHeaderPrinted = true;
@@ -852,16 +866,25 @@ static void printBerkeleyTotals() {
std::string fmtbuf;
raw_string_ostream fmt(fmtbuf);
const char *radix_fmt = getRadixFmt();
- fmt << "%#7" << radix_fmt << "\t"
- << "%#7" << radix_fmt << "\t"
- << "%#7" << radix_fmt << "\t";
- outs() << format(fmtbuf.c_str(), TotalObjectText, TotalObjectData,
- TotalObjectBss);
- fmtbuf.clear();
- fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
- << "%7" PRIx64 "\t";
- outs() << format(fmtbuf.c_str(), TotalObjectTotal, TotalObjectTotal)
- << "(TOTALS)\n";
+
+ if (HasMachOFiles) {
+ // Darwin format totals: __TEXT __DATA __OBJC others dec hex
+ outs() << TotalObjectText << "\t" << TotalObjectData << "\t"
+ << TotalObjectObjc << "\t" << TotalObjectOthers << "\t"
+ << TotalObjectTotal << "\t" << format("%" PRIx64, TotalObjectTotal)
+ << "\t(TOTALS)\n";
+ } else {
+ fmt << "%#7" << radix_fmt << "\t"
+ << "%#7" << radix_fmt << "\t"
+ << "%#7" << radix_fmt << "\t";
+ outs() << format(fmtbuf.c_str(), TotalObjectText, TotalObjectData,
+ TotalObjectBss);
+ fmtbuf.clear();
+ fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
+ << "%7" PRIx64 "\t";
+ outs() << format(fmtbuf.c_str(), TotalObjectTotal, TotalObjectTotal)
+ << "(TOTALS)\n";
+ }
}
int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) {
>From 2762532942eed58adcd6916d68aa5e4c51989e4b Mon Sep 17 00:00:00 2001
From: Ryan Mansfield <ryan_mansfield at apple.com>
Date: Fri, 12 Sep 2025 13:24:46 -0400
Subject: [PATCH 2/2] [llvm-size] Add -z option for Mach-O to exclude
__PAGEZERO size.
Fixes #86644
---
llvm/test/tools/llvm-size/macho-pagezero.test | 56 +++++++++++++++++++
llvm/tools/llvm-size/Opts.td | 2 +
llvm/tools/llvm-size/llvm-size.cpp | 10 +++-
3 files changed, 66 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/tools/llvm-size/macho-pagezero.test
diff --git a/llvm/test/tools/llvm-size/macho-pagezero.test b/llvm/test/tools/llvm-size/macho-pagezero.test
new file mode 100644
index 0000000000000..eda36b972e2f1
--- /dev/null
+++ b/llvm/test/tools/llvm-size/macho-pagezero.test
@@ -0,0 +1,56 @@
+# Test the -z option to skip __PAGEZERO segment in Mach-O files
+
+# RUN: yaml2obj %s --docnum=1 -o %t-pagezero.o
+# RUN: llvm-size %t-pagezero.o | FileCheck %s --check-prefix=NORMAL --match-full-lines --strict-whitespace --implicit-check-not={{.}}
+# RUN: llvm-size -z %t-pagezero.o | FileCheck %s --check-prefix=SKIP --match-full-lines --strict-whitespace --implicit-check-not={{.}}
+
+# NORMAL:__TEXT __DATA __OBJC others dec hex
+# NORMAL-NEXT:20 100 0 4096 4216 1078
+
+# SKIP:__TEXT __DATA __OBJC others dec hex
+# SKIP-NEXT:20 100 0 0 120 78
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x100000C
+ cpusubtype: 0x0
+ filetype: 0x2
+ ncmds: 3
+ sizeofcmds: 216
+ flags: 0x2000
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __PAGEZERO
+ vmaddr: 0x0
+ vmsize: 4096
+ fileoff: 0
+ filesize: 0
+ maxprot: 0
+ initprot: 0
+ nsects: 0
+ flags: 0
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __TEXT
+ vmaddr: 0x100000000
+ vmsize: 20
+ fileoff: 248
+ filesize: 20
+ maxprot: 7
+ initprot: 5
+ nsects: 0
+ flags: 0
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __DATA
+ vmaddr: 0x100001000
+ vmsize: 100
+ fileoff: 268
+ filesize: 100
+ maxprot: 7
+ initprot: 3
+ nsects: 0
+ flags: 0
diff --git a/llvm/tools/llvm-size/Opts.td b/llvm/tools/llvm-size/Opts.td
index edae43f1abd24..65478730c2801 100644
--- a/llvm/tools/llvm-size/Opts.td
+++ b/llvm/tools/llvm-size/Opts.td
@@ -21,6 +21,8 @@ def grp_mach_o : OptionGroup<"kind">, HelpText<"OPTIONS (Mach-O specific)">;
def arch_EQ : Joined<["--"], "arch=">, HelpText<"architecture(s) from a Mach-O file to dump">, Group<grp_mach_o>;
def : Separate<["--", "-"], "arch">, Alias<arch_EQ>;
def l : F<"l", "When format is darwin, use long format to include addresses and offsets">, Group<grp_mach_o>;
+def z : F<"z", "Do not include __PAGEZERO segment in totals">,
+ Group<grp_mach_o>;
def : F<"A", "Alias for --format">, Alias<format_EQ>, AliasArgs<["sysv"]>;
def : F<"B", "Alias for --format">, Alias<format_EQ>, AliasArgs<["berkeley"]>;
diff --git a/llvm/tools/llvm-size/llvm-size.cpp b/llvm/tools/llvm-size/llvm-size.cpp
index acc7843ffac8b..805f8ed1e6dcd 100644
--- a/llvm/tools/llvm-size/llvm-size.cpp
+++ b/llvm/tools/llvm-size/llvm-size.cpp
@@ -79,6 +79,7 @@ static bool DarwinLongFormat;
static RadixTy Radix = RadixTy::decimal;
static bool TotalSizes;
static bool HasMachOFiles = false;
+static bool SkipPageZero = false;
static std::vector<std::string> InputFilenames;
@@ -307,7 +308,9 @@ static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
}
} else {
StringRef SegmentName = StringRef(Seg.segname);
- if (SegmentName == "__TEXT")
+ if (SkipPageZero && SegmentName == "__PAGEZERO")
+ ; // Skip __PAGEZERO segment
+ else if (SegmentName == "__TEXT")
total_text += Seg.vmsize;
else if (SegmentName == "__DATA")
total_data += Seg.vmsize;
@@ -333,7 +336,9 @@ static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
}
} else {
StringRef SegmentName = StringRef(Seg.segname);
- if (SegmentName == "__TEXT")
+ if (SkipPageZero && SegmentName == "__PAGEZERO")
+ ; // Skip __PAGEZERO segment
+ else if (SegmentName == "__TEXT")
total_text += Seg.vmsize;
else if (SegmentName == "__DATA")
total_data += Seg.vmsize;
@@ -914,6 +919,7 @@ int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) {
ELFCommons = Args.hasArg(OPT_common);
DarwinLongFormat = Args.hasArg(OPT_l);
+ SkipPageZero = Args.hasArg(OPT_z);
TotalSizes = Args.hasArg(OPT_totals);
StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley");
if (V == "berkeley")
More information about the llvm-commits
mailing list