1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 12:43:36 +01:00

[obj2yaml] [yaml2obj] MachO support for rebase opcodes

This is the first bit of support for MachO __LINKEDIT segment data.

llvm-svn: 270724
This commit is contained in:
Chris Bieneman 2016-05-25 17:09:07 +00:00
parent 2b1c02aa22
commit d8d2780ae0
5 changed files with 264 additions and 21 deletions

View File

@ -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];

View File

@ -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) {}

View File

@ -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

View File

@ -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) {

View File

@ -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) {