mirror of
https://github.com/rui314/mold.git
synced 2024-09-11 13:06:59 +03:00
[Mach-O] Create __objc_{methname,selrefs,stubs} sections
Recent versions of Xcode started creating `_objc_msgSend$foo` symbols, and we need to synthesize the symbols and place them into `__objc_stubs` section.
This commit is contained in:
parent
73f32940ab
commit
0f36a40a44
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
*.o
|
||||
*.so
|
||||
*~
|
||||
**/.DS_Store
|
||||
.cache
|
||||
compile_commands.json
|
||||
/mold
|
||||
|
@ -82,6 +82,38 @@ void StubHelperSection<E>::copy_buf(Context<E> &ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void ObjcStubsSection<E>::copy_buf(Context<E> &ctx) {
|
||||
if (this->hdr.size == 0)
|
||||
return;
|
||||
|
||||
static const ul32 insn[] = {
|
||||
0x90000001, // adrp x1, @selector("foo")@PAGE
|
||||
0xf9400021, // ldr x1, [x1, @selector("foo")@PAGEOFF]
|
||||
0x90000010, // adrp x16, _objc_msgSend@GOTPAGE
|
||||
0xf9400210, // ldr x16, [x16, _objc_msgSend@GOTPAGEOFF]
|
||||
0xd61f0200, // br x16
|
||||
0xd4200020, // brk #0x1
|
||||
0xd4200020, // brk #0x1
|
||||
0xd4200020, // brk #0x1
|
||||
};
|
||||
static_assert(sizeof(insn) == ENTRY_SIZE);
|
||||
|
||||
u64 msgsend_got_addr = get_symbol(ctx, "_objc_msgSend")->get_got_addr(ctx);
|
||||
|
||||
for (i64 i = 0; i < symbols.size(); i++) {
|
||||
ul32 *buf = (ul32 *)(ctx.buf + this->hdr.offset + sizeof(insn) * i);
|
||||
u64 sel_addr = ctx.objc_selrefs.hdr.addr + word_size * i;
|
||||
u64 ent_addr = this->hdr.addr + sizeof(insn) * i;
|
||||
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
buf[0] |= page_offset(sel_addr, ent_addr);
|
||||
buf[1] |= bits(sel_addr, 11, 3) << 10;
|
||||
buf[2] |= page_offset(msgsend_got_addr, ent_addr + 8);
|
||||
buf[3] |= bits(msgsend_got_addr, 11, 3) << 10;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
std::vector<Relocation<E>>
|
||||
read_relocations(Context<E> &ctx, ObjectFile<E> &file, const MachSection &hdr) {
|
||||
|
@ -57,6 +57,9 @@ void StubHelperSection<E>::copy_buf(Context<E> &ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void ObjcStubsSection<E>::copy_buf(Context<E> &ctx) {}
|
||||
|
||||
static i64 get_reloc_addend(u32 type) {
|
||||
switch (type) {
|
||||
case X86_64_RELOC_SIGNED_1:
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#include <tbb/global_control.h>
|
||||
#include <tbb/parallel_for_each.h>
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/mman.h>
|
||||
@ -294,6 +295,9 @@ static void claim_unresolved_symbols(Context<E> &ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Symbol<E> *> syms;
|
||||
std::mutex mu;
|
||||
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
|
||||
for (i64 i = 0; i < file->mach_syms.size(); i++) {
|
||||
MachSym &msym = file->mach_syms[i];
|
||||
@ -313,9 +317,35 @@ static void claim_unresolved_symbols(Context<E> &ctx) {
|
||||
sym.value = 0;
|
||||
sym.is_common = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sym.file && sym.name.starts_with("_objc_msgSend$")) {
|
||||
sym.file = ctx.internal_obj;
|
||||
std::scoped_lock lock(mu);
|
||||
syms.push_back(&sym);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// We synthesize `_objc_msgSend$foo` in the `__objc_stubs` section
|
||||
// if such symbol is missing.
|
||||
if (!syms.empty()) {
|
||||
tbb::parallel_sort(syms.begin(), syms.end(), [](Symbol<E> *a, Symbol<E> *b) {
|
||||
return a->name < b->name;
|
||||
});
|
||||
|
||||
for (Symbol<E> *sym : syms) {
|
||||
ctx.internal_obj->syms.push_back(sym);
|
||||
ctx.objc_stubs.add(ctx, sym);
|
||||
}
|
||||
|
||||
Symbol<E> *sym = get_symbol(ctx, "_objc_msgSend");
|
||||
if (!sym->file)
|
||||
Error(ctx) << "undefined symbol: _objc_msgSend";
|
||||
if (sym->is_imported)
|
||||
sym->flags |= NEEDS_GOT;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
@ -592,6 +622,8 @@ static void fix_synthetic_symbol_values(Context<E> &ctx) {
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
i64 objc_stubs_offset = 0;
|
||||
|
||||
for (Symbol<E> *sym : ctx.internal_obj->syms) {
|
||||
std::string_view name = sym->name;
|
||||
|
||||
@ -620,6 +652,13 @@ static void fix_synthetic_symbol_values(Context<E> &ctx) {
|
||||
sym->value = ctx.text->hdr.addr;
|
||||
if (MachSection *hdr = find_section(name))
|
||||
sym->value = hdr->addr + hdr->size;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name.starts_with("_objc_msgSend$")) {
|
||||
sym->value = ctx.objc_stubs.hdr.addr + objc_stubs_offset;
|
||||
objc_stubs_offset += ObjcStubsSection<E>::ENTRY_SIZE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
45
macho/mold.h
45
macho/mold.h
@ -605,6 +605,48 @@ private:
|
||||
ObjcImageInfo contents;
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
class ObjcStubsSection : public Chunk<E> {
|
||||
public:
|
||||
ObjcStubsSection(Context<E> &ctx)
|
||||
: Chunk<E>(ctx, "__TEXT", "__objc_stubs") {
|
||||
this->hdr.p2align = 5;
|
||||
this->hdr.attr = S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
|
||||
}
|
||||
|
||||
void add(Context<E> &ctx, Symbol<E> *sym);
|
||||
void copy_buf(Context<E> &ctx) override;
|
||||
|
||||
std::vector<Symbol<E> *> symbols;
|
||||
|
||||
static constexpr i64 ENTRY_SIZE = std::is_same_v<E, ARM64> ? 32 : 16;
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
class ObjcSelrefsSection : public Chunk<E> {
|
||||
public:
|
||||
ObjcSelrefsSection(Context<E> &ctx)
|
||||
: Chunk<E>(ctx, "__DATA", "__objc_selrefs") {
|
||||
this->hdr.p2align = 3;
|
||||
this->hdr.type = S_LITERAL_POINTERS;
|
||||
this->hdr.attr = S_ATTR_NO_DEAD_STRIP;
|
||||
}
|
||||
|
||||
void copy_buf(Context<E> &ctx) override;
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
class ObjcMethnameSection : public Chunk<E> {
|
||||
public:
|
||||
ObjcMethnameSection(Context<E> &ctx)
|
||||
: Chunk<E>(ctx, "__TEXT", "__objc_methname") {
|
||||
this->hdr.p2align = 0;
|
||||
this->hdr.type = S_CSTRING_LITERALS;
|
||||
}
|
||||
|
||||
void copy_buf(Context<E> &ctx) override;
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
class CodeSignatureSection : public Chunk<E> {
|
||||
public:
|
||||
@ -969,6 +1011,9 @@ struct Context {
|
||||
ExportSection<E> export_{*this};
|
||||
SymtabSection<E> symtab{*this};
|
||||
StrtabSection<E> strtab{*this};
|
||||
ObjcStubsSection<E> objc_stubs{*this};
|
||||
ObjcSelrefsSection<E> objc_selrefs{*this};
|
||||
ObjcMethnameSection<E> objc_methname{*this};
|
||||
|
||||
std::unique_ptr<FunctionStartsSection<E>> function_starts;
|
||||
std::unique_ptr<ObjcImageInfoSection<E>> image_info;
|
||||
|
@ -660,6 +660,10 @@ inline void RebaseSection<E>::compute_size(Context<E> &ctx) {
|
||||
enc.add(ctx.data_seg->seg_idx,
|
||||
sym->get_tlv_addr(ctx) - ctx.data_seg->cmd.vmaddr);
|
||||
|
||||
for (i64 i = 0; i < ctx.objc_stubs.symbols.size(); i++)
|
||||
enc.add(ctx.text_seg->seg_idx,
|
||||
ctx.objc_selrefs.hdr.addr + i * word_size - ctx.text_seg->cmd.vmaddr);
|
||||
|
||||
auto refers_tls = [](Symbol<E> *sym) {
|
||||
if (sym && sym->subsec) {
|
||||
auto ty = sym->subsec->isec.osec.hdr.type;
|
||||
@ -1246,6 +1250,35 @@ void ObjcImageInfoSection<E>::copy_buf(Context<E> &ctx) {
|
||||
memcpy(ctx.buf + this->hdr.offset, &contents, sizeof(contents));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ObjcStubsSection<E>::add(Context<E> &ctx, Symbol<E> *sym) {
|
||||
symbols.push_back(sym);
|
||||
this->hdr.size = symbols.size() * ENTRY_SIZE;
|
||||
|
||||
ctx.objc_selrefs.hdr.size += word_size;
|
||||
|
||||
assert(sym->name.starts_with("_objc_msgSend$"));
|
||||
ctx.objc_methname.hdr.size += sym->name.size() + 1 - strlen("_objc_msgSend$");
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ObjcSelrefsSection<E>::copy_buf(Context<E> &ctx) {
|
||||
ul64 *buf = (ul64 *)(ctx.buf + this->hdr.offset);
|
||||
u64 addr = ctx.objc_methname.hdr.addr;
|
||||
|
||||
for (Symbol<E> *sym : ctx.objc_stubs.symbols) {
|
||||
*buf++ = addr;
|
||||
addr += sym->name.size() + 1 - strlen("_objc_msgSend$");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ObjcMethnameSection<E>::copy_buf(Context<E> &ctx) {
|
||||
u8 *buf = ctx.buf + this->hdr.offset;
|
||||
for (Symbol<E> *sym : ctx.objc_stubs.symbols)
|
||||
buf += write_string(buf, sym->name.substr("_objc_msgSend$"s.size()));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void CodeSignatureSection<E>::compute_size(Context<E> &ctx) {
|
||||
std::string filename = filepath(ctx.arg.final_output).filename().string();
|
||||
@ -1653,6 +1686,9 @@ template class ExportSection<E>;
|
||||
template class FunctionStartsSection<E>;
|
||||
template class SymtabSection<E>;
|
||||
template class StrtabSection<E>;
|
||||
template class ObjcStubsSection<E>;
|
||||
template class ObjcSelrefsSection<E>;
|
||||
template class ObjcMethnameSection<E>;
|
||||
template class CodeSignatureSection<E>;
|
||||
template class ObjcImageInfoSection<E>;
|
||||
template class DataInCodeSection<E>;
|
||||
|
Loading…
Reference in New Issue
Block a user