Use pwrite to write the number of sections.
[oota-llvm.git] / lib / MC / ELFObjectWriter.cpp
index b2a83993f90284b088cdd9656f1a9796625f296c..e0214b476c3d73a03e83411820733da66c870046 100644 (file)
@@ -55,7 +55,7 @@ class SymbolTableWriter {
   MCAssembler &Asm;
   FragmentWriter &FWriter;
   bool Is64Bit;
-  SectionIndexMapTy &SectionIndexMap;
+  std::vector<const MCSectionELF *> &Sections;
 
   // The symbol .symtab fragment we are writting to.
   MCDataFragment *SymtabF;
@@ -72,7 +72,7 @@ class SymbolTableWriter {
 
 public:
   SymbolTableWriter(MCAssembler &Asm, FragmentWriter &FWriter, bool Is64Bit,
-                    SectionIndexMapTy &SectionIndexMap,
+                    std::vector<const MCSectionELF *> &Sections,
                     MCDataFragment *SymtabF);
 
   void writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size,
@@ -91,15 +91,9 @@ class ELFObjectWriter : public MCObjectWriter {
                            bool Used, bool Renamed);
     static bool isLocal(const MCSymbolData &Data, bool isUsedInReloc);
     static bool IsELFMetaDataSection(const MCSectionData &SD);
-    static uint64_t DataSectionSize(const MCSectionData &SD);
-    static uint64_t GetSectionFileSize(const MCAsmLayout &Layout,
-                                       const MCSectionData &SD);
-    static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout,
-                                          const MCSectionData &SD);
 
-    void WriteDataSectionData(MCAssembler &Asm,
-                              const MCAsmLayout &Layout,
-                              const MCSectionELF &Section);
+    void writeDataSectionData(MCAssembler &Asm, const MCAsmLayout &Layout,
+                              const MCSectionData &SD);
 
     /// Helper struct for containing some precomputed information on symbols.
     struct ELFSymbolData {
@@ -168,7 +162,7 @@ class ELFObjectWriter : public MCObjectWriter {
     }
 
   public:
-    ELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_ostream &OS,
+    ELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_pwrite_stream &OS,
                     bool IsLittleEndian)
         : MCObjectWriter(OS, IsLittleEndian), FWriter(IsLittleEndian),
           TargetObjectWriter(MOTW), NeedsGOT(false) {}
@@ -200,16 +194,14 @@ class ELFObjectWriter : public MCObjectWriter {
       FWriter.write(F, Value);
     }
 
-    void WriteHeader(const MCAssembler &Asm,
-                     uint64_t SectionHeaderOffset,
-                     unsigned NumberOfSections);
+    void writeHeader(const MCAssembler &Asm);
 
     void WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD,
                      const MCAsmLayout &Layout);
 
     void WriteSymbolTable(MCDataFragment *SymtabF, MCAssembler &Asm,
                           const MCAsmLayout &Layout,
-                          SectionIndexMapTy &SectionIndexMap);
+                          std::vector<const MCSectionELF *> &Sections);
 
     bool shouldRelocateWithSymbol(const MCAssembler &Asm,
                                   const MCSymbolRefExpr *RefA,
@@ -224,12 +216,10 @@ class ELFObjectWriter : public MCObjectWriter {
     uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm,
                                          const MCSymbol *S);
 
-    // Map from a group section to the signature symbol
-    typedef DenseMap<const MCSectionELF*, const MCSymbol*> GroupMapTy;
-    // Map from a signature symbol to the group section
-    typedef DenseMap<const MCSymbol*, const MCSectionELF*> RevGroupMapTy;
-    // Map from a section to its offset
-    typedef DenseMap<const MCSectionELF*, uint64_t> SectionOffsetMapTy;
+    // Map from a signature symbol to the group section index
+    typedef DenseMap<const MCSymbol *, unsigned> RevGroupMapTy;
+    // Start and end offset of each section
+    typedef std::vector<std::pair<uint64_t, uint64_t>> SectionOffsetsTy;
 
     /// Compute the symbol table data
     ///
@@ -240,34 +230,44 @@ class ELFObjectWriter : public MCObjectWriter {
                             const SectionIndexMapTy &SectionIndexMap,
                             const RevGroupMapTy &RevGroupMap);
 
-    void computeIndexMap(MCAssembler &Asm, SectionIndexMapTy &SectionIndexMap);
+    void maybeAddToGroup(MCAssembler &Asm,
+                         ArrayRef<const MCSectionELF *> Sections,
+                         const RevGroupMapTy &RevGroupMap,
+                         const MCSectionELF &Section, unsigned Index);
 
-    MCSectionData *createRelocationSection(MCAssembler &Asm,
-                                           const MCSectionData &SD);
+    void computeIndexMap(MCAssembler &Asm,
+                         std::vector<const MCSectionELF *> &Sections,
+                         SectionIndexMapTy &SectionIndexMap,
+                         const RevGroupMapTy &RevGroupMap);
+
+    void createRelocationSection(MCAssembler &Asm, const MCSectionData &SD);
 
     void CompressDebugSections(MCAssembler &Asm, MCAsmLayout &Layout);
 
-    void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout);
+    void WriteRelocations(MCAssembler &Asm, const MCAsmLayout &Layout);
 
-    void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout,
-                                SectionIndexMapTy &SectionIndexMap);
+    void
+    createSectionHeaderStringTable(MCAssembler &Asm,
+                                   std::vector<const MCSectionELF *> &Sections);
+    void createStringTable(MCAssembler &Asm,
+                           std::vector<const MCSectionELF *> &Sections);
+    void CreateMetadataSections(MCAssembler &Asm, const MCAsmLayout &Layout,
+                                std::vector<const MCSectionELF *> &Sections);
 
     // Create the sections that show up in the symbol table. Currently
     // those are the .note.GNU-stack section and the group sections.
-    void createIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout,
-                               GroupMapTy &GroupMap, RevGroupMapTy &RevGroupMap,
+    void createIndexedSections(MCAssembler &Asm, const MCAsmLayout &Layout,
+                               RevGroupMapTy &RevGroupMap,
+                               std::vector<const MCSectionELF *> &Sections,
                                SectionIndexMapTy &SectionIndexMap);
 
     void ExecutePostLayoutBinding(MCAssembler &Asm,
                                   const MCAsmLayout &Layout) override;
 
-    void writeSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap,
-                            const MCAsmLayout &Layout,
+    void writeSectionHeader(ArrayRef<const MCSectionELF *> Sections,
+                            MCAssembler &Asm, const MCAsmLayout &Layout,
                             const SectionIndexMapTy &SectionIndexMap,
-                            const SectionOffsetMapTy &SectionOffsetMap);
-
-    void ComputeSectionOrder(MCAssembler &Asm,
-                             std::vector<const MCSectionELF*> &Sections);
+                            const SectionOffsetsTy &SectionOffsets);
 
     void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
                           uint64_t Address, uint64_t Offset,
@@ -281,7 +281,6 @@ class ELFObjectWriter : public MCObjectWriter {
     bool
     IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
                                            const MCSymbolData &DataA,
-                                           const MCSymbolData *DataB,
                                            const MCFragment &FB,
                                            bool InSet,
                                            bool IsPCRel) const override;
@@ -320,8 +319,7 @@ void SymbolTableWriter::createSymtabShndx() {
       &Asm.getOrCreateSectionData(*SymtabShndxSection);
   SymtabShndxSD->setAlignment(4);
   ShndxF = new MCDataFragment(SymtabShndxSD);
-  unsigned Index = SectionIndexMap.size() + 1;
-  SectionIndexMap[SymtabShndxSection] = Index;
+  Sections.push_back(SymtabShndxSection);
 
   for (unsigned I = 0; I < NumWritten; ++I)
     write(*ShndxF, uint32_t(0));
@@ -332,13 +330,11 @@ void SymbolTableWriter::write(MCDataFragment &F, T Value) {
   FWriter.write(F, Value);
 }
 
-SymbolTableWriter::SymbolTableWriter(MCAssembler &Asm, FragmentWriter &FWriter,
-                                     bool Is64Bit,
-                                     SectionIndexMapTy &SectionIndexMap,
-                                     MCDataFragment *SymtabF)
-    : Asm(Asm), FWriter(FWriter), Is64Bit(Is64Bit),
-      SectionIndexMap(SectionIndexMap), SymtabF(SymtabF), ShndxF(nullptr),
-      NumWritten(0) {}
+SymbolTableWriter::SymbolTableWriter(
+    MCAssembler &Asm, FragmentWriter &FWriter, bool Is64Bit,
+    std::vector<const MCSectionELF *> &Sections, MCDataFragment *SymtabF)
+    : Asm(Asm), FWriter(FWriter), Is64Bit(Is64Bit), Sections(Sections),
+      SymtabF(SymtabF), ShndxF(nullptr), NumWritten(0) {}
 
 void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value,
                                     uint64_t size, uint8_t other,
@@ -408,9 +404,7 @@ ELFObjectWriter::~ELFObjectWriter()
 {}
 
 // Emit the ELF header.
-void ELFObjectWriter::WriteHeader(const MCAssembler &Asm,
-                                  uint64_t SectionHeaderOffset,
-                                  unsigned NumberOfSections) {
+void ELFObjectWriter::writeHeader(const MCAssembler &Asm) {
   // ELF Header
   // ----------
   //
@@ -419,10 +413,7 @@ void ELFObjectWriter::WriteHeader(const MCAssembler &Asm,
   // emitWord method behaves differently for ELF32 and ELF64, writing
   // 4 bytes in the former and 8 in the latter.
 
-  Write8(0x7f); // e_ident[EI_MAG0]
-  Write8('E');  // e_ident[EI_MAG1]
-  Write8('L');  // e_ident[EI_MAG2]
-  Write8('F');  // e_ident[EI_MAG3]
+  WriteBytes(ELF::ElfMagic); // e_ident[EI_MAG0] to e_ident[EI_MAG3]
 
   Write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS]
 
@@ -443,7 +434,7 @@ void ELFObjectWriter::WriteHeader(const MCAssembler &Asm,
   Write32(ELF::EV_CURRENT);         // e_version
   WriteWord(0);                    // e_entry, no entry point in .o file
   WriteWord(0);                    // e_phoff, no program header for .o
-  WriteWord(SectionHeaderOffset);  // e_shoff = sec hdr table off in bytes
+  WriteWord(0);                     // e_shoff = sec hdr table off in bytes
 
   // e_flags = whatever the target wants
   Write32(Asm.getELFHeaderEFlags());
@@ -458,16 +449,11 @@ void ELFObjectWriter::WriteHeader(const MCAssembler &Asm,
   Write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr));
 
   // e_shnum     = # of section header ents
-  if (NumberOfSections >= ELF::SHN_LORESERVE)
-    Write16(ELF::SHN_UNDEF);
-  else
-    Write16(NumberOfSections);
+  Write16(0);
 
   // e_shstrndx  = Section # of '.shstrtab'
-  if (ShstrtabIndex >= ELF::SHN_LORESERVE)
-    Write16(ELF::SHN_XINDEX);
-  else
-    Write16(ShstrtabIndex);
+  assert(ShstrtabIndex < ELF::SHN_LORESERVE);
+  Write16(ShstrtabIndex);
 }
 
 uint64_t ELFObjectWriter::SymbolValue(MCSymbolData &Data,
@@ -608,16 +594,15 @@ void ELFObjectWriter::WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD,
                      MSD.SectionIndex, IsReserved);
 }
 
-void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF,
-                                       MCAssembler &Asm,
-                                       const MCAsmLayout &Layout,
-                                       SectionIndexMapTy &SectionIndexMap) {
+void ELFObjectWriter::WriteSymbolTable(
+    MCDataFragment *SymtabF, MCAssembler &Asm, const MCAsmLayout &Layout,
+    std::vector<const MCSectionELF *> &Sections) {
   // The string table must be emitted first because we need the index
   // into the string table for all the symbol names.
 
   // FIXME: Make sure the start of the symbol table is aligned.
 
-  SymbolTableWriter Writer(Asm, FWriter, is64Bit(), SectionIndexMap, SymtabF);
+  SymbolTableWriter Writer(Asm, FWriter, is64Bit(), Sections, SymtabF);
 
   // The first entry is the undefined symbol entry.
   Writer.writeSymbol(0, 0, 0, 0, 0, 0, false);
@@ -775,8 +760,24 @@ static const MCSymbol *getWeakRef(const MCSymbolRefExpr &Ref) {
   return nullptr;
 }
 
+// True if the assembler knows nothing about the final value of the symbol.
+// This doesn't cover the comdat issues, since in those cases the assembler
+// can at least know that all symbols in the section will move together.
 static bool isWeak(const MCSymbolData &D) {
-  return D.getFlags() & ELF_STB_Weak || MCELF::GetType(D) == ELF::STT_GNU_IFUNC;
+  if (MCELF::GetType(D) == ELF::STT_GNU_IFUNC)
+    return true;
+
+  switch (MCELF::GetBinding(D)) {
+  default:
+    llvm_unreachable("Unknown binding");
+  case ELF::STB_LOCAL:
+    return false;
+  case ELF::STB_GLOBAL:
+    return false;
+  case ELF::STB_WEAK:
+  case ELF::STB_GNU_UNIQUE:
+    return true;
+  }
 }
 
 void ELFObjectWriter::RecordRelocation(MCAssembler &Asm,
@@ -938,33 +939,34 @@ bool ELFObjectWriter::isLocal(const MCSymbolData &Data, bool isUsedInReloc) {
   return true;
 }
 
-void ELFObjectWriter::computeIndexMap(MCAssembler &Asm,
-                                      SectionIndexMapTy &SectionIndexMap) {
-  unsigned Index = 1;
-  for (MCAssembler::iterator it = Asm.begin(),
-         ie = Asm.end(); it != ie; ++it) {
-    const MCSectionELF &Section =
-      static_cast<const MCSectionELF &>(it->getSection());
-    if (Section.getType() != ELF::SHT_GROUP)
-      continue;
-    SectionIndexMap[&Section] = Index++;
-  }
+void ELFObjectWriter::maybeAddToGroup(MCAssembler &Asm,
+                                      ArrayRef<const MCSectionELF *> Sections,
+                                      const RevGroupMapTy &RevGroupMap,
+                                      const MCSectionELF &Section,
+                                      unsigned Index) {
+  const MCSymbol *Sym = Section.getGroup();
+  if (!Sym)
+    return;
+  const MCSectionELF *Group = Sections[RevGroupMap.lookup(Sym) - 1];
+  MCSectionData &Data = Asm.getOrCreateSectionData(*Group);
+  // FIXME: we could use the previous fragment
+  MCDataFragment *F = new MCDataFragment(&Data);
+  write(*F, Index);
+}
 
-  for (MCAssembler::iterator it = Asm.begin(),
-         ie = Asm.end(); it != ie; ++it) {
-    const MCSectionData &SD = *it;
+void ELFObjectWriter::computeIndexMap(
+    MCAssembler &Asm, std::vector<const MCSectionELF *> &Sections,
+    SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap) {
+  for (const MCSectionData &SD : Asm) {
     const MCSectionELF &Section =
       static_cast<const MCSectionELF &>(SD.getSection());
-    if (Section.getType() == ELF::SHT_GROUP ||
-        Section.getType() == ELF::SHT_REL ||
-        Section.getType() == ELF::SHT_RELA)
+    if (Section.getType() == ELF::SHT_GROUP)
       continue;
-    SectionIndexMap[&Section] = Index++;
-    if (MCSectionData *RelSD = createRelocationSection(Asm, SD)) {
-      const MCSectionELF *RelSection =
-          static_cast<const MCSectionELF *>(&RelSD->getSection());
-      SectionIndexMap[RelSection] = Index++;
-    }
+    Sections.push_back(&Section);
+    unsigned Index = Sections.size();
+    SectionIndexMap[&Section] = Index;
+    maybeAddToGroup(Asm, Sections, RevGroupMap, Section, Index);
+    createRelocationSection(Asm, SD);
   }
 }
 
@@ -1016,7 +1018,7 @@ void ELFObjectWriter::computeSymbolTable(
       MSD.SectionIndex = ELF::SHN_COMMON;
     } else if (BaseSymbol->isUndefined()) {
       if (isSignature && !Used)
-        MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap.lookup(&Symbol));
+        MSD.SectionIndex = RevGroupMap.lookup(&Symbol);
       else
         MSD.SectionIndex = ELF::SHN_UNDEF;
       if (!Used && WeakrefUsed)
@@ -1113,11 +1115,10 @@ void ELFObjectWriter::computeSymbolTable(
     UndefinedSymbolData[i].SymbolData->setIndex(Index++);
 }
 
-MCSectionData *
-ELFObjectWriter::createRelocationSection(MCAssembler &Asm,
-                                         const MCSectionData &SD) {
+void ELFObjectWriter::createRelocationSection(MCAssembler &Asm,
+                                              const MCSectionData &SD) {
   if (Relocations[&SD].empty())
-    return nullptr;
+    return;
 
   MCContext &Ctx = Asm.getContext();
   const MCSectionELF &Section =
@@ -1140,11 +1141,11 @@ ELFObjectWriter::createRelocationSection(MCAssembler &Asm,
   const MCSectionELF *RelaSection = Ctx.createELFRelSection(
       RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL,
       Flags, EntrySize, Section.getGroup(), &Section);
-  return &Asm.getOrCreateSectionData(*RelaSection);
+  Asm.getOrCreateSectionData(*RelaSection);
 }
 
 static SmallVector<char, 128>
-getUncompressedData(MCAsmLayout &Layout,
+getUncompressedData(const MCAsmLayout &Layout,
                     MCSectionData::FragmentListType &Fragments) {
   SmallVector<char, 128> UncompressedData;
   for (const MCFragment &F : Fragments) {
@@ -1191,7 +1192,7 @@ prependCompressionHeader(uint64_t Size,
 // Return a single fragment containing the compressed contents of the whole
 // section. Null if the section was not compressed for any reason.
 static std::unique_ptr<MCDataFragment>
-getCompressedFragment(MCAsmLayout &Layout,
+getCompressedFragment(const MCAsmLayout &Layout,
                       MCSectionData::FragmentListType &Fragments) {
   std::unique_ptr<MCDataFragment> CompressedFragment(new MCDataFragment());
 
@@ -1288,7 +1289,8 @@ void ELFObjectWriter::CompressDebugSections(MCAssembler &Asm,
   }
 }
 
-void ELFObjectWriter::WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) {
+void ELFObjectWriter::WriteRelocations(MCAssembler &Asm,
+                                       const MCAsmLayout &Layout) {
   for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) {
     MCSectionData &RelSD = *it;
     const MCSectionELF &RelSection =
@@ -1368,99 +1370,87 @@ void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm,
   }
 }
 
+void ELFObjectWriter::createSectionHeaderStringTable(
+    MCAssembler &Asm, std::vector<const MCSectionELF *> &Sections) {
+  const MCSectionELF *ShstrtabSection = Sections[ShstrtabIndex - 1];
+
+  Asm.getOrCreateSectionData(*ShstrtabSection);
+
+  for (MCSectionData &SD : Asm) {
+    const MCSectionELF &Section =
+        static_cast<const MCSectionELF &>(SD.getSection());
+    ShStrTabBuilder.add(Section.getSectionName());
+  }
+  ShStrTabBuilder.finalize(StringTableBuilder::ELF);
+  OS << ShStrTabBuilder.data();
+}
+
+void ELFObjectWriter::createStringTable(
+    MCAssembler &Asm, std::vector<const MCSectionELF *> &Sections) {
+  MCContext &Ctx = Asm.getContext();
+  const MCSectionELF *StrtabSection =
+      Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0);
+  Asm.getOrCreateSectionData(*StrtabSection);
+  Sections.push_back(StrtabSection);
+  StringTableIndex = Sections.size();
+  OS << StrTabBuilder.data();
+}
+
 void ELFObjectWriter::CreateMetadataSections(
-    MCAssembler &Asm, MCAsmLayout &Layout, SectionIndexMapTy &SectionIndexMap) {
+    MCAssembler &Asm, const MCAsmLayout &Layout,
+    std::vector<const MCSectionELF *> &Sections) {
   MCContext &Ctx = Asm.getContext();
   MCDataFragment *F;
 
   unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32;
 
-  // We construct .shstrtab, .symtab and .strtab in this order to match gnu as.
-  const MCSectionELF *ShstrtabSection =
-      Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0);
-  MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection);
-  ShstrtabSD.setAlignment(1);
-  ShstrtabIndex = SectionIndexMap.size() + 1;
-  SectionIndexMap[ShstrtabSection] = ShstrtabIndex;
-
+  // Symbol table
   const MCSectionELF *SymtabSection =
     Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0,
                       EntrySize, "");
   MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection);
   SymtabSD.setAlignment(is64Bit() ? 8 : 4);
-  SymbolTableIndex = SectionIndexMap.size() + 1;
-  SectionIndexMap[SymtabSection] = SymbolTableIndex;
-
-  const MCSectionELF *StrtabSection;
-  StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0);
-  MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection);
-  StrtabSD.setAlignment(1);
-  StringTableIndex = SectionIndexMap.size() + 1;
-  SectionIndexMap[StrtabSection] = StringTableIndex;
-
-  // Symbol table
+  SymbolTableIndex = Sections.size() + 1;
+  Sections.push_back(SymtabSection);
   F = new MCDataFragment(&SymtabSD);
-  WriteSymbolTable(F, Asm, Layout, SectionIndexMap);
-
-  F = new MCDataFragment(&StrtabSD);
-  F->getContents().append(StrTabBuilder.data().begin(),
-                          StrTabBuilder.data().end());
-
-  F = new MCDataFragment(&ShstrtabSD);
-
-  // Section header string table.
-  for (auto it = Asm.begin(), ie = Asm.end(); it != ie; ++it) {
-    const MCSectionELF &Section =
-      static_cast<const MCSectionELF&>(it->getSection());
-    ShStrTabBuilder.add(Section.getSectionName());
-  }
-  ShStrTabBuilder.finalize(StringTableBuilder::ELF);
-  F->getContents().append(ShStrTabBuilder.data().begin(),
-                          ShStrTabBuilder.data().end());
+  WriteSymbolTable(F, Asm, Layout, Sections);
 }
 
 void ELFObjectWriter::createIndexedSections(
-    MCAssembler &Asm, MCAsmLayout &Layout, GroupMapTy &GroupMap,
-    RevGroupMapTy &RevGroupMap, SectionIndexMapTy &SectionIndexMap) {
+    MCAssembler &Asm, const MCAsmLayout &Layout, RevGroupMapTy &RevGroupMap,
+    std::vector<const MCSectionELF *> &Sections,
+    SectionIndexMapTy &SectionIndexMap) {
   MCContext &Ctx = Asm.getContext();
 
+  const MCSectionELF *ShstrtabSection =
+      Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0);
+  Sections.push_back(ShstrtabSection);
+  ShstrtabIndex = Sections.size();
+  assert(ShstrtabIndex == 1);
+
   // Build the groups
-  for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
-       it != ie; ++it) {
+  for (const MCSectionData &SD : Asm) {
     const MCSectionELF &Section =
-      static_cast<const MCSectionELF&>(it->getSection());
+        static_cast<const MCSectionELF &>(SD.getSection());
     if (!(Section.getFlags() & ELF::SHF_GROUP))
       continue;
 
     const MCSymbol *SignatureSymbol = Section.getGroup();
     Asm.getOrCreateSymbolData(*SignatureSymbol);
-    const MCSectionELF *&Group = RevGroupMap[SignatureSymbol];
-    if (!Group) {
-      Group = Ctx.CreateELFGroupSection();
+    unsigned &GroupIdx = RevGroupMap[SignatureSymbol];
+    if (!GroupIdx) {
+      const MCSectionELF *Group = Ctx.createELFGroupSection(SignatureSymbol);
+      Sections.push_back(Group);
+      GroupIdx = Sections.size();
+
       MCSectionData &Data = Asm.getOrCreateSectionData(*Group);
       Data.setAlignment(4);
       MCDataFragment *F = new MCDataFragment(&Data);
       write(*F, uint32_t(ELF::GRP_COMDAT));
     }
-    GroupMap[Group] = SignatureSymbol;
   }
 
-  computeIndexMap(Asm, SectionIndexMap);
-
-  // Add sections to the groups
-  for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
-       it != ie; ++it) {
-    const MCSectionELF &Section =
-      static_cast<const MCSectionELF&>(it->getSection());
-    if (!(Section.getFlags() & ELF::SHF_GROUP))
-      continue;
-    const MCSectionELF *Group = RevGroupMap[Section.getGroup()];
-    MCSectionData &Data = Asm.getOrCreateSectionData(*Group);
-    // FIXME: we could use the previous fragment
-    MCDataFragment *F = new MCDataFragment(&Data);
-    uint32_t Index = SectionIndexMap.lookup(&Section);
-    write(*F, Index);
-  }
+  computeIndexMap(Asm, Sections, SectionIndexMap, RevGroupMap);
 }
 
 void ELFObjectWriter::writeSection(MCAssembler &Asm,
@@ -1521,39 +1511,9 @@ bool ELFObjectWriter::IsELFMetaDataSection(const MCSectionData &SD) {
     !SD.getSection().isVirtualSection();
 }
 
-uint64_t ELFObjectWriter::DataSectionSize(const MCSectionData &SD) {
-  uint64_t Ret = 0;
-  for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e;
-       ++i) {
-    const MCFragment &F = *i;
-    assert(F.getKind() == MCFragment::FT_Data);
-    Ret += cast<MCDataFragment>(F).getContents().size();
-  }
-  return Ret;
-}
-
-uint64_t ELFObjectWriter::GetSectionFileSize(const MCAsmLayout &Layout,
-                                             const MCSectionData &SD) {
-  if (IsELFMetaDataSection(SD))
-    return DataSectionSize(SD);
-  return Layout.getSectionFileSize(&SD);
-}
-
-uint64_t ELFObjectWriter::GetSectionAddressSize(const MCAsmLayout &Layout,
-                                                const MCSectionData &SD) {
-  if (IsELFMetaDataSection(SD))
-    return DataSectionSize(SD);
-  return Layout.getSectionAddressSize(&SD);
-}
-
-void ELFObjectWriter::WriteDataSectionData(MCAssembler &Asm,
+void ELFObjectWriter::writeDataSectionData(MCAssembler &Asm,
                                            const MCAsmLayout &Layout,
-                                           const MCSectionELF &Section) {
-  const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
-
-  uint64_t Padding = OffsetToAlignment(OS.tell(), SD.getAlignment());
-  WriteZeros(Padding);
-
+                                           const MCSectionData &SD) {
   if (IsELFMetaDataSection(SD)) {
     for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e;
          ++i) {
@@ -1567,151 +1527,154 @@ void ELFObjectWriter::WriteDataSectionData(MCAssembler &Asm,
 }
 
 void ELFObjectWriter::writeSectionHeader(
-    MCAssembler &Asm, const GroupMapTy &GroupMap, const MCAsmLayout &Layout,
-    const SectionIndexMapTy &SectionIndexMap,
-    const SectionOffsetMapTy &SectionOffsetMap) {
-  const unsigned NumSections = Asm.size() + 1;
-
-  std::vector<const MCSectionELF*> Sections;
-  Sections.resize(NumSections - 1);
-
-  for (SectionIndexMapTy::const_iterator i=
-         SectionIndexMap.begin(), e = SectionIndexMap.end(); i != e; ++i) {
-    const std::pair<const MCSectionELF*, uint32_t> &p = *i;
-    Sections[p.second - 1] = p.first;
-  }
+    ArrayRef<const MCSectionELF *> Sections, MCAssembler &Asm,
+    const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap,
+    const SectionOffsetsTy &SectionOffsets) {
+  const unsigned NumSections = Asm.size();
 
   // Null section first.
   uint64_t FirstSectionSize =
-    NumSections >= ELF::SHN_LORESERVE ? NumSections : 0;
-  uint32_t FirstSectionLink =
-    ShstrtabIndex >= ELF::SHN_LORESERVE ? ShstrtabIndex : 0;
-  WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, FirstSectionLink, 0, 0, 0);
+      (NumSections + 1) >= ELF::SHN_LORESERVE ? NumSections + 1 : 0;
+  WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, 0, 0, 0, 0);
 
-  for (unsigned i = 0; i < NumSections - 1; ++i) {
+  for (unsigned i = 0; i < NumSections; ++i) {
     const MCSectionELF &Section = *Sections[i];
     const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
     uint32_t GroupSymbolIndex;
     if (Section.getType() != ELF::SHT_GROUP)
       GroupSymbolIndex = 0;
     else
-      GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm,
-                                                     GroupMap.lookup(&Section));
+      GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm, Section.getGroup());
 
-    uint64_t Size = GetSectionAddressSize(Layout, SD);
+    const std::pair<uint64_t, uint64_t> &Offsets = SectionOffsets[i];
+    uint64_t Size = Section.getType() == ELF::SHT_NOBITS
+                        ? Layout.getSectionAddressSize(&SD)
+                        : Offsets.second - Offsets.first;
 
-    writeSection(Asm, SectionIndexMap, GroupSymbolIndex,
-                 SectionOffsetMap.lookup(&Section), Size, SD.getAlignment(),
-                 Section);
-  }
-}
-
-void ELFObjectWriter::ComputeSectionOrder(MCAssembler &Asm,
-                                  std::vector<const MCSectionELF*> &Sections) {
-  for (MCAssembler::iterator it = Asm.begin(),
-         ie = Asm.end(); it != ie; ++it) {
-    const MCSectionELF &Section =
-      static_cast<const MCSectionELF &>(it->getSection());
-    if (Section.getType() == ELF::SHT_GROUP)
-      Sections.push_back(&Section);
-  }
-
-  for (MCAssembler::iterator it = Asm.begin(),
-         ie = Asm.end(); it != ie; ++it) {
-    const MCSectionELF &Section =
-      static_cast<const MCSectionELF &>(it->getSection());
-    if (Section.getType() != ELF::SHT_GROUP &&
-        Section.getType() != ELF::SHT_REL &&
-        Section.getType() != ELF::SHT_RELA)
-      Sections.push_back(&Section);
-  }
-
-  for (MCAssembler::iterator it = Asm.begin(),
-         ie = Asm.end(); it != ie; ++it) {
-    const MCSectionELF &Section =
-      static_cast<const MCSectionELF &>(it->getSection());
-    if (Section.getType() == ELF::SHT_REL ||
-        Section.getType() == ELF::SHT_RELA)
-      Sections.push_back(&Section);
+    writeSection(Asm, SectionIndexMap, GroupSymbolIndex, Offsets.first, Size,
+                 SD.getAlignment(), Section);
   }
 }
 
 void ELFObjectWriter::WriteObject(MCAssembler &Asm,
                                   const MCAsmLayout &Layout) {
-  GroupMapTy GroupMap;
   RevGroupMapTy RevGroupMap;
   SectionIndexMapTy SectionIndexMap;
 
   CompressDebugSections(Asm, const_cast<MCAsmLayout &>(Layout));
-  createIndexedSections(Asm, const_cast<MCAsmLayout &>(Layout), GroupMap,
-                        RevGroupMap, SectionIndexMap);
+  std::vector<const MCSectionELF *> Sections;
+  createIndexedSections(Asm, Layout, RevGroupMap, Sections, SectionIndexMap);
 
   // Compute symbol table information.
   computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap);
 
-  WriteRelocations(Asm, const_cast<MCAsmLayout &>(Layout));
+  WriteRelocations(Asm, Layout);
 
-  CreateMetadataSections(const_cast<MCAssembler&>(Asm),
-                         const_cast<MCAsmLayout&>(Layout),
-                         SectionIndexMap);
+  CreateMetadataSections(Asm, Layout, Sections);
 
-  uint64_t NaturalAlignment = is64Bit() ? 8 : 4;
-  uint64_t HeaderSize = is64Bit() ? sizeof(ELF::Elf64_Ehdr) :
-                                    sizeof(ELF::Elf32_Ehdr);
-  uint64_t FileOff = HeaderSize;
-
-  std::vector<const MCSectionELF*> Sections;
-  ComputeSectionOrder(Asm, Sections);
-  unsigned NumSections = Sections.size();
-  SectionOffsetMapTy SectionOffsetMap;
-  for (unsigned i = 0; i < NumSections; ++i) {
+  SectionOffsetsTy SectionOffsets;
 
-    const MCSectionELF &Section = *Sections[i];
-    const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
+  // Write out the ELF header ...
+  writeHeader(Asm);
 
-    FileOff = RoundUpToAlignment(FileOff, SD.getAlignment());
+  // ... then the sections ...
+  SectionOffsets.push_back(std::make_pair(0, 0));
+  for (auto I = ++Sections.begin(), E = Sections.end(); I != E; ++I) {
+    const MCSectionData &SD = Asm.getOrCreateSectionData(**I);
+    uint64_t Padding = OffsetToAlignment(OS.tell(), SD.getAlignment());
+    WriteZeros(Padding);
 
     // Remember the offset into the file for this section.
-    SectionOffsetMap[&Section] = FileOff;
-
-    // Get the size of the section in the output file (including padding).
-    FileOff += GetSectionFileSize(Layout, SD);
+    uint64_t SecStart = OS.tell();
+    writeDataSectionData(Asm, Layout, SD);
+    uint64_t SecEnd = OS.tell();
+    SectionOffsets.push_back(std::make_pair(SecStart, SecEnd));
   }
 
-  FileOff = RoundUpToAlignment(FileOff, NaturalAlignment);
-
-  const unsigned SectionHeaderOffset = FileOff;
-
-  // Write out the ELF header ...
-  WriteHeader(Asm, SectionHeaderOffset, NumSections + 1);
+  {
+    uint64_t SecStart = OS.tell();
+    createStringTable(Asm, Sections);
+    uint64_t SecEnd = OS.tell();
+    SectionOffsets.push_back(std::make_pair(SecStart, SecEnd));
+  }
 
-  // ... then the sections ...
-  for (unsigned i = 0; i < NumSections; ++i)
-    WriteDataSectionData(Asm, Layout, *Sections[i]);
+  {
+    uint64_t SecStart = OS.tell();
+    createSectionHeaderStringTable(Asm, Sections);
+    uint64_t SecEnd = OS.tell();
+    SectionOffsets[0] = std::make_pair(SecStart, SecEnd);
+  }
 
+  uint64_t NaturalAlignment = is64Bit() ? 8 : 4;
   uint64_t Padding = OffsetToAlignment(OS.tell(), NaturalAlignment);
   WriteZeros(Padding);
 
+  const unsigned SectionHeaderOffset = OS.tell();
+
   // ... then the section header table ...
-  writeSectionHeader(Asm, GroupMap, Layout, SectionIndexMap, SectionOffsetMap);
+  writeSectionHeader(Sections, Asm, Layout, SectionIndexMap, SectionOffsets);
+
+  uint16_t NumSections = (Sections.size() + 1 >= ELF::SHN_LORESERVE)
+                             ? ELF::SHN_UNDEF
+                             : Sections.size() + 1;
+  if (sys::IsLittleEndianHost != IsLittleEndian)
+    sys::swapByteOrder(NumSections);
+  unsigned NumSectionsOffset;
+
+  if (is64Bit()) {
+    uint64_t Val = SectionHeaderOffset;
+    if (sys::IsLittleEndianHost != IsLittleEndian)
+      sys::swapByteOrder(Val);
+    OS.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
+              offsetof(ELF::Elf64_Ehdr, e_shoff));
+    NumSectionsOffset = offsetof(ELF::Elf64_Ehdr, e_shnum);
+  } else {
+    uint32_t Val = SectionHeaderOffset;
+    if (sys::IsLittleEndianHost != IsLittleEndian)
+      sys::swapByteOrder(Val);
+    OS.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
+              offsetof(ELF::Elf32_Ehdr, e_shoff));
+    NumSectionsOffset = offsetof(ELF::Elf32_Ehdr, e_shnum);
+  }
+  OS.pwrite(reinterpret_cast<char *>(&NumSections), sizeof(NumSections),
+            NumSectionsOffset);
 }
 
 bool ELFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(
-    const MCAssembler &Asm, const MCSymbolData &DataA,
-    const MCSymbolData *DataB, const MCFragment &FB, bool InSet,
-    bool IsPCRel) const {
-  if (!InSet && (::isWeak(DataA) || (DataB && ::isWeak(*DataB))))
-    return false;
-  return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(
-      Asm, DataA, DataB, FB, InSet, IsPCRel);
+    const MCAssembler &Asm, const MCSymbolData &DataA, const MCFragment &FB,
+    bool InSet, bool IsPCRel) const {
+  if (IsPCRel) {
+    assert(!InSet);
+    if (::isWeak(DataA))
+      return false;
+  }
+  return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(Asm, DataA, FB,
+                                                                InSet, IsPCRel);
 }
 
 bool ELFObjectWriter::isWeak(const MCSymbolData &SD) const {
-  return ::isWeak(SD);
+  if (::isWeak(SD))
+    return true;
+
+  // It is invalid to replace a reference to a global in a comdat
+  // with a reference to a local since out of comdat references
+  // to a local are forbidden.
+  // We could try to return false for more cases, like the reference
+  // being in the same comdat or Sym being an alias to another global,
+  // but it is not clear if it is worth the effort.
+  if (MCELF::GetBinding(SD) != ELF::STB_GLOBAL)
+    return false;
+
+  const MCSymbol &Sym = SD.getSymbol();
+  if (!Sym.isInSection())
+    return false;
+
+  const auto &Sec = cast<MCSectionELF>(Sym.getSection());
+  return Sec.getGroup();
 }
 
 MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW,
-                                            raw_ostream &OS,
+                                            raw_pwrite_stream &OS,
                                             bool IsLittleEndian) {
   return new ELFObjectWriter(MOTW, OS, IsLittleEndian);
 }