[ELF][MIPS] Implement R_MIPS_GPREL16/R_MIPS_GPREL32 relocations
The R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations use the following
expressions for calculations:
```
local symbol: S + A + GP0 - GP
global symbol: S + A - GP
GP - Represents the final gp value, i.e. _gp symbol
GP0 - Represents the gp value used to create the relocatable object
```
The GP0 value is taken from the .reginfo data section defined by an object
file. To implement that I keep a reference to `MipsReginfoInputSection`
in the `ObjectFile` class. This reference is used by the
`ObjectFile::getMipsGp0` method to return the GP0 value.
Differential Revision: http://reviews.llvm.org/D15760
llvm-svn: 256416
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 1b45ec7..2548200 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -187,6 +187,12 @@
uintX_t A = getAddend<ELFT>(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<const Elf_Mips_RegInfo *>(D.data())->ri_gprmask;
}
+template <class ELFT> uint32_t MipsReginfoInputSection<ELFT>::getGp0() const {
+ ArrayRef<uint8_t> D = this->getSectionData();
+ if (D.size() != sizeof(Elf_Mips_RegInfo))
+ error("Invalid size of .reginfo section");
+ return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gp_value;
+}
+
template <class ELFT>
bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;