[lld] r268350 - ELF: Forbid all relative relocations to absolute symbols in PIC, except for weak undefined.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Mon May 2 18:21:09 PDT 2016


Author: pcc
Date: Mon May  2 20:21:08 2016
New Revision: 268350

URL: http://llvm.org/viewvc/llvm-project?rev=268350&view=rev
Log:
ELF: Forbid all relative relocations to absolute symbols in PIC, except for weak undefined.

Weak undefined symbols resolve to the image base. This is a little strange,
but it allows us to link function calls to such symbols. Normally such a
call will be guarded with a comparison, which will load a zero from the GOT.

There's one example of such a function call in crti.o in Linux's CRT.

As part of this change, I also needed to make the synthetic start and end
symbols image base relative in the case where their sections were empty,
so that PC-relative references to those symbols would continue to work.

Differential Revision: http://reviews.llvm.org/D19844

Added:
    lld/trunk/test/ELF/relocation-relative-absolute.s
    lld/trunk/test/ELF/relocation-relative-synthetic.s
    lld/trunk/test/ELF/relocation-relative-weak.s
Modified:
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=268350&r1=268349&r2=268350&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Mon May  2 20:21:08 2016
@@ -1496,7 +1496,7 @@ const OutputSectionBase<ELFT> *
 SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
   switch (Sym->kind()) {
   case SymbolBody::DefinedSyntheticKind:
-    return &cast<DefinedSynthetic<ELFT>>(Sym)->Section;
+    return cast<DefinedSynthetic<ELFT>>(Sym)->Section;
   case SymbolBody::DefinedRegularKind: {
     auto &D = cast<DefinedRegular<ELFT>>(*Sym);
     if (D.Section)

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=268350&r1=268349&r2=268350&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Mon May  2 20:21:08 2016
@@ -388,7 +388,7 @@ Symbol *SymbolTable<ELFT>::addRegular(St
 
 template <typename ELFT>
 Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
-                                        OutputSectionBase<ELFT> &Section,
+                                        OutputSectionBase<ELFT> *Section,
                                         uintX_t Value) {
   Symbol *S;
   bool WasInserted;

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=268350&r1=268349&r2=268350&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Mon May  2 20:21:08 2016
@@ -64,7 +64,7 @@ public:
   Symbol *addRegular(StringRef Name, const Elf_Sym &Sym,
                      InputSectionBase<ELFT> *Section);
   Symbol *addRegular(StringRef Name, uint8_t Binding, uint8_t StOther);
-  Symbol *addSynthetic(StringRef N, OutputSectionBase<ELFT> &Section,
+  Symbol *addSynthetic(StringRef N, OutputSectionBase<ELFT> *Section,
                        uintX_t Value);
   void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
                  const typename ELFT::Verdef *Verdef);

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=268350&r1=268349&r2=268350&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Mon May  2 20:21:08 2016
@@ -36,9 +36,12 @@ static typename ELFT::uint getSymVA(cons
   switch (Body.kind()) {
   case SymbolBody::DefinedSyntheticKind: {
     auto &D = cast<DefinedSynthetic<ELFT>>(Body);
+    const OutputSectionBase<ELFT> *Sec = D.Section;
+    if (!Sec)
+      return D.Value;
     if (D.Value == DefinedSynthetic<ELFT>::SectionEnd)
-      return D.Section.getVA() + D.Section.getSize();
-    return D.Section.getVA() + D.Value;
+      return Sec->getVA() + Sec->getSize();
+    return Sec->getVA() + D.Value;
   }
   case SymbolBody::DefinedRegularKind: {
     auto &D = cast<DefinedRegular<ELFT>>(Body);
@@ -208,7 +211,7 @@ Undefined::Undefined(uint32_t NameOffset
 
 template <typename ELFT>
 DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
-                                         OutputSectionBase<ELFT> &Section)
+                                         OutputSectionBase<ELFT> *Section)
     : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */),
       Value(Value), Section(Section) {}
 

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=268350&r1=268349&r2=268350&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Mon May  2 20:21:08 2016
@@ -237,11 +237,12 @@ InputSectionBase<ELFT> *DefinedRegular<E
 // The difference from the regular symbol is that DefinedSynthetic symbols
 // don't belong to any input files or sections. Thus, its constructor
 // takes an output section to calculate output VA, etc.
+// If Section is null, this symbol is relative to the image base.
 template <class ELFT> class DefinedSynthetic : public Defined {
 public:
   typedef typename ELFT::uint uintX_t;
   DefinedSynthetic(StringRef N, uintX_t Value,
-                   OutputSectionBase<ELFT> &Section);
+                   OutputSectionBase<ELFT> *Section);
 
   static bool classof(const SymbolBody *S) {
     return S->kind() == SymbolBody::DefinedSyntheticKind;
@@ -252,7 +253,7 @@ public:
   static const uintX_t SectionEnd = uintX_t(-1);
 
   uintX_t Value;
-  const OutputSectionBase<ELFT> &Section;
+  const OutputSectionBase<ELFT> *Section;
 };
 
 class Undefined : public SymbolBody {

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=268350&r1=268349&r2=268350&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon May  2 20:21:08 2016
@@ -454,6 +454,20 @@ static bool isRelRelative(RelExpr E, uin
   if (!AbsVal && RelE)
     return true;
 
+  // Relative relocation to an absolute value. This is normally unrepresentable,
+  // but if the relocation refers to a weak undefined symbol, we allow it to
+  // resolve to the image base. This is a little strange, but it allows us to
+  // link function calls to such symbols. Normally such a call will be guarded
+  // with a comparison, which will load a zero from the GOT.
+  if (AbsVal && RelE) {
+    if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
+      return true;
+    StringRef S = getELFRelocationTypeName(Config->EMachine, Type);
+    error("relocation " + S + " cannot refer to absolute symbol " +
+          Body.getName());
+    return true;
+  }
+
   return Target->usesOnlyLowPageBits(Type);
 }
 
@@ -1067,7 +1081,7 @@ bool Writer<ELFT>::isDiscarded(InputSect
 
 template <class ELFT>
 static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name,
-                                    OutputSectionBase<ELFT> &Sec,
+                                    OutputSectionBase<ELFT> *Sec,
                                     typename ELFT::uint Val) {
   if (!Table.find(Name))
     return nullptr;
@@ -1084,10 +1098,10 @@ template <class ELFT> void Writer<ELFT>:
   if (isOutputDynamic() || !Out<ELFT>::RelaPlt)
     return;
   StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
-  addOptionalSynthetic(Symtab, S, *Out<ELFT>::RelaPlt, 0);
+  addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, 0);
 
   S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
-  addOptionalSynthetic(Symtab, S, *Out<ELFT>::RelaPlt,
+  addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt,
                        DefinedSynthetic<ELFT>::SectionEnd);
 }
 
@@ -1189,18 +1203,18 @@ template <class ELFT> void Writer<ELFT>:
     // so that it points to an absolute address which is relative to GOT.
     // See "Global Data Symbols" in Chapter 6 in the following document:
     // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-    Symtab.addSynthetic("_gp", *Out<ELFT>::Got, MipsGPOffset);
+    Symtab.addSynthetic("_gp", Out<ELFT>::Got, MipsGPOffset);
 
     // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
     // start of function and 'gp' pointer into GOT.
     ElfSym<ELFT>::MipsGpDisp =
-        addOptionalSynthetic(Symtab, "_gp_disp", *Out<ELFT>::Got, MipsGPOffset)
+        addOptionalSynthetic(Symtab, "_gp_disp", Out<ELFT>::Got, MipsGPOffset)
             ->body();
     // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
     // pointer. This symbol is used in the code generated by .cpload pseudo-op
     // in case of using -mno-shared option.
     // https://sourceware.org/ml/binutils/2004-12/msg00094.html
-    addOptionalSynthetic(Symtab, "__gnu_local_gp", *Out<ELFT>::Got,
+    addOptionalSynthetic(Symtab, "__gnu_local_gp", Out<ELFT>::Got,
                          MipsGPOffset);
   }
 
@@ -1327,7 +1341,7 @@ template <class ELFT> void Writer<ELFT>:
   // Even the author of gold doesn't remember why gold behaves that way.
   // https://sourceware.org/ml/binutils/2002-03/msg00360.html
   if (isOutputDynamic())
-    Symtab.addSynthetic("_DYNAMIC", *Out<ELFT>::Dynamic, 0);
+    Symtab.addSynthetic("_DYNAMIC", Out<ELFT>::Dynamic, 0);
 
   // Define __rel[a]_iplt_{start,end} symbols if needed.
   addRelIpltSymbols();
@@ -1487,11 +1501,13 @@ template <class ELFT> void Writer<ELFT>:
   auto Define = [&](StringRef Start, StringRef End,
                     OutputSectionBase<ELFT> *OS) {
     if (OS) {
-      this->Symtab.addSynthetic(Start, *OS, 0);
-      this->Symtab.addSynthetic(End, *OS, DefinedSynthetic<ELFT>::SectionEnd);
+      this->Symtab.addSynthetic(Start, OS, 0);
+      this->Symtab.addSynthetic(End, OS, DefinedSynthetic<ELFT>::SectionEnd);
     } else {
-      this->Symtab.addIgnored(Start);
-      this->Symtab.addIgnored(End);
+      addOptionalSynthetic(this->Symtab, Start,
+                           (OutputSectionBase<ELFT> *)nullptr, 0);
+      addOptionalSynthetic(this->Symtab, End,
+                           (OutputSectionBase<ELFT> *)nullptr, 0);
     }
   };
 
@@ -1518,10 +1534,10 @@ void Writer<ELFT>::addStartStopSymbols(O
   StringRef Stop = Saver.save("__stop_" + S);
   if (SymbolBody *B = Symtab.find(Start))
     if (B->isUndefined())
-      Symtab.addSynthetic(Start, *Sec, 0);
+      Symtab.addSynthetic(Start, Sec, 0);
   if (SymbolBody *B = Symtab.find(Stop))
     if (B->isUndefined())
-      Symtab.addSynthetic(Stop, *Sec, DefinedSynthetic<ELFT>::SectionEnd);
+      Symtab.addSynthetic(Stop, Sec, DefinedSynthetic<ELFT>::SectionEnd);
 }
 
 template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) {

Added: lld/trunk/test/ELF/relocation-relative-absolute.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/relocation-relative-absolute.s?rev=268350&view=auto
==============================================================================
--- lld/trunk/test/ELF/relocation-relative-absolute.s (added)
+++ lld/trunk/test/ELF/relocation-relative-absolute.s Mon May  2 20:21:08 2016
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s
+
+.globl _start
+_start:
+
+# CHECK: relocation R_X86_64_PLT32 cannot refer to absolute symbol answer
+call answer at PLT
+
+.globl answer
+answer = 42

Added: lld/trunk/test/ELF/relocation-relative-synthetic.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/relocation-relative-synthetic.s?rev=268350&view=auto
==============================================================================
--- lld/trunk/test/ELF/relocation-relative-synthetic.s (added)
+++ lld/trunk/test/ELF/relocation-relative-synthetic.s Mon May  2 20:21:08 2016
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+call __init_array_start at PLT

Added: lld/trunk/test/ELF/relocation-relative-weak.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/relocation-relative-weak.s?rev=268350&view=auto
==============================================================================
--- lld/trunk/test/ELF/relocation-relative-weak.s (added)
+++ lld/trunk/test/ELF/relocation-relative-weak.s Mon May  2 20:21:08 2016
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+
+.globl w
+.weak w
+call w at PLT




More information about the llvm-commits mailing list