Skip to content

Commit

Permalink
Handle R_LARCH_RELAX
Browse files Browse the repository at this point in the history
  • Loading branch information
rui314 committed Jul 27, 2024
1 parent 34ed39c commit 98a7cff
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 6 deletions.
46 changes: 44 additions & 2 deletions elf/arch-loongarch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
dynrel = (ElfRel<E> *)(ctx.buf + ctx.reldyn->shdr.sh_offset +
file.reldyn_offset + this->reldyn_offset);

auto get_r_delta = [&](i64 idx) {
return extra.r_deltas.empty() ? 0 : extra.r_deltas[idx];
};

for (i64 i = 0; i < rels.size(); i++) {
const ElfRel<E> &rel = rels[i];

Expand All @@ -247,7 +251,9 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
u8 *loc = base + rel.r_offset;
i64 r_offset = rel.r_offset - get_r_delta(i);
[[maybe_unused]] i64 removed_bytes = get_r_delta(i + 1) - get_r_delta(i);
u8 *loc = base + r_offset;

auto check = [&](i64 val, i64 lo, i64 hi) {
if (val < lo || hi <= val)
Expand Down Expand Up @@ -280,7 +286,7 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {

u64 S = sym.get_addr(ctx);
u64 A = rel.r_addend;
u64 P = get_addr() + rel.r_offset;
u64 P = get_addr() + r_offset;
u64 G = get_got_idx() * sizeof(Word<E>);
u64 GOT = ctx.got->shdr.sh_addr;

Expand Down Expand Up @@ -663,6 +669,42 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
}
}

template <>
void shrink_section(Context<E> &ctx, InputSection<E> &isec, bool use_rvc) {
std::span<const ElfRel<E>> rels = isec.get_rels(ctx);
isec.extra.r_deltas.resize(rels.size() + 1);
i64 delta = 0;

for (i64 i = 0; i < rels.size(); i++) {
const ElfRel<E> &r = rels[i];
isec.extra.r_deltas[i] = delta;

if (r.r_type == R_LARCH_ALIGN) {
i64 nop_size;
if (r.r_sym) {
if (r.r_addend & ~0xff)
Fatal(ctx) << isec << ": ternary R_LARCH_ALIGN is not supported: " << i;
nop_size = (1 << (r.r_addend & 0xff)) - 4;
} else {
nop_size = r.r_addend;
}

u64 loc = isec.get_addr() + r.r_offset - delta;
u64 next_loc = loc + nop_size;
u64 alignment = nop_size + 4;

if (!has_single_bit(alignment))
Fatal(ctx) << isec << ": R_LARCH_ALIGN: invalid nop sequence: " << i;

delta += next_loc - align_to(loc, alignment);
continue;
}
}

isec.extra.r_deltas[rels.size()] = delta;
isec.sh_size -= delta;
}

template <>
void Thunk<E>::copy_buf(Context<E> &ctx) {
constexpr ul32 insn[] = {
Expand Down
2 changes: 1 addition & 1 deletion elf/input-sections.cc
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ void InputSection<E>::write_to(Context<E> &ctx, u8 *buf) {
// an atomic unit of copying because of relaxation. That is, some
// relocations are allowed to remove bytes from the middle of a
// section and shrink the overall size of it.
if constexpr (is_riscv<E>) {
if constexpr (is_riscv<E> || is_loongarch<E>) {
if (extra.r_deltas.empty()) {
// If a section is not relaxed, we can copy it as a one big chunk.
copy_contents(ctx, buf);
Expand Down
2 changes: 1 addition & 1 deletion elf/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ int elf_main(int argc, char **argv) {
// that they can jump to anywhere in ±2 GiB by default. They may
// be replaced with shorter instruction sequences if destinations
// are close enough. Do this optimization.
if constexpr (is_riscv<E>)
if constexpr (is_riscv<E> || is_loongarch<E>)
filesize = shrink_sections(ctx);

// At this point, memory layout is fixed.
Expand Down
8 changes: 7 additions & 1 deletion elf/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ struct FdeRecord {
template <typename E>
struct InputSectionExtras {};

template <needs_thunk E>
template <typename E> requires (needs_thunk<E> && !is_loongarch<E>)
struct InputSectionExtras<E> {
std::vector<ThunkRef> thunk_refs;
};
Expand All @@ -242,6 +242,12 @@ struct InputSectionExtras<E> {
std::vector<i32> r_deltas;
};

template <is_loongarch E>
struct InputSectionExtras<E> {
std::vector<ThunkRef> thunk_refs;
std::vector<i32> r_deltas;
};

// InputSection represents a section in an input object file.
template <typename E>
class __attribute__((aligned(4))) InputSection {
Expand Down
3 changes: 2 additions & 1 deletion elf/shrink-sections.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Shrink sections by interpreting relocations.

#if MOLD_RV64LE || MOLD_RV64BE || MOLD_RV32LE || MOLD_RV32BE
#if MOLD_RV64LE || MOLD_RV64BE || MOLD_RV32LE || MOLD_RV32BE || \
MOLD_LOONGARCH64 || MOLD_LOONGARCH32

#include "mold.h"

Expand Down
1 change: 1 addition & 0 deletions elf/thunks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ void OutputSection<E>::create_range_extension_thunks(Context<E> &ctx) {
// haven't.
for (InputSection<E> *isec : m)
isec->offset = -1;
thunks.clear();

// We create thunks from the beginning of the section to the end.
// We manage progress using four offsets which increase monotonically.
Expand Down

0 comments on commit 98a7cff

Please sign in to comment.