[llvm-commits] [PATCH] [lld] patch for ELF Writer to get it to 'Hello world'

Shankar Easwaran shankare at codeaurora.org
Wed Dec 26 15:40:20 PST 2012


Attached is the diff with the changes to the header sort order and the 
lambda function.

Thanks

Shankar Easwaran

On 12/21/2012 11:28 PM, Shankar Easwaran wrote:
> Attached is the diff with the changes.
>
> Thanks
>
> Shankar Easwaran
>
> On 12/21/2012 11:11 PM, Shankar Easwaran wrote:
>> Done the changes as specified by your review comments.
>>
>> OK to commit ?
>>
>> Thanks
>>
>> Shankar Easwaran
>>
>> On 12/21/2012 9:54 PM, Michael Spencer wrote:
>>> On Fri, Dec 21, 2012 at 2:23 PM, Shankar Easwaran
>>> <shankare at codeaurora.org> wrote:
>>>> Hi Michael,
>>>>
>>>> Attached is the new diff after the review with the test case changes.
>>>>
>>>> You would need to apply the other changes that were in the previous 
>>>> patches
>>>> to build.
>>>>
>>>> a) ELFAtoms.h
>>>> b) ReaderELF changes
>>>> c) HexagonRelocation changes
>>>>
>>>> OK to commit ?
>>>>
>>>> Thanks
>>>>
>>>> Shankar Easwaran
>>>>
>>>>
>>>> On 12/21/2012 11:11 AM, Michael Spencer wrote:
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:80-86
>>>>> @@ +79,9 @@
>>>>> +  /// \brief Describes the type of Chunk
>>>>> +  enum Kind {
>>>>> +    ELFHeader, // ELF Header
>>>>> +    ProgramHeader, // Program Header
>>>>> +    Segment, // Segment
>>>>> +    Section, // Section
>>>>> +    SectionHeader // Section header
>>>>> +  };
>>>>> +  Chunk(StringRef name, Kind kind) : _name(name),
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> This either needs to be an enum class, or the members need to 
>>>>>>> follow the
>>>>>>> naming convention. Currently this breaks MSVC because it doesn't 
>>>>>>> do two
>>>>>>> phase name lookup and therefore sees Section and Segment in the 
>>>>>>> derived
>>>>>>> class (Chunk) instead of the templates Section and Segment.
>>>>>> Changed the names to add ELF in the front
>>>>>
>>>>> http://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly 
>>>>>
>>>>>
>>>>> They should start with K_
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:121-123
>>>>> @@ +120,5 @@
>>>>> +  int64_t            fileOffset() const { return _fileoffset; }
>>>>> +  void               setFileOffset(int64_t offset) { _fileoffset =
>>>>> offset; }
>>>>> +  // Output start address of the chunk
>>>>> +  void               setStart(int64_t start) { _start = start; }
>>>>> +  int64_t            startAddr() const { return _start; }
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> What is the difference between these two function? Is one the 
>>>>>>> virtual
>>>>>>> address?
>>>>>> yes.
>>>>> Then the names could be improved and a \brief added.
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:549
>>>>> @@ -235,1 +548,3 @@
>>>>> +  void setOrdinal(int64_t ordinal) {
>>>>> +    ordinal = ordinal;
>>>>>      }
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>>     _ordinal = ordinal;
>>>>>> Nice catch.
>>>>> Clang -Wall caught it for me :P
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:1008
>>>>> @@ +1007,3 @@
>>>>> +  static inline bool classof(const Chunk<target_endianness, 
>>>>> is64Bits> *c)
>>>>> {
>>>>> +    return c->kind() == Section<target_endianness,
>>>>> is64Bits>::StringTable;
>>>>> +  }
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> This is broken. Chunk already has a Kind with the same value.
>>>>>> Chunk doesnot have such a type called StringTable.
>>>>> Not named StringTable. But StringTable shares the same underlying 
>>>>> value as
>>>>> Chunk::Segment
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:1491-1502
>>>>> @@ -826,1 +1490,14 @@
>>>>> +      case DefinedAtom::typeCode:
>>>>> +          if (name.startswith(".eh_frame_hdr"))
>>>>> +            return ORDER_EH_FRAMEHDR;
>>>>> +          if (name.startswith(".eh_frame"))
>>>>> +            return ORDER_EH_FRAME;
>>>>> +          else if (name.startswith(".init"))
>>>>> +            return ORDER_INIT;
>>>>> +          else if (name.startswith(".fini"))
>>>>> +            return ORDER_FINI;
>>>>> +          else if (name.startswith(".hash"))
>>>>> +            return ORDER_HASH;
>>>>> +          else
>>>>> +            return ORDER_TEXT;
>>>>>    ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> llvm::StringSwitch in llvm/ADT/StringSwitch.h
>>>>>> How do you do startswith with StringSwitch ?
>>>>> .StartsWith("") instead of .Case("").
>>>>>
>>>>>
>>>>> https://github.com/Bigcheese/llvm/blob/master/lib/Object/COFFObjectFile.cpp#L214 
>>>>>
>>>>>
>>>>>
>>>>> http://llvm-reviews.chandlerc.com/D222
>>>>> _______________________________________________
>>>>> llvm-commits mailing list
>>>>> llvm-commits at cs.uiuc.edu
>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>>>>
>>>>>
>>>>
>>>> -- 
>>>> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, 
>>>> hosted by
>>>> the Linux Foundation
>>>>
>>>> Index: WriterELF.cpp
>>>> ===================================================================
>>>> --- WriterELF.cpp (revision 170923)
>>>> +++ WriterELF.cpp (working copy)
>>>> @@ -11,20 +11,20 @@
>>>>   #include "ReferenceKinds.h"
>>>>
>>>>   #include "lld/Core/DefinedAtom.h"
>>>> +#include "llvm/Object/ELF.h"
>>> This needs to be sorted. It should come right before the Support 
>>> headers.
>>>
>>>>   #include "lld/Core/File.h"
>>>>   #include "lld/Core/InputFiles.h"
>>>>   #include "lld/Core/Reference.h"
>>>>   #include "lld/Core/SharedLibraryAtom.h"
>>>> -
>>>>   #include "llvm/ADT/ArrayRef.h"
>>>>   #include "llvm/ADT/DenseMap.h"
>>>> +#include "llvm/ADT/Hashing.h"
>>>>   #include "llvm/ADT/OwningPtr.h"
>>>>   #include "llvm/ADT/SmallVector.h"
>>>> +#include "llvm/ADT/StringExtras.h"
>>>>   #include "llvm/ADT/StringMap.h"
>>>>   #include "llvm/ADT/StringRef.h"
>>>> -
>>>> -#include "llvm/Object/ELF.h"
>>>> -
>>>> +#include "llvm/ADT/StringSwitch.h"
>>>>   #include "llvm/Support/Allocator.h"
>>>>   #include "llvm/Support/Debug.h"
>>>>   #include "llvm/Support/ELF.h"
>>>> @@ -34,1382 +34,2020 @@
>>>>   #include "llvm/Support/MathExtras.h"
>>>>   #include "llvm/Support/raw_ostream.h"
>>>>   #include "llvm/Support/system_error.h"
>>>> +#include "ELFAtoms.h"
>>>>
>>>>   #include <map>
>>>> +#include <unordered_map>
>>>>   #include <tuple>
>>>>   #include <vector>
>>>> -#include <algorithm>
>>>>
>>>>   using namespace llvm;
>>>>   using namespace llvm::object;
>>>>   namespace lld {
>>>>   namespace elf {
>>>>
>>>> -// The group decides where sections of similar permissions reside
>>>> -// inside a file. This is also used to create program headers. 
>>>> Each group
>>>> -// will be in a new segment.
>>>> +template<support::endianness target_endianness, bool is64Bits>
>>>> +class ELFExecutableWriter;
>>>>
>>>> -/// \name Chunk Groups
>>>> -/// Each "Chunk" should be arranged in a weak strict order
>>>> -/// This is done to minimize memory utilization when creating 
>>>> program segments.
>>>> -/// This will remain in place till a more felxible mechanism of 
>>>> moving chunks
>>>> -/// around and packing for memory efficiency is put in place.
>>>> -/// The Chunks are arranged by group numbers. Every switch from 
>>>> group A to B
>>>> -/// triggers a formation of new segment. Additionally segments are 
>>>> also made
>>>> -/// within a group if there are vast regions (multiple pages) of 0 
>>>> for
>>>> -/// alignment constraints.
>>>> -enum {
>>>> -/// @{
>>>> -///Invalid group (default on creation)
>>>> -  CG_INVALID = 0x0,
>>>> -///This is a "header" kind of chunk that goes at beginning of ELF 
>>>> file
>>>> -  CG_HEADER = 0x1,
>>>> -///This is a section chunk with read write and execute permissions
>>>> -  CG_RWX = 0x3,
>>>> -///This is a section chunk with read and execute permissions
>>>> -  CG_RX = 0x4,
>>>> -///This is a section chunk with read permission
>>>> -  CG_R = 0x5,
>>>> -///This is a section chunk with read and write permissions
>>>> -  CG_RW = 0x6,
>>>> -///This is a section chunk with write and execute permissions
>>>> -  CG_WX = 0x7,
>>>> -///This is a section chunk with write permission
>>>> -  CG_W = 0x8,
>>>> -///This is a section chunk with execute permission
>>>> -  CG_X = 0x9,
>>>> -///This is a section which is no loaded by program loader
>>>> -  CG_NO_LOAD = 0xFE,
>>>> -///This is ELF file metadata that goes at end of file
>>>> -  CG_FILE_END = 0xFF
>>>> -/// @}
>>>> -};
>>>> +/// \brief The ELFWriter class is a base class for the linker to 
>>>> write
>>>> +///        various kinds of ELF files.
>>>> +class ELFWriter : public Writer {
>>>> +  public:
>>> This shouldn't be indented.
>>>
>>>> +    ELFWriter() { }
>>>>
>>>> -template<support::endianness target_endianness, bool is64Bits>
>>>> -class ELFWriter;
>>>> +  public:
>>>> +    /// \brief builds the chunks that needs to be written to the 
>>>> output
>>>> +    ///        ELF file
>>>> +    virtual void buildChunks(const lld::File &file) = 0;
>>>>
>>>> -template<support::endianness target_endianness, bool is64Bits>
>>>> -class StockSectionChunk;
>>>> +    /// \brief Writes the chunks into the output file specified by 
>>>> path
>>>> +    virtual error_code writeFile(const lld::File &File, StringRef 
>>>> path) = 0;
>>>>
>>>> -/// \brief A Chunk is a contiguous range of space.
>>>> +    /// \brief Writes the chunks into the output file specified by 
>>>> path
>>>> +    virtual int64_t addressOfAtom(const Atom *atom) = 0;
>>>> +
>>>> +    /// \brief Return the processing function to apply Relocations
>>>> +    virtual KindHandler *kindHandler()  = 0;
>>>> +};
>>>> +
>>>> +/// \brief A chunk is a contiguous region of space
>>>>   template<support::endianness target_endianness, bool is64Bits>
>>>>   class Chunk {
>>>>   public:
>>>> -  LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
>>>> +
>>>> +  /// \brief Describes the type of Chunk
>>>> +  enum Kind {
>>>> +    K_ELFHeader, // ELF Header
>>>> +    K_ELFProgramHeader, // Program Header
>>>> +    K_ELFSegment, // Segment
>>>> +    K_ELFSection, // Section
>>>> +    K_ELFSectionHeader // Section header
>>>> +  };
>>>> +  Chunk(StringRef name, Kind kind)
>>>> +    : _name(name)
>>>> +    , _kind(kind)
>>>> +    , _fsize(0)
>>>> +    , _msize(0)
>>>> +    , _align2(0)
>>>> +    , _order(0)
>>>> +    , _ordinal(1)
>>>> +    , _start(0)
>>>> +    , _fileoffset(0) {}
>>>>     virtual             ~Chunk() {}
>>>> -  virtual StringRef   segmentName() const = 0;
>>>> -  virtual bool        occupiesNoDiskSpace();
>>>> -  virtual void        write(uint8_t *fileBuffer) = 0;
>>>> -  void                assignFileOffset(uint64_t &curOff, uint64_t 
>>>> &curAddr);
>>>> -  virtual const char *info() = 0;
>>>> -  uint64_t            size() const;
>>>> -  uint64_t            address() const;
>>>> -  uint64_t            fileOffset() const;
>>>> -  uint64_t            align2() const;
>>>> -  static uint64_t     alignTo(uint64_t value, uint8_t align2);
>>>> -  uint64_t            ordinal() const { return _ordinal;}
>>>> -  void                setOrdinal(uint64_t newVal) { _ordinal = 
>>>> newVal;}
>>>> -  void                setGroup(uint16_t val) { _group = val;}
>>>> -  uint16_t            group() const { return _group;}
>>>> -  void                init();
>>>> -  bool                isLoadable() { return _isLoadable; }
>>>> -  void                isLoadable(uint64_t val) { _isLoadable = val; }
>>>> -  enum class Kind {
>>>> -    Header,      // This is a header chunk
>>>> -    Section      // chunk represents a section
>>>> -  };
>>>> -  Kind getChunkKind() const { return _cKind; }
>>>> -private:
>>>> -  const Kind _cKind;
>>>> +  // Does the chunk occupy disk space
>>>> +  virtual bool        occupiesNoDiskSpace() const {
>>>> +    return false;
>>>> +  }
>>>> +  // The name of the chunk
>>>> +  StringRef name() const { return _name; }
>>>> +  // Kind of chunk
>>>> +  Kind kind() const { return _kind; }
>>>> +  int64_t            fileSize() const { return _fsize; }
>>>> +  int64_t            align2() const { return _align2; }
>>>> +  void                appendAtom() const;
>>>> +
>>>> +  // The ordinal value of the chunk
>>>> +  int64_t            ordinal() const { return _ordinal;}
>>>> +  void               setOrdinal(int64_t newVal) { _ordinal = newVal;}
>>>> +  // The order in which the chunk would appear in the output file
>>>> +  int64_t            order() const { return _order; }
>>>> +  void               setOrder(int32_t order) { _order = order; }
>>>> +  // Output file offset of the chunk
>>>> +  int64_t            fileOffset() const { return _fileoffset; }
>>>> +  void               setFileOffset(int64_t offset) { _fileoffset = 
>>>> offset; }
>>>> +  // Output start address of the chunk
>>>> +  void               setVAddr(int64_t start) { _start = start; }
>>>> +  int64_t            virtualAddr() const { return _start; }
>>>> +  // Does the chunk occupy memory during execution ?
>>>> +  int64_t            memSize() const { return _msize; }
>>>> +  void               setMemSize(int64_t msize) { _msize = msize; }
>>>> +  // Writer the chunk
>>>> +  virtual void       write(ELFWriter *writer,
>>>> + OwningPtr<FileOutputBuffer> &buffer) = 0;
>>>> +  // Finalize the chunk before writing
>>>> +  virtual void       finalize() = 0;
>>>> +
>>>>   protected:
>>>> -  Chunk();
>>>> -  Chunk(Kind K): _cKind(K) { this->init();}
>>>> -  uint64_t _size;
>>>> -  uint64_t _address;
>>>> -  uint64_t _fileOffset;
>>>> -  uint64_t _align2;
>>>> -  uint64_t _ordinal;
>>>> -  uint16_t _group;
>>>> -  bool     _isLoadable;
>>>> +  StringRef _name;
>>>> +  Kind _kind;
>>>> +  int64_t _fsize;
>>>> +  int64_t _msize;
>>>> +  int64_t _align2;
>>>> +  int32_t  _order;
>>>> +  int64_t _ordinal;
>>>> +  int64_t _start;
>>>> +  int64_t _fileoffset;
>>> These should all be unsigned.
>>>
>>>>   };
>>>>
>>>> -template<support::endianness target_endianness, bool is64Bits>
>>>> -static void swapChunkPositions(Chunk<target_endianness, is64Bits>&a,
>>>> -                               Chunk<target_endianness, 
>>>> is64Bits>&b) {
>>>> -  uint64_t tempOrdinal;
>>>> -  if (a.ordinal() == b.ordinal()) return;
>>>> -  tempOrdinal = a.ordinal();
>>>> -  a.setOrdinal(b.ordinal());
>>>> -  b.setOrdinal(tempOrdinal);
>>>> -}
>>>> +/// \brief The ELFLayoutOptions encapsulates the options used by 
>>>> all Layouts
>>>> +///        Examples of the ELFLayoutOptions would be a script that 
>>>> would be used
>>>> +///        to drive the layout
>>>> +class ELFLayoutOptions {
>>>> +public:
>>>> +  ELFLayoutOptions() { }
>>>>
>>>> -template<support::endianness target_endianness, bool is64Bits>
>>>> -bool chunkGroupSort(Chunk<target_endianness, is64Bits> *A,
>>>> -                    Chunk<target_endianness, is64Bits> *B) {
>>>> -  if (A->group() == CG_INVALID || B->group() == CG_INVALID)
>>>> -    llvm_unreachable("Invalid group number");
>>>> -  return A->group() < B->group();
>>>> -}
>>>> +  ELFLayoutOptions(StringRef &linker_script) : _script(linker_script)
>>>> +  {}
>>>>
>>>> +  /// parse the linker script
>>>> +  error_code parseLinkerScript();
>>>> +
>>>> +  /// Is the current section present in the linker script
>>>> +  bool isSectionPresent();
>>>> +
>>>> +private:
>>>> +  StringRef _script;
>>>> +};
>>>> +
>>>> +/// \brief The ELFLayout is an abstract class for managing the 
>>>> final layout for
>>>> +///        the kind of binaries(Shared Libraries / Relocatables / 
>>>> Executables 0
>>>> +///        Each architecture (Hexagon, PowerPC, MIPS) would have a 
>>>> concrete
>>>> +///        subclass derived from ELFLayout for generating each 
>>>> binary thats
>>>> +//         needed by the lld linker
>>>> +class ELFLayout {
>>>> +public:
>>>> +  typedef int32_t SectionOrder;
>>>> +  typedef int32_t SegmentType;
>>>> +  typedef int32_t Flags;
>>> Unsigned.
>>>
>>>> +
>>>> +public:
>>>> +  /// Return the order the section would appear in the output file
>>>> +  virtual SectionOrder getSectionOrder
>>>> +                        (const StringRef name,
>>>> +                         int32_t contentType,
>>>> +                         int32_t contentPerm) = 0;
>>>> +  /// append the Atom to the layout and create appropriate sections
>>>> +  virtual error_code addAtom(const Atom *atom) = 0;
>>>> +  /// find the Atom Address in the current layout
>>>> +  virtual bool findAtomAddrByName(const StringRef name, int64_t 
>>>> &addr) = 0;
>>>> +  /// associates a section to a segment
>>>> +  virtual void assignSectionsToSegments() = 0;
>>>> +  /// associates a virtual address to the segment, section, and 
>>>> the atom
>>>> +  virtual void assignVirtualAddress() = 0;
>>>> +  /// associates a file offset to the segment, section and the atom
>>>> +  virtual void assignFileOffsets() = 0;
>>>> +
>>>> +public:
>>>> +  ELFLayout() {}
>>>> +  ELFLayout(WriterOptionsELF &writerOptions,
>>>> +            ELFLayoutOptions &layoutOptions)
>>>> +    : _writerOptions(writerOptions)
>>>> +    , _layoutOptions(layoutOptions) {}
>>>> +  virtual ~ELFLayout() { }
>>>> +
>>>> +private:
>>>> +  WriterOptionsELF _writerOptions;
>>>> +  ELFLayoutOptions _layoutOptions;
>>>> +};
>>>> +
>>>> +
>>>> +/// \brief A section contains a set of atoms that have similiar 
>>>> properties
>>>> +///        The atoms that have similiar properties are merged to 
>>>> form a section
>>>>   template<support::endianness target_endianness, bool is64Bits>
>>>> -struct ChunkComparator {
>>>> -  bool operator()(uint16_t A, Chunk<target_endianness, is64Bits> 
>>>> *B) {
>>>> -    return A < B->group();
>>>> +class Section : public Chunk<target_endianness, is64Bits> {
>>>> +public:
>>>> +  // The Kind of section that the object represents
>>>> +  enum Kind {
>>>> +    K_Default = 0x100,
>>>> +    K_SymbolTable,
>>>> +    K_StringTable,
>>>> +  };
>>> I see now that this isn't the using the same kind field as Chunk is.
>>> So no need for the 0x100. Although it does hide Chunk::Kind, so it
>>> needs a different name.
>>>
>>>> +  // Create a section object, the section is set to the default 
>>>> type if the
>>>> +  // caller doesnot set it
>>>> +  Section(const StringRef sectionName,
>>>> +          const int32_t contentType,
>>>> +          const int32_t contentPermissions,
>>>> +          const int32_t order,
>>>> +          const Kind kind = K_Default)
>>>> +    : Chunk<target_endianness, is64Bits>
>>>> +      (sectionName, Chunk<target_endianness, is64Bits>::K_ELFSection)
>>>> +    , _contentType(contentType)
>>>> +    , _contentPermissions(contentPermissions)
>>>> +    , _sectionKind(kind)
>>>> +    , _entSize(0)
>>>> +    , _shInfo(0)
>>>> +    , _link(0) {
>>>> +    this->setOrder(order);
>>>>     }
>>>> -  bool operator()(Chunk<target_endianness, is64Bits> *A, uint16_t 
>>>> B) {
>>>> -    return A->group() < B;
>>>> +
>>>> +  /// return the section kind
>>>> +  Kind sectionKind() const {
>>>> +    return _sectionKind;
>>>>     }
>>>> -#if defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL == 2
>>>> - bool operator()(Chunk<target_endianness, is64Bits> *A,
>>>> -        Chunk<target_endianness, is64Bits> *B) {
>>>> -   return A->group() < B->group();
>>>> - }
>>>> -#endif
>>>> -};
>>>>
>>>> -/// Pair of atom and offset in section.
>>>> -typedef std::tuple<const DefinedAtom*, uint64_t> AtomInfo;
>>>> +  /// Align the offset to the required modulus defined by the atom 
>>>> alignment
>>>> +  uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment 
>>>> &atomAlign) {
>>>> +    uint64_t requiredModulus = atomAlign.modulus;
>>>> +    int64_t align2 = 1 << atomAlign.powerOf2;
>>> Unsigned. Won't warn if you do 1u <<.
>>>
>>>> +    uint64_t currentModulus = (offset % align2);
>>>> +    uint64_t retOffset = offset;
>>>> +    if (currentModulus != requiredModulus) {
>>>> +      if (requiredModulus > currentModulus)
>>>> +        retOffset += requiredModulus - currentModulus;
>>>> +      else
>>>> +        retOffset += align2 + requiredModulus - currentModulus;
>>>> +    }
>>>> +    return retOffset;
>>>> +  }
>>>>
>>>> +
>>>> +  void finalize() {
>>>> +    // sh_info should be one greater than last symbol with 
>>>> STB_LOCAL binding
>>>> +    // we sort the symbol table to keep all local symbols at the 
>>>> beginning
>>>> +    std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
>>>> +                    [](const Elf_Sym *A, const Elf_Sym *B) {
>>>> +                     return A->getBinding() < B->getBinding();
>>>> +                     });
>>> This needs to be reformatted.
>>>
>>>> +    uint16_t shInfo = 0;
>>>> +    for (auto i : _symbolTable) {
>>>> +      if (i->getBinding() != ELF::STB_LOCAL)
>>>> +        break;
>>>> +      shInfo++;
>>>> +    }
>>>> +    this->_shInfo = shInfo;
>>>> +    this->setLink(_stringSection->ordinal());
>>>> +  }
>>>> +
>>>> +  // HashKey for the Segment
>>>> +  class SegmentHashKey {
>>>> +  public:
>>>> +    int64_t operator() (const SegmentKey &k) const {
>>>> +      // k.first = SegmentName
>>>> +      // k.second = SegmentFlags
>>>> +      return llvm::hash_combine(k.first, k.second);
>>>>       }
>>>> -    symbol->st_value = aa->value();
>>>> - } else {
>>>> -   symbol->st_value = 0;
>>>> -   t = ELF::STT_NOTYPE;
>>>> -   b = ELF::STB_LOCAL;
>>>> - }
>>>> - symbol->setBindingAndType(b, t);
>>>> +  };
>>>>
>>>> - _symbolTable.push_back(symbol);
>>>> - this->_size += sizeof(Elf_Sym);
>>>> -}
>>>> +  typedef std::unordered_map<Key,
>>>> +          Section<target_endianness, is64Bits>*, HashKey> 
>>>> SectionMapT;
>>>> +  typedef std::unordered_map<SegmentKey,
>>>> +                             Segment<target_endianness, is64Bits>*,
>>>> +                             SegmentHashKey> SegmentMapT;
>>>>
>>> - Michael Spencer
>>>
>>
>>
>
>


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

-------------- next part --------------
Index: WriterELF.cpp
===================================================================
--- WriterELF.cpp	(revision 170980)
+++ WriterELF.cpp	(working copy)
@@ -15,16 +15,16 @@
 #include "lld/Core/InputFiles.h"
 #include "lld/Core/Reference.h"
 #include "lld/Core/SharedLibraryAtom.h"
-
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/OwningPtr.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
-
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Object/ELF.h"
-
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ELF.h"
@@ -34,1382 +34,2022 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/system_error.h"
+#include "AtomsELF.h"
 
 #include <map>
+#include <unordered_map>
 #include <tuple>
 #include <vector>
-#include <algorithm>
 
 using namespace llvm;
 using namespace llvm::object;
 namespace lld {
 namespace elf {
 
-// The group decides where sections of similar permissions reside
-// inside a file. This is also used to create program headers. Each group
-// will be in a new segment.
+template<support::endianness target_endianness, bool is64Bits>
+class ELFExecutableWriter;
 
-/// \name Chunk Groups
-/// Each "Chunk" should be arranged in a weak strict order
-/// This is done to minimize memory utilization when creating program segments.
-/// This will remain in place till a more felxible mechanism of moving chunks 
-/// around and packing for memory efficiency is put in place. 
-/// The Chunks are arranged by group numbers. Every switch from group A to B
-/// triggers a formation of new segment. Additionally segments are also made
-/// within a group if there are vast regions (multiple pages) of 0 for 
-/// alignment constraints.
-enum {
-/// @{
-///Invalid group (default on creation)
-  CG_INVALID = 0x0,
-///This is a "header" kind of chunk that goes at beginning of ELF file
-  CG_HEADER = 0x1,
-///This is a section chunk with read write and execute permissions
-  CG_RWX = 0x3,
-///This is a section chunk with read and execute permissions
-  CG_RX = 0x4,
-///This is a section chunk with read permission
-  CG_R = 0x5,
-///This is a section chunk with read and write permissions
-  CG_RW = 0x6,
-///This is a section chunk with write and execute permissions
-  CG_WX = 0x7,
-///This is a section chunk with write permission
-  CG_W = 0x8,
-///This is a section chunk with execute permission
-  CG_X = 0x9,
-///This is a section which is no loaded by program loader
-  CG_NO_LOAD = 0xFE,
-///This is ELF file metadata that goes at end of file
-  CG_FILE_END = 0xFF 
-/// @}
-};
+/// \brief The ELFWriter class is a base class for the linker to write
+///        various kinds of ELF files.
+class ELFWriter : public Writer {
+  public:
+    ELFWriter() { }
 
-template<support::endianness target_endianness, bool is64Bits>
-class ELFWriter;
+  public:
+    /// \brief builds the chunks that needs to be written to the output
+    ///        ELF file
+    virtual void buildChunks(const lld::File &file) = 0;
 
-template<support::endianness target_endianness, bool is64Bits>
-class StockSectionChunk;
+    /// \brief Writes the chunks into the output file specified by path
+    virtual error_code writeFile(const lld::File &File, StringRef path) = 0;
 
-/// \brief A Chunk is a contiguous range of space.
+    /// \brief Writes the chunks into the output file specified by path
+    virtual uint64_t addressOfAtom(const Atom *atom) = 0;
+
+    /// \brief Return the processing function to apply Relocations
+    virtual KindHandler *kindHandler()  = 0;
+};
+
+/// \brief A chunk is a contiguous region of space
 template<support::endianness target_endianness, bool is64Bits>
 class Chunk {
 public:
-  LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
+
+  /// \brief Describes the type of Chunk
+  enum Kind {
+    K_ELFHeader, // ELF Header
+    K_ELFProgramHeader, // Program Header
+    K_ELFSegment, // Segment
+    K_ELFSection, // Section
+    K_ELFSectionHeader // Section header
+  };
+  Chunk(StringRef name, Kind kind) 
+    : _name(name)
+    , _kind(kind)
+    , _fsize(0)
+    , _msize(0)
+    , _align2(0)
+    , _order(0)
+    , _ordinal(1)
+    , _start(0)
+    , _fileoffset(0) {}
   virtual             ~Chunk() {}
-  virtual StringRef   segmentName() const = 0;
-  virtual bool        occupiesNoDiskSpace();
-  virtual void        write(uint8_t *fileBuffer) = 0;
-  void                assignFileOffset(uint64_t &curOff, uint64_t &curAddr);
-  virtual const char *info() = 0;
-  uint64_t            size() const;
-  uint64_t            address() const;
-  uint64_t            fileOffset() const;
-  uint64_t            align2() const;
-  static uint64_t     alignTo(uint64_t value, uint8_t align2);
+  // Does the chunk occupy disk space 
+  virtual bool        occupiesNoDiskSpace() const {
+    return false;    
+  }
+  // The name of the chunk
+  StringRef name() const { return _name; }
+  // Kind of chunk
+  Kind kind() const { return _kind; }
+  uint64_t            fileSize() const { return _fsize; }
+  uint64_t            align2() const { return _align2; }
+  void                appendAtom() const;
+
+  // The ordinal value of the chunk
   uint64_t            ordinal() const { return _ordinal;}
-  void                setOrdinal(uint64_t newVal) { _ordinal = newVal;}
-  void                setGroup(uint16_t val) { _group = val;}
-  uint16_t            group() const { return _group;}
-  void                init();
-  bool                isLoadable() { return _isLoadable; }
-  void                isLoadable(uint64_t val) {  _isLoadable = val; }
-  enum class Kind {
-    Header,      // This is a header chunk
-    Section      // chunk represents a section
-  };
-  Kind getChunkKind() const { return _cKind; }
-private:
-  const Kind _cKind;
+  void               setOrdinal(uint64_t newVal) { _ordinal = newVal;}
+  // The order in which the chunk would appear in the output file
+  uint64_t            order() const { return _order; }
+  void               setOrder(uint32_t order) { _order = order; }
+  // Output file offset of the chunk
+  uint64_t            fileOffset() const { return _fileoffset; }
+  void               setFileOffset(uint64_t offset) { _fileoffset = offset; }
+  // Output start address of the chunk
+  void               setVAddr(uint64_t start) { _start = start; }
+  uint64_t            virtualAddr() const { return _start; }
+  // Does the chunk occupy memory during execution ?
+  uint64_t            memSize() const { return _msize; }
+  void               setMemSize(uint64_t msize) { _msize = msize; }
+  // Writer the chunk 
+  virtual void       write(ELFWriter *writer, 
+                           OwningPtr<FileOutputBuffer> &buffer) = 0;
+  // Finalize the chunk before writing
+  virtual void       finalize() = 0;
+
 protected:
-  Chunk();
-  Chunk(Kind K): _cKind(K) { this->init();}
-  uint64_t _size;
-  uint64_t _address;
-  uint64_t _fileOffset;
+  StringRef _name;
+  Kind _kind;
+  uint64_t _fsize;
+  uint64_t _msize;
   uint64_t _align2;
+  uint32_t  _order;
   uint64_t _ordinal;
-  uint16_t _group;
-  bool     _isLoadable;
+  uint64_t _start;
+  uint64_t _fileoffset;
 };
 
-template<support::endianness target_endianness, bool is64Bits>
-static void swapChunkPositions(Chunk<target_endianness, is64Bits>&a,
-                               Chunk<target_endianness, is64Bits>&b) {
-  uint64_t tempOrdinal;
-  if (a.ordinal() == b.ordinal()) return;
-  tempOrdinal = a.ordinal();
-  a.setOrdinal(b.ordinal());
-  b.setOrdinal(tempOrdinal);
-}
+/// \brief The ELFLayoutOptions encapsulates the options used by all Layouts
+///        Examples of the ELFLayoutOptions would be a script that would be used
+///        to drive the layout 
+class ELFLayoutOptions {
+public:
+  ELFLayoutOptions() { }
 
-template<support::endianness target_endianness, bool is64Bits>
-bool chunkGroupSort(Chunk<target_endianness, is64Bits> *A,
-                    Chunk<target_endianness, is64Bits> *B) {
-  if (A->group() == CG_INVALID || B->group() == CG_INVALID)
-    llvm_unreachable("Invalid group number");
-  return A->group() < B->group();
-}
+  ELFLayoutOptions(StringRef &linker_script) : _script(linker_script)
+  {}
 
+  /// parse the linker script
+  error_code parseLinkerScript();
+
+  /// Is the current section present in the linker script
+  bool isSectionPresent();
+
+private:
+  StringRef _script;
+};
+
+/// \brief The ELFLayout is an abstract class for managing the final layout for 
+///        the kind of binaries(Shared Libraries / Relocatables / Executables 0
+///        Each architecture (Hexagon, PowerPC, MIPS) would have a concrete 
+///        subclass derived from ELFLayout for generating each binary thats 
+//         needed by the lld linker
+class ELFLayout {
+public:
+  typedef uint32_t SectionOrder;
+  typedef uint32_t SegmentType;
+  typedef uint32_t Flags;
+
+public:
+  /// Return the order the section would appear in the output file
+  virtual SectionOrder getSectionOrder
+                        (const StringRef name,
+                         int32_t contentType,
+                         int32_t contentPerm) = 0;
+  /// append the Atom to the layout and create appropriate sections 
+  virtual error_code addAtom(const Atom *atom) = 0;
+  /// find the Atom Address in the current layout
+  virtual bool findAtomAddrByName(const StringRef name, uint64_t &addr) = 0;
+  /// associates a section to a segment
+  virtual void assignSectionsToSegments() = 0;
+  /// associates a virtual address to the segment, section, and the atom
+  virtual void assignVirtualAddress() = 0;
+  /// associates a file offset to the segment, section and the atom
+  virtual void assignFileOffsets() = 0;
+
+public:
+  ELFLayout() {}
+  ELFLayout(WriterOptionsELF &writerOptions, 
+            ELFLayoutOptions &layoutOptions) 
+    : _writerOptions(writerOptions)
+    , _layoutOptions(layoutOptions) {}
+  virtual ~ELFLayout() { }
+
+private:
+  WriterOptionsELF _writerOptions;
+  ELFLayoutOptions _layoutOptions;
+};
+
+
+/// \brief A section contains a set of atoms that have similiar properties
+///        The atoms that have similiar properties are merged to form a section
 template<support::endianness target_endianness, bool is64Bits>
-struct ChunkComparator {
-  bool operator()(uint16_t A, Chunk<target_endianness, is64Bits> *B) {
-    return A < B->group();
+class Section : public Chunk<target_endianness, is64Bits> {
+public:
+  // The Kind of section that the object represents 
+  enum SectionKind {
+    K_Default,
+    K_SymbolTable,
+    K_StringTable,
+  };
+  // Create a section object, the section is set to the default type if the
+  // caller doesnot set it
+  Section(const StringRef sectionName, 
+          const int32_t contentType,
+          const int32_t contentPermissions,
+          const int32_t order,
+          const SectionKind kind = K_Default) 
+    : Chunk<target_endianness, is64Bits>
+      (sectionName, Chunk<target_endianness, is64Bits>::K_ELFSection)
+    , _contentType(contentType)
+    , _contentPermissions(contentPermissions)
+    , _sectionKind(kind)
+    , _entSize(0)
+    , _shInfo(0)
+    , _link(0) {
+    this->setOrder(order);
   }
-  bool operator()(Chunk<target_endianness, is64Bits> *A, uint16_t B) {
-    return A->group() < B;
+
+  /// return the section kind
+  SectionKind sectionKind() const {
+    return _sectionKind;
   }
-#if defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL == 2
- bool operator()(Chunk<target_endianness, is64Bits> *A,
-        Chunk<target_endianness, is64Bits> *B) {
-   return A->group() < B->group();
- }
-#endif
-};
 
-/// Pair of atom and offset in section.
-typedef std::tuple<const DefinedAtom*, uint64_t> AtomInfo;
+  /// Align the offset to the required modulus defined by the atom alignment
+  uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign) {
+    uint64_t requiredModulus = atomAlign.modulus;
+    uint64_t align2 = 1u << atomAlign.powerOf2;
+    uint64_t currentModulus = (offset % align2);
+    uint64_t retOffset = offset;
+    if (currentModulus != requiredModulus) {
+      if (requiredModulus > currentModulus)
+        retOffset += requiredModulus - currentModulus;
+      else
+        retOffset += align2 + requiredModulus - currentModulus;
+    }
+    return retOffset;
+  }
 
-/// \brief A SectionChunk represents ELF sections 
-template<support::endianness target_endianness, bool is64Bits>
-class SectionChunk : public Chunk<target_endianness, is64Bits> {
-public:
-  virtual StringRef   segmentName() const { return _segmentName; }
-  virtual bool        occupiesNoDiskSpace();
-  virtual const char  *info();
-  StringRef           sectionName() { return _sectionName; }
-  uint64_t            shStrtableOffset(){ return _offsetInStringTable; }
-  void                setShStrtableOffset (uint64_t val) {
-                       _offsetInStringTable = val; } 
-  uint32_t            flags()  { return _flags; }
-  uint32_t            type() const { return _type; }
-  uint64_t            link()   { return _link; }
-  void                link(uint64_t val)   { _link = val; }
-  uint16_t            shinfo() { return _shinfo; }
-  uint64_t            entsize() { return _entsize; }
-  SectionChunk(StringRef secName, StringRef segName, bool loadable, 
-               uint64_t flags , uint64_t link,  uint64_t info ,
-               uint64_t type, uint64_t entsz, const WriterOptionsELF &op, 
-               ELFWriter<target_endianness, is64Bits> &writer);
+  // \brief Append an atom to a Section. The atom gets pushed into a vector 
+  // contains the atom, the atom file offset, the atom virtual address
+  // the atom file offset is aligned appropriately as set by the Reader
+  void appendAtom(const Atom *atom) {
+    Atom::Definition atomType = atom->definition();
+    const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
+    assert(atom != nullptr && "Expecting the atom to be a DefinedAtom");
+    DefinedAtom::Alignment atomAlign = definedAtom->alignment();
+    uint64_t align2 = 1u << atomAlign.powerOf2;
+    // Align the atom to the required modulus/ align the file offset and the 
+    // memory offset seperately this is required so that BSS symbols are handled
+    // properly as the BSS symbols only occupy memory size and not file size
+    uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
+    uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
+    switch (atomType) {
+    case Atom::definitionRegular:
+      switch(definedAtom->contentType()) {
+      case  DefinedAtom::typeCode:
+      case  DefinedAtom::typeData:
+        _atoms.push_back(std::make_pair(atom, std::make_pair(fOffset, 0)));
+        this->_fsize = fOffset + definedAtom->size();
+        this->_msize = mOffset + definedAtom->size();
+        break;
+      case  DefinedAtom::typeZeroFill:
+        _atoms.push_back(std::make_pair(atom, std::make_pair(mOffset, 0)));
+        this->_msize = mOffset + definedAtom->size();
+        break;
+      default:
+        this->_fsize = fOffset + definedAtom->size();
+        this->_msize = mOffset + definedAtom->size();
+        break;
+      }
+      break;
+    default:
+      llvm_unreachable("Expecting only definedAtoms being passed here");
+      break;
+    } 
+    // Set the section alignment to the largest alignment 
+    // std::max doesnot support uint64_t
+    if (this->_align2 < align2) 
+      this->_align2 = align2;
+  }
+
+  /// \brief Set the virtual address of each Atom in the Section. This 
+  /// routine gets called after the linker fixes up the virtual address 
+  /// of the section
+  void assignVirtualAddress(uint64_t &addr) {
+    for (auto &ai : _atoms) {
+      ai.second.second = addr + ai.second.first;
+    }
+    addr += this->memSize();
+  }
+
+  /// \brief Set the file offset of each Atom in the section. This routine 
+  /// gets called after the linker fixes up the section offset 
+  void assignOffsets(uint64_t offset) {
+    for (auto &ai : _atoms) {
+      ai.second.first = offset + ai.second.first;
+    }
+  }
+
+  /// \brief Find the Atom address given a name, this is needed to to properly 
+  ///  apply relocation. The section class calls this to find the atom address
+  ///  to fix the relocation
+  bool findAtomAddrByName(const StringRef name, uint64_t &addr) {
+    for (auto ai : _atoms) {
+      if (ai.first->name() == name) {
+        addr = ai.second.second;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /// \brief Does the Atom occupy any disk space
+  bool occupiesNoDiskSpace() const {
+    return _contentType == DefinedAtom::typeZeroFill;
+  }
+
+  /// \brief The permission of the section is the most permissive permission 
+  /// of all atoms that the section contains
+  void setContentPermissions(int32_t perm) {
+    _contentPermissions = std::max(perm, _contentPermissions);
+  }
+
+  /// \brief Get the section flags, defined by the permissions of the section
+  int64_t flags() {
+    switch (_contentPermissions) {
+    case DefinedAtom::perm___:
+      return 0;
+
+    case DefinedAtom::permR__:
+        return llvm::ELF::SHF_ALLOC;
   
+    case DefinedAtom::permR_X:
+        return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR;
+  
+    case DefinedAtom::permRW_:
+    case DefinedAtom::permRW_L:
+        return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE;
+  
+    case DefinedAtom::permRWX:
+        return llvm::ELF::SHF_ALLOC | 
+                llvm::ELF::SHF_WRITE | 
+                llvm::ELF::SHF_EXECINSTR;
+
+    default:
+        break;
+    }
+    return llvm::ELF::SHF_ALLOC;
+  }
+
+  /// \brief Return the raw flags, we need this to sort segments
+  int64_t atomflags() const {
+    return _contentPermissions;
+  }
+
+  /// \brief Return the section type, the returned value is recorded in the 
+  /// sh_type field of the Section Header
+  int type() {
+    switch (_contentType) {
+    case DefinedAtom::typeCode:
+    case DefinedAtom::typeData:
+    case DefinedAtom::typeConstant:
+      return llvm::ELF::SHT_PROGBITS;
+
+    case DefinedAtom::typeZeroFill:
+     return llvm::ELF::SHT_NOBITS;
+
+    // Case to handle section types
+    // Symtab, String Table ...
+    default:
+     return _contentType;
+    }
+  }
+
+  /// \brief Returns the section link field, the returned value is 
+  ///        recorded in the sh_link field of the Section Header
+  int link() const {
+    return _link;
+  }
+
+  void setLink(int32_t link) {
+    _link = link;
+  }
+
+  /// \brief Returns the section entsize field, the returned value is 
+  ///        recorded in the sh_entsize field of the Section Header
+  int entsize() const {
+    return _entSize;
+  }
+
+  /// \brief Returns the shinfo field, the returned value is 
+  ///        recorded in the sh_info field of the Section Header
+  int shinfo() const { 
+    return _shInfo;
+  }
+
+  /// \brief Records the segmentType, that this section belongs to
+  void setSegment(const ELFLayout::SegmentType segmentType) {
+    _segmentType = segmentType;
+  }
+
+  /// \brief convert the segment type to a String for diagnostics
+  ///        and printing purposes
+  StringRef segmentKindToStr() const {
+    switch(_segmentType) {
+    case llvm::ELF::PT_INTERP:
+      return "INTERP";
+    case llvm::ELF::PT_LOAD:
+      return "LOAD";
+    case llvm::ELF::PT_GNU_EH_FRAME:
+      return "EH_FRAME";
+    case llvm::ELF::PT_NOTE:
+      return "NOTE";
+    case llvm::ELF::PT_DYNAMIC:
+      return "DYNAMIC";
+    case llvm::ELF::PT_GNU_RELRO:
+      return "RELRO";
+    case llvm::ELF::PT_NULL:
+      return "NULL";
+    default:
+      return "UNKNOWN";
+    }
+  }
+
+  /// \brief for LLVM style RTTI information
   static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
-    return c->getChunkKind() == Chunk<target_endianness, is64Bits>::Kind
-                                                                  ::Section;
+    return c->kind() == Chunk<target_endianness, is64Bits>::K_ELFSection;
   }
+
+  /// \brief Finalize the section contents before writing
+  void finalize() { }
+
+  /// \brief Write the section and the atom contents to the buffer 
+  void write(ELFWriter *writer, 
+             OwningPtr<FileOutputBuffer> &buffer) {
+    uint8_t *chunkBuffer = buffer->getBufferStart();
+    for (auto &ai : _atoms) {
+      const DefinedAtom *definedAtom = llvm::dyn_cast<DefinedAtom>(ai.first);
+      // Copy raw content of atom to file buffer.
+      ArrayRef<uint8_t> content = definedAtom->rawContent();
+      uint64_t contentSize = content.size();
+      if (contentSize == 0)
+        continue;
+      uint8_t *atomContent = chunkBuffer + ai.second.first;
+      std::copy_n(content.data(), contentSize, atomContent);
+      for (auto ref = definedAtom->begin(); ref != definedAtom->end(); ++ref) {
+        uint32_t offset = ref->offsetInAtom();
+        uint64_t targetAddress = 0;
+        if (ref->target() != nullptr)
+          targetAddress = writer->addressOfAtom(ref->target());
+        else
+          assert(0 && "Found the target to be NULL");
+        uint64_t fixupAddress = writer->addressOfAtom(ai.first) + offset;
+        // apply the relocation
+        writer->kindHandler()->applyFixup(ref->kind(), 
+                                          ref->addend(),
+                                          &atomContent[offset],
+                                          fixupAddress,
+                                          targetAddress);
+      }
+    }
+  }
+
+  /// Atom Iterators
+  typedef typename std::vector<std::pair<const Atom *, 
+          std::pair<uint64_t, uint64_t>>>::iterator atom_iter;
+
+  atom_iter atoms_begin() { return _atoms.begin(); }
+
+  atom_iter atoms_end() { return _atoms.end(); }
+
 protected:
-  uint64_t                                _link;
-  uint64_t                                _shinfo;
-  uint16_t                                _entsize;
-  StringRef                               _segmentName;
-  StringRef                               _sectionName;
-  const WriterOptionsELF                 &_options;
-  ELFWriter<target_endianness, is64Bits> &_writer;
-  uint64_t                                _flags;
-  uint64_t                                _type;
-  uint64_t                                _offsetInStringTable;
-};
+  int32_t _contentType;
+  int32_t _contentPermissions;
+  SectionKind    _sectionKind;
+  // An Atom is appended to the vector with the following fields
+  // field1 : Atom
+  // field2 : fileoffset (initially set with a base offset of 0)
+  // field3 : virtual address
+  std::vector<std::pair<const Atom *, std::pair<uint64_t, uint64_t>>> _atoms;
+  ELFLayout::SegmentType _segmentType;
+  int64_t _entSize;
+  int64_t _shInfo;
+  int64_t _link;
+};  
 
+/// \brief A MergedSections represents a set of sections grouped by the same name
+///        The output file that gets written by the linker has sections grouped
+///        by similiar names
 template<support::endianness target_endianness, bool is64Bits>
-bool IsBss(const  Chunk<target_endianness, is64Bits> *A) {
-  if (auto X = llvm::dyn_cast<SectionChunk<target_endianness, is64Bits>>(A)) 
-    return X->type() != ELF::SHT_NOBITS;
-  llvm_unreachable("Call to a non section type chunk");
-  // adding a non-reachable return bool for making compiler happy
-  return false;
-}
+class MergedSections {
+public:
+  MergedSections(StringRef name) 
+    : _name(name)
+    ,_hasSegment(false)
+    ,_ordinal(0)
+    ,_flags(0)
+    ,_size(0)
+    ,_memSize(0)
+    ,_fileOffset(0)
+    ,_virtualAddr(0)
+    ,_shInfo(0)
+    ,_entSize(0)
+    ,_link(0)
+    ,_align2(0)
+    ,_kind(0)
+    ,_type(0) { }
+                                  
+  // Set the MergedSections is associated with a segment
+  void setHasSegment() { _hasSegment = true; }
 
-/// \brief Return  pointer to a defined atom whose name is specified as parameter 
-///        if present in the specified section.
-///        When all the atoms are resolved, get addresses and offsets, we 
-///        have atoms with unique names. Only then this routine is guaranteed 
-///        to return the atom of interest. This routine is useful in finding atoms 
-///        which are special such as entry point to a file 
-template<support::endianness target_endianness, bool is64Bits>
-static const DefinedAtom* findDefinedAtomByName(StringRef name,
-                                          StockSectionChunk<target_endianness, 
-                                                            is64Bits> *sec) {
-  ArrayRef<AtomInfo> atoms = sec->atoms();
-  for (auto ai = atoms.begin(); ai != atoms.end(); ai++) {
-    if ((std::get<0>(*ai))->name() == name )
-      return std::get<0>(*ai);
+  /// Sets the ordinal 
+  void setOrdinal(uint64_t ordinal) {
+    _ordinal = ordinal;
   }
-  return nullptr;
-}
 
-/// \brief A StockSectionChunk is a section created by linker with all 
-///        attributes concluded from the defined atom contained within.
-template<support::endianness target_endianness, bool is64Bits>
-class StockSectionChunk : public SectionChunk<target_endianness, is64Bits> {
-public:
-  virtual StringRef segmentName() const { return this->_segmentName; }
-  void                appendAtom(const DefinedAtom*);
-  virtual void        write(uint8_t *filebuffer);
-  const               ArrayRef<AtomInfo> atoms() const;
-  StockSectionChunk(StringRef sectionName, bool loadable,
-                    DefinedAtom::ContentType type, 
-                    const WriterOptionsELF &options,
-                    ELFWriter<target_endianness, is64Bits> &writer);
+  /// Sets the Memory size 
+  void setMemSize(uint64_t memsz) { 
+    _memSize = memsz;
+  }
+
+  /// Sets the size fo the merged Section
+  void setSize(uint64_t fsiz) {
+    _size = fsiz;
+  }
+
+  // The offset of the first section contained in the merged section is contained here
+  void setFileOffset(uint64_t foffset) {
+    _fileOffset = foffset;
+  }
+
+  // Sets the starting address of the section
+  void setAddr(uint64_t addr) {
+    _virtualAddr = addr;
+  }
+
+  // Appends a section into the list of sections that are part of this Merged
+  // Section
+  void appendSection(Chunk<target_endianness, is64Bits> *c) {
+    if (c->align2() > _align2) 
+      _align2 = c->align2();
+    if (c->kind() == Chunk<target_endianness, is64Bits>::K_ELFSection) {
+      Section<target_endianness, is64Bits> *section;
+      section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(c);
+      _link = section->link();
+      _shInfo = section->shinfo();
+      _entSize = section->entsize();
+      _type = section->type();
+      if (_flags < section->flags())
+        _flags = section->flags();
+    }
+    _kind = c->kind();
+    _sections.push_back(c);
+  }
+
+  // Iterators
+  typedef typename std::vector<Chunk<target_endianness, is64Bits> *>::iterator 
+                                                                     ChunkIter;
+
+  ChunkIter begin_sections() { return _sections.begin(); }
+
+  ChunkIter end_sections() { return _sections.end(); }
+
+  // The below functions returns the properties of the MergeSection
+  bool hasSegment() const { return _hasSegment; }
+
+  StringRef name() const { return _name; }
+
+  int64_t shinfo() const { return _shInfo; }
+
+  uint64_t align2() const { return _align2; }
+
+  int64_t link() const { return _link; }
+
+  int64_t type() const { return _type; }
+
+  uint64_t virtualAddr() const { return _virtualAddr; }
+
+  int64_t ordinal() const { return _ordinal; }
+
+  int64_t kind() const { return _kind; }
+
+  uint64_t fileSize() const { return _size; }
+
+  int64_t entsize() const { return _entSize; }
+
+  uint64_t fileOffset() const { return _fileOffset; }
+
+  int64_t flags() const { return _flags; }
+
+  uint64_t memSize() { return _memSize; }
+
 private:
-  std::vector<AtomInfo>                   _atoms;
+  StringRef _name;
+  bool _hasSegment;
+  uint64_t _ordinal;
+  int64_t _flags;
+  uint64_t _size;
+  uint64_t _memSize;
+  uint64_t _fileOffset;
+  uint64_t _virtualAddr;
+  int64_t _shInfo;
+  int64_t _entSize;
+  int64_t _link;
+  uint64_t _align2;
+  int64_t _kind;
+  int64_t _type;
+  std::vector<Chunk<target_endianness, is64Bits> *> _sections;
 };
-                        
-/// \brief An ELFHeaderChunk represents the Elf[32/64]_Ehdr structure at the
-///        start of an ELF executable file.
+
+/// \brief A segment can be divided into segment slices 
+///        depending on how the segments can be split 
 template<support::endianness target_endianness, bool is64Bits>
-class ELFHeaderChunk : public Chunk<target_endianness, is64Bits> {
+class SegmentSlice {
 public:
-  LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
-  typedef object::Elf_Ehdr_Impl<target_endianness, is64Bits> Elf_Ehdr;
+  typedef typename std::vector<Section<target_endianness, is64Bits> *>::iterator 
+                                                                    sectionIter;
 
-  ELFHeaderChunk(const WriterOptionsELF &options,
-                 const File &file);
+  SegmentSlice() { }
 
-  void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
-  void e_type(uint16_t type)           { _eh.e_type = type; }
-  void e_machine(uint16_t machine)     { _eh.e_machine = machine; }
-  void e_version(uint32_t version)     { _eh.e_version = version; }
-  void e_entry(uint64_t entry)         { _eh.e_entry = entry; }
-  void e_phoff(uint64_t phoff)         { _eh.e_phoff = phoff; }
-  void e_shoff(uint64_t shoff)         { _eh.e_shoff = shoff; }
-  void e_flags(uint32_t flags)         { _eh.e_flags = flags; }
-  void e_ehsize(uint16_t ehsize)       { _eh.e_ehsize = ehsize; }
-  void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
-  void e_phnum(uint16_t phnum)         { _eh.e_phnum = phnum; }
-  void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
-  void e_shnum(uint16_t shnum)         { _eh.e_shnum = shnum; }
-  void e_shstrndx(uint16_t shstrndx)   { _eh.e_shstrndx = shstrndx; }
-  uint64_t  size()                     { return sizeof (Elf_Ehdr); }
+  /// Set the segment slice so that it begins at the offset specified
+  /// by fileoffset and set the start of the slice to be s and the end 
+  /// of the slice to be e
+  void set(uint64_t fileoffset, int32_t s, int e) {
+    _startSection = s;
+    _endSection = e+1;
+    _offset = fileoffset;
+  }
 
-  virtual StringRef   segmentName() const;
-  virtual void        write(uint8_t *fileBuffer);
-  virtual const char *info();
-  static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
-    return c->getChunkKind() ==  Chunk<target_endianness, is64Bits>::Kind
-                                                                   ::Header;
+  // Set the segment slice start and end iterators. This is used to walk through
+  // the sections that are part of the Segment slice
+  void setSections(sectionIter start, sectionIter end) {
+    _startSectionIter = start;
+    _endSectionIter = end;
   }
+
+  // Return the fileOffset of the slice
+  uint64_t fileOffset() const { return _offset; }
+
+  // Return the size of the slice
+  uint64_t fileSize() const { return _size; }
+
+  // Return the start of the slice
+  int32_t startSection() const { return _startSection; }
+
+  // Return the start address of the slice
+  uint64_t virtualAddr() const { return _addr; }
+
+  // Return the memory size of the slice
+  uint64_t memSize() const { return _memSize; }
+
+  // Return the alignment of the slice
+  uint64_t align2() const { return _align2; }
+
+  void setSize(uint64_t sz) { _size = sz; }
+
+  void setMemSize(uint64_t memsz) { _memSize = memsz; }
+
+  void setVAddr(uint64_t addr) { _addr = addr; }
+
+  void setAlign(uint64_t align) { _align2 = align; }
+
+  static bool compare_slices(SegmentSlice<target_endianness, is64Bits> *a, 
+                             SegmentSlice<target_endianness, is64Bits> *b) {
+    return (a->startSection() < b->startSection());
+  }
+
+  // Functions to run through the slice
+  sectionIter sections_begin() { return _startSectionIter; }
+
+  sectionIter sections_end() { return _endSectionIter; }
+
 private:
-  Elf_Ehdr             _eh;
+  int32_t _startSection;
+  int32_t _endSection;
+  sectionIter _startSectionIter;
+  sectionIter _endSectionIter;
+  uint64_t _addr;
+  uint64_t _offset;
+  uint64_t _size;
+  uint64_t _align2;
+  uint64_t _memSize;
 };
 
-/// \brief An ELFSectionHeaderChunk represents the Elf[32/64]_Shdr structure
-///        that is placed right after the ELFHeader.
-///
+/// \brief A segment contains a set of sections, that have similiar properties
+//  the sections are already seperated based on different flags and properties
+//  the segment is just a way to concatenate sections to segments
 template<support::endianness target_endianness, bool is64Bits>
-class ELFSectionHeaderChunk : public Chunk<target_endianness, is64Bits> {
+class Segment : public Chunk<target_endianness, is64Bits> {
 public:
-  LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
-  typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
-  ELFSectionHeaderChunk(const WriterOptionsELF &Options,
-                        ELFWriter<target_endianness, is64Bits>&);
-  void createHeaders();
-  virtual StringRef   segmentName() const;
-  virtual void        write(uint8_t *filebuffer);
-  virtual const char *info();
-  void                computeSize();
-  uint16_t            count();
-  uint16_t            size();
-  void                fixOffsets();
-  const ArrayRef<Elf_Shdr*> sectionInfo() {
-    return _sectionInfo;
+  typedef typename std::vector
+       <SegmentSlice<target_endianness, is64Bits> *>::iterator slice_iter;
+  typedef typename 
+        std::vector<Section<target_endianness, is64Bits> *>::iterator SectionIter;
+
+  Segment(const StringRef name,
+          const ELFLayout::SegmentType type,
+          const WriterOptionsELF &options)
+    : Chunk<target_endianness, is64Bits>(name
+    , Chunk<target_endianness, is64Bits>::K_ELFSegment)
+    , _segmentType(type)
+    , _flags(0)
+    , _atomflags(0)
+    , _options(options) {
+    this->_align2 = 0;
+    this->_fsize = 0;
   }
+
+  /// append a section to a segment
+  void append(Section<target_endianness, is64Bits> *section) {
+    _sections.push_back(section);
+    if (_flags < section->flags())
+      _flags = section->flags();
+    if (_atomflags < section->atomflags())
+      _atomflags = section->atomflags();
+    if (this->_align2 < section->align2())
+      this->_align2 = section->align2();
+  }
+
+  /// Sort segments depending on the property
+  /// If we have a Program Header segment, it should appear first
+  /// If we have a INTERP segment, that should appear after the Program Header
+  /// All Loadable segments appear next in this order
+  /// All Read Write Execute segments follow
+  /// All Read Execute segments appear next
+  /// All Read only segments appear first
+  /// All Write execute segments follow 
+  static bool compareSegments(Segment<target_endianness, is64Bits> *sega, 
+                              Segment<target_endianness, is64Bits> *segb)
+  {
+
+    if (sega->atomflags() < segb->atomflags()) 
+      return false;
+    return true;
+  }
+
+  /// \brief Start assigning file offset to the segment chunks The fileoffset
+  /// needs to be page at the start of the segment and in addition the
+  /// fileoffset needs to be aligned to the max section alignment within the
+  /// segment. This is required so that the ELF property p_poffset % p_align =
+  /// p_vaddr mod p_align holds true.
+  /// The algorithm starts off by assigning the startOffset thats passed in as
+  /// parameter to the first section in the segment, if the difference between
+  /// the newly computed offset is greater than a page, then we create a segment
+  /// slice, as it would be a waste of virtual memory just to be filled with 
+  /// zeroes
+  void assignOffsets(uint64_t startOffset) {
+    int startSection = 0;
+    int currSection = 0;
+    SectionIter startSectionIter, endSectionIter;
+    // slice align is set to the max alignment of the chunks that are 
+    // contained in the slice
+    uint64_t sliceAlign = 0;
+    // Current slice size
+    uint64_t curSliceSize = 0;
+    // Current Slice File Offset
+    uint64_t curSliceFileOffset = 0;
+
+    startSectionIter = _sections.begin();
+    endSectionIter = _sections.end();
+    startSection = 0;
+    bool isFirstSection = true;
+    for (auto si = _sections.begin(); si != _sections.end(); ++si) {
+      if (isFirstSection) {
+        // align the startOffset to the section alignment
+        uint64_t newOffset = llvm::RoundUpToAlignment(startOffset, (*si)->align2());
+        curSliceFileOffset = newOffset;
+        sliceAlign = (*si)->align2();
+        this->setFileOffset(startOffset);
+        (*si)->setFileOffset(newOffset);
+        curSliceSize = (*si)->fileSize();
+        isFirstSection = false;
+      } else {
+        uint64_t curOffset = curSliceFileOffset + curSliceSize;
+        uint64_t newOffset = llvm::RoundUpToAlignment(curOffset, (*si)->align2());
+        SegmentSlice<target_endianness, is64Bits> *slice = nullptr;
+        // If the newOffset computed is more than a page away, lets create
+        // a seperate segment, so that memory is not used up while running
+        if ((newOffset - curOffset) > _options.pageSize()) {
+          // TODO: use std::find here
+          for (auto sei = slices_begin(); sei != slices_end(); ++sei) {
+            if ((*sei)->startSection() == startSection) {
+              slice = *sei;
+              break;
+            }
+          }
+          if (!slice) {
+            slice = new (_segmentAllocate.Allocate
+                         <SegmentSlice<target_endianness, is64Bits>>()) 
+                         SegmentSlice<target_endianness, is64Bits>();
+            _segmentSlices.push_back(slice);
+          }
+          slice->set(curSliceFileOffset, startSection, currSection);
+          slice->setSections(startSectionIter, endSectionIter);
+          slice->setSize(curSliceSize);
+          slice->setAlign(sliceAlign);
+          uint64_t newPageOffset = llvm::RoundUpToAlignment(curOffset, _options.pageSize());
+          newOffset = llvm::RoundUpToAlignment(newPageOffset, (*si)->align2());
+          curSliceFileOffset = newOffset;
+          startSectionIter = endSectionIter;
+          startSection = currSection;
+          (*si)->setFileOffset(curSliceFileOffset);
+          curSliceSize = newOffset - curSliceFileOffset + (*si)->fileSize();
+          sliceAlign = (*si)->align2();
+        }
+        else {
+          if (sliceAlign < (*si)->align2())
+            sliceAlign = (*si)->align2();
+          (*si)->setFileOffset(newOffset);
+          curSliceSize = newOffset - curSliceFileOffset + (*si)->fileSize();
+        }
+      }
+      currSection++;
+      endSectionIter = si;
+    }
+    SegmentSlice<target_endianness, is64Bits> *slice = nullptr;
+    for (auto sei = slices_begin(); sei != slices_end(); ++sei) {
+      // TODO: add std::find
+      if ((*sei)->startSection() == startSection) {
+        slice = *sei;
+        break;
+      }
+    }
+    if (!slice) {
+      slice = new (_segmentAllocate.Allocate
+                   <SegmentSlice<target_endianness, is64Bits>>()) 
+                   SegmentSlice<target_endianness, is64Bits>();
+      _segmentSlices.push_back(slice);
+    }
+    slice->set(curSliceFileOffset, startSection, currSection);
+    slice->setSections(startSectionIter, _sections.end());
+    slice->setSize(curSliceSize);
+    slice->setAlign(sliceAlign);
+    this->_fsize = curSliceFileOffset - startOffset + curSliceSize;
+    std::stable_sort(slices_begin(), slices_end(), 
+                     SegmentSlice<target_endianness, is64Bits>::compare_slices);
+  }
+
+  /// \brief Assign virtual addresses to the slices
+  void assignVirtualAddress(uint64_t &addr, bool isFirstSegment) {
+    for (auto sei = slices_begin(), see = slices_end(); sei != see; ++sei) {
+      bool firstSlice = (sei == slices_begin());
+      // The first segment has distinct since it contains the 
+      // ELF header and the Program Header, if we get to the first segment
+      // and the first slice, set it to the baseaddress
+      // which is the segment address
+      if (isFirstSegment && firstSlice)
+        (*sei)->setVAddr(this->virtualAddr());
+      else {
+        // Align to a page
+        addr = llvm::RoundUpToAlignment(addr, _options.pageSize());
+        // Align to the slice alignment
+        addr = llvm::RoundUpToAlignment(addr, (*sei)->align2());
+      }
+      bool virtualAddressSet = false;
+      for (auto si = (*sei)->sections_begin(), se = (*sei)->sections_end(); 
+                                               si != se; ++si) {
+        // Align the section address
+        addr = llvm::RoundUpToAlignment(addr, (*si)->align2());
+        if (!isFirstSegment && !virtualAddressSet) {
+          (*sei)->setVAddr(addr);
+          virtualAddressSet = true;
+        }
+        (*si)->setVAddr(addr);
+        (*si)->assignVirtualAddress(addr);
+        (*si)->setMemSize(addr - (*si)->virtualAddr());
+      }
+      (*sei)->setMemSize(addr - (*sei)->virtualAddr());
+    }
+  }
+
+  slice_iter slices_begin() {
+    return _segmentSlices.begin();
+  }
+
+  slice_iter slices_end() {
+    return _segmentSlices.end();
+  }
+
+  // Write the Segment 
+  void write(ELFWriter *writer, OwningPtr<FileOutputBuffer> &buffer) {
+    for (auto sei = slices_begin(), see = slices_end(); sei != see; ++sei) {
+      for (auto si = (*sei)->sections_begin(), se = (*sei)->sections_end(); 
+                                               si != se; ++si) {
+        (*si)->write(writer, buffer);
+      }
+    }
+  }
+
+  // Finalize the segment, before we want to write to the output file
+  void finalize() { }
+
+  // For LLVM RTTI 
   static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
-    return c->getChunkKind() ==  Chunk<target_endianness, is64Bits>::Kind
-                                                                   ::Header;
+    return c->kind() == Chunk<target_endianness, is64Bits>::K_ELFSegment;
   }
 
+  // Getters
+  int32_t sectionCount() const {
+    return _sections.size();
+  }
+
+  ELFLayout::SegmentType segmentType() { return _segmentType; }
+
+  int pageSize() const { return _options.pageSize(); }
+
+  int64_t atomflags() const { return _atomflags; }
+
+  int64_t flags() const {
+    int64_t fl = 0;
+    if (_flags & llvm::ELF::SHF_ALLOC)
+      fl |= llvm::ELF::PF_R;
+    if (_flags & llvm::ELF::SHF_WRITE)
+      fl |= llvm::ELF::PF_W;
+    if (_flags & llvm::ELF::SHF_EXECINSTR)
+      fl |= llvm::ELF::PF_X;
+    return fl;
+  }
+
+  int64_t numSlices() const {
+    return _segmentSlices.size();
+  }
+
 private:
-  const WriterOptionsELF                 &_options;
-  ELFWriter<target_endianness, is64Bits> &_writer;
-  llvm::BumpPtrAllocator                  _sectionAllocate;
-  std::vector<Elf_Shdr*>                  _sectionInfo;
+  std::vector<Section<target_endianness, is64Bits> *> _sections;
+  std::vector<SegmentSlice<target_endianness, is64Bits> *> _segmentSlices;
+  ELFLayout::SegmentType _segmentType;
+  int64_t _flags;
+  int64_t _atomflags;
+  const WriterOptionsELF _options;
+  llvm::BumpPtrAllocator _segmentAllocate;
 };
 
-/// \brief Represents the shstr section.
-///
-/// This is a contiguous memory that has all the symbol strings each ending with
-/// null character. We might need more than one such chunks shstrtab for setting
-/// e_shstrndx in ELHHeaderChunk and strtab for use with symtab
+/// \brief The class represents the ELF String Table
 template<support::endianness target_endianness, bool is64Bits>
-class ELFStringSectionChunk : public SectionChunk<target_endianness, is64Bits> {
+class ELFStringTable : public Section<target_endianness, is64Bits> {
+
 public:
-  ELFStringSectionChunk(const WriterOptionsELF &Options,
-                        ELFWriter<target_endianness, is64Bits> &writer,
-                        StringRef secName);
-  virtual StringRef   segmentName() const { return this->_segmentName; }
-  uint64_t            addString(StringRef symName);
-  const char          *info();
-  virtual void        write(uint8_t *filebuffer);
+  ELFStringTable(const char *str, 
+                 int32_t order): 
+                            Section<target_endianness, is64Bits>(str,
+                                                         llvm::ELF::SHT_STRTAB,
+                                                         DefinedAtom::perm___,
+                                                         order,
+                            Section<target_endianness, is64Bits>::K_StringTable) {
+    // the string table has a NULL entry for which
+    // add an empty string
+    _strings.push_back("");
+    this->_fsize = 1;
+    this->_align2 = 1;
+    this->setOrder(order);
+  }
 
+  static inline bool classof(ELFStringTable<target_endianness, is64Bits> *s) {
+    return true;
+  }
+
+  static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
+    return c->kind() == Section<target_endianness, is64Bits>::K_StringTable;
+  }
+
+  uint64_t addString(const StringRef symname) {
+    _strings.push_back(symname);
+    uint64_t offset = this->_fsize;
+    this->_fsize += symname.size() + 1;
+    return offset;
+  }
+
+  void write(ELFWriter *writer, 
+             OwningPtr<FileOutputBuffer> &buffer) {
+    uint8_t *chunkBuffer = buffer->getBufferStart();
+    uint8_t *dest = chunkBuffer + this->fileOffset();
+    for (auto si : _strings) {
+      memcpy(dest, si.data(), si.size());
+      dest += si.size();
+      memcpy(dest, "", 1);
+      dest += 1;
+    }
+  }
+
+  void finalize() { }
+
 private:
-  std::vector<StringRef> _stringSection;
+  std::vector<StringRef> _strings;
 };
 
-/// \brief Represents the symtab section
-/// 
-/// ELFSymbolTableChunk represents the Symbol table as per ELF ABI
-/// This is a table with Elf[32/64]_Sym entries in it. 
+/// \brief The ELFSymbolTable class represents the symbol table in a ELF file 
 template<support::endianness target_endianness, bool is64Bits>
-class ELFSymbolTableChunk : public SectionChunk<target_endianness, is64Bits> {
+class ELFSymbolTable : public Section<target_endianness, is64Bits> {
+
 public:
   typedef object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
-  ELFSymbolTableChunk(const WriterOptionsELF &options,
-                      ELFWriter<target_endianness, is64Bits> &writer,
-                      StringRef secName);
-  virtual StringRef   segmentName() const { return this->_segmentName; }
-  void                addSymbol(const Atom *a, uint16_t shndx);
-  void                addSymbol(Elf_Sym *x); 
-  void                fixSymbolValue(); 
-  const char          *info();
-  void                setAttributes();
-  virtual void               write(uint8_t *fileBuffer);
 
+  ELFSymbolTable(const char *str,
+                 int32_t order)
+    : Section<target_endianness, is64Bits>(str
+    , llvm::ELF::SHT_SYMTAB
+    , 0
+    , order
+    , Section<target_endianness, is64Bits>::K_SymbolTable) {
+    this->setOrder(order);
+    Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
+    memset ((void *)symbol,0, sizeof(Elf_Sym));
+    _symbolTable.push_back(symbol);
+    this->_entSize = sizeof(Elf_Sym);
+    this->_fsize = sizeof(Elf_Sym);
+    this->_align2 = sizeof(void *);
+  }
+
+  static inline bool classof(ELFSymbolTable<target_endianness, is64Bits> *s) {
+    return true;
+  }
+
+  static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
+    return c->kind() == Section<target_endianness, is64Bits>::K_SymbolTable;
+  }
+
+  void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0) {
+    Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
+    unsigned char binding = 0, type = 0;
+    symbol->st_name = _stringSection->addString(atom->name());
+    symbol->st_size = 0;
+    symbol->st_shndx = sectionIndex;
+    symbol->st_value = 0;
+    symbol->st_other = ELF::STV_DEFAULT;
+    if (const DefinedAtom *da = llvm::dyn_cast<const DefinedAtom>(atom)){
+      symbol->st_size = da->size();
+      lld::DefinedAtom::ContentType ct;
+      switch (ct = da->contentType()){
+      case  DefinedAtom::typeCode:
+        symbol->st_value = addr;
+        type = ELF::STT_FUNC;
+        break;
+      case  DefinedAtom::typeData:
+        symbol->st_value = addr;
+        type = ELF::STT_OBJECT;
+        break;
+      case  DefinedAtom::typeZeroFill:
+        type = ELF::STT_COMMON;
+        symbol->st_value = addr;
+        break;
+      default:
+        type = ELF::STT_NOTYPE;
+      }
+      if (da->scope() == DefinedAtom::scopeTranslationUnit)  
+        binding = ELF::STB_LOCAL;
+      else
+        binding = ELF::STB_GLOBAL;
+    } else if (const AbsoluteAtom *aa = llvm::dyn_cast<const AbsoluteAtom>(atom)){
+      type = ELF::STT_OBJECT;
+      symbol->st_shndx = ELF::SHN_ABS;
+      switch (aa->scope()) {
+      case AbsoluteAtom::scopeLinkageUnit:
+        symbol->st_other = ELF::STV_HIDDEN;
+        binding = ELF::STB_LOCAL;
+        break;
+      case AbsoluteAtom::scopeTranslationUnit:
+        binding = ELF::STB_LOCAL;
+        break;
+      case AbsoluteAtom::scopeGlobal:
+        binding = ELF::STB_GLOBAL;
+        break;
+      }
+      symbol->st_value = aa->value();
+    } 
+    else {
+     symbol->st_value = 0;
+     type = ELF::STT_NOTYPE;
+     binding = ELF::STB_WEAK;
+    }
+    symbol->setBindingAndType(binding, type);
+    _symbolTable.push_back(symbol);
+    this->_fsize += sizeof(Elf_Sym);
+  }
+
+  void setStringSection(ELFStringTable<target_endianness, is64Bits> *s) {
+    _stringSection = s;
+  }
+
+  void finalize() {
+    // sh_info should be one greater than last symbol with STB_LOCAL binding
+    // we sort the symbol table to keep all local symbols at the beginning
+    std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
+    [](const Elf_Sym *A, const Elf_Sym *B) {
+       return A->getBinding() < B->getBinding();
+    }); 
+    uint16_t shInfo = 0;
+    for (auto i : _symbolTable) {
+      if (i->getBinding() != ELF::STB_LOCAL)
+        break;
+      shInfo++;
+    }
+    this->_shInfo = shInfo;
+    this->setLink(_stringSection->ordinal());
+  }
+
+  void write(ELFWriter *writer, 
+             OwningPtr<FileOutputBuffer> &buffer) {
+
+    uint8_t *chunkBuffer = buffer->getBufferStart();
+    uint8_t *dest = chunkBuffer + this->fileOffset();
+    for (auto sti : _symbolTable) {
+      memcpy(dest, sti, sizeof(Elf_Sym));
+      dest += sizeof(Elf_Sym);
+    }
+  }
+
 private:
+  ELFStringTable<target_endianness, is64Bits> *_stringSection;
   std::vector<Elf_Sym*> _symbolTable;
-  ELFStringSectionChunk<target_endianness, is64Bits> *_stringSection;
   llvm::BumpPtrAllocator _symbolAllocate;
-  std::map<Elf_Sym*, const Atom*> _symbolToAtom;
+  int64_t _link;
 };
 
-/// \brief  ELFProgramHeaderChunk represents the Elf[32/64]_Phdr structure near
-/// the start of an ELF executable file. ELFHeader's e_phentsize and e_phnum 
-/// show the number of entries in table and size of each one.
+/// \brief An ELFHeader represents the Elf[32/64]_Ehdr structure at the
+///        start of an ELF executable file.
 template<support::endianness target_endianness, bool is64Bits>
-class ELFProgramHeaderChunk : public Chunk<target_endianness, is64Bits> {
+class ELFHeader : public Chunk<target_endianness, is64Bits> {
 public:
-  LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
-  typedef object::Elf_Phdr<target_endianness, is64Bits> Elf_Phdr;
-  ELFProgramHeaderChunk(const WriterOptionsELF &options, 
-                        ELFWriter<target_endianness, is64Bits> &);
+  typedef object::Elf_Ehdr_Impl<target_endianness, is64Bits> Elf_Ehdr;
 
-  virtual StringRef   segmentName() const;
-  virtual void        write(uint8_t *filebuffer);
-  virtual const char *info();
-  void                createPHeaders();
-  uint64_t            computeNumber();
+  ELFHeader()
+  : Chunk<target_endianness, is64Bits>("elfhdr"
+  , Chunk<target_endianness, is64Bits>::K_ELFHeader) {
+    memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
+    e_ident(ELF::EI_MAG0, 0x7f);
+    e_ident(ELF::EI_MAG1, 'E');
+    e_ident(ELF::EI_MAG2, 'L');
+    e_ident(ELF::EI_MAG3, 'F');
+    e_ehsize(sizeof(Elf_Ehdr));
+    e_flags(2);
+  }
+  void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
+  void e_type(uint16_t type)           { _eh.e_type = type; }
+  void e_machine(uint16_t machine)     { _eh.e_machine = machine; }
+  void e_version(uint32_t version)     { _eh.e_version = version; }
+  void e_entry(int64_t entry)         { _eh.e_entry = entry; }
+  void e_phoff(int64_t phoff)         { _eh.e_phoff = phoff; }
+  void e_shoff(int64_t shoff)         { _eh.e_shoff = shoff; }
+  void e_flags(uint32_t flags)         { _eh.e_flags = flags; }
+  void e_ehsize(uint16_t ehsize)       { _eh.e_ehsize = ehsize; }
+  void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
+  void e_phnum(uint16_t phnum)         { _eh.e_phnum = phnum; }
+  void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
+  void e_shnum(uint16_t shnum)         { _eh.e_shnum = shnum; }
+  void e_shstrndx(uint16_t shstrndx)   { _eh.e_shstrndx = shstrndx; }
+  uint64_t  fileSize()                 { return sizeof (Elf_Ehdr); }
+
   static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
-    return c->getChunkKind() ==  Chunk<target_endianness, is64Bits>::Kind
-                                                                   ::Header;
+    return c->Kind() ==  Chunk<target_endianness, is64Bits>::K_ELFHeader;
   }
 
-private:
-  typedef typename std::vector<SectionChunk<target_endianness, is64Bits>*>
-                    ::iterator secIterator;
-  const WriterOptionsELF                 &_options;
-  ELFWriter<target_endianness, is64Bits> &_writer;
-  std::vector<Elf_Phdr*>                 _programHeaders;
-  llvm::BumpPtrAllocator                 _headerAllocate;
-  typedef std::pair<uint64_t, uint64_t>  sectionRange; 
-  std::vector<sectionRange>              _segments;
-  std::map<uint16_t, uint16_t>           _groupToPF;
+  void write(ELFWriter *writer, 
+             OwningPtr<FileOutputBuffer> &buffer) {
 
-};
+    uint8_t *chunkBuffer = buffer->getBufferStart();
+    uint8_t *atomContent = chunkBuffer + this->fileOffset();
+    memcpy(atomContent, &_eh, fileSize());
+  }
 
-//===----------------------------------------------------------------------===//
-//  Chunk
-//===----------------------------------------------------------------------===//
+  void finalize() { }
 
-template<support::endianness target_endianness, bool is64Bits>
-Chunk<target_endianness, is64Bits>::Chunk(){
-  this->init();
-}
+private:
+  Elf_Ehdr _eh;
+};
 
+/// \brief An ELFProgramHeader represents the Elf[32/64]_Phdr structure at the
+///        start of an ELF executable file.
 template<support::endianness target_endianness, bool is64Bits>
-void Chunk<target_endianness, is64Bits>::init(){
-  this->_size = 0; 
-  this->_address = 0; 
-  this->_fileOffset = 0; 
-  this->_align2 = 0; 
-  this->_group = CG_INVALID; 
-  this->_isLoadable = false;
-   // 0 and 1 are reserved. 0 for ELF header and 1 for program  header.
-  static uint64_t orderNumber = 0;
-  _ordinal = orderNumber++;
-}
+class ELFProgramHeader : public Chunk<target_endianness, is64Bits> {
+public:
+  typedef object::Elf_Phdr<target_endianness, is64Bits> Elf_Phdr;
 
-template<support::endianness target_endianness, bool is64Bits>
-bool Chunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
-  return false;
-}
+  ELFProgramHeader()
+  : Chunk<target_endianness, is64Bits>("elfphdr"
+  , Chunk<target_endianness, is64Bits>::K_ELFProgramHeader) { }
 
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::size() const {
-  return _size;
-}
+  bool addSegment(Segment<target_endianness, is64Bits> *segment) {
+    Elf_Phdr *phdr = nullptr;
+    bool ret = false;
 
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::align2() const {
-  return _align2;
-}
+    for (auto sei = segment->slices_begin(), see = segment->slices_end(); 
+                                             sei != see; ++sei) {
+      if (_phi == _ph.end()) {
+        phdr = new(_allocator.Allocate<Elf_Phdr>()) Elf_Phdr;
+        _ph.push_back(phdr);
+        _phi = _ph.end();
+        ret = true;
+      } else {
+        phdr = (*_phi);
+        ++_phi;
+      }
+      phdr->p_type = segment->segmentType();
+      phdr->p_offset = (*sei)->fileOffset();
+      phdr->p_vaddr = (*sei)->virtualAddr();
+      phdr->p_paddr = (*sei)->virtualAddr();
+      phdr->p_filesz = (*sei)->fileSize();
+      phdr->p_memsz = (*sei)->memSize();
+      phdr->p_flags = segment->flags();
+      phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ? 
+                       segment->pageSize() : (*sei)->align2();
+    }
+    return ret;
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::address() const {
-  return _address;
-}
+  void resetProgramHeaders() {
+    _phi = _ph.begin();    
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::fileOffset() const {
-  return _fileOffset;
-}
+  void setVAddr(uint64_t addr) {
+    this->_start = llvm::RoundUpToAlignment(addr, 8);
+    this->_fsize = this->_start - addr;
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::
-         alignTo(uint64_t value, uint8_t align2) {
-  uint64_t align = 1 << align2;
-  return (value + (align - 1)) & (-align);
-}
+  uint64_t  fileSize() { return this->_fsize + (sizeof (Elf_Phdr) * _ph.size()); }
 
-template<support::endianness target_endianness, bool is64Bits>
-void Chunk<target_endianness, is64Bits>::
-     assignFileOffset(uint64_t &curOffset, uint64_t &curAddress) {
-  if (occupiesNoDiskSpace()) {
-    // FileOffset does not change, but virtual address does change.
-    uint64_t alignedAddress =
-      alignTo(curAddress, _align2 ? static_cast<uint8_t>(llvm::Log2_64(_align2))
-                                  : 0);
-    _address = alignedAddress;
-    curAddress = alignedAddress + _size;
-  } else {
-    // FileOffset and address both move by _size amount after alignment.
-    uint64_t alignPadding =
-      alignTo(curAddress, _align2 ? static_cast<uint8_t>(llvm::Log2_64(_align2))
-                                  : 0) - curAddress;
-    _fileOffset = curOffset + alignPadding;
-    _address    = curAddress + alignPadding;
-    curOffset   = _fileOffset + _size;
-    curAddress  = _address + _size;
+  static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
+    return c->Kind() ==  Chunk<target_endianness, is64Bits>::K_ELFProgramHeader;
   }
 
-  DEBUG_WITH_TYPE("WriterELF-layout", dbgs()  
-                      << "   fileOffset="
-                      << format("0x%08X", _fileOffset)
-                      << " address="
-                      << format("0x%016X", _address)
-                      << " info=" << info() << "\n");
-}
+  void write(ELFWriter *writer, 
+             OwningPtr<FileOutputBuffer> &buffer) {
 
-//===----------------------------------------------------------------------===//
-//  SectionChunk
-//===----------------------------------------------------------------------===//
+    uint8_t *chunkBuffer = buffer->getBufferStart();
+    uint8_t *dest = chunkBuffer + this->fileOffset();
+    for (auto phi : _ph) {
+      memcpy(dest, phi, sizeof(Elf_Phdr));
+      dest += sizeof(Elf_Phdr);
+    }
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-SectionChunk<target_endianness, is64Bits>::
- SectionChunk(StringRef secName, StringRef segName, bool loadable, 
-              uint64_t flags , uint64_t link,  uint64_t info , uint64_t type,
-              uint64_t entsz, const WriterOptionsELF &op, 
-              ELFWriter<target_endianness, is64Bits> &writer)
-  : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
-                                       ::Kind::Section)
-  , _link(link)
-  , _shinfo(info)
-  , _entsize(entsz)
-  , _segmentName(segName)
-  , _sectionName(secName)
-  , _options(op)
-  , _writer(writer)
-  , _flags(flags)
-  , _type(type)
-  , _offsetInStringTable(0) {
-    this->isLoadable(loadable);
-}
-//FIXME: We need to make decision here for every section created
-template<support::endianness target_endianness, bool is64Bits>
-bool SectionChunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
-  return false;
-}
+  void finalize() { }
 
-template<support::endianness target_endianness, bool is64Bits>
-const char *SectionChunk<target_endianness, is64Bits>::info() {
-  return _sectionName.data();
-}
+  int64_t entsize() { 
+    return sizeof(Elf_Phdr);
+  }
 
-//===----------------------------------------------------------------------===//
-//  StockSectionChunk
-//===----------------------------------------------------------------------===//
+  int64_t numHeaders() {
+    return _ph.size();
+  }
 
+private:
+  std::vector<Elf_Phdr *> _ph;
+  typedef typename std::vector<Elf_Phdr *>::iterator ph_iter;
+  ph_iter _phi;
+  llvm::BumpPtrAllocator  _allocator;
+};
+
+/// \brief An ELFSectionHeader represents the Elf[32/64]_Shdr structure
+/// at the end of the file
 template<support::endianness target_endianness, bool is64Bits>
-StockSectionChunk<target_endianness, is64Bits>::
-  StockSectionChunk(StringRef secName, bool loadable, 
-                    DefinedAtom::ContentType type,
-                    const WriterOptionsELF &options, 
-                    ELFWriter<target_endianness, is64Bits> &writer)
- : SectionChunk<target_endianness, is64Bits>(secName, "PT_NULL", 
-                                             loadable, 0lu, 0lu, 0u, 0lu, 0lu,
-                                             options, writer) {
-  this->_segmentName = this->_isLoadable ? "PT_LOAD" : "PT_NULL" ;
-  // If the section is custom loadable section, group should be set explicitly.
-  // Stock non loadable section go as NO_LOAD and others  will get their 
-  // group determined by the atoms contained within. Many constant 
-  // sections will have no symbols but the constants are referred as 
-  // offset from start symbol, hence there may not be any defined atoms being 
-  // appended to them, we force them  at time of creation to CG_R
-  this->setGroup(this->isLoadable() ? CG_INVALID : CG_NO_LOAD);
-  switch(type) {
-  case DefinedAtom::typeCode:
-    this->_type        = ELF::SHT_PROGBITS;
-    break;
-  case DefinedAtom::typeData:
-    this->_type        = ELF::SHT_PROGBITS;
-    break;
-  case DefinedAtom::typeZeroFill:
-    this->_type        = ELF::SHT_NOBITS;
-    break;
-  case DefinedAtom::typeConstant:
-    this->_type        = ELF::SHT_PROGBITS;
-    this->_flags       = ELF::SHF_ALLOC;
-    this->setGroup(CG_R);
-    break;
-  default:
-    llvm_unreachable("Unhandled content type for section!");
+class ELFSectionHeader : public Chunk<target_endianness, is64Bits> {
+public:
+  typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
+
+  ELFSectionHeader(int32_t order):Chunk<target_endianness, is64Bits>("shdr",
+                                 Chunk<target_endianness, is64Bits>::K_ELFSectionHeader)
+  {
+    this->_fsize = 0;
+    this->_align2 = 8;
+    this->setOrder(order);
+    // The first element in the list is always NULL
+    Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
+    ::memset(nullshdr, 0, sizeof (Elf_Shdr));
+    _sectionInfo.push_back(nullshdr);
+    this->_fsize += sizeof (Elf_Shdr);
   }
-}
- 
 
-template<support::endianness target_endianness, bool is64Bits>
-const ArrayRef<AtomInfo> StockSectionChunk<target_endianness, is64Bits>::
-    atoms() const {
-  return _atoms;
-}
+  uint16_t fileSize() { 
+    return sizeof(Elf_Shdr) * _sectionInfo.size();
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-void StockSectionChunk<target_endianness, is64Bits>::
-     appendAtom(const DefinedAtom *atom) {
-  static uint16_t groupArray[] = {CG_INVALID, CG_W, CG_R, CG_RW, CG_X,
-                                  CG_WX, CG_RX, CG_RWX};
-  // Figure out offset for atom in this section given alignment constraints.
-  uint64_t offset = this->_size;
-  DefinedAtom::Alignment atomAlign = atom->alignment();
-  uint64_t align2 = 1 << atomAlign.powerOf2;
-  uint64_t requiredModulus = atomAlign.modulus;
-  uint64_t currentModulus = (offset % align2);
-  if (currentModulus != requiredModulus) {
-    if (requiredModulus > currentModulus)
-      offset += requiredModulus - currentModulus;
-    else
-      offset += align2 + requiredModulus - currentModulus;
+  void appendSection(MergedSections<target_endianness, is64Bits> *section) { 
+    Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
+    shdr->sh_name   = _stringSection->addString(section->name());
+    shdr->sh_type   = section->type();
+    shdr->sh_flags  = section->flags();
+    shdr->sh_offset = section->fileOffset();
+    shdr->sh_addr   = section->virtualAddr();
+    shdr->sh_size   = section->memSize();
+    shdr->sh_link   = section->link();
+    shdr->sh_info   = section->shinfo();
+    shdr->sh_addralign = section->align2();
+    shdr->sh_entsize = section->entsize();
+    _sectionInfo.push_back(shdr);
   }
-  // Record max alignment of any atom in this section.
-  if (align2 > this->_align2)
-    this->_align2 = align2;
-  // Assign atom to this section with this offset.
-  _atoms.emplace_back(atom, offset);
-  // Update section size to include this atom.
-  this->_size = offset + atom->size();
-  // Update permissions
-  DefinedAtom::ContentPermissions perms = atom->permissions();
- 
-  if ((perms & DefinedAtom::permR__) == DefinedAtom::permR__)
-    this->_flags |= ELF::SHF_ALLOC;
-  if ((perms & DefinedAtom::permRW_) == DefinedAtom::permRW_)
-    this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
-  if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
-    this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
-  if (atom->contentType() == DefinedAtom::typeZeroFill)
-    this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
-  this->setGroup(groupArray[this->_flags]);
-}
 
-template<support::endianness target_endianness, bool is64Bits>
-void StockSectionChunk<target_endianness, is64Bits>
-                      ::write(uint8_t *chunkBuffer) {
-  // Each section's content is just its atoms' content.
-  for (const auto &ai : _atoms ) {
-    // Copy raw content of atom to file buffer.
-   ArrayRef<uint8_t> content = std::get<0>(ai)->rawContent();
-   uint64_t contentSize = content.size();
-   if (contentSize == 0)
-     continue;
-   uint8_t *atomContent = chunkBuffer + std::get<1>(ai);
-   std::copy_n(content.data(), contentSize, atomContent);
+  void updateSection(Section<target_endianness, is64Bits> *section) {
+    Elf_Shdr *shdr = _sectionInfo[section->ordinal()];
+    shdr->sh_type   = section->type();
+    shdr->sh_flags  = section->flags();
+    shdr->sh_offset = section->fileOffset();
+    shdr->sh_addr   = section->virtualAddr();
+    shdr->sh_size   = section->fileSize();
+    shdr->sh_link   = section->link();
+    shdr->sh_info   = section->shinfo();
+    shdr->sh_addralign = section->align2();
+    shdr->sh_entsize = section->entsize();
+  }
 
-  for (const Reference *ref : *std::get<0>(ai)){
-    uint32_t offset = ref->offsetInAtom();
-    uint64_t targetAddress = 0;
+  static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
+    return c->getChunkKind() ==  Chunk<target_endianness, is64Bits>::K_ELFSectionHeader;
+  }
 
-    if ( ref->target() != nullptr )
-      targetAddress = this->_writer.addressOfAtom(ref->target());
+  void setStringSection(ELFStringTable<target_endianness, is64Bits> *s) {
+    _stringSection = s;
+  }
 
-    uint64_t fixupAddress = this->_writer.addressOfAtom(std::get<0>(ai)) +
-                            offset;
-    this->_writer.kindHandler()->applyFixup(ref->kind(), ref->addend(),
-                                            &atomContent[offset],
-                                            fixupAddress,
-                                            targetAddress);
+  void write(ELFWriter *writer, 
+             OwningPtr<FileOutputBuffer> &buffer) {
+
+    uint8_t *chunkBuffer = buffer->getBufferStart();
+    uint8_t *dest = chunkBuffer + this->fileOffset();
+    for (auto shi : _sectionInfo) {
+      memcpy(dest, shi, sizeof(Elf_Shdr));
+      dest += sizeof(Elf_Shdr);
     }
+    _stringSection->write(writer, buffer);
   }
-}
 
-//===----------------------------------------------------------------------===//
-//  ELFStringSectionChunk
-//===----------------------------------------------------------------------===//
-template<support::endianness target_endianness, bool is64Bits>
-ELFStringSectionChunk<target_endianness, is64Bits>::
-    ELFStringSectionChunk(const WriterOptionsELF &options,
-                          ELFWriter<target_endianness, is64Bits> &writer, 
-                          StringRef secName) 
-  : SectionChunk<target_endianness, is64Bits>(secName, "PT_NULL", 
-                                              false, 0lu, 0lu, 0lu, 
-                                              ELF::SHT_STRTAB, 0lu, options, 
-                                              writer) {
-  // First Add a null character. It also occupies 1 byte
-  _stringSection.emplace_back("");
-  this->_size = 1;
-  this->setGroup(CG_NO_LOAD);
-}
+  void finalize() { }
 
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t ELFStringSectionChunk<target_endianness, is64Bits>::
-         addString(StringRef symName) {
-  _stringSection.emplace_back(symName);
-  uint64_t offset = this->_size;
-  this->_size += symName.size() + 1;
+  int64_t entsize() { 
+    return sizeof(Elf_Shdr);
+  }
 
-  return offset;
-}
-
-// We need to unwrap the _stringSection and then make one large memory 
-// chunk of null terminated strings
-template<support::endianness target_endianness, bool is64Bits>
-void ELFStringSectionChunk<target_endianness, is64Bits>::
-     write(uint8_t *chunkBuffer) {
-  uint64_t chunkOffset = 0;
- 
-  for (auto it : _stringSection) {
-    ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size());
-    chunkOffset += it.size();
-    ::memcpy(chunkBuffer + chunkOffset, "", 1);
-    chunkOffset += 1;
+  int64_t numHeaders() {
+    return _sectionInfo.size();
   }
-}
 
+private:
+  ELFStringTable<target_endianness, is64Bits> *_stringSection;
+  std::vector<Elf_Shdr*>                  _sectionInfo;
+  llvm::BumpPtrAllocator                  _sectionAllocate;
+};
+
+
+/// \brief The DefaultELFLayout class is used by the Writer to arrange 
+///        sections and segments in the order determined by the target ELF 
+///        format. The writer creates a single instance of the DefaultELFLayout
+///        class 
 template<support::endianness target_endianness, bool is64Bits>
-const char *ELFStringSectionChunk<target_endianness, is64Bits>::info() {
-  return "String Table";
-}
+class DefaultELFLayout : public ELFLayout {
+public:
 
-//===----------------------------------------------------------------------===//
-//  ELFSymbolTableChunk
-//===----------------------------------------------------------------------===//
-template< support::endianness target_endianness, bool is64Bits>
-ELFSymbolTableChunk<target_endianness, is64Bits>::ELFSymbolTableChunk
-                    (const WriterOptionsELF &options, 
-                     ELFWriter<target_endianness, is64Bits> &writer, 
-                     StringRef secName)
-  : SectionChunk<target_endianness, is64Bits>(secName, StringRef("PT_NULL"), 
-                                              false, 0, 0, 0, ELF::SHT_SYMTAB,
-                                              sizeof(Elf_Sym), options, writer)
-{
-  _stringSection = this->_writer.strtab();
-  Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
-  memset ((void *)symbol,0, sizeof(Elf_Sym));
-  _symbolTable.push_back(symbol);
-  this->_link = 0;
-  this->_entsize = sizeof(Elf_Sym);
-  this->_size = sizeof(Elf_Sym);
-  this->_align2 = this->_options.pointerWidth();
-  this->setGroup(CG_NO_LOAD);
-}
+  // The order in which the sections appear in the output file
+  // If its determined, that the layout needs to change 
+  // just changing the order of enumerations would essentially 
+  // change the layout in the output file
+  enum DefaultSectionOrder {
+    ORDER_NOT_DEFINED = 0,
+    ORDER_INTERP,
+    ORDER_NOTE,
+    ORDER_HASH,
+    ORDER_DYNAMIC_SYMBOLS,
+    ORDER_DYNAMIC_STRINGS,
+    ORDER_INIT,
+    ORDER_TEXT,
+    ORDER_PLT,
+    ORDER_FINI,
+    ORDER_RODATA,
+    ORDER_EH_FRAME,
+    ORDER_EH_FRAMEHDR,
+    ORDER_CTORS,
+    ORDER_DTORS,
+    ORDER_DYNAMIC,
+    ORDER_GOT,
+    ORDER_GOT_PLT,
+    ORDER_DATA,
+    ORDER_BSS,
+    ORDER_OTHER,
+    ORDER_SECTION_STRINGS,
+    ORDER_SYMBOL_TABLE,
+    ORDER_STRING_TABLE,
+    ORDER_SECTION_HEADERS
+  };
 
-template< support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>::fixSymbolValue(){
-  for (auto sym : _symbolTable) {
-    if ( sym->st_shndx != ELF::SHN_ABS) {
-      sym->st_value = this->_writer.addressOfAtom(_symbolToAtom[sym]);
-    }
-  }
-}
+public:
 
-template< support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>::addSymbol(Elf_Sym *sym){
-   _symbolTable.push_back(sym);
-   this->_size+= sizeof(Elf_Sym) ;
-}
+  // The Key used for creating Sections
+  // The sections are created using 
+  // SectionName, [contentType, contentPermissions]
+  typedef std::pair<StringRef, 
+                    std::pair<int32_t, int32_t>> Key;
+  typedef typename std::vector<Chunk<target_endianness, is64Bits> *>::iterator 
+                                                                     ChunkIter;
+  // The key used for Segments
+  // The segments are created using 
+  // SegmentName, Segment flags
+  typedef std::pair<StringRef, int64_t> SegmentKey;
+  // Merged Sections contain the map of Sectionnames to a vector of sections,
+  // that have been merged to form a single section
+  typedef std::map<StringRef, MergedSections<target_endianness, is64Bits> *> 
+                                                            MergedSectionMapT;
+  typedef typename std::vector
+   <MergedSections<target_endianness, is64Bits> *>::iterator MergedSectionIter;
 
-/// \brief Add symbols to symbol table
-/// We examine each property of atom to infer the various st_* fields in Elf*_Sym
-template< support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>
-                  ::addSymbol(const Atom *a, uint16_t shndx) {
- Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
- unsigned char b = 0, t = 0;
- symbol->st_name = _stringSection->addString(a->name());
- _symbolToAtom[symbol] = a;
-// In relocatable files, st_value holds a section offset for a defined symbol.
-// st_value is an offset from the beginning of the section that st_shndx
-// identifies. After we assign file offsets we can set this value correctly.
- symbol->st_size = 0;
- symbol->st_shndx = shndx;
- symbol->st_value = 0;
-// FIXME: Need to change and account all STV* when visibilities are supported
- symbol->st_other = ELF::STV_DEFAULT;
- if (const DefinedAtom *da = llvm::dyn_cast<const DefinedAtom>(a)){
-    symbol->st_size = da->size();
-    lld::DefinedAtom::ContentType ct;
-    switch (ct = da->contentType()){
-    case  DefinedAtom::typeCode:
-      t = ELF::STT_FUNC;
-      break;
-    case  DefinedAtom::typeData:
-      t = ELF::STT_OBJECT;
-      break;
-    case  DefinedAtom::typeZeroFill:
-   // In relocatable files, st_value holds alignment constraints for a symbol whose 
-   // section index is SHN_COMMON
-      if (this->_options.type() == ELF::ET_REL){
-        t = ELF::STT_COMMON;
-        symbol->st_value = 1 << (da->alignment()).powerOf2;
-        symbol->st_shndx = ELF::SHN_COMMON;
-      }
-      break;
-   // TODO:: How to find STT_FILE symbols?
-    default:
-      t = ELF::STT_NOTYPE;
+  // HashKey for the Section
+  class HashKey {
+  public:
+    int64_t operator() (const Key &k) const {
+      // k.first = section Name
+      // k.second = [contentType, Permissions]
+      return llvm::hash_combine(k.first, k.second.first, k.second.second);
     }
- 
-    if (da->scope() == DefinedAtom::scopeTranslationUnit)  
-      b = ELF::STB_LOCAL;
-    else if (da->merge() == DefinedAtom::mergeAsWeak)
-      b = ELF::STB_WEAK;
-    else
-      b = ELF::STB_GLOBAL;
-  } else if (const AbsoluteAtom *aa = llvm::dyn_cast<const AbsoluteAtom>(a)){
-//FIXME: Absolute atoms need more properties to differentiate each other
-// based on binding and type of symbol
-    t = ELF::STT_OBJECT;
+  };
 
-    switch (aa->scope()) {
-    case AbsoluteAtom::scopeLinkageUnit:
-      symbol->st_other = ELF::STV_HIDDEN;
-      b = ELF::STB_LOCAL;
-      break;
-    case AbsoluteAtom::scopeTranslationUnit:
-      b = ELF::STB_LOCAL;
-      break;
-    case AbsoluteAtom::scopeGlobal:
-      b = ELF::STB_GLOBAL;
-      break;
+  // HashKey for the Segment
+  class SegmentHashKey {
+  public:
+    int64_t operator() (const SegmentKey &k) const {
+      // k.first = SegmentName
+      // k.second = SegmentFlags
+      return llvm::hash_combine(k.first, k.second);
     }
-    symbol->st_value = aa->value();
- } else {
-   symbol->st_value = 0;
-   t = ELF::STT_NOTYPE;
-   b = ELF::STB_LOCAL;
- }
- symbol->setBindingAndType(b, t);
+  };
 
- _symbolTable.push_back(symbol);
- this->_size += sizeof(Elf_Sym);
-}
+  typedef std::unordered_map<Key, 
+          Section<target_endianness, is64Bits>*, HashKey> SectionMapT;
+  typedef std::unordered_map<SegmentKey,
+                             Segment<target_endianness, is64Bits>*, 
+                             SegmentHashKey> SegmentMapT;
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>::setAttributes() {
-// sh_info should be one greater than last symbol with STB_LOCAL binding
-// we sort the symbol table to keep all local symbols at the beginning
- std::stable_sort(_symbolTable.begin(), _symbolTable.end(), ([]
-                  (const Elf_Sym *A, const Elf_Sym *B) -> bool {
-                   return (A->getBinding() < B->getBinding());}));
-  uint16_t shInfo = 0;
-  for (auto i : _symbolTable) {
-    if (i->getBinding() != ELF::STB_LOCAL)
-      break;
-    shInfo++;
-  }
-  this->_shinfo = shInfo;
-// we set the associated string table index in th sh_link member
-  this->_link = this->_writer.strtab()->ordinal() - 1;
-  this->_align2 = this->_options.pointerWidth();
-}
+  DefaultELFLayout(const WriterOptionsELF &options):_options(options) { }
 
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFSymbolTableChunk<target_endianness, is64Bits>::info() {
-  return "Symbol Table";
-}
+  /// \brief Return the section order for a input section
+  virtual SectionOrder getSectionOrder
+              (const StringRef name,
+              int32_t contentType,
+              int32_t contentPermissions) {
+    switch (contentType) {
+    case DefinedAtom::typeCode:
+      return llvm::StringSwitch<Reference::Kind>(name)
+        .StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
+        .StartsWith(".eh_frame", ORDER_EH_FRAME)
+        .StartsWith(".init", ORDER_INIT)
+        .StartsWith(".fini", ORDER_FINI)
+        .StartsWith(".hash", ORDER_HASH)
+        .Default(ORDER_TEXT);
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>::
-     write(uint8_t *chunkBuffer) {
-  uint64_t chunkOffset = 0;
-  for (auto it : _symbolTable) {
-    ::memcpy(chunkBuffer + chunkOffset, it, this->_entsize);
-    chunkOffset += this->_entsize;
+    case DefinedAtom::typeConstant:
+      return ORDER_RODATA;        
+  
+    case DefinedAtom::typeData:
+      return ORDER_DATA;
+  
+    case DefinedAtom::typeZeroFill:
+      return ORDER_BSS;
+
+    default:
+      // If we get passed in a section push it to OTHER
+      if (contentPermissions == DefinedAtom::perm___) 
+        return ORDER_OTHER;
+    
+      return ORDER_NOT_DEFINED;
+    }
   }
-}
 
-//===----------------------------------------------------------------------===//
-//  ELFHeaderChunk
-//===----------------------------------------------------------------------===//
-template<support::endianness target_endianness, bool is64Bits>
-ELFHeaderChunk<target_endianness, is64Bits>
-              ::ELFHeaderChunk(const WriterOptionsELF &options,
-                               const File &File) 
-  : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
-                                       ::Kind::Header){
-  this->_size = size();
-  e_ident(ELF::EI_MAG0, 0x7f);
-  e_ident(ELF::EI_MAG1, 'E');
-  e_ident(ELF::EI_MAG2, 'L');
-  e_ident(ELF::EI_MAG3, 'F');
-  e_ident(ELF::EI_CLASS, (options.is64Bit() ? ELF::ELFCLASS64
-                                            : ELF::ELFCLASS32));
-  e_ident(ELF::EI_DATA, (options.endianness() == llvm::support::big)
-                         ? ELF::ELFDATA2MSB
-                         : ELF::ELFDATA2LSB);
-  e_ident(ELF::EI_VERSION, 1);
-  e_ident(ELF::EI_OSABI, ELF::ELFOSABI_NONE);
+  /// \brief This maps the input sections to the output section names
+  StringRef getSectionName(const StringRef name,
+                           const int32_t contentType) {
+    if (contentType == DefinedAtom::typeZeroFill) 
+      return ".bss";
+    if (name.startswith(".text")) 
+      return ".text";
+    if (name.startswith(".rodata")) 
+      return ".rodata";
+    return name;
+  }
 
-  e_type(options.type());
-  e_machine(options.machine());
-  e_version(1);
+  /// \brief Gets the segment for a output section
+  virtual ELFLayout::SegmentType getSegmentType(Section<target_endianness, 
+                                     is64Bits> *section) const {
+    switch(section->order()) {
+    case ORDER_INTERP:
+      return llvm::ELF::PT_INTERP;
 
-  e_entry(0ULL);
-  e_phoff(0);
-  e_shoff(0ULL);
-  
-  e_flags(2);
-  e_ehsize(this->_size);
-  e_phentsize(0);
-  e_phnum(0);
-  e_shentsize(0);
-  e_shnum(0);
-  e_shstrndx(0);
-  this->setGroup(CG_HEADER);
-}
+    case ORDER_TEXT:
+    case ORDER_HASH:
+    case ORDER_DYNAMIC_SYMBOLS:
+    case ORDER_DYNAMIC_STRINGS:
+    case ORDER_INIT:
+    case ORDER_PLT:
+    case ORDER_FINI:
+    case ORDER_RODATA:
+    case ORDER_EH_FRAME:
+    case ORDER_EH_FRAMEHDR:
+      return llvm::ELF::PT_LOAD;
 
-template<support::endianness target_endianness, bool is64Bits>
-StringRef ELFHeaderChunk<target_endianness, is64Bits>
-                        ::segmentName() const {
-  return "ELF";
-}
+    case ORDER_NOTE:
+      return llvm::ELF::PT_NOTE;
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFHeaderChunk<target_endianness, is64Bits>
-                   ::write(uint8_t *chunkBuffer) {
-  ::memcpy(chunkBuffer, &_eh, size());
-}
+    case ORDER_DYNAMIC:
+      return llvm::ELF::PT_DYNAMIC;
 
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFHeaderChunk<target_endianness, is64Bits>::info() {
-  return "elf_header";
-}
+    case ORDER_CTORS:
+    case ORDER_DTORS:
+    case ORDER_GOT:
+      return llvm::ELF::PT_GNU_RELRO;
 
-//===----------------------------------------------------------------------===//
-//  ELFSectionHeaderChunk
-//  List of Section Headers:
-//[Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
-//[ 0]                   NULL            00000000 000000 000000 00      0   0  0
-//[ 1] .text             PROGBITS        00000000 000034 000040 00  AX  0   0  4
-//===----------------------------------------------------------------------===//
-template<support::endianness target_endianness, bool is64Bits>
-ELFSectionHeaderChunk<target_endianness, is64Bits>
-                     ::ELFSectionHeaderChunk(const WriterOptionsELF& options,
-                                             ELFWriter<target_endianness, 
-                                                       is64Bits> &writer) 
-  : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
-                                       ::Kind::Header)
-  , _options(options)
-  , _writer(writer) {
-  this->_size = 0;
-  this->_align2 = 0;
-  // The first element in the list is always NULL
-  Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
-  ::memset(nullshdr, 0, sizeof (Elf_Shdr));
-  _sectionInfo.push_back(nullshdr);
-  this->_size += sizeof (Elf_Shdr);
-  this->setGroup(CG_FILE_END);
+    case ORDER_GOT_PLT:
+    case ORDER_DATA:
+    case ORDER_BSS:
+      return llvm::ELF::PT_LOAD;
+
+    default:
+      return llvm::ELF::PT_NULL;
+    }
   }
 
+  /// \brief Returns true/false depending on whether the section has a Output
+  //         segment or not
+  static bool hasOutputSegment(Section<target_endianness, 
+                                 is64Bits> *section) {
+    switch(section->order()) {
+    case ORDER_INTERP:
+    case ORDER_HASH:
+    case ORDER_DYNAMIC_SYMBOLS:
+    case ORDER_DYNAMIC_STRINGS:
+    case ORDER_INIT:
+    case ORDER_PLT:
+    case ORDER_TEXT:
+    case ORDER_FINI:
+    case ORDER_RODATA:
+    case ORDER_EH_FRAME:
+    case ORDER_EH_FRAMEHDR:
+    case ORDER_NOTE:
+    case ORDER_DYNAMIC:
+    case ORDER_CTORS:
+    case ORDER_DTORS:
+    case ORDER_GOT:
+    case ORDER_GOT_PLT:
+    case ORDER_DATA:
+    case ORDER_BSS:
+      return true;
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSectionHeaderChunk<target_endianness, is64Bits>::computeSize(){
-  this->_size = (this->_writer.sectionChunks().size() + 1) * sizeof(Elf_Shdr);
-}
+    default:
+      return false;
+    }
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSectionHeaderChunk<target_endianness, is64Bits>::fixOffsets(){
-  auto it = _sectionInfo.begin();
-  auto sections =  _writer.sectionChunks();
-  // First section is a NULL section with no sh_offset fix
-  (*it)->sh_offset = 0;
-  (*it)->sh_addr = 0;
-  ++it;
-  for (auto &chunk : sections){
-    (*it)->sh_offset = chunk->fileOffset();
-    (*it)->sh_addr = chunk->address();
-    ++it;
+  // 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, is64Bits> *> 
+                                                currentSection(key, nullptr);
+    std::pair<typename SectionMapT::iterator, bool> 
+                              sectionInsert(_sectionMap.insert(currentSection));
+    Section<target_endianness, 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, is64Bits>>())
+                     Section<target_endianness, is64Bits>
+                     (sectionName, contentType, 
+                      permissions, section_order);
+      sectionInsert.first->second = section;
+      section->setOrder(section_order);
+      _sections.push_back(section);
+    }
+    section->appendAtom(atom);
+    return error_code::success();
   }
-}
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSectionHeaderChunk<target_endianness, is64Bits>::createHeaders(){
-  ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
+  // Merge sections with the same name into a MergedSections
+  void mergeSimiliarSections() {
+    MergedSections<target_endianness, is64Bits> *mergedSection;
+  
+    for (auto &si : _sections) {
+      const std::pair<StringRef, MergedSections<target_endianness, is64Bits> *> 
+                                            currentMergedSections(si->name(), 
+                                                                 nullptr);
+      std::pair<typename MergedSectionMapT::iterator, bool>
+                              mergedSectionInsert
+                              (_mergedSectionMap.insert(currentMergedSections));
+      if (!mergedSectionInsert.second) {
+        mergedSection = mergedSectionInsert.first->second;
+      }
+      else {
+        mergedSection = new (_allocator.Allocate
+                     <MergedSections<target_endianness, is64Bits>>())
+                     MergedSections<target_endianness, is64Bits>(si->name());
+        _mergedSections.push_back(mergedSection);
+        mergedSectionInsert.first->second = mergedSection;
+      }
+      mergedSection->appendSection(si);
+    }
+  }
 
- for (const  auto &chunk : _writer.sectionChunks()) {
-    Elf_Shdr *shdr  = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
-    StringRef Name  = chunk->sectionName();
-    if (chunk->shStrtableOffset() == 0){
-      chunk->setShStrtableOffset(str->addString(Name));
+  void assignSectionsToSegments() {
+    // sort the sections by their order as defined by the layout
+    std::stable_sort(_sections.begin(), _sections.end(),
+    [](Chunk<target_endianness, is64Bits> *A, 
+       Chunk<target_endianness, is64Bits> *B) {
+      return A->order() < B->order();
+    });
+    // Merge all sections
+    mergeSimiliarSections();
+    // Set the ordinal after sorting the sections
+    int ordinal = 1;
+    for (auto &msi : _mergedSections) {
+      (*msi).setOrdinal(ordinal);
+      for (auto ai = (*msi).begin_sections(), ae = (*msi).end_sections();
+                                               ai != ae; ++ai) {
+        (*ai)->setOrdinal(ordinal);
+      }
+      ++ordinal;
     }
-    shdr->sh_name   = chunk->shStrtableOffset();
+    Section<target_endianness, is64Bits> *section;
+    Segment<target_endianness, is64Bits> *segment;
+    for (auto msi = merged_sections_begin(), mse = merged_sections_end(); 
+                                             msi != mse; ++msi) {
+      for (auto ai = (*msi)->begin_sections(), ae = (*msi)->end_sections(); 
+                                               ai != ae; ++ai) {
+        if ((*ai)->kind() == Chunk<target_endianness, is64Bits>::K_ELFSection) {
+          section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*ai);
+          if (!hasOutputSegment(section))
+            continue;
+          (*msi)->setHasSegment();
+          section->setSegment(getSegmentType(section));
+          const StringRef segmentName = section->segmentKindToStr();
+          // Use the flags of the merged Section for the segment
+          const SegmentKey key(segmentName, (*msi)->flags());
+          const std::pair<SegmentKey, Segment<target_endianness, is64Bits> *> 
+                                                  currentSegment(key, nullptr);
+          std::pair<typename SegmentMapT::iterator, bool> 
+                              segmentInsert(_segmentMap.insert(currentSegment));
 
-    shdr->sh_type   = chunk->type();
-    shdr->sh_flags  = chunk->flags();
-    // TODO: At the time of creation of this section header, we will not have
-    // any address and offset info. We  revisit this after assigning the file
-    // offsets.
-    shdr->sh_offset = chunk->fileOffset();
-    shdr->sh_addr   = chunk->address();
-    shdr->sh_size   = chunk->size();
-    shdr->sh_link = chunk->link() ;
-    shdr->sh_info = chunk->shinfo();
-    shdr->sh_addralign = chunk->align2();
-    shdr->sh_entsize = chunk->entsize();
+          if (!segmentInsert.second) {
+            segment = segmentInsert.first->second;
+          } else {
+            segment = new (_allocator.Allocate
+                           <Segment<target_endianness, is64Bits>>())
+                           Segment<target_endianness, is64Bits>
+                           (segmentName, getSegmentType(section), 
+                            _options);
+            segmentInsert.first->second = segment;
+            _segments.push_back(segment);
+          }
+          segment->append(section);
+        }
+      }
+    }
+  }
 
-    _sectionInfo.push_back(shdr);
-    this->_size += sizeof (Elf_Shdr);
-    _writer.symtab()->setAttributes();
+  void addSection(Chunk<target_endianness, is64Bits> *c) {
+    _sections.push_back(c);
   }
-}
 
-template<support::endianness target_endianness, bool is64Bits>
-StringRef ELFSectionHeaderChunk<target_endianness, is64Bits>
-                               ::segmentName() const {
-  return "PT_NULL";
-}
+  void assignFileOffsets() {
+    std::sort(_segments.begin(), 
+              _segments.end(), 
+              Segment<target_endianness, is64Bits>::compareSegments);
+    int ordinal = 0;
+    // Compute the number of segments that might be needed, so that the
+    // size of the program header can be computed
+    uint64_t offset = 0;
+    for (auto si : _segments) {
+      si->setOrdinal(++ordinal);
+      si->assignOffsets(offset);
+      offset += si->fileSize();
+    }
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSectionHeaderChunk<target_endianness, is64Bits>
-                          ::write(uint8_t *chunkBuffer) {
-  for (const auto si : _sectionInfo) {
-    ::memcpy(chunkBuffer, si, sizeof(*si));
-    chunkBuffer += sizeof (*si);
+  void setELFHeader(ELFHeader<target_endianness, is64Bits> *e) {
+    _elfHeader = e;
   }
-}
 
-template<support::endianness target_endianness, bool is64Bits>
-uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::count() {
-  return _sectionInfo.size();
-}
-template<support::endianness target_endianness, bool is64Bits>
-uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::size() {
-  return sizeof (Elf_Shdr);
-}
+  void setProgramHeader(ELFProgramHeader<target_endianness, is64Bits> *p) {
+    _programHeader = p;
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFSectionHeaderChunk<target_endianness, is64Bits>::info() {
-  return "elf_section_header";
-}
+  void assignVirtualAddress() {
+    int32_t numSlices = 0;
+    uint64_t virtualAddress = _options.baseAddress();
 
-//===----------------------------------------------------------------------===//
-//  ELFProgramHeaderChunk
-//===----------------------------------------------------------------------===//
-template<support::endianness target_endianness, bool is64Bits>
-ELFProgramHeaderChunk<target_endianness, is64Bits>
-          ::ELFProgramHeaderChunk(const WriterOptionsELF &options, 
-                                  ELFWriter<target_endianness, is64Bits>
-                                                 &writer)
-  : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
-                                       ::Kind::Header)
-  , _options(options)
-  , _writer(writer) {
-  this->_align2 = 0;
-  this->setGroup(CG_HEADER);
-  _groupToPF[CG_RWX] = ELF::PF_R | ELF::PF_W | ELF::PF_X;
-  _groupToPF[CG_RW]  = ELF::PF_R | ELF::PF_W;
-  _groupToPF[CG_RX]  = ELF::PF_R | ELF::PF_X;
-  _groupToPF[CG_R]   = ELF::PF_R;
-  _groupToPF[CG_W]   = ELF::PF_W;
-  _groupToPF[CG_WX]  = ELF::PF_W | ELF::PF_X;
-  _groupToPF[CG_X]   = ELF::PF_X;
+    // Add the ELF Header
+    if (_elfHeader) {
+      _elfHeader->setFileOffset(0);
+      _elfHeader->setVAddr(virtualAddress);
+    }
+    // Add the program header
+    if (_programHeader) {
+      _programHeader->setVAddr(uint64_t(virtualAddress + _elfHeader->fileSize()));
+      _programHeader->setFileOffset(_elfHeader->fileSize());
+    }
+    bool newSegmentHeaderAdded = true;
+    while (true) {
+      for (auto si : _segments) {
+        newSegmentHeaderAdded = _programHeader->addSegment(si);
+        numSlices += si->numSlices();
+      }
+      if (!newSegmentHeaderAdded) 
+        break;
+      uint64_t fileoffset = _elfHeader->fileSize() + _programHeader->fileSize();
+      uint64_t address = virtualAddress;
+      // Fix the offsets after adding the program header
+      for (auto &si : _segments) {
+        // Align the segment to a page boundary
+        fileoffset = llvm::RoundUpToAlignment(fileoffset, _options.pageSize());
+        si->assignOffsets(fileoffset);
+        fileoffset = si->fileOffset() + si->fileSize();
+      }
+      // start assigning virtual addresses
+      for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+        (*si)->setVAddr(virtualAddress);
+        // The first segment has the virtualAddress set to the base address as
+        // we have added the file header and the program header dont align the
+        // first segment to the pagesize 
+        (*si)->assignVirtualAddress(address, (si == _segments.begin()));
+        (*si)->setMemSize(address - virtualAddress);
+        virtualAddress = llvm::RoundUpToAlignment(address, _options.pageSize());
+      }
+      _programHeader->resetProgramHeaders();
+    }
+    Section<target_endianness, is64Bits> *section;
+    // Fix the offsets of all the atoms within a section
+    for (auto &si : _sections) {
+      section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(si);
+      if (section && 
+          DefaultELFLayout<target_endianness, is64Bits>::hasOutputSegment(section))
+        section->assignOffsets(section->fileOffset());
+    }
+    // Set the size of the merged Sections
+    for (auto msi = merged_sections_begin(), mse = merged_sections_end(); 
+                                             msi != mse; ++msi) {
+      uint64_t sectionfileoffset = 0;
+      uint64_t startFileOffset = 0;
+      uint64_t sectionsize = 0;
+      bool isFirstSection = true;
+      for (auto si = (*msi)->begin_sections(); si != (*msi)->end_sections(); ++si) {
+        if (isFirstSection) {
+          startFileOffset = (*si)->fileOffset();
+          isFirstSection = false;
+        }
+        sectionfileoffset = (*si)->fileOffset();
+        sectionsize = (*si)->fileSize();
+      }
+      sectionsize = (sectionfileoffset - startFileOffset) + sectionsize;
+      (*msi)->setFileOffset(startFileOffset);
+      (*msi)->setSize(sectionsize);
+    }
+    // Set the virtual addr of the merged Sections
+    for (auto msi = merged_sections_begin(), mse = merged_sections_end(); 
+                                             msi != mse; ++msi) {
+      uint64_t sectionstartaddr = 0;
+      uint64_t startaddr = 0;
+      uint64_t sectionsize = 0;
+      bool isFirstSection = true;
+      for (auto si = (*msi)->begin_sections(), se = (*msi)->end_sections(); 
+                                               si != se; ++si) {
+        if (isFirstSection) {
+          startaddr = (*si)->virtualAddr();
+          isFirstSection = false;
+        }
+        sectionstartaddr = (*si)->virtualAddr();
+        sectionsize = (*si)->memSize();
+      }
+      sectionsize = (sectionstartaddr - startaddr) + sectionsize;
+      (*msi)->setMemSize(sectionsize);
+      (*msi)->setAddr(startaddr);
+    }
   }
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFProgramHeaderChunk<target_endianness, is64Bits>::createPHeaders() {
+  void assignOffsetsForMiscSections() {
+    uint64_t fileoffset = 0;
+    uint64_t size = 0;
+    for (auto si : _segments) {
+      fileoffset = si->fileOffset();
+      size = si->fileSize();
+    }
+    fileoffset = fileoffset + size;
+    Section<target_endianness, is64Bits> *section;
+    for (auto si : _sections) {
+      section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(si);
+      if (section && 
+          DefaultELFLayout<target_endianness, is64Bits>::hasOutputSegment
+                                                         (section))
+        continue;
+      fileoffset = llvm::RoundUpToAlignment(fileoffset, si->align2());
+      si->setFileOffset(fileoffset);
+      si->setVAddr(0);
+      fileoffset += si->fileSize();
+    }
+  }
 
-  //TODO Once dynamic linking is supported, implement PHDR segment
-  //     Implement mechanism inside this class to correctly find
-  //     attributes for sections such as eh_frame, note etc 
-  //     when they are supported.
-  const uint16_t seg[] = { CG_RWX, CG_RX, CG_R, CG_RW, CG_WX, CG_W, CG_X };
-  std::pair<secIterator, secIterator> sectionPair;
-  auto sections = _writer.sectionChunks();
-  _programHeaders.clear();
-  this->_size = 0;
-  for (auto group : seg) {
-    uint64_t size = 0, mSize = 0;
-    sectionPair = std::equal_range(sections.begin(), sections.end(), 
-                                   group, ChunkComparator<target_endianness, 
-                                                      is64Bits>());
-    if (sectionPair.first != sectionPair.second) {
-      // FIXME: fix occupiesNoDiskSpace() function in Chunks class
-      auto segBegin = sectionPair.first, segEnd = segBegin + 1;
-      // Since  this group has a section, atleast this is a part of segment
-      size = (*segBegin)->occupiesNoDiskSpace() ? 0 : (*segBegin)->size();
-      mSize = (*segBegin)->size();
+  void finalize() {
+    for (auto &si : _sections) {
+      si->finalize();
+    }
+  }
 
-      for (; segEnd != sectionPair.second; segEnd++) {
-      // This means there are more than 1 sections of same permissions
-        if ((*segEnd)->fileOffset() - (*segBegin)->fileOffset() - size >
-             _options.pageSize()) {
-          // we have a case where padding zeros span more than a page
-          // we can skip those pages.
-          Elf_Phdr *phdr = new(_headerAllocate.Allocate<Elf_Phdr>()) Elf_Phdr;
-          phdr->p_type = ELF::PT_LOAD;
-          phdr->p_offset = (*segBegin)->fileOffset();
-          phdr->p_vaddr =  (*segBegin)->address();
-          phdr->p_paddr = phdr->p_vaddr;
-          phdr->p_filesz = size;
-          // memory size may be more than file size if there are sections
-          // that do not occupy space on disk such as .bss
-          phdr->p_memsz = mSize;
-          phdr->p_flags = _groupToPF[group];
-          phdr->p_align = _options.pageSize();
-          _programHeaders.push_back(phdr);
-          this->_size += sizeof(Elf_Phdr);
-          segBegin = segEnd;
-          size = (*segBegin)->occupiesNoDiskSpace() ? 0 : (*segBegin)->size();
-          mSize = (*segBegin)->size();
-        } else {
-          size = (*segEnd)->fileOffset() - (*segBegin)->fileOffset() + 
-                 ((*segEnd)->occupiesNoDiskSpace() ? 0 : (*segEnd)->size())  ;
-          mSize =  (*segEnd)->fileOffset() - (*segBegin)->fileOffset() + 
-                   (*segEnd)->size();
-        }
+  bool findAtomAddrByName(const StringRef name, uint64_t &addr) {
+    Section<target_endianness, is64Bits> *section;
+    for (auto ai = _sections.begin(); ai != _sections.end(); ++ai) {
+      if ((*ai)->kind() == Chunk<target_endianness, is64Bits>::K_ELFSection) {
+        section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*ai);
+        if (section->findAtomAddrByName(name, addr))
+         return true;
       }
-
-      Elf_Phdr *phdr = new(_headerAllocate.Allocate<Elf_Phdr>()) Elf_Phdr;
-      phdr->p_type = ELF::PT_LOAD;
-      phdr->p_offset = (*segBegin)->fileOffset();
-      phdr->p_vaddr = (*segBegin)->address();
-      phdr->p_paddr = phdr->p_vaddr;
-      phdr->p_filesz = size;
-      phdr->p_memsz = mSize;
-      phdr->p_flags = _groupToPF[group];
-      phdr->p_align = _options.pageSize();
-      _programHeaders.push_back(phdr);
-      this->_size += sizeof(Elf_Phdr);
     }
+    return false;    
   }
-}
 
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t ELFProgramHeaderChunk<target_endianness, is64Bits>::computeNumber() {
-  return _programHeaders.size();
-}
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFProgramHeaderChunk<target_endianness, is64Bits>::info() {
-  return "elf_program_header";
-}
+  MergedSectionIter merged_sections_begin() { 
+    return _mergedSections.begin();
+  }
 
-template<support::endianness target_endianness, bool is64Bits>
-void ELFProgramHeaderChunk<target_endianness, is64Bits>
-                          ::write(uint8_t *chunkBuffer) {
-  for (const auto si : _programHeaders) {
-    ::memcpy(chunkBuffer, si, sizeof(*si));
-    chunkBuffer += sizeof (*si);
+  MergedSectionIter merged_sections_end() { 
+    return _mergedSections.end();
   }
-}
-template<support::endianness target_endianness, bool is64Bits>
-StringRef ELFProgramHeaderChunk<target_endianness, is64Bits>
-                               ::segmentName() const {
-  return "PT_NULL";
-}
+
+  ChunkIter sections_begin() {
+    return _sections.begin();
+  }
+  ChunkIter sections_end() {
+    return _sections.end();
+  }
+
+  ChunkIter segments_begin() {
+    return _segments.begin();
+  }
+
+  ChunkIter segments_end() {
+    return _segments.end();
+  }
+
+  ELFHeader<target_endianness, is64Bits> *elfHeader() { 
+    return _elfHeader;
+  }
+
+  ELFProgramHeader<target_endianness, is64Bits> *elfProgramHeader() { 
+    return _programHeader;
+  }
+
+private:
+  SectionMapT _sectionMap;
+  MergedSectionMapT _mergedSectionMap;
+  SegmentMapT _segmentMap;
+
+  std::vector<Chunk<target_endianness, is64Bits> *> _sections;
+  std::vector<Segment<target_endianness, is64Bits> *> _segments;
+  std::vector<MergedSections<target_endianness, is64Bits> *> _mergedSections;
+  ELFHeader<target_endianness, is64Bits> *_elfHeader;
+  ELFProgramHeader<target_endianness, is64Bits> *_programHeader;
+  llvm::BumpPtrAllocator _allocator;
+  const WriterOptionsELF &_options;
+};
+
 //===----------------------------------------------------------------------===//
-//  ELFWriter Class
+//  ELFExecutableWriter Class
 //===----------------------------------------------------------------------===//
 template<support::endianness target_endianness, bool is64Bits>
-class ELFWriter : public Writer {
+class ELFExecutableWriter : public ELFWriter {
 public:
-  LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
   typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
   typedef object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
-  typedef object::Elf_Phdr<target_endianness, is64Bits> Elf_Phdr;
-  ELFWriter(const WriterOptionsELF &options);
+
+  ELFExecutableWriter(const WriterOptionsELF &options);
+
+private:
+  // build the sections that need to be created 
+  void buildChunks(const lld::File &file);
   virtual error_code writeFile(const lld::File &File, StringRef path);
-  uint64_t addressOfAtom(const Atom *atom);
+  void buildAtomToAddressMap();
+  void buildSymbolTable ();
+  void buildSectionHeaderTable();
+  void assignSectionsWithNoSegments();
+  void addAbsoluteUndefinedSymbols(const lld::File &File);
 
-  std::vector<Chunk<target_endianness, is64Bits>*> chunks() const {
-    return _chunks; }
+  uint64_t addressOfAtom(const Atom *atom) { 
+    return _atomToAddressMap[atom];
+  }
 
   KindHandler *kindHandler() { return _referenceKindHandler.get(); }
-  
-  std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() const {
-    return _sectionChunks ;
-  }
- 
-  ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab()  const {
-    return _shstrtable;
-  }
-  
-  ELFStringSectionChunk<target_endianness, is64Bits> *strtab() const {
-    return _strtable;
-  }
-  ELFSymbolTableChunk<target_endianness, is64Bits> *symtab() const {
-    return _symtable;
-  }
 
-private:
-  void build(const lld::File &file);
-  void createChunks(const lld::File &file);
-  void buildAtomToAddressMap();
-  void assignFileOffsets();
+  void createDefaultSections();
+
   const WriterOptionsELF &_options;
 
-/// \brief AtomToAddress: Is a mapping from an Atom to the address where
-/// it will live in the output file.
   typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
-  typedef typename std::vector<Chunk<target_endianness, is64Bits>*>
-                     ::iterator chunkIterator;
-  ELFProgramHeaderChunk<target_endianness, is64Bits> *_phdr;
-  ELFHeaderChunk<target_endianness, is64Bits> *ehc;
-  ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
-  ELFStringSectionChunk<target_endianness, is64Bits> *_strtable ;
-  ELFSymbolTableChunk<target_endianness, is64Bits> *_symtable;
   std::unique_ptr<KindHandler> _referenceKindHandler;
-  ELFSectionHeaderChunk<target_endianness, is64Bits> *_sectionHeaderChunk;
-  AtomToAddress _atomToAddress;
-  std::vector<Chunk<target_endianness, is64Bits>*> _chunks;
-  const DefinedAtom *_entryAtom;
-  std::vector<SectionChunk<target_endianness, is64Bits>*> _sectionChunks;
-  std::vector<StockSectionChunk<target_endianness, is64Bits>*> 
-                                                      _stockSectionChunks;
+  AtomToAddress _atomToAddressMap;
   llvm::BumpPtrAllocator _chunkAllocate;
+  DefaultELFLayout<target_endianness, is64Bits> *_layout;
+  ELFHeader<target_endianness, is64Bits> *_elfHeader;
+  ELFProgramHeader<target_endianness, is64Bits> *_programHeader;
+  ELFSymbolTable<target_endianness, is64Bits> * _symtab;
+  ELFStringTable<target_endianness, is64Bits> *_strtab;
+  ELFStringTable<target_endianness, is64Bits> *_shstrtab;
+  ELFSectionHeader<target_endianness, is64Bits> *_shdrtab;
 };
 
 //===----------------------------------------------------------------------===//
-//  ELFWriter
+//  ELFExecutableWriter
 //===----------------------------------------------------------------------===//
 template<support::endianness target_endianness, bool is64Bits>
-ELFWriter<target_endianness, is64Bits>
-         ::ELFWriter(const WriterOptionsELF &options)
+ELFExecutableWriter<target_endianness, is64Bits>
+         ::ELFExecutableWriter(const WriterOptionsELF &options)
   : _options(options)
   , _referenceKindHandler(KindHandler::makeHandler(_options.machine(),
                                                    target_endianness))
-{}
+{
+  _layout = new DefaultELFLayout<target_endianness, is64Bits>(options);
+}
 
 template<support::endianness target_endianness, bool is64Bits>
-void ELFWriter<target_endianness, is64Bits>::build(const lld::File &file){
-// Create objects for each chunk.
-  createChunks(file);
-  assignFileOffsets();
-  _phdr->createPHeaders();
-  _sectionHeaderChunk->createHeaders();
-  // Creating program headers changed its size. so we need to re-assign offsets
-  assignFileOffsets();
-  _sectionHeaderChunk->fixOffsets();
-  _phdr->createPHeaders();
-  buildAtomToAddressMap();
-  _symtable->fixSymbolValue();
-  ehc->e_shentsize(_sectionHeaderChunk->size());
-  ehc->e_shnum(_sectionHeaderChunk->count());
-  // We need to put the index of section string table in ELF header
-  // first two chunks are not sections so we subtract 2 to start sections
-  // and add 1 since we have a NULL header
-  ehc->e_shstrndx(_shstrtable->ordinal() - 1);
-  ehc->e_phnum(_phdr->computeNumber());
-  ehc->e_phoff(_phdr->fileOffset());
-  ehc->e_phentsize(sizeof(Elf_Phdr));
-  for (auto i : _stockSectionChunks) {
-    if(const DefinedAtom* da = findDefinedAtomByName(_options.entryPoint(), i)) {
-      ehc->e_entry(this->addressOfAtom(da));
-      return;
-    }
+void ELFExecutableWriter<target_endianness, is64Bits>
+                        ::buildChunks(const lld::File &file){
+  for (const DefinedAtom *definedAtom : file.defined() ) {
+    _layout->addAtom(definedAtom);
   }
 }
 
 template<support::endianness target_endianness, bool is64Bits>
-void ELFWriter<target_endianness, is64Bits>
-              ::createChunks (const lld::File &file) {
-  std::map<StringRef, StockSectionChunk<target_endianness, is64Bits>*> 
-             sectionMap;
-
-// Make header chunk
-  ehc = new (_chunkAllocate.Allocate
-        <ELFHeaderChunk<target_endianness, is64Bits>>())
-        ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
-  _chunks.push_back(ehc);
-
-  _phdr = new (_chunkAllocate.Allocate
-               <ELFProgramHeaderChunk<target_endianness, is64Bits>>())
-                ELFProgramHeaderChunk<target_endianness, is64Bits>(_options, 
-                                                                   *this);
-  _chunks.push_back(_phdr);
-        
-// We need to create hand crafted sections such as shstrtab strtab hash and
-// symtab to put relevant information in ELF structures and then process the
-// atoms.
-
-  _shstrtable = new (_chunkAllocate.Allocate
-                     <ELFStringSectionChunk<target_endianness, is64Bits>>()) 
-                    ELFStringSectionChunk<target_endianness, is64Bits>
-                             (_options, *this, ".shstrtab");
-  _shstrtable->setShStrtableOffset(_shstrtable->addString(".shstrtab"));
-  _sectionChunks.push_back(_shstrtable);
-  
-  _strtable = new (_chunkAllocate.Allocate
-                     <ELFStringSectionChunk<target_endianness, is64Bits>>()) 
-                    ELFStringSectionChunk<target_endianness, is64Bits>
-                             (_options, *this, ".strtab");
-  _strtable->setShStrtableOffset( _shstrtable->addString(".strtab"));
-  _sectionChunks.push_back(_strtable);
-  
-  _symtable = new (_chunkAllocate.Allocate
-                     <ELFSymbolTableChunk<target_endianness, is64Bits>>()) 
-                    ELFSymbolTableChunk<target_endianness, is64Bits>
-                             (_options, *this, ".symtab");
-  _symtable->setShStrtableOffset( _shstrtable->addString(".symtab"));
-  _sectionChunks.push_back(_symtable);
-
-//TODO: implement .hash section
-
-  DEBUG_WITH_TYPE("WriterELF-layout", dbgs() 
-                    << "Atoms in file" << file.path()<<":\n");
-  for (const DefinedAtom *a : file.defined() ) {
-    DEBUG_WITH_TYPE("WriterELF-layout", dbgs() 
-                    << a->name() << " type: " << a->contentType() <<"\n");
-    StringRef sectionName = a->customSectionName();
-    if (a->sectionChoice() == 
-        DefinedAtom::SectionChoice::sectionBasedOnContent) {
-      if (a->contentType() == DefinedAtom::typeZeroFill)
-         sectionName = ".bss";
+void ELFExecutableWriter<target_endianness, is64Bits>::buildSymbolTable () {
+  Section<target_endianness, is64Bits> *section;
+  for (auto si = _layout->sections_begin(); si != _layout->sections_end(); ++si) {
+    if ((*si)->kind() != Chunk<target_endianness, is64Bits>::K_ELFSection) 
+      continue;
+    section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*si);
+    for (auto ai = section->atoms_begin(); ai != section->atoms_end(); ++ai) {
+      _symtab->addSymbol(ai->first, section->ordinal(), ai->second.second);
     }
-    auto pos = sectionMap.find(sectionName);
-    DefinedAtom::ContentType type = a->contentType();
-    if (type != DefinedAtom::typeUnknown){
-      if (pos == sectionMap.end()) {
-       StockSectionChunk<target_endianness, is64Bits>
-                  *chunk = new(_chunkAllocate.Allocate
-                               <StockSectionChunk<target_endianness, is64Bits>>
-                               ())StockSectionChunk<target_endianness, is64Bits>
-                                   (sectionName, true, type, _options, *this);
-
-       sectionMap[sectionName] = chunk;
-       chunk->appendAtom(a);
-       _sectionChunks.push_back(chunk);
-       _stockSectionChunks.push_back(chunk);
-                            
-      } else {
-        pos->second->appendAtom(a);
-      }
-    }
   }
+}
 
-  for (auto chnk : _sectionChunks)
-    _chunks.push_back(chnk);
-
-  _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
-                               <target_endianness, is64Bits>>())
-                              ELFSectionHeaderChunk
-                               <target_endianness, is64Bits>(_options, *this); 
-  _chunks.push_back(_sectionHeaderChunk);
-  // We sort the chunks based on the group they belong to
-  std::stable_sort(_chunks.begin(), _chunks.end(), 
-                   chunkGroupSort<target_endianness, is64Bits>);
-  
-  // The CG_RW group also has to be arranged such that all
-  // SHT_NOBITS type of sections (.*bss) are at end of this 
-  // "partition" of group.
-  chunkIterator cI;
-  std::pair<chunkIterator, chunkIterator> range;
-  range = std::equal_range(_chunks.begin() + 2, _chunks.end() - 1, CG_RW, 
-                           ChunkComparator<target_endianness, is64Bits>());
-                           
-  cI = std::stable_partition(range.first, range.second, 
-                             IsBss<target_endianness, is64Bits>);
-
-  // We reassign all the ordinals since its needed when making headers and 
-  // populating symbol table.
-  uint64_t i = 0;
-  for (auto chnk : _chunks) {
-    chnk->setOrdinal(i++);
-  }
-
-  // We sort the sections as per new ordinal set after group sorting.
-  std::stable_sort(_sectionChunks.begin(), _sectionChunks.end(),([]
-  (const SectionChunk<target_endianness, is64Bits> *A, 
-   const SectionChunk<target_endianness, is64Bits> *B) -> bool {
-     return A->ordinal() < B->ordinal();}));
-
-  // Populate symbol table  with correct st_shndx member.
-  for (auto chnk : _sectionChunks ) {
-     Elf_Sym *sym  = new (_chunkAllocate.Allocate<Elf_Sym>()) Elf_Sym;
-     sym->st_name  = 0;
-     sym->st_value = 0;
-     sym->st_size  = 0;
-     sym->st_other = ELF::STV_DEFAULT;
-    // first two chunks are not sections hence we subtract 2 but there is a 
-    // NULL section in section table so add 1
-     sym->st_shndx = chnk->ordinal() - 1 ;
-     sym->setBindingAndType(ELF::STB_LOCAL, ELF::STT_SECTION);
-     _symtable->addSymbol(sym);
-  }
- for (const auto ssc : _stockSectionChunks){
-   for (const auto da : ssc->atoms()) {
-     _symtable->addSymbol(std::get<0>(da), ssc->ordinal() -1);
-   }
- }
+template<support::endianness target_endianness, bool is64Bits>
+void ELFExecutableWriter<target_endianness, is64Bits>::
+                addAbsoluteUndefinedSymbols(const lld::File &file) {
  for (const UndefinedAtom *a : file.undefined()) {
-   _symtable->addSymbol(a, ELF::SHN_UNDEF);
+   _symtab->addSymbol(a, ELF::SHN_UNDEF);
  }
  
  for (const AbsoluteAtom *a : file.absolute()) {
-   _symtable->addSymbol(a, ELF::SHN_ABS);
+   _symtab->addSymbol(a, ELF::SHN_ABS);
  }
 }
 
 template<support::endianness target_endianness, bool is64Bits>
-void ELFWriter<target_endianness, is64Bits>
+void ELFExecutableWriter<target_endianness, is64Bits>
               ::buildAtomToAddressMap () {
-
-// _atomToAddress is a DenseMap that maps an atom its file address.
-// std::get<1>(ai) is the offset from the start of the section to the atom.
-  for (auto chunk : _stockSectionChunks){
-    for (auto &ai : chunk->atoms() ) {
-      _atomToAddress[std::get<0>(ai)] = chunk->address() + std::get<1>(ai);
+  Section<target_endianness, is64Bits> *section;
+  for (auto si = _layout->sections_begin(); 
+       si != _layout->sections_end(); ++si) {
+    if ((*si)->kind() != Chunk<target_endianness, is64Bits>::K_ELFSection) 
+      continue;
+    section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*si);
+    for (auto ai = section->atoms_begin(); ai != section->atoms_end(); ++ai) {
+      _atomToAddressMap[ai->first] = (ai)->second.second;
     }
   }
 }
 
 template<support::endianness target_endianness, bool is64Bits>
-void ELFWriter<target_endianness, is64Bits>::assignFileOffsets() {
-  DEBUG_WITH_TYPE("WriterELF-layout", dbgs() 
-                    << "assign file offsets:\n");
-  uint64_t offset = 0;
-  uint64_t address = _options.type() == ELF::ET_REL ? 0 : 
-                                        _options.baseAddress();
-  uint16_t chunkGroup;
-  auto chunkIt = _chunks.begin();
-  // first (two in case of ET_EXEC or ET_DYN) chunks is (are) not  section(s)
-  (*chunkIt)->assignFileOffset(offset, address);
-  chunkIt++;
-  if (_options.type() == ELF::ET_EXEC || 
-      _options.type() == ELF::ET_DYN) {
-    (*chunkIt)->assignFileOffset(offset, address);
-    chunkIt++;
+void ELFExecutableWriter<target_endianness, is64Bits>
+              ::buildSectionHeaderTable() {
+  for (auto msi = _layout->merged_sections_begin(); 
+       msi != _layout->merged_sections_end(); ++msi) {
+    if ((*msi)->kind() != Chunk<target_endianness, is64Bits>::K_ELFSection) 
+      continue;
+    if ((*msi)->hasSegment())
+      _shdrtab->appendSection(*msi);
   }
-  while (chunkIt != (_chunks.end() - 1) ) {
-    (*chunkIt)->assignFileOffset(offset, address);
-    if (_options.type() == ELF::ET_EXEC || 
-        _options.type() == ELF::ET_DYN) {
-      chunkGroup = (*chunkIt)->group();
-      chunkIt++;
-    // If the chunk group changes we start on new page
-      if (chunkGroup != (*chunkIt)->group() && (*chunkIt)->group() != CG_NO_LOAD 
-                                            && (*chunkIt)->group() != CG_FILE_END)
-        address = address + _options.pageSize();
-    } else {
-      chunkIt++;
-    }
+}
+
+template<support::endianness target_endianness, bool is64Bits>
+void ELFExecutableWriter<target_endianness, is64Bits>
+              ::assignSectionsWithNoSegments() {
+  Section<target_endianness, is64Bits> *section;
+  for (auto msi = _layout->merged_sections_begin(); 
+       msi != _layout->merged_sections_end(); ++msi) {
+    if ((*msi)->kind() != Chunk<target_endianness, is64Bits>::K_ELFSection) 
+      continue;
+    if (!(*msi)->hasSegment())
+      _shdrtab->appendSection(*msi);
   }
-  (*chunkIt)->assignFileOffset(offset, address);
-  ehc->e_shoff(_sectionHeaderChunk->fileOffset());
+  _layout->assignOffsetsForMiscSections();
+  for (auto si = _layout->sections_begin(); 
+       si != _layout->sections_end(); ++si) {
+    if ((*si)->kind() != Chunk<target_endianness, is64Bits>::K_ELFSection) 
+      continue;
+    section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*si);
+    if (!DefaultELFLayout<target_endianness, is64Bits>::hasOutputSegment
+                                                        (section))
+      _shdrtab->updateSection(section);
+  }
 }
 
 template<support::endianness target_endianness, bool is64Bits>
-error_code ELFWriter<target_endianness, is64Bits>
+error_code ELFExecutableWriter<target_endianness, is64Bits>
                     ::writeFile(const lld::File &file, StringRef path) {
-  build(file);
+  buildChunks(file);
+  // Create the default sections like the symbol table, string table, and the
+  // section string table
+  createDefaultSections();
 
-  uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
+  // Set the Layout
+  _layout->assignSectionsToSegments();
+  _layout->assignFileOffsets();
+  _layout->assignVirtualAddress();
 
+  // Build the Atom To Address map for applying relocations
+  buildAtomToAddressMap();
+
+  // Create symbol table and section string table
+  buildSymbolTable();
+
+  // add other symbols
+  addAbsoluteUndefinedSymbols(file);
+
+  // Finalize the layout by calling the finalize() functions
+  _layout->finalize();
+
+  // build Section Header table
+  buildSectionHeaderTable();
+
+  // assign Offsets and virtual addresses
+  // for sections with no segments
+  assignSectionsWithNoSegments();
+
+  uint64_t totalSize = _shdrtab->fileOffset() + _shdrtab->fileSize();
+
   OwningPtr<FileOutputBuffer> buffer;
   error_code ec = FileOutputBuffer::create(path,
                                            totalSize, buffer,
@@ -1417,28 +2057,78 @@
   if (ec)
     return ec;
 
-  for (auto chunk : _chunks) {
-    chunk->write(buffer->getBufferStart() + chunk->fileOffset());
-  }
+  for (auto si = _layout->sections_begin(); si != _layout->sections_end(); ++si)
+    (*si)->write(this, buffer);
+
+  _elfHeader->e_ident(ELF::EI_CLASS, (_options.is64Bit() ? ELF::ELFCLASS64
+                                                        : ELF::ELFCLASS32));
+  _elfHeader->e_ident(ELF::EI_DATA, (_options.endianness() == llvm::support::big)
+                                    ? ELF::ELFDATA2MSB : ELF::ELFDATA2LSB);
+  _elfHeader->e_ident(ELF::EI_VERSION, 1);
+  _elfHeader->e_ident(ELF::EI_OSABI, 0);
+  _elfHeader->e_type(_options.type());
+  _elfHeader->e_machine(_options.machine());
+  _elfHeader->e_version(1);
+  _elfHeader->e_entry(0ULL);
+  _elfHeader->e_phoff(_programHeader->fileOffset());
+  _elfHeader->e_shoff(_shdrtab->fileOffset());
+  _elfHeader->e_phentsize(_programHeader->entsize());
+  _elfHeader->e_phnum(_programHeader->numHeaders());
+  _elfHeader->e_shentsize(_shdrtab->entsize());
+  _elfHeader->e_shnum(_shdrtab->numHeaders());
+  _elfHeader->e_shstrndx(_shstrtab->ordinal());
+  uint64_t virtualAddr = 0;
+  _layout->findAtomAddrByName("_start", virtualAddr);
+  _elfHeader->e_entry(virtualAddr);
+  _elfHeader->write(this, buffer);
+  _programHeader->write(this, buffer);
+
   return buffer->commit();
 }
 
 template<support::endianness target_endianness, bool is64Bits>
-uint64_t ELFWriter<target_endianness, is64Bits>
-                    ::addressOfAtom(const Atom *atom) {
-  return _atomToAddress[atom];
+void ELFExecutableWriter<target_endianness, is64Bits>
+                    ::createDefaultSections() {
+  _elfHeader = new ELFHeader<target_endianness, is64Bits>();
+  _programHeader = new ELFProgramHeader<target_endianness, is64Bits>();
+  _layout->setELFHeader(_elfHeader);
+  _layout->setProgramHeader(_programHeader);
+
+  _symtab = new ELFSymbolTable<target_endianness, is64Bits>
+            (".symtab", 
+            DefaultELFLayout<target_endianness, is64Bits>::ORDER_SYMBOL_TABLE);
+  _strtab = new ELFStringTable<target_endianness, is64Bits>
+          (".strtab", 
+          DefaultELFLayout<target_endianness, is64Bits>::ORDER_STRING_TABLE);
+  _shstrtab = new ELFStringTable<target_endianness, is64Bits>
+          (".shstrtab", 
+          DefaultELFLayout<target_endianness, is64Bits>::ORDER_SECTION_STRINGS);
+  _shdrtab  = new ELFSectionHeader<target_endianness, is64Bits>
+         (DefaultELFLayout<target_endianness, is64Bits>::ORDER_SECTION_HEADERS);
+  _layout->addSection(_symtab);
+  _layout->addSection(_strtab);
+  _layout->addSection(_shstrtab);
+  _shdrtab->setStringSection(_shstrtab);
+  _symtab->setStringSection(_strtab);
+  _layout->addSection(_shdrtab);
 }
+
 } // namespace elf
 
 Writer *createWriterELF(const WriterOptionsELF &options) {
+
+  // Set the default layout to be the static executable layout
+  // We would set the layout to a dynamic executable layout 
+  // if we came across any shared libraries in the process
+  
   if (!options.is64Bit() && options.endianness() == llvm::support::little)
-    return new lld::elf::ELFWriter<support::little, false>(options);
+    return new lld::elf::ELFExecutableWriter<support::little, false>(options);
   else if (options.is64Bit() && options.endianness() == llvm::support::little)
-    return new lld::elf::ELFWriter<support::little, true>(options);
+    return new lld::elf::ELFExecutableWriter<support::little, true>(options);
   else if (!options.is64Bit() && options.endianness() == llvm::support::big)
-    return new lld::elf::ELFWriter<support::big, false>(options);
+    return new lld::elf::ELFExecutableWriter<support::big, false>(options);
   else if (options.is64Bit() && options.endianness() == llvm::support::big)
-    return new lld::elf::ELFWriter<support::big, true>(options);
+    return new lld::elf::ELFExecutableWriter<support::big, true>(options);
 
   llvm_unreachable("Invalid Options!");
 }


More information about the llvm-commits mailing list