1
1
mirror of https://github.com/rui314/mold.git synced 2024-10-26 13:10:46 +03:00

Improve MIPS64 support

This commit is contained in:
Rui Ueyama 2023-07-16 16:59:06 +09:00
parent 000e395c07
commit 761c341c19
4 changed files with 120 additions and 64 deletions

View File

@ -69,7 +69,7 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
auto write_combined = [&](u64 val) {
if (rel.r_type2 == R_MIPS_64 && rel.r_type3 == R_NONE) {
*(U64<E> *)loc |= val;
*(U64<E> *)loc = val;
} else if (rel.r_type2 == R_MIPS_SUB && rel.r_type3 == R_MIPS_HI16) {
*(U32<E> *)loc |= ((-val + BIAS) >> 16) & 0xffff;
} else if (rel.r_type2 == R_MIPS_SUB && rel.r_type3 == R_MIPS_LO16) {
@ -141,6 +141,18 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
case R_MIPS_TLS_GOTTPREL:
write_lo16(ctx.extra.got->get_gottp_addr(ctx, sym) - GP);
break;
case R_MIPS_TLS_DTPREL_HI16:
write_hi16(S + A - ctx.dtp_addr);
break;
case R_MIPS_TLS_DTPREL_LO16:
write_lo16(S + A - ctx.dtp_addr);
break;
case R_MIPS_TLS_GD:
write_lo16(ctx.extra.got->get_tlsgd_addr(ctx, sym) + A - GP);
break;
case R_MIPS_TLS_LDM:
write_lo16(ctx.extra.got->get_tlsld_addr(ctx) + A - GP);
break;
default:
unreachable();
}
@ -196,25 +208,42 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
switch (rel.r_type) {
case R_MIPS_GOT_DISP:
case R_MIPS_CALL16:
ctx.extra.got->add_got_symbol(sym, rel.r_addend);
case R_MIPS_CALL16: {
std::scoped_lock lock(ctx.extra.got->mu);
ctx.extra.got->got_syms.push_back({&sym, rel.r_addend});
break;
case R_MIPS_GOT_PAGE:
ctx.extra.got->add_gotpage_symbol(sym, rel.r_addend);
}
case R_MIPS_GOT_PAGE: {
std::scoped_lock lock(ctx.extra.got->mu);
ctx.extra.got->gotpage_syms.push_back({&sym, rel.r_addend});
break;
case R_MIPS_TLS_GOTTPREL:
}
case R_MIPS_TLS_GOTTPREL: {
std::scoped_lock lock(ctx.extra.got->mu);
assert(rel.r_addend == 0);
ctx.extra.got->add_gottp_symbol(sym);
ctx.extra.got->gottp_syms.push_back(&sym);
break;
}
case R_MIPS_TLS_TPREL_HI16:
case R_MIPS_TLS_TPREL_LO16:
check_tlsle(ctx, sym, rel);
break;
case R_MIPS_TLS_GD: {
std::scoped_lock lock(ctx.extra.got->mu);
assert(rel.r_addend == 0);
ctx.extra.got->tlsgd_syms.push_back(&sym);
break;
}
case R_MIPS_TLS_LDM:
ctx.extra.got->needs_tlsld = true;
break;
case R_MIPS_64:
case R_MIPS_GPREL16:
case R_MIPS_GPREL32:
case R_MIPS_GOT_OFST:
case R_MIPS_JALR:
case R_MIPS_TLS_DTPREL_HI16:
case R_MIPS_TLS_DTPREL_LO16:
break;
default:
Error(ctx) << *this << ": unknown relocation: " << rel;
@ -222,24 +251,6 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
}
}
template <typename E>
void MipsGotSection<E>::add_got_symbol(Symbol<E> &sym, i64 addend) {
std::scoped_lock lock(mu);
got_syms.push_back({&sym, addend});
}
template <typename E>
void MipsGotSection<E>::add_gotpage_symbol(Symbol<E> &sym, i64 addend) {
std::scoped_lock lock(mu);
gotpage_syms.push_back({&sym, addend});
}
template <typename E>
void MipsGotSection<E>::add_gottp_symbol(Symbol<E> &sym) {
std::scoped_lock lock(mu);
gottp_syms.push_back(&sym);
}
template <typename E>
bool MipsGotSection<E>::SymbolAddend::operator<(const SymbolAddend &other) const {
return std::tuple(sym->file->priority, sym->sym_idx, addend) <
@ -263,7 +274,8 @@ MipsGotSection<E>::get_got_addr(Context<E> &ctx, Symbol<E> &sym, i64 addend) con
auto it = std::lower_bound(got_syms.begin(), got_syms.end(),
SymbolAddend{&sym, addend});
assert(it != got_syms.end());
return this->shdr.sh_addr + (it - got_syms.begin()) * sizeof(Word<E>);
i64 idx = it - got_syms.begin();
return this->shdr.sh_addr + idx * sizeof(Word<E>);
}
template <typename E>
@ -272,8 +284,8 @@ u64 MipsGotSection<E>::get_gotpage_got_addr(Context<E> &ctx, Symbol<E> &sym,
auto it = std::lower_bound(gotpage_syms.begin(), gotpage_syms.end(),
SymbolAddend{&sym, addend});
assert(it != gotpage_syms.end());
i64 idx = it - gotpage_syms.begin();
return this->shdr.sh_addr + (got_syms.size() + idx) * sizeof(Word<E>);
i64 idx = got_syms.size() + (it - gotpage_syms.begin());
return this->shdr.sh_addr + idx * sizeof(Word<E>);
}
template <typename E>
@ -285,63 +297,104 @@ u64 MipsGotSection<E>::get_gotpage_page_addr(Context<E> &ctx, Symbol<E> &sym,
return it->get_addr(ctx);
}
template <typename E>
u64 MipsGotSection<E>::get_tlsgd_addr(Context<E> &ctx, Symbol<E> &sym) const {
auto it = std::lower_bound(tlsgd_syms.begin(), tlsgd_syms.end(),
&sym, compare<E>);
assert(it != tlsgd_syms.end());
i64 idx = got_syms.size() + gotpage_syms.size() + (it - tlsgd_syms.begin()) * 2;
return this->shdr.sh_addr + idx * sizeof(Word<E>);
}
template <typename E>
u64 MipsGotSection<E>::get_gottp_addr(Context<E> &ctx, Symbol<E> &sym) const {
auto it = std::lower_bound(gottp_syms.begin(), gottp_syms.end(),
&sym, compare<E>);
assert(it != gottp_syms.end());
i64 idx = it - gottp_syms.begin();
return this->shdr.sh_addr +
(got_syms.size() + gotpage_syms.size() + idx) * sizeof(Word<E>);
i64 idx = got_syms.size() + gotpage_syms.size() + tlsgd_syms.size() * 2 +
(it - gottp_syms.begin());
return this->shdr.sh_addr + idx * sizeof(Word<E>);
}
template <typename E>
u64 MipsGotSection<E>::get_tlsld_addr(Context<E> &ctx) const {
assert(needs_tlsld);
i64 idx = got_syms.size() + gotpage_syms.size() + tlsgd_syms.size() * 2 +
gottp_syms.size();
return this->shdr.sh_addr + idx * sizeof(Word<E>);
}
template <typename E>
std::vector<typename MipsGotSection<E>::GotEntry>
MipsGotSection<E>::get_got_entries(Context<E> &ctx) const {
std::vector<GotEntry> entries;
auto add = [&](GotEntry ent) { entries.push_back(ent); };
// Create GOT entries for ordinary symbols
for (const SymbolAddend &ent : got_syms) {
// If a symbol is imported, let the dynamic linker to resolve it.
if (ent.sym->is_imported) {
entries.push_back({0, E::R_GLOB_DAT, ent.sym});
add({0, E::R_GLOB_DAT, ent.sym});
continue;
}
// If we know an address at link-time, fill that GOT entry now.
// It may need a base relocation, though.
if (ctx.arg.pic && ent.sym->is_relative())
entries.push_back({ent.get_addr(ctx, NO_PLT), E::R_RELATIVE});
add({ent.get_addr(ctx, NO_PLT), E::R_RELATIVE});
else
entries.push_back({ent.get_addr(ctx, NO_PLT)});
add({ent.get_addr(ctx, NO_PLT)});
}
// Create GOT entries for GOT_PAGE and GOT_OFST relocs
for (const SymbolAddend &ent : gotpage_syms) {
if (ctx.arg.pic && ent.sym->is_relative())
entries.push_back({ent.get_addr(ctx), E::R_RELATIVE});
add({ent.get_addr(ctx), E::R_RELATIVE});
else
entries.push_back({ent.get_addr(ctx)});
add({ent.get_addr(ctx)});
}
// Create GOT entries for TLVs
for (Symbol<E> *sym : tlsgd_syms) {
if (sym->is_imported) {
// If a symbol is imported, let the dynamic linker to resolve it.
add({0, E::R_DTPMOD, sym});
add({0, E::R_DTPOFF, sym});
} else if (ctx.arg.shared) {
// If we are creating a shared library, we know the TLV's offset
// within the current TLS block. We don't know the module ID though.
add({0, E::R_DTPMOD});
add({sym->get_addr(ctx) - ctx.dtp_addr});
} else {
// If we are creating an executable, we know both the module ID and the
// offset. Module ID 1 indicates the main executable.
add({1});
add({sym->get_addr(ctx) - ctx.dtp_addr});
}
}
for (Symbol<E> *sym : gottp_syms) {
// If we know nothing about the symbol, let the dynamic linker
// to fill the GOT entry.
if (sym->is_imported) {
entries.push_back({0, E::R_TPOFF, sym});
continue;
// If we know nothing about the symbol, let the dynamic linker
// to fill the GOT entry.
add({0, E::R_TPOFF, sym});
} else if (ctx.arg.shared) {
// If we know the offset within the current thread vector,
// let the dynamic linker to adjust it.
add({sym->get_addr(ctx) - ctx.tls_begin, E::R_TPOFF});
} else {
// Otherwise, we know the offset from the thread pointer (TP) at
// link-time, so we can fill the GOT entry directly.
add({sym->get_addr(ctx) - ctx.tp_addr});
}
}
// If we know the offset within the current thread vector,
// let the dynamic linker to adjust it.
if (ctx.arg.shared) {
entries.push_back({sym->get_addr(ctx) - ctx.tls_begin, E::R_TPOFF});
continue;
}
// Otherwise, we know the offset from the thread pointer (TP) at
// link-time, so we can fill the GOT entry directly.
entries.push_back({sym->get_addr(ctx) - ctx.tp_addr});
if (needs_tlsld) {
if (ctx.arg.shared)
add({0, E::R_DTPMOD});
else
add({1}); // 1 means the main executable
add({0});
}
return entries;
@ -359,10 +412,18 @@ void MipsGotSection<E>::update_shdr(Context<E> &ctx) {
remove_duplicates(gotpage_syms);
this->shdr.sh_size += gotpage_syms.size() * sizeof(Word<E>);
// Finalize tlsgd_syms
sort(tlsgd_syms, compare<E>);
remove_duplicates(tlsgd_syms);
this->shdr.sh_size += tlsgd_syms.size() * 2 * sizeof(Word<E>);
// Finalize gottp_syms
sort(gottp_syms, compare<E>);
remove_duplicates(gottp_syms);
this->shdr.sh_size += gottp_syms.size() * sizeof(Word<E>);
if (needs_tlsld)
this->shdr.sh_size += 2 * sizeof(Word<E>);
}
template <typename E>

View File

@ -1738,15 +1738,9 @@ struct ElfRel<SPARC64> {
ib64 r_addend;
};
static u8 get_mips_r_type2(u8 r_type) {
switch (r_type) {
case R_MIPS_REL32:
case R_MIPS_GLOB_DAT:
case R_MIPS_TLS_DTPMOD64:
case R_MIPS_TLS_DTPREL64:
case R_MIPS_TLS_TPREL64:
static inline u8 get_mips_r_type2(u8 r_type) {
if (r_type == R_MIPS_REL32 || r_type == R_MIPS_GLOB_DAT)
return R_MIPS_64;
}
return R_NONE;
}

View File

@ -505,9 +505,9 @@ public:
void populate_symtab(Context<E> &ctx) override;
std::vector<Symbol<E> *> got_syms;
std::vector<Symbol<E> *> gottp_syms;
std::vector<Symbol<E> *> tlsgd_syms;
std::vector<Symbol<E> *> tlsdesc_syms;
std::vector<Symbol<E> *> gottp_syms;
u32 tlsld_idx = -1;
void construct_relr(Context<E> &ctx);
@ -1548,14 +1548,12 @@ public:
this->shdr.sh_size = 8;
}
void add_got_symbol(Symbol<E> &sym, i64 addend);
void add_gotpage_symbol(Symbol<E> &sym, i64 addend);
void add_gottp_symbol(Symbol<E> &sym);
u64 get_got_addr(Context<E> &ctx, Symbol<E> &sym, i64 addend) const;
u64 get_gotpage_got_addr(Context<E> &ctx, Symbol<E> &sym, i64 addend) const;
u64 get_gotpage_page_addr(Context<E> &ctx, Symbol<E> &sym, i64 addend) const;
u64 get_gottp_addr(Context<E> &ctx, Symbol<E> &sym) const;
u64 get_tlsgd_addr(Context<E> &ctx, Symbol<E> &sym) const;
u64 get_tlsld_addr(Context<E> &ctx) const;
void update_shdr(Context<E> &ctx) override;
i64 get_reldyn_size(Context<E> &ctx) const override;
@ -1576,12 +1574,13 @@ public:
i64 addend;
};
private:
std::vector<GotEntry> get_got_entries(Context<E> &ctx) const;
std::vector<SymbolAddend> got_syms;
std::vector<SymbolAddend> gotpage_syms;
std::vector<Symbol<E> *> tlsgd_syms;
std::vector<Symbol<E> *> gottp_syms;
std::atomic_bool needs_tlsld = false;
std::mutex mu;
};

View File

@ -6,6 +6,8 @@
[ $MACHINE = ppc64le ] && skip
[ $MACHINE = s390x ] && skip
[ $MACHINE = alpha ] && skip
[ $MACHINE = mips64el ] && skip
[ $MACHINE = mips64 ] && skip
cat <<EOF | $CC -fPIC -c -o $t/a.o -xassembler -
.globl foo