diff --git a/include/llvm/ObjectYAML/MachOYAML.h b/include/llvm/ObjectYAML/MachOYAML.h index d86589cb5e93..185afdcdd50d 100644 --- a/include/llvm/ObjectYAML/MachOYAML.h +++ b/include/llvm/ObjectYAML/MachOYAML.h @@ -63,8 +63,17 @@ struct RebaseOpcode { std::vector ExtraData; }; +struct BindOpcode { + MachO::BindOpcode Opcode; + uint8_t Imm; + std::vector ULEBExtraData; + std::vector SLEBExtraData; + StringRef Symbol; +}; + struct LinkEditData { std::vector RebaseOpcodes; + std::vector 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 { static void mapping(IO &IO, MachOYAML::RebaseOpcode &RebaseOpcode); }; +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::BindOpcode &BindOpcode); +}; + template <> struct MappingTraits { static void mapping(IO &IO, MachOYAML::Section &Section); }; @@ -116,25 +131,43 @@ template <> struct MappingTraits { template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, MachO::LoadCommandType &value) { #include "llvm/Support/MachO.def" - io.enumFallback(value); + io.enumFallback(value); } }; -#define ENUM_CASE(Enum) \ - io.enumCase(value, #Enum, MachO::Enum); +#define ENUM_CASE(Enum) io.enumCase(value, #Enum, MachO::Enum); template <> struct ScalarEnumerationTraits { 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(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(value); + } +}; + +template <> struct ScalarEnumerationTraits { + 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(value); } }; diff --git a/lib/ObjectYAML/MachOYAML.cpp b/lib/ObjectYAML/MachOYAML.cpp index 641e27e43f70..48217af54b70 100644 --- a/lib/ObjectYAML/MachOYAML.cpp +++ b/lib/ObjectYAML/MachOYAML.cpp @@ -97,18 +97,28 @@ void MappingTraits::mapping(IO &IO, IO.setContext(nullptr); } -void MappingTraits::mapping(IO &IO, - MachOYAML::LinkEditData &LinkEditData) { +void MappingTraits::mapping( + IO &IO, MachOYAML::LinkEditData &LinkEditData) { IO.mapOptional("RebaseOpcodes", LinkEditData.RebaseOpcodes); + IO.mapOptional("BindOpcodes", LinkEditData.BindOpcodes); } -void MappingTraits::mapping(IO &IO, - MachOYAML::RebaseOpcode &RebaseOpcode) { +void MappingTraits::mapping( + IO &IO, MachOYAML::RebaseOpcode &RebaseOpcode) { IO.mapRequired("Opcode", RebaseOpcode.Opcode); IO.mapRequired("Imm", RebaseOpcode.Imm); IO.mapOptional("ExtraData", RebaseOpcode.ExtraData); } +void MappingTraits::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 void mapLoadCommandData(IO &IO, MachOYAML::LoadCommand &LoadCommand) {} diff --git a/test/ObjectYAML/MachO/bind_opcode.yaml b/test/ObjectYAML/MachO/bind_opcode.yaml new file mode 100644 index 000000000000..4c010b4cd48e --- /dev/null +++ b/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/tools/obj2yaml/macho2yaml.cpp b/tools/obj2yaml/macho2yaml.cpp index d3dfdbbf8dae..7aca3fd82f03 100644 --- a/tools/obj2yaml/macho2yaml.cpp +++ b/tools/obj2yaml/macho2yaml.cpp @@ -29,6 +29,9 @@ class MachODumper { void dumpHeader(std::unique_ptr &Y); void dumpLoadCommands(std::unique_ptr &Y); void dumpLinkEdit(std::unique_ptr &Y); + void dumpRebaseOpcodes(std::unique_ptr &Y); + void dumpBindOpcodes(std::vector &BindOpcodes, + ArrayRef OpcodeBuffer, bool Lazy = false); public: MachODumper(const object::MachOObjectFile &O) : Obj(O) {} @@ -192,6 +195,11 @@ void MachODumper::dumpLoadCommands(std::unique_ptr &Y) { } void MachODumper::dumpLinkEdit(std::unique_ptr &Y) { + dumpRebaseOpcodes(Y); + dumpBindOpcodes(Y->LinkEdit.BindOpcodes, Obj.getDyldInfoBindOpcodes()); +} + +void MachODumper::dumpRebaseOpcodes(std::unique_ptr &Y) { MachOYAML::LinkEditData &LEData = Y->LinkEdit; auto RebaseOpcodes = Obj.getDyldInfoRebaseOpcodes(); @@ -232,6 +240,64 @@ void MachODumper::dumpLinkEdit(std::unique_ptr &Y) { } } +void MachODumper::dumpBindOpcodes( + std::vector &BindOpcodes, + ArrayRef OpcodeBuffer, bool Lazy) { + for (auto OpCode = OpcodeBuffer.begin(); OpCode != OpcodeBuffer.end(); + ++OpCode) { + MachOYAML::BindOpcode BindOp; + BindOp.Opcode = + static_cast(*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(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> YAML = Dumper.dump(); diff --git a/tools/yaml2obj/yaml2macho.cpp b/tools/yaml2obj/yaml2macho.cpp index d24a08c6e54c..a1f5dda9d9de 100644 --- a/tools/yaml2obj/yaml2macho.cpp +++ b/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(&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);