From addb5f1675cbd16f95debe077591845c59d38e32 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Tue, 13 Aug 2024 16:12:09 +0900 Subject: [PATCH] [SPARC] Relax TLS GD/LD relocations --- elf/arch-sparc64.cc | 113 +++++++++++++++++++++++++++++--------------- elf/mold.h | 18 ------- elf/passes.cc | 5 +- 3 files changed, 76 insertions(+), 60 deletions(-) diff --git a/elf/arch-sparc64.cc b/elf/arch-sparc64.cc index 5c7f8be3e8..99fb817310 100644 --- a/elf/arch-sparc64.cc +++ b/elf/arch-sparc64.cc @@ -359,27 +359,75 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { *(ub32 *)loc |= bits(S + A, 11, 0); break; case R_SPARC_TLS_GD_HI22: - *(ub32 *)loc |= bits(sym.get_tlsgd_addr(ctx) + A - GOT, 31, 10); + if (sym.has_tlsgd(ctx)) { + *(ub32 *)loc |= bits(sym.get_tlsgd_addr(ctx) + A - GOT, 31, 10); + } else if (sym.has_gottp(ctx)) { + *(ub32 *)loc |= bits(sym.get_gottp_addr(ctx) + A - GOT, 31, 10); + } else { + *(ub32 *)loc |= bits(~(S + A - ctx.tp_addr), 31, 10); + } break; case R_SPARC_TLS_GD_LO10: - *(ub32 *)loc |= bits(sym.get_tlsgd_addr(ctx) + A - GOT, 9, 0); + if (sym.has_tlsgd(ctx)) { + *(ub32 *)loc |= bits(sym.get_tlsgd_addr(ctx) + A - GOT, 9, 0); + } else if (sym.has_gottp(ctx)) { + u32 rd = bits(*(ub32 *)loc, 29, 25); + *(ub32 *)loc = 0x8010'2000 | (rd << 25) | (rd << 14); // or %reg, $0, %reg + *(ub32 *)loc |= bits(sym.get_gottp_addr(ctx) + A - GOT, 9, 0); + } else { + u32 rd = bits(*(ub32 *)loc, 29, 25); + *(ub32 *)loc = 0x8018'2000 | (rd << 25) | (rd << 14); // xor %reg, $0, %reg + *(ub32 *)loc |= bits(S + A - ctx.tp_addr, 9, 0) | 0b1'1100'0000'0000; + } + break; + case R_SPARC_TLS_GD_ADD: + if (sym.has_tlsgd(ctx)) { + // do nothing + } else if (sym.has_gottp(ctx)) { + u32 rs2 = bits(*(ub32 *)loc, 4, 0); + *(ub32 *)loc = 0xd05d'c000 | rs2; // ldx [ %l7 + %reg ], %o0 + } else { + u32 rs2 = bits(*(ub32 *)loc, 4, 0); + *(ub32 *)loc = 0x9001'c000 | rs2; // add %g7, %reg, %o0 + } break; case R_SPARC_TLS_GD_CALL: - case R_SPARC_TLS_LDM_CALL: { - u64 addr; - if (ctx.arg.static_) - addr = ctx.extra.tls_get_addr_sec->shdr.sh_addr; - else - addr = ctx.extra.tls_get_addr_sym->get_addr(ctx); - - *(ub32 *)loc |= bits(addr + A - P, 31, 2); + if (sym.has_tlsgd(ctx)) { + u64 addr = ctx.extra.tls_get_addr_sym->get_addr(ctx); + *(ub32 *)loc |= bits(addr + A - P, 31, 2); + } else if (sym.has_gottp(ctx)) { + *(ub32 *)loc = 0x9001'c008; // add %g7, %o0, %o0 + } else { + *(ub32 *)loc = 0x0100'0000; // nop + } break; - } case R_SPARC_TLS_LDM_HI22: - *(ub32 *)loc |= bits(ctx.got->get_tlsld_addr(ctx) + A - GOT, 31, 10); + if (ctx.got->has_tlsld(ctx)) + *(ub32 *)loc |= bits(ctx.got->get_tlsld_addr(ctx) + A - GOT, 31, 10); + else + *(ub32 *)loc |= bits(ctx.tp_addr - ctx.tls_begin, 31, 10); break; case R_SPARC_TLS_LDM_LO10: - *(ub32 *)loc |= bits(ctx.got->get_tlsld_addr(ctx) + A - GOT, 9, 0); + if (ctx.got->has_tlsld(ctx)) + *(ub32 *)loc |= bits(ctx.got->get_tlsld_addr(ctx) + A - GOT, 9, 0); + else + *(ub32 *)loc |= bits(ctx.tp_addr - ctx.tls_begin, 9, 0); + break; + case R_SPARC_TLS_LDM_ADD: + if (ctx.got->has_tlsld(ctx)) { + // do nothing + } else { + u32 rs2 = bits(*(ub32 *)loc, 4, 0); + *(ub32 *)loc = 0x9021'c000 | rs2; // sub %g7, %reg, %o0 + } + break; + case R_SPARC_TLS_LDM_CALL: + if (ctx.got->has_tlsld(ctx)) { + u64 addr = ctx.extra.tls_get_addr_sym->get_addr(ctx); + *(ub32 *)loc |= bits(addr + A - P, 31, 2); + } else { + *(ub32 *)loc = 0x0100'0000; // nop + } break; case R_SPARC_TLS_LDO_HIX22: *(ub32 *)loc |= bits(S + A - ctx.dtp_addr, 31, 10); @@ -402,8 +450,6 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { case R_SPARC_SIZE32: *(ub32 *)loc = sym.esym().st_size + A; break; - case R_SPARC_TLS_GD_ADD: - case R_SPARC_TLS_LDM_ADD: case R_SPARC_TLS_LDO_ADD: case R_SPARC_TLS_IE_LD: case R_SPARC_TLS_IE_LDX: @@ -554,10 +600,22 @@ void InputSection::scan_relocations(Context &ctx) { scan_pcrel(ctx, sym, rel); break; case R_SPARC_TLS_GD_HI22: - sym.flags |= NEEDS_TLSGD; + if (ctx.arg.static_ || (ctx.arg.relax && sym.is_tprel_linktime_const(ctx))) { + // We always relax if -static because libc.a doesn't contain + // __tls_get_addr(). + } else if (ctx.arg.relax && sym.is_tprel_runtime_const(ctx)) { + sym.flags |= NEEDS_GOTTP; + } else { + sym.flags |= NEEDS_TLSGD; + } break; case R_SPARC_TLS_LDM_HI22: - ctx.needs_tlsld = true; + if (ctx.arg.static_ || (ctx.arg.relax && !ctx.arg.shared)) { + // We always relax if -static because libc.a doesn't contain + // __tls_get_addr(). + } else { + ctx.needs_tlsld = true; + } break; case R_SPARC_TLS_IE_HI22: sym.flags |= NEEDS_GOTTP; @@ -594,25 +652,4 @@ void InputSection::scan_relocations(Context &ctx) { } } -// __tls_get_addr is not defined by libc.a, so we can't use that function -// in statically-linked executables. This section provides a replacement. -void SparcTlsGetAddrSection::copy_buf(Context &ctx) { - ub32 *buf = (ub32 *)(ctx.buf + this->shdr.sh_offset); - - constexpr ub32 insn[] = { - 0x0300'0000, // sethi %hi(TP_SIZE), %g1 - 0x8210'6000, // or %g1, %lo(TP_SIZE), %g1 - 0x8221'c001, // sub %g7, %g1, %g1 - 0xd05a'2008, // ldx [ %o0 + 8 ], %o0 - 0x81c3'e008, // retl - 0x9000'4008, // add %g1, %o0, %o0 - }; - - assert(this->shdr.sh_size == sizeof(insn)); - memcpy(buf, insn, sizeof(insn)); - - buf[0] |= bits(ctx.tp_addr - ctx.tls_begin, 31, 10); - buf[1] |= bits(ctx.tp_addr - ctx.tls_begin, 9, 0); -} - } // namespace mold::elf diff --git a/elf/mold.h b/elf/mold.h index 9918f95bab..6620ccdc88 100644 --- a/elf/mold.h +++ b/elf/mold.h @@ -1599,23 +1599,6 @@ class PPC64SaveRestoreSection : public Chunk { template <> u64 get_eflags(Context &ctx); -// -// arch-sparc.cc -// - -class SparcTlsGetAddrSection : public Chunk { -public: - SparcTlsGetAddrSection() { - this->name = ".tls_get_addr"; - this->shdr.sh_type = SHT_PROGBITS; - this->shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; - this->shdr.sh_addralign = 4; - this->shdr.sh_size = 24; - } - - void copy_buf(Context &ctx) override; -}; - // // arch-alpha.cc // @@ -1747,7 +1730,6 @@ struct ContextExtras { template <> struct ContextExtras { - SparcTlsGetAddrSection *tls_get_addr_sec = nullptr; Symbol *tls_get_addr_sym = nullptr; }; diff --git a/elf/passes.cc b/elf/passes.cc index 477fdc476c..0f1c43ee07 100644 --- a/elf/passes.cc +++ b/elf/passes.cc @@ -190,11 +190,8 @@ void create_synthetic_sections(Context &ctx) { if constexpr (is_ppc64v2) ctx.extra.save_restore = push(new PPC64SaveRestoreSection); - if constexpr (is_sparc) { - if (ctx.arg.static_) - ctx.extra.tls_get_addr_sec = push(new SparcTlsGetAddrSection); + if constexpr (is_sparc) ctx.extra.tls_get_addr_sym = get_symbol(ctx, "__tls_get_addr"); - } if constexpr (is_alpha) ctx.extra.got = push(new AlphaGotSection);