1
1
mirror of https://github.com/rui314/mold.git synced 2024-09-20 09:27:45 +03:00

[Mach-O] Add ARM64 stub

This commit is contained in:
Rui Ueyama 2021-12-02 11:35:48 +09:00
parent 790703b5fa
commit 16921c78ea
13 changed files with 236 additions and 175 deletions

22
macho/arch-arm64.cc Normal file
View File

@ -0,0 +1,22 @@
#include "mold.h"
#include <algorithm>
namespace mold::macho {
template <>
Relocation<ARM64>
read_reloc(Context<ARM64> &ctx, ObjectFile<ARM64> &file,
const MachSection &hdr, MachRel r) {
return {};
}
template <>
void Subsection<ARM64>::scan_relocations(Context<ARM64> &ctx) {
}
template <>
void Subsection<ARM64>::apply_reloc(Context<ARM64> &ctx, u8 *buf) {
}
} // namespace mold::macho

165
macho/arch-x86-64.cc Normal file
View File

@ -0,0 +1,165 @@
#include "mold.h"
#include <algorithm>
namespace mold::macho {
static i64 get_reloc_addend(u32 type) {
switch (type) {
case X86_64_RELOC_SIGNED_1:
return 1;
case X86_64_RELOC_SIGNED_2:
return 2;
case X86_64_RELOC_SIGNED_4:
return 4;
default:
return 0;
}
}
static i64 read_addend(u8 *buf, const MachRel &r) {
switch (r.p2size) {
case 2:
return *(i32 *)(buf + r.offset) + get_reloc_addend(r.type);
case 3:
return *(i64 *)(buf + r.offset) + get_reloc_addend(r.type);
default:
unreachable();
}
}
template <>
Relocation<X86_64>
read_reloc(Context<X86_64> &ctx, ObjectFile<X86_64> &file,
const MachSection &hdr, MachRel r) {
if (r.p2size != 2 && r.p2size != 3)
Fatal(ctx) << file << ": invalid r.p2size: " << (u32)r.p2size;
if (r.is_pcrel) {
if (r.p2size != 2)
Fatal(ctx) << file << ": invalid PC-relative reloc: " << r.offset;
} else {
if (r.p2size != 3)
Fatal(ctx) << file << ": invalid non-PC-relative reloc: " << r.offset;
}
u8 *buf = (u8 *)file.mf->data + hdr.offset;
Relocation<X86_64> rel{r.offset, (u8)r.type, (u8)r.p2size, (bool)r.is_pcrel};
i64 addend = read_addend(buf, r);
if (r.is_extern) {
rel.sym = file.syms[r.idx];
rel.addend = addend;
return rel;
}
u32 addr;
if (r.is_pcrel)
addr = hdr.addr + r.offset + 4 + addend;
else
addr = addend;
Subsection<X86_64> *target = file.find_subsection(ctx, addr);
if (!target)
Fatal(ctx) << file << ": bad relocation: " << r.offset;
rel.subsec = target;
rel.addend = addr - target->input_addr;
return rel;
}
template <>
void Subsection<X86_64>::scan_relocations(Context<X86_64> &ctx) {
for (Relocation<X86_64> &rel : get_rels()) {
Symbol<X86_64> *sym = rel.sym;
if (!sym)
continue;
switch (rel.type) {
case X86_64_RELOC_GOT_LOAD:
if (sym->file && sym->file->is_dylib)
sym->flags |= NEEDS_GOT;
break;
case X86_64_RELOC_GOT:
sym->flags |= NEEDS_GOT;
break;
case X86_64_RELOC_TLV:
if (sym->file && sym->file->is_dylib)
sym->flags |= NEEDS_THREAD_PTR;
break;
}
if (sym->file && sym->file->is_dylib) {
sym->flags |= NEEDS_STUB;
((DylibFile<X86_64> *)sym->file)->is_needed = true;
}
}
}
template <>
void Subsection<X86_64>::apply_reloc(Context<X86_64> &ctx, u8 *buf) {
for (const Relocation<X86_64> &rel : get_rels()) {
if (rel.sym && !rel.sym->file) {
Error(ctx) << "undefined symbol: " << isec.file << ": " << *rel.sym;
continue;
}
u64 val = 0;
switch (rel.type) {
case X86_64_RELOC_UNSIGNED:
case X86_64_RELOC_SIGNED:
case X86_64_RELOC_BRANCH:
case X86_64_RELOC_SIGNED_1:
case X86_64_RELOC_SIGNED_2:
case X86_64_RELOC_SIGNED_4:
val = rel.sym ? rel.sym->get_addr(ctx) : rel.subsec->get_addr(ctx);
break;
case X86_64_RELOC_GOT_LOAD:
if (rel.sym->got_idx != -1) {
val = rel.sym->get_got_addr(ctx);
} else {
// Relax MOVQ into LEAQ
if (buf[rel.offset - 2] != 0x8b)
Error(ctx) << isec << ": invalid GOT_LOAD relocation";
buf[rel.offset - 2] = 0x8d;
val = rel.sym->get_addr(ctx);
}
break;
case X86_64_RELOC_GOT:
val = rel.sym->get_got_addr(ctx);
break;
case X86_64_RELOC_TLV:
if (rel.sym->tlv_idx != -1) {
val = rel.sym->get_tlv_addr(ctx);
} else {
// Relax MOVQ into LEAQ
if (buf[rel.offset - 2] != 0x8b)
Error(ctx) << isec << ": invalid TLV relocation";
buf[rel.offset - 2] = 0x8d;
val = rel.sym->get_addr(ctx);
}
break;
default:
Fatal(ctx) << isec << ": unknown reloc: " << (int)rel.type;
}
val += rel.addend;
if (rel.is_pcrel)
val -= get_addr(ctx) + rel.offset + 4 + get_reloc_addend(rel.type);
switch (rel.p2size) {
case 2:
*(u32 *)(buf + rel.offset) = val;
break;
case 3:
*(u64 *)(buf + rel.offset) = val;
break;
default:
unreachable();
};
}
}
} // namespace mold::macho

View File

@ -179,7 +179,11 @@ void parse_nonpositional_args(Context<E> &ctx,
} else if (read_flag("-no_adhoc_codesign")) {
ctx.arg.adhoc_codesign = false;
} else if (read_arg("-arch")) {
if (arg != "x86_64")
if (arg == "x86_64")
ctx.arg.arch = CPU_TYPE_X86_64;
else if (arg == "arm64")
ctx.arg.arch = CPU_TYPE_ARM64;
else
Fatal(ctx) << "unknown -arch: " << arg;
} else if (read_flag("-color-diagnostics") ||
read_flag("--color-diagnostics")) {
@ -297,6 +301,7 @@ void parse_nonpositional_args(Context<E> &ctx,
#define INSTANTIATE(E) \
template void parse_nonpositional_args(Context<E> &, std::vector<std::string> &)
INSTANTIATE(ARM64);
INSTANTIATE(X86_64);
} // namespace mold::macho

View File

@ -105,6 +105,7 @@ void dead_strip(Context<E> &ctx) {
#define INSTANTIATE(E) \
template void dead_strip(Context<E> &)
INSTANTIATE(ARM64);
INSTANTIATE(X86_64);
} // namespace mold::macho

View File

@ -1,16 +1,7 @@
#include "mold.h"
#include <algorithm>
namespace mold::macho {
template <typename E>
std::ostream &operator<<(std::ostream &out, const InputSection<E> &sec) {
out << sec.file << "(" << sec.hdr.get_segname() << ","
<< sec.hdr.get_sectname() << ")";
return out;
}
template <typename E>
InputSection<E>::InputSection(Context<E> &ctx, ObjectFile<E> &file,
const MachSection &hdr)
@ -21,69 +12,6 @@ InputSection<E>::InputSection(Context<E> &ctx, ObjectFile<E> &file,
contents = file.mf->get_contents().substr(hdr.offset, hdr.size);
}
static i64 get_reloc_addend(u32 type) {
switch (type) {
case X86_64_RELOC_SIGNED_1:
return 1;
case X86_64_RELOC_SIGNED_2:
return 2;
case X86_64_RELOC_SIGNED_4:
return 4;
default:
return 0;
}
}
static i64 read_addend(u8 *buf, const MachRel &r) {
switch (r.p2size) {
case 2:
return *(i32 *)(buf + r.offset) + get_reloc_addend(r.type);
case 3:
return *(i64 *)(buf + r.offset) + get_reloc_addend(r.type);
default:
unreachable();
}
}
template <typename E>
static Relocation<E> read_reloc(Context<E> &ctx, ObjectFile<E> &file,
const MachSection &hdr, MachRel r) {
if (r.p2size != 2 && r.p2size != 3)
Fatal(ctx) << file << ": invalid r.p2size: " << (u32)r.p2size;
if (r.is_pcrel) {
if (r.p2size != 2)
Fatal(ctx) << file << ": invalid PC-relative reloc: " << r.offset;
} else {
if (r.p2size != 3)
Fatal(ctx) << file << ": invalid non-PC-relative reloc: " << r.offset;
}
u8 *buf = (u8 *)file.mf->data + hdr.offset;
Relocation<E> rel{r.offset, (u8)r.type, (u8)r.p2size, (bool)r.is_pcrel};
i64 addend = read_addend(buf, r);
if (r.is_extern) {
rel.sym = file.syms[r.idx];
rel.addend = addend;
return rel;
}
u32 addr;
if (r.is_pcrel)
addr = hdr.addr + r.offset + 4 + addend;
else
addr = addend;
Subsection<E> *target = file.find_subsection(ctx, addr);
if (!target)
Fatal(ctx) << file << ": bad relocation: " << r.offset;
rel.subsec = target;
rel.addend = addr - target->input_addr;
return rel;
}
template <typename E>
void InputSection<E>::parse_relocations(Context<E> &ctx) {
rels.reserve(hdr.nreloc);
@ -125,104 +53,10 @@ void InputSection<E>::parse_relocations(Context<E> &ctx) {
}
}
template <typename E>
void Subsection<E>::scan_relocations(Context<E> &ctx) {
for (Relocation<E> &rel : get_rels()) {
Symbol<E> *sym = rel.sym;
if (!sym)
continue;
switch (rel.type) {
case X86_64_RELOC_GOT_LOAD:
if (sym->file && sym->file->is_dylib)
sym->flags |= NEEDS_GOT;
break;
case X86_64_RELOC_GOT:
sym->flags |= NEEDS_GOT;
break;
case X86_64_RELOC_TLV:
if (sym->file && sym->file->is_dylib)
sym->flags |= NEEDS_THREAD_PTR;
break;
}
if (sym->file && sym->file->is_dylib) {
sym->flags |= NEEDS_STUB;
((DylibFile<E> *)sym->file)->is_needed = true;
}
}
}
template <typename E>
void Subsection<E>::apply_reloc(Context<E> &ctx, u8 *buf) {
for (const Relocation<E> &rel : get_rels()) {
if (rel.sym && !rel.sym->file) {
Error(ctx) << "undefined symbol: " << isec.file << ": " << *rel.sym;
continue;
}
u64 val = 0;
switch (rel.type) {
case X86_64_RELOC_UNSIGNED:
case X86_64_RELOC_SIGNED:
case X86_64_RELOC_BRANCH:
case X86_64_RELOC_SIGNED_1:
case X86_64_RELOC_SIGNED_2:
case X86_64_RELOC_SIGNED_4:
val = rel.sym ? rel.sym->get_addr(ctx) : rel.subsec->get_addr(ctx);
break;
case X86_64_RELOC_GOT_LOAD:
if (rel.sym->got_idx != -1) {
val = rel.sym->get_got_addr(ctx);
} else {
// Relax MOVQ into LEAQ
if (buf[rel.offset - 2] != 0x8b)
Error(ctx) << isec << ": invalid GOT_LOAD relocation";
buf[rel.offset - 2] = 0x8d;
val = rel.sym->get_addr(ctx);
}
break;
case X86_64_RELOC_GOT:
val = rel.sym->get_got_addr(ctx);
break;
case X86_64_RELOC_TLV:
if (rel.sym->tlv_idx != -1) {
val = rel.sym->get_tlv_addr(ctx);
} else {
// Relax MOVQ into LEAQ
if (buf[rel.offset - 2] != 0x8b)
Error(ctx) << isec << ": invalid TLV relocation";
buf[rel.offset - 2] = 0x8d;
val = rel.sym->get_addr(ctx);
}
break;
default:
Fatal(ctx) << isec << ": unknown reloc: " << (int)rel.type;
}
val += rel.addend;
if (rel.is_pcrel)
val -= get_addr(ctx) + rel.offset + 4 + get_reloc_addend(rel.type);
switch (rel.p2size) {
case 2:
*(u32 *)(buf + rel.offset) = val;
break;
case 3:
*(u64 *)(buf + rel.offset) = val;
break;
default:
unreachable();
};
}
}
#define INSTANTIATE(E) \
template class InputSection<E>; \
template class Subsection<E>
template class InputSection<E>
INSTANTIATE(ARM64);
INSTANTIATE(X86_64);
} // namespace mold::macho

View File

@ -168,7 +168,7 @@ static constexpr u32 S_ATTR_NO_TOC = 0x400000;
static constexpr u32 S_ATTR_PURE_INSTRUCTIONS = 0x800000;
static constexpr u32 CPU_TYPE_X86_64 = 0x1000007;
static constexpr u32 CPU_TYPE_ARM64 = 0x1000012;
static constexpr u32 CPU_TYPE_ARM64 = 0x100000c;
static constexpr u32 CPU_SUBTYPE_X86_64_ALL = 3;
static constexpr u32 CPU_SUBTYPE_ARM64_ALL = 0;
@ -306,6 +306,18 @@ static constexpr u32 TOOL_CLANG = 1;
static constexpr u32 TOOL_SWIFT = 2;
static constexpr u32 TOOL_LD = 3;
static constexpr u32 ARM64_RELOC_UNSIGNED = 0;
static constexpr u32 ARM64_RELOC_SUBTRACTOR = 1;
static constexpr u32 ARM64_RELOC_BRANCH26 = 2;
static constexpr u32 ARM64_RELOC_PAGE21 = 3;
static constexpr u32 ARM64_RELOC_PAGEOFF12 = 4;
static constexpr u32 ARM64_RELOC_GOT_LOAD_PAGE21 = 5;
static constexpr u32 ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6;
static constexpr u32 ARM64_RELOC_POINTER_TO_GOT = 7;
static constexpr u32 ARM64_RELOC_TLVP_LOAD_PAGE21 = 8;
static constexpr u32 ARM64_RELOC_TLVP_LOAD_PAGEOFF12 = 9;
static constexpr u32 ARM64_RELOC_ADDEND = 10;
static constexpr u32 X86_64_RELOC_UNSIGNED = 0;
static constexpr u32 X86_64_RELOC_SIGNED = 1;
static constexpr u32 X86_64_RELOC_BRANCH = 2;
@ -657,12 +669,14 @@ struct CodeSignatureDirectory {
ubig64 exec_seg_flags;
};
struct ARM64 {
static constexpr u32 cputype = CPU_TYPE_ARM64;
static constexpr u32 cpusubtype = CPU_SUBTYPE_ARM64_ALL;
};
struct X86_64 {
static constexpr u32 cputype = CPU_TYPE_X86_64;
static constexpr u32 cpusubtype = CPU_SUBTYPE_X86_64_ALL;
};
struct AARCH64 {
};
} // namespace mold::macho

View File

@ -254,7 +254,7 @@ strip_universal_header(Context<E> &ctx, MappedFile<Context<E>> *mf) {
FatArch *arch = (FatArch *)(mf->data + sizeof(hdr));
for (i64 i = 0; i < hdr.nfat_arch; i++)
if (arch[i].cputype == CPU_TYPE_X86_64)
if (arch[i].cputype == E::cputype)
return mf->slice(ctx, mf->name, arch[i].offset, arch[i].size);
Fatal(ctx) << mf->name << ": fat file contains no matching file";
}
@ -358,6 +358,9 @@ static int do_main(int argc, char **argv) {
std::vector<std::string> file_args;
parse_nonpositional_args(ctx, file_args);
if (ctx.arg.arch == CPU_TYPE_X86_64)
return do_main<X86_64>(argc, argv);
read_input_files(ctx, file_args);
i64 priority = 1;
@ -453,7 +456,7 @@ static int do_main(int argc, char **argv) {
}
int main(int argc, char **argv) {
return do_main<X86_64>(argc, argv);
return do_main<ARM64>(argc, argv);
}
}

View File

@ -74,6 +74,7 @@ void print_map(Context<E> &ctx) {
#define INSTANTIATE(E) \
template void print_map(Context<E> &)
INSTANTIATE(ARM64);
INSTANTIATE(X86_64);
} // namespace mold::macho

View File

@ -191,6 +191,10 @@ public:
std::atomic_bool is_alive = false;
};
template <typename E>
Relocation<E> read_reloc(Context<E> &ctx, ObjectFile<E> &file,
const MachSection &hdr, MachRel r);
//
// Symbol
//
@ -781,6 +785,7 @@ struct Context {
bool dynamic = true;
bool fatal_warnings = false;
bool trace = false;
i64 arch = CPU_TYPE_ARM64;
i64 headerpad = 256;
i64 pagezero_size = 0;
i64 platform = PLATFORM_MACOS;
@ -857,6 +862,13 @@ int main(int argc, char **argv);
// Inline functions
//
template <typename E>
std::ostream &operator<<(std::ostream &out, const InputSection<E> &sec) {
out << sec.file << "(" << sec.hdr.get_segname() << ","
<< sec.hdr.get_sectname() << ")";
return out;
}
template <typename E>
u64 Subsection<E>::get_addr(Context<E> &ctx) const {
return ctx.arg.pagezero_size + raddr;

View File

@ -602,6 +602,7 @@ void DylibFile<E>::resolve_symbols(Context<E> &ctx) {
template class ObjectFile<E>; \
template class DylibFile<E>
INSTANTIATE(ARM64);
INSTANTIATE(X86_64);
} // namespace mold::macho

View File

@ -1342,6 +1342,7 @@ void ThreadPtrsSection<E>::copy_buf(Context<E> &ctx) {
template class LazySymbolPtrSection<E>; \
template class ThreadPtrsSection<E>
INSTANTIATE(ARM64);
INSTANTIATE(X86_64);
} // namespace mold::macho

View File

@ -114,6 +114,7 @@ OutputFile<E>::open(Context<E> &ctx, std::string path, i64 filesize, i64 perm) {
#define INSTANTIATE(E) \
template class OutputFile<E>
INSTANTIATE(ARM64);
INSTANTIATE(X86_64);
} // namespace mold::macho

View File

@ -131,6 +131,7 @@ TextDylib parse_tbd(Context<E> &ctx, MappedFile<Context<E>> *mf) {
#define INSTANTIATE(E) \
template TextDylib parse_tbd(Context<E> &, MappedFile<Context<E>> *);
INSTANTIATE(ARM64);
INSTANTIATE(X86_64);
} // namespace mold::macho