[obj2yaml] [yaml2obj] Basic support for MachO::load_command

This patch adds basic support for MachO::load_command. Load command types and sizes are encoded in the YAML and expanded back into MachO.

The YAML doesn't yet support load command structs, that is coming next. In the meantime as a temporary measure when writing MachO files the load commands are padded with zeros so that the generated binary is valid.

llvm-svn: 269442
This commit is contained in:
Chris Bieneman 2016-05-13 17:41:41 +00:00
parent e6e6eb6572
commit 58dc349826
5 changed files with 152 additions and 6 deletions

View File

@ -33,12 +33,23 @@ struct FileHeader {
llvm::yaml::Hex32 reserved;
};
struct LoadCommand {
virtual ~LoadCommand();
MachO::LoadCommandType cmd;
uint32_t cmdsize;
};
struct Object {
FileHeader Header;
std::vector<std::unique_ptr<LoadCommand>> LoadCommands;
};
} // namespace llvm::MachOYAML
} // namespace llvm
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MachOYAML::LoadCommand>)
namespace llvm {
namespace yaml {
template <> struct MappingTraits<MachOYAML::FileHeader> {
@ -49,6 +60,22 @@ template <> struct MappingTraits<MachOYAML::Object> {
static void mapping(IO &IO, MachOYAML::Object &Object);
};
template <> struct MappingTraits<std::unique_ptr<MachOYAML::LoadCommand>> {
static void mapping(IO &IO,
std::unique_ptr<MachOYAML::LoadCommand> &LoadCommand);
};
#define HANDLE_LOAD_COMMAND(LoadCommandName, LoadCommandValue) \
io.enumCase(value, #LoadCommandName, MachO::LoadCommandName);
template <> struct ScalarEnumerationTraits<MachO::LoadCommandType> {
static void enumeration(IO &io, MachO::LoadCommandType &value) {
#include "llvm/Support/MachO.def"
}
};
#undef HANDLE_LOAD_COMMAND
} // namespace llvm::yaml
} // namespace llvm

View File

@ -16,6 +16,8 @@
namespace llvm {
MachOYAML::LoadCommand::~LoadCommand() {}
namespace yaml {
void MappingTraits<MachOYAML::FileHeader>::mapping(
@ -40,9 +42,18 @@ void MappingTraits<MachOYAML::Object>::mapping(IO &IO,
IO.mapTag("!mach-o", true);
}
IO.mapRequired("FileHeader", Object.Header);
IO.mapOptional("LoadCommands", Object.LoadCommands);
IO.setContext(nullptr);
}
void MappingTraits<std::unique_ptr<MachOYAML::LoadCommand>>::mapping(
IO &IO, std::unique_ptr<MachOYAML::LoadCommand> &LoadCommand) {
if (!IO.outputting())
LoadCommand.reset(new MachOYAML::LoadCommand());
IO.mapRequired("cmd", LoadCommand->cmd);
IO.mapRequired("cmdsize", LoadCommand->cmdsize);
}
} // namespace llvm::yaml
} // namespace llvm

View File

@ -0,0 +1,81 @@
# RUN: yaml2obj -format=macho %s | obj2yaml | FileCheck %s
--- !mach-o
FileHeader:
magic: 0xFEEDFACF
cputype: 0x01000007
cpusubtype: 0x80000003
filetype: 0x00000002
ncmds: 16
sizeofcmds: 1408
flags: 0x00218085
reserved: 0x00000000
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 72
- cmd: LC_SEGMENT_64
cmdsize: 552
- cmd: LC_SEGMENT_64
cmdsize: 312
- cmd: LC_SEGMENT_64
cmdsize: 72
- cmd: LC_DYLD_INFO_ONLY
cmdsize: 48
- cmd: LC_SYMTAB
cmdsize: 24
- cmd: LC_DYSYMTAB
cmdsize: 80
- cmd: LC_LOAD_DYLINKER
cmdsize: 32
- cmd: LC_UUID
cmdsize: 24
- cmd: LC_VERSION_MIN_MACOSX
cmdsize: 16
- cmd: LC_SOURCE_VERSION
cmdsize: 16
- cmd: LC_MAIN
cmdsize: 24
- cmd: LC_LOAD_DYLIB
cmdsize: 48
- cmd: LC_LOAD_DYLIB
cmdsize: 56
- cmd: LC_FUNCTION_STARTS
cmdsize: 16
- cmd: LC_DATA_IN_CODE
cmdsize: 16
...
# CHECK: LoadCommands:
# CHECK: - cmd: LC_SEGMENT_64
# CHECK: cmdsize: 72
# CHECK: - cmd: LC_SEGMENT_64
# CHECK: cmdsize: 552
# CHECK: - cmd: LC_SEGMENT_64
# CHECK: cmdsize: 312
# CHECK: - cmd: LC_SEGMENT_64
# CHECK: cmdsize: 72
# CHECK: - cmd: LC_DYLD_INFO_ONLY
# CHECK: cmdsize: 48
# CHECK: - cmd: LC_SYMTAB
# CHECK: cmdsize: 24
# CHECK: - cmd: LC_DYSYMTAB
# CHECK: cmdsize: 80
# CHECK: - cmd: LC_LOAD_DYLINKER
# CHECK: cmdsize: 32
# CHECK: - cmd: LC_UUID
# CHECK: cmdsize: 24
# CHECK: - cmd: LC_VERSION_MIN_MACOSX
# CHECK: cmdsize: 16
# CHECK: - cmd: LC_SOURCE_VERSION
# CHECK: cmdsize: 16
# CHECK: - cmd: LC_MAIN
# CHECK: cmdsize: 24
# CHECK: - cmd: LC_LOAD_DYLIB
# CHECK: cmdsize: 48
# CHECK: - cmd: LC_LOAD_DYLIB
# CHECK: cmdsize: 56
# CHECK: - cmd: LC_FUNCTION_STARTS
# CHECK: cmdsize: 16
# CHECK: - cmd: LC_DATA_IN_CODE
# CHECK: cmdsize: 16

View File

@ -21,10 +21,10 @@ class MachODumper {
public:
MachODumper(const object::MachOObjectFile &O) : Obj(O) {}
Expected<std::unique_ptr<MachOYAML::Object> > dump();
Expected<std::unique_ptr<MachOYAML::Object>> dump();
};
Expected<std::unique_ptr<MachOYAML::Object> > MachODumper::dump() {
Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() {
auto Y = make_unique<MachOYAML::Object>();
Y->Header.magic = Obj.getHeader().magic;
Y->Header.cputype = Obj.getHeader().cputype;
@ -34,12 +34,19 @@ Expected<std::unique_ptr<MachOYAML::Object> > MachODumper::dump() {
Y->Header.sizeofcmds = Obj.getHeader().sizeofcmds;
Y->Header.flags = Obj.getHeader().flags;
for (auto load_command : Obj.load_commands()) {
auto LC = make_unique<MachOYAML::LoadCommand>();
LC->cmd = static_cast<MachO::LoadCommandType>(load_command.C.cmd);
LC->cmdsize = load_command.C.cmdsize;
Y->LoadCommands.push_back(std::move(LC));
}
return std::move(Y);
}
Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) {
MachODumper Dumper(Obj);
Expected<std::unique_ptr<MachOYAML::Object> > YAML = Dumper.dump();
Expected<std::unique_ptr<MachOYAML::Object>> YAML = Dumper.dump();
if (!YAML)
return YAML.takeError();

View File

@ -40,8 +40,9 @@ public:
private:
Error writeHeader(raw_ostream &OS);
Error writeLoadCommands(raw_ostream &OS);
MachOYAML::Object Obj;
MachOYAML::Object &Obj;
bool is64Bit;
union {
@ -53,6 +54,8 @@ private:
Error MachOWriter::writeMachO(raw_ostream &OS) {
if (auto Err = writeHeader(OS))
return Err;
if (auto Err = writeLoadCommands(OS))
return Err;
return Error::success();
}
@ -66,15 +69,32 @@ Error MachOWriter::writeHeader(raw_ostream &OS) {
Header.flags = Obj.Header.flags;
Header64.reserved = Obj.Header.reserved;
if (is64Bit) {
if (is64Bit)
OS.write((const char *)&Header64, sizeof(MachO::mach_header_64));
}
else
OS.write((const char *)&Header, sizeof(MachO::mach_header));
return Error::success();
}
Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
for (auto &LC : Obj.LoadCommands) {
MachO::load_command LCTemp;
LCTemp.cmd = LC->cmd;
LCTemp.cmdsize = LC->cmdsize;
OS.write(reinterpret_cast<const char *>(&LCTemp),
sizeof(MachO::load_command));
auto remaining_size = LC->cmdsize - sizeof(MachO::load_command);
if (remaining_size > 0) {
// TODO: Replace all this once the load command data is present in yaml.
std::vector<char> fill_data;
fill_data.insert(fill_data.begin(), remaining_size, 0);
OS.write(fill_data.data(), remaining_size);
}
}
return Error::success();
}
} // end anonymous namespace
int yaml2macho(yaml::Input &YIn, raw_ostream &Out) {