1
1
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:
Rui Ueyama 2022-12-06 16:46:32 +08:00
parent 73f32940ab
commit 0f36a40a44
6 changed files with 156 additions and 0 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
*.o
*.so
*~
**/.DS_Store
.cache
compile_commands.json
/mold

View File

@ -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) {

View File

@ -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:

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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>;