[lld] r250432 - ELF2: Implement __start_SECNAME and __stop_SECNAME.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 15 10:11:03 PDT 2015


Author: ruiu
Date: Thu Oct 15 12:11:03 2015
New Revision: 250432

URL: http://llvm.org/viewvc/llvm-project?rev=250432&view=rev
Log:
ELF2: Implement __start_SECNAME and __stop_SECNAME.

If a section name is valid as a C identifier (which is rare because of
the leading '.'), linkers are expected to define __start_<secname> and
__stop_<secname> symbols. They are at beginning and end of the section,
respectively. This is not requested by the ELF standard, but GNU ld and
gold provide this feature.

Added:
    lld/trunk/test/elf2/startstop.s
Modified:
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=250432&r1=250431&r2=250432&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Thu Oct 15 12:11:03 2015
@@ -88,6 +88,12 @@ template <class ELFT> void SymbolTable<E
   resolve(Sym);
 }
 
+template <class ELFT> bool SymbolTable<ELFT>::isUndefined(StringRef Name) {
+  if (SymbolBody *Sym = find(Name))
+    return Sym->isUndefined();
+  return false;
+}
+
 template <class ELFT>
 void SymbolTable<ELFT>::addELFFile(ELFFileBase<ELFT> *File) {
   if (auto *O = dyn_cast<ObjectFile<ELFT>>(File))

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=250432&r1=250431&r2=250432&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Thu Oct 15 12:11:03 2015
@@ -54,6 +54,7 @@ public:
                        OutputSectionBase<ELFT::Is64Bits> &Section,
                        typename llvm::object::ELFFile<ELFT>::uintX_t Value);
   void addIgnoredSym(StringRef Name);
+  bool isUndefined(StringRef Name);
   void scanShlibUndefined();
 
 private:

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=250432&r1=250431&r2=250432&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Oct 15 12:11:03 2015
@@ -16,6 +16,7 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/StringSaver.h"
 
 using namespace llvm;
 using namespace llvm::ELF;
@@ -70,9 +71,11 @@ private:
   std::unique_ptr<llvm::FileOutputBuffer> Buffer;
 
   SpecificBumpPtrAllocator<OutputSection<ELFT>> SecAlloc;
+  BumpPtrAllocator Alloc;
   std::vector<OutputSectionBase<ELFT::Is64Bits> *> OutputSections;
   unsigned getNumSections() const { return OutputSections.size() + 1; }
 
+  void addStartStopSymbols(OutputSection<ELFT> *Sec);
   void setPhdr(Elf_Phdr *PH, uint32_t Type, uint32_t Flags, uintX_t FileOff,
                uintX_t VA, uintX_t Align);
   void copyPhdr(Elf_Phdr *PH, OutputSectionBase<ELFT::Is64Bits> *From);
@@ -400,6 +403,8 @@ template <class ELFT> void Writer<ELFT>:
   if (!isOutputDynamic())
     Symtab.addIgnoredSym("__tls_get_addr");
 
+  std::vector<OutputSection<ELFT> *> RegularSections;
+
   for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
     for (InputSection<ELFT> *C : F->getSections()) {
       if (!C || C == &InputSection<ELFT>::Discarded)
@@ -413,12 +418,16 @@ template <class ELFT> void Writer<ELFT>:
         Sec = new (SecAlloc.Allocate())
             OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
         OutputSections.push_back(Sec);
+        RegularSections.push_back(Sec);
       }
       Sec->addSection(C);
       scanRelocs(*C);
     }
   }
 
+  for (OutputSection<ELFT> *Sec : RegularSections)
+    addStartStopSymbols(Sec);
+
   Out<ELFT>::Dynamic->PreInitArraySec =
       Map.lookup({".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC});
   Out<ELFT>::Dynamic->InitArraySec =
@@ -501,6 +510,38 @@ template <class ELFT> void Writer<ELFT>:
   Out<ELFT>::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC});
 }
 
+static bool isAlpha(char C) {
+  return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_';
+}
+
+static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); }
+
+// Returns true if S is valid as a C language identifier.
+static bool isValidCIdentifier(StringRef S) {
+  if (S.empty() || !isAlpha(S[0]))
+    return false;
+  return std::all_of(S.begin() + 1, S.end(), isAlnum);
+}
+
+// If a section name is valid as a C identifier (which is rare because of
+// the leading '.'), linkers are expected to define __start_<secname> and
+// __stop_<secname> symbols. They are at beginning and end of the section,
+// respectively. This is not requested by the ELF standard, but GNU ld and
+// gold provide the feature, and used by many programs.
+template <class ELFT>
+void Writer<ELFT>::addStartStopSymbols(OutputSection<ELFT> *Sec) {
+  StringRef S = Sec->getName();
+  if (!isValidCIdentifier(S))
+    return;
+  StringSaver Saver(Alloc);
+  StringRef Start = Saver.save("__start_" + S);
+  StringRef Stop = Saver.save("__stop_" + S);
+  if (Symtab.isUndefined(Start))
+    Symtab.addSyntheticSym(Start, *Sec, 0);
+  if (Symtab.isUndefined(Stop))
+    Symtab.addSyntheticSym(Stop, *Sec, Sec->getSize());
+}
+
 template <class ELFT>
 static bool needsPhdr(OutputSectionBase<ELFT::Is64Bits> *Sec) {
   return Sec->getFlags() & SHF_ALLOC;

Added: lld/trunk/test/elf2/startstop.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/startstop.s?rev=250432&view=auto
==============================================================================
--- lld/trunk/test/elf2/startstop.s (added)
+++ lld/trunk/test/elf2/startstop.s Thu Oct 15 12:11:03 2015
@@ -0,0 +1,54 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld2 %t -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+// RUN: llvm-readobj -symbols %tout | FileCheck -check-prefix=SYMBOL %s
+
+// DISASM: _start:
+// DISASM:    11000:       e8 0a 00 00 00  callq   10
+// DISASM:    11005:       e8 08 00 00 00  callq   8
+// DISASM:    1100a:       e8 03 00 00 00  callq   3
+// DISASM: Disassembly of section foo:
+// DISASM: __start_foo:
+// DISASM:    1100f:       90      nop
+// DISASM:    11010:       90      nop
+// DISASM:    11011:       90      nop
+// DISASM: Disassembly of section bar:
+// DISASM: __start_bar:
+// DISASM:    11012:       90      nop
+// DISASM:    11013:       90      nop
+// DISASM:    11014:       90      nop
+
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __start_bar
+// SYMBOL:   Value: 0x11012
+// SYMBOL:   Section: bar
+// SYMBOL: }
+// SYMBOL-NOT:   Section: __stop_bar
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __start_foo
+// SYMBOL:   Value: 0x1100F
+// SYMBOL:   Section: foo
+// SYMBOL: }
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __stop_foo
+// SYMBOL:   Value: 0x11012
+// SYMBOL:   Section: foo (0x2)
+// SYMBOL: }
+
+.global _start
+.text
+_start:
+	call __start_foo
+	call __stop_foo
+	call __start_bar
+
+.section foo,"ax"
+	nop
+	nop
+	nop
+
+.section bar,"ax"
+	nop
+	nop
+	nop




More information about the llvm-commits mailing list