diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -711,6 +711,8 @@ ArrayRef getDyldInfoBindOpcodes() const; ArrayRef getDyldInfoWeakBindOpcodes() const; ArrayRef getDyldInfoLazyBindOpcodes() const; + ArrayRef getDyldInfoExportsTrie() const; + /// If the optional is None, no header was found, but the object was /// well-formed. Expected> @@ -725,8 +727,8 @@ // a ChainedFixupsSegment for each segment that has fixups. Expected>> getChainedFixupsSegments() const; + ArrayRef getDyldExportsTrie() const; - ArrayRef getDyldInfoExportsTrie() const; SmallVector getFunctionStarts() const; ArrayRef getUuid() const; @@ -856,6 +858,7 @@ const char *DyldInfoLoadCmd = nullptr; const char *FuncStartsLoadCmd = nullptr; const char *DyldChainedFixupsLoadCmd = nullptr; + const char *DyldExportsTrieLoadCmd = nullptr; const char *UuidLoadCmd = nullptr; bool HasPageZeroSegment = false; }; diff --git a/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp b/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp --- a/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp @@ -235,6 +235,26 @@ "Incorrect tail offset"); Offset = std::max(Offset, HeaderSize + O.Header.SizeOfCmds); + // The exports trie can be in either LC_DYLD_INFO or in + // LC_DYLD_EXPORTS_TRIE, but not both. + size_t DyldInfoExportsTrieSize = 0; + size_t DyldExportsTrieSize = 0; + for (const auto &LC : O.LoadCommands) { + switch (LC.MachOLoadCommand.load_command_data.cmd) { + case MachO::LC_DYLD_INFO: + case MachO::LC_DYLD_INFO_ONLY: + DyldInfoExportsTrieSize = O.Exports.Trie.size(); + break; + case MachO::LC_DYLD_EXPORTS_TRIE: + DyldExportsTrieSize = O.Exports.Trie.size(); + break; + default: + break; + } + } + assert((DyldInfoExportsTrieSize == 0 || DyldExportsTrieSize == 0) && + "Export trie in both LCs"); + // The order of LINKEDIT elements is as follows: // rebase info, binding info, weak binding info, lazy binding info, export // trie, data-in-code, symbol table, indirect symbol table, symbol table @@ -248,11 +268,10 @@ StartOfWeakBindingInfo + O.WeakBinds.Opcodes.size(); uint64_t StartOfExportTrie = StartOfLazyBindingInfo + O.LazyBinds.Opcodes.size(); - uint64_t StartOfFunctionStarts = StartOfExportTrie + O.Exports.Trie.size(); + uint64_t StartOfFunctionStarts = StartOfExportTrie + DyldInfoExportsTrieSize; uint64_t StartOfDyldExportsTrie = StartOfFunctionStarts + O.FunctionStarts.Data.size(); - uint64_t StartOfChainedFixups = - StartOfDyldExportsTrie + O.ExportsTrie.Data.size(); + uint64_t StartOfChainedFixups = StartOfDyldExportsTrie + DyldExportsTrieSize; uint64_t StartOfDataInCode = StartOfChainedFixups + O.ChainedFixups.Data.size(); uint64_t StartOfLinkerOptimizationHint = @@ -363,7 +382,7 @@ break; case MachO::LC_DYLD_EXPORTS_TRIE: MLC.linkedit_data_command_data.dataoff = StartOfDyldExportsTrie; - MLC.linkedit_data_command_data.datasize = O.ExportsTrie.Data.size(); + MLC.linkedit_data_command_data.datasize = DyldExportsTrieSize; break; case MachO::LC_DYLD_INFO: case MachO::LC_DYLD_INFO_ONLY: @@ -381,7 +400,7 @@ MLC.dyld_info_command_data.lazy_bind_size = O.LazyBinds.Opcodes.size(); MLC.dyld_info_command_data.export_off = O.Exports.Trie.empty() ? 0 : StartOfExportTrie; - MLC.dyld_info_command_data.export_size = O.Exports.Trie.size(); + MLC.dyld_info_command_data.export_size = DyldInfoExportsTrieSize; break; // Note that LC_ENCRYPTION_INFO.cryptoff despite its name and the comment in // is not an offset in the binary file, instead, it is a diff --git a/llvm/lib/ObjCopy/MachO/MachOObject.h b/llvm/lib/ObjCopy/MachO/MachOObject.h --- a/llvm/lib/ObjCopy/MachO/MachOObject.h +++ b/llvm/lib/ObjCopy/MachO/MachOObject.h @@ -315,7 +315,6 @@ LinkData DataInCode; LinkData LinkerOptimizationHint; LinkData FunctionStarts; - LinkData ExportsTrie; LinkData ChainedFixups; Optional SwiftVersion; diff --git a/llvm/lib/ObjCopy/MachO/MachOReader.h b/llvm/lib/ObjCopy/MachO/MachOReader.h --- a/llvm/lib/ObjCopy/MachO/MachOReader.h +++ b/llvm/lib/ObjCopy/MachO/MachOReader.h @@ -44,7 +44,6 @@ void readDataInCodeData(Object &O) const; void readLinkerOptimizationHint(Object &O) const; void readFunctionStartsData(Object &O) const; - void readExportsTrie(Object &O) const; void readChainedFixups(Object &O) const; void readIndirectSymbolTable(Object &O) const; void readSwiftVersion(Object &O) const; diff --git a/llvm/lib/ObjCopy/MachO/MachOReader.cpp b/llvm/lib/ObjCopy/MachO/MachOReader.cpp --- a/llvm/lib/ObjCopy/MachO/MachOReader.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOReader.cpp @@ -281,7 +281,11 @@ } void MachOReader::readExportInfo(Object &O) const { - O.Exports.Trie = MachOObj.getDyldInfoExportsTrie(); + // This information can be in LC_DYLD_INFO or in LC_DYLD_EXPORTS_TRIE + ArrayRef Trie = MachOObj.getDyldInfoExportsTrie(); + if (Trie.empty()) + Trie = MachOObj.getDyldExportsTrie(); + O.Exports.Trie = Trie; } void MachOReader::readLinkData(Object &O, Optional LCIndex, @@ -307,10 +311,6 @@ return readLinkData(O, O.FunctionStartsCommandIndex, O.FunctionStarts); } -void MachOReader::readExportsTrie(Object &O) const { - return readLinkData(O, O.ExportsTrieCommandIndex, O.ExportsTrie); -} - void MachOReader::readChainedFixups(Object &O) const { return readLinkData(O, O.ChainedFixupsCommandIndex, O.ChainedFixups); } @@ -366,7 +366,6 @@ readDataInCodeData(*Obj); readLinkerOptimizationHint(*Obj); readFunctionStartsData(*Obj); - readExportsTrie(*Obj); readChainedFixups(*Obj); readIndirectSymbolTable(*Obj); readSwiftVersion(*Obj); diff --git a/llvm/lib/ObjCopy/MachO/MachOWriter.cpp b/llvm/lib/ObjCopy/MachO/MachOWriter.cpp --- a/llvm/lib/ObjCopy/MachO/MachOWriter.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOWriter.cpp @@ -564,7 +564,15 @@ } void MachOWriter::writeExportsTrieData() { - return writeLinkData(O.ExportsTrieCommandIndex, O.ExportsTrie); + if (!O.ExportsTrieCommandIndex) + return; + const MachO::linkedit_data_command &ExportsTrieCmd = + O.LoadCommands[*O.ExportsTrieCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + char *Out = (char *)Buf->getBufferStart() + ExportsTrieCmd.dataoff; + assert((ExportsTrieCmd.datasize == O.Exports.Trie.size()) && + "Incorrect export trie size"); + memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size()); } void MachOWriter::writeTail() { diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -1386,6 +1386,11 @@ *this, Load, I, &DyldChainedFixupsLoadCmd, "LC_DYLD_CHAINED_FIXUPS", Elements, "chained fixups"))) return; + } else if (Load.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE) { + if ((Err = checkLinkeditDataCommand( + *this, Load, I, &DyldExportsTrieLoadCmd, "LC_DYLD_EXPORTS_TRIE", + Elements, "exports trie"))) + return; } else if (Load.C.cmd == MachO::LC_UUID) { if (Load.C.cmdsize != sizeof(MachO::uuid_command)) { Err = malformedError("LC_UUID command " + Twine(I) + " has incorrect " @@ -3225,7 +3230,13 @@ } iterator_range MachOObjectFile::exports(Error &Err) const { - return exports(Err, getDyldInfoExportsTrie(), this); + ArrayRef Trie; + if (DyldInfoLoadCmd) + Trie = getDyldInfoExportsTrie(); + else if (DyldExportsTrieLoadCmd) + Trie = getDyldExportsTrie(); + + return exports(Err, Trie, this); } MachOAbstractFixupEntry::MachOAbstractFixupEntry(Error *E, @@ -4932,6 +4943,20 @@ return makeArrayRef(Ptr, DyldInfo.lazy_bind_size); } +ArrayRef MachOObjectFile::getDyldInfoExportsTrie() const { + if (!DyldInfoLoadCmd) + return None; + + auto DyldInfoOrErr = + getStructOrErr(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); + const uint8_t *Ptr = + reinterpret_cast(getPtr(*this, DyldInfo.export_off)); + return makeArrayRef(Ptr, DyldInfo.export_size); +} + Expected> MachOObjectFile::getChainedFixupsLoadCommand() const { // Load the dyld chained fixups load command. @@ -5209,18 +5234,18 @@ return std::move(Targets); } -ArrayRef MachOObjectFile::getDyldInfoExportsTrie() const { - if (!DyldInfoLoadCmd) +ArrayRef MachOObjectFile::getDyldExportsTrie() const { + if (!DyldExportsTrieLoadCmd) return None; - auto DyldInfoOrErr = - getStructOrErr(*this, DyldInfoLoadCmd); - if (!DyldInfoOrErr) + auto DyldExportsTrieOrError = getStructOrErr( + *this, DyldExportsTrieLoadCmd); + if (!DyldExportsTrieOrError) return None; - MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); + MachO::linkedit_data_command DyldExportsTrie = DyldExportsTrieOrError.get(); const uint8_t *Ptr = - reinterpret_cast(getPtr(*this, DyldInfo.export_off)); - return makeArrayRef(Ptr, DyldInfo.export_size); + reinterpret_cast(getPtr(*this, DyldExportsTrie.dataoff)); + return makeArrayRef(Ptr, DyldExportsTrie.datasize); } SmallVector MachOObjectFile::getFunctionStarts() const { diff --git a/llvm/lib/ObjectYAML/MachOEmitter.cpp b/llvm/lib/ObjectYAML/MachOEmitter.cpp --- a/llvm/lib/ObjectYAML/MachOEmitter.cpp +++ b/llvm/lib/ObjectYAML/MachOEmitter.cpp @@ -56,6 +56,7 @@ void writeExportTrie(raw_ostream &OS); void writeDynamicSymbolTable(raw_ostream &OS); void writeFunctionStarts(raw_ostream &OS); + void writeDyldExportsTrie(raw_ostream &OS); void writeDataInCode(raw_ostream &OS); void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry); @@ -487,6 +488,7 @@ MachO::symtab_command *SymtabCmd = nullptr; MachO::dysymtab_command *DSymtabCmd = nullptr; MachO::linkedit_data_command *FunctionStartsCmd = nullptr; + MachO::linkedit_data_command *DyldExportsTrieCmd = nullptr; MachO::linkedit_data_command *DataInCodeCmd = nullptr; for (auto &LC : Obj.LoadCommands) { switch (LC.Data.load_command_data.cmd) { @@ -520,6 +522,11 @@ WriteQueue.push_back(std::make_pair(FunctionStartsCmd->dataoff, &MachOWriter::writeFunctionStarts)); break; + case MachO::LC_DYLD_EXPORTS_TRIE: + DyldExportsTrieCmd = &LC.Data.linkedit_data_command_data; + WriteQueue.push_back(std::make_pair(DyldExportsTrieCmd->dataoff, + &MachOWriter::writeDyldExportsTrie)); + break; case MachO::LC_DATA_IN_CODE: DataInCodeCmd = &LC.Data.linkedit_data_command_data; WriteQueue.push_back(std::make_pair(DataInCodeCmd->dataoff, @@ -602,6 +609,10 @@ } } +void MachOWriter::writeDyldExportsTrie(raw_ostream &OS) { + dumpExportEntry(OS, Obj.LinkEdit.ExportTrie); +} + class UniversalWriter { public: UniversalWriter(yaml::YamlObjectFile &ObjectFile) diff --git a/llvm/test/tools/llvm-objdump/MachO/exports-trie-lc.test b/llvm/test/tools/llvm-objdump/MachO/exports-trie-lc.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/MachO/exports-trie-lc.test @@ -0,0 +1,205 @@ +# RUN: yaml2obj %s | llvm-objdump --macho --exports-trie - | FileCheck %s + +# CHECK: Exports trie: +# CHECK-NEXT: 0x100000000 __mh_execute_header +# CHECK-NEXT: 0x100003F98 _main + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x1000007 + cpusubtype: 0x3 + filetype: 0x2 + ncmds: 15 + sizeofcmds: 728 + flags: 0x200085 + reserved: 0x0 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 72 + segname: __PAGEZERO + vmaddr: 0 + vmsize: 4294967296 + fileoff: 0 + filesize: 0 + maxprot: 0 + initprot: 0 + nsects: 0 + flags: 0 + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: __TEXT + vmaddr: 4294967296 + vmsize: 16384 + fileoff: 0 + filesize: 16384 + maxprot: 5 + initprot: 5 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x100003FB0 + size: 8 + offset: 0x3FB0 + align: 4 + reloff: 0x0 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: C30F1F0000000000 + - sectname: __unwind_info + segname: __TEXT + addr: 0x100003FB8 + size: 72 + offset: 0x3FB8 + align: 2 + reloff: 0x0 + nreloc: 0 + flags: 0x0 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: 010000001C000000000000001C000000000000001C00000002000000B03F00003400000034000000B93F00000000000034000000030000000C000100100001000000000000000000 + - cmd: LC_SEGMENT_64 + cmdsize: 72 + segname: __LINKEDIT + vmaddr: 4294983680 + vmsize: 16384 + fileoff: 16384 + filesize: 176 + maxprot: 1 + initprot: 1 + nsects: 0 + flags: 0 + - cmd: LC_DYLD_CHAINED_FIXUPS + cmdsize: 16 + dataoff: 16384 + datasize: 56 + - cmd: LC_DYLD_EXPORTS_TRIE + cmdsize: 16 + dataoff: 16440 + datasize: 48 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 16504 + nsyms: 2 + stroff: 16536 + strsize: 32 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 2 + iundefsym: 2 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 + - cmd: LC_LOAD_DYLINKER + cmdsize: 32 + name: 12 + Content: '/usr/lib/dyld' + ZeroPadBytes: 7 + - cmd: LC_UUID + cmdsize: 24 + uuid: 362D6303-E0AC-3074-B083-CF48B87DB35D + - cmd: LC_BUILD_VERSION + cmdsize: 32 + platform: 1 + minos: 786432 + sdk: 787200 + ntools: 1 + Tools: + - tool: 3 + version: 50069504 + - cmd: LC_SOURCE_VERSION + cmdsize: 16 + version: 0 + - cmd: LC_MAIN + cmdsize: 24 + entryoff: 16304 + stacksize: 0 + - cmd: LC_LOAD_DYLIB + cmdsize: 56 + dylib: + name: 24 + timestamp: 2 + current_version: 85943299 + compatibility_version: 65536 + Content: '/usr/lib/libSystem.B.dylib' + ZeroPadBytes: 6 + - cmd: LC_FUNCTION_STARTS + cmdsize: 16 + dataoff: 16488 + datasize: 8 + - cmd: LC_DATA_IN_CODE + cmdsize: 16 + dataoff: 0 + datasize: 0 +LinkEditData: + ExportTrie: + TerminalSize: 0 + NodeOffset: 0 + Name: '' + Flags: 0x0 + Address: 0x0 + Other: 0x0 + ImportName: '' + Children: + - TerminalSize: 0 + NodeOffset: 5 + Name: _ + Flags: 0x0 + Address: 0x0 + Other: 0x0 + ImportName: '' + Children: + - TerminalSize: 2 + NodeOffset: 33 + Name: _mh_execute_header + Flags: 0x0 + Address: 0x0 + Other: 0x0 + ImportName: '' + - TerminalSize: 3 + NodeOffset: 37 + Name: main + Flags: 0x0 + Address: 0x3F98 + Other: 0x0 + ImportName: '' + NameList: + - n_strx: 2 + n_type: 0xF + n_sect: 1 + n_desc: 16 + n_value: 4294967296 + - n_strx: 22 + n_type: 0xF + n_sect: 1 + n_desc: 0 + n_value: 4294983600 + StringTable: + - ' ' + - __mh_execute_header + - _main + - '' + - '' + - '' + - '' + FunctionStarts: [ 0x3FB0 ] +... diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -578,7 +578,10 @@ void MachODumper::dumpExportTrie(std::unique_ptr &Y) { MachOYAML::LinkEditData &LEData = Y->LinkEdit; + // The exports trie can be in LC_DYLD_INFO or LC_DYLD_EXPORTS_TRIE auto ExportsTrie = Obj.getDyldInfoExportsTrie(); + if (ExportsTrie.empty()) + ExportsTrie = Obj.getDyldExportsTrie(); processExportNode(ExportsTrie.begin(), ExportsTrie.end(), LEData.ExportTrie); }