[llvm-commits] [lld] support for adding absolute symbols in WriterELF

Shankar Easwaran shankare at codeaurora.org
Wed Jan 9 07:38:04 PST 2013


Hi,

This functionality is to support adding absolute symbols / undefined 
symbols in WriterELF.

Patch attached.

Thanks

Shankar Easwaran

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation

-------------- next part --------------
Index: test/Driver/x86_64-target.test
===================================================================
--- test/Driver/x86_64-target.test	(revision 171973)
+++ test/Driver/x86_64-target.test	(working copy)
@@ -1 +1,2 @@
-RUN: lld -flavor ld -target x86_64-linux
+# Will fail with unersolved symbol 
+RUN: lld -flavor ld -target x86_64-linux || exit 0 
Index: test/elf/Inputs/writersyms.o
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: test/elf/Inputs/writersyms.o
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: test/elf/sections.objtxt
===================================================================
--- test/elf/sections.objtxt	(revision 171973)
+++ test/elf/sections.objtxt	(working copy)
@@ -10,8 +10,8 @@
 OBJDUMP:  4 .anotherspecial 000000004 00000000000001008 DATA
 OBJDUMP:  5 .bss          000000001 0000000000000100c BSS
 OBJDUMP:  6 .shstrtab     000000045 00000000000000000
-OBJDUMP:  7 .symtab       0000000c0 00000000000000000
-OBJDUMP:  8 .strtab       00000003b 00000000000000000
+OBJDUMP:  7 .symtab       000000110 00000000000000000
+OBJDUMP:  8 .strtab       000000061 00000000000000000
 
 READOBJ: File Format : ELF32-i386
 READOBJ: Arch        : i386
Index: test/elf/symbols.objtxt
===================================================================
--- test/elf/symbols.objtxt	(revision 0)
+++ test/elf/symbols.objtxt	(revision 0)
@@ -0,0 +1,27 @@
+# Tests the functionality of archive libraries reading 
+# and resolution 
+# Note: The binary files would not be required once we have support to generate
+# binary archives from textual(yaml) input
+#
+# Tests generated using the source files below
+# main file
+#
+#extern int __bss_start  __attribute__ ((weak));
+#int a;
+#int main() 
+#{ 
+#  return 0;
+#}
+#
+
+RUN: lld-core -reader ELF %p/Inputs/writersyms.o -writer ELF -o %t1 
+RUN: llvm-nm -n %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+CHECKSYMS:  00000000 a 1.c
+CHECKSYMS:  00000094 T main
+CHECKSYMS:  00001000 A __bss_start
+CHECKSYMS:  00001000 B a
+CHECKSYMS:  00001004 A __bss_end
+CHECKSYMS:  00001004 A _end
+CHECKSYMS:  00001004 A end
+CHECKSYMS:           w _start
Index: lib/ReaderWriter/ELF/WriterELF.cpp
===================================================================
--- lib/ReaderWriter/ELF/WriterELF.cpp	(revision 171973)
+++ lib/ReaderWriter/ELF/WriterELF.cpp	(working copy)
@@ -34,7 +34,7 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/system_error.h"
-#include "AtomsELF.h"
+#include "ExecutableAtoms.h"
 
 #include <map>
 #include <unordered_map>
@@ -1101,7 +1101,7 @@
         binding = ELF::STB_GLOBAL;
         break;
       }
-      symbol->st_value = aa->value();
+      symbol->st_value = addr;
     }
     else {
      symbol->st_value = 0;
@@ -1218,7 +1218,29 @@
 class ELFProgramHeader : public Chunk<target_endianness, max_align, is64Bits> {
 public:
   typedef Elf_Phdr_Impl<target_endianness, max_align, is64Bits> Elf_Phdr;
+  typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
 
+  /// \brief Find a program header entry, given the type of entry that
+  /// we are looking for
+  class FindPhdr {
+  public:
+    FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear) 
+             : _type(type)
+             , _flags(flags)
+             , _flagsClear(flagsClear)
+    {}
+
+    bool operator()(const Elf_Phdr* j) const { 
+      return ((j->p_type == _type) &&
+              ((j->p_flags & _flags) == _flags) &&
+              (!(j->p_flags & _flagsClear)));
+    }
+  private:
+    uint64_t _type;
+    uint64_t _flags;
+    uint64_t _flagsClear;
+  };
+
   ELFProgramHeader()
   : Chunk<target_endianness, max_align, is64Bits>(
       "elfphdr",
@@ -1283,6 +1305,20 @@
     }
   }
 
+  /// \brief find a program header entry in the list of program headers
+  PhIterT findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
+    return std::find_if(_ph.begin(), _ph.end(), 
+                        FindPhdr(type, flags, flagClear));
+  }
+
+  PhIterT begin() {
+    return _ph.begin();
+  }
+
+  PhIterT end() {
+    return _ph.end();
+  }
+
   void finalize() { }
 
   int64_t entsize() {
@@ -1295,8 +1331,7 @@
 
 private:
   std::vector<Elf_Phdr *> _ph;
-  typedef typename std::vector<Elf_Phdr *>::iterator ph_iter;
-  ph_iter _phi;
+  PhIterT _phi;
   llvm::BumpPtrAllocator  _allocator;
 };
 
@@ -1482,6 +1517,35 @@
                              Segment<target_endianness, max_align, is64Bits>*,
                              SegmentHashKey> SegmentMapT;
 
+  /// \brief All absolute atoms are created in the ELF Layout by using 
+  /// an AbsoluteAtomPair. Contains a pair of AbsoluteAtom and the 
+  /// value which is the address of the absolute atom
+  class AbsoluteAtomPair {
+  public:
+    AbsoluteAtomPair(const AbsoluteAtom *a, int64_t value) 
+                     : _absoluteAtom(a)
+                     , _value(value) { }
+
+    const AbsoluteAtom *absoluteAtom() { return _absoluteAtom; }
+    int64_t value() const { return _value; }
+    void setValue(int64_t val) { _value = val; }
+
+  private:
+    const AbsoluteAtom *_absoluteAtom;
+    int64_t _value;
+  };
+
+  /// \brief find a absolute atom pair given a absolute atom name
+  struct FindByName {
+    const std::string name;
+    FindByName(const StringRef name) : name(name) {}
+    bool operator()(AbsoluteAtomPair& j) { 
+      return j.absoluteAtom()->name() == name; 
+    }
+  };
+
+  typedef typename std::vector<AbsoluteAtomPair>::iterator AbsoluteAtomIterT;
+
   DefaultELFLayout(const WriterOptionsELF &options):_options(options) { }
 
   /// \brief Return the section order for a input section
@@ -1602,42 +1666,69 @@
 
   // Adds an atom to the section
   virtual error_code addAtom(const Atom *atom) {
-    const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
-    const StringRef sectionName =
-                getSectionName(definedAtom->customSectionName(),
-                               definedAtom->contentType());
-    const lld::DefinedAtom::ContentPermissions permissions =
-                                  definedAtom->permissions();
-    const lld::DefinedAtom::ContentType contentType =
-                                  definedAtom->contentType();
-    const Key key(sectionName, std::make_pair(contentType, permissions));
-    const std::pair<Key, Section<target_endianness, max_align, is64Bits> *>
-                                                currentSection(key, nullptr);
-    std::pair<typename SectionMapT::iterator, bool>
-                              sectionInsert(_sectionMap.insert(currentSection));
-    Section<target_endianness, max_align, is64Bits> *section;
-    // the section is already in the map
-    if (!sectionInsert.second) {
-      section = sectionInsert.first->second;
-      section->setContentPermissions(permissions);
+    const Atom::Definition atomType = atom->definition();
+    if (atomType == Atom::definitionRegular) {
+      const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
+      const StringRef sectionName =
+                  getSectionName(definedAtom->customSectionName(),
+                                 definedAtom->contentType());
+      const lld::DefinedAtom::ContentPermissions permissions =
+                                    definedAtom->permissions();
+      const lld::DefinedAtom::ContentType contentType =
+                                    definedAtom->contentType();
+      const Key key(sectionName, std::make_pair(contentType, permissions));
+      const std::pair<Key, Section<target_endianness, max_align, is64Bits> *>
+                                                  currentSection(key, nullptr);
+      std::pair<typename SectionMapT::iterator, bool>
+                                sectionInsert(_sectionMap.insert(currentSection));
+      Section<target_endianness, max_align, is64Bits> *section;
+      // the section is already in the map
+      if (!sectionInsert.second) {
+        section = sectionInsert.first->second;
+        section->setContentPermissions(permissions);
+      }
+      else {
+        SectionOrder section_order = getSectionOrder(sectionName,
+                                       contentType,
+                                       permissions);
+        section = new (_allocator.Allocate
+                       <Section<target_endianness, max_align, is64Bits>>())
+                       Section<target_endianness, max_align, is64Bits>
+                       (sectionName, contentType,
+                        permissions, section_order);
+        sectionInsert.first->second = section;
+        section->setOrder(section_order);
+        _sections.push_back(section);
+      }
+      section->appendAtom(atom);
     }
-    else {
-      SectionOrder section_order = getSectionOrder(sectionName,
-                                     contentType,
-                                     permissions);
-      section = new (_allocator.Allocate
-                     <Section<target_endianness, max_align, is64Bits>>())
-                     Section<target_endianness, max_align, is64Bits>
-                     (sectionName, contentType,
-                      permissions, section_order);
-      sectionInsert.first->second = section;
-      section->setOrder(section_order);
-      _sections.push_back(section);
+    // Absolute atoms are not part of any section, they are global for the whole
+    // link
+    else if (atomType == Atom::definitionAbsolute) {
+      const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom);
+      _absoluteAtoms.push_back(AbsoluteAtomPair(absoluteAtom, 
+                                                absoluteAtom->value()));
     }
-    section->appendAtom(atom);
+    else 
+      llvm_unreachable("Only absolute / defined atoms can be added here");
     return error_code::success();
   }
 
+  /// \brief find a absolute atom given a name
+  AbsoluteAtomIterT findAbsoluteAtom(const StringRef name) {
+    return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
+                                                FindByName(name));
+  }
+
+  /// \bried Begin/End iterators
+  AbsoluteAtomIterT absAtomsBegin() { 
+    return _absoluteAtoms.begin();
+  }
+
+  AbsoluteAtomIterT absAtomsEnd() { 
+    return _absoluteAtoms.end();
+  }
+
   // Merge sections with the same name into a MergedSections
   void mergeSimiliarSections() {
     MergedSections<target_endianness, max_align, is64Bits> *mergedSection;
@@ -1922,13 +2013,13 @@
   SectionMapT _sectionMap;
   MergedSectionMapT _mergedSectionMap;
   SegmentMapT _segmentMap;
-
   std::vector<Chunk<target_endianness, max_align, is64Bits> *> _sections;
   std::vector<Segment<target_endianness, max_align, is64Bits> *> _segments;
   std::vector<MergedSections<target_endianness, max_align, is64Bits> *>
     _mergedSections;
   ELFHeader<target_endianness, max_align, is64Bits> *_elfHeader;
   ELFProgramHeader<target_endianness, max_align, is64Bits> *_programHeader;
+  std::vector<AbsoluteAtomPair> _absoluteAtoms;
   llvm::BumpPtrAllocator _allocator;
   const WriterOptionsELF &_options;
 };
@@ -1955,6 +2046,9 @@
   void buildSectionHeaderTable();
   void assignSectionsWithNoSegments();
   void addAbsoluteUndefinedSymbols(const lld::File &File);
+  void addDefaultAtoms();
+  void addFiles(InputFiles&);
+  void finalizeDefaultAtomValues();
 
   uint64_t addressOfAtom(const Atom *atom) {
     return _atomToAddressMap[atom];
@@ -1977,6 +2071,7 @@
   ELFStringTable<target_endianness, max_align, is64Bits> *_strtab;
   ELFStringTable<target_endianness, max_align, is64Bits> *_shstrtab;
   ELFSectionHeader<target_endianness, max_align, is64Bits> *_shdrtab;
+  CRuntimeFile<target_endianness, max_align, is64Bits> _runtimeFile;
 };
 
 //===----------------------------------------------------------------------===//
@@ -1989,7 +2084,8 @@
                    ::ELFExecutableWriter(const WriterOptionsELF &options)
   : _options(options)
   , _referenceKindHandler(KindHandler::makeHandler(_options.machine(),
-                                                   target_endianness)) {
+                                                   target_endianness))
+  , _runtimeFile(options) {
   _layout =
     new DefaultELFLayout<target_endianness, max_align, is64Bits>(options);
 }
@@ -2002,6 +2098,10 @@
   for (const DefinedAtom *definedAtom : file.defined() ) {
     _layout->addAtom(definedAtom);
   }
+  /// Add all the absolute atoms to the layout
+  for (const AbsoluteAtom *absoluteAtom : file.absolute()) {
+    _layout->addAtom(absoluteAtom);
+  }
 }
 
 template<support::endianness target_endianness,
@@ -2028,13 +2128,15 @@
          bool is64Bits>
 void ELFExecutableWriter<target_endianness, max_align, is64Bits>
                         ::addAbsoluteUndefinedSymbols(const lld::File &file) {
+  /// add all the absolute symbols that the layout contains to the output symbol
+  /// table
+  for (auto absi = _layout->absAtomsBegin(), abse = _layout->absAtomsEnd();
+       absi != abse; ++absi) {
+    _symtab->addSymbol(absi->absoluteAtom(), ELF::SHN_ABS, absi->value());
+  }
  for (const UndefinedAtom *a : file.undefined()) {
    _symtab->addSymbol(a, ELF::SHN_UNDEF);
  }
-
- for (const AbsoluteAtom *a : file.absolute()) {
-   _symtab->addSymbol(a, ELF::SHN_ABS);
- }
 }
 
 template<support::endianness target_endianness,
@@ -2054,6 +2156,11 @@
       _atomToAddressMap[ai->first] = (ai)->second.second;
     }
   }
+  /// build the atomToAddressMap that contains absolute symbols too
+  for (auto absi = _layout->absAtomsBegin(), abse = _layout->absAtomsEnd();
+       absi != abse; ++absi) {
+    _atomToAddressMap[absi->absoluteAtom()] = absi->value();
+  }
 }
 
 template<support::endianness target_endianness,
@@ -2099,9 +2206,66 @@
   }
 }
 
+/// \brief Add absolute symbols by default. These are linker added
+/// absolute symbols
 template<support::endianness target_endianness,
          std::size_t max_align,
          bool is64Bits>
+void ELFExecutableWriter<target_endianness, max_align, is64Bits>
+                        ::addDefaultAtoms() {
+  _runtimeFile.addUndefinedAtom("_start");
+  _runtimeFile.addAbsoluteAtom("__bss_start");
+  _runtimeFile.addAbsoluteAtom("__bss_end");
+  _runtimeFile.addAbsoluteAtom("_end");
+  _runtimeFile.addAbsoluteAtom("end");
+}
+
+/// \brief Hook in lld to add CRuntime file 
+template<support::endianness target_endianness,
+         std::size_t max_align,
+         bool is64Bits>
+void ELFExecutableWriter<target_endianness, max_align, is64Bits>
+                        ::addFiles(InputFiles &inputFiles) {
+  addDefaultAtoms();
+  inputFiles.prependFile(_runtimeFile);
+}
+
+/// Finalize the value of all the absolute symbols that we 
+/// created
+template<support::endianness target_endianness,
+         std::size_t max_align,
+         bool is64Bits>
+void ELFExecutableWriter<target_endianness, max_align, is64Bits>
+                        ::finalizeDefaultAtomValues() {
+ auto abse = _layout->absAtomsEnd();
+ auto bssStartAtomIter = _layout->findAbsoluteAtom("__bss_start");
+ auto bssEndAtomIter = _layout->findAbsoluteAtom("__bss_end");
+ auto underScoreEndAtomIter = _layout->findAbsoluteAtom("_end");
+ auto endAtomIter = _layout->findAbsoluteAtom("end");
+
+ if (bssStartAtomIter == abse ||
+     bssEndAtomIter == abse ||
+     underScoreEndAtomIter == abse ||
+     endAtomIter == abse) 
+   assert(0 && "something has gone wrong with the ELFLayout");
+
+ auto phe = _programHeader->findProgramHeader(
+                                 llvm::ELF::PT_LOAD,
+                                 llvm::ELF::PF_W,
+                                 llvm::ELF::PF_X);
+
+ if (phe == _programHeader->end()) 
+   assert(0 && "something has gone wrong with the Program Header");
+
+ bssStartAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_filesz);
+ bssEndAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
+ underScoreEndAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
+ endAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
+}
+
+template<support::endianness target_endianness,
+         std::size_t max_align,
+         bool is64Bits>
 error_code ELFExecutableWriter<target_endianness, max_align, is64Bits>
                             ::writeFile(const lld::File &file, StringRef path) {
   buildChunks(file);
@@ -2114,6 +2278,9 @@
   _layout->assignFileOffsets();
   _layout->assignVirtualAddress();
 
+  // Finalize the default value of symbols that the linker adds
+  finalizeDefaultAtomValues();
+
   // Build the Atom To Address map for applying relocations
   buildAtomToAddressMap();
 
Index: lib/ReaderWriter/ELF/ExecutableAtoms.h
===================================================================
--- lib/ReaderWriter/ELF/ExecutableAtoms.h	(revision 0)
+++ lib/ReaderWriter/ELF/ExecutableAtoms.h	(revision 0)
@@ -0,0 +1,103 @@
+//===- lib/ReaderWriter/ELF/ExecutableAtoms.h ----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_EXECUTABLE_ATOM_H_
+#define LLD_READER_WRITER_ELF_EXECUTABLE_ATOM_H_
+
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/ReaderWriter/WriterELF.h"
+#include "AtomsELF.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief All atoms are owned by a File. To add linker specific atoms
+/// the atoms need to be inserted to a file called (CRuntimeFile) which 
+/// are basically additional symbols required by libc and other runtime 
+/// libraries part of executing a program. This class provides support
+/// for adding absolute symbols and undefined symbols
+template<llvm::support::endianness target_endianness,
+         std::size_t max_align,
+         bool is64Bits>
+class CRuntimeFile : public File {
+public:
+  typedef llvm::object::Elf_Sym_Impl<target_endianness, max_align, is64Bits> Elf_Sym;
+  CRuntimeFile(const WriterOptionsELF &options) 
+    : File("C runtime") 
+  { }
+  
+  /// \brief add a global absolute atom
+  void addAbsoluteAtom(const StringRef symbolName) {
+    Elf_Sym *symbol = new(_allocator.Allocate<Elf_Sym>()) Elf_Sym;
+    symbol->st_name = 0;
+    symbol->st_value = 0;
+    symbol->st_shndx = llvm::ELF::SHN_ABS;
+    symbol->setBindingAndType(llvm::ELF::STB_GLOBAL, 
+                              llvm::ELF::STT_OBJECT);
+    symbol->st_other = llvm::ELF::STV_DEFAULT;
+    symbol->st_size = 0;
+    auto *newAtom = new (_allocator.Allocate<
+      ELFAbsoluteAtom<target_endianness, max_align, is64Bits> > ())
+      ELFAbsoluteAtom<target_endianness, max_align, is64Bits>(
+        *this, symbolName, symbol, -1);
+    _absoluteAtoms._atoms.push_back(newAtom);
+  }
+
+  /// \brief add an undefined atom 
+  void addUndefinedAtom(const StringRef symbolName) {
+    Elf_Sym *symbol = new(_allocator.Allocate<Elf_Sym>()) Elf_Sym;
+    symbol->st_name = 0;
+    symbol->st_value = 0;
+    symbol->st_shndx = llvm::ELF::SHN_UNDEF;
+    symbol->st_other = llvm::ELF::STV_DEFAULT;
+    symbol->st_size = 0;
+    auto *newAtom = new (_allocator.Allocate<
+      ELFUndefinedAtom<target_endianness, max_align, is64Bits> > ())
+      ELFUndefinedAtom<target_endianness, max_align, is64Bits>(
+        *this, symbolName, symbol);
+    _undefinedAtoms._atoms.push_back(newAtom);
+  }
+
+  const atom_collection<DefinedAtom> &defined() const {
+    return _definedAtoms;
+  }
+
+  const atom_collection<UndefinedAtom> &undefined() const {
+    return _undefinedAtoms;
+  }
+
+  const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
+    return _sharedLibraryAtoms;
+  }
+
+  const atom_collection<AbsoluteAtom> &absolute() const {
+    return _absoluteAtoms;
+  }
+
+  // cannot add atoms to C Runtime file
+  virtual void addAtom(const Atom&) {
+    llvm_unreachable("cannot add atoms to C Runtime files");
+  }
+
+private:
+  llvm::BumpPtrAllocator _allocator;
+  atom_collection_vector<DefinedAtom>       _definedAtoms;
+  atom_collection_vector<UndefinedAtom>     _undefinedAtoms;
+  atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+  atom_collection_vector<AbsoluteAtom>      _absoluteAtoms;
+};
+
+} // namespace elf
+} // namespace lld 
+
+#endif // LLD_READER_WRITER_ELF_EXECUTABLE_ATOM_H_
Index: lib/Driver/LinkerInvocation.cpp
===================================================================
--- lib/Driver/LinkerInvocation.cpp	(revision 171973)
+++ lib/Driver/LinkerInvocation.cpp	(working copy)
@@ -72,11 +72,16 @@
       _undefinesAreErrors = true;
     }
   } ro;
+
+  auto writer = target->getWriter();
+
+  // Give writer a chance to add files
+  writer->addFiles(inputs);
+
   Resolver resolver(ro, inputs);
   resolver.resolve();
   File &merged = resolver.resultFile();
 
-  auto writer = target->getWriter();
   if (error_code ec = writer) {
     llvm::errs() << "Failed to get writer: " << ec.message() << ".\n";
     return;


More information about the llvm-commits mailing list