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:
parent
2b1c02aa22
commit
d8d2780ae0
@ -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];
|
||||
|
||||
|
@ -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) {}
|
||||
|
||||
|
92
test/ObjectYAML/MachO/rebase_opcode.yaml
Normal file
92
test/ObjectYAML/MachO/rebase_opcode.yaml
Normal 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
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user