From 42ad9bf95fd5cb30e2ab3e017b6718ac6efea1be Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Rodr=C3=ADguez=20Troiti=C3=B1o?= Date: Tue, 22 Nov 2022 15:12:27 -0800 Subject: [PATCH] [MachO] Support exports trie in both LC_DYLD_INFO and LC_DYLD_EXPORTS_TRIE The exports trie used to be pointed by the information in LC_DYLD_INFO, but when chained fixups are present, the exports trie is pointed by LC_DYLD_EXPORTS_TRIE instead. Modify the Object library to give access to the information pointed by each of the load commands, and to fallback from one into the other when the exports are requested. Modify ObjectYAML to support dumping the export trie when pointed by LC_DYLD_EXPORTS_TRIE and to parse the existence of a export trie also when the load command is present. This is a split of D134250 with improvements on top. Reviewed By: alexander-shaposhnikov Differential Revision: https://reviews.llvm.org/D134571 --- llvm/include/llvm/Object/MachO.h | 5 +- llvm/lib/Object/MachOObjectFile.cpp | 43 ++++- llvm/lib/ObjectYAML/MachOEmitter.cpp | 11 ++ .../MachO/export_trie_lc_dyld_exports_trie.yaml | 204 +++++++++++++++++++++ ...rie.yaml => export_trie_lc_dyld_info_only.yaml} | 0 llvm/tools/obj2yaml/macho2yaml.cpp | 3 + 6 files changed, 256 insertions(+), 10 deletions(-) create mode 100644 llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml rename llvm/test/ObjectYAML/MachO/{export_trie.yaml => export_trie_lc_dyld_info_only.yaml} (100%) diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index caeee6a..9da7f33 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -711,6 +711,8 @@ public: 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 @@ public: // 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 @@ private: 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/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 20ac343..f3ca2e9 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -1386,6 +1386,11 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, *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 @@ MachOObjectFile::exports(Error &E, ArrayRef Trie, } 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 @@ ArrayRef MachOObjectFile::getDyldInfoLazyBindOpcodes() const { 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 @@ MachOObjectFile::getDyldChainedFixupTargets() const { 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 index 75ff2ef..022c08e 100644 --- a/llvm/lib/ObjectYAML/MachOEmitter.cpp +++ b/llvm/lib/ObjectYAML/MachOEmitter.cpp @@ -57,6 +57,7 @@ private: void writeDynamicSymbolTable(raw_ostream &OS); void writeFunctionStarts(raw_ostream &OS); void writeChainedFixups(raw_ostream &OS); + void writeDyldExportsTrie(raw_ostream &OS); void writeDataInCode(raw_ostream &OS); void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry); @@ -489,6 +490,7 @@ void MachOWriter::writeLinkEditData(raw_ostream &OS) { MachO::dysymtab_command *DSymtabCmd = nullptr; MachO::linkedit_data_command *FunctionStartsCmd = nullptr; MachO::linkedit_data_command *ChainedFixupsCmd = 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) { @@ -527,6 +529,11 @@ void MachOWriter::writeLinkEditData(raw_ostream &OS) { WriteQueue.push_back(std::make_pair(ChainedFixupsCmd->dataoff, &MachOWriter::writeChainedFixups)); 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, @@ -615,6 +622,10 @@ void MachOWriter::writeChainedFixups(raw_ostream &OS) { Obj.LinkEdit.ChainedFixups.size()); } +void MachOWriter::writeDyldExportsTrie(raw_ostream &OS) { + dumpExportEntry(OS, Obj.LinkEdit.ExportTrie); +} + class UniversalWriter { public: UniversalWriter(yaml::YamlObjectFile &ObjectFile) diff --git a/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml b/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml new file mode 100644 index 0000000..4710bca --- /dev/null +++ b/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml @@ -0,0 +1,204 @@ +# RUN: yaml2obj %s -o=%t +# RUN: obj2yaml %t | FileCheck %s +# RUN: llvm-objdump --macho --exports-trie %t | FileCheck %s --check-prefix=OBJDUMP-VERIFY + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x80000003 + filetype: 0x00000002 + ncmds: 16 + sizeofcmds: 1408 + flags: 0x00218085 + reserved: 0x00000000 +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: 552 + segname: __TEXT + vmaddr: 4294967296 + vmsize: 8192 + fileoff: 0 + filesize: 8192 + maxprot: 7 + initprot: 5 + nsects: 6 + flags: 0 + - cmd: LC_SEGMENT_64 + cmdsize: 312 + segname: __DATA + vmaddr: 4294975488 + vmsize: 4096 + fileoff: 8192 + filesize: 4096 + maxprot: 7 + initprot: 3 + nsects: 3 + flags: 0 + - cmd: LC_SEGMENT_64 + cmdsize: 72 + segname: __LINKEDIT + vmaddr: 4294979584 + vmsize: 4096 + fileoff: 12288 + filesize: 1884 + maxprot: 7 + initprot: 1 + nsects: 0 + flags: 0 + - cmd: LC_DYLD_CHAINED_FIXUPS + cmdsize: 16 + dataoff: 12288 + datasize: 104 + - cmd: LC_DYLD_EXPORTS_TRIE + cmdsize: 16 + dataoff: 12392 + datasize: 48 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 12456 + nsyms: 30 + stroff: 13076 + strsize: 1096 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 9 + iextdefsym: 9 + nextdefsym: 2 + iundefsym: 11 + nundefsym: 19 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 12936 + nindirectsyms: 35 + 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: 461A1B28-822F-3F38-B670-645419E636F5 + - cmd: LC_VERSION_MIN_MACOSX + cmdsize: 16 + version: 658176 + sdk: 658176 + - cmd: LC_SOURCE_VERSION + cmdsize: 16 + version: 0 + - cmd: LC_MAIN + cmdsize: 24 + entryoff: 4448 + stacksize: 0 + - cmd: LC_LOAD_DYLIB + cmdsize: 48 + dylib: + name: 24 + timestamp: 2 + current_version: 7864576 + compatibility_version: 65536 + Content: '/usr/lib/libc++.1.dylib' + ZeroPadBytes: 1 + - cmd: LC_LOAD_DYLIB + cmdsize: 56 + dylib: + name: 24 + timestamp: 2 + current_version: 80349697 + compatibility_version: 65536 + Content: /usr/lib/libSystem.B.dylib + ZeroPadBytes: 6 + - cmd: LC_FUNCTION_STARTS + cmdsize: 16 + dataoff: 12440 + datasize: 16 + - cmd: LC_DATA_IN_CODE + cmdsize: 16 + dataoff: 12456 + datasize: 0 +LinkEditData: + ExportTrie: + TerminalSize: 0 + NodeOffset: 0 + Name: '' + Flags: 0x0000000000000000 + Address: 0x0000000000000000 + Other: 0x0000000000000000 + ImportName: '' + Children: + - TerminalSize: 0 + NodeOffset: 5 + Name: _ + Flags: 0x0000000000000000 + Address: 0x0000000000000000 + Other: 0x0000000000000000 + ImportName: '' + Children: + - TerminalSize: 2 + NodeOffset: 33 + Name: _mh_execute_header + Flags: 0x0000000000000000 + Address: 0x0000000000000000 + Other: 0x0000000000000000 + ImportName: '' + - TerminalSize: 3 + NodeOffset: 37 + Name: main + Flags: 0x0000000000000000 + Address: 0x0000000000003FA0 + Other: 0x0000000000000000 + ImportName: '' + ChainedFixups: [ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x50, 0x0, + 0x0, 0x0, 0x58, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, + 0x0, 0x10, 0x6, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + 0x1, 0x2, 0x0, 0x0, 0xFD, 0xC, 0x0, 0x0, 0x0, 0x5F, + 0x66, 0x6F, 0x6F, 0x0, 0x5F, 0x77, 0x65, 0x61, 0x6B, + 0x5F, 0x66, 0x6F, 0x6F, 0x0 ] +... + +#CHECK: ExportTrie: +#CHECK: TerminalSize: 0 +#CHECK: NodeOffset: 0 +#CHECK: Name: '' +#CHECK: Children: +#CHECK: - TerminalSize: 0 +#CHECK: NodeOffset: 5 +#CHECK: Name: _ +#CHECK: Children: +#CHECK: - TerminalSize: 2 +#CHECK: NodeOffset: 33 +#CHECK: Name: _mh_execute_header +#CHECK: Address: 0x0 +#CHECK: - TerminalSize: 3 +#CHECK: NodeOffset: 37 +#CHECK: Name: main +#CHECK: Address: 0x3FA0 + +# OBJDUMP-VERIFY: Exports trie: +# OBJDUMP-VERIFY: 0x100000000 __mh_execute_header +# OBJDUMP-VERIFY: 0x100003FA0 _main diff --git a/llvm/test/ObjectYAML/MachO/export_trie.yaml b/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_info_only.yaml similarity index 100% rename from llvm/test/ObjectYAML/MachO/export_trie.yaml rename to llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_info_only.yaml diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp index e564467..4464f0c 100644 --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -580,7 +580,10 @@ const uint8_t *processExportNode(const uint8_t *CurrPtr, 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); } -- 2.7.4