From b0210e83b32dd529ba441ef0e614b592ee169ac4 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Tue, 26 Jan 2016 00:24:57 +0000 Subject: [PATCH] ELF: Move code for GNU_IFUNC to one place. NFC. This does not solve the problem that we call isGnuIFunc function both from RelocationSection and from the Writer::scanRelocs, but this at least should improve readability. I'm taking an incremental approach to reduce complexity. llvm-svn: 258753 --- lld/ELF/OutputSections.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index a3160c3b89af..979728e05a3d 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -300,15 +300,27 @@ template void RelocationSection::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(*Body)) { + P->setSymbolAndType(0, Target->getIRelativeReloc(), Config->Mips64EL); + if (Out::GotPlt) + P->r_offset = Out::GotPlt->getEntryAddr(*Body); + else + P->r_offset = Out::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(*Body)) - Reloc = Target->getIRelativeReloc(); - else if (!CBP || IsDynRelative) + if (!CBP || IsDynRelative) Reloc = Target->getRelativeReloc(); else if (LazyReloc) Reloc = Target->getPltReloc();