diff options
Diffstat (limited to 'lld/ELF')
-rw-r--r-- | lld/ELF/Target.cpp | 1 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 12 |
2 files changed, 11 insertions, 2 deletions
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 8b12d751771..240eb983c5a 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -1579,6 +1579,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, default: return R_ABS; case R_MIPS_HI16: + case R_MIPS_LO16: // MIPS _gp_disp designates offset between start of function and 'gp' // pointer into GOT. __gnu_local_gp is equal to the current value of // the 'gp'. Therefore any relocations against them do not require diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 31f2d3e2dcd..7a75d234396 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -462,14 +462,22 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) { if (auto *S = dyn_cast<SharedSymbol<ELFT>>(&Body)) S->File->IsUsed = true; + RelExpr Expr = Target->getRelExpr(Type, Body); uintX_t Addend = getAddend<ELFT>(RI); const uint8_t *BufLoc = Buf + RI.r_offset; if (!RelTy::IsRela) Addend += Target->getImplicitAddend(BufLoc, Type); - if (Config->EMachine == EM_MIPS) + if (Config->EMachine == EM_MIPS) { Addend += findMipsPairedAddend<ELFT>(Buf, BufLoc, Body, &RI, E); + if (Type == R_MIPS_LO16 && Expr == R_PC) + // R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp + // symbol. In that case we should use the following formula for + // calculation "AHL + GP – P + 4". Let's add 4 right here. + // For details see p. 4-19 at + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + Addend += 4; + } - RelExpr Expr = Target->getRelExpr(Type, Body); if (unsigned Processed = handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) { I += (Processed - 1); |