diff options
author | Chris Bieneman <beanz@apple.com> | 2016-05-26 20:06:14 +0000 |
---|---|---|
committer | Chris Bieneman <beanz@apple.com> | 2016-05-26 20:06:14 +0000 |
commit | 524243d61e9ed6f99be875cdc63071ff86b3a4a1 (patch) | |
tree | 6c6132369f2687f5bd68039f86303a7cf7b3b50b | |
parent | f1f3f93c9efe6a409bc79d17cd8be1f860a758b4 (diff) | |
download | bcm5719-llvm-524243d61e9ed6f99be875cdc63071ff86b3a4a1.tar.gz bcm5719-llvm-524243d61e9ed6f99be875cdc63071ff86b3a4a1.zip |
[obj2yaml][yaml2obj] Support for MachO bind opcodes
This adds support for YAML round tripping dyld info bind opcodes. Bind opcodes can have signed or unsigned LEB128 data, and they can have symbols associated with them.
llvm-svn: 270901
-rw-r--r-- | llvm/include/llvm/ObjectYAML/MachOYAML.h | 59 | ||||
-rw-r--r-- | llvm/lib/ObjectYAML/MachOYAML.cpp | 18 | ||||
-rw-r--r-- | llvm/test/ObjectYAML/MachO/bind_opcode.yaml | 133 | ||||
-rw-r--r-- | llvm/tools/obj2yaml/macho2yaml.cpp | 66 | ||||
-rw-r--r-- | llvm/tools/yaml2obj/yaml2macho.cpp | 17 |
5 files changed, 276 insertions, 17 deletions
diff --git a/llvm/include/llvm/ObjectYAML/MachOYAML.h b/llvm/include/llvm/ObjectYAML/MachOYAML.h index d86589cb5e9..185afdcdd50 100644 --- a/llvm/include/llvm/ObjectYAML/MachOYAML.h +++ b/llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -63,8 +63,17 @@ struct RebaseOpcode { std::vector<yaml::Hex64> ExtraData; }; +struct BindOpcode { + MachO::BindOpcode Opcode; + uint8_t Imm; + std::vector<yaml::Hex64> ULEBExtraData; + std::vector<int64_t> SLEBExtraData; + StringRef Symbol; +}; + struct LinkEditData { std::vector<MachOYAML::RebaseOpcode> RebaseOpcodes; + std::vector<MachOYAML::BindOpcode> BindOpcodes; }; struct Object { @@ -81,7 +90,9 @@ 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(int64_t) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::RebaseOpcode) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::BindOpcode) namespace llvm { namespace yaml { @@ -106,6 +117,10 @@ template <> struct MappingTraits<MachOYAML::RebaseOpcode> { static void mapping(IO &IO, MachOYAML::RebaseOpcode &RebaseOpcode); }; +template <> struct MappingTraits<MachOYAML::BindOpcode> { + static void mapping(IO &IO, MachOYAML::BindOpcode &BindOpcode); +}; + template <> struct MappingTraits<MachOYAML::Section> { static void mapping(IO &IO, MachOYAML::Section &Section); }; @@ -116,25 +131,43 @@ template <> struct MappingTraits<MachOYAML::Section> { template <> struct ScalarEnumerationTraits<MachO::LoadCommandType> { static void enumeration(IO &io, MachO::LoadCommandType &value) { #include "llvm/Support/MachO.def" - io.enumFallback<Hex32>(value); + io.enumFallback<Hex32>(value); } }; -#define ENUM_CASE(Enum) \ - io.enumCase(value, #Enum, MachO::Enum); +#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); + 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); + } +}; + +template <> struct ScalarEnumerationTraits<MachO::BindOpcode> { + static void enumeration(IO &io, MachO::BindOpcode &value) { + ENUM_CASE(BIND_OPCODE_DONE) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM) + ENUM_CASE(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM) + ENUM_CASE(BIND_OPCODE_SET_TYPE_IMM) + ENUM_CASE(BIND_OPCODE_SET_ADDEND_SLEB) + ENUM_CASE(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB) + ENUM_CASE(BIND_OPCODE_ADD_ADDR_ULEB) + ENUM_CASE(BIND_OPCODE_DO_BIND) + ENUM_CASE(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) + ENUM_CASE(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED) + ENUM_CASE(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB) + io.enumFallback<Hex8>(value); } }; diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp index 641e27e43f7..48217af54b7 100644 --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -97,18 +97,28 @@ void MappingTraits<MachOYAML::Object>::mapping(IO &IO, IO.setContext(nullptr); } -void MappingTraits<MachOYAML::LinkEditData>::mapping(IO &IO, - MachOYAML::LinkEditData &LinkEditData) { +void MappingTraits<MachOYAML::LinkEditData>::mapping( + IO &IO, MachOYAML::LinkEditData &LinkEditData) { IO.mapOptional("RebaseOpcodes", LinkEditData.RebaseOpcodes); + IO.mapOptional("BindOpcodes", LinkEditData.BindOpcodes); } -void MappingTraits<MachOYAML::RebaseOpcode>::mapping(IO &IO, - MachOYAML::RebaseOpcode &RebaseOpcode) { +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); } +void MappingTraits<MachOYAML::BindOpcode>::mapping( + IO &IO, MachOYAML::BindOpcode &BindOpcode) { + IO.mapRequired("Opcode", BindOpcode.Opcode); + IO.mapRequired("Imm", BindOpcode.Imm); + IO.mapOptional("ULEBExtraData", BindOpcode.ULEBExtraData); + IO.mapOptional("SLEBExtraData", BindOpcode.SLEBExtraData); + IO.mapOptional("Symbol", BindOpcode.Symbol); +} + template <typename StructType> void mapLoadCommandData(IO &IO, MachOYAML::LoadCommand &LoadCommand) {} diff --git a/llvm/test/ObjectYAML/MachO/bind_opcode.yaml b/llvm/test/ObjectYAML/MachO/bind_opcode.yaml new file mode 100644 index 00000000000..4c010b4cd48 --- /dev/null +++ b/llvm/test/ObjectYAML/MachO/bind_opcode.yaml @@ -0,0 +1,133 @@ +# 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: + BindOpcodes: + - Opcode: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM + Imm: 1 + - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM + Imm: 0 + Symbol: __ZNSt3__14coutE + - Opcode: BIND_OPCODE_SET_TYPE_IMM + Imm: 1 + - Opcode: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB + Imm: 2 + ULEBExtraData: + - 0x0000000000000000 + - Opcode: BIND_OPCODE_DO_BIND + Imm: 0 + - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM + Imm: 0 + Symbol: __ZNSt3__15ctypeIcE2idE + - Opcode: BIND_OPCODE_DO_BIND + Imm: 0 + - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM + Imm: 0 + Symbol: ___gxx_personality_v0 + - Opcode: BIND_OPCODE_DO_BIND + Imm: 0 + - Opcode: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM + Imm: 2 + - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM + Imm: 0 + Symbol: dyld_stub_binder + - Opcode: BIND_OPCODE_DO_BIND + Imm: 0 + - Opcode: BIND_OPCODE_DONE + Imm: 0 +... + +#CHECK: LinkEditData: +#CHECK: BindOpcodes: +#CHECK: - Opcode: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM +#CHECK: Imm: 1 +#CHECK: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM +#CHECK: Imm: 0 +#CHECK: Symbol: __ZNSt3__14coutE +#CHECK: - Opcode: BIND_OPCODE_SET_TYPE_IMM +#CHECK: Imm: 1 +#CHECK: - Opcode: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB +#CHECK: Imm: 2 +#CHECK: ULEBExtraData: +#CHECK: - 0x0000000000000000 +#CHECK: - Opcode: BIND_OPCODE_DO_BIND +#CHECK: Imm: 0 +#CHECK: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM +#CHECK: Imm: 0 +#CHECK: Symbol: __ZNSt3__15ctypeIcE2idE +#CHECK: - Opcode: BIND_OPCODE_DO_BIND +#CHECK: Imm: 0 +#CHECK: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM +#CHECK: Imm: 0 +#CHECK: Symbol: ___gxx_personality_v0 +#CHECK: - Opcode: BIND_OPCODE_DO_BIND +#CHECK: Imm: 0 +#CHECK: - Opcode: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM +#CHECK: Imm: 2 +#CHECK: - Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM +#CHECK: Imm: 0 +#CHECK: Symbol: dyld_stub_binder +#CHECK: - Opcode: BIND_OPCODE_DO_BIND +#CHECK: Imm: 0 +#CHECK: - Opcode: BIND_OPCODE_DONE +#CHECK: Imm: 0 + diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp index d3dfdbbf8da..7aca3fd82f0 100644 --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -29,6 +29,9 @@ class MachODumper { void dumpHeader(std::unique_ptr<MachOYAML::Object> &Y); void dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y); void dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y); + void dumpRebaseOpcodes(std::unique_ptr<MachOYAML::Object> &Y); + void dumpBindOpcodes(std::vector<MachOYAML::BindOpcode> &BindOpcodes, + ArrayRef<uint8_t> OpcodeBuffer, bool Lazy = false); public: MachODumper(const object::MachOObjectFile &O) : Obj(O) {} @@ -192,6 +195,11 @@ void MachODumper::dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y) { } void MachODumper::dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y) { + dumpRebaseOpcodes(Y); + dumpBindOpcodes(Y->LinkEdit.BindOpcodes, Obj.getDyldInfoBindOpcodes()); +} + +void MachODumper::dumpRebaseOpcodes(std::unique_ptr<MachOYAML::Object> &Y) { MachOYAML::LinkEditData &LEData = Y->LinkEdit; auto RebaseOpcodes = Obj.getDyldInfoRebaseOpcodes(); @@ -232,6 +240,64 @@ void MachODumper::dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y) { } } +void MachODumper::dumpBindOpcodes( + std::vector<MachOYAML::BindOpcode> &BindOpcodes, + ArrayRef<uint8_t> OpcodeBuffer, bool Lazy) { + for (auto OpCode = OpcodeBuffer.begin(); OpCode != OpcodeBuffer.end(); + ++OpCode) { + MachOYAML::BindOpcode BindOp; + BindOp.Opcode = + static_cast<MachO::BindOpcode>(*OpCode & MachO::BIND_OPCODE_MASK); + BindOp.Imm = *OpCode & MachO::BIND_IMMEDIATE_MASK; + + unsigned Count; + uint64_t ULEB = 0; + int64_t SLEB = 0; + const uint8_t *SymStart; + + switch (BindOp.Opcode) { + case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: + ULEB = decodeULEB128(OpCode + 1, &Count); + BindOp.ULEBExtraData.push_back(ULEB); + OpCode += Count; + // Intentionally no break here -- this opcode has two ULEB values + + case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: + case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + case MachO::BIND_OPCODE_ADD_ADDR_ULEB: + case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: + ULEB = decodeULEB128(OpCode + 1, &Count); + BindOp.ULEBExtraData.push_back(ULEB); + OpCode += Count; + break; + + case MachO::BIND_OPCODE_SET_ADDEND_SLEB: + SLEB = decodeSLEB128(OpCode + 1, &Count); + BindOp.SLEBExtraData.push_back(SLEB); + OpCode += Count; + break; + + case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: + SymStart = ++OpCode; + while (*OpCode) { + ++OpCode; + } + BindOp.Symbol = StringRef(reinterpret_cast<const char *>(SymStart), + OpCode - SymStart); + break; + default: + break; + } + + BindOpcodes.push_back(BindOp); + + // Lazy bindings have DONE opcodes between operations, so we need to keep + // processing after a DONE. + if (!Lazy && BindOp.Opcode == MachO::BIND_OPCODE_DONE) + break; + } +} + Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) { MachODumper Dumper(Obj); Expected<std::unique_ptr<MachOYAML::Object>> YAML = Dumper.dump(); diff --git a/llvm/tools/yaml2obj/yaml2macho.cpp b/llvm/tools/yaml2obj/yaml2macho.cpp index d24a08c6e54..a1f5dda9d9d 100644 --- a/llvm/tools/yaml2obj/yaml2macho.cpp +++ b/llvm/tools/yaml2obj/yaml2macho.cpp @@ -289,6 +289,23 @@ Error MachOWriter::writeLinkEditData(raw_ostream &OS) { } } + ZeroToOffset(OS, DyldInfoOnlyCmd->bind_off); + + for (auto Opcode : LinkEdit.BindOpcodes) { + uint8_t OpByte = Opcode.Opcode | Opcode.Imm; + OS.write(reinterpret_cast<char *>(&OpByte), 1); + for (auto Data : Opcode.ULEBExtraData) { + encodeULEB128(Data, OS); + } + for (auto Data : Opcode.SLEBExtraData) { + encodeSLEB128(Data, OS); + } + if(!Opcode.Symbol.empty()) { + OS.write(Opcode.Symbol.data(), Opcode.Symbol.size()); + OS.write("\0", 1); + } + } + // Fill to the end of the string table ZeroToOffset(OS, SymtabCmd->stroff + SymtabCmd->strsize); |