Index: lld/trunk/ELF/InputSection.h =================================================================== --- lld/trunk/ELF/InputSection.h +++ lld/trunk/ELF/InputSection.h @@ -76,9 +76,16 @@ InputSectionBase *getRelocTarget(const Elf_Rela &Rel); template - void relocate(uint8_t *Buf, uint8_t *BufEnd, - llvm::iterator_range< - const llvm::object::Elf_Rel_Impl *> Rels); + using RelIteratorRange = + llvm::iterator_range *>; + + template + void relocate(uint8_t *Buf, uint8_t *BufEnd, RelIteratorRange Rels); + +private: + template + uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t Type, + RelIteratorRange Rels); }; template Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -94,9 +94,38 @@ template template -void InputSectionBase::relocate( - uint8_t *Buf, uint8_t *BufEnd, - iterator_range *> Rels) { +uint8_t * +InputSectionBase::findMipsPairedReloc(uint8_t *Buf, uint32_t Type, + RelIteratorRange Rels) { + // Some MIPS relocations use addend calculated from addend of the relocation + // itself and addend of paired relocation. ABI requires to compute such + // combined addend in case of REL relocation record format only. + // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (isRela || Config->EMachine != EM_MIPS) + return nullptr; + if (Type == R_MIPS_HI16) + Type = R_MIPS_LO16; + else if (Type == R_MIPS_PCHI16) + Type = R_MIPS_PCLO16; + else if (Type == R_MICROMIPS_HI16) + Type = R_MICROMIPS_LO16; + else + return nullptr; + for (const auto &RI : Rels) { + if (RI.getType(Config->Mips64EL) != Type) + continue; + uintX_t Offset = getOffset(RI.r_offset); + if (Offset == (uintX_t)-1) + return nullptr; + return Buf + Offset; + } + return nullptr; +} + +template +template +void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd, + RelIteratorRange Rels) { typedef Elf_Rel_Impl RelType; size_t Num = Rels.end() - Rels.begin(); for (size_t I = 0; I < Num; ++I) { @@ -109,6 +138,7 @@ uint8_t *BufLoc = Buf + Offset; uintX_t AddrLoc = OutSec->getVA() + Offset; + auto NextRelocs = llvm::make_range(&RI, Rels.end()); if (Target->isTlsLocalDynamicReloc(Type) && !Target->isTlsOptimized(Type, nullptr)) { @@ -123,7 +153,8 @@ const Elf_Shdr *SymTab = File->getSymbolTable(); if (SymIndex < SymTab->sh_info) { uintX_t SymVA = getLocalRelTarget(*File, RI); - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA); + Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, + findMipsPairedReloc(Buf, Type, NextRelocs)); continue; } @@ -161,7 +192,8 @@ continue; } Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, - SymVA + getAddend(RI)); + SymVA + getAddend(RI), + findMipsPairedReloc(Buf, Type, NextRelocs)); } } Index: lld/trunk/ELF/Target.h =================================================================== --- lld/trunk/ELF/Target.h +++ lld/trunk/ELF/Target.h @@ -57,7 +57,8 @@ virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0; virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0; virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const = 0; + uint64_t P, uint64_t SA, + uint8_t *PairedLoc = nullptr) const = 0; virtual bool isTlsOptimized(unsigned Type, const SymbolBody *S) const; virtual unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, Index: lld/trunk/ELF/Target.cpp =================================================================== --- lld/trunk/ELF/Target.cpp +++ lld/trunk/ELF/Target.cpp @@ -87,7 +87,7 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, uint8_t *PairedLoc = nullptr) const override; }; class X86_64TargetInfo final : public TargetInfo { @@ -106,7 +106,7 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, uint8_t *PairedLoc = nullptr) const override; bool isRelRelative(uint32_t Type) const override; bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override; unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, @@ -133,7 +133,7 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, uint8_t *PairedLoc = nullptr) const override; bool isRelRelative(uint32_t Type) const override; }; @@ -150,7 +150,7 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, uint8_t *PairedLoc = nullptr) const override; }; template class MipsTargetInfo final : public TargetInfo { @@ -166,7 +166,7 @@ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, - uint64_t SA) const override; + uint64_t SA, uint8_t *PairedLoc = nullptr) const override; }; } // anonymous namespace @@ -308,7 +308,8 @@ } void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { + uint64_t P, uint64_t SA, + uint8_t *PairedLoc) const { switch (Type) { case R_386_32: add32le(Loc, SA); @@ -581,7 +582,8 @@ } void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { + uint64_t P, uint64_t SA, + uint8_t *PairedLoc) const { switch (Type) { case R_X86_64_32: checkUInt<32>(SA, Type); @@ -728,7 +730,8 @@ } void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, - uint64_t P, uint64_t SA) const { + uint64_t P, uint64_t SA, + uint8_t *PairedLoc) const { uint64_t TB = getPPC64TocBase(); // For a TOC-relative relocation, adjust the addend and proceed in terms of @@ -933,8 +936,8 @@ } void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { + uint32_t Type, uint64_t P, uint64_t SA, + uint8_t *PairedLoc) const { switch (Type) { case R_AARCH64_ABS16: checkIntUInt<16>(SA, Type); @@ -1046,13 +1049,31 @@ template void MipsTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, - uint32_t Type, uint64_t P, - uint64_t SA) const { + uint32_t Type, uint64_t P, uint64_t SA, + uint8_t *PairedLoc) const { const endianness E = ELFT::TargetEndianness; switch (Type) { case R_MIPS_32: add32(Loc, SA); break; + case R_MIPS_HI16: { + uint32_t Instr = read32(Loc); + if (PairedLoc) { + uint64_t AHL = ((Instr & 0xffff) << 16) + + llvm::SignExtend64<16>(read32(PairedLoc) & 0xffff); + write32(Loc, (Instr & 0xffff0000) | (((SA + AHL) >> 16) & 0xffff)); + } else { + warning("Can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16"); + write32(Loc, (Instr & 0xffff0000) | ((SA >> 16) & 0xffff)); + } + break; + } + case R_MIPS_LO16: { + uint32_t Instr = read32(Loc); + int64_t AHL = llvm::SignExtend64<16>(Instr & 0xffff); + write32(Loc, (Instr & 0xffff0000) | ((SA + AHL) & 0xffff)); + break; + } case R_MIPS_CALL16: case R_MIPS_GOT16: { int64_t V = SA - getMipsGpAddr(); Index: lld/trunk/test/ELF/mips-hilo-hi-only.s =================================================================== --- lld/trunk/test/ELF/mips-hilo-hi-only.s +++ lld/trunk/test/ELF/mips-hilo-hi-only.s @@ -0,0 +1,22 @@ +# Check warning on orphaned R_MIPS_HI16 relocations. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.exe 2>&1 | FileCheck -check-prefix=WARN %s +# RUN: llvm-objdump -d -t %t.exe | FileCheck %s + +# REQUIRES: mips + + .text + .globl __start +__start: + lui $t0,%hi(__start+0x10000) + +# WARN: Can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16 + +# CHECK: Disassembly of section .text: +# CHECK-NEXT: __start: +# CHECK-NEXT: 20000: 3c 08 00 02 lui $8, 2 +# ^-- %hi(__start) w/o addend + +# CHECK: SYMBOL TABLE: +# CHECK: 0020000 .text 00000000 __start Index: lld/trunk/test/ELF/mips-hilo.s =================================================================== --- lld/trunk/test/ELF/mips-hilo.s +++ lld/trunk/test/ELF/mips-hilo.s @@ -0,0 +1,53 @@ +# Check R_MIPS_HI16 / LO16 relocations calculation. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.exe +# RUN: llvm-objdump -d -t %t.exe | FileCheck %s + +# REQUIRES: mips + + .text + .globl __start +__start: + lui $t0,%hi(__start) + lui $t1,%hi(g1) + addi $t0,$t0,%lo(__start+4) + addi $t0,$t0,%lo(g1+8) + + lui $t0,%hi(l1+0x10000) + lui $t1,%hi(l1+0x20000) + addi $t0,$t0,%lo(l1+(-4)) + + .data + .type l1,@object + .size l1,4 +l1: + .word 0 + + .globl g1 + .type g1,@object + .size g1,4 +g1: + .word 0 + +# CHECK: Disassembly of section .text: +# CHECK-NEXT: __start: +# CHECK-NEXT: 20000: 3c 08 00 02 lui $8, 2 +# ^-- %hi(__start+4) +# CHECK-NEXT: 20004: 3c 09 00 03 lui $9, 3 +# ^-- %hi(g1+8) +# CHECK-NEXT: 20008: 21 08 00 04 addi $8, $8, 4 +# ^-- %lo(__start+4) +# CHECK-NEXT: 2000c: 21 08 00 0c addi $8, $8, 12 +# ^-- %lo(g1+8) +# CHECK-NEXT: 20010: 3c 08 00 03 lui $8, 3 +# ^-- %hi(l1+0x10000-4) +# CHECK-NEXT: 20014: 3c 09 00 04 lui $9, 4 +# ^-- %hi(l1+0x20000-4) +# CHECK-NEXT: 20018: 21 08 ff fc addi $8, $8, -4 +# ^-- %lo(l1-4) + +# CHECK: SYMBOL TABLE: +# CHECK: 0030000 l .data 00000004 l1 +# CHECK: 0020000 .text 00000000 __start +# CHECK: 0030004 g .data 00000004 g1