diff options
-rw-r--r-- | lld/ELF/OutputSections.cpp | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index a3160c3b89a..979728e05a3 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -300,15 +300,27 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body); bool CBP = canBePreempted(Body, NeedsGot); + + // For a symbol with STT_GNU_IFUNC type, we always create a PLT and + // a GOT entry for the symbol, and emit an IRELATIVE reloc rather than + // the usual JUMP_SLOT reloc for the GOT entry. For the details, you + // want to read http://www.airs.com/blog/archives/403 + if (!CBP && Body && isGnuIFunc<ELFT>(*Body)) { + P->setSymbolAndType(0, Target->getIRelativeReloc(), Config->Mips64EL); + if (Out<ELFT>::GotPlt) + P->r_offset = Out<ELFT>::GotPlt->getEntryAddr(*Body); + else + P->r_offset = Out<ELFT>::Got->getEntryAddr(*Body); + continue; + } + bool LazyReloc = Body && Target->supportsLazyRelocations() && Target->relocNeedsPlt(Type, *Body); bool IsDynRelative = Type == Target->getRelativeReloc(); unsigned Sym = CBP ? Body->DynamicSymbolTableIndex : 0; unsigned Reloc; - if (!CBP && Body && isGnuIFunc<ELFT>(*Body)) - Reloc = Target->getIRelativeReloc(); - else if (!CBP || IsDynRelative) + if (!CBP || IsDynRelative) Reloc = Target->getRelativeReloc(); else if (LazyReloc) Reloc = Target->getPltReloc(); |