// 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<ELFT>::MipsGot->getPageEntryOffset(Body.getVA<ELFT>(A));
+ return In<ELFT>::MipsGot->getVA() +
+ In<ELFT>::MipsGot->getPageEntryOffset(Body.getVA<ELFT>(A)) -
+ In<ELFT>::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<ELFT>::MipsGot->getBodyEntryOffset(Body, A);
+ return In<ELFT>::MipsGot->getVA() +
+ In<ELFT>::MipsGot->getBodyEntryOffset(Body, A) -
+ In<ELFT>::MipsGot->getGp();
case R_MIPS_GOTREL:
- return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getVA() - MipsGPOffset;
+ return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSGD:
- return In<ELFT>::MipsGot->getGlobalDynOffset(Body) +
- In<ELFT>::MipsGot->getTlsOffset() - MipsGPOffset;
+ return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
+ In<ELFT>::MipsGot->getGlobalDynOffset(Body) -
+ In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSLD:
- return In<ELFT>::MipsGot->getTlsIndexOff() +
- In<ELFT>::MipsGot->getTlsOffset() - MipsGPOffset;
+ return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
+ In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp();
case R_PPC_OPD: {
uint64_t SymVA = Body.getVA<ELFT>(A);
// If we have an undefined weak symbol, we might get here with a symbol
static DefinedRegular<ELFT> *End;
static DefinedRegular<ELFT> *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<ELFT> *MipsGpDisp;
+ static DefinedRegular<ELFT> *MipsLocalGp;
+ static SymbolBody *MipsGp;
};
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::EhdrStart;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
-template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsGpDisp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGpDisp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsLocalGp;
+template <class ELFT> SymbolBody *ElfSym<ELFT>::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
Options->size = getSize();
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getVA() + MipsGPOffset;
+ Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
memcpy(Buf + sizeof(typename ELFT::uint), &Reginfo, sizeof(Reginfo));
}
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getVA() + MipsGPOffset;
+ Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
memcpy(Buf, &Reginfo, sizeof(Reginfo));
}
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 <class ELFT>
assert(It != EntryIndexMap.end());
GotIndex = It->second;
}
- return GotBlockOff + GotIndex * sizeof(uintX_t) - MipsGPOffset;
+ return GotBlockOff + GotIndex * sizeof(uintX_t);
}
template <class ELFT>
Size = EntriesNum * sizeof(uintX_t);
}
+template <class ELFT> unsigned MipsGotSection<ELFT>::getGp() const {
+ return ElfSym<ELFT>::MipsGp->template getVA<ELFT>(0);
+}
+
template <class ELFT>
static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
typedef typename ELFT::uint uintX_t;
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:
std::string toString(uint32_t RelType);
uint64_t getPPC64TocBase();
-const unsigned MipsGPOffset = 0x7ff0;
-
extern TargetInfo *Target;
TargetInfo *createTarget();
}
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<ELFT>::MipsGot, MipsGPOffset);
+ ElfSym<ELFT>::MipsGp = addRegular("_gp", In<ELFT>::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<ELFT>::MipsGot, MipsGPOffset);
- if (Sym)
- ElfSym<ELFT>::MipsGpDisp = Sym->body();
+ if (Symbol *S = addOptionalRegular("_gp_disp", In<ELFT>::MipsGot, 0))
+ ElfSym<ELFT>::MipsGpDisp = cast<DefinedRegular<ELFT>>(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<ELFT>::MipsGot, MipsGPOffset);
+ if (Symbol *S = addOptionalRegular("__gnu_local_gp", In<ELFT>::MipsGot, 0))
+ ElfSym<ELFT>::MipsLocalGp = cast<DefinedRegular<ELFT>>(S->body());
}
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
else
Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::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<ELFT>::MipsGot->getGp() - In<ELFT>::MipsGot->getVA();
+ if (ElfSym<ELFT>::MipsGpDisp)
+ ElfSym<ELFT>::MipsGpDisp->Value = GpDisp;
+ if (ElfSym<ELFT>::MipsLocalGp)
+ ElfSym<ELFT>::MipsLocalGp->Value = GpDisp;
+ }
}
template <class ELFT> void Writer<ELFT>::writeHeader() {
--- /dev/null
+# 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