1
1
mirror of https://github.com/rui314/mold.git synced 2024-09-21 01:47:11 +03:00

[Mach-O] wip

This commit is contained in:
Rui Ueyama 2021-09-15 21:00:14 +09:00
parent 2fedb900d3
commit 5ea876ff2f
6 changed files with 168 additions and 28 deletions

View File

@ -84,7 +84,7 @@ void dump_file(std::string path) {
<< "\n strsize: 0x" << cmd.strsize << "\n strsize: 0x" << cmd.strsize
<< "\n"; << "\n";
MachoSym *syms = (MachoSym *)(buf + cmd.symoff); MachSym *syms = (MachSym *)(buf + cmd.symoff);
for (i64 j = 0; j < cmd.nsyms; j++) { for (i64 j = 0; j < cmd.nsyms; j++) {
std::cout << " symbol:" std::cout << " symbol:"
<< "\n name: " << (char *)(buf + cmd.stroff + syms[j].stroff) << "\n name: " << (char *)(buf + cmd.stroff + syms[j].stroff)
@ -184,7 +184,7 @@ void dump_file(std::string path) {
// } // }
if (sec[j].reloff) { if (sec[j].reloff) {
MachoRel *rel = (MachoRel *)(buf + sec[j].reloff); MachRel *rel = (MachRel *)(buf + sec[j].reloff);
for (i64 k = 0; k < sec[j].nreloc; k++) { for (i64 k = 0; k < sec[j].nreloc; k++) {
std::cout << " reloc: " std::cout << " reloc: "
<< "\n offset: 0x" << rel[k].offset << "\n offset: 0x" << rel[k].offset

View File

@ -377,7 +377,7 @@ struct DataInCodeEntry {
}; };
// This struct is named `n_list` on BSD and macOS. // This struct is named `n_list` on BSD and macOS.
struct MachoSym { struct MachSym {
u32 stroff; u32 stroff;
u8 ext : 1; u8 ext : 1;
u8 type : 3; u8 type : 3;
@ -389,7 +389,7 @@ struct MachoSym {
}; };
// This struct is named `relocation_info` on BSD and macOS. // This struct is named `relocation_info` on BSD and macOS.
struct MachoRel { struct MachRel {
i32 offset; i32 offset;
u32 idx : 24; u32 idx : 24;
u32 is_pcrel : 1; u32 is_pcrel : 1;

View File

@ -10,21 +10,34 @@
namespace mold::macho { namespace mold::macho {
static void print_bytes(u8 *buf, i64 size) { void create_synthetic_sections(Context &ctx) {
if (size == 0) { auto add = [&](auto &chunk) {
std::cout << "[]\n"; ctx.chunks.push_back(chunk.get());
return; };
}
std::cout << "[" << std::setw(2) << std::setfill('0') << (u32)buf[0]; add(ctx.mach_hdr = std::make_unique<MachHeaderChunk>());
for (i64 i = 1; i < size; i++) add(ctx.load_cmd = std::make_unique<LoadCommandChunk>());
std::cout << " " << std::setw(2) << std::setfill('0') << (u32)buf[i]; add(ctx.zero_page = std::make_unique<PageZeroChunk>());
std::cout << "]\n"; }
void compute_chunk_sizes(Context &ctx) {
for (Chunk *chunk : ctx.chunks)
chunk->update_hdr(ctx);
}
void assign_file_offsets(Context &ctx) {
i64 fileoff = 0;
for (Chunk *chunk : ctx.chunks) {
chunk->fileoff = fileoff;
fileoff += chunk->size;
}
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
Context ctx; Context ctx;
// Parse command line arguments
if (argc == 1) { if (argc == 1) {
SyncOut(ctx) << "mold macho stub\n"; SyncOut(ctx) << "mold macho stub\n";
exit(0); exit(0);
@ -37,25 +50,27 @@ int main(int argc, char **argv) {
exit(0); exit(0);
} }
if (argc != 2) if (std::string_view(argv[1]) == "-out") {
Fatal(ctx) << "usage: ld64.mold <output-file>\n"; if (argc != 3)
ctx.arg.output = argv[1]; Fatal(ctx) << "usage: ld64.mold -out <output-file>\n";
ctx.arg.output = argv[2];
ctx.output_file = std::make_unique<OutputFile>(ctx, ctx.arg.output, 1024, 0777); create_synthetic_sections(ctx);
ctx.buf = ctx.output_file->buf; compute_chunk_sizes(ctx);
assign_file_offsets(ctx);
MachHeader &hdr = *(MachHeader *)ctx.buf; ctx.output_file =
hdr.magic = 0xfeedfacf; std::make_unique<OutputFile>(ctx, ctx.arg.output, 1024, 0777);
hdr.cputype = CPU_TYPE_X86_64; ctx.buf = ctx.output_file->buf;
hdr.cpusubtype = CPU_SUBTYPE_X86_64_ALL;
hdr.filetype = MH_EXECUTE;
hdr.ncmds = 0x10;
hdr.sizeofcmds = 0x558;
hdr.flags = MH_TWOLEVEL | MH_NOUNDEFS | MH_DYLDLINK | MH_PIE;
ctx.output_file->close(ctx); for (Chunk *chunk : ctx.chunks)
chunk->copy_buf(ctx);
return 0; ctx.output_file->close(ctx);
exit(0);
}
Fatal(ctx) << "usage: ld64.mold\n";
} }
} }

View File

@ -9,6 +9,59 @@ namespace mold::macho {
struct Context; struct Context;
//
// output-chunks.cc
//
class Chunk {
public:
// There are three types of OutputChunks:
// - HEADER: the ELF, section or segment headers
// - REGULAR: output sections containing input sections
// - SYNTHETIC: linker-synthesized sections such as got or plt
enum Kind : u8 { HEADER, REGULAR, SYNTHETIC };
virtual ~Chunk() = default;
virtual void copy_buf(Context &ctx) {}
virtual void update_hdr(Context &ctx) {}
std::string_view name;
Kind kind;
i64 size = 0;
i64 fileoff = 0;
std::vector<u8> load_cmd;
protected:
Chunk(Kind kind) : kind(kind) {}
};
class MachHeaderChunk : public Chunk {
public:
MachHeaderChunk() : Chunk(HEADER) {
size = sizeof(MachHeader);
}
void copy_buf(Context &ctx) override;
};
class LoadCommandChunk : public Chunk {
public:
LoadCommandChunk() : Chunk(HEADER) {}
void update_hdr(Context &ctx) override;
void copy_buf(Context &ctx) override;
i64 ncmds = 0;
private:
std::vector<u8> contents;
};
class PageZeroChunk : public Chunk {
public:
PageZeroChunk();
};
// //
// output-file.cc // output-file.cc
// //
@ -56,6 +109,11 @@ struct Context {
std::unique_ptr<OutputFile> output_file; std::unique_ptr<OutputFile> output_file;
u8 *buf; u8 *buf;
std::unique_ptr<MachHeaderChunk> mach_hdr;
std::unique_ptr<LoadCommandChunk> load_cmd;
std::unique_ptr<PageZeroChunk> zero_page;
std::vector<Chunk *> chunks;
}; };
int main(int argc, char **argv); int main(int argc, char **argv);

52
macho/output-chunks.cc Normal file
View File

@ -0,0 +1,52 @@
#include "mold.h"
namespace mold::macho {
void MachHeaderChunk::copy_buf(Context &ctx) {
MachHeader &hdr = *(MachHeader *)(ctx.buf + fileoff);
memset(&hdr, 0, sizeof(hdr));
hdr.magic = 0xfeedfacf;
hdr.cputype = CPU_TYPE_X86_64;
hdr.cpusubtype = CPU_SUBTYPE_X86_64_ALL;
hdr.filetype = MH_EXECUTE;
hdr.ncmds = ctx.load_cmd->ncmds;
hdr.sizeofcmds = ctx.load_cmd->size;
hdr.flags = MH_TWOLEVEL | MH_NOUNDEFS | MH_DYLDLINK | MH_PIE;
}
void LoadCommandChunk::update_hdr(Context &ctx) {
size = 0;
ncmds = 0;
for (Chunk *chunk : ctx.chunks) {
if (chunk->load_cmd.size() > 0) {
size += chunk->load_cmd.size();
ncmds++;
}
}
}
void LoadCommandChunk::copy_buf(Context &ctx) {
u8 *buf = ctx.buf + fileoff;
i64 off = 0;
for (Chunk *chunk : ctx.chunks) {
if (chunk->load_cmd.size() > 0) {
std::vector<u8> &vec = chunk->load_cmd;
memcpy(buf + off, vec.data(), vec.size());
off += vec.size();
}
}
}
PageZeroChunk::PageZeroChunk() : Chunk(SYNTHETIC) {
load_cmd.resize(sizeof(SegmentCommand));
SegmentCommand &cmd = *(SegmentCommand *)load_cmd.data();
cmd.cmd = LC_SEGMENT_64;
cmd.cmdsize = sizeof(cmd);
strcpy(cmd.segname, "__PAGEZERO");
cmd.vmsize = 0x100000000;
}
} // namespace mold::macho

15
test/macho/dump.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
set -e
cd $(dirname $0)
mold=`pwd`/../../ld64.mold
echo -n "Testing $(basename -s .sh $0) ... "
t=$(pwd)/../../out/test/elf/$(basename -s .sh $0)
mkdir -p $t
$mold -out $t/exe
$mold -dump $t/exe > $t/log
grep -q 'magic: 0xfeedfacf' $t/log
grep -q 'segname: __PAGEZERO' $t/log
echo OK