Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -389,21 +389,26 @@ // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. - return In::MipsGot->getPageEntryOffset(Body.getVA(A)); + return In::MipsGot->getVA() + + In::MipsGot->getPageEntryOffset(Body.getVA(A)) - + In::MipsGot->getGp(); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend // should be applied to the GOT entry content not to the GOT entry offset. // That is why we use separate expression type. - return In::MipsGot->getBodyEntryOffset(Body, A); + return In::MipsGot->getVA() + + In::MipsGot->getBodyEntryOffset(Body, A) - + In::MipsGot->getGp(); case R_MIPS_GOTREL: - return Body.getVA(A) - In::MipsGot->getVA() - MipsGPOffset; + return Body.getVA(A) - In::MipsGot->getGp(); case R_MIPS_TLSGD: - return In::MipsGot->getGlobalDynOffset(Body) + - In::MipsGot->getTlsOffset() - MipsGPOffset; + return In::MipsGot->getVA() + In::MipsGot->getTlsOffset() + + In::MipsGot->getGlobalDynOffset(Body) - + In::MipsGot->getGp(); case R_MIPS_TLSLD: - return In::MipsGot->getTlsIndexOff() + - In::MipsGot->getTlsOffset() - MipsGPOffset; + return In::MipsGot->getVA() + In::MipsGot->getTlsOffset() + + In::MipsGot->getTlsIndexOff() - In::MipsGot->getGp(); case R_PPC_OPD: { uint64_t SymVA = Body.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -361,8 +361,10 @@ static DefinedRegular *End; static DefinedRegular *End2; - // The content for _gp_disp symbol for MIPS target. - static SymbolBody *MipsGpDisp; + // The content for _gp_disp/__gnu_local_gp symbols for MIPS target. + static DefinedRegular *MipsGpDisp; + static DefinedRegular *MipsLocalGp; + static SymbolBody *MipsGp; }; template DefinedRegular *ElfSym::EhdrStart; @@ -372,7 +374,9 @@ template DefinedRegular *ElfSym::Edata2; template DefinedRegular *ElfSym::End; template DefinedRegular *ElfSym::End2; -template SymbolBody *ElfSym::MipsGpDisp; +template DefinedRegular *ElfSym::MipsGpDisp; +template DefinedRegular *ElfSym::MipsLocalGp; +template SymbolBody *ElfSym::MipsGp; // A real symbol object, SymbolBody, is usually stored within a Symbol. There's // always one Symbol for each symbol name. The resolver updates the SymbolBody Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -122,6 +122,8 @@ uint32_t getTlsIndexOff() const { return TlsIndexOff; } + unsigned getGp() const; + private: // MIPS GOT consists of three parts: local, global and tls. Each part // contains different types of entries. Here is a layout of GOT: Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -177,7 +177,7 @@ Options->size = getSize(); if (!Config->Relocatable) - Reginfo.ri_gp_value = In::MipsGot->getVA() + MipsGPOffset; + Reginfo.ri_gp_value = In::MipsGot->getGp(); memcpy(Buf + sizeof(typename ELFT::uint), &Reginfo, sizeof(Reginfo)); } @@ -233,7 +233,7 @@ template void MipsReginfoSection::writeTo(uint8_t *Buf) { if (!Config->Relocatable) - Reginfo.ri_gp_value = In::MipsGot->getVA() + MipsGPOffset; + Reginfo.ri_gp_value = In::MipsGot->getGp(); memcpy(Buf, &Reginfo, sizeof(Reginfo)); } @@ -546,7 +546,7 @@ size_t NewIndex = PageIndexMap.size() + 2; auto P = PageIndexMap.insert(std::make_pair(EntryValue, NewIndex)); assert(!P.second || PageIndexMap.size() <= PageEntriesNum); - return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset; + return (uintX_t)P.first->second * sizeof(uintX_t); } template @@ -572,7 +572,7 @@ assert(It != EntryIndexMap.end()); GotIndex = It->second; } - return GotBlockOff + GotIndex * sizeof(uintX_t) - MipsGPOffset; + return GotBlockOff + GotIndex * sizeof(uintX_t); } template @@ -614,6 +614,10 @@ Size = EntriesNum * sizeof(uintX_t); } +template unsigned MipsGotSection::getGp() const { + return ElfSym::MipsGp->template getVA(0); +} + template static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { typedef typename ELFT::uint uintX_t; Index: lld/trunk/ELF/Target.h =================================================================== --- lld/trunk/ELF/Target.h +++ lld/trunk/ELF/Target.h @@ -105,8 +105,6 @@ std::string toString(uint32_t RelType); uint64_t getPPC64TocBase(); -const unsigned MipsGPOffset = 0x7ff0; - extern TargetInfo *Target; TargetInfo *createTarget(); } Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -605,22 +605,22 @@ if (Config->EMachine == EM_MIPS) { // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer // so that it points to an absolute address which is relative to GOT. + // Default offset is 0x7ff0. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - addRegular("_gp", In::MipsGot, MipsGPOffset); + ElfSym::MipsGp = addRegular("_gp", In::MipsGot, 0x7ff0)->body(); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. - Symbol *Sym = - addOptionalRegular("_gp_disp", In::MipsGot, MipsGPOffset); - if (Sym) - ElfSym::MipsGpDisp = Sym->body(); + if (Symbol *S = addOptionalRegular("_gp_disp", In::MipsGot, 0)) + ElfSym::MipsGpDisp = cast>(S->body()); // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' // pointer. This symbol is used in the code generated by .cpload pseudo-op // in case of using -mno-shared option. // https://sourceware.org/ml/binutils/2004-12/msg00094.html - addOptionalRegular("__gnu_local_gp", In::MipsGot, MipsGPOffset); + if (Symbol *S = addOptionalRegular("__gnu_local_gp", In::MipsGot, 0)) + ElfSym::MipsLocalGp = cast>(S->body()); } // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol @@ -1413,6 +1413,16 @@ else Set(ElfSym::Etext, ElfSym::Etext2, Val); } + + // Setup MIPS _gp_disp/__gnu_local_gp symbols which should + // be equal to the _gp symbol's value. + if (Config->EMachine == EM_MIPS) { + uintX_t GpDisp = In::MipsGot->getGp() - In::MipsGot->getVA(); + if (ElfSym::MipsGpDisp) + ElfSym::MipsGpDisp->Value = GpDisp; + if (ElfSym::MipsLocalGp) + ElfSym::MipsLocalGp->Value = GpDisp; + } } template void Writer::writeHeader() { Index: lld/trunk/test/ELF/mips-gp-ext.s =================================================================== --- lld/trunk/test/ELF/mips-gp-ext.s +++ lld/trunk/test/ELF/mips-gp-ext.s @@ -0,0 +1,41 @@ +# Check that the linker use a value of _gp symbol defined +# in a linker script to calculate GOT relocations. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: .text : { *(.text) } \ +# RUN: _gp = . + 0x100; \ +# RUN: .got : { *(.got) } }" > %t.script +# RUN: ld.lld -shared -o %t.so --script %t.script %t.o +# RUN: llvm-objdump -s -t %t.so | FileCheck %s + +# REQUIRES: mips + +# CHECK: Contents of section .text: +# CHECK-NEXT: 0000 3c080000 2108010c 8f82ffe4 +# ^-- %hi(_gp_disp) +# ^-- %lo(_gp_disp) +# ^-- 8 - (0x10c - 0xe8) +# G - (GP - .got) + +# CHECK: Contents of section .reginfo: +# CHECK-NEXT: 0028 10000104 00000000 00000000 00000000 +# CHECK-NEXT: 0038 00000000 0000010c +# ^-- _gp + +# CHECK: Contents of section .data: +# CHECK-NEXT: 0100 fffffef4 +# ^-- 0-0x10c + +# CHECK: 00000000 .text 00000000 foo +# CHECK: 0000010c .got 00000000 .hidden _gp_disp +# CHECK: 0000010c .text 00000000 .hidden _gp + + .text +foo: + lui $t0, %hi(_gp_disp) + addi $t0, $t0, %lo(_gp_disp) + lw $v0, %call16(bar)($gp) + + .data + .gpword foo