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:
parent
2fedb900d3
commit
5ea876ff2f
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
58
macho/mold.h
58
macho/mold.h
@ -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
52
macho/output-chunks.cc
Normal 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
15
test/macho/dump.sh
Executable 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
|
Loading…
Reference in New Issue
Block a user