diff options
-rwxr-xr-x | test/Object/Inputs/hello-world.macho-x86_64 | bin | 0 -> 8496 bytes | |||
-rw-r--r-- | test/Object/Inputs/macho-archive-x86_64.a | bin | 0 -> 1304 bytes | |||
-rw-r--r-- | test/Object/size-trivial-macho.test | 56 | ||||
-rw-r--r-- | tools/llvm-size/llvm-size.cpp | 247 |
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 Binary files differnew file mode 100755 index 0000000000..d004bedf6a --- /dev/null +++ b/test/Object/Inputs/hello-world.macho-x86_64 diff --git a/test/Object/Inputs/macho-archive-x86_64.a b/test/Object/Inputs/macho-archive-x86_64.a Binary files differnew file mode 100644 index 0000000000..9979ba9dd1 --- /dev/null +++ b/test/Object/Inputs/macho-archive-x86_64.a 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); |