[ELF] Emit the file header and program headers at the beginning of the first segment.

This is required for the loader to correctly set AT_PHDR.

With this lld can correctly link against dietlibc and get to main.

llvm-svn: 171709
diff --git a/lld/lib/ReaderWriter/ELF/WriterELF.cpp b/lld/lib/ReaderWriter/ELF/WriterELF.cpp
index 2dcbbce..b6e847e 100644
--- a/lld/lib/ReaderWriter/ELF/WriterELF.cpp
+++ b/lld/lib/ReaderWriter/ELF/WriterELF.cpp
@@ -747,6 +747,11 @@
       this->_align2 = section->align2();
   }
 
+  /// Prepend a generic chunk to the segment.
+  void prepend(Chunk<target_endianness, max_align, is64Bits> *c) {
+    _sections.insert(_sections.begin(), c);
+  }
+
   /// 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
@@ -869,27 +874,19 @@
   }
 
   /// \brief Assign virtual addresses to the slices
-  void assignVirtualAddress(uint64_t &addr, bool isFirstSegment) {
+  void assignVirtualAddress(uint64_t &addr) {
     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());
-      }
+      // 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) {
+        if (!virtualAddressSet) {
           (*sei)->setVAddr(addr);
           virtualAddressSet = true;
         }
@@ -897,6 +894,8 @@
         if (auto s =
               dyn_cast<Section<target_endianness, max_align, is64Bits>>(*si))
           s->assignVirtualAddress(addr);
+        else
+          addr += (*si)->memSize();
         (*si)->setMemSize(addr - (*si)->virtualAddr());
       }
       (*sei)->setMemSize(addr - (*sei)->virtualAddr());
@@ -1161,6 +1160,9 @@
   ELFHeader()
   : Chunk<target_endianness, max_align, is64Bits>(
       "elfhdr", Chunk<target_endianness, max_align, is64Bits>::K_ELFHeader) {
+    this->_align2 = is64Bits ? 8 : 4;
+    this->_fsize = sizeof(Elf_Ehdr);
+    this->_msize = sizeof(Elf_Ehdr);
     memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
     e_ident(ELF::EI_MAG0, 0x7f);
     e_ident(ELF::EI_MAG1, 'E');
@@ -1217,6 +1219,7 @@
   : Chunk<target_endianness, max_align, is64Bits>(
       "elfphdr",
       Chunk<target_endianness, max_align, is64Bits>::K_ELFProgramHeader) {
+    this->_align2 = is64Bits ? 8 : 4;
     resetProgramHeaders();
   }
 
@@ -1245,6 +1248,10 @@
       phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ?
                        segment->pageSize() : (*sei)->align2();
     }
+
+    this->_fsize = fileSize();
+    this->_msize = this->_fsize;
+
     return ret;
   }
 
@@ -1252,13 +1259,8 @@
     _phi = _ph.begin();
   }
 
-  void setVAddr(uint64_t addr) {
-    this->_start = llvm::RoundUpToAlignment(addr, 8);
-    this->_fsize = this->_start - addr;
-  }
-
   uint64_t  fileSize() {
-    return this->_fsize + (sizeof (Elf_Phdr) * _ph.size());
+    return sizeof(Elf_Phdr) * _ph.size();
   }
 
   static inline bool classof(
@@ -1745,27 +1747,27 @@
   }
 
   void assignVirtualAddress() {
+    if (_segments.empty())
+      return;
+
     uint64_t virtualAddress = _options.baseAddress();
 
-    // 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());
-    }
+    // HACK: This is a super dirty hack. The elf header and program header are
+    // not part of a section, but we need them to be loaded at the base address
+    // so that AT_PHDR is set correctly by the loader and so they are accessible
+    // at runtime. To do this we simply prepend them to the first Segment and
+    // let the layout logic take care of it.
+    _segments[0]->prepend(_programHeader);
+    _segments[0]->prepend(_elfHeader);
+
     bool newSegmentHeaderAdded = true;
-    while (true && !_segments.empty()) {
+    while (true) {
       for (auto si : _segments) {
         newSegmentHeaderAdded = _programHeader->addSegment(si);
       }
       if (!newSegmentHeaderAdded)
         break;
-      uint64_t fileoffset = _elfHeader->fileSize() + _programHeader->fileSize();
+      uint64_t fileoffset = 0;
       uint64_t address = virtualAddress;
       // Fix the offsets after adding the program header
       for (auto &si : _segments) {
@@ -1780,7 +1782,7 @@
         // 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)->assignVirtualAddress(address);
         (*si)->setMemSize(address - virtualAddress);
         virtualAddress = llvm::RoundUpToAlignment(address, _options.pageSize());
       }
@@ -2136,9 +2138,6 @@
   if (ec)
     return ec;
 
-  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
@@ -2159,9 +2158,16 @@
   uint64_t virtualAddr = 0;
   _layout->findAtomAddrByName("_start", virtualAddr);
   _elfHeader->e_entry(virtualAddr);
+
+  // HACK: We have to write out the header and program header here even though
+  // they are a member of a segment because only sections are written in the
+  // following loop.
   _elfHeader->write(this, buffer);
   _programHeader->write(this, buffer);
 
+  for (auto si = _layout->sections_begin(); si != _layout->sections_end(); ++si)
+    (*si)->write(this, buffer);
+
   return buffer->commit();
 }