mirror of
https://github.com/rui314/mold.git
synced 2024-09-11 21:17:28 +03:00
[ELF][m68k] Add initial m68k support
This commit is contained in:
parent
e0ff005333
commit
5fe60e3b6d
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -43,7 +43,7 @@ jobs:
|
||||
# Install cross toolchains
|
||||
dpkg --add-architecture i386
|
||||
./install-build-deps.sh update
|
||||
apt-get install -y sudo qemu-user gdb zstd dwarfdump gcc-10-i686-linux-gnu gcc-10-aarch64-linux-gnu gcc-10-riscv64-linux-gnu gcc-10-arm-linux-gnueabihf gcc-10-powerpc64-linux-gnu gcc-10-powerpc64le-linux-gnu gcc-10-s390x-linux-gnu gcc-10-sparc64-linux-gnu g++-10-i686-linux-gnu g++-10-aarch64-linux-gnu g++-10-riscv64-linux-gnu g++-10-arm-linux-gnueabihf g++-10-powerpc64-linux-gnu g++-10-powerpc64le-linux-gnu g++-10-s390x-linux-gnu g++-10-sparc64-linux-gnu
|
||||
apt-get install -y sudo qemu-user gdb zstd dwarfdump gcc-10-i686-linux-gnu gcc-10-aarch64-linux-gnu gcc-10-riscv64-linux-gnu gcc-10-arm-linux-gnueabihf gcc-10-powerpc64-linux-gnu gcc-10-powerpc64le-linux-gnu gcc-10-s390x-linux-gnu gcc-10-sparc64-linux-gnu gcc-10-m68k-linux-gnu g++-10-i686-linux-gnu g++-10-aarch64-linux-gnu g++-10-riscv64-linux-gnu g++-10-arm-linux-gnueabihf g++-10-powerpc64-linux-gnu g++-10-powerpc64le-linux-gnu g++-10-s390x-linux-gnu g++-10-sparc64-linux-gnu g++-10-m68k-linux-gnu
|
||||
ln -sf /usr/bin/i686-linux-gnu-gcc-10 /usr/bin/i686-linux-gnu-gcc
|
||||
ln -sf /usr/bin/i686-linux-gnu-g++-10 /usr/bin/i686-linux-gnu-g++
|
||||
ln -sf /usr/bin/aarch64-linux-gnu-gcc-10 /usr/bin/aarch64-linux-gnu-gcc
|
||||
@ -60,6 +60,8 @@ jobs:
|
||||
ln -sf /usr/bin/s390x-linux-gnu-g++-10 /usr/bin/s390x-linux-gnu-g++
|
||||
ln -sf /usr/bin/sparc64-linux-gnu-gcc-10 /usr/bin/sparc64-linux-gnu-gcc
|
||||
ln -sf /usr/bin/sparc64-linux-gnu-g++-10 /usr/bin/sparc64-linux-gnu-g++
|
||||
ln -sf /usr/bin/m68k-linux-gnu-gcc-10 /usr/bin/m68k-linux-gnu-gcc
|
||||
ln -sf /usr/bin/m68k-linux-gnu-g++-10 /usr/bin/m68k-linux-gnu-g++
|
||||
|
||||
# Install a RV32 toolchain from third party since it's not available
|
||||
# as an Ubuntu package.
|
||||
|
@ -246,7 +246,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
# compiler instances. This is hacky but greatly reduces compile time.
|
||||
list(APPEND MOLD_ELF_TARGETS
|
||||
X86_64 I386 ARM64 ARM32 RV32LE RV32BE RV64LE RV64BE
|
||||
PPC64V1 PPC64V2 SPARC64 S390X)
|
||||
PPC64V1 PPC64V2 S390X SPARC64 M68K)
|
||||
|
||||
list(APPEND MOLD_ELF_TEMPLATE_FILES
|
||||
elf/cmdline.cc
|
||||
@ -308,6 +308,7 @@ target_sources(mold PRIVATE
|
||||
elf/arch-arm32.cc
|
||||
elf/arch-arm64.cc
|
||||
elf/arch-i386.cc
|
||||
elf/arch-m68k.cc
|
||||
elf/arch-ppc64v1.cc
|
||||
elf/arch-ppc64v2.cc
|
||||
elf/arch-riscv.cc
|
||||
|
338
elf/arch-m68k.cc
Normal file
338
elf/arch-m68k.cc
Normal file
@ -0,0 +1,338 @@
|
||||
// This file contains code for the Motorola 68000 series microprocessors,
|
||||
// which is often abbreviated as m68k. Running a Unix-like system on a
|
||||
// m68k-based machine today is probably a retro-computing hobby activity,
|
||||
// but the processor was a popular choice to build Unix computers during
|
||||
// '80s. Early Sun workstations for example used m68k. Macintosh until
|
||||
// 1994 were based on m68k as well until they switched to PowerPC (and
|
||||
// then to x86 and to ARM.)
|
||||
//
|
||||
// From the linker's point of view, it is not hard to support m68k. It's
|
||||
// just a 32-bit big-endian CISC ISA. Compared to comtemporary i386,
|
||||
// m68k's psABI is actually simpler because m68k has PC-relative memory
|
||||
// access instructions and therefore can support position-independent
|
||||
// code without too much hassle.
|
||||
|
||||
#include "mold.h"
|
||||
|
||||
namespace mold::elf {
|
||||
|
||||
using E = M68K;
|
||||
|
||||
template <>
|
||||
void write_plt_header(Context<E> &ctx, u8 *buf) {
|
||||
static const u8 insn[] = {
|
||||
0x2f, 0x00, // move.l %d0, -(%sp)
|
||||
0x2f, 0x3b, 0x01, 0x70, 0, 0, 0, 0, // move.l (GOTPLT+4, %pc), -(%sp)
|
||||
0x4e, 0xfb, 0x01, 0x71, 0, 0, 0, 0, // jmp ([GOTPLT+8, %pc])
|
||||
};
|
||||
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ub32 *)(buf + 6) = ctx.gotplt->shdr.sh_addr - ctx.plt->shdr.sh_addr;
|
||||
*(ub32 *)(buf + 14) = ctx.gotplt->shdr.sh_addr - ctx.plt->shdr.sh_addr - 4;
|
||||
}
|
||||
|
||||
template <>
|
||||
void write_plt_entry(Context<E> &ctx, u8 *buf, Symbol<E> &sym) {
|
||||
static const u8 insn[] = {
|
||||
0x20, 0x3c, 0, 0, 0, 0, // move.l PLT_OFFSET, %d0
|
||||
0x4e, 0xfb, 0x01, 0x71, 0, 0, 0, 0, // jmp ([GOTPLT_ENTRY, %pc])
|
||||
};
|
||||
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ub32 *)(buf + 2) = sym.get_plt_idx(ctx) * sizeof(ElfRel<E>);
|
||||
*(ub32 *)(buf + 10) = sym.get_gotplt_addr(ctx) - sym.get_plt_addr(ctx) - 8;
|
||||
}
|
||||
|
||||
template <>
|
||||
void write_pltgot_entry(Context<E> &ctx, u8 *buf, Symbol<E> &sym) {
|
||||
static const u8 insn[] = {
|
||||
0x4e, 0xfb, 0x01, 0x71, 0, 0, 0, 0, // jmp ([GOT_ENTRY, %pc])
|
||||
};
|
||||
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ub32 *)(buf + 4) = sym.get_got_addr(ctx) - sym.get_plt_addr(ctx) - 2;
|
||||
}
|
||||
|
||||
template <>
|
||||
void EhFrameSection<E>::apply_reloc(Context<E> &ctx, const ElfRel<E> &rel,
|
||||
u64 offset, u64 val) {
|
||||
u8 *loc = ctx.buf + this->shdr.sh_offset + offset;
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_68K_32:
|
||||
*(ub32 *)loc = val;
|
||||
break;
|
||||
case R_68K_PC32:
|
||||
*(ub32 *)loc = val - this->shdr.sh_addr - offset;
|
||||
break;
|
||||
default:
|
||||
Fatal(ctx) << "unsupported relocation in .eh_frame: " << rel;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
std::span<const ElfRel<E>> rels = get_rels(ctx);
|
||||
|
||||
ElfRel<E> *dynrel = nullptr;
|
||||
if (ctx.reldyn)
|
||||
dynrel = (ElfRel<E> *)(ctx.buf + ctx.reldyn->shdr.sh_offset +
|
||||
file.reldyn_offset + this->reldyn_offset);
|
||||
|
||||
for (i64 i = 0; i < rels.size(); i++) {
|
||||
const ElfRel<E> &rel = rels[i];
|
||||
if (rel.r_type == R_NONE)
|
||||
continue;
|
||||
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
auto write16 = [&](u64 val) {
|
||||
check(val, 0, 1 << 16);
|
||||
*(ub16 *)loc = val;
|
||||
};
|
||||
|
||||
auto write16s = [&](u64 val) {
|
||||
check(val, -(1 << 15), 1 << 15);
|
||||
*(ub16 *)loc = val;
|
||||
};
|
||||
|
||||
auto write8 = [&](u64 val) {
|
||||
check(val, 0, 1 << 8);
|
||||
*loc = val;
|
||||
};
|
||||
|
||||
auto write8s = [&](u64 val) {
|
||||
check(val, -(1 << 7), 1 << 7);
|
||||
*loc = val;
|
||||
};
|
||||
|
||||
#define S sym.get_addr(ctx)
|
||||
#define A rel.r_addend
|
||||
#define P (get_addr() + rel.r_offset)
|
||||
#define G (sym.get_got_idx(ctx) * sizeof(Word<E>))
|
||||
#define GOT ctx.got->shdr.sh_addr
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_68K_32:
|
||||
apply_dyn_absrel(ctx, sym, rel, loc, S, A, P, dynrel);
|
||||
break;
|
||||
case R_68K_16:
|
||||
write16(S + A);
|
||||
break;
|
||||
case R_68K_8:
|
||||
write8(S + A);
|
||||
break;
|
||||
case R_68K_PC32:
|
||||
case R_68K_PLT32:
|
||||
*(ub32 *)loc = S + A - P;
|
||||
break;
|
||||
case R_68K_PC16:
|
||||
case R_68K_PLT16:
|
||||
write16s(S + A - P);
|
||||
break;
|
||||
case R_68K_PC8:
|
||||
case R_68K_PLT8:
|
||||
write8s(S + A - P);
|
||||
break;
|
||||
case R_68K_GOTPCREL32:
|
||||
*(ub32 *)loc = GOT + A - P;
|
||||
break;
|
||||
case R_68K_GOTPCREL16:
|
||||
write16s(GOT + A - P);
|
||||
break;
|
||||
case R_68K_GOTPCREL8:
|
||||
write8s(GOT + A - P);
|
||||
break;
|
||||
case R_68K_GOTOFF32:
|
||||
*(ub32 *)loc = G + A;
|
||||
break;
|
||||
case R_68K_GOTOFF16:
|
||||
write16(G + A);
|
||||
break;
|
||||
case R_68K_GOTOFF8:
|
||||
write8(G + A);
|
||||
break;
|
||||
case R_68K_TLS_GD32:
|
||||
*(ub32 *)loc = sym.get_tlsgd_addr(ctx) + A - GOT;
|
||||
break;
|
||||
case R_68K_TLS_GD16:
|
||||
write16(sym.get_tlsgd_addr(ctx) + A - GOT);
|
||||
break;
|
||||
case R_68K_TLS_GD8:
|
||||
write8(sym.get_tlsgd_addr(ctx) + A - GOT);
|
||||
break;
|
||||
case R_68K_TLS_LDM32:
|
||||
*(ub32 *)loc = ctx.got->get_tlsld_addr(ctx) + A - GOT;
|
||||
break;
|
||||
case R_68K_TLS_LDM16:
|
||||
write16(ctx.got->get_tlsld_addr(ctx) + A - GOT);
|
||||
break;
|
||||
case R_68K_TLS_LDM8:
|
||||
write8(ctx.got->get_tlsld_addr(ctx) + A - GOT);
|
||||
break;
|
||||
case R_68K_TLS_LDO32:
|
||||
*(ub32 *)loc = S + A - ctx.tls_begin - E::tls_dtp_offset;
|
||||
break;
|
||||
case R_68K_TLS_LDO16:
|
||||
write16s(S + A - ctx.tls_begin - E::tls_dtp_offset);
|
||||
break;
|
||||
case R_68K_TLS_LDO8:
|
||||
write8s(S + A - ctx.tls_begin - E::tls_dtp_offset);
|
||||
break;
|
||||
case R_68K_TLS_IE32:
|
||||
*(ub32 *)loc = sym.get_gottp_addr(ctx) + A - GOT;
|
||||
break;
|
||||
case R_68K_TLS_IE16:
|
||||
write16(sym.get_gottp_addr(ctx) + A - GOT);
|
||||
break;
|
||||
case R_68K_TLS_IE8:
|
||||
write8(sym.get_gottp_addr(ctx) + A - GOT);
|
||||
break;
|
||||
case R_68K_TLS_LE32:
|
||||
*(ub32 *)loc = S + A - ctx.tp_addr;
|
||||
break;
|
||||
case R_68K_TLS_LE16:
|
||||
write16(S + A - ctx.tp_addr);
|
||||
break;
|
||||
case R_68K_TLS_LE8:
|
||||
write8(S + A - ctx.tp_addr);
|
||||
break;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
|
||||
#undef S
|
||||
#undef A
|
||||
#undef P
|
||||
#undef G
|
||||
#undef GOT
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
std::span<const ElfRel<E>> rels = get_rels(ctx);
|
||||
|
||||
for (i64 i = 0; i < rels.size(); i++) {
|
||||
const ElfRel<E> &rel = rels[i];
|
||||
if (rel.r_type == R_NONE)
|
||||
continue;
|
||||
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
if (!sym.file) {
|
||||
record_undef_error(ctx, rel);
|
||||
continue;
|
||||
}
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
|
||||
#define S (frag ? frag->get_addr(ctx) : sym.get_addr(ctx))
|
||||
#define A (frag ? frag_addend : (i64)rel.r_addend)
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_68K_32:
|
||||
if (std::optional<u64> val = get_tombstone(sym, frag))
|
||||
*(ub32 *)loc = *val;
|
||||
else
|
||||
*(ub32 *)loc = S + A;
|
||||
break;
|
||||
default:
|
||||
Fatal(ctx) << *this << ": invalid relocation for non-allocated sections: "
|
||||
<< rel;
|
||||
}
|
||||
|
||||
#undef S
|
||||
#undef A
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void InputSection<E>::scan_relocations(Context<E> &ctx) {
|
||||
assert(shdr().sh_flags & SHF_ALLOC);
|
||||
|
||||
this->reldyn_offset = file.num_dynrel * sizeof(ElfRel<E>);
|
||||
std::span<const ElfRel<E>> rels = get_rels(ctx);
|
||||
|
||||
for (i64 i = 0; i < rels.size(); i++) {
|
||||
const ElfRel<E> &rel = rels[i];
|
||||
if (rel.r_type == R_NONE)
|
||||
continue;
|
||||
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
|
||||
if (!sym.file) {
|
||||
record_undef_error(ctx, rel);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sym.is_ifunc())
|
||||
Error(ctx) << sym << ": GNU ifunc symbol is not supported on m68k";
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_68K_32:
|
||||
scan_rel(ctx, sym, rel, dyn_absrel_table);
|
||||
break;
|
||||
case R_68K_16:
|
||||
case R_68K_8:
|
||||
scan_rel(ctx, sym, rel, absrel_table);
|
||||
break;
|
||||
case R_68K_PC32:
|
||||
case R_68K_PC16:
|
||||
case R_68K_PC8:
|
||||
scan_rel(ctx, sym, rel, pcrel_table);
|
||||
break;
|
||||
case R_68K_GOTPCREL32:
|
||||
case R_68K_GOTPCREL16:
|
||||
case R_68K_GOTPCREL8:
|
||||
case R_68K_GOTOFF32:
|
||||
case R_68K_GOTOFF16:
|
||||
case R_68K_GOTOFF8:
|
||||
sym.flags |= NEEDS_GOT;
|
||||
break;
|
||||
case R_68K_PLT32:
|
||||
case R_68K_PLT16:
|
||||
case R_68K_PLT8:
|
||||
if (sym.is_imported)
|
||||
sym.flags |= NEEDS_PLT;
|
||||
break;
|
||||
case R_68K_TLS_GD32:
|
||||
case R_68K_TLS_GD16:
|
||||
case R_68K_TLS_GD8:
|
||||
sym.flags |= NEEDS_TLSGD;
|
||||
break;
|
||||
case R_68K_TLS_LDM32:
|
||||
case R_68K_TLS_LDM16:
|
||||
case R_68K_TLS_LDM8:
|
||||
ctx.needs_tlsld = true;
|
||||
break;
|
||||
case R_68K_TLS_IE32:
|
||||
case R_68K_TLS_IE16:
|
||||
case R_68K_TLS_IE8:
|
||||
sym.flags |= NEEDS_GOTTP;
|
||||
break;
|
||||
case R_68K_TLS_LDO32:
|
||||
case R_68K_TLS_LDO16:
|
||||
case R_68K_TLS_LDO8:
|
||||
case R_68K_TLS_LE32:
|
||||
case R_68K_TLS_LE16:
|
||||
case R_68K_TLS_LE8:
|
||||
break;
|
||||
default:
|
||||
Fatal(ctx) << *this << ": unknown relocation: " << rel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mold::elf
|
@ -194,8 +194,8 @@ Options:
|
||||
-z notext
|
||||
-z textoff
|
||||
|
||||
mold: supported targets: elf32-i386 elf64-x86-64 elf32-littlearm elf64-littleaarch64 elf32-littleriscv elf32-bigriscv elf64-littleriscv elf64-bigriscv elf64-powerpc elf64-powerpc elf64-powerpcle elf64-s390 elf64-sparc
|
||||
mold: supported emulations: elf_i386 elf_x86_64 armelf_linux_eabi aarch64linux aarch64elf elf32lriscv elf32briscv elf64lriscv elf64briscv elf64_s390 elf64_sparc)";
|
||||
mold: supported targets: elf32-i386 elf64-x86-64 elf32-littlearm elf64-littleaarch64 elf32-littleriscv elf32-bigriscv elf64-littleriscv elf64-bigriscv elf64-powerpc elf64-powerpc elf64-powerpcle elf64-s390 elf64-sparc elf32-m68k
|
||||
mold: supported emulations: elf_i386 elf_x86_64 armelf_linux_eabi aarch64linux aarch64elf elf32lriscv elf32briscv elf64lriscv elf64briscv elf64_s390 elf64_sparc m68kelf)";
|
||||
|
||||
static std::vector<std::string> add_dashes(std::string name) {
|
||||
// Single-letter option
|
||||
@ -507,7 +507,8 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
|
||||
<< "\n Supported emulations:\n elf_x86_64\n elf_i386\n"
|
||||
<< " aarch64linux\n armelf_linux_eabi\n elf64lriscv\n"
|
||||
<< " elf64briscv\n elf32lriscv\n elf32briscv\n"
|
||||
<< " elf64ppc\n elf64lppc\n elf64_s390\n elf64_sparc";
|
||||
<< " elf64ppc\n elf64lppc\n elf64_s390\n elf64_sparc\n"
|
||||
<< " m68kelf";
|
||||
version_shown = true;
|
||||
} else if (read_arg("m")) {
|
||||
if (arg == "elf_x86_64") {
|
||||
@ -534,6 +535,8 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
|
||||
ctx.arg.emulation = MachineType::S390X;
|
||||
} else if (arg == "elf64_sparc") {
|
||||
ctx.arg.emulation = MachineType::SPARC64;
|
||||
} else if (arg == "m68kelf") {
|
||||
ctx.arg.emulation = MachineType::M68K;
|
||||
} else {
|
||||
Fatal(ctx) << "unknown -m argument: " << arg;
|
||||
}
|
||||
|
137
elf/elf.h
137
elf/elf.h
@ -19,8 +19,9 @@ struct RV32LE;
|
||||
struct RV32BE;
|
||||
struct PPC64V1;
|
||||
struct PPC64V2;
|
||||
struct SPARC64;
|
||||
struct S390X;
|
||||
struct SPARC64;
|
||||
struct M68K;
|
||||
|
||||
template <typename E> struct ElfSym;
|
||||
template <typename E> struct ElfShdr;
|
||||
@ -39,7 +40,7 @@ static constexpr u32 R_NONE = 0;
|
||||
|
||||
enum class MachineType {
|
||||
NONE, X86_64, I386, ARM64, ARM32, RV64LE, RV64BE, RV32LE, RV32BE,
|
||||
PPC64V1, PPC64V2, SPARC64, S390X
|
||||
PPC64V1, PPC64V2, S390X, SPARC64, M68K
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, MachineType mt) {
|
||||
@ -55,8 +56,9 @@ inline std::ostream &operator<<(std::ostream &out, MachineType mt) {
|
||||
case MachineType::RV32BE: out << "riscv32be"; break;
|
||||
case MachineType::PPC64V1: out << "ppc64v1"; break;
|
||||
case MachineType::PPC64V2: out << "ppc64v2"; break;
|
||||
case MachineType::SPARC64: out << "sparc64"; break;
|
||||
case MachineType::S390X: out << "s390x"; break;
|
||||
case MachineType::SPARC64: out << "sparc64"; break;
|
||||
case MachineType::M68K: out << "m68k"; break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@ -179,6 +181,7 @@ static constexpr u32 EV_CURRENT = 1;
|
||||
|
||||
static constexpr u32 EM_NONE = 0;
|
||||
static constexpr u32 EM_386 = 3;
|
||||
static constexpr u32 EM_68K = 4;
|
||||
static constexpr u32 EM_PPC64 = 21;
|
||||
static constexpr u32 EM_S390X = 22;
|
||||
static constexpr u32 EM_ARM = 40;
|
||||
@ -1649,6 +1652,96 @@ inline std::string rel_to_string<S390X>(u32 r_type) {
|
||||
return "unknown (" + std::to_string(r_type) + ")";
|
||||
}
|
||||
|
||||
static constexpr u32 R_68K_NONE = 0;
|
||||
static constexpr u32 R_68K_32 = 1;
|
||||
static constexpr u32 R_68K_16 = 2;
|
||||
static constexpr u32 R_68K_8 = 3;
|
||||
static constexpr u32 R_68K_PC32 = 4;
|
||||
static constexpr u32 R_68K_PC16 = 5;
|
||||
static constexpr u32 R_68K_PC8 = 6;
|
||||
static constexpr u32 R_68K_GOTPCREL32 = 7;
|
||||
static constexpr u32 R_68K_GOTPCREL16 = 8;
|
||||
static constexpr u32 R_68K_GOTPCREL8 = 9;
|
||||
static constexpr u32 R_68K_GOTOFF32 = 10;
|
||||
static constexpr u32 R_68K_GOTOFF16 = 11;
|
||||
static constexpr u32 R_68K_GOTOFF8 = 12;
|
||||
static constexpr u32 R_68K_PLT32 = 13;
|
||||
static constexpr u32 R_68K_PLT16 = 14;
|
||||
static constexpr u32 R_68K_PLT8 = 15;
|
||||
static constexpr u32 R_68K_PLTOFF32 = 16;
|
||||
static constexpr u32 R_68K_PLTOFF16 = 17;
|
||||
static constexpr u32 R_68K_PLTOFF8 = 18;
|
||||
static constexpr u32 R_68K_COPY = 19;
|
||||
static constexpr u32 R_68K_GLOB_DAT = 20;
|
||||
static constexpr u32 R_68K_JMP_SLOT = 21;
|
||||
static constexpr u32 R_68K_RELATIVE = 22;
|
||||
static constexpr u32 R_68K_TLS_GD32 = 25;
|
||||
static constexpr u32 R_68K_TLS_GD16 = 26;
|
||||
static constexpr u32 R_68K_TLS_GD8 = 27;
|
||||
static constexpr u32 R_68K_TLS_LDM32 = 28;
|
||||
static constexpr u32 R_68K_TLS_LDM16 = 29;
|
||||
static constexpr u32 R_68K_TLS_LDM8 = 30;
|
||||
static constexpr u32 R_68K_TLS_LDO32 = 31;
|
||||
static constexpr u32 R_68K_TLS_LDO16 = 32;
|
||||
static constexpr u32 R_68K_TLS_LDO8 = 33;
|
||||
static constexpr u32 R_68K_TLS_IE32 = 34;
|
||||
static constexpr u32 R_68K_TLS_IE16 = 35;
|
||||
static constexpr u32 R_68K_TLS_IE8 = 36;
|
||||
static constexpr u32 R_68K_TLS_LE32 = 37;
|
||||
static constexpr u32 R_68K_TLS_LE16 = 38;
|
||||
static constexpr u32 R_68K_TLS_LE8 = 39;
|
||||
static constexpr u32 R_68K_TLS_DTPMOD32 = 40;
|
||||
static constexpr u32 R_68K_TLS_DTPREL32 = 41;
|
||||
static constexpr u32 R_68K_TLS_TPREL32 = 42;
|
||||
|
||||
template <>
|
||||
inline std::string rel_to_string<M68K>(u32 r_type) {
|
||||
switch (r_type) {
|
||||
case R_68K_NONE: return "R_68K_NONE";
|
||||
case R_68K_32: return "R_68K_32";
|
||||
case R_68K_16: return "R_68K_16";
|
||||
case R_68K_8: return "R_68K_8";
|
||||
case R_68K_PC32: return "R_68K_PC32";
|
||||
case R_68K_PC16: return "R_68K_PC16";
|
||||
case R_68K_PC8: return "R_68K_PC8";
|
||||
case R_68K_GOTPCREL32: return "R_68K_GOTPCREL32";
|
||||
case R_68K_GOTPCREL16: return "R_68K_GOTPCREL16";
|
||||
case R_68K_GOTPCREL8: return "R_68K_GOTPCREL8";
|
||||
case R_68K_GOTOFF32: return "R_68K_GOTOFF32";
|
||||
case R_68K_GOTOFF16: return "R_68K_GOTOFF16";
|
||||
case R_68K_GOTOFF8: return "R_68K_GOTOFF8";
|
||||
case R_68K_PLT32: return "R_68K_PLT32";
|
||||
case R_68K_PLT16: return "R_68K_PLT16";
|
||||
case R_68K_PLT8: return "R_68K_PLT8";
|
||||
case R_68K_PLTOFF32: return "R_68K_PLTOFF32";
|
||||
case R_68K_PLTOFF16: return "R_68K_PLTOFF16";
|
||||
case R_68K_PLTOFF8: return "R_68K_PLTOFF8";
|
||||
case R_68K_COPY: return "R_68K_COPY";
|
||||
case R_68K_GLOB_DAT: return "R_68K_GLOB_DAT";
|
||||
case R_68K_JMP_SLOT: return "R_68K_JMP_SLOT";
|
||||
case R_68K_RELATIVE: return "R_68K_RELATIVE";
|
||||
case R_68K_TLS_GD32: return "R_68K_TLS_GD32";
|
||||
case R_68K_TLS_GD16: return "R_68K_TLS_GD16";
|
||||
case R_68K_TLS_GD8: return "R_68K_TLS_GD8";
|
||||
case R_68K_TLS_LDM32: return "R_68K_TLS_LDM32";
|
||||
case R_68K_TLS_LDM16: return "R_68K_TLS_LDM16";
|
||||
case R_68K_TLS_LDM8: return "R_68K_TLS_LDM8";
|
||||
case R_68K_TLS_LDO32: return "R_68K_TLS_LDO32";
|
||||
case R_68K_TLS_LDO16: return "R_68K_TLS_LDO16";
|
||||
case R_68K_TLS_LDO8: return "R_68K_TLS_LDO8";
|
||||
case R_68K_TLS_IE32: return "R_68K_TLS_IE32";
|
||||
case R_68K_TLS_IE16: return "R_68K_TLS_IE16";
|
||||
case R_68K_TLS_IE8: return "R_68K_TLS_IE8";
|
||||
case R_68K_TLS_LE32: return "R_68K_TLS_LE32";
|
||||
case R_68K_TLS_LE16: return "R_68K_TLS_LE16";
|
||||
case R_68K_TLS_LE8: return "R_68K_TLS_LE8";
|
||||
case R_68K_TLS_DTPMOD32: return "R_68K_TLS_DTPMOD32";
|
||||
case R_68K_TLS_DTPREL32: return "R_68K_TLS_DTPREL32";
|
||||
case R_68K_TLS_TPREL32: return "R_68K_TLS_TPREL32";
|
||||
}
|
||||
return "unknown (" + std::to_string(r_type) + ")";
|
||||
}
|
||||
|
||||
//
|
||||
// DWARF data types
|
||||
//
|
||||
@ -2341,6 +2434,9 @@ static constexpr bool is_sparc = std::is_same_v<E, SPARC64>;
|
||||
template <typename E>
|
||||
static constexpr bool is_s390x = std::is_same_v<E, S390X>;
|
||||
|
||||
template <typename E>
|
||||
static constexpr bool is_m68k = std::is_same_v<E, M68K>;
|
||||
|
||||
struct X86_64 {
|
||||
static constexpr u32 R_COPY = R_X86_64_COPY;
|
||||
static constexpr u32 R_GLOB_DAT = R_X86_64_GLOB_DAT;
|
||||
@ -2795,4 +2891,39 @@ template <> struct ElfVerdaux<SPARC64> : EBVerdaux {};
|
||||
template <> struct ElfChdr<SPARC64> : EB64Chdr {};
|
||||
template <> struct ElfNhdr<SPARC64> : EBNhdr {};
|
||||
|
||||
struct M68K {
|
||||
static constexpr u32 R_COPY = R_68K_COPY;
|
||||
static constexpr u32 R_GLOB_DAT = R_68K_GLOB_DAT;
|
||||
static constexpr u32 R_JUMP_SLOT = R_68K_JMP_SLOT;
|
||||
static constexpr u32 R_ABS = R_68K_32;
|
||||
static constexpr u32 R_RELATIVE = R_68K_RELATIVE;
|
||||
static constexpr u32 R_IRELATIVE = R_68K_NONE; // m68k does not support ifunc
|
||||
static constexpr u32 R_DTPOFF = R_68K_TLS_DTPREL32;
|
||||
static constexpr u32 R_TPOFF = R_68K_TLS_TPREL32;
|
||||
static constexpr u32 R_DTPMOD = R_68K_TLS_DTPMOD32;
|
||||
|
||||
static constexpr MachineType machine_type = MachineType::M68K;
|
||||
static constexpr bool is_64 = false;
|
||||
static constexpr bool is_le = false;
|
||||
static constexpr u32 page_size = 8192;
|
||||
static constexpr u32 e_machine = EM_68K;
|
||||
static constexpr u32 plt_hdr_size = 18;
|
||||
static constexpr u32 plt_size = 14;
|
||||
static constexpr u32 pltgot_size = 8;
|
||||
static constexpr u32 tls_dtp_offset = 0x8000;
|
||||
};
|
||||
|
||||
template <> struct ElfSym<M68K> : EB32Sym {};
|
||||
template <> struct ElfShdr<M68K> : EB32Shdr {};
|
||||
template <> struct ElfEhdr<M68K> : EB32Ehdr {};
|
||||
template <> struct ElfPhdr<M68K> : EB32Phdr {};
|
||||
template <> struct ElfRel<M68K> : EB32Rela { using EB32Rela::EB32Rela; };
|
||||
template <> struct ElfDyn<M68K> : EB32Dyn {};
|
||||
template <> struct ElfVerneed<M68K> : EBVerneed {};
|
||||
template <> struct ElfVernaux<M68K> : EBVernaux {};
|
||||
template <> struct ElfVerdef<M68K> : EBVerdef {};
|
||||
template <> struct ElfVerdaux<M68K> : EBVerdaux {};
|
||||
template <> struct ElfChdr<M68K> : EB32Chdr {};
|
||||
template <> struct ElfNhdr<M68K> : EBNhdr {};
|
||||
|
||||
} // namespace mold::elf
|
||||
|
@ -62,6 +62,8 @@ static MachineType get_machine_type(Context<E> &ctx, MappedFile<Context<E>> *mf)
|
||||
return MachineType::S390X;
|
||||
case EM_SPARC64:
|
||||
return MachineType::SPARC64;
|
||||
case EM_68K:
|
||||
return MachineType::M68K;
|
||||
default:
|
||||
return MachineType::NONE;
|
||||
}
|
||||
@ -397,6 +399,8 @@ static int redo_main(int argc, char **argv, MachineType ty) {
|
||||
return elf_main<S390X>(argc, argv);
|
||||
case MachineType::SPARC64:
|
||||
return elf_main<SPARC64>(argc, argv);
|
||||
case MachineType::M68K:
|
||||
return elf_main<M68K>(argc, argv);
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
@ -792,6 +796,7 @@ extern template int elf_main<PPC64V1>(int, char **);
|
||||
extern template int elf_main<PPC64V2>(int, char **);
|
||||
extern template int elf_main<S390X>(int, char **);
|
||||
extern template int elf_main<SPARC64>(int, char **);
|
||||
extern template int elf_main<M68K>(int, char **);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return elf_main<X86_64>(argc, argv);
|
||||
|
@ -178,12 +178,12 @@ static void init_thread_pointers(Context<E> &ctx, ElfPhdr<E> phdr) {
|
||||
// template image when copying TLVs to per-thread area, so we need
|
||||
// to offset it.
|
||||
//
|
||||
// On PPC64, TP is 0x7000 (28 KiB) past the beginning of the TLV block
|
||||
// to maximize the addressable range for load/store instructions with
|
||||
// 16-bits signed immediates. It's not exactly 0x8000 (32 KiB) off
|
||||
// because there's a small implementation-defined piece of data before
|
||||
// the TLV block, and the runtime wants to access them efficiently
|
||||
// too.
|
||||
// On PPC64 and m68k, TP is 0x7000 (28 KiB) past the beginning of the
|
||||
// TLV block to maximize the addressable range for load/store
|
||||
// instructions with 16-bits signed immediates. It's not exactly 0x8000
|
||||
// (32 KiB) off because there's a small implementation-defined piece of
|
||||
// data before the TLV block, and the runtime wants to access them
|
||||
// efficiently too.
|
||||
//
|
||||
// RISC-V just uses the beginning of the TLV block as TP. RISC-V
|
||||
// load/store instructions usually take 12-bits signed immediates,
|
||||
@ -193,7 +193,7 @@ static void init_thread_pointers(Context<E> &ctx, ElfPhdr<E> phdr) {
|
||||
ctx.tp_addr = align_to(phdr.p_vaddr + phdr.p_memsz, phdr.p_align);
|
||||
} else if constexpr (is_arm<E>) {
|
||||
ctx.tp_addr = align_down(phdr.p_vaddr - sizeof(Word<E>) * 2, phdr.p_align);
|
||||
} else if constexpr (is_ppc<E>) {
|
||||
} else if constexpr (is_ppc<E> || is_m68k<E>) {
|
||||
ctx.tp_addr = phdr.p_vaddr + 0x7000;
|
||||
} else {
|
||||
static_assert(is_riscv<E>);
|
||||
|
@ -97,8 +97,13 @@ FileType get_file_type(MappedFile<C> *mf) {
|
||||
elf::EB32Ehdr &ehdr = *(elf::EB32Ehdr *)data.data();
|
||||
|
||||
if (ehdr.e_type == elf::ET_REL) {
|
||||
if (is_gcc_lto_obj<elf::SPARC64>(mf))
|
||||
return FileType::GCC_LTO_OBJ;
|
||||
if (ehdr.e_ident[elf::EI_CLASS] == elf::ELFCLASS32) {
|
||||
if (is_gcc_lto_obj<elf::M68K>(mf))
|
||||
return FileType::GCC_LTO_OBJ;
|
||||
} else {
|
||||
if (is_gcc_lto_obj<elf::SPARC64>(mf))
|
||||
return FileType::GCC_LTO_OBJ;
|
||||
}
|
||||
return FileType::ELF_OBJ;
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ add_target(powerpc64-linux-gnu)
|
||||
add_target(powerpc64le-linux-gnu)
|
||||
add_target(sparc64-linux-gnu)
|
||||
add_target(s390x-linux-gnu)
|
||||
add_target(m68k-linux-gnu)
|
||||
|
||||
if(MOLD_ENABLE_QEMU_TESTS_RV32)
|
||||
add_target(riscv32-linux-gnu)
|
||||
|
@ -1,6 +1,8 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
[ $MACHINE = m68k ] && skip
|
||||
|
||||
command -v llvm-readelf >& /dev/null || skip
|
||||
|
||||
cat <<EOF | $CC -o $t/a.o -fPIC -c -xc -
|
||||
|
Loading…
Reference in New Issue
Block a user