summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtest/Object/Inputs/hello-world.macho-x86_64bin0 -> 8496 bytes
-rw-r--r--test/Object/Inputs/macho-archive-x86_64.abin0 -> 1304 bytes
-rw-r--r--test/Object/size-trivial-macho.test56
-rw-r--r--tools/llvm-size/llvm-size.cpp247
4 files changed, 276 insertions, 27 deletions
diff --git a/test/Object/Inputs/hello-world.macho-x86_64 b/test/Object/Inputs/hello-world.macho-x86_64
new file mode 100755
index 0000000000..d004bedf6a
--- /dev/null
+++ b/test/Object/Inputs/hello-world.macho-x86_64
Binary files differ
diff --git a/test/Object/Inputs/macho-archive-x86_64.a b/test/Object/Inputs/macho-archive-x86_64.a
new file mode 100644
index 0000000000..9979ba9dd1
--- /dev/null
+++ b/test/Object/Inputs/macho-archive-x86_64.a
Binary files differ
diff --git a/test/Object/size-trivial-macho.test b/test/Object/size-trivial-macho.test
index 6ecdf5c2a8..960fb25fbe 100644
--- a/test/Object/size-trivial-macho.test
+++ b/test/Object/size-trivial-macho.test
@@ -2,6 +2,14 @@ RUN: llvm-size -A %p/Inputs/macho-text-data-bss.macho-x86_64 \
RUN: | FileCheck %s -check-prefix A
RUN: llvm-size -B %p/Inputs/macho-text-data-bss.macho-x86_64 \
RUN: | FileCheck %s -check-prefix B
+RUN: llvm-size -format darwin %p/Inputs/macho-text-data-bss.macho-x86_64 \
+RUN: | FileCheck %s -check-prefix m
+RUN: llvm-size %p/Inputs/macho-archive-x86_64.a \
+RUN: | FileCheck %s -check-prefix AR
+RUN: llvm-size -format darwin %p/Inputs/macho-archive-x86_64.a \
+RUN: | FileCheck %s -check-prefix mAR
+RUN: llvm-size -format darwin -x -l %p/Inputs/hello-world.macho-x86_64 \
+RUN: | FileCheck %s -check-prefix mxl
A: section size addr
A: __text 12 0
@@ -11,5 +19,49 @@ A: __compact_unwind 32 16
A: __eh_frame 64 48
A: Total 116
-B: text data bss dec hex filename
-B: 12 100 4 116 74
+B: __TEXT __DATA __OBJC others dec hex
+B: 76 8 0 32 116 74
+
+m: Segment : 116
+m: Section (__TEXT, __text): 12
+m: Section (__DATA, __data): 4
+m: Section (__DATA, __bss): 4
+m: Section (__LD, __compact_unwind): 32
+m: Section (__TEXT, __eh_frame): 64
+m: total 116
+m: total 116
+
+AR: __TEXT __DATA __OBJC others dec hex
+AR: 70 0 0 32 102 66 {{.*}}/macho-archive-x86_64.a(foo.o)
+AR: 0 4 0 0 4 4 {{.*}}/macho-archive-x86_64.a(bar.o)
+
+mAR: {{.*}}/macho-archive-x86_64.a(foo.o):
+mAR: Segment : 104
+mAR: Section (__TEXT, __text): 6
+mAR: Section (__LD, __compact_unwind): 32
+mAR: Section (__TEXT, __eh_frame): 64
+mAR: total 102
+mAR: total 104
+mAR: {{.*}}/macho-archive-x86_64.a(bar.o):
+mAR: Segment : 4
+mAR: Section (__TEXT, __text): 0
+mAR: Section (__DATA, __data): 4
+mAR: total 4
+mAR: total 4
+
+
+mxl: Segment __PAGEZERO: 0x100000000 (vmaddr 0x0 fileoff 0)
+mxl: Segment __TEXT: 0x1000 (vmaddr 0x100000000 fileoff 0)
+mxl: Section __text: 0x3b (addr 0x100000f30 offset 3888)
+mxl: Section __stubs: 0x6 (addr 0x100000f6c offset 3948)
+mxl: Section __stub_helper: 0x1a (addr 0x100000f74 offset 3956)
+mxl: Section __cstring: 0xd (addr 0x100000f8e offset 3982)
+mxl: Section __unwind_info: 0x48 (addr 0x100000f9b offset 3995)
+mxl: Section __eh_frame: 0x18 (addr 0x100000fe8 offset 4072)
+mxl: total 0xc8
+mxl: Segment __DATA: 0x1000 (vmaddr 0x100001000 fileoff 4096)
+mxl: Section __nl_symbol_ptr: 0x10 (addr 0x100001000 offset 4096)
+mxl: Section __la_symbol_ptr: 0x8 (addr 0x100001010 offset 4112)
+mxl: total 0x18
+mxl: Segment __LINKEDIT: 0x1000 (vmaddr 0x100002000 fileoff 8192)
+mxl: total 0x100003000
diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp
index ebd41a5280..5e4e4aa932 100644
--- a/tools/llvm-size/llvm-size.cpp
+++ b/tools/llvm-size/llvm-size.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/APInt.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/MachO.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@@ -31,13 +32,13 @@
using namespace llvm;
using namespace object;
-enum OutputFormatTy {berkeley, sysv};
+enum OutputFormatTy {berkeley, sysv, darwin};
static cl::opt<OutputFormatTy>
OutputFormat("format",
cl::desc("Specify output format"),
cl::values(clEnumVal(sysv, "System V format"),
clEnumVal(berkeley, "Berkeley format"),
- clEnumValEnd),
+ clEnumVal(darwin, "Darwin -m format"), clEnumValEnd),
cl::init(berkeley));
static cl::opt<OutputFormatTy>
@@ -47,6 +48,13 @@ static cl::opt<OutputFormatTy>
clEnumValEnd),
cl::init(berkeley));
+static bool berkeleyHeaderPrinted = false;
+static bool moreThanOneFile = false;
+
+cl::opt<bool> DarwinLongFormat("l",
+ cl::desc("When format is darwin, use long format "
+ "to include addresses and offsets."));
+
enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16};
static cl::opt<unsigned int>
Radix("-radix",
@@ -85,6 +93,182 @@ static size_t getNumLengthAsString(uint64_t num) {
return result.size();
}
+/// @brief Return the the printing format for the Radix.
+static const char * getRadixFmt(void) {
+ switch (Radix) {
+ case octal:
+ return PRIo64;
+ case decimal:
+ return PRIu64;
+ case hexadecimal:
+ return PRIx64;
+ }
+ return nullptr;
+}
+
+/// @brief Print the size of each Mach-O segment and section in @p MachO.
+///
+/// This is when used when @c OutputFormat is darwin and produces the same
+/// output as darwin's size(1) -m output.
+static void PrintDarwinSectionSizes(MachOObjectFile *MachO) {
+ std::string fmtbuf;
+ raw_string_ostream fmt(fmtbuf);
+ const char *radix_fmt = getRadixFmt();
+ if (Radix == hexadecimal)
+ fmt << "0x";
+ fmt << "%" << radix_fmt;
+
+ uint32_t LoadCommandCount = MachO->getHeader().ncmds;
+ uint32_t Filetype = MachO->getHeader().filetype;
+ MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
+
+ uint64_t total = 0;
+ for (unsigned I = 0; ; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
+ outs() << "Segment " << Seg.segname << ": "
+ << format(fmt.str().c_str(), Seg.vmsize);
+ if (DarwinLongFormat)
+ outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr)
+ << " fileoff " << Seg.fileoff << ")";
+ outs() << "\n";
+ total += Seg.vmsize;
+ uint64_t sec_total = 0;
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = MachO->getSection64(Load, J);
+ if (Filetype == MachO::MH_OBJECT)
+ outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
+ << format("%.16s", &Sec.sectname) << "): ";
+ else
+ outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
+ outs() << format(fmt.str().c_str(), Sec.size);
+ if (DarwinLongFormat)
+ outs() << " (addr 0x" << format("%" PRIx64, Sec.addr)
+ << " offset " << Sec.offset << ")";
+ outs() << "\n";
+ sec_total += Sec.size;
+ }
+ if (Seg.nsects != 0)
+ outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
+ }
+ else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
+ outs() << "Segment " << Seg.segname << ": "
+ << format(fmt.str().c_str(), Seg.vmsize);
+ if (DarwinLongFormat)
+ outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr)
+ << " fileoff " << Seg.fileoff << ")";
+ outs() << "\n";
+ total += Seg.vmsize;
+ uint64_t sec_total = 0;
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section Sec = MachO->getSection(Load, J);
+ if (Filetype == MachO::MH_OBJECT)
+ outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
+ << format("%.16s", &Sec.sectname) << "): ";
+ else
+ outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
+ outs() << format(fmt.str().c_str(), Sec.size);
+ if (DarwinLongFormat)
+ outs() << " (addr 0x" << format("%" PRIx64, Sec.addr)
+ << " offset " << Sec.offset << ")";
+ outs() << "\n";
+ sec_total += Sec.size;
+ }
+ if (Seg.nsects != 0)
+ outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = MachO->getNextLoadCommandInfo(Load);
+ }
+ outs() << "total " << format(fmt.str().c_str(), total) << "\n";
+}
+
+/// @brief Print the summary sizes of the standard Mach-O segments in @p MachO.
+///
+/// This is when used when @c OutputFormat is berkeley with a Mach-O file and
+/// produces the same output as darwin's size(1) default output.
+static void PrintDarwinSegmentSizes(MachOObjectFile *MachO) {
+ uint32_t LoadCommandCount = MachO->getHeader().ncmds;
+ MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
+
+ uint64_t total_text = 0;
+ uint64_t total_data = 0;
+ uint64_t total_objc = 0;
+ uint64_t total_others = 0;
+ for (unsigned I = 0; ; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
+ if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = MachO->getSection64(Load, J);
+ StringRef SegmentName = StringRef(Sec.segname);
+ if (SegmentName == "__TEXT")
+ total_text += Sec.size;
+ else if (SegmentName == "__DATA")
+ total_data += Sec.size;
+ else if (SegmentName == "__OBJC")
+ total_objc += Sec.size;
+ else
+ total_others += Sec.size;
+ }
+ } else {
+ StringRef SegmentName = StringRef(Seg.segname);
+ if (SegmentName == "__TEXT")
+ total_text += Seg.vmsize;
+ else if (SegmentName == "__DATA")
+ total_data += Seg.vmsize;
+ else if (SegmentName == "__OBJC")
+ total_objc += Seg.vmsize;
+ else
+ total_others += Seg.vmsize;
+ }
+ }
+ else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
+ if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section Sec = MachO->getSection(Load, J);
+ StringRef SegmentName = StringRef(Sec.segname);
+ if (SegmentName == "__TEXT")
+ total_text += Sec.size;
+ else if (SegmentName == "__DATA")
+ total_data += Sec.size;
+ else if (SegmentName == "__OBJC")
+ total_objc += Sec.size;
+ else
+ total_others += Sec.size;
+ }
+ } else {
+ StringRef SegmentName = StringRef(Seg.segname);
+ if (SegmentName == "__TEXT")
+ total_text += Seg.vmsize;
+ else if (SegmentName == "__DATA")
+ total_data += Seg.vmsize;
+ else if (SegmentName == "__OBJC")
+ total_objc += Seg.vmsize;
+ else
+ total_others += Seg.vmsize;
+ }
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = MachO->getNextLoadCommandInfo(Load);
+ }
+ uint64_t total = total_text + total_data + total_objc + total_others;
+
+ if (!berkeleyHeaderPrinted) {
+ outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
+ berkeleyHeaderPrinted = true;
+ }
+ outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
+ << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
+ << "\t";
+}
+
/// @brief Print the size of each section in @p Obj.
///
/// The format used is determined by @c OutputFormat and @c Radix.
@@ -92,20 +276,19 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
uint64_t total = 0;
std::string fmtbuf;
raw_string_ostream fmt(fmtbuf);
-
- const char *radix_fmt = nullptr;
- switch (Radix) {
- case octal:
- radix_fmt = PRIo64;
- break;
- case decimal:
- radix_fmt = PRIu64;
- break;
- case hexadecimal:
- radix_fmt = PRIx64;
- break;
- }
- if (OutputFormat == sysv) {
+ const char *radix_fmt = getRadixFmt();
+
+ // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
+ // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
+ // let it fall through to OutputFormat berkeley.
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
+ if (OutputFormat == darwin && MachO)
+ PrintDarwinSectionSizes(MachO);
+ // If we have a MachOObjectFile and the OutputFormat is berkeley print as
+ // darwin's default berkeley format for Mach-O files.
+ else if (MachO && OutputFormat == berkeley)
+ PrintDarwinSegmentSizes(MachO);
+ else if (OutputFormat == sysv) {
// Run two passes over all sections. The first gets the lengths needed for
// formatting the output. The second actually does the output.
std::size_t max_name_len = strlen("section");
@@ -204,6 +387,13 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
total = total_text + total_data + total_bss;
+ if (!berkeleyHeaderPrinted) {
+ outs() << " text data bss "
+ << (Radix == octal ? "oct" : "dec")
+ << " hex filename\n";
+ berkeleyHeaderPrinted = true;
+ }
+
// Print result.
fmt << "%#7" << radix_fmt << " "
<< "%#7" << radix_fmt << " "
@@ -251,20 +441,31 @@ static void PrintFileSectionSizes(StringRef file) {
continue;
}
if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
if (OutputFormat == sysv)
outs() << o->getFileName() << " (ex " << a->getFileName()
<< "):\n";
+ else if(MachO && OutputFormat == darwin)
+ outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
PrintObjectSectionSizes(o);
- if (OutputFormat == berkeley)
- outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
+ if (OutputFormat == berkeley) {
+ if (MachO)
+ outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
+ else
+ outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
+ }
}
}
} else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
if (OutputFormat == sysv)
outs() << o->getFileName() << " :\n";
PrintObjectSectionSizes(o);
- if (OutputFormat == berkeley)
- outs() << o->getFileName() << "\n";
+ if (OutputFormat == berkeley) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
+ if (!MachO || moreThanOneFile)
+ outs() << o->getFileName();
+ outs() << "\n";
+ }
} else {
errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n";
}
@@ -290,11 +491,7 @@ int main(int argc, char **argv) {
if (InputFilenames.size() == 0)
InputFilenames.push_back("a.out");
- if (OutputFormat == berkeley)
- outs() << " text data bss "
- << (Radix == octal ? "oct" : "dec")
- << " hex filename\n";
-
+ moreThanOneFile = InputFilenames.size() > 1;
std::for_each(InputFilenames.begin(), InputFilenames.end(),
PrintFileSectionSizes);