[lld] r189719 - [lld][ELF] Add Init/Fini support

Shankar Easwaran shankare at codeaurora.org
Fri Aug 30 22:27:44 PDT 2013


Author: shankare
Date: Sat Aug 31 00:27:44 2013
New Revision: 189719

URL: http://llvm.org/viewvc/llvm-project?rev=189719&view=rev
Log:
[lld][ELF] Add Init/Fini support

This creates .init_array/.fini_array section for X86_64 ELF
targets and executes init/fini functions specified by the
-init/-fini options respectively.

Added:
    lld/trunk/test/elf/X86_64/Inputs/initfini-option.c
    lld/trunk/test/elf/X86_64/Inputs/initfini-option.o
    lld/trunk/test/elf/X86_64/initfini-option.test
Modified:
    lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
    lld/trunk/lib/Driver/GnuLdDriver.cpp
    lld/trunk/lib/Driver/LDOptions.td
    lld/trunk/lib/ReaderWriter/ELF/Atoms.h
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h

Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Sat Aug 31 00:27:44 2013
@@ -159,6 +159,22 @@ public:
   /// Get the entry symbol name
   virtual StringRef entrySymbolName() const;
 
+  /// add to the list of initializer functions
+  void addInitFunction(StringRef name) { _initFunctions.push_back(name); }
+
+  /// add to the list of finalizer functions
+  void addFiniFunction(StringRef name) { _finiFunctions.push_back(name); }
+
+  /// Return the list of initializer symbols that are specified in the
+  /// linker command line, using the -init option.
+  range<const StringRef *> initFunctions() const {
+    return _initFunctions;
+  }
+
+  /// Return the list of finalizer symbols that are specified in the
+  /// linker command line, using the -fini option.
+  range<const StringRef *> finiFunctions() const { return _finiFunctions; }
+
 private:
   ELFLinkingContext() LLVM_DELETED_FUNCTION;
 
@@ -189,6 +205,8 @@ protected:
   std::unique_ptr<Writer> _writer;
   std::unique_ptr<Reader> _linkerScriptReader;
   StringRef _dynamicLinkerPath;
+  StringRefVector _initFunctions;
+  StringRefVector _finiFunctions;
 };
 } // end namespace lld
 

Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdDriver.cpp Sat Aug 31 00:27:44 2013
@@ -230,6 +230,14 @@ bool GnuLdDriver::parse(int argc, const
       ctx->addInitialUndefinedSymbol(inputArg->getValue());
       break;
 
+    case OPT_init:
+      ctx->addInitFunction(inputArg->getValue());
+      break;
+
+    case OPT_fini:
+      ctx->addFiniFunction(inputArg->getValue());
+      break;
+
     case OPT_emit_yaml:
       if (!_outputOptionSet)
         ctx->setOutputPath("-");

Modified: lld/trunk/lib/Driver/LDOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/LDOptions.td?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/Driver/LDOptions.td (original)
+++ lld/trunk/lib/Driver/LDOptions.td Sat Aug 31 00:27:44 2013
@@ -18,6 +18,13 @@ multiclass smDash<string opt1, string op
       Alias<!cast<Option>(opt1)>;
 }
 
+// Support -<option>,-<option>=
+multiclass dashEq<string opt1, string opt2, string help> {
+  def "" : Separate<["-"], opt1>, HelpText<help>;
+  def opt2_eq : Separate<["-"], opt2#"=">,
+      Alias<!cast<Option>(opt1)>;
+}
+
 defm e : smDash<"e", "entry",
          "Name of entry point symbol">;
 
@@ -102,6 +109,12 @@ def no_as_needed : Flag<["--"], "no-as-n
     HelpText<"This option restores the default behavior"
              " of adding DT_NEEDED entries">;
 
+defm init: dashEq<"init", "init",
+                 "Specify an initializer function">;
+
+defm fini: dashEq<"fini", "fini",
+                 "Specify a finalizer function">;
+
 // extensions
 def emit_yaml : Flag<["-"], "emit-yaml">, 
     HelpText<"Write YAML instead of ELF">;

Modified: lld/trunk/lib/ReaderWriter/ELF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Atoms.h?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Atoms.h Sat Aug 31 00:27:44 2013
@@ -879,6 +879,39 @@ public:
   virtual ArrayRef<uint8_t> rawContent() const { return ArrayRef<uint8_t>(); }
 };
 
+class InitFiniAtom : public SimpleDefinedAtom {
+  StringRef _section;
+
+public:
+  InitFiniAtom(const File &f, StringRef secName)
+      : SimpleDefinedAtom(f), _section(secName) {
+  }
+
+  virtual Scope scope() const { return scopeGlobal; }
+
+  virtual SectionChoice sectionChoice() const { return sectionCustomRequired; }
+
+  virtual StringRef customSectionName() const { return _section; }
+
+  virtual ContentType contentType() const { return typeStub; }
+
+  virtual uint64_t size() const { return rawContent().size(); }
+
+  virtual ContentPermissions permissions() const { return permRW_; }
+
+  virtual ArrayRef<uint8_t> rawContent() const = 0;
+
+  virtual Alignment alignment() const { return size(); }
+
+#ifndef NDEBUG
+  virtual StringRef name() const { return _name; }
+
+  std::string _name;
+#else
+  virtual StringRef name() const { return ""; }
+#endif
+};
+
 } // end namespace elf
 } // end namespace lld
 

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp Sat Aug 31 00:27:44 2013
@@ -29,6 +29,7 @@ using namespace llvm::ELF;
 
 // .got values
 const uint8_t x86_64GotAtomContent[8] = { 0 };
+const uint8_t x86_64InitFiniAtomContent[8] = { 0 };
 
 // .plt value (entry 0)
 const uint8_t x86_64Plt0AtomContent[16] = {
@@ -393,8 +394,69 @@ public:
       const_cast<Reference &>(ref).setTarget(getSharedGOT(sla));
   }
 };
+
+// X86_64InitFini Atom
+class X86_64InitAtom : public InitFiniAtom {
+public:
+  X86_64InitAtom(const File &f, StringRef function)
+      : InitFiniAtom(f, ".init_array") {
+#ifndef NDEBUG
+    _name = "__init_fn";
+    _name += function;
+#endif
+  }
+  virtual ArrayRef<uint8_t> rawContent() const {
+    return ArrayRef<uint8_t>(x86_64InitFiniAtomContent, 8);
+  }
+};
+
+class X86_64FiniAtom : public InitFiniAtom {
+public:
+  X86_64FiniAtom(const File &f, StringRef function)
+      : InitFiniAtom(f, ".fini_array") {
+#ifndef NDEBUG
+    _name = "__fini_fn_";
+    _name += function;
+#endif
+  }
+  virtual ArrayRef<uint8_t> rawContent() const {
+    return ArrayRef<uint8_t>(x86_64InitFiniAtomContent, 8);
+  }
+};
+
+class X86_64InitFiniFile : public SimpleFile {
+public:
+  X86_64InitFiniFile(const ELFLinkingContext &context):
+    SimpleFile(context, "command line option -init/-fini")
+  {}
+
+  void addInitFunction(StringRef name) {
+    Atom *initFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name);
+    X86_64InitAtom *initAtom =
+           (new (_allocator) X86_64InitAtom(*this, name));
+    initAtom->addReference(llvm::ELF::R_X86_64_64, 0, initFunctionAtom, 0);
+    initAtom->setOrdinal(_ordinal++);
+    addAtom(*initFunctionAtom);
+    addAtom(*initAtom);
+  }
+
+  void addFiniFunction(StringRef name) {
+    Atom *finiFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name);
+    X86_64FiniAtom *finiAtom =
+           (new (_allocator) X86_64FiniAtom(*this, name));
+    finiAtom->addReference(llvm::ELF::R_X86_64_64, 0, finiFunctionAtom, 0);
+    finiAtom->setOrdinal(_ordinal++);
+    addAtom(*finiFunctionAtom);
+    addAtom(*finiAtom);
+  }
+
+private:
+  llvm::BumpPtrAllocator _allocator;
+};
+
 } // end anon namespace
 
+
 void elf::X86_64LinkingContext::addPasses(PassManager &pm) const {
   switch (_outputFileType) {
   case llvm::ELF::ET_EXEC:
@@ -414,6 +476,20 @@ void elf::X86_64LinkingContext::addPasse
   ELFLinkingContext::addPasses(pm);
 }
 
+std::vector<std::unique_ptr<File>>
+  elf::X86_64LinkingContext::createInternalFiles(){
+  std::vector<std::unique_ptr<File> > result =
+    ELFLinkingContext::createInternalFiles();
+  std::unique_ptr<X86_64InitFiniFile>
+    initFiniFile(new X86_64InitFiniFile(*this));
+  for (auto ai:initFunctions())
+    initFiniFile->addInitFunction(ai);
+  for (auto ai:finiFunctions())
+    initFiniFile->addFiniFunction(ai);
+  result.push_back(std::move(initFiniFile));
+  return result;
+}
+
 #define LLD_CASE(name) .Case(#name, llvm::ELF::name)
 
 ErrorOr<Reference::Kind>
@@ -497,3 +573,4 @@ elf::X86_64LinkingContext::stringFromRel
 
   return make_error_code(yaml_reader_error::illegal_value);
 }
+

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h Sat Aug 31 00:27:44 2013
@@ -75,6 +75,9 @@ public:
     }
   }
 
+  /// \brief Create Internal files for Init/Fini
+  std::vector<std::unique_ptr<File>> createInternalFiles();
+
   virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
   virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
 };

Added: lld/trunk/test/elf/X86_64/Inputs/initfini-option.c
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/Inputs/initfini-option.c?rev=189719&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/Inputs/initfini-option.c (added)
+++ lld/trunk/test/elf/X86_64/Inputs/initfini-option.c Sat Aug 31 00:27:44 2013
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+void init() {
+ printf("%s\n", __FUNCTION__);
+}
+
+void fini() {
+ printf("%s\n", __FUNCTION__);
+}
+
+int main() {
+}
+

Added: lld/trunk/test/elf/X86_64/Inputs/initfini-option.o
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/Inputs/initfini-option.o?rev=189719&view=auto
==============================================================================
Binary files lld/trunk/test/elf/X86_64/Inputs/initfini-option.o (added) and lld/trunk/test/elf/X86_64/Inputs/initfini-option.o Sat Aug 31 00:27:44 2013 differ

Added: lld/trunk/test/elf/X86_64/initfini-option.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/initfini-option.test?rev=189719&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/initfini-option.test (added)
+++ lld/trunk/test/elf/X86_64/initfini-option.test Sat Aug 31 00:27:44 2013
@@ -0,0 +1,21 @@
+# This tests the functionality that lld is able to create
+# init_array/fini_array sections in the output ELF. This
+# corresponds to the the .init_array/.fini_array sections
+# in the output ELF. 
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/initfini-option.o  \
+RUN: -init init -fini fini --noinhibit-exec -emit-yaml -o %t
+RUN: FileCheck %s < %t
+
+CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK:    section-name:    .init_array
+CHECK:    references:      
+CHECK:      - kind:            R_X86_64_64
+CHECK:        offset:          0
+CHECK:        target:          init
+CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK:    section-name:    .fini_array
+CHECK:    references:      
+CHECK:      - kind:            R_X86_64_64
+CHECK:        offset:          0
+CHECK:        target:          fini





More information about the llvm-commits mailing list