1
1
mirror of https://github.com/rui314/mold.git synced 2024-11-14 07:18:42 +03:00

[Mach-O] wip

This commit is contained in:
Rui Ueyama 2021-11-01 13:39:07 +09:00
parent ec5c85dcc7
commit 3c297c2254
4 changed files with 128 additions and 81 deletions

View File

@ -32,6 +32,54 @@ static void create_internal_file(Context &ctx) {
sym->value = PAGE_ZERO_SIZE;
}
static bool compare_chunks(const Chunk *a, const Chunk *b) {
assert(a->hdr.get_segname() == b->hdr.get_segname());
if ((a->hdr.type == S_ZEROFILL) != (b->hdr.type == S_ZEROFILL))
return a->hdr.type != S_ZEROFILL;
static const std::string_view rank[] = {
// __TEXT
"__mach_header",
"__text",
"__stubs",
"__stub_helper",
"__cstring",
"__unwind_info",
// __DATA_CONST
"__got",
// __DATA
"__la_symbol_ptr"
"__data",
"__common",
"__bss",
// __LINKEDIT
"__rebase",
"__binding",
"__lazy_binding",
"__export",
"__func_starts",
"__symbol_table",
"__ind_sym_tab",
"__string_table",
};
auto get_rank = [](const Chunk *chunk) -> i64 {
std::string_view name = chunk->hdr.get_sectname();
i64 i = 0;
for (; i < sizeof(rank) / sizeof(rank[0]); i++)
if (name == rank[i])
return i;
return INT_MAX;
};
i64 ra = get_rank(a);
i64 rb = get_rank(b);
if (ra == INT_MAX && rb == INT_MAX)
return a->hdr.get_sectname() < b->hdr.get_sectname();
return ra < rb;
}
static void create_synthetic_chunks(Context &ctx) {
for (ObjectFile *obj : ctx.objs) {
for (std::unique_ptr<InputSection> &isec : obj->sections) {
@ -41,31 +89,18 @@ static void create_synthetic_chunks(Context &ctx) {
}
}
ctx.text_seg->chunks.push_back(&ctx.mach_hdr);
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);
for (Chunk *chunk : ctx.chunks) {
if (chunk != ctx.data && chunk->is_regular &&
((OutputSection *)chunk)->members.empty())
continue;
ctx.data_const_seg->chunks.push_back(&ctx.got);
OutputSegment *seg =
OutputSegment::get_instance(ctx, chunk->hdr.get_segname());
seg->chunks.push_back(chunk);
}
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);
if (!ctx.bss->members.empty())
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);
for (std::unique_ptr<OutputSegment> &seg : ctx.segments)
sort(seg->chunks, compare_chunks);
}
static void export_symbols(Context &ctx) {

View File

@ -211,11 +211,7 @@ private:
class Chunk {
public:
Chunk(std::string_view segname, std::string_view sectname) {
hdr.set_segname(segname);
hdr.set_sectname(sectname);
}
inline Chunk(Context &ctx, std::string_view segname, std::string_view sectname);
virtual ~Chunk() = default;
virtual void compute_size(Context &ctx) {};
virtual void copy_buf(Context &ctx) {}
@ -226,9 +222,11 @@ public:
bool is_regular = false;
};
std::ostream &operator<<(std::ostream &out, const Chunk &chunk);
class OutputMachHeader : public Chunk {
public:
OutputMachHeader() : Chunk("__TEXT", "__mach_header") {
OutputMachHeader(Context &ctx) : Chunk(ctx, "__TEXT", "__mach_header") {
is_hidden = true;
}
@ -241,8 +239,8 @@ public:
static OutputSection *
get_instance(Context &ctx, std::string_view segname, std::string_view sectname);
OutputSection(std::string_view segname, std::string_view sectname)
: Chunk(segname, sectname) {
OutputSection(Context &ctx, std::string_view segname, std::string_view sectname)
: Chunk(ctx, segname, sectname) {
is_regular = true;
}
@ -274,7 +272,8 @@ private:
class OutputRebaseSection : public Chunk {
public:
OutputRebaseSection() : Chunk("__LINKEDIT", "__rebase") {
OutputRebaseSection(Context &ctx)
: Chunk(ctx, "__LINKEDIT", "__rebase") {
is_hidden = true;
}
@ -303,7 +302,8 @@ private:
class OutputBindSection : public Chunk {
public:
OutputBindSection() : Chunk("__LINKEDIT", "__binding") {
OutputBindSection(Context &ctx)
: Chunk(ctx, "__LINKEDIT", "__binding") {
is_hidden = true;
}
@ -315,7 +315,8 @@ public:
class OutputLazyBindSection : public Chunk {
public:
OutputLazyBindSection() : Chunk("__LINKEDIT", "__lazy_binding") {
OutputLazyBindSection(Context &ctx)
: Chunk(ctx, "__LINKEDIT", "__lazy_binding") {
is_hidden = true;
}
@ -363,7 +364,8 @@ private:
class OutputExportSection : public Chunk {
public:
OutputExportSection() : Chunk("__LINKEDIT", "__export") {
OutputExportSection(Context &ctx)
: Chunk(ctx, "__LINKEDIT", "__export") {
is_hidden = true;
}
@ -376,7 +378,8 @@ private:
class OutputFunctionStartsSection : public Chunk {
public:
OutputFunctionStartsSection() : Chunk("__LINKEDIT", "__func_starts") {
OutputFunctionStartsSection(Context &ctx)
: Chunk(ctx, "__LINKEDIT", "__func_starts") {
is_hidden = true;
}
@ -388,7 +391,8 @@ public:
class OutputSymtabSection : public Chunk {
public:
OutputSymtabSection() : Chunk("__LINKEDIT", "__symbol_table") {
OutputSymtabSection(Context &ctx)
: Chunk(ctx, "__LINKEDIT", "__symbol_table") {
is_hidden = true;
hdr.p2align = __builtin_ctz(8);
}
@ -408,7 +412,8 @@ public:
class OutputStrtabSection : public Chunk {
public:
OutputStrtabSection() : Chunk("__LINKEDIT", "__string_table") {
OutputStrtabSection(Context &ctx)
: Chunk(ctx, "__LINKEDIT", "__string_table") {
is_hidden = true;
hdr.p2align = __builtin_ctz(8);
}
@ -422,7 +427,8 @@ public:
class OutputIndirectSymtabSection : public Chunk {
public:
OutputIndirectSymtabSection() : Chunk("__LINKEDIT", "__ind_sym_tab") {
OutputIndirectSymtabSection(Context &ctx)
: Chunk(ctx, "__LINKEDIT", "__ind_sym_tab") {
is_hidden = true;
}
@ -442,8 +448,7 @@ public:
class StubsSection : public Chunk {
public:
StubsSection();
StubsSection(Context &ctx);
void add(Context &ctx, Symbol *sym);
void copy_buf(Context &ctx) override;
@ -455,7 +460,7 @@ public:
class StubHelperSection : public Chunk {
public:
StubHelperSection();
StubHelperSection(Context &ctx);
void copy_buf(Context &ctx) override;
static constexpr i64 HEADER_SIZE = 16;
@ -479,7 +484,7 @@ private:
class UnwindInfoSection : public Chunk {
public:
UnwindInfoSection();
UnwindInfoSection(Context &ctx);
void compute_size(Context &ctx) override;
void copy_buf(Context &ctx) override;
@ -488,7 +493,7 @@ public:
class GotSection : public Chunk {
public:
GotSection();
GotSection(Context &ctx);
void add(Context &ctx, Symbol *sym);
void copy_buf(Context &ctx) override;
@ -499,7 +504,7 @@ public:
class LazySymbolPtrSection : public Chunk {
public:
LazySymbolPtrSection();
LazySymbolPtrSection(Context &ctx);
void copy_buf(Context &ctx) override;
static constexpr i64 ENTRY_SIZE = 8;
@ -657,23 +662,23 @@ struct Context {
OutputSegment *linkedit_seg = nullptr;
std::vector<std::unique_ptr<OutputSegment>> segments;
std::vector<std::unique_ptr<Chunk>> chunks;
std::vector<Chunk *> chunks;
OutputMachHeader mach_hdr;
StubsSection stubs;
StubHelperSection stub_helper;
UnwindInfoSection unwind_info;
GotSection got;
LazySymbolPtrSection lazy_symbol_ptr;
OutputMachHeader mach_hdr{*this};
StubsSection stubs{*this};
StubHelperSection stub_helper{*this};
UnwindInfoSection unwind_info{*this};
GotSection got{*this};
LazySymbolPtrSection lazy_symbol_ptr{*this};
OutputRebaseSection rebase;
OutputBindSection bind;
OutputLazyBindSection lazy_bind;
OutputExportSection export_;
OutputFunctionStartsSection function_starts;
OutputSymtabSection symtab;
OutputIndirectSymtabSection indir_symtab;
OutputStrtabSection strtab;
OutputRebaseSection rebase{*this};
OutputBindSection bind{*this};
OutputLazyBindSection lazy_bind{*this};
OutputExportSection export_{*this};
OutputFunctionStartsSection function_starts{*this};
OutputSymtabSection symtab{*this};
OutputIndirectSymtabSection indir_symtab{*this};
OutputStrtabSection strtab{*this};
OutputSection *text = nullptr;
OutputSection *data = nullptr;
@ -688,10 +693,6 @@ int main(int argc, char **argv);
// Inline functions
//
u64 UnwindRecord::get_func_addr(Context &ctx) const {
return subsec->addr + offset;
}
u64 Symbol::get_addr(Context &ctx) const {
if (subsec)
return subsec->addr + value;
@ -716,4 +717,14 @@ inline std::ostream &operator<<(std::ostream &out, const Symbol &sym) {
return out;
}
Chunk::Chunk(Context &ctx, std::string_view segname, std::string_view sectname) {
ctx.chunks.push_back(this);
hdr.set_segname(segname);
hdr.set_sectname(sectname);
}
u64 UnwindRecord::get_func_addr(Context &ctx) const {
return subsec->addr + offset;
}
} // namespace mold::macho

View File

@ -4,6 +4,11 @@
namespace mold::macho {
std::ostream &operator<<(std::ostream &out, const Chunk &chunk) {
out << chunk.hdr.get_segname() << "," << chunk.hdr.get_sectname();
return out;
}
static std::vector<u8> create_page_zero_cmd(Context &ctx) {
std::vector<u8> buf(sizeof(SegmentCommand));
SegmentCommand &cmd = *(SegmentCommand *)buf.data();
@ -245,12 +250,12 @@ OutputSection::get_instance(Context &ctx, std::string_view segname,
static std::shared_mutex mu;
auto find = [&]() -> OutputSection * {
for (std::unique_ptr<Chunk> &chunk : ctx.chunks) {
for (Chunk *chunk : ctx.chunks) {
if (chunk->hdr.get_segname() == segname &&
chunk->hdr.get_sectname() == sectname) {
if (!chunk->is_regular)
Fatal(ctx) << ": reserved name is used: " << segname << "," << sectname;
return (OutputSection *)chunk.get();
return (OutputSection *)chunk;
}
}
return nullptr;
@ -266,9 +271,7 @@ OutputSection::get_instance(Context &ctx, std::string_view segname,
if (OutputSection *osec = find())
return osec;
OutputSection *osec = new OutputSection(segname, sectname);
ctx.chunks.push_back(std::unique_ptr<Chunk>(osec));
return osec;
return new OutputSection(ctx, segname, sectname);
}
void OutputSection::compute_size(Context &ctx) {
@ -794,8 +797,8 @@ void OutputIndirectSymtabSection::copy_buf(Context &ctx) {
buf[ent.sym->stub_idx] = ent.symtab_idx;
}
StubsSection::StubsSection() : Chunk("__LINKEDIT", "__stubs") {
hdr.set_sectname("__stubs");
StubsSection::StubsSection(Context &ctx)
: Chunk(ctx, "__TEXT", "__stubs") {
hdr.p2align = __builtin_ctz(2);
hdr.type = S_SYMBOL_STUBS;
hdr.attr = S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
@ -832,8 +835,8 @@ void StubsSection::copy_buf(Context &ctx) {
}
}
StubHelperSection::StubHelperSection() : Chunk("__LINKEDIT", "__stub_helper") {
hdr.set_sectname("__stub_helper");
StubHelperSection::StubHelperSection(Context &ctx)
: Chunk(ctx, "__TEXT", "__stub_helper") {
hdr.p2align = __builtin_ctz(4);
hdr.attr = S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
}
@ -870,8 +873,8 @@ void StubHelperSection::copy_buf(Context &ctx) {
}
}
UnwindInfoSection::UnwindInfoSection() : Chunk("__LINKEDIT", "__unwind_info") {
hdr.set_sectname("__unwind_info");
UnwindInfoSection::UnwindInfoSection(Context &ctx)
: Chunk(ctx, "__TEXT", "__unwind_info") {
hdr.p2align = __builtin_ctz(4);
hdr.size = contents.size();
}
@ -1024,8 +1027,7 @@ void UnwindInfoSection::copy_buf(Context &ctx) {
write_vector(ctx.buf + hdr.offset, contents);
}
GotSection::GotSection() : Chunk("__LINKEDIT", "__got") {
hdr.set_sectname("__got");
GotSection::GotSection(Context &ctx) : Chunk(ctx, "__DATA_CONST", "__got") {
hdr.p2align = __builtin_ctz(8);
hdr.type = S_NON_LAZY_SYMBOL_POINTERS;
}
@ -1044,9 +1046,8 @@ void GotSection::copy_buf(Context &ctx) {
buf[i] = syms[i]->get_addr(ctx);
}
LazySymbolPtrSection::LazySymbolPtrSection()
: Chunk("__LINKEDIT", "__la_symbol_ptr") {
hdr.set_sectname("__la_symbol_ptr");
LazySymbolPtrSection::LazySymbolPtrSection(Context &ctx)
: Chunk(ctx, "__DATA", "__la_symbol_ptr") {
hdr.p2align = __builtin_ctz(8);
hdr.type = S_LAZY_SYMBOL_POINTERS;
}

View File

@ -29,7 +29,7 @@ int main() {
}
EOF
clang++ -fuse-ld=$mold -o $t/exe $t/c.o $t/c.a
clang++ -fuse-ld=$mold -o $t/exe $t/d.o $t/c.a
$t/exe | grep -q 'Hello world'
otool -tv $t/exe | grep -q '^_hello:'