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

[Mach-O] wip

This commit is contained in:
Rui Ueyama 2021-10-30 15:16:55 +09:00
parent 631412844c
commit 3b47e90274
3 changed files with 89 additions and 55 deletions

View File

@ -43,38 +43,33 @@ static void create_synthetic_chunks(Context &ctx) {
ctx.headerpad.hdr.size = ctx.arg.headerpad;
ctx.segments.push_back(&ctx.text_seg);
ctx.segments.push_back(&ctx.data_const_seg);
ctx.segments.push_back(&ctx.data_seg);
ctx.segments.push_back(&ctx.linkedit_seg);
ctx.text_seg->chunks.push_back(&ctx.mach_hdr);
ctx.text_seg->chunks.push_back(&ctx.load_cmd);
ctx.text_seg->chunks.push_back(&ctx.headerpad);
ctx.text_seg->chunks.push_back(ctx.text);
ctx.text_seg->chunks.push_back(&ctx.stubs);
ctx.text_seg->chunks.push_back(&ctx.stub_helper);
ctx.text_seg->chunks.push_back(ctx.cstring);
ctx.text_seg->chunks.push_back(&ctx.unwind_info);
ctx.text_seg.chunks.push_back(&ctx.mach_hdr);
ctx.text_seg.chunks.push_back(&ctx.load_cmd);
ctx.text_seg.chunks.push_back(&ctx.headerpad);
ctx.text_seg.chunks.push_back(ctx.text);
ctx.text_seg.chunks.push_back(&ctx.stubs);
ctx.text_seg.chunks.push_back(&ctx.stub_helper);
ctx.text_seg.chunks.push_back(ctx.cstring);
ctx.text_seg.chunks.push_back(&ctx.unwind_info);
ctx.data_const_seg->chunks.push_back(&ctx.got);
ctx.data_const_seg.chunks.push_back(&ctx.got);
ctx.data_seg.chunks.push_back(&ctx.lazy_symbol_ptr);
ctx.data_seg.chunks.push_back(ctx.data);
ctx.data_seg->chunks.push_back(&ctx.lazy_symbol_ptr);
ctx.data_seg->chunks.push_back(ctx.data);
if (!ctx.common->members.empty())
ctx.data_seg.chunks.push_back(ctx.common);
ctx.data_seg->chunks.push_back(ctx.common);
if (!ctx.bss->members.empty())
ctx.data_seg.chunks.push_back(ctx.bss);
ctx.data_seg->chunks.push_back(ctx.bss);
ctx.linkedit_seg.chunks.push_back(&ctx.rebase);
ctx.linkedit_seg.chunks.push_back(&ctx.bind);
ctx.linkedit_seg.chunks.push_back(&ctx.lazy_bind);
ctx.linkedit_seg.chunks.push_back(&ctx.export_);
ctx.linkedit_seg.chunks.push_back(&ctx.function_starts);
ctx.linkedit_seg.chunks.push_back(&ctx.symtab);
ctx.linkedit_seg.chunks.push_back(&ctx.indir_symtab);
ctx.linkedit_seg.chunks.push_back(&ctx.strtab);
ctx.linkedit_seg->chunks.push_back(&ctx.rebase);
ctx.linkedit_seg->chunks.push_back(&ctx.bind);
ctx.linkedit_seg->chunks.push_back(&ctx.lazy_bind);
ctx.linkedit_seg->chunks.push_back(&ctx.export_);
ctx.linkedit_seg->chunks.push_back(&ctx.function_starts);
ctx.linkedit_seg->chunks.push_back(&ctx.symtab);
ctx.linkedit_seg->chunks.push_back(&ctx.indir_symtab);
ctx.linkedit_seg->chunks.push_back(&ctx.strtab);
}
static void export_symbols(Context &ctx) {
@ -98,7 +93,7 @@ static void export_symbols(Context &ctx) {
static i64 assign_offsets(Context &ctx) {
i64 sect_idx = 1;
for (OutputSegment *seg : ctx.segments)
for (std::unique_ptr<OutputSegment> &seg : ctx.segments)
for (Chunk *chunk : seg->chunks)
if (!chunk->is_hidden)
chunk->sect_idx = sect_idx++;
@ -106,7 +101,7 @@ static i64 assign_offsets(Context &ctx) {
i64 fileoff = 0;
i64 vmaddr = PAGE_ZERO_SIZE;
for (OutputSegment *seg : ctx.segments) {
for (std::unique_ptr<OutputSegment> &seg : ctx.segments) {
seg->set_offset(ctx, fileoff, vmaddr);
fileoff += seg->cmd.filesize;
vmaddr += seg->cmd.vmsize;
@ -230,7 +225,7 @@ int main(int argc, char **argv) {
ctx.output_file = OutputFile::open(ctx, ctx.arg.output, output_size, 0777);
ctx.buf = ctx.output_file->buf;
for (OutputSegment *seg : ctx.segments)
for (std::unique_ptr<OutputSegment> &seg : ctx.segments)
seg->copy_buf(ctx);
ctx.output_file->close(ctx);

View File

@ -196,7 +196,7 @@ std::ostream &operator<<(std::ostream &out, const Symbol &sym);
class OutputSegment {
public:
OutputSegment(std::string_view name, u32 prot, u32 flags);
static OutputSegment *get_instance(Context &ctx, std::string_view name);
void set_offset(Context &ctx, i64 fileoff, u64 vmaddr);
void copy_buf(Context &ctx);
@ -204,6 +204,9 @@ public:
SegmentCommand cmd = {};
i32 seg_idx = -1;
std::vector<Chunk *> chunks;
private:
OutputSegment(std::string_view name);
};
class Chunk {
@ -591,6 +594,22 @@ void parse_nonpositional_args(Context &ctx,
struct Context {
Context() {
text_seg = OutputSegment::get_instance(*this, "__TEXT");
data_const_seg = OutputSegment::get_instance(*this, "__DATA_CONST");
data_seg = OutputSegment::get_instance(*this, "__DATA");
linkedit_seg = OutputSegment::get_instance(*this, "__LINKEDIT");
auto set = [](OutputSegment &seg, u32 prot, u32 flags) {
seg.cmd.initprot = prot;
seg.cmd.maxprot = prot;
seg.cmd.flags = flags;
};
set(*text_seg, VM_PROT_READ | VM_PROT_EXECUTE, 0);
set(*data_const_seg, VM_PROT_READ | VM_PROT_WRITE, SG_READ_ONLY);
set(*data_seg, VM_PROT_READ | VM_PROT_WRITE, 0);
set(*linkedit_seg, VM_PROT_READ, 0);
text = OutputSection::get_instance(*this, "__TEXT", "__text");
data = OutputSection::get_instance(*this, "__DATA", "__data");
bss = OutputSection::get_instance(*this, "__DATA", "__bss");
@ -646,13 +665,13 @@ struct Context {
std::vector<ObjectFile *> objs;
std::vector<DylibFile *> dylibs;
OutputSegment text_seg{"__TEXT", VM_PROT_READ | VM_PROT_EXECUTE, 0};
OutputSegment data_const_seg{"__DATA_CONST", VM_PROT_READ | VM_PROT_WRITE,
SG_READ_ONLY};
OutputSegment data_seg{"__DATA", VM_PROT_READ | VM_PROT_WRITE, 0};
OutputSegment linkedit_seg{"__LINKEDIT", VM_PROT_READ, 0};
OutputSegment *text_seg = nullptr;
OutputSegment *data_const_seg = nullptr;
OutputSegment *data_seg = nullptr;
OutputSegment *linkedit_seg = nullptr;
std::vector<std::unique_ptr<OutputSection>> output_sections;
std::vector<std::unique_ptr<OutputSegment>> segments;
std::vector<std::unique_ptr<OutputSection>> sections;
OutputMachHeader mach_hdr;
StubsSection stubs;
@ -677,8 +696,6 @@ struct Context {
OutputSection *bss = nullptr;
OutputSection *cstring = nullptr;
OutputSection *common = nullptr;
std::vector<OutputSegment *> segments;
};
int main(int argc, char **argv);

View File

@ -191,7 +191,7 @@ static std::vector<std::vector<u8>> create_load_commands(Context &ctx) {
};
// Add LC_SEGMENT_64 comamnds
for (OutputSegment *seg : ctx.segments) {
for (std::unique_ptr<OutputSegment> &seg : ctx.segments) {
std::vector<u8> &buf = vec.emplace_back();
i64 nsects = 0;
@ -244,7 +244,7 @@ OutputSection::get_instance(Context &ctx, std::string_view segname,
static std::shared_mutex mu;
auto find = [&]() -> OutputSection *{
for (std::unique_ptr<OutputSection> &osec : ctx.output_sections)
for (std::unique_ptr<OutputSection> &osec : ctx.sections)
if (osec->hdr.get_segname() == segname &&
osec->hdr.get_sectname() == sectname)
return osec.get();
@ -262,7 +262,7 @@ OutputSection::get_instance(Context &ctx, std::string_view segname,
return osec;
OutputSection *osec = new OutputSection(segname, sectname);
ctx.output_sections.push_back(std::unique_ptr<OutputSection>(osec));
ctx.sections.push_back(std::unique_ptr<OutputSection>(osec));
return osec;
}
@ -300,12 +300,34 @@ void OutputSection::copy_buf(Context &ctx) {
}
}
OutputSegment::OutputSegment(std::string_view name, u32 prot, u32 flags) {
OutputSegment *OutputSegment::get_instance(Context &ctx, std::string_view name) {
static std::shared_mutex mu;
auto find = [&]() -> OutputSegment *{
for (std::unique_ptr<OutputSegment> &seg : ctx.segments)
if (seg->cmd.get_segname() == name)
return seg.get();
return nullptr;
};
{
std::shared_lock lock(mu);
if (OutputSegment *seg = find())
return seg;
}
std::unique_lock lock(mu);
if (OutputSegment *seg = find())
return seg;
OutputSegment *seg = new OutputSegment(name);
ctx.segments.push_back(std::unique_ptr<OutputSegment>(seg));
return seg;
}
OutputSegment::OutputSegment(std::string_view name) {
cmd.cmd = LC_SEGMENT_64;
memcpy(cmd.segname, name.data(), name.size());
cmd.maxprot = prot;
cmd.initprot = prot;
cmd.flags = flags;
}
void OutputSegment::set_offset(Context &ctx, i64 fileoff, u64 vmaddr) {
@ -338,7 +360,7 @@ void OutputSegment::set_offset(Context &ctx, i64 fileoff, u64 vmaddr) {
cmd.vmsize = align_to(vmaddr - cmd.vmaddr, PAGE_SIZE);
if (this == ctx.segments.back())
if (this == ctx.segments.back().get())
cmd.filesize = fileoff - cmd.fileoff;
else
cmd.filesize = align_to(fileoff - cmd.fileoff, PAGE_SIZE);
@ -410,14 +432,14 @@ void OutputRebaseSection::compute_size(Context &ctx) {
RebaseEncoder enc;
for (i64 i = 0; i < ctx.stubs.syms.size(); i++)
enc.add(ctx.data_seg.seg_idx,
enc.add(ctx.data_seg->seg_idx,
ctx.lazy_symbol_ptr.hdr.addr + i * LazySymbolPtrSection::ENTRY_SIZE -
ctx.data_seg.cmd.vmaddr);
ctx.data_seg->cmd.vmaddr);
for (Symbol *sym : ctx.got.syms)
if (!sym->file->is_dylib)
enc.add(ctx.data_const_seg.seg_idx,
sym->get_got_addr(ctx) - ctx.data_const_seg.cmd.vmaddr);
enc.add(ctx.data_const_seg->seg_idx,
sym->get_got_addr(ctx) - ctx.data_const_seg->cmd.vmaddr);
enc.finish();
contents = enc.buf;
@ -475,8 +497,8 @@ void OutputBindSection::compute_size(Context &ctx) {
for (Symbol *sym : ctx.got.syms)
if (sym->file->is_dylib)
enc.add(((DylibFile *)sym->file)->dylib_idx, sym->name, 0,
ctx.data_const_seg.seg_idx,
sym->get_got_addr(ctx) - ctx.data_const_seg.cmd.vmaddr);
ctx.data_const_seg->seg_idx,
sym->get_got_addr(ctx) - ctx.data_const_seg->cmd.vmaddr);
enc.finish();
@ -507,12 +529,12 @@ void OutputLazyBindSection::add(Context &ctx, Symbol &sym, i64 flags) {
(u8 *)(sym.name.data() + sym.name.size()));
emit('\0');
i64 seg_idx = ctx.data_seg.seg_idx;
i64 seg_idx = ctx.data_seg->seg_idx;
emit(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | seg_idx);
i64 offset = ctx.lazy_symbol_ptr.hdr.addr +
sym.stub_idx * LazySymbolPtrSection::ENTRY_SIZE -
ctx.data_seg.cmd.vmaddr;
ctx.data_seg->cmd.vmaddr;
encode_uleb(contents, offset);
emit(BIND_OPCODE_DO_BIND);
@ -983,7 +1005,7 @@ UnwindEncoder::split_records(Context &ctx) {
static std::vector<u8> construct_unwind_info(Context &ctx) {
UnwindEncoder enc;
for (OutputSegment *seg : ctx.segments)
for (std::unique_ptr<OutputSegment> &seg : ctx.segments)
for (Chunk *chunk : seg->chunks)
if (chunk->is_regular)
for (Subsection *subsec : ((OutputSection *)chunk)->members)