Skip to content

Commit

Permalink
Change how we handle word-size absolute relocations
Browse files Browse the repository at this point in the history
Word-size absolute relocations, such as R_X86_64_64, are special from
the linker's point of view because only such symbols can be promoted
to dynamic symbols. This patch handles them separately.
  • Loading branch information
rui314 committed Sep 14, 2024
1 parent 7734a93 commit 431fc39
Show file tree
Hide file tree
Showing 19 changed files with 219 additions and 482 deletions.
15 changes: 2 additions & 13 deletions src/arch-alpha.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,6 @@ 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)
Expand All @@ -102,9 +97,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
u64 GP = ctx.got->shdr.sh_addr + 0x8000;

switch (rel.r_type) {
case R_ALPHA_REFQUAD:
apply_dyn_absrel(ctx, sym, rel, loc, S, A, P, &dynrel);
break;
case R_ALPHA_GPREL32:
*(ul32 *)loc = S + A - GP;
break;
Expand Down Expand Up @@ -151,6 +143,7 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
case R_ALPHA_TPRELLO:
*(ul16 *)loc = S + A - ctx.tp_addr;
break;
case R_ALPHA_REFQUAD:
case R_ALPHA_LITUSE:
case R_ALPHA_HINT:
break;
Expand Down Expand Up @@ -202,8 +195,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
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++) {
Expand All @@ -217,9 +208,6 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
Error(ctx) << sym << ": GNU ifunc symbol is not supported on Alpha";

switch (rel.r_type) {
case R_ALPHA_REFQUAD:
scan_dyn_absrel(ctx, sym, rel);
break;
case R_ALPHA_LITERAL:
if (rel.r_addend)
ctx.extra.got->add_symbol(sym, rel.r_addend);
Expand All @@ -246,6 +234,7 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_ALPHA_TPRELLO:
check_tlsle(ctx, sym, rel);
break;
case R_ALPHA_REFQUAD:
case R_ALPHA_GPREL32:
case R_ALPHA_LITUSE:
case R_ALPHA_GPDISP:
Expand Down
20 changes: 5 additions & 15 deletions src/arch-arm32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,6 @@ 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);

auto get_tls_trampoline_addr = [&, i = 0](u64 addr) mutable {
for (; i < output_section->thunks.size(); i++) {
i64 disp = output_section->shdr.sh_addr + output_section->thunks[i]->offset -
Expand Down Expand Up @@ -299,7 +294,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
switch (rel.r_type) {
case R_ARM_ABS32:
case R_ARM_TARGET1:
apply_dyn_absrel(ctx, sym, rel, loc, S, A, P, &dynrel);
break;
case R_ARM_REL32:
*(ul32 *)loc = S + A - P;
Expand Down Expand Up @@ -586,8 +580,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
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);

// Scan relocations
Expand All @@ -602,12 +594,6 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
sym.flags |= NEEDS_GOT | NEEDS_PLT;

switch (rel.r_type) {
case R_ARM_ABS32:
case R_ARM_MOVT_ABS:
case R_ARM_THM_MOVT_ABS:
case R_ARM_TARGET1:
scan_dyn_absrel(ctx, sym, rel);
break;
case R_ARM_MOVW_ABS_NC:
case R_ARM_THM_MOVW_ABS_NC:
scan_absrel(ctx, sym, rel);
Expand Down Expand Up @@ -646,6 +632,10 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_ARM_TLS_LE32:
check_tlsle(ctx, sym, rel);
break;
case R_ARM_ABS32:
case R_ARM_MOVT_ABS:
case R_ARM_THM_MOVT_ABS:
case R_ARM_TARGET1:
case R_ARM_REL32:
case R_ARM_BASE_PREL:
case R_ARM_GOTOFF32:
Expand Down Expand Up @@ -762,7 +752,7 @@ std::vector<u8> Arm32ExidxSection::get_contents(Context<E> &ctx) {
std::vector<u8> buf(output_section.shdr.sh_size);

output_section.shdr.sh_addr = this->shdr.sh_addr;
output_section.write_to(ctx, buf.data());
output_section.write_to(ctx, buf.data(), nullptr);

// .ARM.exidx records consists of a signed 31-bit relative address
// and a 32-bit value. The relative address indicates the start
Expand Down
12 changes: 1 addition & 11 deletions src/arch-arm64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,6 @@ 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)
Expand All @@ -173,7 +168,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {

switch (rel.r_type) {
case R_AARCH64_ABS64:
apply_dyn_absrel(ctx, sym, rel, loc, S, A, P, &dynrel);
break;
case R_AARCH64_LDST8_ABS_LO12_NC:
case R_AARCH64_ADD_ABS_LO12_NC:
Expand Down Expand Up @@ -490,8 +484,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
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);

// Scan relocations
Expand All @@ -507,9 +499,6 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
sym.flags |= NEEDS_GOT | NEEDS_PLT;

switch (rel.r_type) {
case R_AARCH64_ABS64:
scan_dyn_absrel(ctx, sym, rel);
break;
case R_AARCH64_MOVW_UABS_G3:
scan_absrel(ctx, sym, rel);
break;
Expand Down Expand Up @@ -569,6 +558,7 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
check_tlsle(ctx, sym, rel);
break;
case R_AARCH64_ABS64:
case R_AARCH64_ADD_ABS_LO12_NC:
case R_AARCH64_ADR_PREL_LO21:
case R_AARCH64_CONDBR19:
Expand Down
12 changes: 1 addition & 11 deletions src/arch-i386.cc
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,6 @@ 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)
Expand Down Expand Up @@ -322,7 +317,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
*(ul16 *)loc = S + A;
break;
case R_386_32:
apply_dyn_absrel(ctx, sym, rel, loc, S, A, P, &dynrel);
break;
case R_386_PC8:
check(S + A - P, -(1 << 7), 1 << 7);
Expand Down Expand Up @@ -520,8 +514,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
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);

// Scan relocations
Expand Down Expand Up @@ -551,9 +543,6 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_386_16:
scan_absrel(ctx, sym, rel);
break;
case R_386_32:
scan_dyn_absrel(ctx, sym, rel);
break;
case R_386_PC8:
case R_386_PC16:
case R_386_PC32:
Expand Down Expand Up @@ -602,6 +591,7 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_386_TLS_LE:
check_tlsle(ctx, sym, rel);
break;
case R_386_32:
case R_386_GOTOFF:
case R_386_TLS_LDO_32:
case R_386_SIZE32:
Expand Down
21 changes: 2 additions & 19 deletions src/arch-loongarch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,6 @@ 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);

auto get_r_delta = [&](i64 idx) {
return extra.r_deltas.empty() ? 0 : extra.r_deltas[idx];
};
Expand Down Expand Up @@ -329,12 +324,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
case R_LARCH_32:
if constexpr (E::is_64)
*(ul32 *)loc = S + A;
else
apply_dyn_absrel(ctx, sym, rel, loc, S, A, P, &dynrel);
break;
case R_LARCH_64:
assert(E::is_64);
apply_dyn_absrel(ctx, sym, rel, loc, S, A, P, &dynrel);
break;
case R_LARCH_B16:
check_branch(S + A - P, -(1 << 17), 1 << 17);
Expand Down Expand Up @@ -661,6 +650,7 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
set_rj(loc, 2);
break;
}
case R_LARCH_64:
case R_LARCH_TLS_LE_ADD_R:
break;
default:
Expand Down Expand Up @@ -762,8 +752,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
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);

// Scan relocations
Expand All @@ -787,12 +775,6 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_LARCH_32:
if constexpr (E::is_64)
scan_absrel(ctx, sym, rel);
else
scan_dyn_absrel(ctx, sym, rel);
break;
case R_LARCH_64:
assert(E::is_64);
scan_dyn_absrel(ctx, sym, rel);
break;
case R_LARCH_B26:
case R_LARCH_PCALA_HI20:
Expand Down Expand Up @@ -829,6 +811,7 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_LARCH_TLS_DESC_CALL:
scan_tlsdesc(ctx, sym);
break;
case R_LARCH_64:
case R_LARCH_B16:
case R_LARCH_B21:
case R_LARCH_ABS_HI20:
Expand Down
12 changes: 1 addition & 11 deletions src/arch-m68k.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,6 @@ 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)
Expand Down Expand Up @@ -126,7 +121,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {

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);
Expand Down Expand Up @@ -251,8 +245,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
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++) {
Expand All @@ -266,9 +258,6 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
Error(ctx) << sym << ": GNU ifunc symbol is not supported on m68k";

switch (rel.r_type) {
case R_68K_32:
scan_dyn_absrel(ctx, sym, rel);
break;
case R_68K_16:
case R_68K_8:
scan_absrel(ctx, sym, rel);
Expand Down Expand Up @@ -312,6 +301,7 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_68K_TLS_LE8:
check_tlsle(ctx, sym, rel);
break;
case R_68K_32:
case R_68K_TLS_LDO32:
case R_68K_TLS_LDO16:
case R_68K_TLS_LDO8:
Expand Down
19 changes: 4 additions & 15 deletions src/arch-ppc32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,6 @@ 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);

u64 GOT2 = file.extra.got2 ? file.extra.got2->get_addr() : 0;

for (i64 i = 0; i < rels.size(); i++) {
Expand All @@ -170,10 +165,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
u64 GOT = ctx.got->shdr.sh_addr;

switch (rel.r_type) {
case R_PPC_ADDR32:
case R_PPC_UADDR32:
apply_dyn_absrel(ctx, sym, rel, loc, S, A, P, &dynrel);
break;
case R_PPC_ADDR14:
*(ub32 *)loc |= bits(S + A, 15, 2) << 2;
break;
Expand Down Expand Up @@ -275,6 +266,8 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
case R_PPC_GOT_TPREL16:
*(ub16 *)loc = sym.get_gottp_addr(ctx) - GOT;
break;
case R_PPC_ADDR32:
case R_PPC_UADDR32:
case R_PPC_TLS:
case R_PPC_TLSGD:
case R_PPC_TLSLD:
Expand Down Expand Up @@ -323,8 +316,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
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);

// Scan relocations
Expand All @@ -339,10 +330,6 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
sym.flags |= NEEDS_GOT | NEEDS_PLT;

switch (rel.r_type) {
case R_PPC_ADDR32:
case R_PPC_UADDR32:
scan_dyn_absrel(ctx, sym, rel);
break;
case R_PPC_ADDR14:
case R_PPC_ADDR16:
case R_PPC_UADDR16:
Expand Down Expand Up @@ -391,6 +378,8 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
case R_PPC_TPREL16_HA:
check_tlsle(ctx, sym, rel);
break;
case R_PPC_ADDR32:
case R_PPC_UADDR32:
case R_PPC_LOCAL24PC:
case R_PPC_TLS:
case R_PPC_TLSGD:
Expand Down
Loading

0 comments on commit 431fc39

Please sign in to comment.