[Mips] Implement R_MIPS_64 relocation handling

llvm-svn: 231642
This commit is contained in:
Simon Atanasyan 2015-03-09 10:53:41 +00:00
parent cc0ed289b4
commit 1397f520d4
4 changed files with 203 additions and 32 deletions

View File

@ -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 <size_t BITS, class T> 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<uint32_t> calculateRelocation(const Reference &ref,
static ErrorOr<uint64_t> 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<uint32_t> 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:
@ -364,6 +373,42 @@ static ErrorOr<uint32_t> calculateRelocation(const Reference &ref,
}
}
template <class ELFT>
static uint64_t relocRead(const MipsRelocationParams &params,
const uint8_t *loc) {
uint64_t data;
switch (params._size) {
case 4:
data = endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(loc);
break;
case 8:
data = endian::read<uint64_t, ELFT::TargetEndianness, unaligned>(loc);
break;
default:
llvm_unreachable("Unexpected size");
}
if (params._shuffle)
data = microShuffle(data);
return data;
}
template <class ELFT>
static void relocWrite(uint64_t data, const MipsRelocationParams &params,
uint8_t *loc) {
if (params._shuffle)
data = microShuffle(data);
switch (params._size) {
case 4:
endian::write<uint32_t, ELFT::TargetEndianness, unaligned>(loc, data);
break;
case 8:
endian::write<uint64_t, ELFT::TargetEndianness, unaligned>(loc, data);
break;
default:
llvm_unreachable("Unexpected size");
}
}
template <class ELFT>
std::error_code MipsRelocationHandler<ELFT>::applyRelocation(
ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
@ -394,22 +439,15 @@ std::error_code MipsRelocationHandler<ELFT>::applyRelocation(
if (auto ec = res.getError())
return ec;
uint32_t ins =
endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(location);
auto params = getRelocationParams(ref.kindValue());
if (params._shuffle)
ins = microShuffle(ins);
uint64_t ins = relocRead<ELFT>(params, location);
if (auto ec = adjustJumpOpCode(ins, targetVAddress, getCrossJumpMode(ref)))
return ec;
ins = (ins & ~params._mask) | (*res & params._mask);
relocWrite<ELFT>(ins, params, location);
if (params._shuffle)
ins = microShuffle(ins);
endian::write<uint32_t, ELFT::TargetEndianness, unaligned>(location, ins);
return std::error_code();
}
@ -417,10 +455,8 @@ template <class ELFT>
Reference::Addend
MipsRelocationHandler<ELFT>::readAddend(Reference::KindValue kind,
const uint8_t *content) {
auto ins = endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(content);
auto params = getRelocationParams(kind);
if (params._shuffle)
ins = microShuffle(ins);
uint64_t ins = relocRead<ELFT>(params, content);
return (ins & params._mask) << params._shift;
}

View File

@ -587,7 +587,7 @@ bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &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;

View File

@ -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
...

View File

@ -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