Skip to content

Commit

Permalink
[obj2yaml][yaml2obj] Support for MachO bind opcodes
Browse files Browse the repository at this point in the history
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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@270901 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Chris Bieneman committed May 26, 2016
1 parent 34fca4b commit 7ad3d3b
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 17 deletions.
59 changes: 46 additions & 13 deletions include/llvm/ObjectYAML/MachOYAML.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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);
};
Expand All @@ -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);
}
};

Expand Down
18 changes: 14 additions & 4 deletions lib/ObjectYAML/MachOYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}

Expand Down
133 changes: 133 additions & 0 deletions test/ObjectYAML/MachO/bind_opcode.yaml
Original file line number Diff line number Diff line change
@@ -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

66 changes: 66 additions & 0 deletions tools/obj2yaml/macho2yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
17 changes: 17 additions & 0 deletions tools/yaml2obj/yaml2macho.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 7ad3d3b

Please sign in to comment.