From 1397f520d42665e00015d2d28fee425177026bc6 Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Mon, 9 Mar 2015 10:53:41 +0000 Subject: [PATCH] [Mips] Implement R_MIPS_64 relocation handling llvm-svn: 231642 --- .../ELF/Mips/MipsRelocationHandler.cpp | 98 +++++++++++++++------- .../ReaderWriter/ELF/Mips/MipsRelocationPass.cpp | 2 +- lld/test/elf/Mips/dt-textrel-64.test | 74 ++++++++++++++++ lld/test/elf/Mips/rel-64.test | 61 ++++++++++++++ 4 files changed, 203 insertions(+), 32 deletions(-) create mode 100644 lld/test/elf/Mips/dt-textrel-64.test create mode 100644 lld/test/elf/Mips/rel-64.test diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp index 54d7c7d..7a1147f 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp @@ -25,6 +25,7 @@ enum class CrossJumpMode { }; struct MipsRelocationParams { + uint8_t _size; // Relocations's size in bytes uint64_t _mask; // Read/write mask of relocation uint8_t _shift; // Relocation's addendum left shift size bool _shuffle; // Relocation's addendum/result needs to be shuffled @@ -34,15 +35,17 @@ struct MipsRelocationParams { static MipsRelocationParams getRelocationParams(uint32_t rType) { switch (rType) { case llvm::ELF::R_MIPS_NONE: - return {0x0, 0, false}; + return {4, 0x0, 0, false}; + case llvm::ELF::R_MIPS_64: + return {8, 0xffffffffffffffffull, 0, false}; case llvm::ELF::R_MIPS_32: case llvm::ELF::R_MIPS_GPREL32: case llvm::ELF::R_MIPS_PC32: case LLD_R_MIPS_32_HI16: - return {0xffffffff, 0, false}; + return {4, 0xffffffff, 0, false}; case llvm::ELF::R_MIPS_26: case LLD_R_MIPS_GLOBAL_26: - return {0x3ffffff, 2, false}; + return {4, 0x3ffffff, 2, false}; case llvm::ELF::R_MIPS_HI16: case llvm::ELF::R_MIPS_LO16: case llvm::ELF::R_MIPS_GPREL16: @@ -53,41 +56,41 @@ static MipsRelocationParams getRelocationParams(uint32_t rType) { case llvm::ELF::R_MIPS_TLS_TPREL_LO16: case LLD_R_MIPS_HI16: case LLD_R_MIPS_LO16: - return {0xffff, 0, false}; + return {4, 0xffff, 0, false}; case llvm::ELF::R_MICROMIPS_TLS_DTPREL_HI16: case llvm::ELF::R_MICROMIPS_TLS_DTPREL_LO16: case llvm::ELF::R_MICROMIPS_TLS_TPREL_HI16: case llvm::ELF::R_MICROMIPS_TLS_TPREL_LO16: - return {0xffff, 0, true}; + return {4, 0xffff, 0, true}; case llvm::ELF::R_MICROMIPS_26_S1: case LLD_R_MICROMIPS_GLOBAL_26_S1: - return {0x3ffffff, 1, true}; + return {4, 0x3ffffff, 1, true}; case llvm::ELF::R_MICROMIPS_HI16: case llvm::ELF::R_MICROMIPS_LO16: case llvm::ELF::R_MICROMIPS_GOT16: - return {0xffff, 0, true}; + return {4, 0xffff, 0, true}; case llvm::ELF::R_MICROMIPS_PC16_S1: - return {0xffff, 1, true}; + return {4, 0xffff, 1, true}; case llvm::ELF::R_MICROMIPS_PC7_S1: - return {0x7f, 1, false}; + return {4, 0x7f, 1, false}; case llvm::ELF::R_MICROMIPS_PC10_S1: - return {0x3ff, 1, false}; + return {4, 0x3ff, 1, false}; case llvm::ELF::R_MICROMIPS_PC23_S2: - return {0x7fffff, 2, true}; + return {4, 0x7fffff, 2, true}; case llvm::ELF::R_MIPS_CALL16: case llvm::ELF::R_MIPS_TLS_GD: case llvm::ELF::R_MIPS_TLS_LDM: case llvm::ELF::R_MIPS_TLS_GOTTPREL: - return {0xffff, 0, false}; + return {4, 0xffff, 0, false}; case llvm::ELF::R_MICROMIPS_CALL16: case llvm::ELF::R_MICROMIPS_TLS_GD: case llvm::ELF::R_MICROMIPS_TLS_LDM: case llvm::ELF::R_MICROMIPS_TLS_GOTTPREL: - return {0xffff, 0, true}; + return {4, 0xffff, 0, true}; case R_MIPS_JALR: - return {0x0, 0, false}; + return {4, 0x0, 0, false}; case R_MICROMIPS_JALR: - return {0x0, 0, true}; + return {4, 0x0, 0, true}; case R_MIPS_REL32: case R_MIPS_JUMP_SLOT: case R_MIPS_COPY: @@ -95,11 +98,11 @@ static MipsRelocationParams getRelocationParams(uint32_t rType) { case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: // Ignore runtime relocations. - return {0x0, 0, false}; + return {4, 0x0, 0, false}; case LLD_R_MIPS_GLOBAL_GOT: case LLD_R_MIPS_STO_PLT: // Do nothing. - return {0x0, 0, false}; + return {4, 0x0, 0, false}; default: llvm_unreachable("Unknown relocation"); } @@ -115,6 +118,10 @@ template inline T signExtend(T val) { /// local/external: word32 S + A (truncate) static uint32_t reloc32(uint64_t S, int64_t A) { return S + A; } +/// \brief R_MIPS_64 +/// local/external: word64 S + A (truncate) +static uint64_t reloc64(uint64_t S, int64_t A) { return S + A; } + /// \brief R_MIPS_PC32 /// local/external: word32 S + A i- P (truncate) static uint32_t relocpc32(uint64_t P, uint64_t S, int64_t A) { @@ -219,7 +226,7 @@ static uint32_t reloc32hi16(uint64_t S, int64_t A) { return (S + A + 0x8000) & 0xffff0000; } -static std::error_code adjustJumpOpCode(uint32_t &ins, uint64_t tgt, +static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt, CrossJumpMode mode) { if (mode == CrossJumpMode::None) return std::error_code(); @@ -273,7 +280,7 @@ static uint32_t microShuffle(uint32_t ins) { return ((ins & 0xffff) << 16) | ((ins & 0xffff0000) >> 16); } -static ErrorOr calculateRelocation(const Reference &ref, +static ErrorOr calculateRelocation(const Reference &ref, uint64_t tgtAddr, uint64_t relAddr, uint64_t gpAddr, bool isGP) { bool isCrossJump = getCrossJumpMode(ref) != CrossJumpMode::None; @@ -282,6 +289,8 @@ static ErrorOr calculateRelocation(const Reference &ref, return 0; case R_MIPS_32: return reloc32(tgtAddr, ref.addend()); + case R_MIPS_64: + return reloc64(tgtAddr, ref.addend()); case R_MIPS_26: return reloc26loc(relAddr, tgtAddr, ref.addend(), 2); case R_MICROMIPS_26_S1: @@ -365,6 +374,42 @@ static ErrorOr calculateRelocation(const Reference &ref, } template +static uint64_t relocRead(const MipsRelocationParams ¶ms, + const uint8_t *loc) { + uint64_t data; + switch (params._size) { + case 4: + data = endian::read(loc); + break; + case 8: + data = endian::read(loc); + break; + default: + llvm_unreachable("Unexpected size"); + } + if (params._shuffle) + data = microShuffle(data); + return data; +} + +template +static void relocWrite(uint64_t data, const MipsRelocationParams ¶ms, + uint8_t *loc) { + if (params._shuffle) + data = microShuffle(data); + switch (params._size) { + case 4: + endian::write(loc, data); + break; + case 8: + endian::write(loc, data); + break; + default: + llvm_unreachable("Unexpected size"); + } +} + +template std::error_code MipsRelocationHandler::applyRelocation( ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom, const Reference &ref) const { @@ -394,22 +439,15 @@ std::error_code MipsRelocationHandler::applyRelocation( if (auto ec = res.getError()) return ec; - uint32_t ins = - endian::read(location); - auto params = getRelocationParams(ref.kindValue()); - if (params._shuffle) - ins = microShuffle(ins); + uint64_t ins = relocRead(params, location); if (auto ec = adjustJumpOpCode(ins, targetVAddress, getCrossJumpMode(ref))) return ec; ins = (ins & ~params._mask) | (*res & params._mask); + relocWrite(ins, params, location); - if (params._shuffle) - ins = microShuffle(ins); - - endian::write(location, ins); return std::error_code(); } @@ -417,10 +455,8 @@ template Reference::Addend MipsRelocationHandler::readAddend(Reference::KindValue kind, const uint8_t *content) { - auto ins = endian::read(content); auto params = getRelocationParams(kind); - if (params._shuffle) - ins = microShuffle(ins); + uint64_t ins = relocRead(params, content); return (ins & params._mask) << params._shift; } diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp index 7cfbf68..83254ee 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp @@ -587,7 +587,7 @@ bool RelocationPass::mightBeDynamic(const MipsELFDefinedAtom &atom, refKind == R_MICROMIPS_CALL16 || refKind == R_MICROMIPS_GOT16) return true; - if (refKind != R_MIPS_32) + if (refKind != R_MIPS_32 && refKind != R_MIPS_64) return false; if ((atom.section()->sh_flags & SHF_ALLOC) == 0) return false; diff --git a/lld/test/elf/Mips/dt-textrel-64.test b/lld/test/elf/Mips/dt-textrel-64.test new file mode 100644 index 0000000..32cc99e --- /dev/null +++ b/lld/test/elf/Mips/dt-textrel-64.test @@ -0,0 +1,74 @@ +# Check that if a dynamic relocation R_MIPS_64 modify a read-only section, +# .dynamic section contains the DT_TEXTREL tag. + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o +# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t-so.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o +# RUN: lld -flavor gnu -target mips64el -e T0 -o %t.exe %t-o.o %t.so +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck %s + +# CHECK: 0x{{[0-9A-F]+}} TEXTREL + +# so.o +--- +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64] + +Sections: +- Name: .text + Type: SHT_PROGBITS + Size: 0x4 + AddressAlign: 16 + Flags: [SHF_EXECINSTR, SHF_ALLOC] + +Symbols: + Global: + - Name: T1 + Section: .text + Type: STT_FUNC + Value: 0x0 + Size: 0x08 + +# o.o +--- +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64] + +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x4 + Size: 0x8 + + - Name: .rel.text + Type: SHT_RELA + Link: .symtab + Info: .text + AddressAlign: 0x04 + Relocations: + - Offset: 0 + Symbol: T1 + Type: R_MIPS_64 + +Symbols: + Local: + - Name: .text + Type: STT_SECTION + Section: .text + + Global: + - Name: T0 + Type: STT_FUNC + Section: .text + Size: 0x8 + - Name: T1 +... diff --git a/lld/test/elf/Mips/rel-64.test b/lld/test/elf/Mips/rel-64.test new file mode 100644 index 0000000..e05b756 --- /dev/null +++ b/lld/test/elf/Mips/rel-64.test @@ -0,0 +1,61 @@ +# Check handling of R_MIPS_64 relocation. + +# RUN: yaml2obj -format=elf %s > %t.o +# RUN: lld -flavor gnu -target mips64el -o %t.exe %t.o +# RUN: llvm-objdump -s -t %t.exe | FileCheck %s + +# CHECK: Contents of section .data: +# CHECK-NEXT: 120002000 d1010020 01000000 d0010020 01000100 ... ....... .... +# ^^ __start + 1 = 0x1200001d1 +# ^^ __start + 0x1000000000000 +# = 0x10001200001d0 +# CHECK: SYMBOL TABLE: +# CHECK: 00000001200001d0 g .rodata 00000008 __start + +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64] + +Sections: +- Name: .text + Type: SHT_PROGBITS + Size: 0x08 + AddressAlign: 16 + Flags: [SHF_ALLOC] +- Name: .data + Type: SHT_PROGBITS + Size: 0x10 + AddressAlign: 16 + Flags: [SHF_ALLOC, SHF_WRITE] + +- Name: .rela.data + Type: SHT_RELA + Info: .data + AddressAlign: 4 + Relocations: + - Offset: 0x0 + Symbol: __start + Type: R_MIPS_64 + Addend: 1 + - Offset: 0x8 + Symbol: __start + Type: R_MIPS_64 + Addend: 0x1000000000000 + +Symbols: + Global: + - Name: __start + Section: .text + Value: 0x0 + Size: 8 + - Name: data1 + Section: .data + Value: 0x0 + Size: 8 + - Name: data2 + Section: .data + Value: 0x8 + Size: 8 -- 2.7.4