From a6e1b3c5c223e4868ab77d6d66b62f136b12febc Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 7 Feb 2022 17:33:32 -0800 Subject: [PATCH] [ObjectYAML][MachO] Add LC_FUNCTION_STARTS support This adds support for encoding and decoding the LC_FUNCTION_STARTS load command payload. Differential Revision: https://reviews.llvm.org/D119205 --- llvm/include/llvm/Object/MachO.h | 2 + llvm/include/llvm/ObjectYAML/MachOYAML.h | 1 + llvm/lib/Object/MachOObjectFile.cpp | 16 +- llvm/lib/ObjectYAML/MachOEmitter.cpp | 18 +++ llvm/lib/ObjectYAML/MachOYAML.cpp | 9 +- llvm/test/ObjectYAML/MachO/function_starts.yaml | 186 ++++++++++++++++++++++++ llvm/tools/obj2yaml/macho2yaml.cpp | 10 ++ 7 files changed, 237 insertions(+), 5 deletions(-) create mode 100644 llvm/test/ObjectYAML/MachO/function_starts.yaml diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index 49a0706..840faa7 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -563,6 +563,7 @@ public: ArrayRef getDyldInfoWeakBindOpcodes() const; ArrayRef getDyldInfoLazyBindOpcodes() const; ArrayRef getDyldInfoExportsTrie() const; + SmallVector getFunctionStarts() const; ArrayRef getUuid() const; StringRef getStringTableData() const; @@ -689,6 +690,7 @@ private: const char *DataInCodeLoadCmd = nullptr; const char *LinkOptHintsLoadCmd = nullptr; const char *DyldInfoLoadCmd = nullptr; + const char *FuncStartsLoadCmd = nullptr; const char *UuidLoadCmd = nullptr; bool HasPageZeroSegment = false; }; diff --git a/llvm/include/llvm/ObjectYAML/MachOYAML.h b/llvm/include/llvm/ObjectYAML/MachOYAML.h index 38a7de3..095377c 100644 --- a/llvm/include/llvm/ObjectYAML/MachOYAML.h +++ b/llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -122,6 +122,7 @@ struct LinkEditData { std::vector NameList; std::vector StringTable; std::vector IndirectSymbols; + std::vector FunctionStarts; bool isEmpty() const; }; diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 909a4cf..85f3824 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -1303,7 +1303,6 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, } const char *DyldIdLoadCmd = nullptr; - const char *FuncStartsLoadCmd = nullptr; const char *SplitInfoLoadCmd = nullptr; const char *CodeSignDrsLoadCmd = nullptr; const char *CodeSignLoadCmd = nullptr; @@ -4663,6 +4662,21 @@ ArrayRef MachOObjectFile::getDyldInfoExportsTrie() const { return makeArrayRef(Ptr, DyldInfo.export_size); } +SmallVector MachOObjectFile::getFunctionStarts() const { + if (!FuncStartsLoadCmd) + return {}; + + auto InfoOrErr = + getStructOrErr(*this, FuncStartsLoadCmd); + if (!InfoOrErr) + return {}; + + MachO::linkedit_data_command Info = InfoOrErr.get(); + SmallVector FunctionStarts; + this->ReadULEB128s(Info.dataoff, FunctionStarts); + return std::move(FunctionStarts); +} + ArrayRef MachOObjectFile::getUuid() const { if (!UuidLoadCmd) return None; diff --git a/llvm/lib/ObjectYAML/MachOEmitter.cpp b/llvm/lib/ObjectYAML/MachOEmitter.cpp index b9fad29..c781152 100644 --- a/llvm/lib/ObjectYAML/MachOEmitter.cpp +++ b/llvm/lib/ObjectYAML/MachOEmitter.cpp @@ -55,6 +55,7 @@ private: void writeStringTable(raw_ostream &OS); void writeExportTrie(raw_ostream &OS); void writeDynamicSymbolTable(raw_ostream &OS); + void writeFunctionStarts(raw_ostream &OS); void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry); void ZeroToOffset(raw_ostream &OS, size_t offset); @@ -484,6 +485,7 @@ void MachOWriter::writeLinkEditData(raw_ostream &OS) { MachO::dyld_info_command *DyldInfoOnlyCmd = nullptr; MachO::symtab_command *SymtabCmd = nullptr; MachO::dysymtab_command *DSymtabCmd = nullptr; + MachO::linkedit_data_command *FunctionStartsCmd = nullptr; for (auto &LC : Obj.LoadCommands) { switch (LC.Data.load_command_data.cmd) { case MachO::LC_SYMTAB: @@ -511,6 +513,11 @@ void MachOWriter::writeLinkEditData(raw_ostream &OS) { WriteQueue.push_back(std::make_pair( DSymtabCmd->indirectsymoff, &MachOWriter::writeDynamicSymbolTable)); break; + case MachO::LC_FUNCTION_STARTS: + FunctionStartsCmd = &LC.Data.linkedit_data_command_data; + WriteQueue.push_back(std::make_pair(FunctionStartsCmd->dataoff, + &MachOWriter::writeFunctionStarts)); + break; } } @@ -569,6 +576,17 @@ void MachOWriter::writeDynamicSymbolTable(raw_ostream &OS) { sizeof(yaml::Hex32::BaseType)); } +void MachOWriter::writeFunctionStarts(raw_ostream &OS) { + uint64_t Addr = 0; + for (uint64_t NextAddr : Obj.LinkEdit.FunctionStarts) { + uint64_t Delta = NextAddr - Addr; + encodeULEB128(Delta, OS); + Addr = NextAddr; + } + + OS.write('\0'); +} + class UniversalWriter { public: UniversalWriter(yaml::YamlObjectFile &ObjectFile) diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp index f320094..b6f3b53 100644 --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -26,10 +26,10 @@ namespace llvm { MachOYAML::LoadCommand::~LoadCommand() = default; bool MachOYAML::LinkEditData::isEmpty() const { - return 0 == - RebaseOpcodes.size() + BindOpcodes.size() + WeakBindOpcodes.size() + - LazyBindOpcodes.size() + ExportTrie.Children.size() + - NameList.size() + StringTable.size(); + return 0 == RebaseOpcodes.size() + BindOpcodes.size() + + WeakBindOpcodes.size() + LazyBindOpcodes.size() + + ExportTrie.Children.size() + NameList.size() + + StringTable.size() + FunctionStarts.size(); } namespace yaml { @@ -165,6 +165,7 @@ void MappingTraits::mapping( IO.mapOptional("NameList", LinkEditData.NameList); IO.mapOptional("StringTable", LinkEditData.StringTable); IO.mapOptional("IndirectSymbols", LinkEditData.IndirectSymbols); + IO.mapOptional("FunctionStarts", LinkEditData.FunctionStarts); } void MappingTraits::mapping( diff --git a/llvm/test/ObjectYAML/MachO/function_starts.yaml b/llvm/test/ObjectYAML/MachO/function_starts.yaml new file mode 100644 index 0000000..fe939a6 --- /dev/null +++ b/llvm/test/ObjectYAML/MachO/function_starts.yaml @@ -0,0 +1,186 @@ +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x100000C + cpusubtype: 0x0 + 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: 0x100003F80 + size: 48 + offset: 0x3F80 + align: 2 + reloff: 0x0 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: C0035FD6FF8300D1FD7B01A9FD43009108008052E80B00B9BFC31FB8F9FFFF97E00B40B9FD7B41A9FF830091C0035FD6 + - sectname: __unwind_info + segname: __TEXT + addr: 0x100003FB0 + size: 80 + offset: 0x3FB0 + align: 2 + reloff: 0x0 + nreloc: 0 + flags: 0x0 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: 010000001C000000000000001C000000000000001C00000002000000803F00003400000034000000B13F00000000000034000000030000000C0002001400020000000001040000000000000400000002 + - cmd: LC_SEGMENT_64 + cmdsize: 72 + segname: __LINKEDIT + vmaddr: 4294983680 + vmsize: 16384 + fileoff: 16384 + filesize: 208 + 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: 56 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 16504 + nsyms: 3 + stroff: 16552 + strsize: 40 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 3 + iundefsym: 3 + 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: E1953271-0EDC-3009-9BED-635C8BB3DFE7 + - cmd: LC_BUILD_VERSION + cmdsize: 32 + platform: 1 + minos: 786432 + sdk: 786688 + ntools: 1 + Tools: + - tool: 3 + version: 46596096 + - cmd: LC_SOURCE_VERSION + cmdsize: 16 + version: 0 + - cmd: LC_MAIN + cmdsize: 24 + entryoff: 16260 + stacksize: 0 + - cmd: LC_LOAD_DYLIB + cmdsize: 56 + dylib: + name: 24 + timestamp: 2 + current_version: 85917696 + compatibility_version: 65536 + Content: '/usr/lib/libSystem.B.dylib' + ZeroPadBytes: 6 + - cmd: LC_FUNCTION_STARTS + cmdsize: 16 + dataoff: 16496 + datasize: 8 + - cmd: LC_DATA_IN_CODE + cmdsize: 16 + dataoff: 16504 + datasize: 0 +LinkEditData: + 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: 4294983552 + - n_strx: 27 + n_type: 0xF + n_sect: 1 + n_desc: 0 + n_value: 4294983556 + StringTable: + - ' ' + - __mh_execute_header + - _foo + - _main + - '' + - '' + - '' + - '' + - '' + - '' + - '' + FunctionStarts: [ 0x3F80, 0x3F84 ] +... + +# RUN: yaml2obj %s -o=%t +# RUN obj2yaml %t | FileCheck %s +# CHECK: FunctionStarts: [ 0x3F80, 0x3F84 ] + +# RUN: llvm-objdump --macho --function-starts %t | FileCheck %s --check-prefix=OBJDUMP-VERIFY +# OBJDUMP-VERIFY: function_starts.yaml.tmp: +# OBJDUMP-VERIFY: 0000000100003f80 +# OBJDUMP-VERIFY: 0000000100003f84 diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp index a6339b2..a32b6bf 100644 --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -34,6 +34,7 @@ class MachODumper { Error dumpLoadCommands(std::unique_ptr &Y); void dumpLinkEdit(std::unique_ptr &Y); void dumpRebaseOpcodes(std::unique_ptr &Y); + void dumpFunctionStarts(std::unique_ptr &Y); void dumpBindOpcodes(std::vector &BindOpcodes, ArrayRef OpcodeBuffer, bool Lazy = false); void dumpExportTrie(std::unique_ptr &Y); @@ -353,6 +354,15 @@ void MachODumper::dumpLinkEdit(std::unique_ptr &Y) { dumpExportTrie(Y); dumpSymbols(Y); dumpIndirectSymbols(Y); + dumpFunctionStarts(Y); +} + +void MachODumper::dumpFunctionStarts(std::unique_ptr &Y) { + MachOYAML::LinkEditData &LEData = Y->LinkEdit; + + auto FunctionStarts = Obj.getFunctionStarts(); + for (auto Addr : FunctionStarts) + LEData.FunctionStarts.push_back(Addr); } void MachODumper::dumpRebaseOpcodes(std::unique_ptr &Y) { -- 2.7.4