Index: lld/trunk/ELF/InputFiles.h =================================================================== --- lld/trunk/ELF/InputFiles.h +++ lld/trunk/ELF/InputFiles.h @@ -121,6 +121,11 @@ const Elf_Shdr *getSymbolTable() const { return this->Symtab; }; + // Get MIPS GP0 value defined by this file. This value represents the gp value + // used to create the relocatable object and required to support + // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations. + uint32_t getMipsGp0() const; + private: void initializeSections(llvm::DenseSet &Comdats); void initializeSymbols(); @@ -134,6 +139,9 @@ // List of all symbols referenced or defined by this file. std::vector SymbolBodies; + // MIPS .reginfo section defined by this file. + MipsReginfoInputSection *MipsReginfo = nullptr; + llvm::BumpPtrAllocator Alloc; llvm::SpecificBumpPtrAllocator> MAlloc; llvm::SpecificBumpPtrAllocator> EHAlloc; Index: lld/trunk/ELF/InputFiles.cpp =================================================================== --- lld/trunk/ELF/InputFiles.cpp +++ lld/trunk/ELF/InputFiles.cpp @@ -93,6 +93,10 @@ return this->getSymbolsHelper(true); } +template uint32_t ObjectFile::getMipsGp0() const { + return MipsReginfo ? MipsReginfo->getGp0() : 0; +} + template const typename ObjectFile::Elf_Sym * ObjectFile::getLocalSymbol(uintX_t SymIndex) { @@ -245,8 +249,10 @@ // A MIPS object file has a special section that contains register // usage info, which needs to be handled by the linker specially. - if (Config->EMachine == EM_MIPS && Name == ".reginfo") - return new (this->Alloc) MipsReginfoInputSection(this, &Sec); + if (Config->EMachine == EM_MIPS && Name == ".reginfo") { + MipsReginfo = new (this->Alloc) MipsReginfoInputSection(this, &Sec); + return MipsReginfo; + } if (Name == ".eh_frame") return new (this->EHAlloc.Allocate()) EHInputSection(this, &Sec); Index: lld/trunk/ELF/InputSection.h =================================================================== --- lld/trunk/ELF/InputSection.h +++ lld/trunk/ELF/InputSection.h @@ -176,6 +176,7 @@ MipsReginfoInputSection(ObjectFile *F, const Elf_Shdr *Header); uint32_t getGeneralMask() const; + uint32_t getGp0() const; static bool classof(const InputSectionBase *S); }; Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -187,6 +187,12 @@ uintX_t A = getAddend(RI); if (!Body) { uintX_t SymVA = getLocalRelTarget(*File, RI, A); + // We need to adjust SymVA value in case of R_MIPS_GPREL16/32 relocations + // because they use the following expression to calculate the relocation's + // result for local symbol: S + A + GP0 - G. + if (Config->EMachine == EM_MIPS && + (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32)) + SymVA += File->getMipsGp0(); Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs)); continue; @@ -351,6 +357,13 @@ return reinterpret_cast(D.data())->ri_gprmask; } +template uint32_t MipsReginfoInputSection::getGp0() const { + ArrayRef D = this->getSectionData(); + if (D.size() != sizeof(Elf_Mips_RegInfo)) + error("Invalid size of .reginfo section"); + return reinterpret_cast(D.data())->ri_gp_value; +} + template bool MipsReginfoInputSection::classof(const InputSectionBase *S) { return S->SectionKind == InputSectionBase::MipsReginfo; Index: lld/trunk/ELF/Target.cpp =================================================================== --- lld/trunk/ELF/Target.cpp +++ lld/trunk/ELF/Target.cpp @@ -1382,6 +1382,16 @@ write32(Loc, (read32(Loc) & 0xffff0000) | (V & 0xffff)); break; } + case R_MIPS_GPREL16: { + uint32_t Instr = read32(Loc); + int64_t V = SA + SignExtend64<16>(Instr & 0xffff) - getMipsGpAddr(); + checkInt<16>(V, Type); + write32(Loc, (Instr & 0xffff0000) | (V & 0xffff)); + break; + } + case R_MIPS_GPREL32: + write32(Loc, SA + int32_t(read32(Loc)) - getMipsGpAddr()); + break; case R_MIPS_HI16: { uint32_t Instr = read32(Loc); if (PairedLoc) { Index: lld/trunk/test/ELF/mips-gprel32-relocs.test =================================================================== --- lld/trunk/test/ELF/mips-gprel32-relocs.test +++ lld/trunk/test/ELF/mips-gprel32-relocs.test @@ -0,0 +1,31 @@ +# Check R_MIPS_GPREL32 relocation calculation. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld -shared -o %t.so %t.o +# RUN: llvm-objdump -s -section=.rodata -t %t.so | FileCheck %s + +# REQUIRES: mips + + .text + .globl __start +__start: + lw $t0,%call16(__start)($gp) +foo: + nop +bar: + nop + + .section .rodata, "a" +v1: + .gpword foo + .gpword bar + +# CHECK: Contents of section .rodata: +# CHECK: 0114 fffe8014 fffe8018 +# ^ 0x10004 - 0x27ff0 +# ^ 0x10008 - 0x27ff0 + +# CHECK: SYMBOL TABLE: +# CHECK: 00010008 .text 00000000 bar +# CHECK: 00010004 .text 00000000 foo +# CHECK: 00027ff0 *ABS* 00000000 _gp