Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -86,6 +86,11 @@ template uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex, uint32_t Type, RelIteratorRange Rels); + + template + uint8_t *getLocalPaired(uintX_t &SymVA, uint8_t *Buf, uint8_t *BufLoc, + uint32_t Type, uint32_t SymIndex, + RelIteratorRange NextRelocs); }; template Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -173,6 +173,52 @@ template template +uint8_t *InputSectionBase::getLocalPaired( + uintX_t &SymVA, uint8_t *Buf, uint8_t *BufLoc, uint32_t Type, + uint32_t SymIndex, RelIteratorRange NextRelocs) { + if (Config->EMachine != EM_MIPS) + return nullptr; + + if (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32) { + // 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. + SymVA += File->getMipsGp0(); + return nullptr; + } + + if (Type != R_MIPS_GOT16) + return findMipsPairedReloc(Buf, SymIndex, getMipsPairedRelocType(Type), + NextRelocs); + + // R_MIPS_GOT16 relocation against local symbol requires index of + // a local GOT entry which contains page address corresponds + // to sum of the symbol address and addend. The addend in that case + // is calculated using addends from R_MIPS_GOT16 and paired + // R_MIPS_LO16 relocations. + const endianness E = ELFT::TargetEndianness; + uint8_t *LowLoc = findMipsPairedReloc(Buf, SymIndex, R_MIPS_LO16, NextRelocs); + uint64_t AHL = read32(BufLoc) << 16; + if (LowLoc) + AHL += SignExtend64<16>(read32(LowLoc)); + SymVA = Out::Got->getMipsLocalPageAddr(SymVA + AHL); + return nullptr; +} + +template +static uintX_t adjustMipsGpSymVA(uint32_t Type, SymbolBody &Body, + uintX_t AddrLoc) { + if (Type == R_MIPS_HI16 && &Body == Config->MipsGpDisp) + return getMipsGpAddr() - AddrLoc; + if (Type == R_MIPS_LO16 && &Body == Config->MipsGpDisp) + return getMipsGpAddr() - AddrLoc + 4; + if (&Body == Config->MipsLocalGp) + return getMipsGpAddr(); + return Body.getVA(); +} + +template +template void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd, RelIteratorRange Rels) { typedef Elf_Rel_Impl RelType; @@ -188,7 +234,7 @@ uint32_t Type = RI.getType(Config->Mips64EL); uint8_t *BufLoc = Buf + Offset; uintX_t AddrLoc = OutSec->getVA() + Offset; - auto NextRelocs = llvm::make_range(&RI, Rels.end()); + auto NextRel = llvm::make_range(&RI, Rels.end()); if (Target->pointsToLocalDynamicGotEntry(Type) && !Target->canRelaxTls(Type, nullptr)) { @@ -225,31 +271,8 @@ // Handle relocations for local symbols. if (Body.isLocal()) { uintX_t SymVA = Body.getVA(A); - uint8_t *PairedLoc = nullptr; - if (Config->EMachine == EM_MIPS) { - if (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32) - // 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. - SymVA += File->getMipsGp0(); - else if (Type == R_MIPS_GOT16) { - // R_MIPS_GOT16 relocation against local symbol requires index of - // a local GOT entry which contains page address corresponds - // to sum of the symbol address and addend. The addend in that case - // is calculated using addends from R_MIPS_GOT16 and paired - // R_MIPS_LO16 relocations. - const endianness E = ELFT::TargetEndianness; - uint8_t *LowLoc = - findMipsPairedReloc(Buf, SymIndex, R_MIPS_LO16, NextRelocs); - uint64_t AHL = read32(BufLoc) << 16; - if (LowLoc) - AHL += SignExtend64<16>(read32(LowLoc)); - SymVA = Out::Got->getMipsLocalPageAddr(SymVA + AHL); - } else - PairedLoc = findMipsPairedReloc( - Buf, SymIndex, getMipsPairedRelocType(Type), NextRelocs); - } - Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, PairedLoc); + uint8_t *P = getLocalPaired(SymVA, Buf, BufLoc, Type, SymIndex, NextRel); + Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, P); continue; } @@ -281,12 +304,7 @@ // with a possibly incorrect value. continue; } else if (Config->EMachine == EM_MIPS) { - if (Type == R_MIPS_HI16 && &Body == Config->MipsGpDisp) - SymVA = getMipsGpAddr() - AddrLoc; - else if (Type == R_MIPS_LO16 && &Body == Config->MipsGpDisp) - SymVA = getMipsGpAddr() - AddrLoc + 4; - else if (&Body == Config->MipsLocalGp) - SymVA = getMipsGpAddr(); + SymVA = adjustMipsGpSymVA(Type, Body, AddrLoc); } else if (!Target->needsCopyRel(Type, Body) && CBP) { continue; } @@ -294,7 +312,7 @@ Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A, findMipsPairedReloc(Buf, SymIndex, getMipsPairedRelocType(Type), - NextRelocs)); + NextRel)); } }