[lld] r259516 - Expand comment a bit.

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 2 08:00:02 PST 2016


On 2 February 2016 at 10:45, Rafael Espindola via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: rafael
> Date: Tue Feb  2 09:45:37 2016
> New Revision: 259516
>
> URL: http://llvm.org/viewvc/llvm-project?rev=259516&view=rev
> Log:
> Expand comment a bit.
>
> I have spent some time prototyping this idea. While it seems to work, I
> now think it is probably not worth it.

In case anyone is interested this is what the currently very broken
patch looks like.

I might come back to it at some point, but for now I will explore some
other options for simplifying the relocation code.

Cheers,
Rafael
-------------- next part --------------
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index d5ff181..f6c8f8d 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -14,6 +14,8 @@
 #include "OutputSections.h"
 #include "Target.h"
 
+#include "llvm/Support/raw_ostream.h"
+
 using namespace llvm;
 using namespace llvm::ELF;
 using namespace llvm::object;
@@ -212,6 +214,12 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
                               getAddend<ELFT>(RI));
       continue;
     }
+    bool NeedsGot = Target->needsGot(Type, *Body);
+    bool CBP = canBePreempted(Body, NeedsGot);
+    bool NoDynrel = Target->isRelRelative(Type) || Target->isSizeRel(Type) ||
+                    !Config->Shared;
+    if (CBP || !NoDynrel)
+      Out<ELFT>::RelaDyn->addReloc({this, &RI});
 
     uintX_t SymVA = Body->getVA<ELFT>();
     if (Target->needsPlt(Type, *Body)) {
@@ -249,22 +257,20 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
   }
 }
 
-template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT> void InputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
   if (this->Header->sh_type == SHT_NOBITS)
     return;
+
+  uint32_t Align = this->getAlign();
+  uint64_t P = OS.tell();
+  uint64_t PAlign = alignTo(P, Align);
+  uint64_t Padding = PAlign - P;
+  for (uint64_t I = 0; I < Padding; ++I)
+    OS.write('\0');
+
   // Copy section contents from source object file to output file.
   ArrayRef<uint8_t> Data = this->getSectionData();
-  memcpy(Buf + OutSecOff, Data.data(), Data.size());
-
-  ELFFile<ELFT> &EObj = this->File->getObj();
-  uint8_t *BufEnd = Buf + OutSecOff + Data.size();
-  // Iterate over all relocation sections that apply to this section.
-  for (const Elf_Shdr *RelSec : this->RelocSections) {
-    if (RelSec->sh_type == SHT_RELA)
-      this->relocate(Buf, BufEnd, EObj.relas(RelSec));
-    else
-      this->relocate(Buf, BufEnd, EObj.rels(RelSec));
-  }
+  OS.write(reinterpret_cast<const char *>(Data.data()), Data.size());
 }
 
 template <class ELFT>
@@ -382,6 +388,23 @@ template class elf2::InputSectionBase<ELF32BE>;
 template class elf2::InputSectionBase<ELF64LE>;
 template class elf2::InputSectionBase<ELF64BE>;
 
+template void InputSectionBase<ELF32LE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                                  RelIteratorRange<false> Rels);
+template void InputSectionBase<ELF32LE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                                  RelIteratorRange<true> Rels);
+template void InputSectionBase<ELF32BE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                                  RelIteratorRange<false> Rels);
+template void InputSectionBase<ELF32BE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                                  RelIteratorRange<true> Rels);
+template void InputSectionBase<ELF64LE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                                  RelIteratorRange<false> Rels);
+template void InputSectionBase<ELF64LE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                                  RelIteratorRange<true> Rels);
+template void InputSectionBase<ELF64BE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                                  RelIteratorRange<false> Rels);
+template void InputSectionBase<ELF64BE>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                                  RelIteratorRange<true> Rels);
+
 template class elf2::InputSection<ELF32LE>;
 template class elf2::InputSection<ELF32BE>;
 template class elf2::InputSection<ELF64LE>;
@@ -401,3 +424,4 @@ template class elf2::MipsReginfoInputSection<ELF32LE>;
 template class elf2::MipsReginfoInputSection<ELF32BE>;
 template class elf2::MipsReginfoInputSection<ELF64LE>;
 template class elf2::MipsReginfoInputSection<ELF64BE>;
+
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 26956c7..673b665 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -14,6 +14,10 @@
 #include "lld/Core/LLVM.h"
 #include "llvm/Object/ELF.h"
 
+namespace llvm {
+class raw_fd_ostream;
+}
+
 namespace lld {
 namespace elf2 {
 
@@ -157,7 +161,7 @@ public:
 
   // Write this section to a mmap'ed file, assuming Buf is pointing to
   // beginning of the output section.
-  void writeTo(uint8_t *Buf);
+  void writeTo(llvm::raw_fd_ostream &OS);
 
   // Relocation sections that refer to this one.
   SmallVector<const Elf_Shdr *, 1> RelocSections;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 14194f7..e56a017 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -12,7 +12,9 @@
 #include "SymbolTable.h"
 #include "Target.h"
 #include "llvm/Support/Dwarf.h"
+#include "llvm/Support/EndianStream.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
 #include <map>
 
 using namespace llvm;
@@ -33,6 +35,16 @@ OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type,
 }
 
 template <class ELFT>
+void OutputSectionBase<ELFT>::align(llvm::raw_fd_ostream &OS) {
+  uint64_t A = OS.tell();
+  uint64_t B = getFileOff();
+  assert(B >= A);
+  B-= A;
+  while (B--)
+    OS.write('\0');
+}
+
+template <class ELFT>
 GotPltSection<ELFT>::GotPltSection()
     : OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
   this->Header.sh_addralign = sizeof(uintX_t);
@@ -52,13 +64,11 @@ template <class ELFT> void GotPltSection<ELFT>::finalize() {
       (Target->GotPltHeaderEntriesNum + Entries.size()) * sizeof(uintX_t);
 }
 
-template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
-  Target->writeGotPltHeader(Buf);
-  Buf += Target->GotPltHeaderEntriesNum * sizeof(uintX_t);
-  for (const SymbolBody *B : Entries) {
-    Target->writeGotPlt(Buf, B->getPltVA<ELFT>());
-    Buf += sizeof(uintX_t);
-  }
+template <class ELFT> void GotPltSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
+  Target->writeGotPltHeader(OS);
+  for (const SymbolBody *B : Entries)
+    Target->writeGotPlt(OS, B->getPltVA<ELFT>());
 }
 
 template <class ELFT>
@@ -142,28 +152,31 @@ template <class ELFT> void GotSection<ELFT>::finalize() {
       sizeof(uintX_t);
 }
 
-template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
-  Target->writeGotHeader(Buf);
-  for (const auto &L : MipsLocalGotPos) {
-    uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
-    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
-  }
-  Buf += Target->GotHeaderEntriesNum * sizeof(uintX_t);
-  Buf += MipsLocalEntries * sizeof(uintX_t);
+template <class ELFT> void GotSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  Writer<ELFT::TargetEndianness> W(OS);
+  this->align(OS);
+
+  Target->writeGotHeader(OS);
+  std::vector<uintX_t> EntriesVal;
+  EntriesVal.resize(MipsLocalEntries);
+  for (const auto &L : MipsLocalGotPos)
+    EntriesVal[L.second - 2 ] = L.first;
+  W.template write<uintX_t>(EntriesVal);
   for (const SymbolBody *B : Entries) {
-    uint8_t *Entry = Buf;
-    Buf += sizeof(uintX_t);
-    if (!B)
+    if (!B) {
+      W. write((uintX_t)0);
       continue;
+    }
     // MIPS has special rules to fill up GOT entries.
     // See "Global Offset Table" in Chapter 5 in the following document
     // for detailed description:
     // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
     // As the first approach, we can just store addresses for all symbols.
-    if (Config->EMachine != EM_MIPS && canBePreempted(B, false))
+    if (Config->EMachine != EM_MIPS && canBePreempted(B, false)) {
+      W. write((uintX_t)0);
       continue; // The dynamic linker will take care of it.
-    uintX_t VA = B->getVA<ELFT>();
-    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
+    }
+    W. write( (uintX_t)B->getVA<ELFT>());
   }
 }
 
@@ -173,11 +186,13 @@ PltSection<ELFT>::PltSection()
   this->Header.sh_addralign = 16;
 }
 
-template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT> void PltSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
+
   size_t Off = 0;
   if (Target->UseLazyBinding) {
     // First write PLT[0] entry which is special.
-    Target->writePltZero(Buf);
+    Target->writePltZero(OS);
     Off += Target->PltZeroSize;
   }
   for (auto &I : Entries) {
@@ -186,7 +201,7 @@ template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
     uint64_t Got =
         Target->UseLazyBinding ? B->getGotPltVA<ELFT>() : B->getGotVA<ELFT>();
     uint64_t Plt = this->getVA() + Off;
-    Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
+    Target->writePlt(OS, Got, Plt, B->PltIndex, RelOff);
     Off += Target->PltEntrySize;
   }
 }
@@ -216,11 +231,15 @@ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool IsRela)
 // Returns true if relocation was handled.
 template <class ELFT>
 bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body,
-                                                   uint32_t Type, Elf_Rel *P,
-                                                   Elf_Rel *N) {
+                                                   uint32_t Type,
+                                                   raw_fd_ostream &OS) {
+  Elf_Rela P{};
+  unsigned Size = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+
   if (Target->isTlsLocalDynamicRel(Type)) {
-    P->setSymbolAndType(0, Target->TlsModuleIndexRel, Config->Mips64EL);
-    P->r_offset = Out<ELFT>::Got->getLocalTlsIndexVA();
+    P.setSymbolAndType(0, Target->TlsModuleIndexRel, Config->Mips64EL);
+    P.r_offset = Out<ELFT>::Got->getLocalTlsIndexVA();
+    OS.write(reinterpret_cast<const char*>(&P), Size);
     return true;
   }
 
@@ -228,26 +247,30 @@ bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body,
     return false;
 
   if (Target->canRelaxTls(Type, Body)) {
-    P->setSymbolAndType(Body->DynsymIndex, Target->getTlsGotRel(),
+    P.setSymbolAndType(Body->DynsymIndex, Target->getTlsGotRel(),
                         Config->Mips64EL);
-    P->r_offset = Body->getGotVA<ELFT>();
+    P.r_offset = Body->getGotVA<ELFT>();
+    OS.write(reinterpret_cast<const char*>(&P), Size);
     return true;
   }
 
-  P->setSymbolAndType(Body->DynsymIndex, Target->TlsModuleIndexRel,
+  P.setSymbolAndType(Body->DynsymIndex, Target->TlsModuleIndexRel,
                       Config->Mips64EL);
-  P->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body);
-  N->setSymbolAndType(Body->DynsymIndex, Target->TlsOffsetRel,
+  P.r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body);
+  OS.write(reinterpret_cast<const char*>(&P), Size);
+  P.setSymbolAndType(Body->DynsymIndex, Target->TlsOffsetRel,
                       Config->Mips64EL);
-  N->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t);
+  P.r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t);
+  OS.write(reinterpret_cast<const char*>(&P), Size);
   return true;
 }
 
-template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
-  for (const DynamicReloc<ELFT> &Rel : Relocs) {
-    auto *P = reinterpret_cast<Elf_Rel *>(Buf);
-    Buf += IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+template <class ELFT>
+void RelocationSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
 
+  Writer<ELFT::TargetEndianness> W(OS);
+  for (const DynamicReloc<ELFT> &Rel : Relocs) {
     // Skip placeholder for global dynamic TLS relocation pair. It was already
     // handled by the previous relocation.
     if (!Rel.C)
@@ -262,22 +285,26 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
       Body = Body->repl();
 
     uint32_t Type = RI.getType(Config->Mips64EL);
-    if (applyTlsDynamicReloc(Body, Type, P, reinterpret_cast<Elf_Rel *>(Buf)))
+    if (applyTlsDynamicReloc(Body, Type, OS))
       continue;
 
+    Elf_Rela P{};
+    unsigned Size = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
     // Writer::scanRelocs creates a RELATIVE reloc for some type of TLS reloc.
     // We want to write it down as is.
     if (Type == Target->RelativeRel) {
-      P->setSymbolAndType(0, Type, Config->Mips64EL);
-      P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
+      P.setSymbolAndType(0, Type, Config->Mips64EL);
+      P.r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
+      OS.write(reinterpret_cast<const char*>(&P), Size);
       continue;
     }
 
     // Emit a copy relocation.
     auto *SS = dyn_cast_or_null<SharedSymbol<ELFT>>(Body);
     if (SS && SS->NeedsCopy) {
-      P->setSymbolAndType(Body->DynsymIndex, Target->CopyRel, Config->Mips64EL);
-      P->r_offset = Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
+      P.setSymbolAndType(Body->DynsymIndex, Target->CopyRel, Config->Mips64EL);
+      P.r_offset = Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
+      OS.write(reinterpret_cast<const char*>(&P), Size);
       continue;
     }
 
@@ -289,11 +316,12 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
     // the usual JUMP_SLOT reloc for the GOT entry. For the details, you
     // want to read http://www.airs.com/blog/archives/403
     if (!CBP && Body && isGnuIFunc<ELFT>(*Body)) {
-      P->setSymbolAndType(0, Target->IRelativeRel, Config->Mips64EL);
+      P.setSymbolAndType(0, Target->IRelativeRel, Config->Mips64EL);
       if (Out<ELFT>::GotPlt)
-        P->r_offset = Body->getGotPltVA<ELFT>();
+        P.r_offset = Body->getGotPltVA<ELFT>();
       else
-        P->r_offset = Body->getGotVA<ELFT>();
+        P.r_offset = Body->getGotVA<ELFT>();
+      OS.write(reinterpret_cast<const char*>(&P), Size);
       continue;
     }
 
@@ -309,27 +337,26 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
       Reloc = Body->isTls() ? Target->getTlsGotRel() : Target->GotRel;
     else
       Reloc = Target->getDynRel(Type);
-    P->setSymbolAndType(CBP ? Body->DynsymIndex : 0, Reloc, Config->Mips64EL);
+    P.setSymbolAndType(CBP ? Body->DynsymIndex : 0, Reloc, Config->Mips64EL);
 
     if (LazyReloc)
-      P->r_offset = Body->getGotPltVA<ELFT>();
+      P.r_offset = Body->getGotPltVA<ELFT>();
     else if (NeedsGot)
-      P->r_offset = Body->getGotVA<ELFT>();
+      P.r_offset = Body->getGotVA<ELFT>();
     else
-      P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
-
-    if (!IsRela)
-      continue;
-
-    auto R = static_cast<const Elf_Rela &>(RI);
-    auto S = static_cast<Elf_Rela *>(P);
-    uintX_t A = NeedsGot ? 0 : R.r_addend;
-    if (CBP)
-      S->r_addend = A;
-    else if (Body)
-      S->r_addend = Body->getVA<ELFT>() + A;
-    else
-      S->r_addend = getLocalRelTarget(File, R, A);
+      P.r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
+
+    if (IsRela ) {
+      auto R = static_cast<const Elf_Rela &>(RI);
+      uintX_t A = NeedsGot ? 0 : R.r_addend;
+      if (CBP)
+        P.r_addend = A;
+      else if (Body)
+        P.r_addend = Body->getVA<ELFT>() + A;
+      else
+        P.r_addend = getLocalRelTarget(File, R, A);
+    }
+    OS.write(reinterpret_cast<const char*>(&P), Size);
   }
 }
 
@@ -352,12 +379,13 @@ InterpSection<ELFT>::InterpSection()
 }
 
 template <class ELFT>
-void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
-  *SHdr = Header;
+void OutputSectionBase<ELFT>::writeHeaderTo(raw_fd_ostream &OS) {
+  OS.write(reinterpret_cast<const char*>(&Header), sizeof(Header));
 }
 
-template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) {
-  memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size());
+template <class ELFT> void InterpSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
+  OS.write(Config->DynamicLinker.data(), Config->DynamicLinker.size());
 }
 
 template <class ELFT>
@@ -392,14 +420,19 @@ template <class ELFT> void HashTableSection<ELFT>::finalize() {
   this->Header.sh_size = NumEntries * sizeof(Elf_Word);
 }
 
-template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
-  unsigned NumSymbols = Out<ELFT>::DynSymTab->getNumSymbols();
-  auto *P = reinterpret_cast<Elf_Word *>(Buf);
-  *P++ = NumSymbols; // nbucket
-  *P++ = NumSymbols; // nchain
+template <class ELFT> void HashTableSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
+  Elf_Word NumSymbols = (Elf_Word) Out<ELFT>::DynSymTab->getNumSymbols();
+  // FIXME: a templated write would be nice.
+  OS.write(reinterpret_cast<const char *>(&NumSymbols),
+           sizeof(NumSymbols));              // nbucket
+  OS.write(reinterpret_cast<const char *>(&NumSymbols),
+           sizeof(NumSymbols)); // nchain
 
-  Elf_Word *Buckets = P;
-  Elf_Word *Chains = P + NumSymbols;
+  std::vector<Elf_Word> Buckets;
+  std::vector<Elf_Word> Chains;
+  Buckets.resize(NumSymbols);
+  Chains.resize(NumSymbols);
 
   for (const std::pair<SymbolBody *, unsigned> &P :
        Out<ELFT>::DynSymTab->getSymbols()) {
@@ -410,6 +443,10 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
     Chains[I] = Buckets[Hash];
     Buckets[Hash] = I;
   }
+  OS.write(reinterpret_cast<const char *>(Buckets.data()),
+           NumSymbols * sizeof(Elf_Word));
+  OS.write(reinterpret_cast<const char *>(Chains.data()),
+           NumSymbols * sizeof(Elf_Word));
 }
 
 static uint32_t hashGnu(StringRef Name) {
@@ -474,42 +511,49 @@ template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
                          + sizeof(Elf_Word) * NumHashed; // Hash Values
 }
 
-template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
-  writeHeader(Buf);
+template <class ELFT>
+void GnuHashTableSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  writeHeader(OS);
   if (HashedSymbols.empty())
     return;
-  writeBloomFilter(Buf);
-  writeHashTable(Buf);
+  writeBloomFilter(OS);
+  writeHashTable(OS);
 }
 
 template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
-  auto *P = reinterpret_cast<Elf_Word *>(Buf);
-  *P++ = NBuckets;
-  *P++ = Out<ELFT>::DynSymTab->getNumSymbols() - HashedSymbols.size();
-  *P++ = MaskWords;
-  *P++ = Shift2;
-  Buf = reinterpret_cast<uint8_t *>(P);
+void GnuHashTableSection<ELFT>::writeHeader(raw_fd_ostream &OS) {
+  Writer<ELFT::TargetEndianness> W(OS);
+
+  W.write(uint32_t(NBuckets));
+  W.write(
+      uint32_t(Out<ELFT>::DynSymTab->getNumSymbols() - HashedSymbols.size()));
+  W.write(uint32_t(MaskWords));
+  W.write(uint32_t(Shift2));
 }
 
 template <class ELFT>
-void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
+void GnuHashTableSection<ELFT>::writeBloomFilter(raw_fd_ostream &OS) {
   unsigned C = sizeof(Elf_Off) * 8;
 
-  auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
+  std::vector<Elf_Off> Masks;
+  Masks.resize(MaskWords);
   for (const HashedSymbolData &Item : HashedSymbols) {
     size_t Pos = (Item.Hash / C) & (MaskWords - 1);
     uintX_t V = (uintX_t(1) << (Item.Hash % C)) |
                 (uintX_t(1) << ((Item.Hash >> Shift2) % C));
     Masks[Pos] |= V;
   }
-  Buf += sizeof(Elf_Off) * MaskWords;
+  OS.write(reinterpret_cast<const char *>(Masks.data()),
+           Masks.size() * sizeof(Elf_Off));
 }
 
 template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
-  Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf);
-  Elf_Word *Values = Buckets + NBuckets;
+void GnuHashTableSection<ELFT>::writeHashTable(raw_fd_ostream &OS) {
+  std::vector<Elf_Word> Buckets;
+  Buckets.resize(NBuckets);
+
+  std::vector<Elf_Word> Values;
+  Values.resize(HashedSymbols.size());
 
   int PrevBucket = -1;
   int I = 0;
@@ -527,6 +571,11 @@ void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
   }
   if (I > 0)
     Values[I - 1] |= 1;
+
+  OS.write(reinterpret_cast<const char *>(Buckets.data()),
+           Buckets.size() * sizeof(Elf_Word));
+  OS.write(reinterpret_cast<const char *>(Values.data()),
+           Values.size() * sizeof(Elf_Word));
 }
 
 static bool includeInGnuHashTable(SymbolBody *B) {
@@ -684,23 +733,23 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
   Header.sh_size = (Entries.size() + 1) * Header.sh_entsize;
 }
 
-template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
-  auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
+template <class ELFT> void DynamicSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
+  Writer<ELFT::TargetEndianness> W(OS);
 
   for (const Entry &E : Entries) {
-    P->d_tag = E.Tag;
+    W.write((uintX_t)E.Tag);
     switch (E.Kind) {
     case Entry::SecAddr:
-      P->d_un.d_ptr = E.OutSec->getVA();
+      W.write((uintX_t)E.OutSec->getVA());
       break;
     case Entry::SymAddr:
-      P->d_un.d_ptr = E.Sym->template getVA<ELFT>();
+      W.write((uintX_t)E.Sym->template getVA<ELFT>());
       break;
     case Entry::PlainInt:
-      P->d_un.d_val = E.Val;
+      W.write((uintX_t)E.Val);
       break;
     }
-    ++P;
   }
 }
 
@@ -743,20 +792,19 @@ EhFrameHeader<ELFT>::getFdePc(uintX_t EhVA, const FdeData &F) {
   fatal("unknown FDE size encoding");
 }
 
-template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
-  const endianness E = ELFT::TargetEndianness;
+template <class ELFT> void EhFrameHeader<ELFT>::writeTo(raw_fd_ostream &OS) {
+  Writer<ELFT::TargetEndianness> W(OS);
+  this->align(OS);
 
-  const uint8_t Header[] = {1, dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4,
-                            dwarf::DW_EH_PE_udata4,
-                            dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4};
-  memcpy(Buf, Header, sizeof(Header));
+  W.template write<uint8_t>({1, dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4,
+                             dwarf::DW_EH_PE_udata4,
+                             dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4});
 
   uintX_t EhVA = Sec->getVA();
   uintX_t VA = this->getVA();
   uintX_t EhOff = EhVA - VA - 4;
-  write32<E>(Buf + 4, EhOff);
-  write32<E>(Buf + 8, this->FdeList.size());
-  Buf += 12;
+  W.template write<uint32_t>(EhOff);
+  W.template write<uint32_t>(this->FdeList.size());
 
   // InitialPC -> Offset in .eh_frame, sorted by InitialPC.
   std::map<uintX_t, size_t> PcToOffset;
@@ -765,10 +813,9 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
 
   for (auto &I : PcToOffset) {
     // The first four bytes are an offset to the initial PC value for the FDE.
-    write32<E>(Buf, I.first - VA);
+    W.template write<uint32_t>(I.first - VA);
     // The last four bytes are an offset to the FDE data itself.
-    write32<E>(Buf + 4, EhVA + I.second - VA);
-    Buf += 8;
+    W.template write<uint32_t>(EhVA + I.second - VA);
   }
 }
 
@@ -898,9 +945,28 @@ bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) {
   return Body->getVisibility() == STV_DEFAULT;
 }
 
-template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT> void OutputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
   for (InputSection<ELFT> *C : Sections)
-    C->writeTo(Buf);
+    C->writeTo(OS);
+}
+
+template <class ELFT> void OutputSection<ELFT>::relocate(uint8_t *Buf) {
+  Buf = Buf + this->getFileOff();
+
+  if (this == Out<ELFT>::Opd)
+    Out<ELFT>::OpdBuf = Buf;
+
+  for (InputSection<ELFT> *S : Sections) {
+    uint8_t *BufEnd = Buf + S->OutSecOff + S->getSize();
+    ELFFile<ELFT> &EObj = S->getFile()->getObj();
+    for (const Elf_Shdr *RelSec : S->RelocSections) {
+      if (RelSec->sh_type == SHT_RELA)
+        S->relocate(Buf, BufEnd, EObj.relas(RelSec));
+      else
+        S->relocate(Buf, BufEnd, EObj.rels(RelSec));
+    }
+  }
 }
 
 template <class ELFT>
@@ -1145,45 +1211,61 @@ void EHOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
 }
 
 template <class ELFT>
-static typename ELFFile<ELFT>::uintX_t writeAlignedCieOrFde(StringRef Data,
-                                                            uint8_t *Buf) {
+static typename ELFFile<ELFT>::uintX_t
+writeAlignedCieOrFde(StringRef Data, uint32_t CIEPointer, raw_fd_ostream &OS) {
   typedef typename ELFFile<ELFT>::uintX_t uintX_t;
-  const endianness E = ELFT::TargetEndianness;
   uint64_t Len = alignTo(Data.size(), sizeof(uintX_t));
-  write32<E>(Buf, Len - 4);
-  memcpy(Buf + 4, Data.data() + 4, Data.size() - 4);
+  unsigned Pad = Len - Data.size();
+  support::ulittle32_t V(Len - 4);
+  OS.write(reinterpret_cast<const char *>(&V), sizeof(V));
+  support::ulittle32_t V2(CIEPointer);
+  OS.write(reinterpret_cast<const char *>(&V2), sizeof(V2));
+  OS.write(Data.data() + 8, Data.size() - 8);
+  for (unsigned I = 0; I < Pad; ++I)
+    OS.write('\0');
   return Len;
 }
 
-template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) {
-  const endianness E = ELFT::TargetEndianness;
+template <class ELFT> void EHOutputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
   size_t Offset = 0;
   for (const Cie<ELFT> &C : Cies) {
     size_t CieOffset = Offset;
 
-    uintX_t CIELen = writeAlignedCieOrFde<ELFT>(C.data(), Buf + Offset);
+    uintX_t CIELen = writeAlignedCieOrFde<ELFT>(C.data(), 0, OS);
     C.S->Offsets[C.Index].second = Offset;
     Offset += CIELen;
 
     for (const EHRegion<ELFT> &F : C.Fdes) {
-      uintX_t Len = writeAlignedCieOrFde<ELFT>(F.data(), Buf + Offset);
-      write32<E>(Buf + Offset + 4, Offset + 4 - CieOffset); // Pointer
+      uintX_t Len =
+          writeAlignedCieOrFde<ELFT>(F.data(), Offset + 4 - CieOffset, OS);
       F.S->Offsets[F.Index].second = Offset;
-      Out<ELFT>::EhFrameHdr->addFde(C.FdeEncoding, Offset, Buf + Offset + 8);
       Offset += Len;
     }
   }
+}
+
+template <class ELFT> void EHOutputSection<ELFT>::relocate(uint8_t *Buf) {
+  Buf = Buf + this->getFileOff();
 
   for (EHInputSection<ELFT> *S : Sections) {
+    ELFFile<ELFT> &EObj = S->getFile()->getObj();
     const Elf_Shdr *RelSec = S->RelocSection;
     if (!RelSec)
       continue;
-    ELFFile<ELFT> &EObj = S->getFile()->getObj();
     if (RelSec->sh_type == SHT_RELA)
       S->relocate(Buf, nullptr, EObj.relas(RelSec));
     else
       S->relocate(Buf, nullptr, EObj.rels(RelSec));
   }
+  if (!Config->EhFrameHdr)
+    return;
+  for (const Cie<ELFT> &C : Cies) {
+    for (const EHRegion<ELFT> &F : C.Fdes) {
+      auto Offset = F.S->Offsets[F.Index].second;
+      Out<ELFT>::EhFrameHdr->addFde(C.FdeEncoding, Offset, Buf + Offset + 8);
+    }
+  }
 }
 
 template <class ELFT>
@@ -1191,15 +1273,23 @@ MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
                                              uintX_t Flags)
     : OutputSectionBase<ELFT>(Name, Type, Flags) {}
 
-template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT>
+void MergeOutputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->  align(OS);
   if (shouldTailMerge()) {
     StringRef Data = Builder.data();
-    memcpy(Buf, Data.data(), Data.size());
+    OS.write(Data.data(), Data.size());
     return;
   }
-  for (const std::pair<StringRef, size_t> &P : Builder.getMap()) {
+  std::vector<std::pair<StringRef, size_t> > Entries;
+  const auto &Map = Builder.getMap();
+  Entries.reserve(Map.size());
+  for (const std::pair<StringRef, size_t> &P : Map)
+    Entries.push_back(P);
+  std::sort(Entries.begin(), Entries.end(), [&](std::pair<StringRef, size_t> &A, std::pair<StringRef, size_t> &B) {return A.second < B.second;});
+  for (const std::pair<StringRef, size_t> &P : Entries) {
     StringRef Data = P.first;
-    memcpy(Buf + P.second, Data.data(), Data.size());
+    OS.write(Data.data(), Data.size());
   }
 }
 
@@ -1293,12 +1383,14 @@ unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
   return Ret;
 }
 
-template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
-  // ELF string tables start with NUL byte, so advance the pointer by one.
-  ++Buf;
+template <class ELFT>
+void StringTableSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  // ELF string tables start with NUL byte.
+  this->align(OS);
+  OS << '\0';
   for (StringRef S : Strings) {
-    memcpy(Buf, S.data(), S.size());
-    Buf += S.size() + 1;
+    OS << S;
+    OS << '\0';
   }
 }
 
@@ -1358,45 +1450,49 @@ void SymbolTableSection<ELFT>::addSymbol(SymbolBody *Body) {
       std::make_pair(Body, StrTabSec.addString(Body->getName(), false)));
 }
 
-template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
-  Buf += sizeof(Elf_Sym);
+template <class ELFT>
+void SymbolTableSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
+  // First entry is null.
+  Elf_Sym S{};
+  OS.write(reinterpret_cast<const char *>(&S), sizeof(S));
 
   // All symbols with STB_LOCAL binding precede the weak and global symbols.
   // .dynsym only contains global symbols.
   if (!Config->DiscardAll && !StrTabSec.isDynamic())
-    writeLocalSymbols(Buf);
+    writeLocalSymbols(OS);
 
-  writeGlobalSymbols(Buf);
+  writeGlobalSymbols(OS);
 }
 
 template <class ELFT>
-void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
+void SymbolTableSection<ELFT>::writeLocalSymbols(raw_fd_ostream &OS) {
   // Iterate over all input object files to copy their local symbols
   // to the output symbol table pointed by Buf.
   for (const std::unique_ptr<ObjectFile<ELFT>> &File : Table.getObjectFiles()) {
     for (const std::pair<const Elf_Sym *, unsigned> &P : File->KeptLocalSyms) {
       const Elf_Sym *Sym = P.first;
-
-      auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
       uintX_t VA = 0;
+
+      Elf_Sym ESym{};
       if (Sym->st_shndx == SHN_ABS) {
-        ESym->st_shndx = SHN_ABS;
+        ESym.st_shndx = SHN_ABS;
         VA = Sym->st_value;
       } else {
         InputSectionBase<ELFT> *Section = File->getSection(*Sym);
         const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
-        ESym->st_shndx = OutSec->SectionIndex;
+        ESym.st_shndx = OutSec->SectionIndex;
         VA = Section->getOffset(*Sym);
         // Symbol offsets for AMDGPU need to be the offset in bytes of the
         // symbol from the beginning of the section.
         if (Config->EMachine != EM_AMDGPU)
           VA += OutSec->getVA();
       }
-      ESym->st_name = P.second;
-      ESym->st_size = Sym->st_size;
-      ESym->setBindingAndType(Sym->getBinding(), Sym->getType());
-      ESym->st_value = VA;
-      Buf += sizeof(*ESym);
+      ESym.st_name = P.second;
+      ESym.st_size = Sym->st_size;
+      ESym.setBindingAndType(Sym->getBinding(), Sym->getType());
+      ESym.st_value = VA;
+      OS.write(reinterpret_cast<const char*>(&ESym), sizeof(ESym));
     }
   }
 }
@@ -1412,10 +1508,9 @@ getElfSym(SymbolBody &Body) {
 }
 
 template <class ELFT>
-void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
+void SymbolTableSection<ELFT>::writeGlobalSymbols(raw_fd_ostream &OS) {
   // Write the internal symbol table contents to the output symbol table
   // pointed by Buf.
-  auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
   for (const std::pair<SymbolBody *, unsigned> &P : Symbols) {
     SymbolBody *Body = P.first;
     const OutputSectionBase<ELFT> *OutSec = nullptr;
@@ -1447,7 +1542,9 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
       break;
     }
 
-    ESym->st_name = P.second;
+    Elf_Sym ESym{};
+
+    ESym.st_name = P.second;
 
     unsigned char Type = STT_NOTYPE;
     uintX_t Size = 0;
@@ -1459,17 +1556,16 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
       Size = C->Size;
     }
 
-    ESym->setBindingAndType(getSymbolBinding(Body), Type);
-    ESym->st_size = Size;
-    ESym->setVisibility(Body->getVisibility());
-    ESym->st_value = Body->getVA<ELFT>();
+    ESym.setBindingAndType(getSymbolBinding(Body), Type);
+    ESym.st_size = Size;
+    ESym.setVisibility(Body->getVisibility());
+    ESym.st_value = Body->getVA<ELFT>();
 
     if (OutSec)
-      ESym->st_shndx = OutSec->SectionIndex;
+      ESym.st_shndx = OutSec->SectionIndex;
     else if (isa<DefinedRegular<ELFT>>(Body))
-      ESym->st_shndx = SHN_ABS;
-
-    ++ESym;
+      ESym.st_shndx = SHN_ABS;
+    OS.write(reinterpret_cast<const char*>(&ESym), sizeof(ESym));
   }
 }
 
@@ -1494,10 +1590,13 @@ MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
 }
 
 template <class ELFT>
-void MipsReginfoOutputSection<ELFT>::writeTo(uint8_t *Buf) {
-  auto *R = reinterpret_cast<Elf_Mips_RegInfo *>(Buf);
-  R->ri_gp_value = getMipsGpAddr<ELFT>();
-  R->ri_gprmask = GprMask;
+void MipsReginfoOutputSection<ELFT>::writeTo(raw_fd_ostream &OS) {
+  this->align(OS);
+
+  Elf_Mips_RegInfo R{};
+  R.ri_gp_value = getMipsGpAddr<ELFT>();
+  R.ri_gprmask = GprMask;
+  OS.write(reinterpret_cast<const char*>(&R), sizeof(R));
 }
 
 template <class ELFT>
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 7045720..5104bfe 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -19,6 +19,10 @@
 
 #include <type_traits>
 
+namespace llvm {
+class raw_fd_ostream;
+}
+
 namespace lld {
 namespace elf2 {
 
@@ -70,7 +74,7 @@ public:
   uintX_t getVA() const { return Header.sh_addr; }
   void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
   void setSHName(unsigned Val) { Header.sh_name = Val; }
-  void writeHeaderTo(Elf_Shdr *SHdr);
+  void writeHeaderTo(llvm::raw_fd_ostream &OS);
   StringRef getName() { return Name; }
 
   virtual void addSection(InputSectionBase<ELFT> *C) {}
@@ -94,10 +98,12 @@ public:
   }
 
   virtual void finalize() {}
-  virtual void writeTo(uint8_t *Buf) = 0;
+  virtual void writeTo(llvm::raw_fd_ostream &OS) = 0;
+  virtual void relocate(uint8_t *Buf) {}
   virtual ~OutputSectionBase() = default;
 
 protected:
+  void align(llvm::raw_fd_ostream &OS);
   StringRef Name;
   Elf_Shdr Header;
 };
@@ -109,7 +115,7 @@ template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {
 public:
   GotSection();
   void finalize() override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
   void addEntry(SymbolBody *Sym);
   void addMipsLocalEntry();
   bool addDynTlsEntry(SymbolBody *Sym);
@@ -148,7 +154,7 @@ class GotPltSection final : public OutputSectionBase<ELFT> {
 public:
   GotPltSection();
   void finalize() override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
   void addEntry(SymbolBody *Sym);
   bool empty() const;
 
@@ -163,7 +169,7 @@ template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> {
 public:
   PltSection();
   void finalize() override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
   void addEntry(SymbolBody *Sym);
   bool empty() const { return Entries.empty(); }
 
@@ -188,7 +194,7 @@ public:
                      StringTableSection<ELFT> &StrTabSec);
 
   void finalize() override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
   void addSymbol(SymbolBody *Body);
   StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
   unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; }
@@ -201,8 +207,8 @@ public:
   StringTableSection<ELFT> &StrTabSec;
 
 private:
-  void writeLocalSymbols(uint8_t *&Buf);
-  void writeGlobalSymbols(uint8_t *Buf);
+  void writeLocalSymbols(llvm::raw_fd_ostream &OS);
+  void writeGlobalSymbols(llvm::raw_fd_ostream &OS);
 
   static uint8_t getSymbolBinding(SymbolBody *Body);
 
@@ -221,15 +227,15 @@ public:
   void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); }
   unsigned getRelocOffset();
   void finalize() override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
   bool hasRelocs() const { return !Relocs.empty(); }
   bool isRela() const { return IsRela; }
 
   bool Static = false;
 
 private:
-  bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type, Elf_Rel *P,
-                            Elf_Rel *N);
+  bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type,
+                            llvm::raw_fd_ostream &OS);
 
   std::vector<DynamicReloc<ELFT>> Relocs;
   const bool IsRela;
@@ -245,7 +251,8 @@ public:
   typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
   OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
   void addSection(InputSectionBase<ELFT> *C) override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
+  void relocate(uint8_t *Buf) override;
 
 private:
   std::vector<InputSection<ELFT> *> Sections;
@@ -260,7 +267,7 @@ class MergeOutputSection final : public OutputSectionBase<ELFT> {
 public:
   MergeOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
   void addSection(InputSectionBase<ELFT> *S) override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
   unsigned getOffset(StringRef Val);
   void finalize() override;
 
@@ -291,7 +298,7 @@ public:
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
   EHOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
 
   template <bool IsRela>
   void addSectionAux(
@@ -300,6 +307,7 @@ public:
           Rels);
 
   void addSection(InputSectionBase<ELFT> *S) override;
+  void relocate(uint8_t *Buf) override;
 
 private:
   uint8_t getFdeEncoding(ArrayRef<uint8_t> D);
@@ -316,7 +324,7 @@ template <class ELFT>
 class InterpSection final : public OutputSectionBase<ELFT> {
 public:
   InterpSection();
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
 };
 
 template <class ELFT>
@@ -325,7 +333,7 @@ public:
   typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
   StringTableSection(StringRef Name, bool Dynamic);
   unsigned addString(StringRef S, bool HashIt = true);
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
   unsigned getSize() const { return Size; }
   void finalize() override { this->Header.sh_size = getSize(); }
   bool isDynamic() const { return Dynamic; }
@@ -344,7 +352,7 @@ class HashTableSection final : public OutputSectionBase<ELFT> {
 public:
   HashTableSection();
   void finalize() override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
 };
 
 // Outputs GNU Hash section. For detailed explanation see:
@@ -358,7 +366,7 @@ class GnuHashTableSection final : public OutputSectionBase<ELFT> {
 public:
   GnuHashTableSection();
   void finalize() override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
 
   // Adds symbols to the hash table.
   // Sorts the input to satisfy GNU hash section requirements.
@@ -368,9 +376,9 @@ private:
   static unsigned calcNBuckets(unsigned NumHashed);
   static unsigned calcMaskWords(unsigned NumHashed);
 
-  void writeHeader(uint8_t *&Buf);
-  void writeBloomFilter(uint8_t *&Buf);
-  void writeHashTable(uint8_t *Buf);
+  void writeHeader(llvm::raw_fd_ostream &OS);
+  void writeBloomFilter(llvm::raw_fd_ostream &OS);
+  void writeHashTable(llvm::raw_fd_ostream &OS);
 
   struct HashedSymbolData {
     SymbolBody *Body;
@@ -414,7 +422,7 @@ class DynamicSection final : public OutputSectionBase<ELFT> {
 public:
   DynamicSection(SymbolTable<ELFT> &SymTab);
   void finalize() override;
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
 
   OutputSectionBase<ELFT> *PreInitArraySec = nullptr;
   OutputSectionBase<ELFT> *InitArraySec = nullptr;
@@ -430,7 +438,7 @@ class MipsReginfoOutputSection final : public OutputSectionBase<ELFT> {
 
 public:
   MipsReginfoOutputSection();
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
   void addSection(InputSectionBase<ELFT> *S) override;
 
 private:
@@ -452,7 +460,7 @@ class EhFrameHeader final : public OutputSectionBase<ELFT> {
 
 public:
   EhFrameHeader();
-  void writeTo(uint8_t *Buf) override;
+  void writeTo(llvm::raw_fd_ostream &OS) override;
 
   void addFde(uint8_t Enc, size_t Off, uint8_t *PCRel);
   void assignEhFrame(EHOutputSection<ELFT> *Sec);
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index d248459..4758d3d 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -22,8 +22,9 @@
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Object/ELF.h"
-#include "llvm/Support/Endian.h"
 #include "llvm/Support/ELF.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 using namespace llvm::object;
@@ -80,14 +81,15 @@ namespace {
 class X86TargetInfo final : public TargetInfo {
 public:
   X86TargetInfo();
-  void writeGotPltHeader(uint8_t *Buf) const override;
+  void writeGotPltHeader(raw_fd_ostream &OS) const override;
   unsigned getDynRel(unsigned Type) const override;
   unsigned getTlsGotRel(unsigned Type) const override;
   bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
-  void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
-  void writePltZero(uint8_t *Buf) const override;
-  void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
-                int32_t Index, unsigned RelOff) const override;
+  void writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const override;
+  void writePltZero(raw_fd_ostream &OS) const override;
+  void writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
+                uint64_t PltEntryAddr, int32_t Index,
+                unsigned RelOff) const override;
   bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
   bool needsDynRelative(unsigned Type) const override;
   bool needsGot(uint32_t Type, const SymbolBody &S) const override;
@@ -115,11 +117,13 @@ class X86_64TargetInfo final : public TargetInfo {
 public:
   X86_64TargetInfo();
   bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
-  void writeGotPltHeader(uint8_t *Buf) const override;
-  void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
-  void writePltZero(uint8_t *Buf) const override;
-  void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
-                int32_t Index, unsigned RelOff) const override;
+  void writeGotPltHeader(raw_fd_ostream &OS) const override;
+  void writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const override;
+  void writePltZero(raw_fd_ostream &OS) const override;
+  void writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
+                uint64_t PltEntryAddr, int32_t Index,
+                unsigned RelOff) const override;
+
   bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
   bool needsGot(uint32_t Type, const SymbolBody &S) const override;
   bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
@@ -155,8 +159,9 @@ public:
 class PPC64TargetInfo final : public TargetInfo {
 public:
   PPC64TargetInfo();
-  void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
-                int32_t Index, unsigned RelOff) const override;
+  void writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
+                uint64_t PltEntryAddr, int32_t Index,
+                unsigned RelOff) const override;
   bool needsGot(uint32_t Type, const SymbolBody &S) const override;
   bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
@@ -169,10 +174,11 @@ class AArch64TargetInfo final : public TargetInfo {
 public:
   AArch64TargetInfo();
   unsigned getDynRel(unsigned Type) const override;
-  void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
-  void writePltZero(uint8_t *Buf) const override;
-  void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
-                int32_t Index, unsigned RelOff) const override;
+  void writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const override;
+  void writePltZero(raw_fd_ostream &OS) const override;
+  void writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
+                uint64_t PltEntryAddr, int32_t Index,
+                unsigned RelOff) const override;
   unsigned getTlsGotRel(unsigned Type = -1) const override;
   bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
   bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
@@ -195,7 +201,7 @@ template <class ELFT> class MipsTargetInfo final : public TargetInfo {
 public:
   MipsTargetInfo();
   unsigned getDynRel(unsigned Type) const override;
-  void writeGotHeader(uint8_t *Buf) const override;
+  void writeGotHeader(raw_fd_ostream &OS) const override;
   bool needsGot(uint32_t Type, const SymbolBody &S) const override;
   bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
@@ -276,6 +282,14 @@ unsigned TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
   return 0;
 }
 
+void TargetInfo::writeGotPltHeader(llvm::raw_fd_ostream &OS) const {
+  uint64_t E = 0;
+  unsigned Size =
+      (Config->EKind == ELF64LEKind || Config->EKind == ELF64BEKind) ? 8 : 4;
+  for (unsigned I = 0; I < GotPltHeaderEntriesNum; ++I)
+    OS.write((const char*)&E, Size);
+}
+
 X86TargetInfo::X86TargetInfo() {
   CopyRel = R_386_COPY;
   GotRel = R_386_GLOB_DAT;
@@ -292,14 +306,16 @@ X86TargetInfo::X86TargetInfo() {
   PltZeroSize = 16;
 }
 
-void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
-  write32le(Buf, Out<ELF32LE>::Dynamic->getVA());
+void X86TargetInfo::writeGotPltHeader(raw_fd_ostream &OS) const {
+  Writer<support::little> W(OS);
+  W.write<uint32_t>({Out<ELF32LE>::Dynamic->getVA(), 0, 0});
 }
 
-void X86TargetInfo::writeGotPlt(uint8_t *Buf, uint64_t Plt) const {
+void X86TargetInfo::writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const {
+  Writer<support::little> W(OS);
   // Entries in .got.plt initially points back to the corresponding
   // PLT entries with a fixed offset to skip the first instruction.
-  write32le(Buf, Plt + 6);
+  W.write<uint32_t>(Plt + 6);
 }
 
 unsigned X86TargetInfo::getDynRel(unsigned Type) const {
@@ -325,47 +341,53 @@ bool X86TargetInfo::isTlsDynRel(unsigned Type, const SymbolBody &S) const {
   return Type == R_386_TLS_GD;
 }
 
-void X86TargetInfo::writePltZero(uint8_t *Buf) const {
+void X86TargetInfo::writePltZero(raw_fd_ostream &OS) const {
+  Writer<support::little> W(OS);
+
   // Executable files and shared object files have
   // separate procedure linkage tables.
   if (Config->Shared) {
-    const uint8_t V[] = {
+    W.write<uint8_t>({
         0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
         0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp   *8(%ebx)
         0x90, 0x90, 0x90, 0x90              // nop; nop; nop; nop
-    };
-    memcpy(Buf, V, sizeof(V));
+    });
     return;
   }
 
-  const uint8_t PltData[] = {
-      0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOT+4)
-      0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp   *(GOT+8)
-      0x90, 0x90, 0x90, 0x90              // nop; nop; nop; nop
-  };
-  memcpy(Buf, PltData, sizeof(PltData));
   uint32_t Got = Out<ELF32LE>::GotPlt->getVA();
-  write32le(Buf + 2, Got + 4);
-  write32le(Buf + 8, Got + 8);
+
+  // pushl (GOT+4)
+  W.write<uint8_t>({0xff, 0x35});
+  W.write<uint32_t>(Got + 4);
+
+  // jmp   *(GOT+8)
+  W.write<uint8_t>({0xff, 0x25});
+  W.write<uint32_t>(Got + 8);
+
+  // nop; nop; nop; nop
+  W.write<uint8_t>({0x90, 0x90, 0x90, 0x90});
 }
 
-void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void X86TargetInfo::writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
                              uint64_t PltEntryAddr, int32_t Index,
                              unsigned RelOff) const {
-  const uint8_t Inst[] = {
-      0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo at GOT(%ebx)
-      0x68, 0x00, 0x00, 0x00, 0x00,       // pushl $reloc_offset
-      0xe9, 0x00, 0x00, 0x00, 0x00        // jmp .PLT0 at PC
-  };
-  memcpy(Buf, Inst, sizeof(Inst));
+  Writer<support::little> W(OS);
 
-  // jmp *foo at GOT(%ebx) or jmp *foo_in_GOT
-  Buf[1] = Config->Shared ? 0xa3 : 0x25;
   uint32_t Got = UseLazyBinding ? Out<ELF32LE>::GotPlt->getVA()
                                 : Out<ELF32LE>::Got->getVA();
-  write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
-  write32le(Buf + 7, RelOff);
-  write32le(Buf + 12, -Index * PltEntrySize - PltZeroSize - 16);
+
+  // jmp *foo_in_GOT|*foo at GOT(%ebx)
+  W.write<uint8_t>({0xff, Config->Shared ? (uint8_t)0xa3 : (uint8_t)0x25});
+  W.write<uint32_t>(Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
+
+  // pushl $reloc_offset
+  W.write<uint8_t>(0x68);
+  W.write<uint32_t>(RelOff);
+
+  // jmp .PLT0 at PC
+  W.write<uint8_t>(0xe9);
+  W.write<uint32_t>(-Index * PltEntrySize - PltZeroSize - 16);
 }
 
 bool X86TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
@@ -600,41 +622,50 @@ X86_64TargetInfo::X86_64TargetInfo() {
   PltZeroSize = 16;
 }
 
-void X86_64TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
-  write64le(Buf, Out<ELF64LE>::Dynamic->getVA());
+void X86_64TargetInfo::writeGotPltHeader(raw_fd_ostream &OS) const {
+  Writer<support::little> W(OS);
+  W.write<uint64_t>({Out<ELF64LE>::Dynamic->getVA(), 0, 0});
 }
 
-void X86_64TargetInfo::writeGotPlt(uint8_t *Buf, uint64_t Plt) const {
+void X86_64TargetInfo::writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const {
   // See comments in X86TargetInfo::writeGotPlt.
-  write32le(Buf, Plt + 6);
+  Writer<support::little> W(OS);
+  W.write<uint64_t>(Plt + 6);
 }
 
-void X86_64TargetInfo::writePltZero(uint8_t *Buf) const {
-  const uint8_t PltData[] = {
-      0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
-      0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
-      0x0f, 0x1f, 0x40, 0x00              // nopl 0x0(rax)
-  };
-  memcpy(Buf, PltData, sizeof(PltData));
+void X86_64TargetInfo::writePltZero(raw_fd_ostream &OS) const {
+  Writer<support::little> W(OS);
   uint64_t Got = Out<ELF64LE>::GotPlt->getVA();
   uint64_t Plt = Out<ELF64LE>::Plt->getVA();
-  write32le(Buf + 2, Got - Plt + 2); // GOT+8
-  write32le(Buf + 8, Got - Plt + 4); // GOT+16
+
+  // pushq GOT+8(%rip)
+  W.write<uint8_t>({0xff, 0x35});
+  W.write<uint32_t>(Got - Plt + 2); // GOT+8
+
+  // jmp *GOT+16(%rip)
+  W.write<uint8_t>({0xff, 0x25});
+  W.write<uint32_t>(Got - Plt + 4); // GOT+16
+
+  // nopl 0x0(rax)
+  W.write<uint8_t>({0x0f, 0x1f, 0x40, 0x00});
 }
 
-void X86_64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void X86_64TargetInfo::writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
                                 uint64_t PltEntryAddr, int32_t Index,
                                 unsigned RelOff) const {
-  const uint8_t Inst[] = {
-      0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
-      0x68, 0x00, 0x00, 0x00, 0x00,       // pushq <relocation index>
-      0xe9, 0x00, 0x00, 0x00, 0x00        // jmpq plt[0]
-  };
-  memcpy(Buf, Inst, sizeof(Inst));
+  Writer<support::little> W(OS);
+
+  // jmpq *got(%rip)
+  W.write<uint8_t>({0xff, 0x25});
+  W.write<uint32_t>(GotEntryAddr - PltEntryAddr - 6);
+
+  // pushq <relocation index>
+  W.write<uint8_t>(0x68);
+  W.write<uint32_t>(Index);
 
-  write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
-  write32le(Buf + 7, Index);
-  write32le(Buf + 12, -Index * PltEntrySize - PltZeroSize - 16);
+  // jmpq plt[0]
+  W.write<uint8_t>(0xe9);
+  W.write<uint32_t>(-Index * PltEntrySize - PltZeroSize - 16);
 }
 
 bool X86_64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
@@ -970,7 +1001,7 @@ uint64_t getPPC64TocBase() {
   return TocVA + 0x8000;
 }
 
-void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void PPC64TargetInfo::writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
                                uint64_t PltEntryAddr, int32_t Index,
                                unsigned RelOff) const {
   uint64_t Off = GotEntryAddr - getPPC64TocBase();
@@ -980,15 +1011,15 @@ void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
   // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
   // be a pointer to the function descriptor in the .opd section. Using
   // this scheme is simpler, but requires an extra indirection per PLT dispatch.
-
-  write32be(Buf,      0xf8410028);                   // std %r2, 40(%r1)
-  write32be(Buf + 4,  0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X at ha
-  write32be(Buf + 8,  0xe98b0000 | applyPPCLo(Off)); // ld %r12, X at l(%r11)
-  write32be(Buf + 12, 0xe96c0000);                   // ld %r11,0(%r12)
-  write32be(Buf + 16, 0x7d6903a6);                   // mtctr %r11
-  write32be(Buf + 20, 0xe84c0008);                   // ld %r2,8(%r12)
-  write32be(Buf + 24, 0xe96c0010);                   // ld %r11,16(%r12)
-  write32be(Buf + 28, 0x4e800420);                   // bctr
+  Writer<support::big> W(OS);
+  W.write<uint32_t>(0xf8410028);                     // std %r2, 40(%r1)
+  W.write<uint32_t>(0x3d620000 | applyPPCHa(Off));   // addis %r11, %r2, X at ha
+  W.write<uint32_t>(0xe98b0000 | applyPPCLo(Off));   // ld %r12, X at l(%r11)
+  W.write<uint32_t>(0xe96c0000);                     // ld %r11,0(%r12)
+  W.write<uint32_t>(0x7d6903a6);                     // mtctr %r11
+  W.write<uint32_t>(0xe84c0008);                     // ld %r2,8(%r12)
+  W.write<uint32_t>(0xe96c0010);                     // ld %r11,16(%r12)
+  W.write<uint32_t>(0x4e800420);                     // bctr
 }
 
 bool PPC64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
@@ -1160,12 +1191,13 @@ unsigned AArch64TargetInfo::getDynRel(unsigned Type) const {
                             "recompile with -fPIC.");
 }
 
-void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, uint64_t Plt) const {
-  write64le(Buf, Out<ELF64LE>::Plt->getVA());
+void AArch64TargetInfo::writeGotPlt(raw_fd_ostream &OS, uint64_t Plt) const {
+  Writer<support::little> W(OS);
+  W.write((uint64_t)Out<ELF64LE>::Plt->getVA());
 }
 
-void AArch64TargetInfo::writePltZero(uint8_t *Buf) const {
-  const uint8_t PltData[] = {
+void AArch64TargetInfo::writePltZero(raw_fd_ostream &OS) const {
+  uint8_t PltData[] = {
       0xf0, 0x7b, 0xbf, 0xa9, // stp	x16, x30, [sp,#-16]!
       0x10, 0x00, 0x00, 0x90, // adrp	x16, Page(&(.plt.got[2]))
       0x11, 0x02, 0x40, 0xf9, // ldr	x17, [x16, Offset(&(.plt.got[2]))]
@@ -1175,34 +1207,35 @@ void AArch64TargetInfo::writePltZero(uint8_t *Buf) const {
       0x1f, 0x20, 0x03, 0xd5, // nop
       0x1f, 0x20, 0x03, 0xd5  // nop
   };
-  memcpy(Buf, PltData, sizeof(PltData));
 
   uint64_t Got = Out<ELF64LE>::GotPlt->getVA();
   uint64_t Plt = Out<ELF64LE>::Plt->getVA();
-  relocateOne(Buf + 4, Buf + 8, R_AARCH64_ADR_PREL_PG_HI21, Plt + 4, Got + 16);
-  relocateOne(Buf + 8, Buf + 12, R_AARCH64_LDST64_ABS_LO12_NC, Plt + 8,
+  relocateOne(PltData + 4, PltData + 8, R_AARCH64_ADR_PREL_PG_HI21, Plt + 4, Got + 16);
+  relocateOne(PltData + 8, PltData + 12, R_AARCH64_LDST64_ABS_LO12_NC, Plt + 8,
               Got + 16);
-  relocateOne(Buf + 12, Buf + 16, R_AARCH64_ADD_ABS_LO12_NC, Plt + 12,
+  relocateOne(PltData + 12, PltData + 16, R_AARCH64_ADD_ABS_LO12_NC, Plt + 12,
               Got + 16);
+  OS.write((const char*)PltData, sizeof(PltData));
 }
 
-void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void AArch64TargetInfo::writePlt(raw_fd_ostream &OS, uint64_t GotEntryAddr,
                                  uint64_t PltEntryAddr, int32_t Index,
                                  unsigned RelOff) const {
-  const uint8_t Inst[] = {
+  uint8_t Inst[] = {
       0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
       0x11, 0x02, 0x40, 0xf9, // ldr  x17, [x16, Offset(&(.plt.got[n]))]
       0x10, 0x02, 0x00, 0x91, // add  x16, x16, Offset(&(.plt.got[n]))
       0x20, 0x02, 0x1f, 0xd6  // br   x17
   };
-  memcpy(Buf, Inst, sizeof(Inst));
 
-  relocateOne(Buf, Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr,
+  relocateOne(Inst, Inst + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr,
               GotEntryAddr);
-  relocateOne(Buf + 4, Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4,
+  relocateOne(Inst + 4, Inst + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4,
               GotEntryAddr);
-  relocateOne(Buf + 8, Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8,
+  relocateOne(Inst + 8, Inst + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8,
               GotEntryAddr);
+  Writer<support::little> W(OS);
+  W.write<uint8_t>(Inst);
 }
 
 unsigned AArch64TargetInfo::getTlsGotRel(unsigned Type) const {
@@ -1402,9 +1435,9 @@ unsigned MipsTargetInfo<ELFT>::getDynRel(unsigned Type) const {
 }
 
 template <class ELFT>
-void MipsTargetInfo<ELFT>::writeGotHeader(uint8_t *Buf) const {
-  typedef typename ELFFile<ELFT>::Elf_Off Elf_Off;
+void MipsTargetInfo<ELFT>::writeGotHeader(raw_fd_ostream &OS) const {
   typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+  Writer<ELFT::TargetEndianness> W(OS);
 
   // Set the MSB of the second GOT slot. This is not required by any
   // MIPS ABI documentation, though.
@@ -1420,8 +1453,8 @@ void MipsTargetInfo<ELFT>::writeGotHeader(uint8_t *Buf) const {
   // we've been doing this for years, it is probably a safe bet to
   // keep doing this for now. We really need to revisit this to see
   // if we had to do this.
-  auto *P = reinterpret_cast<Elf_Off *>(Buf);
-  P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
+  W.template write<uintX_t>(
+      {(uintX_t)0, (uintX_t)(1) << (ELFT::Is64Bits ? 63 : 31)});
 }
 
 template <class ELFT>
diff --git a/ELF/Target.h b/ELF/Target.h
index 2b1e14d..9e0f6e7 100644
--- a/ELF/Target.h
+++ b/ELF/Target.h
@@ -15,6 +15,10 @@
 
 #include <memory>
 
+namespace llvm {
+class raw_fd_ostream;
+}
+
 namespace lld {
 namespace elf2 {
 class SymbolBody;
@@ -27,16 +31,16 @@ public:
   virtual unsigned getDynRel(unsigned Type) const { return Type; }
   virtual bool isTlsDynRel(unsigned Type, const SymbolBody &S) const;
   virtual unsigned getTlsGotRel(unsigned Type = -1) const { return TlsGotRel; }
-  virtual void writeGotHeader(uint8_t *Buf) const {}
-  virtual void writeGotPltHeader(uint8_t *Buf) const {}
-  virtual void writeGotPlt(uint8_t *Buf, uint64_t Plt) const {};
+  virtual void writeGotHeader(llvm::raw_fd_ostream &OS) const {}
+  virtual void writeGotPltHeader(llvm::raw_fd_ostream &OS) const;
+  virtual void writeGotPlt(llvm::raw_fd_ostream &OS, uint64_t Plt) const {};
 
   // If lazy binding is supported, the first entry of the PLT has code
   // to call the dynamic linker to resolve PLT entries the first time
   // they are called. This function writes that code.
-  virtual void writePltZero(uint8_t *Buf) const {}
+  virtual void writePltZero(llvm::raw_fd_ostream &OS) const {}
 
-  virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+  virtual void writePlt(llvm::raw_fd_ostream &OS, uint64_t GotEntryAddr,
                         uint64_t PltEntryAddr, int32_t Index,
                         unsigned RelOff) const {}
 
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index f8f6215..1226037 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -15,7 +15,6 @@
 
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/FileOutputBuffer.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/StringSaver.h"
 
@@ -37,7 +36,7 @@ public:
   typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
   typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
   typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
-  Writer(SymbolTable<ELFT> &S) : Symtab(S) {}
+  Writer(SymbolTable<ELFT> &S, raw_fd_ostream &OS) : OS(OS), Symtab(S) {}
   void run();
 
 private:
@@ -56,9 +55,9 @@ private:
   void assignAddresses();
   void buildSectionMap();
   void fixAbsoluteSymbols();
-  void openFile(StringRef OutputPath);
   void writeHeader();
   void writeSections();
+  void writeSectionHeader();
   bool isDiscarded(InputSectionBase<ELFT> *IS) const;
   StringRef getOutputSectionName(StringRef S) const;
   bool needsInterpSection() const {
@@ -73,7 +72,7 @@ private:
   void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
   void addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms);
 
-  std::unique_ptr<llvm::FileOutputBuffer> Buffer;
+  raw_fd_ostream &OS;
 
   BumpPtrAllocator Alloc;
   std::vector<OutputSectionBase<ELFT> *> OutputSections;
@@ -147,7 +146,10 @@ template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) {
   EhFrameHeader<ELFT> EhFrameHdr;
   Out<ELFT>::EhFrameHdr = &EhFrameHdr;
 
-  Writer<ELFT>(*Symtab).run();
+  // FIXME: use temp file
+  std::error_code EC;
+  raw_fd_ostream OS(Config->OutputFile,EC, sys::fs::F_RW);
+  Writer<ELFT>(*Symtab, OS).run();
 }
 
 // The main function of the writer.
@@ -160,10 +162,9 @@ template <class ELFT> void Writer<ELFT>::run() {
     return;
   assignAddresses();
   fixAbsoluteSymbols();
-  openFile(Config->OutputFile);
   writeHeader();
   writeSections();
-  fatal(Buffer->commit());
+  writeSectionHeader();
 }
 
 namespace {
@@ -356,22 +357,6 @@ void Writer<ELFT>::scanRelocs(
   }
 }
 
-template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
-  if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
-    for (const Elf_Shdr *RelSec : C.RelocSections)
-      scanRelocs(C, *RelSec);
-}
-
-template <class ELFT>
-void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &S,
-                              const Elf_Shdr &RelSec) {
-  ELFFile<ELFT> &EObj = S.getFile()->getObj();
-  if (RelSec.sh_type == SHT_RELA)
-    scanRelocs(S, EObj.relas(&RelSec));
-  else
-    scanRelocs(S, EObj.rels(&RelSec));
-}
-
 template <class ELFT>
 static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
   if (Config->Shared && !Config->NoUndefined)
@@ -473,6 +458,12 @@ template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) {
          S == ".eh_frame";
 }
 
+template <class ELFT>
+static bool isAfterReloc(OutputSectionBase<ELFT> *S) {
+  return S == Out<ELFT>::Got || S == Out<ELFT>::EhFrameHdr ||
+         S == Out<ELFT>::RelaDyn || S == Out<ELFT>::RelaPlt;
+}
+
 // Output section ordering is determined by this function.
 template <class ELFT>
 static bool compareOutputSections(OutputSectionBase<ELFT> *A,
@@ -494,6 +485,12 @@ static bool compareOutputSections(OutputSectionBase<ELFT> *A,
   if (!AIsAlloc)
     return false;
 
+
+  bool AIsAfterReloc = isAfterReloc(A);
+  bool BIsAfterReloc = isAfterReloc(B);
+  if (AIsAfterReloc != BIsAfterReloc)
+    return BIsAfterReloc;
+
   // We want the read only sections first so that they go in the PT_LOAD
   // covering the program headers at the start of the file.
   bool AIsWritable = AFlags & SHF_WRITE;
@@ -846,20 +843,6 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
   for (OutputSectionBase<ELFT> *Sec : RegularSections)
     addStartStopSymbols(Sec);
 
-  // Scan relocations. This must be done after every symbol is declared so that
-  // we can correctly decide if a dynamic relocation is needed.
-  for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
-    for (InputSectionBase<ELFT> *C : F->getSections()) {
-      if (isDiscarded(C))
-        continue;
-      if (auto *S = dyn_cast<InputSection<ELFT>>(C))
-        scanRelocs(*S);
-      else if (auto *S = dyn_cast<EHInputSection<ELFT>>(C))
-        if (S->RelocSection)
-          scanRelocs(*S, *S->RelocSection);
-    }
-  }
-
   // Define __rel[a]_iplt_{start,end} symbols if needed.
   addRelIpltSymbols();
 
@@ -899,6 +882,8 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
   // This function adds linker-created Out<ELFT>::* sections.
   addPredefinedSections();
 
+  // FIXME: We don't actually support reordering some predefined sections. We
+  // should check for that.
   std::stable_sort(OutputSections.begin(), OutputSections.end(),
                    compareSections<ELFT>);
 
@@ -1284,64 +1269,86 @@ template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
 }
 
 template <class ELFT> void Writer<ELFT>::writeHeader() {
-  uint8_t *Buf = Buffer->getBufferStart();
-  memcpy(Buf, "\177ELF", 4);
-
   // Write the ELF header.
-  auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
-  EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
-  EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
+  Elf_Ehdr EHdr{};
+  EHdr.e_ident[0] = 0x7f;
+  EHdr.e_ident[1] = 'E';
+  EHdr.e_ident[2] = 'L';
+  EHdr.e_ident[3] = 'F';
+  EHdr.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
+  EHdr.e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
                                ? ELFDATA2LSB
                                : ELFDATA2MSB;
-  EHdr->e_ident[EI_VERSION] = EV_CURRENT;
+  EHdr.e_ident[EI_VERSION] = EV_CURRENT;
 
   auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
-  EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI();
-
-  EHdr->e_type = Config->Shared ? ET_DYN : ET_EXEC;
-  EHdr->e_machine = FirstObj.getEMachine();
-  EHdr->e_version = EV_CURRENT;
-  EHdr->e_entry = getEntryAddr<ELFT>();
-  EHdr->e_phoff = sizeof(Elf_Ehdr);
-  EHdr->e_shoff = SectionHeaderOff;
-  EHdr->e_flags = getELFFlags();
-  EHdr->e_ehsize = sizeof(Elf_Ehdr);
-  EHdr->e_phentsize = sizeof(Elf_Phdr);
-  EHdr->e_phnum = Phdrs.size();
-  EHdr->e_shentsize = sizeof(Elf_Shdr);
-  EHdr->e_shnum = getNumSections();
-  EHdr->e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex;
+  EHdr.e_ident[EI_OSABI] = FirstObj.getOSABI();
+
+  EHdr.e_type = Config->Shared ? ET_DYN : ET_EXEC;
+  EHdr.e_machine = FirstObj.getEMachine();
+  EHdr.e_version = EV_CURRENT;
+  EHdr.e_entry = getEntryAddr<ELFT>();
+  EHdr.e_phoff = sizeof(Elf_Ehdr);
+  EHdr.e_shoff = SectionHeaderOff;
+  EHdr.e_flags = getELFFlags();
+  EHdr.e_ehsize = sizeof(Elf_Ehdr);
+  EHdr.e_phentsize = sizeof(Elf_Phdr);
+  EHdr.e_phnum = Phdrs.size();
+  EHdr.e_shentsize = sizeof(Elf_Shdr);
+  EHdr.e_shnum = getNumSections();
+  EHdr.e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex;
+
+  OS.write(reinterpret_cast<const char*>(&EHdr), sizeof(EHdr));
 
   // Write the program header table.
-  memcpy(Buf + EHdr->e_phoff, &Phdrs[0], Phdrs.size() * sizeof(Phdrs[0]));
+  OS.write(reinterpret_cast<const char *>(&Phdrs[0]),
+           Phdrs.size() * sizeof(Phdrs[0]));
+}
 
+template <class ELFT> void Writer<ELFT>::writeSectionHeader() {
   // Write the section header table. Note that the first table entry is null.
-  auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+  OS.seek(SectionHeaderOff + sizeof(Elf_Shdr));
   for (OutputSectionBase<ELFT> *Sec : OutputSections)
-    Sec->writeHeaderTo(++SHdrs);
-}
-
-template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
-  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
-      FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
-  fatal(BufferOrErr, "failed to open " + Path);
-  Buffer = std::move(*BufferOrErr);
+    Sec->writeHeaderTo(OS);
 }
 
 // Write section contents to a mmap'ed file.
 template <class ELFT> void Writer<ELFT>::writeSections() {
-  uint8_t *Buf = Buffer->getBufferStart();
-
-  // PPC64 needs to process relocations in the .opd section before processing
-  // relocations in code-containing sections.
-  if (OutputSectionBase<ELFT> *Sec = Out<ELFT>::Opd) {
-    Out<ELFT>::OpdBuf = Buf + Sec->getFileOff();
-    Sec->writeTo(Buf + Sec->getFileOff());
+  for (OutputSectionBase<ELFT> *Sec : OutputSections)
+    Sec->setSHName( Out<ELFT>::ShStrTab->addString(Sec->getName()));
+
+  unsigned SecI;
+  for (SecI = 0; SecI < OutputSections.size(); ++SecI) {
+    OutputSectionBase<ELFT> *Sec = OutputSections[SecI];
+    if (isAfterReloc(Sec))
+      break;
+    Sec->writeTo(OS);
   }
 
+  OS.flush();
+  std::error_code EC;
+  sys::fs::mapped_file_region Region(
+				     OS.getFD(), sys::fs::mapped_file_region::readwrite, OS.tell(), 0,
+      EC);
+  error(EC, "bar");
+  auto *Buf = reinterpret_cast<uint8_t*>(Region.data());
+
+  if (OutputSectionBase<ELFT> *Sec = Out<ELFT>::Opd)
+    Sec->relocate(Buf);
+
   for (OutputSectionBase<ELFT> *Sec : OutputSections)
     if (Sec != Out<ELFT>::Opd)
-      Sec->writeTo(Buf + Sec->getFileOff());
+      Sec->relocate(Buf);
+
+  if (Out<ELFT>::RelaDyn->hasRelocs())
+    OutputSections.push_back(Out<ELFT>::RelaDyn);
+
+  for (; SecI < OutputSections.size(); ++SecI) {
+    OutputSectionBase<ELFT> *Sec = OutputSections[SecI];
+    Sec->writeTo(OS);
+  }
+
+
 }
 
 template <class ELFT>
diff --git a/test/ELF/basic.s b/test/ELF/basic.s
index bbc674c..c8559cd 100644
--- a/test/ELF/basic.s
+++ b/test/ELF/basic.s
@@ -98,7 +98,7 @@ _start:
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Section {
 # CHECK-NEXT:     Index: 4
-# CHECK-NEXT:     Name: .strtab (25)
+# CHECK-NEXT:     Name: .strtab
 # CHECK-NEXT:     Type: SHT_STRTAB (0x3)
 # CHECK-NEXT:     Flags [ (0x0)
 # CHECK-NEXT:     ]
diff --git a/test/ELF/eh-frame-hdr.s b/test/ELF/eh-frame-hdr.s
index 97bef97..707b8f3 100644
--- a/test/ELF/eh-frame-hdr.s
+++ b/test/ELF/eh-frame-hdr.s
@@ -48,8 +48,8 @@ _start:
 // HDR-NEXT:    Flags [
 // HDR-NEXT:      SHF_ALLOC
 // HDR-NEXT:    ]
-// HDR-NEXT:    Address: 0x10158
-// HDR-NEXT:    Offset: 0x158
+// HDR-NEXT:    Address: 0x10190
+// HDR-NEXT:    Offset: 0x190
 // HDR-NEXT:    Size: 96
 // HDR-NEXT:    Link: 0
 // HDR-NEXT:    Info: 0
diff --git a/test/ELF/mips-got16.s b/test/ELF/mips-got16.s
index c1eee3c..89b1189 100644
--- a/test/ELF/mips-got16.s
+++ b/test/ELF/mips-got16.s
@@ -19,24 +19,24 @@
 #
 # CHECK: SYMBOL TABLE:
 # CHECK: 0001001c         .text           00000000 $LC0
-# CHECK: 00030000         .data           00000000 $LC1
-# CHECK: 00030004         .data           00000000 .hidden bar
+# CHECK: 00020000         .data           00000000 $LC1
+# CHECK: 00020004         .data           00000000 .hidden bar
 # CHECK: 00000000         *UND*           00000000 foo
 
 # GOT:      Relocations [
 # GOT-NEXT: ]
 
 # GOT:      Primary GOT {
-# GOT-NEXT:   Canonical gp value: 0x27FF0
+# GOT-NEXT:   Canonical gp value: 0x28000
 # GOT-NEXT:   Reserved entries [
 # GOT-NEXT:     Entry {
-# GOT-NEXT:       Address: 0x20000
+# GOT-NEXT:       Address: 0x20010
 # GOT-NEXT:       Access: -32752
 # GOT-NEXT:       Initial: 0x0
 # GOT-NEXT:       Purpose: Lazy resolver
 # GOT-NEXT:     }
 # GOT-NEXT:     Entry {
-# GOT-NEXT:       Address: 0x20004
+# GOT-NEXT:       Address: 0x20014
 # GOT-NEXT:       Access: -32748
 # GOT-NEXT:       Initial: 0x80000000
 # GOT-NEXT:       Purpose: Module pointer (GNU extension)
@@ -44,24 +44,24 @@
 # GOT-NEXT:   ]
 # GOT-NEXT:   Local entries [
 # GOT-NEXT:     Entry {
-# GOT-NEXT:       Address: 0x20008
+# GOT-NEXT:       Address: 0x20018
 # GOT-NEXT:       Access: -32744
 # GOT-NEXT:       Initial: 0x10000
 # GOT-NEXT:     }
 # GOT-NEXT:     Entry {
-# GOT-NEXT:       Address: 0x2000C
+# GOT-NEXT:       Address: 0x2001C
 # GOT-NEXT:       Access: -32740
-# GOT-NEXT:       Initial: 0x30000
+# GOT-NEXT:       Initial: 0x20000
 # GOT-NEXT:     }
 # GOT-NEXT:     Entry {
-# GOT-NEXT:       Address: 0x20010
+# GOT-NEXT:       Address: 0x20020
 # GOT-NEXT:       Access: -32736
-# GOT-NEXT:       Initial: 0x30004
+# GOT-NEXT:       Initial: 0x20004
 # GOT-NEXT:     }
 # GOT-NEXT:   ]
 # GOT-NEXT:   Global entries [
 # GOT-NEXT:     Entry {
-# GOT-NEXT:       Address: 0x20014
+# GOT-NEXT:       Address: 0x20024
 # GOT-NEXT:       Access: -32732
 # GOT-NEXT:       Initial: 0x0
 # GOT-NEXT:       Value: 0x0
diff --git a/test/ELF/relro.s b/test/ELF/relro.s
index 692d6b2..5b040a2 100644
--- a/test/ELF/relro.s
+++ b/test/ELF/relro.s
@@ -11,7 +11,7 @@
 
 // FULLRELRO:        Section {
 // FULLRELRO:        Index: 9
-// FULLRELRO-NEXT:   Name: .got
+// FULLRELRO-NEXT:   Name: .got.plt
 // FULLRELRO-NEXT:   Type: SHT_PROGBITS
 // FULLRELRO-NEXT:   Flags [
 // FULLRELRO-NEXT:     SHF_ALLOC
@@ -19,25 +19,6 @@
 // FULLRELRO-NEXT:   ]
 // FULLRELRO-NEXT:   Address: 0x12110
 // FULLRELRO-NEXT:   Offset: 0x2110
-// FULLRELRO-NEXT:   Size: 8
-// FULLRELRO-NEXT:   Link: 0
-// FULLRELRO-NEXT:   Info: 0
-// FULLRELRO-NEXT:   AddressAlignment: 8
-// FULLRELRO-NEXT:   EntrySize: 0
-// FULLRELRO-NEXT:   SectionData (
-// FULLRELRO-NEXT:     0000: 00000000 00000000
-// FULLRELRO-NEXT:   )
-// FULLRELRO-NEXT: }
-// FULLRELRO-NEXT: Section {
-// FULLRELRO-NEXT:   Index: 10
-// FULLRELRO-NEXT:   Name: .got.plt
-// FULLRELRO-NEXT:   Type: SHT_PROGBITS
-// FULLRELRO-NEXT:   Flags [
-// FULLRELRO-NEXT:     SHF_ALLOC
-// FULLRELRO-NEXT:     SHF_WRITE
-// FULLRELRO-NEXT:   ]
-// FULLRELRO-NEXT:   Address: 0x12118
-// FULLRELRO-NEXT:   Offset: 0x2118
 // FULLRELRO-NEXT:   Size: 32
 // FULLRELRO-NEXT:   Link: 0
 // FULLRELRO-NEXT:   Info: 0
@@ -49,7 +30,7 @@
 // FULLRELRO-NEXT:   )
 // FULLRELRO-NEXT: }
 // FULLRELRO-NEXT: Section {
-// FULLRELRO-NEXT:   Index: 11
+// FULLRELRO-NEXT:   Index: 10
 // FULLRELRO-NEXT:   Name: .data
 // FULLRELRO-NEXT:   Type: SHT_PROGBITS
 // FULLRELRO-NEXT:   Flags [
@@ -68,7 +49,7 @@
 // FULLRELRO-NEXT:   )
 // FULLRELRO-NEXT: }
 // FULLRELRO-NEXT: Section {
-// FULLRELRO-NEXT:   Index: 12
+// FULLRELRO-NEXT:   Index: 11
 // FULLRELRO-NEXT:   Name: .foo
 // FULLRELRO-NEXT:   Type: SHT_PROGBITS
 // FULLRELRO-NEXT:   Flags [


More information about the llvm-commits mailing list