From f4ce278729c1484760e8735e72efe82c901cea06 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 14 Oct 2022 12:46:50 +0800 Subject: [PATCH] [ELF][S390X] Support more relocation types --- elf/arch-s390x.cc | 76 ++++++++++++++++++++++++++++++++++++++--------- elf/elf.h | 4 +-- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/elf/arch-s390x.cc b/elf/arch-s390x.cc index d58de3aa5e..9f03c0106e 100644 --- a/elf/arch-s390x.cc +++ b/elf/arch-s390x.cc @@ -41,6 +41,21 @@ namespace mold::elf { using E = S390X; +static void write_low12(u8 *loc, u64 val) { + *(ub16 *)loc &= 0xf000; + *(ub16 *)loc |= val & 0x0fff; +} + +static void write_mid20(u8 *loc, u64 val) { + *(ub32 *)loc &= 0xf000'00ff; + *(ub32 *)loc |= (bits(val, 11, 0) << 16) | (bits(val, 19, 12) << 8); +} + +static void write_low24(u8 *loc, u64 val) { + *(ub32 *)loc &= 0xff00'0000; + *(ub32 *)loc |= val & 0x00ff'ffff; +} + template <> void write_plt_header(Context &ctx, u8 *buf) { static u8 insn[] = { @@ -133,12 +148,14 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { *loc = S + A; break; case R_390_12: - *(ub16 *)loc &= 0xf000; - *(ub16 *)loc |= (S + A) & 0x0fff; + write_low12(loc, S + A); break; case R_390_16: *(ub16 *)loc = S + A; break; + case R_390_20: + write_mid20(loc, S + A); + break; case R_390_32: case R_390_PLT32: *(ub32 *)loc = S + A; @@ -146,15 +163,26 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { case R_390_PLT64: *(ub64 *)loc = S + A; break; + case R_390_PC12DBL: + case R_390_PLT12DBL: + write_low12(loc, (S + A - P) >> 1); + break; case R_390_PC16: *(ub16 *)loc = S + A - P; break; + case R_390_PC32: + *(ub32 *)loc = S + A - P; + break; + case R_390_PC64: + *(ub64 *)loc = S + A - P; + break; case R_390_PC16DBL: case R_390_PLT16DBL: *(ub16 *)loc = (S + A - P) >> 1; break; - case R_390_PC32: - *(ub32 *)loc = S + A - P; + case R_390_PC24DBL: + case R_390_PLT24DBL: + write_low24(loc, (S + A - P) >> 1); break; case R_390_PC32DBL: case R_390_PLT32DBL: @@ -166,26 +194,36 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { *(ub32 *)loc = (S + A - P) >> 1; } break; - case R_390_PC64: - *(ub64 *)loc = S + A - P; - break; case R_390_GOT12: - *(ub16 *)loc &= 0xf000; - *(ub16 *)loc |= (G + A) & 0x0fff; + case R_390_GOTPLT12: + write_low12(loc, G + A); break; case R_390_GOT16: + case R_390_GOTPLT16: *(ub16 *)loc = G + A; break; + case R_390_GOT20: + case R_390_GOTPLT20: + write_mid20(loc, G + A); + break; case R_390_GOT32: + case R_390_GOTPLT32: *(ub32 *)loc = G + A; break; case R_390_GOT64: + case R_390_GOTPLT64: *(ub64 *)loc = G + A; break; case R_390_GOTOFF16: + case R_390_PLTOFF16: *(ub16 *)loc = S + A - GOT; break; + case R_390_GOTOFF32: + case R_390_PLTOFF32: + *(ub32 *)loc = S + A - GOT; + break; case R_390_GOTOFF64: + case R_390_PLTOFF64: *(ub64 *)loc = S + A - GOT; break; case R_390_GOTPC: @@ -203,12 +241,9 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { case R_390_TLS_LE64: *(ub64 *)loc = S + A - ctx.tp_addr; break; - case R_390_TLS_GOTIE20: { - i64 val = sym.get_gottp_addr(ctx) + A - GOT; - *(ub32 *)loc &= 0xf000'00ff; - *(ub32 *)loc |= (bits(val, 11, 0) << 16) | (bits(val, 19, 12) << 8); + case R_390_TLS_GOTIE20: + write_mid20(loc, sym.get_gottp_addr(ctx) + A - GOT); break; - } case R_390_TLS_IEENT: *(ub32 *)loc = (sym.get_gottp_addr(ctx) + A - P) >> 1; break; @@ -347,6 +382,7 @@ void InputSection::scan_relocations(Context &ctx) { case R_390_8: case R_390_12: case R_390_16: + case R_390_20: case R_390_32: scan_rel(ctx, sym, rel, absrel_table); break; @@ -359,19 +395,31 @@ void InputSection::scan_relocations(Context &ctx) { break; case R_390_GOT12: case R_390_GOT16: + case R_390_GOT20: case R_390_GOT32: case R_390_GOT64: case R_390_GOTOFF16: + case R_390_GOTOFF32: case R_390_GOTOFF64: + case R_390_GOTPLT12: + case R_390_GOTPLT16: + case R_390_GOTPLT20: + case R_390_GOTPLT32: + case R_390_GOTPLT64: case R_390_GOTPC: case R_390_GOTPCDBL: case R_390_GOTENT: sym.flags |= NEEDS_GOT; break; + case R_390_PLT12DBL: case R_390_PLT16DBL: + case R_390_PLT24DBL: case R_390_PLT32: case R_390_PLT32DBL: case R_390_PLT64: + case R_390_PLTOFF16: + case R_390_PLTOFF32: + case R_390_PLTOFF64: if (sym.is_imported) sym.flags |= NEEDS_PLT; break; diff --git a/elf/elf.h b/elf/elf.h index 2bc529da25..2df03895ce 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -1522,7 +1522,7 @@ static constexpr u32 R_390_COPY = 9; static constexpr u32 R_390_GLOB_DAT = 10; static constexpr u32 R_390_JMP_SLOT = 11; static constexpr u32 R_390_RELATIVE = 12; -static constexpr u32 R_390_GOTOFF = 13; +static constexpr u32 R_390_GOTOFF32 = 13; static constexpr u32 R_390_GOTPC = 14; static constexpr u32 R_390_GOT16 = 15; static constexpr u32 R_390_PC16 = 16; @@ -1592,7 +1592,7 @@ inline std::string rel_to_string(u32 r_type) { case R_390_GLOB_DAT: return "R_390_GLOB_DAT"; case R_390_JMP_SLOT: return "R_390_JMP_SLOT"; case R_390_RELATIVE: return "R_390_RELATIVE"; - case R_390_GOTOFF: return "R_390_GOTOFF"; + case R_390_GOTOFF32: return "R_390_GOTOFF32"; case R_390_GOTPC: return "R_390_GOTPC"; case R_390_GOT16: return "R_390_GOT16"; case R_390_PC16: return "R_390_PC16";