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:
parent
790703b5fa
commit
16921c78ea
22
macho/arch-arm64.cc
Normal file
22
macho/arch-arm64.cc
Normal 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
165
macho/arch-x86-64.cc
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
12
macho/mold.h
12
macho/mold.h
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user