[lld] r368661 - [ELF] Don't special case symbolic relocations with 0 addend to ifunc in writable locations

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 13 02:43:40 PDT 2019


Author: maskray
Date: Tue Aug 13 02:43:40 2019
New Revision: 368661

URL: http://llvm.org/viewvc/llvm-project?rev=368661&view=rev
Log:
[ELF] Don't special case symbolic relocations with 0 addend to ifunc in writable locations

Currently the following 3 relocation types do not trigger the creation
of a canonical PLT (which changes STT_GNU_IFUNC to STT_FUNC and
redirects all references):

1) GOT-generating (`needsGot`)
2) PLT-generating (`needsPlt`)
3) R_ABS with 0 addend in a writable location. This is used for
  for ifunc function pointers in writable sections such as .data and .toc.

This patch deletes case 3) to simplify the R_*_IRELATIVE generating
logic added in D57371. Other advantages:

* It is guaranteed no more than 1 R_*_IRELATIVE is created for an ifunc.
* PPC64: no need to special case ifunc in toc-indirect to toc-relative relaxation. See D65755

The deleted elf::addIRelativeRelocs demonstrates that one-pass scan
through relocations makes several optimizations difficult. This is
something we can think about in the future.

Reviewed By: peter.smith

Differential Revision: https://reviews.llvm.org/D65995

Added:
    lld/trunk/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s
Modified:
    lld/trunk/ELF/Arch/PPC64.cpp
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/gnu-ifunc-canon.s
    lld/trunk/test/ELF/ppc64-toc-relax-ifunc.s

Modified: lld/trunk/ELF/Arch/PPC64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC64.cpp?rev=368661&r1=368660&r2=368661&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC64.cpp (original)
+++ lld/trunk/ELF/Arch/PPC64.cpp Tue Aug 13 02:43:40 2019
@@ -172,13 +172,13 @@ bool elf::tryRelaxPPC64TocIndirection(Re
                    : getRelaTocSymAndAddend<ELF64BE>(tocISB, rel.addend);
 
   // Only non-preemptable defined symbols can be relaxed.
-  //
-  // The toc entry of a non-preemptable ifunc is relocated by R_PPC64_IRELATIVE,
-  // which will run at load time to determine the relocated value. It is not
-  // known until load time, so the access cannot be relaxed.
-  if (!d || d->isPreemptible || d->isGnuIFunc())
+  if (!d || d->isPreemptible)
     return false;
 
+  // R_PPC64_ADDR64 should have created a canonical PLT for the non-preemptable
+  // ifunc and changed its type to STT_FUNC.
+  assert(!d->isGnuIFunc());
+
   // Two instructions can materialize a 32-bit signed offset from the toc base.
   uint64_t tocRelative = d->getVA(addend) - getPPC64TocBase();
   if (!isInt<32>(tocRelative))

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=368661&r1=368660&r2=368661&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Tue Aug 13 02:43:40 2019
@@ -1089,15 +1089,6 @@ static void processRelocAux(InputSection
               getLocation(sec, sym, offset));
 }
 
-struct IRelativeReloc {
-  RelType type;
-  InputSectionBase *sec;
-  uint64_t offset;
-  Symbol *sym;
-};
-
-static std::vector<IRelativeReloc> iRelativeRelocs;
-
 template <class ELFT, class RelTy>
 static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
                       RelTy *end) {
@@ -1265,12 +1256,6 @@ static void scanReloc(InputSectionBase &
     //   correctly, the IRELATIVE relocations are stored in an array which a
     //   statically linked executable's startup code must enumerate using the
     //   linker-defined symbols __rela?_iplt_{start,end}.
-    //
-    // - An absolute relocation to a non-preemptible ifunc (such as a global
-    //   variable containing a pointer to the ifunc) needs to be relocated in
-    //   the exact same way as a GOT entry, so we can avoid needing to make the
-    //   PLT entry canonical by translating such relocations into IRELATIVE
-    //   relocations in the relaIplt.
     if (!sym.isInPlt()) {
       // Create PLT and GOTPLT slots for the symbol.
       sym.isInIplt = true;
@@ -1287,17 +1272,6 @@ static void scanReloc(InputSectionBase &
                         *directSym);
       sym.pltIndex = directSym->pltIndex;
     }
-    if (expr == R_ABS && addend == 0 && (sec.flags & SHF_WRITE)) {
-      // We might be able to represent this as an IRELATIVE. But we don't know
-      // yet whether some later relocation will make the symbol point to a
-      // canonical PLT, which would make this either a dynamic RELATIVE (PIC) or
-      // static (non-PIC) relocation. So we keep a record of the information
-      // required to process the relocation, and after scanRelocs() has been
-      // called on all relocations, the relocation is resolved by
-      // addIRelativeRelocs().
-      iRelativeRelocs.push_back({type, &sec, offset, &sym});
-      return;
-    }
     if (needsGot(expr)) {
       // Redirect GOT accesses to point to the Igot.
       //
@@ -1365,21 +1339,6 @@ template <class ELFT> void elf::scanRelo
     scanRelocs<ELFT>(s, s.rels<ELFT>());
 }
 
-// Figure out which representation to use for any absolute relocs to
-// non-preemptible ifuncs that we visited during scanRelocs().
-void elf::addIRelativeRelocs() {
-  for (IRelativeReloc &r : iRelativeRelocs) {
-    if (r.sym->type == STT_GNU_IFUNC)
-      in.relaIplt->addReloc(
-          {target->iRelativeRel, r.sec, r.offset, true, r.sym, 0});
-    else if (config->isPic)
-      addRelativeReloc(r.sec, r.offset, r.sym, 0, R_ABS, r.type);
-    else
-      r.sec->relocations.push_back({R_ABS, r.type, r.offset, 0, r.sym});
-  }
-  iRelativeRelocs.clear();
-}
-
 static bool mergeCmp(const InputSection *a, const InputSection *b) {
   // std::merge requires a strict weak ordering.
   if (a->outSecOff < b->outSecOff)

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=368661&r1=368660&r2=368661&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Tue Aug 13 02:43:40 2019
@@ -1738,8 +1738,6 @@ template <class ELFT> void Writer<ELFT>:
     reportUndefinedSymbols<ELFT>();
   }
 
-  addIRelativeRelocs();
-
   if (in.plt && in.plt->isNeeded())
     in.plt->addSymbols();
   if (in.iplt && in.iplt->isNeeded())

Added: lld/trunk/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s?rev=368661&view=auto
==============================================================================
--- lld/trunk/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s (added)
+++ lld/trunk/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s Tue Aug 13 02:43:40 2019
@@ -0,0 +1,36 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -S -s %t | FileCheck %s --check-prefix=SEC
+# RUN: llvm-readelf -x .rodata -x .data %t | FileCheck --check-prefix=HEX %s
+# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
+
+## ifunc is a non-preemptable STT_GNU_IFUNC. Check we create a canonical PLT
+## and redirect .rodata and .data references to it.
+
+# SEC: .text    PROGBITS 0000000000210000
+# SEC: .got.plt PROGBITS 0000000000220008
+# SEC: 0000000000210010 0 FUNC GLOBAL DEFAULT 4 ifunc
+
+## .rodata[0] and .data[0] store the address of the canonical PLT.
+# HEX:      section '.rodata':
+# HEX-NEXT: 0x00200170 10002100 00000000
+# HEX:      section '.data':
+# HEX-NEXT: 0x00220000 10002100 00000000
+
+# RELOC:      .rela.dyn {
+# RELOC-NEXT:   0x220008 R_AARCH64_IRELATIVE - 0x210000
+# RELOC-NEXT: }
+
+.globl ifunc
+.type ifunc, at gnu_indirect_function
+ifunc:
+  ret
+
+.rodata
+.p2align 3
+.xword ifunc
+
+.data
+.p2align 3
+.xword ifunc

Modified: lld/trunk/test/ELF/gnu-ifunc-canon.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gnu-ifunc-canon.s?rev=368661&r1=368660&r2=368661&view=diff
==============================================================================
--- lld/trunk/test/ELF/gnu-ifunc-canon.s (original)
+++ lld/trunk/test/ELF/gnu-ifunc-canon.s Tue Aug 13 02:43:40 2019
@@ -4,7 +4,7 @@
 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-ro-abs.s -o %t-ro-abs.o
 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-rw-addend.s -o %t-rw-addend.o
 // RUN: ld.lld %t.o -o %t1
-// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=IREL2 %s
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=IREL1 %s
 // RUN: ld.lld %t.o %t-ro-pcrel.o -o %t2
 // RUN: llvm-readobj -r %t2 | FileCheck --check-prefix=IREL1 %s
 // RUN: ld.lld %t.o %t-ro-abs.o -o %t3
@@ -22,7 +22,7 @@
 // RUN: ld.lld %t-rw-addend.o %t.o -o %t7
 // RUN: llvm-readobj -r %t7 | FileCheck --check-prefix=IREL1 %s
 // RUN: ld.lld %t.o -o %t8 -pie
-// RUN: llvm-readobj -r %t8 | FileCheck --check-prefix=IREL2 %s
+// RUN: llvm-readobj -r %t8 | FileCheck --check-prefix=IREL1-REL2 %s
 // RUN: ld.lld %t.o %t-ro-pcrel.o -o %t9 -pie
 // RUN: llvm-readobj -r %t9 | FileCheck --check-prefix=IREL1-REL2 %s
 // RUN: ld.lld %t.o %t-rw-addend.o -o %t10 -pie
@@ -32,13 +32,6 @@
 // RUN: ld.lld %t-rw-addend.o %t.o -o %t12 -pie
 // RUN: llvm-readobj -r %t12 | FileCheck --check-prefix=IREL1-REL3 %s
 
-// Two relocs, one for the GOT and the other for .data.
-// IREL2-NOT: R_X86_64_
-// IREL2: .rela.dyn
-// IREL2-NEXT: R_X86_64_IRELATIVE
-// IREL2-NEXT: R_X86_64_IRELATIVE
-// IREL2-NOT: R_X86_64_
-
 // One reloc for the canonical PLT.
 // IREL1-NOT: R_X86_64_
 // IREL1: .rela.dyn

Modified: lld/trunk/test/ELF/ppc64-toc-relax-ifunc.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-toc-relax-ifunc.s?rev=368661&r1=368660&r2=368661&view=diff
==============================================================================
--- lld/trunk/test/ELF/ppc64-toc-relax-ifunc.s (original)
+++ lld/trunk/test/ELF/ppc64-toc-relax-ifunc.s Tue Aug 13 02:43:40 2019
@@ -4,14 +4,28 @@
 # RUN: echo '.globl ifunc; .type ifunc, %gnu_indirect_function; ifunc:' | \
 # RUN:   llvm-mc -filetype=obj -triple=powerpc64le - -o %t1.o
 # RUN: ld.lld %t.o %t1.o -o %t
-# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: llvm-readelf -S -s %t | FileCheck --check-prefix=SEC %s
+# RUN: llvm-readelf -x .toc %t | FileCheck --check-prefix=HEX %s
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=DIS %s
 
-## ifunc is a non-preemptable STT_GNU_IFUNC. Its toc entry will be
-## relocated by R_PPC64_IRELATIVE, not representable by a toc-relative value.
-## Check the toc-indirect access is not relaxed.
+## ifunc is a non-preemptable STT_GNU_IFUNC. The R_PPC64_ADDR64 in .toc
+## creates a canonical PLT for it and changes its type to STT_FUNC. We can thus
+## still perform toc-indirect to toc-relative relaxation because the distance
+## to the address of the canonical PLT is fixed.
 
-# CHECK:      nop
-# CHECK-NEXT: ld 3, -32768(2)
+# SEC: .text PROGBITS 0000000010010000
+# SEC: .plt  NOBITS   0000000010030000
+# SEC: 0000000010010010 0 FUNC GLOBAL DEFAULT 3 ifunc
+
+## .toc[0] stores the address of the canonical PLT.
+# HEX:      section '.toc':
+# HEX-NEXT: 0x10020000 10000110 00000000
+
+# REL:      .rela.dyn {
+# REL-NEXT:   0x10030000 R_PPC64_IRELATIVE - 0x10010008
+# REL-NEXT: }
+
+# DIS: addi 3, 3,
 
 addis 3, 2, .toc at toc@ha
 ld 3, .toc at toc@l(3)




More information about the llvm-commits mailing list