Skip to content

Commit

Permalink
Support -fixup_chains
Browse files Browse the repository at this point in the history
  • Loading branch information
rui314 committed Feb 1, 2023
1 parent 8131948 commit 2c87cf8
Show file tree
Hide file tree
Showing 14 changed files with 635 additions and 77 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ if(NOT "${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC")
-fno-asynchronous-unwind-tables
-Wno-sign-compare
-Wno-unused-function
-Wno-bitfield-constant-conversion
-ggnu-pubnames)
endif()

Expand Down
5 changes: 5 additions & 0 deletions common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,12 @@ inline void append(std::vector<T> &vec1, std::vector<U> vec2) {

template <typename T>
inline std::vector<T> flatten(std::vector<std::vector<T>> &vec) {
i64 size = 0;
for (std::vector<T> &v : vec)
size += v.size();

std::vector<T> ret;
ret.reserve(size);
for (std::vector<T> &v : vec)
append(ret, v);
return ret;
Expand Down
5 changes: 3 additions & 2 deletions macho/arch-arm64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void StubsSection<E>::copy_buf(Context<E> &ctx) {
if (syms[i]->has_got())
ptr_addr = syms[i]->get_got_addr(ctx);
else
ptr_addr = ctx.lazy_symbol_ptr.hdr.addr + word_size * j++;
ptr_addr = ctx.lazy_symbol_ptr->hdr.addr + word_size * j++;

memcpy(buf, insn, sizeof(insn));
buf[0] |= page_offset(ptr_addr, this_addr);
Expand Down Expand Up @@ -107,7 +107,7 @@ void StubHelperSection<E>::copy_buf(Context<E> &ctx) {

memcpy(buf, insn, sizeof(insn));
buf[1] |= bits((start - buf - 1) * 4, 27, 2);
buf[2] = ctx.lazy_bind.bind_offsets[i];
buf[2] = ctx.lazy_bind->bind_offsets[i];
buf += 3;
i++;
}
Expand Down Expand Up @@ -187,6 +187,7 @@ read_relocations(Context<E> &ctx, ObjectFile<E> &file, const MachSection &hdr) {
vec.push_back({r.offset, (u8)r.type, (u8)(1 << r.p2size)});

Relocation<E> &rel = vec.back();
rel.is_subtracted = (i > 0 && rels[i - 1].type == ARM64_RELOC_SUBTRACTOR);

// A relocation refers to either a symbol or a section
if (r.is_extern) {
Expand Down
6 changes: 4 additions & 2 deletions macho/arch-x86-64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void StubsSection<E>::copy_buf(Context<E> &ctx) {
if (syms[i]->has_got())
ptr_addr = syms[i]->get_got_addr(ctx);
else
ptr_addr = ctx.lazy_symbol_ptr.hdr.addr + word_size * j++;
ptr_addr = ctx.lazy_symbol_ptr->hdr.addr + word_size * j++;

*(ul32 *)(buf + 2) = ptr_addr - this_addr - 6;
buf += sizeof(insn);
Expand Down Expand Up @@ -63,7 +63,7 @@ void StubHelperSection<E>::copy_buf(Context<E> &ctx) {
static_assert(sizeof(insn) == E::stub_helper_size);

memcpy(buf, insn, sizeof(insn));
*(ul32 *)(buf + 1) = ctx.lazy_bind.bind_offsets[i];
*(ul32 *)(buf + 1) = ctx.lazy_bind->bind_offsets[i];
*(ul32 *)(buf + 6) = start - buf - 10;
buf += sizeof(insn);
i++;
Expand Down Expand Up @@ -129,6 +129,8 @@ read_relocations(Context<E> &ctx, ObjectFile<E> &file,
vec.push_back({r.offset, (u8)r.type, (u8)(1 << r.p2size)});

Relocation<E> &rel = vec.back();
rel.is_subtracted = (i > 0 && rels[i - 1].type == X86_64_RELOC_SUBTRACTOR);

i64 addend = read_addend(file.mf->data + hdr.offset, r) +
get_reloc_addend(r.type);

Expand Down
6 changes: 6 additions & 0 deletions macho/cmdline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
} else if (read_flag("-debug_variant")) {
} else if (read_flag("-demangle")) {
ctx.arg.demangle = true;
} else if (read_flag("-no_demangle")) {
ctx.arg.demangle = false;
} else if (read_arg("-dependency_info")) {
ctx.arg.dependency_info = arg;
} else if (read_flag("-dylib")) {
Expand Down Expand Up @@ -387,6 +389,10 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
remaining.push_back(std::string(arg));
} else if (read_arg("-final_output")) {
ctx.arg.final_output = arg;
} else if (read_flag("-fixup_chains")) {
ctx.arg.fixup_chains = true;
} else if (read_flag("-no_fixup_chains")) {
ctx.arg.fixup_chains = false;
} else if (read_arg("-force_load")) {
remaining.push_back("-force_load");
remaining.push_back(std::string(arg));
Expand Down
4 changes: 3 additions & 1 deletion macho/dead-strip.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ static void collect_root_set(Context<E> &ctx,
add(sym);

add(ctx.arg.entry);
add(get_symbol(ctx, "dyld_stub_binder"));

if (ctx.stub_helper)
add(get_symbol(ctx, "dyld_stub_binder"));
}

template <typename E>
Expand Down
21 changes: 19 additions & 2 deletions macho/macho-main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ static bool compare_chunks(const Chunk<E> *a, const Chunk<E> *b) {
"__binding",
"__weak_binding",
"__lazy_binding",
"__chainfixups",
"__export",
"__func_starts",
"__data_in_code",
Expand Down Expand Up @@ -375,6 +376,17 @@ template <typename E>
static void create_synthetic_chunks(Context<E> &ctx) {
Timer t(ctx, "create_synthetic_chunks");

// Create symbol import tables.
if (ctx.arg.fixup_chains) {
ctx.chained_fixups.reset(new ChainedFixupsSection<E>(ctx));
} else {
ctx.rebase.reset(new RebaseSection<E>(ctx));
ctx.bind.reset(new BindSection<E>(ctx));
ctx.stub_helper.reset(new StubHelperSection<E>(ctx));
ctx.lazy_symbol_ptr.reset(new LazySymbolPtrSection<E>(ctx));
ctx.lazy_bind.reset(new LazyBindSection<E>(ctx));
}

// Create a __DATA,__objc_imageinfo section.
ctx.image_info = ObjcImageInfoSection<E>::create(ctx);

Expand Down Expand Up @@ -598,7 +610,8 @@ template <typename E>
static void export_symbols(Context<E> &ctx) {
Timer t(ctx, "export_symbols");

ctx.got.add(ctx, get_symbol(ctx, "dyld_stub_binder"));
if (ctx.stub_helper)
ctx.got.add(ctx, get_symbol(ctx, "dyld_stub_binder"));

std::vector<InputFile<E> *> files;
append(files, ctx.objs);
Expand All @@ -618,13 +631,14 @@ static void export_symbols(Context<E> &ctx) {
ctx.got.add(ctx, sym);

if (sym->flags & NEEDS_STUB) {
if (ctx.arg.bind_at_load)
if (ctx.arg.bind_at_load || ctx.arg.fixup_chains)
ctx.got.add(ctx, sym);
ctx.stubs.add(ctx, sym);
}

if (sym->flags & NEEDS_THREAD_PTR)
ctx.thread_ptrs.add(ctx, sym);

sym->flags = 0;
}
}
Expand Down Expand Up @@ -1200,6 +1214,9 @@ int macho_main(int argc, char **argv) {

copy_sections_to_output_file(ctx);

if (ctx.chained_fixups)
ctx.chained_fixups->write_fixup_chains(ctx);

if (ctx.code_sig)
ctx.code_sig->write_signature(ctx);
else if (ctx.arg.uuid == UUID_HASH)
Expand Down
85 changes: 85 additions & 0 deletions macho/macho.h
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,91 @@ struct ObjcImageInfo {
ul16 swift_lang_version = 0;
};

// __LINKEDIT,__chainfixups
struct DyldChainedFixupsHeader {
ul32 fixups_version;
ul32 starts_offset;
ul32 imports_offset;
ul32 symbols_offset;
ul32 imports_count;
ul32 imports_format;
ul32 symbols_format;
};

struct DyldChainedStartsInImage {
ul32 seg_count;
ul32 seg_info_offset[];
};

struct DyldChainedStartsInSegment {
ul32 size;
ul16 page_size;
ul16 pointer_format;
ul64 segment_offset;
ul32 max_valid_pointer;
ul16 page_count;
ul16 page_start[];
};

struct DyldChainedPtr64Rebase {
u64 target : 36;
u64 high8 : 8;
u64 reserved : 7;
u64 next : 12;
u64 bind : 1;
};

struct DyldChainedPtr64Bind {
u64 ordinal : 24;
u64 addend : 8;
u64 reserved : 19;
u64 next : 12;
u64 bind : 1;
};

struct DyldChainedImport {
u32 lib_ordinal : 8;
u32 weak_import : 1;
u32 name_offset : 23;
};

struct DyldChainedImportAddend {
u32 lib_ordinal : 8;
u32 weak_import : 1;
u32 name_offset : 23;
u32 addend;
};

struct DyldChainedImportAddend64 {
u64 lib_ordinal : 16;
u64 weak_import : 1;
u64 reserved : 15;
u64 name_offset : 32;
u64 addend;
};

enum : u32 {
DYLD_CHAINED_PTR_ARM64E = 1,
DYLD_CHAINED_PTR_64 = 2,
DYLD_CHAINED_PTR_32 = 3,
DYLD_CHAINED_PTR_32_CACHE = 4,
DYLD_CHAINED_PTR_32_FIRMWARE = 5,
};

enum : u32 {
DYLD_CHAINED_PTR_START_NONE = 0xFFFF,
DYLD_CHAINED_PTR_START_MULTI = 0x8000,
DYLD_CHAINED_PTR_START_LAST = 0x8000,
};

enum : u32 {
DYLD_CHAINED_IMPORT = 1,
DYLD_CHAINED_IMPORT_ADDEND = 2,
DYLD_CHAINED_IMPORT_ADDEND64 = 3,
DYLD_CHAINED_PTR_64_OFFSET = 6,
DYLD_CHAINED_PTR_ARM64E_OFFSET = 7,
};

struct ARM64 {
static constexpr u32 cputype = CPU_TYPE_ARM64;
static constexpr u32 cpusubtype = CPU_SUBTYPE_ARM64_ALL;
Expand Down
68 changes: 58 additions & 10 deletions macho/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@ struct Relocation {
u32 offset = 0;
u8 type = -1;
u8 size = 0;
bool is_subtracted : 1 = false;
i64 addend = 0;
Symbol<E> *sym = nullptr;
Subsection<E> *subsec = nullptr;

// For range extension thunks
i32 thunk_idx = -1;
i32 thunk_sym_idx = -1;
i16 thunk_idx = -1;
i16 thunk_sym_idx = -1;
};

template <typename E>
Expand Down Expand Up @@ -333,9 +334,16 @@ struct Symbol {
bool no_dead_strip : 1 = false;
bool referenced_dynamically : 1 = false;

// For range extension thunks
i32 thunk_idx = -1;
i32 thunk_sym_idx = -1;
union {
// For range extension thunks. Used by OutputSection::compute_size().
struct {
i16 thunk_idx = -1;
i16 thunk_sym_idx = -1;
};

// For chained fixups. Used by ChainedFixupsSection.
i32 fixup_ordinal;
};

// For symtab
i32 output_symtab_idx = -1;
Expand Down Expand Up @@ -684,6 +692,43 @@ class DataInCodeSection : public Chunk<E> {
std::vector<DataInCodeEntry> contents;
};

template <typename E>
struct Fixup {
u64 addr;
Symbol<E> *sym = nullptr;
u64 addend = 0;
};

template <typename E>
struct SymbolAddend {
bool operator==(const SymbolAddend &) const = default;

Symbol<E> *sym = nullptr;
u64 addend = 0;
};

template <typename E>
class ChainedFixupsSection : public Chunk<E> {
public:
ChainedFixupsSection(Context<E> &ctx)
: Chunk<E>(ctx, "__LINKEDIT", "__chainfixups") {
this->is_hidden = true;
this->hdr.p2align = 3;
}

void compute_size(Context<E> &ctx) override;
void copy_buf(Context<E> &ctx) override;
void write_fixup_chains(Context<E> &ctx);

private:
u8 *allocate(i64 size);
template <typename T> void write_imports(Context<E> &ctx);

std::vector<Fixup<E>> fixups;
std::vector<SymbolAddend<E>> dynsyms;
std::vector<u8> contents;
};

template <typename E>
class StubsSection : public Chunk<E> {
public:
Expand Down Expand Up @@ -927,6 +972,7 @@ struct Context {
bool dynamic = true;
bool export_dynamic = false;
bool fatal_warnings = false;
bool fixup_chains = false;
bool function_starts = true;
bool mark_dead_strippable_dylib = false;
bool noinhibit_exec = false;
Expand Down Expand Up @@ -1018,20 +1064,22 @@ struct Context {

OutputMachHeader<E> mach_hdr{*this};
StubsSection<E> stubs{*this};
StubHelperSection<E> stub_helper{*this};
UnwindInfoSection<E> unwind_info{*this};
GotSection<E> got{*this};
LazySymbolPtrSection<E> lazy_symbol_ptr{*this};
DataInCodeSection<E> data_in_code{*this};
ThreadPtrsSection<E> thread_ptrs{*this};
RebaseSection<E> rebase{*this};
BindSection<E> bind{*this};
LazyBindSection<E> lazy_bind{*this};
ExportSection<E> export_{*this};
SymtabSection<E> symtab{*this};
StrtabSection<E> strtab{*this};
IndirectSymtabSection<E> indir_symtab{*this};

std::unique_ptr<StubHelperSection<E>> stub_helper;
std::unique_ptr<LazySymbolPtrSection<E>> lazy_symbol_ptr;
std::unique_ptr<LazyBindSection<E>> lazy_bind;
std::unique_ptr<RebaseSection<E>> rebase;
std::unique_ptr<BindSection<E>> bind;

std::unique_ptr<ChainedFixupsSection<E>> chained_fixups;
std::unique_ptr<FunctionStartsSection<E>> function_starts;
std::unique_ptr<ObjcImageInfoSection<E>> image_info;
std::unique_ptr<CodeSignatureSection<E>> code_sig;
Expand Down
Loading

0 comments on commit 2c87cf8

Please sign in to comment.