Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -176,6 +176,49 @@ return nullptr; } +template +static uintX_t adjustMipsSymVA(uint32_t Type, const ObjectFile &File, + const SymbolBody &Body, uintX_t AddrLoc, + uintX_t SymVA) { + 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(); + if (Body.isLocal() && (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. + return SymVA + File.getMipsGp0(); + return SymVA; +} + +template +static uintX_t getMipsGotVA(const SymbolBody &Body, uintX_t SymVA, + uint8_t *BufLoc, uint8_t *PairedLoc) { + if (Body.isLocal()) { + // 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. The addend in that case is + // calculated using addends from R_MIPS_GOT16 and paired R_MIPS_LO16 + // relocations. + const endianness E = ELFT::TargetEndianness; + uint64_t AHL = read32(BufLoc) << 16; + if (PairedLoc) + AHL += SignExtend64<16>(read32(PairedLoc)); + return Out::Got->getMipsLocalPageAddr(SymVA + AHL); + } + if (!canBePreempted(Body)) + // For non-local symbols GOT entries should contain their full + // addresses. But if such symbol cannot be preempted, we do not + // have to put them into the "global" part of GOT and use dynamic + // linker to determine their actual addresses. That is why we + // create GOT entries for them in the "local" part of GOT. + return Out::Got->getMipsLocalFullAddr(Body); + return Body.getGotVA(); +} + template template void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd, @@ -239,29 +282,10 @@ if (Target->needsPlt(Type, Body)) { SymVA = Body.getPltVA() + A; } else if (Target->needsGot(Type, Body)) { - if (Config->EMachine == EM_MIPS && !CBP) { - if (Body.isLocal()) { - // 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; - uint64_t AHL = read32(BufLoc) << 16; - if (PairedLoc) - AHL += SignExtend64<16>(read32(PairedLoc)); - SymVA = Out::Got->getMipsLocalPageAddr(SymVA + AHL); - } else { - // For non-local symbols GOT entries should contain their full - // addresses. But if such symbol cannot be preempted, we do not - // have to put them into the "global" part of GOT and use dynamic - // linker to determine their actual addresses. That is why we - // create GOT entries for them in the "local" part of GOT. - SymVA = Out::Got->getMipsLocalFullAddr(Body) + A; - } - } else { + if (Config->EMachine == EM_MIPS) + SymVA = getMipsGotVA(Body, SymVA, BufLoc, PairedLoc) + A; + else SymVA = Body.getGotVA() + A; - } if (Body.IsTls) Type = Target->getTlsGotRel(Type); } else if (Target->isSizeRel(Type) && CBP) { @@ -271,18 +295,7 @@ // with a possibly incorrect value. continue; } else if (Config->EMachine == EM_MIPS) { - if (Type == R_MIPS_HI16 && &Body == Config->MipsGpDisp) { - SymVA = getMipsGpAddr() - AddrLoc + A; - } else if (Type == R_MIPS_LO16 && &Body == Config->MipsGpDisp) { - SymVA = getMipsGpAddr() - AddrLoc + 4 + A; - } else if (&Body == Config->MipsLocalGp) { - SymVA = getMipsGpAddr() + A; - } else 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(); - } + SymVA = adjustMipsSymVA(Type, *File, Body, AddrLoc, SymVA) + A; } else if (!Target->needsCopyRel(Type, Body) && CBP) { continue; }