diff options
-rw-r--r-- | llvm/include/llvm/ObjectYAML/MachOYAML.h | 39 | ||||
-rw-r--r-- | llvm/lib/ObjectYAML/MachOYAML.cpp | 13 | ||||
-rw-r--r-- | llvm/test/ObjectYAML/MachO/rebase_opcode.yaml | 92 | ||||
-rw-r--r-- | llvm/tools/obj2yaml/macho2yaml.cpp | 54 | ||||
-rw-r--r-- | llvm/tools/yaml2obj/yaml2macho.cpp | 87 |
5 files changed, 264 insertions, 21 deletions
diff --git a/llvm/include/llvm/ObjectYAML/MachOYAML.h b/llvm/include/llvm/ObjectYAML/MachOYAML.h index c9eb48a24c5..d86589cb5e9 100644 --- a/llvm/include/llvm/ObjectYAML/MachOYAML.h +++ b/llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -57,10 +57,21 @@ struct LoadCommand { uint64_t ZeroPadBytes; }; +struct RebaseOpcode { + MachO::RebaseOpcode Opcode; + uint8_t Imm; + std::vector<yaml::Hex64> ExtraData; +}; + +struct LinkEditData { + std::vector<MachOYAML::RebaseOpcode> RebaseOpcodes; +}; + struct Object { FileHeader Header; std::vector<LoadCommand> LoadCommands; std::vector<Section> Sections; + LinkEditData LinkEdit; }; } // namespace llvm::MachOYAML @@ -69,6 +80,8 @@ struct Object { LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::LoadCommand) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Section) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex8) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex64) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::RebaseOpcode) namespace llvm { namespace yaml { @@ -85,6 +98,14 @@ template <> struct MappingTraits<MachOYAML::LoadCommand> { static void mapping(IO &IO, MachOYAML::LoadCommand &LoadCommand); }; +template <> struct MappingTraits<MachOYAML::LinkEditData> { + static void mapping(IO &IO, MachOYAML::LinkEditData &LinkEditData); +}; + +template <> struct MappingTraits<MachOYAML::RebaseOpcode> { + static void mapping(IO &IO, MachOYAML::RebaseOpcode &RebaseOpcode); +}; + template <> struct MappingTraits<MachOYAML::Section> { static void mapping(IO &IO, MachOYAML::Section &Section); }; @@ -99,6 +120,24 @@ template <> struct ScalarEnumerationTraits<MachO::LoadCommandType> { } }; +#define ENUM_CASE(Enum) \ + io.enumCase(value, #Enum, MachO::Enum); + +template <> struct ScalarEnumerationTraits<MachO::RebaseOpcode> { + static void enumeration(IO &io, MachO::RebaseOpcode &value) { + ENUM_CASE(REBASE_OPCODE_DONE) + ENUM_CASE(REBASE_OPCODE_SET_TYPE_IMM) + ENUM_CASE(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB) + ENUM_CASE(REBASE_OPCODE_ADD_ADDR_ULEB) + ENUM_CASE(REBASE_OPCODE_ADD_ADDR_IMM_SCALED) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_IMM_TIMES) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB) + io.enumFallback<Hex8>(value); + } +}; + // This trait is used for 16-byte chars in Mach structures used for strings typedef char char_16[16]; diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp index 2b4cfa0ce47..641e27e43f7 100644 --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -93,9 +93,22 @@ void MappingTraits<MachOYAML::Object>::mapping(IO &IO, } IO.mapRequired("FileHeader", Object.Header); IO.mapOptional("LoadCommands", Object.LoadCommands); + IO.mapOptional("LinkEditData", Object.LinkEdit); IO.setContext(nullptr); } +void MappingTraits<MachOYAML::LinkEditData>::mapping(IO &IO, + MachOYAML::LinkEditData &LinkEditData) { + IO.mapOptional("RebaseOpcodes", LinkEditData.RebaseOpcodes); +} + +void MappingTraits<MachOYAML::RebaseOpcode>::mapping(IO &IO, + MachOYAML::RebaseOpcode &RebaseOpcode) { + IO.mapRequired("Opcode", RebaseOpcode.Opcode); + IO.mapRequired("Imm", RebaseOpcode.Imm); + IO.mapOptional("ExtraData", RebaseOpcode.ExtraData); +} + template <typename StructType> void mapLoadCommandData(IO &IO, MachOYAML::LoadCommand &LoadCommand) {} diff --git a/llvm/test/ObjectYAML/MachO/rebase_opcode.yaml b/llvm/test/ObjectYAML/MachO/rebase_opcode.yaml new file mode 100644 index 00000000000..8a873be6e75 --- /dev/null +++ b/llvm/test/ObjectYAML/MachO/rebase_opcode.yaml @@ -0,0 +1,92 @@ +# RUN: yaml2obj -format=macho %s | obj2yaml | FileCheck %s + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x80000003 + filetype: 0x00000002 + ncmds: 4 + sizeofcmds: 224 + flags: 0x00218085 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 72 + segname: __LINKEDIT + vmaddr: 4294979584 + vmsize: 4096 + fileoff: 1024 + filesize: 2508 + maxprot: 7 + initprot: 1 + nsects: 0 + flags: 0 + - cmd: LC_DYLD_INFO_ONLY + cmdsize: 48 + rebase_off: 1024 + rebase_size: 8 + bind_off: 1032 + bind_size: 96 + weak_bind_off: 0 + weak_bind_size: 0 + lazy_bind_off: 1128 + lazy_bind_size: 624 + export_off: 1752 + export_size: 48 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 1816 + nsyms: 30 + stroff: 2436 + 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: 2296 + nindirectsyms: 35 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + RebaseOpcodes: + - Opcode: REBASE_OPCODE_SET_TYPE_IMM + Imm: 1 + - Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB + Imm: 2 + ExtraData: + - 0x0000000000000028 + - Opcode: REBASE_OPCODE_DO_REBASE_ULEB_TIMES + Imm: 0 + ExtraData: + - 0x000000000000000F + - Opcode: REBASE_OPCODE_DONE + Imm: 0 +... + +#CHECK: LinkEditData: +#CHECK: RebaseOpcodes: +#CHECK: - Opcode: REBASE_OPCODE_SET_TYPE_IMM +#CHECK: Imm: 1 +#CHECK: - Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB +#CHECK: Imm: 2 +#CHECK: ExtraData: +#CHECK: - 0x0000000000000028 +#CHECK: - Opcode: REBASE_OPCODE_DO_REBASE_ULEB_TIMES +#CHECK: Imm: 0 +#CHECK: ExtraData: +#CHECK: - 0x000000000000000F +#CHECK: - Opcode: REBASE_OPCODE_DONE +#CHECK: Imm: 0 diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp index eae15533d07..d3dfdbbf8da 100644 --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -12,6 +12,7 @@ #include "llvm/Object/MachOUniversal.h" #include "llvm/ObjectYAML/MachOYAML.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" #include <string.h> // for memcpy @@ -25,6 +26,9 @@ class MachODumper { const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd); const object::MachOObjectFile &Obj; + void dumpHeader(std::unique_ptr<MachOYAML::Object> &Y); + void dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y); + void dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y); public: MachODumper(const object::MachOObjectFile &O) : Obj(O) {} @@ -144,6 +148,13 @@ const char *MachODumper::processLoadCommandData<MachO::dylinker_command>( Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() { auto Y = make_unique<MachOYAML::Object>(); + dumpHeader(Y); + dumpLoadCommands(Y); + dumpLinkEdit(Y); + return std::move(Y); +} + +void MachODumper::dumpHeader(std::unique_ptr<MachOYAML::Object> &Y) { Y->Header.magic = Obj.getHeader().magic; Y->Header.cputype = Obj.getHeader().cputype; Y->Header.cpusubtype = Obj.getHeader().cpusubtype; @@ -152,7 +163,9 @@ Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() { Y->Header.sizeofcmds = Obj.getHeader().sizeofcmds; Y->Header.flags = Obj.getHeader().flags; Y->Header.reserved = 0; +} +void MachODumper::dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y) { for (auto LoadCmd : Obj.load_commands()) { MachOYAML::LoadCommand LC; const char *EndPtr = LoadCmd.Ptr; @@ -176,8 +189,47 @@ Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() { LC.ZeroPadBytes = RemainingBytes; Y->LoadCommands.push_back(std::move(LC)); } +} - return std::move(Y); +void MachODumper::dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y) { + MachOYAML::LinkEditData &LEData = Y->LinkEdit; + + auto RebaseOpcodes = Obj.getDyldInfoRebaseOpcodes(); + for (auto OpCode = RebaseOpcodes.begin(); OpCode != RebaseOpcodes.end(); + ++OpCode) { + MachOYAML::RebaseOpcode RebaseOp; + RebaseOp.Opcode = + static_cast<MachO::RebaseOpcode>(*OpCode & MachO::REBASE_OPCODE_MASK); + RebaseOp.Imm = *OpCode & MachO::REBASE_IMMEDIATE_MASK; + + unsigned Count; + uint64_t ULEB = 0; + + switch (RebaseOp.Opcode) { + case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: + + ULEB = decodeULEB128(OpCode + 1, &Count); + RebaseOp.ExtraData.push_back(ULEB); + OpCode += Count; + // Intentionally no break here -- This opcode has two ULEB values + case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + case MachO::REBASE_OPCODE_ADD_ADDR_ULEB: + case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: + case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: + + ULEB = decodeULEB128(OpCode + 1, &Count); + RebaseOp.ExtraData.push_back(ULEB); + OpCode += Count; + break; + default: + break; + } + + LEData.RebaseOpcodes.push_back(RebaseOp); + + if (RebaseOp.Opcode == MachO::REBASE_OPCODE_DONE) + break; + } } Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) { diff --git a/llvm/tools/yaml2obj/yaml2macho.cpp b/llvm/tools/yaml2obj/yaml2macho.cpp index 749090e7cfa..d24a08c6e54 100644 --- a/llvm/tools/yaml2obj/yaml2macho.cpp +++ b/llvm/tools/yaml2obj/yaml2macho.cpp @@ -15,10 +15,13 @@ #include "yaml2obj.h" #include "llvm/ObjectYAML/MachOYAML.h" #include "llvm/Support/Error.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MachO.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Format.h" + using namespace llvm; namespace { @@ -42,6 +45,9 @@ private: Error writeHeader(raw_ostream &OS); Error writeLoadCommands(raw_ostream &OS); Error writeSectionData(raw_ostream &OS); + Error writeLinkEditData(raw_ostream &OS); + + void ZeroToOffset(raw_ostream &OS, size_t offset); MachOYAML::Object &Obj; bool is64Bit; @@ -165,6 +171,12 @@ void Fill(raw_ostream &OS, size_t Size, uint32_t Data) { OS.write(reinterpret_cast<char *>(FillData.data()), Size); } +void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { + auto currOffset = OS.tell() - fileStart; + if (currOffset < Offset) + ZeroFillBytes(OS, Offset - currOffset); +} + Error MachOWriter::writeLoadCommands(raw_ostream &OS) { for (auto &LC : Obj.LoadCommands) { size_t BytesWritten = 0; @@ -212,42 +224,77 @@ Error MachOWriter::writeSectionData(raw_ostream &OS) { switch (LC.Data.load_command_data.cmd) { case MachO::LC_SEGMENT: case MachO::LC_SEGMENT_64: + auto currOffset = OS.tell() - fileStart; + auto segname = LC.Data.segment_command_data.segname; uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff : LC.Data.segment_command_data.fileoff; - // Zero Fill any data between the end of the last thing we wrote and the - // start of this section. - auto currOffset = OS.tell() - fileStart; - if (currOffset < segOff) { - ZeroFillBytes(OS, segOff - currOffset); - } - - for (auto &Sec : LC.Sections) { + if (0 == strncmp(&segname[0], "__LINKEDIT", 16)) { + if (auto Err = writeLinkEditData(OS)) + return Err; + } else { // Zero Fill any data between the end of the last thing we wrote and the // start of this section. - assert(OS.tell() - fileStart <= Sec.offset && - "Wrote too much data somewhere, section offsets don't line up."); - currOffset = OS.tell() - fileStart; - if (currOffset < Sec.offset) { - ZeroFillBytes(OS, Sec.offset - currOffset); + if (currOffset < segOff) { + ZeroFillBytes(OS, segOff - currOffset); } - // Fills section data with 0xDEADBEEF - Fill(OS, Sec.size, 0xDEADBEEFu); + for (auto &Sec : LC.Sections) { + // Zero Fill any data between the end of the last thing we wrote and + // the + // start of this section. + assert( + OS.tell() - fileStart <= Sec.offset && + "Wrote too much data somewhere, section offsets don't line up."); + currOffset = OS.tell() - fileStart; + if (currOffset < Sec.offset) { + ZeroFillBytes(OS, Sec.offset - currOffset); + } + + // Fills section data with 0xDEADBEEF + Fill(OS, Sec.size, 0xDEADBEEFu); + } } uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize : LC.Data.segment_command_data.filesize; - currOffset = OS.tell() - fileStart; - if (currOffset < segOff + segSize) { - // Fills segment data not covered by a section with 0xBAADDA7A - Fill(OS, (segOff + segSize) - currOffset, 0xBAADDA7Au); - } + ZeroToOffset(OS, segOff + segSize); break; } } return Error::success(); } +Error MachOWriter::writeLinkEditData(raw_ostream &OS) { + MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit; + MachO::dyld_info_command *DyldInfoOnlyCmd = 0; + MachO::symtab_command *SymtabCmd = 0; + for (auto &LC : Obj.LoadCommands) { + switch (LC.Data.load_command_data.cmd) { + case MachO::LC_SYMTAB: + SymtabCmd = &LC.Data.symtab_command_data; + break; + case MachO::LC_DYLD_INFO_ONLY: + DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data; + break; + } + } + + ZeroToOffset(OS, DyldInfoOnlyCmd->rebase_off); + + for (auto Opcode : LinkEdit.RebaseOpcodes) { + uint8_t OpByte = Opcode.Opcode | Opcode.Imm; + OS.write(reinterpret_cast<char *>(&OpByte), 1); + for (auto Data : Opcode.ExtraData) { + encodeULEB128(Data, OS); + } + } + + // Fill to the end of the string table + ZeroToOffset(OS, SymtabCmd->stroff + SymtabCmd->strsize); + + return Error::success(); +} + } // end anonymous namespace int yaml2macho(yaml::Input &YIn, raw_ostream &Out) { |