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:
parent
631412844c
commit
3b47e90274
@ -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);
|
||||
|
35
macho/mold.h
35
macho/mold.h
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user