summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Trent <mtrent@apple.com>2017-12-12 23:53:46 +0000
committerMichael Trent <mtrent@apple.com>2017-12-12 23:53:46 +0000
commit2aa4a861a6d336f39831c2b2199548d5be444b01 (patch)
tree10e7790917dc14a1fd1e1f40dd88f374e0692a8c
parent0dace14523dca00761b00e1a96d52a57b416feaf (diff)
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. rdar://35778019 Reviewers: enderby Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D41061 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@320532 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Object/MachO.h3
-rw-r--r--lib/Object/MachOObjectFile.cpp24
-rwxr-xr-xtest/tools/llvm-objdump/X86/Inputs/macho-preload-x86_64bin0 -> 1084 bytes
-rw-r--r--test/tools/llvm-objdump/X86/macho-preload-relocations.test5
-rw-r--r--test/tools/llvm-objdump/X86/macho-relocations.test12
-rw-r--r--test/tools/llvm-objdump/X86/malformed-machos.test2
-rw-r--r--tools/llvm-objdump/MachODump.cpp336
7 files changed, 371 insertions, 11 deletions
diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h
index 03fd52fb482..c3ec1f6fcfe 100644
--- a/include/llvm/Object/MachO.h
+++ b/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/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp
index 4620fdde81d..aa4015c5f90 100644
--- a/lib/Object/MachOObjectFile.cpp
+++ b/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<const MachO::any_relocation_info *>(
diff --git a/test/tools/llvm-objdump/X86/Inputs/macho-preload-x86_64 b/test/tools/llvm-objdump/X86/Inputs/macho-preload-x86_64
new file mode 100755
index 00000000000..236606e77c6
--- /dev/null
+++ b/test/tools/llvm-objdump/X86/Inputs/macho-preload-x86_64
Binary files differ
diff --git a/test/tools/llvm-objdump/X86/macho-preload-relocations.test b/test/tools/llvm-objdump/X86/macho-preload-relocations.test
new file mode 100644
index 00000000000..dda0b2b465b
--- /dev/null
+++ b/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/test/tools/llvm-objdump/X86/macho-relocations.test b/test/tools/llvm-objdump/X86/macho-relocations.test
index 536aec8b1bc..111cf0cc95b 100644
--- a/test/tools/llvm-objdump/X86/macho-relocations.test
+++ b/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/test/tools/llvm-objdump/X86/malformed-machos.test b/test/tools/llvm-objdump/X86/malformed-machos.test
index e29df464a4e..414cf973b9d 100644
--- a/test/tools/llvm-objdump/X86/malformed-machos.test
+++ b/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/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp
index 4412d683341..80061f0544f 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/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<StringRef> 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() << format("\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)