From a1703b1fc206f2050de9160f9bc1f85a1aa000dc Mon Sep 17 00:00:00 2001 From: Michael Trent Date: Fri, 15 Dec 2017 17:57:40 +0000 Subject: [PATCH] Updated llvm-objdump to display local relocations in Mach-O binaries Summary: llvm-objdump's Mach-O parser was updated in r306037 to display external relocations for MH_KEXT_BUNDLE file types. This change extends the Macho-O parser to display local relocations for MH_PRELOAD files. When used with the -macho option relocations will be displayed in a historical format. All tests are passing for llvm, clang, and lld. llvm-objdump builds without compiler warnings. rdar://35778019 Reviewers: enderby Reviewed By: enderby Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D41199 llvm-svn: 320832 --- llvm/include/llvm/Object/MachO.h | 3 + llvm/lib/Object/MachOObjectFile.cpp | 24 +- .../X86/Inputs/macho-preload-x86_64 | Bin 0 -> 1084 bytes .../X86/macho-preload-relocations.test | 5 + .../llvm-objdump/X86/macho-relocations.test | 12 +- .../llvm-objdump/X86/malformed-machos.test | 2 +- llvm/tools/llvm-objdump/MachODump.cpp | 336 +++++++++++++++++- 7 files changed, 371 insertions(+), 11 deletions(-) create mode 100755 llvm/test/tools/llvm-objdump/X86/Inputs/macho-preload-x86_64 create mode 100644 llvm/test/tools/llvm-objdump/X86/macho-preload-relocations.test diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index 59297eaffbda..d0cc40da4293 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -329,6 +329,9 @@ public: return make_range(extrel_begin(), extrel_end()); } + relocation_iterator locrel_begin() const; + relocation_iterator locrel_end() const; + void moveRelocationNext(DataRefImpl &Rel) const override; uint64_t getRelocationOffset(DataRefImpl Rel) const override; symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 83becc413198..2e3415618e5f 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -1960,6 +1960,7 @@ MachOObjectFile::section_rel_end(DataRefImpl Sec) const { relocation_iterator MachOObjectFile::extrel_begin() const { DataRefImpl Ret; + // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations Ret.d.a = 0; // Would normally be a section index. Ret.d.b = 0; // Index into the external relocations return relocation_iterator(RelocationRef(Ret, this)); @@ -1968,11 +1969,29 @@ relocation_iterator MachOObjectFile::extrel_begin() const { relocation_iterator MachOObjectFile::extrel_end() const { MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); DataRefImpl Ret; + // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations Ret.d.a = 0; // Would normally be a section index. Ret.d.b = DysymtabLoadCmd.nextrel; // Index into the external relocations return relocation_iterator(RelocationRef(Ret, this)); } +relocation_iterator MachOObjectFile::locrel_begin() const { + DataRefImpl Ret; + // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations + Ret.d.a = 1; // Would normally be a section index. + Ret.d.b = 0; // Index into the local relocations + return relocation_iterator(RelocationRef(Ret, this)); +} + +relocation_iterator MachOObjectFile::locrel_end() const { + MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); + DataRefImpl Ret; + // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations + Ret.d.a = 1; // Would normally be a section index. + Ret.d.b = DysymtabLoadCmd.nlocrel; // Index into the local relocations + return relocation_iterator(RelocationRef(Ret, this)); +} + void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const { ++Rel.d.b; } @@ -4301,7 +4320,10 @@ MachOObjectFile::getRelocation(DataRefImpl Rel) const { } } else { MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); - Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations + if (Rel.d.a == 0) + Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations + else + Offset = DysymtabLoadCmd.locreloff; // Offset to the local relocations } auto P = reinterpret_cast( diff --git a/llvm/test/tools/llvm-objdump/X86/Inputs/macho-preload-x86_64 b/llvm/test/tools/llvm-objdump/X86/Inputs/macho-preload-x86_64 new file mode 100755 index 0000000000000000000000000000000000000000..236606e77c6a258f25de6e7338b61fe0e80ea1a8 GIT binary patch literal 1084 zcmX^A>+L^w1_nlE1_lOJAZ7z%4j_k-K>^5OV2}i23q}Tp`1lalh!C(4gkXYD4N##3 zkO4r@045n2fM$Ztg9-!nm!wvdKqY|`F7xD}Ns35v| z@=*72L*?sX4uSHa(r_c=<5M%@(~1&vQz1g=<{3aWI6!qw0GfwpB-|_z0~BsEfH*$h z#WBPYBmw~qP;(TZ{0C4&V0=)xfrNlT4hHe@DTyVCP!5p7WgZ7q3CKKr?gCja0mK}@ zzy+~2fV2pZ28B}q5Q6~7ZWx9-7c5Q`0W=S!R~m>x_5{Cp{I2KtP!*t<3=nVl4*{@z!r;g!(8lD<3(B|HfC>@*11e$T i1Zw63MhYx_g0%62A`+@!fgwIMucWAwAwIVfmhk}C6Hc1| literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-objdump/X86/macho-preload-relocations.test b/llvm/test/tools/llvm-objdump/X86/macho-preload-relocations.test new file mode 100644 index 000000000000..dda0b2b465bb --- /dev/null +++ b/llvm/test/tools/llvm-objdump/X86/macho-preload-relocations.test @@ -0,0 +1,5 @@ +// RUN: llvm-objdump -macho -r %p/Inputs/macho-preload-x86_64 | FileCheck %s + +CHECK: Local relocation information 1 entries +CHECK: address pcrel length extern type scattered symbolnum/value +CHECK: 00000000 False quad False UNSIGND False 2 (__TEXT,__cstring) diff --git a/llvm/test/tools/llvm-objdump/X86/macho-relocations.test b/llvm/test/tools/llvm-objdump/X86/macho-relocations.test index 536aec8b1bcc..111cf0cc95b7 100644 --- a/llvm/test/tools/llvm-objdump/X86/macho-relocations.test +++ b/llvm/test/tools/llvm-objdump/X86/macho-relocations.test @@ -1,7 +1,9 @@ RUN: llvm-objdump -macho -r %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s -CHECK: RELOCATION RECORDS FOR [__text]: -CHECK: 0000000000000027 X86_64_RELOC_BRANCH _printf -CHECK: 000000000000000b X86_64_RELOC_SIGNED L_.str -CHECK: RELOCATION RECORDS FOR [__compact_unwind]: -CHECK: 0000000000000000 X86_64_RELOC_UNSIGNED __text +CHECK: Relocation information (__TEXT,__text) 2 entries +CHECK: address pcrel length extern type scattered symbolnum/value +CHECK: 00000027 True long True BRANCH False _printf +CHECK: 0000000b True long True SIGNED False L_.str +CHECK: Relocation information (__LD,__compact_unwind) 1 entries +CHECK: address pcrel length extern type scattered symbolnum/value +CHECK: 00000000 False quad False UNSIGND False 1 (__TEXT,__text) diff --git a/llvm/test/tools/llvm-objdump/X86/malformed-machos.test b/llvm/test/tools/llvm-objdump/X86/malformed-machos.test index e29df464a4ef..414cf973b9d9 100644 --- a/llvm/test/tools/llvm-objdump/X86/malformed-machos.test +++ b/llvm/test/tools/llvm-objdump/X86/malformed-machos.test @@ -68,4 +68,4 @@ RUN: not llvm-objdump -macho -objc-meta-data %p/Inputs/macho-invalid-bind-entry INVALID-BIND-ENTRY: macho-invalid-bind-entry': truncated or malformed object (for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad library ordinal: 83 (max 0) for opcode at: 0x0) RUN: llvm-objdump -macho -r %p/Inputs/macho-invalid-reloc-section-index | FileCheck -check-prefix INVALID-RELOC-SECTION-INDEX %s -INVALID-RELOC-SECTION-INDEX: 0000000000000021 X86_64_RELOC_UNSIGNED 8388613 (?,?) +INVALID-RELOC-SECTION-INDEX: 00000021 False byte False UNSIGND False 8388613 (?,?) diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp index 4412d6833411..9908c2f2d016 100644 --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -467,6 +467,333 @@ static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) { } } +static void PrintRType(const uint64_t cputype, const unsigned r_type) { + static char const *generic_r_types[] = { + "VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ", + " 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ", + " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) " + }; + static char const *x86_64_r_types[] = { + "UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ", + "SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ", + " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) " + }; + static char const *arm_r_types[] = { + "VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ", + "BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ", + " 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) " + }; + static char const *arm64_r_types[] = { + "UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ", + "GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF", + "ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) " + }; + + if (r_type > 0xf){ + outs() << format("%-7u", r_type) << " "; + return; + } + switch (cputype) { + case MachO::CPU_TYPE_I386: + outs() << generic_r_types[r_type]; + break; + case MachO::CPU_TYPE_X86_64: + outs() << x86_64_r_types[r_type]; + break; + case MachO::CPU_TYPE_ARM: + outs() << arm_r_types[r_type]; + break; + case MachO::CPU_TYPE_ARM64: + outs() << arm64_r_types[r_type]; + break; + default: + outs() << format("%-7u ", r_type); + } +} + +static void PrintRLength(const uint64_t cputype, const unsigned r_type, + const unsigned r_length, const bool previous_arm_half){ + if (cputype == MachO::CPU_TYPE_ARM && + (r_type == llvm::MachO::ARM_RELOC_HALF || + r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF || + previous_arm_half == true)) { + if ((r_length & 0x1) == 0) + outs() << "lo/"; + else + outs() << "hi/"; + if ((r_length & 0x1) == 0) + outs() << "arm "; + else + outs() << "thm "; + } else { + switch (r_length) { + case 0: + outs() << "byte "; + break; + case 1: + outs() << "word "; + break; + case 2: + outs() << "long "; + break; + case 3: + if (cputype == MachO::CPU_TYPE_X86_64) + outs() << "quad "; + else + outs() << format("?(%2d) ", r_length); + break; + default: + outs() << format("?(%2d) ", r_length); + } + } +} + +static void PrintRelocationEntries(const MachOObjectFile *O, + const relocation_iterator Begin, + const relocation_iterator End, + const uint64_t cputype, + const bool verbose) { + const MachO::symtab_command Symtab = O->getSymtabLoadCommand(); + bool previous_arm_half = false; + bool previous_sectdiff = false; + uint32_t sectdiff_r_type = 0; + + for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) { + const DataRefImpl Rel = Reloc->getRawDataRefImpl(); + const MachO::any_relocation_info RE = O->getRelocation(Rel); + const unsigned r_type = O->getAnyRelocationType(RE); + const bool r_scattered = O->isRelocationScattered(RE); + const unsigned r_pcrel = O->getAnyRelocationPCRel(RE); + const unsigned r_length = O->getAnyRelocationLength(RE); + const unsigned r_address = O->getAnyRelocationAddress(RE); + const bool r_extern = (r_scattered ? false : + O->getPlainRelocationExternal(RE)); + const uint32_t r_value = (r_scattered ? + O->getScatteredRelocationValue(RE) : 0); + const unsigned r_symbolnum = (r_scattered ? 0 : + O->getPlainRelocationSymbolNum(RE)); + + if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) { + if (verbose) { + // scattered: address + if ((cputype == MachO::CPU_TYPE_I386 && + r_type == llvm::MachO::GENERIC_RELOC_PAIR) || + (cputype == MachO::CPU_TYPE_ARM && + r_type == llvm::MachO::ARM_RELOC_PAIR)) + outs() << " "; + else + outs() << format("%08x ", (unsigned int)r_address); + + // scattered: pcrel + if (r_pcrel) + outs() << "True "; + else + outs() << "False "; + + // scattered: length + PrintRLength(cputype, r_type, r_length, previous_arm_half); + + // scattered: extern & type + outs() << "n/a "; + PrintRType(cputype, r_type); + + // scattered: scattered & value + outs() << format("True 0x%08x", (unsigned int)r_value); + if (previous_sectdiff == false) { + if ((cputype == MachO::CPU_TYPE_ARM && + r_type == llvm::MachO::ARM_RELOC_PAIR)) + outs() << format(" half = 0x%04x ", (unsigned int)r_address); + } + else if (cputype == MachO::CPU_TYPE_ARM && + sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF) + outs() << format(" other_half = 0x%04x ", (unsigned int)r_address); + if ((cputype == MachO::CPU_TYPE_I386 && + (r_type == llvm::MachO::GENERIC_RELOC_SECTDIFF || + r_type == llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) || + (cputype == MachO::CPU_TYPE_ARM && + (sectdiff_r_type == llvm::MachO::ARM_RELOC_SECTDIFF || + sectdiff_r_type == llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF || + sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))) { + previous_sectdiff = true; + sectdiff_r_type = r_type; + } + else { + previous_sectdiff = false; + sectdiff_r_type = 0; + } + if (cputype == MachO::CPU_TYPE_ARM && + (r_type == llvm::MachO::ARM_RELOC_HALF || + r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF)) + previous_arm_half = true; + else + previous_arm_half = false; + outs() << "\n"; + } + else { + // scattered: address pcrel length extern type scattered value + outs() << format("%08x %1d %-2d n/a %-7d 1 0x%08x\n", + (unsigned int)r_address, r_pcrel, r_length, r_type, + (unsigned int)r_value); + } + } + else { + if (verbose) { + // plain: address + if (cputype == MachO::CPU_TYPE_ARM && + r_type == llvm::MachO::ARM_RELOC_PAIR) + outs() << " "; + else + outs() << format("%08x ", (unsigned int)r_address); + + // plain: pcrel + if (r_pcrel) + outs() << "True "; + else + outs() << "False "; + + // plain: length + PrintRLength(cputype, r_type, r_length, previous_arm_half); + + if (r_extern) { + // plain: extern & type & scattered + outs() << "True "; + PrintRType(cputype, r_type); + outs() << "False "; + + // plain: symbolnum/value + if (r_symbolnum > Symtab.nsyms) + outs() << format("?(%d)\n", r_symbolnum); + else { + SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum); + Expected SymNameNext = Symbol.getName(); + const char *name = NULL; + if (SymNameNext) + name = SymNameNext->data(); + if (name == NULL) + outs() << format("?(%d)\n", r_symbolnum); + else + outs() << name << "\n"; + } + } + else { + // plain: extern & type & scattered + outs() << "False "; + PrintRType(cputype, r_type); + outs() << "False "; + + // plain: symbolnum/value + if (cputype == MachO::CPU_TYPE_ARM && + r_type == llvm::MachO::ARM_RELOC_PAIR) + outs() << format("other_half = 0x%04x\n", (unsigned int)r_address); + else if (cputype == MachO::CPU_TYPE_ARM64 && + r_type == llvm::MachO::ARM64_RELOC_ADDEND) + outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum); + else { + outs() << format("%d ", r_symbolnum); + if (r_symbolnum == llvm::MachO::R_ABS) + outs() << "R_ABS\n"; + else { + // in this case, r_symbolnum is actually a 1-based section number + uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a; + if (r_symbolnum > 0 && r_symbolnum <= nsects) { + llvm::object::DataRefImpl DRI; + DRI.d.a = r_symbolnum-1; + StringRef SegName = O->getSectionFinalSegmentName(DRI); + StringRef SectName; + if (O->getSectionName(DRI, SectName)) + outs() << "(?,?)\n"; + else + outs() << "(" << SegName << "," << SectName << ")\n"; + } + else { + outs() << "(?,?)\n"; + } + } + } + } + if (cputype == MachO::CPU_TYPE_ARM && + (r_type == llvm::MachO::ARM_RELOC_HALF || + r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF)) + previous_arm_half = true; + else + previous_arm_half = false; + } + else { + // plain: address pcrel length extern type scattered symbolnum/section + outs() << format("%08x %1d %-2d %1d %-7d 0 %d\n", + (unsigned int)r_address, r_pcrel, r_length, r_extern, + r_type, r_symbolnum); + } + } + } +} + +static void PrintRelocations(const MachOObjectFile *O, const bool verbose) { + const uint64_t cputype = O->getHeader().cputype; + const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand(); + if (Dysymtab.nextrel != 0) { + outs() << "External relocation information " << Dysymtab.nextrel + << " entries"; + outs() << "\naddress pcrel length extern type scattered " + "symbolnum/value\n"; + PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype, + verbose); + } + if (Dysymtab.nlocrel != 0) { + outs() << format("Local relocation information %u entries", + Dysymtab.nlocrel); + outs() << "\naddress pcrel length extern type scattered " + "symbolnum/value\n"; + PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype, + verbose); + } + for (const auto &Load : O->load_commands()) { + if (Load.C.cmd == MachO::LC_SEGMENT_64) { + const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load); + for (unsigned J = 0; J < Seg.nsects; ++J) { + const MachO::section_64 Sec = O->getSection64(Load, J); + if (Sec.nreloc != 0) { + DataRefImpl DRI; + DRI.d.a = J; + const StringRef SegName = O->getSectionFinalSegmentName(DRI); + StringRef SectName; + if (O->getSectionName(DRI, SectName)) + outs() << "Relocation information (" << SegName << ",?) " + << format("%u entries", Sec.nreloc); + else + outs() << "Relocation information (" << SegName << "," + << SectName << format(") %u entries", Sec.nreloc); + outs() << "\naddress pcrel length extern type scattered " + "symbolnum/value\n"; + PrintRelocationEntries(O, O->section_rel_begin(DRI), + O->section_rel_end(DRI), cputype, verbose); + } + } + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + const MachO::segment_command Seg = O->getSegmentLoadCommand(Load); + for (unsigned J = 0; J < Seg.nsects; ++J) { + const MachO::section Sec = O->getSection(Load, J); + if (Sec.nreloc != 0) { + DataRefImpl DRI; + DRI.d.a = J; + const StringRef SegName = O->getSectionFinalSegmentName(DRI); + StringRef SectName; + if (O->getSectionName(DRI, SectName)) + outs() << "Relocation information (" << SegName << ",?) " + << format("%u entries", Sec.nreloc); + else + outs() << "Relocation information (" << SegName << "," + << SectName << format(") %u entries", Sec.nreloc); + outs() << "\naddress pcrel length extern type scattered " + "symbolnum/value\n"; + PrintRelocationEntries(O, O->section_rel_begin(DRI), + O->section_rel_end(DRI), cputype, verbose); + } + } + } + } +} + static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) { MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand(); uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry); @@ -1221,9 +1548,10 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF, // If we are doing some processing here on the Mach-O file print the header // info. And don't print it otherwise like in the case of printing the // UniversalHeaders or ArchiveHeaders. - if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || SymbolTable || - LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints || - DylibsUsed || DylibId || ObjcMetaData || (FilterSections.size() != 0)) { + if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase || + Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols || + DataInCode || LinkOptHints || DylibsUsed || DylibId || ObjcMetaData || + (FilterSections.size() != 0)) { if (!NoLeadingHeaders) { outs() << Name; if (!ArchiveMemberName.empty()) @@ -1267,7 +1595,7 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF, if (LinkOptHints) PrintLinkOptHints(MachOOF); if (Relocations) - PrintRelocations(MachOOF); + PrintRelocations(MachOOF, !NonVerbose); if (SectionHeaders) PrintSectionHeaders(MachOOF); if (SectionContents)