Merge "Major refactoring of ElfBuilder."
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h
index 022fac2..230ebe3 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/dwarf/dwarf_test.h
@@ -57,44 +57,41 @@
 
   // Pretty-print the generated DWARF data using objdump.
   template<typename ElfTypes>
-  std::vector<std::string> Objdump(bool is64bit, const char* args) {
+  std::vector<std::string> Objdump(const char* args) {
     // Write simple elf file with just the DWARF sections.
+    InstructionSet isa = (sizeof(typename ElfTypes::Addr) == 8) ? kX86_64 : kX86;
     class NoCode : public CodeOutput {
-      virtual void SetCodeOffset(size_t) { }
-      virtual bool Write(OutputStream*) { return true; }
-    } code;
-    ScratchFile file;
-    InstructionSet isa = is64bit ? kX86_64 : kX86;
-    ElfBuilder<ElfTypes> builder(
-        &code, file.GetFile(), isa, 0, 0, 0, 0, 0, 0, false, false);
-    typedef typename ElfBuilder<ElfTypes>::ElfRawSectionBuilder Section;
-    Section debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-    Section debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-    Section debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-    Section debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-    Section eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
+      bool Write(OutputStream*) OVERRIDE { return true; }  // NOLINT
+    } no_code;
+    ElfBuilder<ElfTypes> builder(isa, 0, &no_code, 0, &no_code, 0);
+    typedef typename ElfBuilder<ElfTypes>::RawSection RawSection;
+    RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0);
     if (!debug_info_data_.empty()) {
       debug_info.SetBuffer(debug_info_data_);
-      builder.RegisterRawSection(&debug_info);
+      builder.RegisterSection(&debug_info);
     }
     if (!debug_abbrev_data_.empty()) {
       debug_abbrev.SetBuffer(debug_abbrev_data_);
-      builder.RegisterRawSection(&debug_abbrev);
+      builder.RegisterSection(&debug_abbrev);
     }
     if (!debug_str_data_.empty()) {
       debug_str.SetBuffer(debug_str_data_);
-      builder.RegisterRawSection(&debug_str);
+      builder.RegisterSection(&debug_str);
     }
     if (!debug_line_data_.empty()) {
       debug_line.SetBuffer(debug_line_data_);
-      builder.RegisterRawSection(&debug_line);
+      builder.RegisterSection(&debug_line);
     }
     if (!eh_frame_data_.empty()) {
       eh_frame.SetBuffer(eh_frame_data_);
-      builder.RegisterRawSection(&eh_frame);
+      builder.RegisterSection(&eh_frame);
     }
-    builder.Init();
-    builder.Write();
+    ScratchFile file;
+    builder.Write(file.GetFile());
 
     // Read the elf file back using objdump.
     std::vector<std::string> lines;
@@ -123,9 +120,9 @@
 
   std::vector<std::string> Objdump(bool is64bit, const char* args) {
     if (is64bit) {
-      return Objdump<ElfTypes64>(is64bit, args);
+      return Objdump<ElfTypes64>(args);
     } else {
-      return Objdump<ElfTypes32>(is64bit, args);
+      return Objdump<ElfTypes32>(args);
     }
   }
 
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 9c173f8..90b99bc 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,9 +17,10 @@
 #ifndef ART_COMPILER_ELF_BUILDER_H_
 #define ART_COMPILER_ELF_BUILDER_H_
 
+#include <vector>
+
 #include "arch/instruction_set.h"
-#include "base/stl_util.h"
-#include "base/value_object.h"
+#include "base/unix_file/fd_file.h"
 #include "buffered_output_stream.h"
 #include "elf_utils.h"
 #include "file_output_stream.h"
@@ -28,15 +29,20 @@
 
 class CodeOutput {
  public:
-  virtual void SetCodeOffset(size_t offset) = 0;
   virtual bool Write(OutputStream* out) = 0;
   virtual ~CodeOutput() {}
 };
 
+// Writes ELF file.
+// The main complication is that the sections often want to reference
+// each other.  We solve this by writing the ELF file in two stages:
+//  * Sections are asked about their size, and overall layout is calculated.
+//  * Sections do the actual writes which may use offsets of other sections.
 template <typename ElfTypes>
 class ElfBuilder FINAL {
  public:
   using Elf_Addr = typename ElfTypes::Addr;
+  using Elf_Off = typename ElfTypes::Off;
   using Elf_Word = typename ElfTypes::Word;
   using Elf_Sword = typename ElfTypes::Sword;
   using Elf_Ehdr = typename ElfTypes::Ehdr;
@@ -45,36 +51,43 @@
   using Elf_Phdr = typename ElfTypes::Phdr;
   using Elf_Dyn = typename ElfTypes::Dyn;
 
-  class ElfSectionBuilder : public ValueObject {
+  // Base class of all sections.
+  class Section {
    public:
-    ElfSectionBuilder(const std::string& sec_name, Elf_Word type, Elf_Word flags,
-                      const ElfSectionBuilder *link, Elf_Word info,
-                      Elf_Word align, Elf_Word entsize)
-        : section_index_(0), name_(sec_name), link_(link) {
-      memset(&section_, 0, sizeof(section_));
-      section_.sh_type = type;
-      section_.sh_flags = flags;
-      section_.sh_info = info;
-      section_.sh_addralign = align;
-      section_.sh_entsize = entsize;
+    Section(const std::string& name, Elf_Word type, Elf_Word flags,
+            const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize)
+        : header_(), section_index_(0), name_(name), link_(link) {
+      header_.sh_type = type;
+      header_.sh_flags = flags;
+      header_.sh_info = info;
+      header_.sh_addralign = align;
+      header_.sh_entsize = entsize;
     }
-    ElfSectionBuilder(const ElfSectionBuilder&) = default;
+    virtual ~Section() {}
 
-    ~ElfSectionBuilder() {}
+    // Returns the size of the content of this section.  It is used to
+    // calculate file offsets of all sections before doing any writes.
+    virtual Elf_Word GetSize() const = 0;
+
+    // Write the content of this section to the given file.
+    // This must write exactly the number of bytes returned by GetSize().
+    // Offsets of all sections are known when this method is called.
+    virtual bool Write(File* elf_file) = 0;
 
     Elf_Word GetLink() const {
-      return (link_ != nullptr) ? link_->section_index_ : 0;
+      return (link_ != nullptr) ? link_->GetSectionIndex() : 0;
     }
 
-    const Elf_Shdr* GetSection() const {
-      return &section_;
+    const Elf_Shdr* GetHeader() const {
+      return &header_;
     }
 
-    Elf_Shdr* GetSection() {
-      return &section_;
+    Elf_Shdr* GetHeader() {
+      return &header_;
     }
 
     Elf_Word GetSectionIndex() const {
+      DCHECK_NE(section_index_, 0u);
       return section_index_;
     }
 
@@ -87,171 +100,303 @@
     }
 
    private:
-    Elf_Shdr section_;
+    Elf_Shdr header_;
     Elf_Word section_index_;
     const std::string name_;
-    const ElfSectionBuilder* const link_;
+    const Section* const link_;
+
+    DISALLOW_COPY_AND_ASSIGN(Section);
   };
 
-  class ElfDynamicBuilder FINAL : public ElfSectionBuilder {
+  // Writer of .dynamic section.
+  class DynamicSection FINAL : public Section {
    public:
-    void AddDynamicTag(Elf_Sword tag, Elf_Word d_un) {
-      if (tag == DT_NULL) {
-        return;
-      }
-      dynamics_.push_back({nullptr, tag, d_un});
+    void AddDynamicTag(Elf_Sword tag, Elf_Word value, const Section* section) {
+      DCHECK_NE(tag, static_cast<Elf_Sword>(DT_NULL));
+      dynamics_.push_back({tag, value, section});
     }
 
-    void AddDynamicTag(Elf_Sword tag, Elf_Word d_un,
-                       const ElfSectionBuilder* section) {
-      if (tag == DT_NULL) {
-        return;
-      }
-      dynamics_.push_back({section, tag, d_un});
+    DynamicSection(const std::string& name, Section* link)
+        : Section(name, SHT_DYNAMIC, SHF_ALLOC,
+                  link, 0, kPageSize, sizeof(Elf_Dyn)) {}
+
+    Elf_Word GetSize() const OVERRIDE {
+      return (dynamics_.size() + 1 /* DT_NULL */) * sizeof(Elf_Dyn);
     }
 
-    ElfDynamicBuilder(const std::string& sec_name,
-                      ElfSectionBuilder *link)
-    : ElfSectionBuilder(sec_name, SHT_DYNAMIC, SHF_ALLOC | SHF_ALLOC,
-                                  link, 0, kPageSize, sizeof(Elf_Dyn)) {}
-    ~ElfDynamicBuilder() {}
-
-    Elf_Word GetSize() const {
-      // Add 1 for the DT_NULL, 1 for DT_STRSZ, and 1 for DT_SONAME. All of
-      // these must be added when we actually put the file together because
-      // their values are very dependent on state.
-      return dynamics_.size() + 3;
-    }
-
-    // Create the actual dynamic vector. strsz should be the size of the .dynstr
-    // table and soname_off should be the offset of the soname in .dynstr.
-    // Since niether can be found prior to final layout we will wait until here
-    // to add them.
-    std::vector<Elf_Dyn> GetDynamics(Elf_Word strsz, Elf_Word soname) const {
-      std::vector<Elf_Dyn> ret;
-      for (auto it = dynamics_.cbegin(); it != dynamics_.cend(); ++it) {
-        if (it->section_ != nullptr) {
+    bool Write(File* elf_file) OVERRIDE {
+      std::vector<Elf_Dyn> buffer;
+      buffer.reserve(dynamics_.size() + 1u);
+      for (const ElfDynamicState& it : dynamics_) {
+        if (it.section_ != nullptr) {
           // We are adding an address relative to a section.
-          ret.push_back(
-              {it->tag_, {it->off_ + it->section_->GetSection()->sh_addr}});
+          buffer.push_back(
+              {it.tag_, {it.value_ + it.section_->GetHeader()->sh_addr}});
         } else {
-          ret.push_back({it->tag_, {it->off_}});
+          buffer.push_back({it.tag_, {it.value_}});
         }
       }
-      ret.push_back({DT_STRSZ, {strsz}});
-      ret.push_back({DT_SONAME, {soname}});
-      ret.push_back({DT_NULL, {0}});
-      return ret;
+      buffer.push_back({DT_NULL, {0}});
+      return WriteArray(elf_file, buffer.data(), buffer.size());
     }
 
    private:
     struct ElfDynamicState {
-      const ElfSectionBuilder* section_;
       Elf_Sword tag_;
-      Elf_Word off_;
+      Elf_Word value_;
+      const Section* section_;
     };
     std::vector<ElfDynamicState> dynamics_;
   };
 
-  class ElfRawSectionBuilder FINAL : public ElfSectionBuilder {
+  // Section with content based on simple memory buffer.
+  // The buffer can be optionally patched before writing.
+  // The resulting address can be either absolute memory
+  // address or offset relative to the pointer location.
+  class RawSection FINAL : public Section {
    public:
-    ElfRawSectionBuilder(const std::string& sec_name, Elf_Word type, Elf_Word flags,
-                         const ElfSectionBuilder* link, Elf_Word info,
-                         Elf_Word align, Elf_Word entsize)
-      : ElfSectionBuilder(sec_name, type, flags, link, info, align, entsize) {
+    RawSection(const std::string& name, Elf_Word type, Elf_Word flags,
+               const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize,
+               const Section* patch_base = nullptr, bool patch_relative = false,
+               bool patch_64bit = (sizeof(Elf_Addr) == sizeof(Elf64_Addr)))
+        : Section(name, type, flags, link, info, align, entsize),
+          patched(false), patch_base_(patch_base),
+          patch_relative_(patch_relative), patch_64bit_(patch_64bit) {
     }
-    ElfRawSectionBuilder(const ElfRawSectionBuilder&) = default;
 
-    ~ElfRawSectionBuilder() {}
+    Elf_Word GetSize() const OVERRIDE {
+      return buffer_.size();
+    }
+
+    bool Write(File* elf_file) OVERRIDE {
+      if (!patch_locations_.empty()) {
+        DCHECK(patch_base_ != nullptr);
+        DCHECK(!patched);  // Do not patch twice.
+        if (patch_relative_) {
+          if (patch_64bit_) {
+            Patch<true, uint64_t>();
+          } else {
+            Patch<true, uint32_t>();
+          }
+        } else {
+          if (patch_64bit_) {
+            Patch<false, uint64_t>();
+          } else {
+            Patch<false, uint32_t>();
+          }
+        }
+        patched = true;
+      }
+      return WriteArray(elf_file, buffer_.data(), buffer_.size());
+    }
+
+    bool IsEmpty() const {
+      return buffer_.size() == 0;
+    }
 
     std::vector<uint8_t>* GetBuffer() {
-      return &buf_;
+      return &buffer_;
     }
 
-    void SetBuffer(const std::vector<uint8_t>& buf) {
-      buf_ = buf;
+    void SetBuffer(const std::vector<uint8_t>& buffer) {
+      buffer_ = buffer;
+    }
+
+    std::vector<uintptr_t>* GetPatchLocations() {
+      return &patch_locations_;
     }
 
    private:
-    std::vector<uint8_t> buf_;
+    template <bool RelativeAddress = false, typename PatchedAddress = Elf_Addr>
+    void Patch() {
+      Elf_Addr base_addr = patch_base_->GetHeader()->sh_addr;
+      Elf_Addr addr = this->GetHeader()->sh_addr;
+      for (uintptr_t patch_location : patch_locations_) {
+        typedef __attribute__((__aligned__(1))) PatchedAddress UnalignedAddress;
+        auto* to_patch = reinterpret_cast<UnalignedAddress*>(buffer_.data() + patch_location);
+        *to_patch = (base_addr + *to_patch) - (RelativeAddress ? (addr + patch_location) : 0);
+      }
+    }
+
+    std::vector<uint8_t> buffer_;
+    std::vector<uintptr_t> patch_locations_;
+    bool patched;
+    const Section* patch_base_;
+    bool patch_relative_;
+    bool patch_64bit_;
   };
 
-  class ElfOatSectionBuilder FINAL : public ElfSectionBuilder {
+  // Writer of .rodata section or .text section.
+  // The write is done lazily using the provided CodeOutput.
+  class OatSection FINAL : public Section {
    public:
-    ElfOatSectionBuilder(const std::string& sec_name, Elf_Word size, Elf_Word offset,
-                         Elf_Word type, Elf_Word flags)
-      : ElfSectionBuilder(sec_name, type, flags, nullptr, 0, kPageSize, 0),
-        offset_(offset), size_(size) {
+    OatSection(const std::string& name, Elf_Word type, Elf_Word flags,
+               const Section* link, Elf_Word info, Elf_Word align,
+               Elf_Word entsize, Elf_Word size, CodeOutput* code_output)
+        : Section(name, type, flags, link, info, align, entsize),
+          size_(size), code_output_(code_output) {
     }
 
-    ~ElfOatSectionBuilder() {}
-
-    Elf_Word GetOffset() const {
-      return offset_;
-    }
-
-    Elf_Word GetSize() const {
+    Elf_Word GetSize() const OVERRIDE {
       return size_;
     }
 
+    bool Write(File* elf_file) OVERRIDE {
+      // The BufferedOutputStream class contains the buffer as field,
+      // therefore it is too big to allocate on the stack.
+      std::unique_ptr<BufferedOutputStream> output_stream(
+          new BufferedOutputStream(new FileOutputStream(elf_file)));
+      return code_output_->Write(output_stream.get());
+    }
+
    private:
-    // Offset of the content within the file.
-    Elf_Word offset_;
-    // Size of the content within the file.
+    Elf_Word size_;
+    CodeOutput* code_output_;
+  };
+
+  // Writer of .bss section.
+  class NoBitsSection FINAL : public Section {
+   public:
+    NoBitsSection(const std::string& name, Elf_Word size)
+        : Section(name, SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
+          size_(size) {
+    }
+
+    Elf_Word GetSize() const OVERRIDE {
+      return size_;
+    }
+
+    bool Write(File* elf_file ATTRIBUTE_UNUSED) OVERRIDE {
+      LOG(ERROR) << "This section should not be written to the ELF file";
+      return false;
+    }
+
+   private:
     Elf_Word size_;
   };
 
-  static inline constexpr uint8_t MakeStInfo(uint8_t binding, uint8_t type) {
-    return ((binding) << 4) + ((type) & 0xf);
-  }
-
-  // from bionic
-  static inline unsigned elfhash(const char *_name) {
-    const unsigned char *name = (const unsigned char *) _name;
-    unsigned h = 0, g;
-
-    while (*name) {
-      h = (h << 4) + *name++;
-      g = h & 0xf0000000;
-      h ^= g;
-      h ^= g >> 24;
+  // Writer of .dynstr .strtab and .shstrtab sections.
+  class StrtabSection FINAL : public Section {
+   public:
+    StrtabSection(const std::string& name, Elf_Word flags)
+        : Section(name, SHT_STRTAB, flags, nullptr, 0, 1, 1) {
+      buffer_.reserve(4 * KB);
+      // The first entry of strtab must be empty string.
+      buffer_ += '\0';
     }
-    return h;
-  }
 
-  class ElfSymtabBuilder FINAL : public ElfSectionBuilder {
+    Elf_Word AddName(const std::string& name) {
+      Elf_Word offset = buffer_.size();
+      buffer_ += name;
+      buffer_ += '\0';
+      return offset;
+    }
+
+    Elf_Word GetSize() const OVERRIDE {
+      return buffer_.size();
+    }
+
+    bool Write(File* elf_file) OVERRIDE {
+      return WriteArray(elf_file, buffer_.data(), buffer_.size());
+    }
+
+   private:
+    std::string buffer_;
+  };
+
+  class HashSection;
+
+  // Writer of .dynsym and .symtab sections.
+  class SymtabSection FINAL : public Section {
    public:
     // Add a symbol with given name to this symtab. The symbol refers to
     // 'relative_addr' within the given section and has the given attributes.
-    void AddSymbol(const std::string& name,
-                   const ElfSectionBuilder* section,
-                   Elf_Addr addr,
-                   bool is_relative,
-                   Elf_Word size,
-                   uint8_t binding,
-                   uint8_t type,
-                   uint8_t other = 0) {
-      CHECK(section);
-      ElfSymtabBuilder::ElfSymbolState state {name, section, addr, size, is_relative,
-                                              MakeStInfo(binding, type), other, 0};
-      symbols_.push_back(state);
+    void AddSymbol(const std::string& name, const Section* section,
+                   Elf_Addr addr, bool is_relative, Elf_Word size,
+                   uint8_t binding, uint8_t type, uint8_t other = 0) {
+      CHECK(section != nullptr);
+      Elf_Word name_idx = strtab_->AddName(name);
+      symbols_.push_back({ name, section, addr, size, is_relative,
+                           MakeStInfo(binding, type), other, name_idx });
     }
 
-    ElfSymtabBuilder(const std::string& sec_name, Elf_Word type,
-                     const std::string& str_name, Elf_Word str_type, bool alloc)
-    : ElfSectionBuilder(sec_name, type, ((alloc) ? SHF_ALLOC : 0U),
-                        &strtab_, 0, sizeof(Elf_Word),
-                        sizeof(Elf_Sym)), str_name_(str_name),
-                        str_type_(str_type),
-                        strtab_(str_name,
-                                str_type,
-                                ((alloc) ? SHF_ALLOC : 0U),
-                                nullptr, 0, 1, 1) {
+    SymtabSection(const std::string& name, Elf_Word type, Elf_Word flags,
+                  StrtabSection* strtab)
+        : Section(name, type, flags, strtab, 0, sizeof(Elf_Word), sizeof(Elf_Sym)),
+          strtab_(strtab) {
     }
 
-    ~ElfSymtabBuilder() {}
+    bool IsEmpty() const {
+      return symbols_.empty();
+    }
 
-    std::vector<Elf_Word> GenerateHashContents() const {
+    Elf_Word GetSize() const OVERRIDE {
+      return (1 /* NULL */ + symbols_.size()) * sizeof(Elf_Sym);
+    }
+
+    bool Write(File* elf_file) OVERRIDE {
+      std::vector<Elf_Sym> buffer;
+      buffer.reserve(1u + symbols_.size());
+      buffer.push_back(Elf_Sym());  // NULL.
+      for (const ElfSymbolState& it : symbols_) {
+        Elf_Sym sym = Elf_Sym();
+        sym.st_name = it.name_idx_;
+        if (it.is_relative_) {
+          sym.st_value = it.addr_ + it.section_->GetHeader()->sh_addr;
+        } else {
+          sym.st_value = it.addr_;
+        }
+        sym.st_size = it.size_;
+        sym.st_other = it.other_;
+        sym.st_shndx = it.section_->GetSectionIndex();
+        sym.st_info = it.info_;
+        buffer.push_back(sym);
+      }
+      return WriteArray(elf_file, buffer.data(), buffer.size());
+    }
+
+   private:
+    struct ElfSymbolState {
+      const std::string name_;
+      const Section* section_;
+      Elf_Addr addr_;
+      Elf_Word size_;
+      bool is_relative_;
+      uint8_t info_;
+      uint8_t other_;
+      Elf_Word name_idx_;  // index in the strtab.
+    };
+
+    static inline constexpr uint8_t MakeStInfo(uint8_t binding, uint8_t type) {
+      return ((binding) << 4) + ((type) & 0xf);
+    }
+
+    // The symbols in the same order they will be in the symbol table.
+    std::vector<ElfSymbolState> symbols_;
+    StrtabSection* strtab_;
+
+    friend class HashSection;
+  };
+
+  // TODO: Consider removing.
+  // We use it only for the dynsym section which has only 5 symbols.
+  // We do not use it for symtab, and we probably do not have to
+  // since we use those symbols only to print backtraces.
+  class HashSection FINAL : public Section {
+   public:
+    HashSection(const std::string& name, Elf_Word flags, SymtabSection* symtab)
+        : Section(name, SHT_HASH, flags, symtab,
+                  0, sizeof(Elf_Word), sizeof(Elf_Word)),
+          symtab_(symtab) {
+    }
+
+    Elf_Word GetSize() const OVERRIDE {
+      Elf_Word nbuckets = GetNumBuckets();
+      Elf_Word chain_size = symtab_->symbols_.size() + 1 /* NULL */;
+      return (2 /* header */ + nbuckets + chain_size) * sizeof(Elf_Word);
+    }
+
+    bool Write(File* const elf_file) OVERRIDE {
       // Here is how The ELF hash table works.
       // There are 3 arrays to worry about.
       // * The symbol table where the symbol information is.
@@ -282,21 +427,12 @@
       //
       // Between bucket and chain arrays every symtab index must be present exactly
       // once (except for STN_UNDEF, which must be present 1 + num_bucket times).
-
+      const auto& symbols = symtab_->symbols_;
       // Select number of buckets.
       // This is essentially arbitrary.
-      Elf_Word nbuckets;
-      Elf_Word chain_size = GetSize();
-      if (symbols_.size() < 8) {
-        nbuckets = 2;
-      } else if (symbols_.size() < 32) {
-        nbuckets = 4;
-      } else if (symbols_.size() < 256) {
-        nbuckets = 16;
-      } else {
-        // Have about 32 ids per bucket.
-        nbuckets = RoundUp(symbols_.size()/32, 2);
-      }
+      Elf_Word nbuckets = GetNumBuckets();
+      // 1 is for the implicit NULL symbol.
+      Elf_Word chain_size = (symbols.size() + 1);
       std::vector<Elf_Word> hash;
       hash.push_back(nbuckets);
       hash.push_back(chain_size);
@@ -308,11 +444,11 @@
       Elf_Word* chain   = hash.data() + chain_offset;
 
       // Set up the actual hash table.
-      for (Elf_Word i = 0; i < symbols_.size(); i++) {
+      for (Elf_Word i = 0; i < symbols.size(); i++) {
         // Add 1 since we need to have the null symbol that is not in the symbols
         // list.
         Elf_Word index = i + 1;
-        Elf_Word hash_val = static_cast<Elf_Word>(elfhash(symbols_[i].name_.c_str())) % nbuckets;
+        Elf_Word hash_val = static_cast<Elf_Word>(elfhash(symbols[i].name_.c_str())) % nbuckets;
         if (buckets[hash_val] == 0) {
           buckets[hash_val] = index;
         } else {
@@ -329,251 +465,67 @@
           CHECK_EQ(chain[index], static_cast<Elf_Word>(0));
         }
       }
-
-      return hash;
-    }
-
-    std::string GenerateStrtab() {
-      std::string tab;
-      tab += '\0';
-      for (auto it = symbols_.begin(); it != symbols_.end(); ++it) {
-        it->name_idx_ = tab.size();
-        tab += it->name_;
-        tab += '\0';
-      }
-      strtab_.GetSection()->sh_size = tab.size();
-      return tab;
-    }
-
-    std::vector<Elf_Sym> GenerateSymtab() {
-      std::vector<Elf_Sym> ret;
-      Elf_Sym undef_sym;
-      memset(&undef_sym, 0, sizeof(undef_sym));
-      undef_sym.st_shndx = SHN_UNDEF;
-      ret.push_back(undef_sym);
-
-      for (auto it = symbols_.cbegin(); it != symbols_.cend(); ++it) {
-        Elf_Sym sym;
-        memset(&sym, 0, sizeof(sym));
-        sym.st_name = it->name_idx_;
-        if (it->is_relative_) {
-          sym.st_value = it->addr_ + it->section_->GetSection()->sh_offset;
-        } else {
-          sym.st_value = it->addr_;
-        }
-        sym.st_size = it->size_;
-        sym.st_other = it->other_;
-        sym.st_shndx = it->section_->GetSectionIndex();
-        sym.st_info = it->info_;
-
-        ret.push_back(sym);
-      }
-      return ret;
-    }
-
-    Elf_Word GetSize() const {
-      // 1 is for the implicit null symbol.
-      return symbols_.size() + 1;
-    }
-
-    ElfSectionBuilder* GetStrTab() {
-      return &strtab_;
+      return WriteArray(elf_file, hash.data(), hash.size());
     }
 
    private:
-    struct ElfSymbolState {
-      const std::string name_;
-      const ElfSectionBuilder* section_;
-      Elf_Addr addr_;
-      Elf_Word size_;
-      bool is_relative_;
-      uint8_t info_;
-      uint8_t other_;
-      // Used during Write() to temporarially hold name index in the strtab.
-      Elf_Word name_idx_;
-    };
-
-    // Information for the strsym for dynstr sections.
-    const std::string str_name_;
-    Elf_Word str_type_;
-    // The symbols in the same order they will be in the symbol table.
-    std::vector<ElfSymbolState> symbols_;
-    ElfSectionBuilder strtab_;
-  };
-
-  template <typename Elf_Word>
-  class ElfFilePiece {
-   public:
-    virtual ~ElfFilePiece() {}
-
-    virtual bool Write(File* elf_file) {
-      if (static_cast<off_t>(offset_) != lseek(elf_file->Fd(), offset_, SEEK_SET)) {
-        PLOG(ERROR) << "Failed to seek to " << GetDescription() << " offset " << offset_ << " for "
-            << elf_file->GetPath();
-        return false;
-      }
-
-      return DoActualWrite(elf_file);
-    }
-
-    static bool Compare(ElfFilePiece* a, ElfFilePiece* b) {
-      return a->offset_ < b->offset_;
-    }
-
-   protected:
-    explicit ElfFilePiece(Elf_Word offset) : offset_(offset) {}
-
-    Elf_Word GetOffset() const {
-      return offset_;
-    }
-
-    virtual const char* GetDescription() const = 0;
-    virtual bool DoActualWrite(File* elf_file) = 0;
-
-   private:
-    const Elf_Word offset_;
-
-    DISALLOW_COPY_AND_ASSIGN(ElfFilePiece);
-  };
-
-  template <typename Elf_Word>
-  class ElfFileMemoryPiece FINAL : public ElfFilePiece<Elf_Word> {
-   public:
-    ElfFileMemoryPiece(const std::string& name, Elf_Word offset, const void* data, Elf_Word size)
-        : ElfFilePiece<Elf_Word>(offset), dbg_name_(name), data_(data), size_(size) {}
-
-   protected:
-    bool DoActualWrite(File* elf_file) OVERRIDE {
-      DCHECK(data_ != nullptr || size_ == 0U) << dbg_name_ << " " << size_;
-
-      if (!elf_file->WriteFully(data_, size_)) {
-        PLOG(ERROR) << "Failed to write " << dbg_name_ << " for " << elf_file->GetPath();
-        return false;
-      }
-
-      return true;
-    }
-
-    const char* GetDescription() const OVERRIDE {
-      return dbg_name_.c_str();
-    }
-
-   private:
-    const std::string& dbg_name_;
-    const void *data_;
-    Elf_Word size_;
-  };
-
-  template <typename Elf_Word>
-  class ElfFileRodataPiece FINAL : public ElfFilePiece<Elf_Word> {
-   public:
-    ElfFileRodataPiece(Elf_Word offset, CodeOutput* output) : ElfFilePiece<Elf_Word>(offset),
-        output_(output) {}
-
-   protected:
-    bool DoActualWrite(File* elf_file) OVERRIDE {
-      output_->SetCodeOffset(this->GetOffset());
-      std::unique_ptr<BufferedOutputStream> output_stream(
-          new BufferedOutputStream(new FileOutputStream(elf_file)));
-      if (!output_->Write(output_stream.get())) {
-        PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file->GetPath();
-        return false;
-      }
-
-      return true;
-    }
-
-    const char* GetDescription() const OVERRIDE {
-      return ".rodata";
-    }
-
-   private:
-    CodeOutput* const output_;
-
-    DISALLOW_COPY_AND_ASSIGN(ElfFileRodataPiece);
-  };
-
-  template <typename Elf_Word>
-  class ElfFileOatTextPiece FINAL : public ElfFilePiece<Elf_Word> {
-   public:
-    ElfFileOatTextPiece(Elf_Word offset, CodeOutput* output) : ElfFilePiece<Elf_Word>(offset),
-        output_(output) {}
-
-   protected:
-    bool DoActualWrite(File* elf_file ATTRIBUTE_UNUSED) OVERRIDE {
-      // All data is written by the ElfFileRodataPiece right now, as the oat writer writes in one
-      // piece. This is for future flexibility.
-      UNUSED(output_);
-      return true;
-    }
-
-    const char* GetDescription() const OVERRIDE {
-      return ".text";
-    }
-
-   private:
-    CodeOutput* const output_;
-
-    DISALLOW_COPY_AND_ASSIGN(ElfFileOatTextPiece);
-  };
-
-  template <typename Elf_Word>
-  static bool WriteOutFile(const std::vector<ElfFilePiece<Elf_Word>*>& pieces, File* elf_file) {
-    // TODO It would be nice if this checked for overlap.
-    for (auto it = pieces.begin(); it != pieces.end(); ++it) {
-      if (!(*it)->Write(elf_file)) {
-        return false;
+    Elf_Word GetNumBuckets() const {
+      const auto& symbols = symtab_->symbols_;
+      if (symbols.size() < 8) {
+        return 2;
+      } else if (symbols.size() < 32) {
+        return 4;
+      } else if (symbols.size() < 256) {
+        return 16;
+      } else {
+        // Have about 32 ids per bucket.
+        return RoundUp(symbols.size()/32, 2);
       }
     }
-    return true;
-  }
 
-  template <typename Elf_Word, typename Elf_Shdr>
-  static inline constexpr Elf_Word NextOffset(const Elf_Shdr& cur, const Elf_Shdr& prev) {
-    return RoundUp(prev.sh_size + prev.sh_offset, cur.sh_addralign);
-  }
+    // from bionic
+    static inline unsigned elfhash(const char *_name) {
+      const unsigned char *name = (const unsigned char *) _name;
+      unsigned h = 0, g;
 
-  ElfBuilder(CodeOutput* oat_writer,
-             File* elf_file,
-             InstructionSet isa,
-             Elf_Word rodata_relative_offset,
-             Elf_Word rodata_size,
-             Elf_Word text_relative_offset,
-             Elf_Word text_size,
-             Elf_Word bss_relative_offset,
-             Elf_Word bss_size,
-             const bool add_symbols,
-             bool debug = false)
-    : oat_writer_(oat_writer),
-      elf_file_(elf_file),
-      add_symbols_(add_symbols),
-      debug_logging_(debug),
-      text_builder_(".text", text_size, text_relative_offset, SHT_PROGBITS,
-                    SHF_ALLOC | SHF_EXECINSTR),
-      rodata_builder_(".rodata", rodata_size, rodata_relative_offset, SHT_PROGBITS, SHF_ALLOC),
-      bss_builder_(".bss", bss_size, bss_relative_offset, SHT_NOBITS, SHF_ALLOC),
-      dynsym_builder_(".dynsym", SHT_DYNSYM, ".dynstr", SHT_STRTAB, true),
-      symtab_builder_(".symtab", SHT_SYMTAB, ".strtab", SHT_STRTAB, false),
-      hash_builder_(".hash", SHT_HASH, SHF_ALLOC, &dynsym_builder_, 0, sizeof(Elf_Word),
-                    sizeof(Elf_Word)),
-      dynamic_builder_(".dynamic", &dynsym_builder_),
-      shstrtab_builder_(".shstrtab", SHT_STRTAB, 0, nullptr, 0, 1, 1) {
-    SetupEhdr();
-    SetupDynamic();
-    SetupRequiredSymbols();
-    SetISA(isa);
+      while (*name) {
+        h = (h << 4) + *name++;
+        g = h & 0xf0000000;
+        h ^= g;
+        h ^= g >> 24;
+      }
+      return h;
+    }
+
+    SymtabSection* symtab_;
+
+    DISALLOW_COPY_AND_ASSIGN(HashSection);
+  };
+
+  ElfBuilder(InstructionSet isa,
+             Elf_Word rodata_size, CodeOutput* rodata_writer,
+             Elf_Word text_size, CodeOutput* text_writer,
+             Elf_Word bss_size)
+    : isa_(isa),
+      dynstr_(".dynstr", SHF_ALLOC),
+      dynsym_(".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_),
+      hash_(".hash", SHF_ALLOC, &dynsym_),
+      rodata_(".rodata", SHT_PROGBITS, SHF_ALLOC,
+              nullptr, 0, kPageSize, 0, rodata_size, rodata_writer),
+      text_(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
+            nullptr, 0, kPageSize, 0, text_size, text_writer),
+      bss_(".bss", bss_size),
+      dynamic_(".dynamic", &dynsym_),
+      strtab_(".strtab", 0),
+      symtab_(".symtab", SHT_SYMTAB, 0, &strtab_),
+      shstrtab_(".shstrtab", 0) {
   }
   ~ElfBuilder() {}
 
-  const ElfOatSectionBuilder& GetTextBuilder() const {
-    return text_builder_;
-  }
+  OatSection* GetText() { return &text_; }
+  SymtabSection* GetSymtab() { return &symtab_; }
 
-  ElfSymtabBuilder* GetSymtabBuilder() {
-    return &symtab_builder_;
-  }
-
-  bool Init() {
+  bool Write(File* elf_file) {
     // Since the .text section of an oat file contains relative references to .rodata
     // and (optionally) .bss, we keep these 2 or 3 sections together. This creates
     // a non-traditional layout where the .bss section is mapped independently of the
@@ -600,21 +552,10 @@
     // | Elf_Sym  oatbsslastword | (Optional)
     // +-------------------------+
     // | .dynstr                 |
-    // | \0                      |
-    // | oatdata\0               |
-    // | oatexec\0               |
-    // | oatlastword\0           |
-    // | boot.oat\0              |
+    // | names for .dynsym       |
     // +-------------------------+
     // | .hash                   |
-    // | Elf_Word nbucket = b    |
-    // | Elf_Word nchain  = c    |
-    // | Elf_Word bucket[0]      |
-    // |         ...             |
-    // | Elf_Word bucket[b - 1]  |
-    // | Elf_Word chain[0]       |
-    // |         ...             |
-    // | Elf_Word chain[c - 1]   |
+    // | hashtable for dynsym    |
     // +-------------------------+
     // | .eh_frame               |  (Optional)
     // +-------------------------+
@@ -627,38 +568,19 @@
     // | oatexec..oatlastword    |
     // +-------------------------+
     // | .dynamic                |
-    // | Elf_Dyn DT_SONAME       |
     // | Elf_Dyn DT_HASH         |
+    // | Elf_Dyn DT_STRTAB       |
     // | Elf_Dyn DT_SYMTAB       |
     // | Elf_Dyn DT_SYMENT       |
-    // | Elf_Dyn DT_STRTAB       |
     // | Elf_Dyn DT_STRSZ        |
+    // | Elf_Dyn DT_SONAME       |
     // | Elf_Dyn DT_NULL         |
     // +-------------------------+  (Optional)
-    // | .strtab                 |  (Optional)
-    // | program symbol names    |  (Optional)
-    // +-------------------------+  (Optional)
     // | .symtab                 |  (Optional)
     // | program symbols         |  (Optional)
-    // +-------------------------+
-    // | .shstrtab               |
-    // | \0                      |
-    // | .dynamic\0              |
-    // | .dynsym\0               |
-    // | .dynstr\0               |
-    // | .hash\0                 |
-    // | .rodata\0               |
-    // | .text\0                 |
-    // | .bss\0                  |  (Optional)
-    // | .shstrtab\0             |
-    // | .symtab\0               |  (Optional)
-    // | .strtab\0               |  (Optional)
-    // | .eh_frame\0             |  (Optional)
-    // | .eh_frame_hdr\0         |  (Optional)
-    // | .debug_info\0           |  (Optional)
-    // | .debug_abbrev\0         |  (Optional)
-    // | .debug_str\0            |  (Optional)
-    // | .debug_line\0           |  (Optional)
+    // +-------------------------+  (Optional)
+    // | .strtab                 |  (Optional)
+    // | names for .symtab       |  (Optional)
     // +-------------------------+  (Optional)
     // | .debug_info             |  (Optional)
     // +-------------------------+  (Optional)
@@ -667,574 +589,280 @@
     // | .debug_str              |  (Optional)
     // +-------------------------+  (Optional)
     // | .debug_line             |  (Optional)
-    // +-------------------------+  (Optional)
+    // +-------------------------+
+    // | .shstrtab               |
+    // | names of sections       |
+    // +-------------------------+
     // | Elf_Shdr null           |
     // | Elf_Shdr .dynsym        |
     // | Elf_Shdr .dynstr        |
     // | Elf_Shdr .hash          |
+    // | Elf_Shdr .eh_frame      |  (Optional)
+    // | Elf_Shdr .eh_frame_hdr  |  (Optional)
     // | Elf_Shdr .rodata        |
     // | Elf_Shdr .text          |
     // | Elf_Shdr .bss           |  (Optional)
     // | Elf_Shdr .dynamic       |
-    // | Elf_Shdr .shstrtab      |
-    // | Elf_Shdr .eh_frame      |  (Optional)
-    // | Elf_Shdr .eh_frame_hdr  |  (Optional)
+    // | Elf_Shdr .symtab        |  (Optional)
+    // | Elf_Shdr .strtab        |  (Optional)
     // | Elf_Shdr .debug_info    |  (Optional)
     // | Elf_Shdr .debug_abbrev  |  (Optional)
     // | Elf_Shdr .debug_str     |  (Optional)
     // | Elf_Shdr .debug_line    |  (Optional)
+    // | Elf_Shdr .oat_patches   |  (Optional)
+    // | Elf_Shdr .shstrtab      |
     // +-------------------------+
+    constexpr bool debug_logging_ = false;
 
-    if (fatal_error_) {
-      return false;
-    }
-    // Step 1. Figure out all the offsets.
-
-    if (debug_logging_) {
-      LOG(INFO) << "phdr_offset=" << PHDR_OFFSET << std::hex << " " << PHDR_OFFSET;
-      LOG(INFO) << "phdr_size=" << PHDR_SIZE << std::hex << " " << PHDR_SIZE;
-    }
-
-    memset(&program_headers_, 0, sizeof(program_headers_));
-    program_headers_[PH_PHDR].p_type    = PT_PHDR;
-    program_headers_[PH_PHDR].p_offset  = PHDR_OFFSET;
-    program_headers_[PH_PHDR].p_vaddr   = PHDR_OFFSET;
-    program_headers_[PH_PHDR].p_paddr   = PHDR_OFFSET;
-    program_headers_[PH_PHDR].p_filesz  = sizeof(program_headers_);
-    program_headers_[PH_PHDR].p_memsz   = sizeof(program_headers_);
-    program_headers_[PH_PHDR].p_flags   = PF_R;
-    program_headers_[PH_PHDR].p_align   = sizeof(Elf_Word);
-
-    program_headers_[PH_LOAD_R__].p_type    = PT_LOAD;
-    program_headers_[PH_LOAD_R__].p_offset  = 0;
-    program_headers_[PH_LOAD_R__].p_vaddr   = 0;
-    program_headers_[PH_LOAD_R__].p_paddr   = 0;
-    program_headers_[PH_LOAD_R__].p_flags   = PF_R;
-
-    program_headers_[PH_LOAD_R_X].p_type    = PT_LOAD;
-    program_headers_[PH_LOAD_R_X].p_flags   = PF_R | PF_X;
-
-    program_headers_[PH_LOAD_RW_BSS].p_type    = PT_LOAD;
-    program_headers_[PH_LOAD_RW_BSS].p_flags   = PF_R | PF_W;
-
-    program_headers_[PH_LOAD_RW_DYNAMIC].p_type    = PT_LOAD;
-    program_headers_[PH_LOAD_RW_DYNAMIC].p_flags   = PF_R | PF_W;
-
-    program_headers_[PH_DYNAMIC].p_type    = PT_DYNAMIC;
-    program_headers_[PH_DYNAMIC].p_flags   = PF_R | PF_W;
-
-    program_headers_[PH_EH_FRAME_HDR].p_type = PT_NULL;
-    program_headers_[PH_EH_FRAME_HDR].p_flags = PF_R;
-
-    // Get the dynstr string.
-    dynstr_ = dynsym_builder_.GenerateStrtab();
-
-    // Add the SONAME to the dynstr.
-    dynstr_soname_offset_ = dynstr_.size();
-    std::string file_name(elf_file_->GetPath());
-    size_t directory_separator_pos = file_name.rfind('/');
-    if (directory_separator_pos != std::string::npos) {
-      file_name = file_name.substr(directory_separator_pos + 1);
-    }
-    dynstr_ += file_name;
-    dynstr_ += '\0';
-    if (debug_logging_) {
-      LOG(INFO) << "dynstr size (bytes)   =" << dynstr_.size()
-                << std::hex << " " << dynstr_.size();
-      LOG(INFO) << "dynsym size (elements)=" << dynsym_builder_.GetSize()
-                << std::hex << " " << dynsym_builder_.GetSize();
-    }
-
-    // Get the section header string table.
-    shstrtab_ += '\0';
-
-    // Setup sym_undef
-    memset(&null_hdr_, 0, sizeof(null_hdr_));
-    null_hdr_.sh_type = SHT_NULL;
-    null_hdr_.sh_link = SHN_UNDEF;
-    section_ptrs_.push_back(&null_hdr_);
-
-    section_index_ = 1;
-
-    // setup .dynsym
-    section_ptrs_.push_back(dynsym_builder_.GetSection());
-    AssignSectionStr(&dynsym_builder_, &shstrtab_);
-    dynsym_builder_.SetSectionIndex(section_index_);
-    section_index_++;
-
-    // Setup .dynstr
-    section_ptrs_.push_back(dynsym_builder_.GetStrTab()->GetSection());
-    AssignSectionStr(dynsym_builder_.GetStrTab(), &shstrtab_);
-    dynsym_builder_.GetStrTab()->SetSectionIndex(section_index_);
-    section_index_++;
-
-    // Setup .hash
-    section_ptrs_.push_back(hash_builder_.GetSection());
-    AssignSectionStr(&hash_builder_, &shstrtab_);
-    hash_builder_.SetSectionIndex(section_index_);
-    section_index_++;
-
-    // Setup .eh_frame and .eh_frame_hdr
-    for (auto* builder : other_builders_) {
-      if ((builder->GetSection()->sh_flags & SHF_ALLOC) != 0) {
-        section_ptrs_.push_back(builder->GetSection());
-        AssignSectionStr(builder, &shstrtab_);
-        builder->SetSectionIndex(section_index_);
-        section_index_++;
+    // Create a list of all section which we want to write.
+    // This is the order in which they will be written.
+    std::vector<Section*> sections;
+    sections.push_back(&dynsym_);
+    sections.push_back(&dynstr_);
+    sections.push_back(&hash_);
+    for (Section* section : other_sections_) {
+      if ((section->GetHeader()->sh_flags & SHF_ALLOC) != 0) {
+        sections.push_back(section);
       }
     }
-
-    // Setup .rodata
-    section_ptrs_.push_back(rodata_builder_.GetSection());
-    AssignSectionStr(&rodata_builder_, &shstrtab_);
-    rodata_builder_.SetSectionIndex(section_index_);
-    section_index_++;
-
-    // Setup .text
-    section_ptrs_.push_back(text_builder_.GetSection());
-    AssignSectionStr(&text_builder_, &shstrtab_);
-    text_builder_.SetSectionIndex(section_index_);
-    section_index_++;
-
-    // Setup .bss
-    if (bss_builder_.GetSize() != 0u) {
-      section_ptrs_.push_back(bss_builder_.GetSection());
-      AssignSectionStr(&bss_builder_, &shstrtab_);
-      bss_builder_.SetSectionIndex(section_index_);
-      section_index_++;
+    sections.push_back(&rodata_);
+    sections.push_back(&text_);
+    if (bss_.GetSize() != 0u) {
+      sections.push_back(&bss_);
     }
-
-    // Setup .dynamic
-    section_ptrs_.push_back(dynamic_builder_.GetSection());
-    AssignSectionStr(&dynamic_builder_, &shstrtab_);
-    dynamic_builder_.SetSectionIndex(section_index_);
-    section_index_++;
-
-    // Fill in the hash section.
-    hash_ = dynsym_builder_.GenerateHashContents();
-
-    if (debug_logging_) {
-      LOG(INFO) << ".hash size (bytes)=" << hash_.size() * sizeof(Elf_Word)
-                << std::hex << " " << hash_.size() * sizeof(Elf_Word);
+    sections.push_back(&dynamic_);
+    if (!symtab_.IsEmpty()) {
+      sections.push_back(&symtab_);
+      sections.push_back(&strtab_);
     }
-
-    Elf_Word base_offset = sizeof(Elf_Ehdr) + sizeof(program_headers_);
-
-    // Get the layout in the sections.
-    //
-    // Get the layout of the dynsym section.
-    dynsym_builder_.GetSection()->sh_offset =
-        RoundUp(base_offset, dynsym_builder_.GetSection()->sh_addralign);
-    dynsym_builder_.GetSection()->sh_addr = dynsym_builder_.GetSection()->sh_offset;
-    dynsym_builder_.GetSection()->sh_size = dynsym_builder_.GetSize() * sizeof(Elf_Sym);
-    dynsym_builder_.GetSection()->sh_link = dynsym_builder_.GetLink();
-
-    // Get the layout of the dynstr section.
-    dynsym_builder_.GetStrTab()->GetSection()->sh_offset =
-        NextOffset<Elf_Word, Elf_Shdr>(*dynsym_builder_.GetStrTab()->GetSection(),
-                                       *dynsym_builder_.GetSection());
-    dynsym_builder_.GetStrTab()->GetSection()->sh_addr =
-        dynsym_builder_.GetStrTab()->GetSection()->sh_offset;
-    dynsym_builder_.GetStrTab()->GetSection()->sh_size = dynstr_.size();
-    dynsym_builder_.GetStrTab()->GetSection()->sh_link = dynsym_builder_.GetStrTab()->GetLink();
-
-    // Get the layout of the hash section
-    hash_builder_.GetSection()->sh_offset =
-        NextOffset<Elf_Word, Elf_Shdr>(*hash_builder_.GetSection(),
-                                       *dynsym_builder_.GetStrTab()->GetSection());
-    hash_builder_.GetSection()->sh_addr = hash_builder_.GetSection()->sh_offset;
-    hash_builder_.GetSection()->sh_size = hash_.size() * sizeof(Elf_Word);
-    hash_builder_.GetSection()->sh_link = hash_builder_.GetLink();
-
-    // Get the layout of the extra sections with SHF_ALLOC flag.
-    // This will deal with .eh_frame and .eh_frame_hdr.
-    // .eh_frame contains relative pointers to .text which we
-    // want to fixup between the calls to Init() and Write().
-    // Therefore we handle those sections here as opposed to Write().
-    // It also has the nice side effect of including .eh_frame
-    // with the rest of LOAD_R segment.  It must come before .rodata
-    // because .rodata and .text must be next to each other.
-    Elf_Shdr* prev = hash_builder_.GetSection();
-    for (auto* it : other_builders_) {
-      if ((it->GetSection()->sh_flags & SHF_ALLOC) != 0) {
-        it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev);
-        it->GetSection()->sh_addr = it->GetSection()->sh_offset;
-        it->GetSection()->sh_size = it->GetBuffer()->size();
-        it->GetSection()->sh_link = it->GetLink();
-        prev = it->GetSection();
+    for (Section* section : other_sections_) {
+      if ((section->GetHeader()->sh_flags & SHF_ALLOC) == 0) {
+        sections.push_back(section);
       }
     }
-    // If the sections exist, check that they have been handled.
-    const auto* eh_frame = FindRawSection(".eh_frame");
-    if (eh_frame != nullptr) {
-      DCHECK_NE(eh_frame->GetSection()->sh_offset, 0u);
-    }
-    const auto* eh_frame_hdr = FindRawSection(".eh_frame_hdr");
-    if (eh_frame_hdr != nullptr) {
-      DCHECK_NE(eh_frame_hdr->GetSection()->sh_offset, 0u);
+    sections.push_back(&shstrtab_);
+    for (size_t i = 0; i < sections.size(); i++) {
+      // The first section index is 1.  Index 0 is reserved for NULL.
+      // Section index is used for relative symbols and for section links.
+      sections[i]->SetSectionIndex(i + 1);
+      // Add section name to .shstrtab.
+      Elf_Word name_offset = shstrtab_.AddName(sections[i]->GetName());
+      sections[i]->GetHeader()->sh_name = name_offset;
     }
 
-    // Get the layout of the rodata section.
-    rodata_builder_.GetSection()->sh_offset =
-        NextOffset<Elf_Word, Elf_Shdr>(*rodata_builder_.GetSection(), *prev);
-    rodata_builder_.GetSection()->sh_addr = rodata_builder_.GetSection()->sh_offset;
-    rodata_builder_.GetSection()->sh_size = rodata_builder_.GetSize();
-    rodata_builder_.GetSection()->sh_link = rodata_builder_.GetLink();
+    // The running program does not have access to section headers
+    // and the loader is not supposed to use them either.
+    // The dynamic sections therefore replicates some of the layout
+    // information like the address and size of .rodata and .text.
+    // It also contains other metadata like the SONAME.
+    // The .dynamic section is found using the PT_DYNAMIC program header.
+    BuildDynsymSection();
+    BuildDynamicSection(elf_file->GetPath());
 
-    // Get the layout of the text section.
-    text_builder_.GetSection()->sh_offset =
-        NextOffset<Elf_Word, Elf_Shdr>(*text_builder_.GetSection(),
-                                       *rodata_builder_.GetSection());
-    text_builder_.GetSection()->sh_addr = text_builder_.GetSection()->sh_offset;
-    text_builder_.GetSection()->sh_size = text_builder_.GetSize();
-    text_builder_.GetSection()->sh_link = text_builder_.GetLink();
-    CHECK_ALIGNED(rodata_builder_.GetSection()->sh_offset +
-                  rodata_builder_.GetSection()->sh_size, kPageSize);
+    // We do not know the number of headers until the final stages of write.
+    // It is easiest to just reserve a fixed amount of space for them.
+    constexpr size_t kMaxProgramHeaders = 7;
+    constexpr size_t kProgramHeadersOffset = sizeof(Elf_Ehdr);
+    constexpr size_t kProgramHeadersSize = sizeof(Elf_Phdr) * kMaxProgramHeaders;
 
-    // Get the layout of the .bss section.
-    bss_builder_.GetSection()->sh_offset =
-        NextOffset<Elf_Word, Elf_Shdr>(*bss_builder_.GetSection(),
-                                       *text_builder_.GetSection());
-    bss_builder_.GetSection()->sh_addr = bss_builder_.GetSection()->sh_offset;
-    bss_builder_.GetSection()->sh_size = bss_builder_.GetSize();
-    bss_builder_.GetSection()->sh_link = bss_builder_.GetLink();
-
-    // Get the layout of the dynamic section.
-    CHECK(IsAlignedParam(bss_builder_.GetSection()->sh_offset,
-                         dynamic_builder_.GetSection()->sh_addralign));
-    dynamic_builder_.GetSection()->sh_offset = bss_builder_.GetSection()->sh_offset;
-    dynamic_builder_.GetSection()->sh_addr =
-        NextOffset<Elf_Word, Elf_Shdr>(*dynamic_builder_.GetSection(), *bss_builder_.GetSection());
-    dynamic_builder_.GetSection()->sh_size = dynamic_builder_.GetSize() * sizeof(Elf_Dyn);
-    dynamic_builder_.GetSection()->sh_link = dynamic_builder_.GetLink();
-
-    if (debug_logging_) {
-      LOG(INFO) << "dynsym off=" << dynsym_builder_.GetSection()->sh_offset
-                << " dynsym size=" << dynsym_builder_.GetSection()->sh_size;
-      LOG(INFO) << "dynstr off=" << dynsym_builder_.GetStrTab()->GetSection()->sh_offset
-                << " dynstr size=" << dynsym_builder_.GetStrTab()->GetSection()->sh_size;
-      LOG(INFO) << "hash off=" << hash_builder_.GetSection()->sh_offset
-                << " hash size=" << hash_builder_.GetSection()->sh_size;
-      LOG(INFO) << "rodata off=" << rodata_builder_.GetSection()->sh_offset
-                << " rodata size=" << rodata_builder_.GetSection()->sh_size;
-      LOG(INFO) << "text off=" << text_builder_.GetSection()->sh_offset
-                << " text size=" << text_builder_.GetSection()->sh_size;
-      LOG(INFO) << "dynamic off=" << dynamic_builder_.GetSection()->sh_offset
-                << " dynamic size=" << dynamic_builder_.GetSection()->sh_size;
-    }
-
-    return true;
-  }
-
-  bool Write() {
-    std::vector<ElfFilePiece<Elf_Word>*> pieces;
-    Elf_Shdr* prev = dynamic_builder_.GetSection();
-    std::string strtab;
-
-    if (IncludingDebugSymbols()) {
-      // Setup .symtab
-      section_ptrs_.push_back(symtab_builder_.GetSection());
-      AssignSectionStr(&symtab_builder_, &shstrtab_);
-      symtab_builder_.SetSectionIndex(section_index_);
-      section_index_++;
-
-      // Setup .strtab
-      section_ptrs_.push_back(symtab_builder_.GetStrTab()->GetSection());
-      AssignSectionStr(symtab_builder_.GetStrTab(), &shstrtab_);
-      symtab_builder_.GetStrTab()->SetSectionIndex(section_index_);
-      section_index_++;
-
-      strtab = symtab_builder_.GenerateStrtab();
+    // Layout of all sections - determine the final file offsets and addresses.
+    // This must be done after we have built all sections and know their size.
+    Elf_Off file_offset = kProgramHeadersOffset + kProgramHeadersSize;
+    Elf_Addr load_address = file_offset;
+    std::vector<Elf_Shdr> section_headers;
+    section_headers.reserve(1u + sections.size());
+    section_headers.push_back(Elf_Shdr());  // NULL at index 0.
+    for (auto* section : sections) {
+      Elf_Shdr* header = section->GetHeader();
+      Elf_Off alignment = header->sh_addralign > 0 ? header->sh_addralign : 1;
+      header->sh_size = section->GetSize();
+      header->sh_link = section->GetLink();
+      // Allocate memory for the section in the file.
+      if (header->sh_type != SHT_NOBITS) {
+        header->sh_offset = RoundUp(file_offset, alignment);
+        file_offset = header->sh_offset + header->sh_size;
+      }
+      // Allocate memory for the section during program execution.
+      if ((header->sh_flags & SHF_ALLOC) != 0) {
+        header->sh_addr = RoundUp(load_address, alignment);
+        load_address = header->sh_addr + header->sh_size;
+      }
       if (debug_logging_) {
-        LOG(INFO) << "strtab size (bytes)    =" << strtab.size()
-                  << std::hex << " " << strtab.size();
-        LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
-                  << std::hex << " " << symtab_builder_.GetSize();
+        LOG(INFO) << "Section " << section->GetName() << ":" << std::hex
+                  << " offset=0x" << header->sh_offset
+                  << " addr=0x" << header->sh_addr
+                  << " size=0x" << header->sh_size;
       }
+      // Collect section headers into continuous array for convenience.
+      section_headers.push_back(*header);
     }
+    Elf_Off section_headers_offset = RoundUp(file_offset, sizeof(Elf_Word));
 
-    // Setup all the other sections.
-    for (auto* builder : other_builders_) {
-      if ((builder->GetSection()->sh_flags & SHF_ALLOC) == 0) {
-        section_ptrs_.push_back(builder->GetSection());
-        AssignSectionStr(builder, &shstrtab_);
-        builder->SetSectionIndex(section_index_);
-        section_index_++;
-      }
+    // Create program headers now that we know the layout of the whole file.
+    // Each segment contains one or more sections which are mapped together.
+    // Not all sections are mapped during the execution of the program.
+    // PT_LOAD does the mapping.  Other PT_* types allow the program to locate
+    // interesting parts of memory and their addresses overlap with PT_LOAD.
+    std::vector<Elf_Phdr> program_headers;
+    program_headers.push_back(MakeProgramHeader(PT_PHDR, PF_R,
+      kProgramHeadersOffset, kProgramHeadersSize, sizeof(Elf_Word)));
+    // Create the main LOAD R segment which spans all sections up to .rodata.
+    const Elf_Shdr* rodata = rodata_.GetHeader();
+    program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R,
+      0, rodata->sh_offset + rodata->sh_size, rodata->sh_addralign));
+    program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_X, text_));
+    if (bss_.GetHeader()->sh_size != 0u) {
+      program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_W, bss_));
     }
-
-    // Setup shstrtab
-    section_ptrs_.push_back(shstrtab_builder_.GetSection());
-    AssignSectionStr(&shstrtab_builder_, &shstrtab_);
-    shstrtab_builder_.SetSectionIndex(section_index_);
-    section_index_++;
-
-    if (debug_logging_) {
-      LOG(INFO) << ".shstrtab size    (bytes)   =" << shstrtab_.size()
-                << std::hex << " " << shstrtab_.size();
-      LOG(INFO) << "section list size (elements)=" << section_ptrs_.size()
-                << std::hex << " " << section_ptrs_.size();
-    }
-
-    if (IncludingDebugSymbols()) {
-      // Get the layout of the symtab section.
-      symtab_builder_.GetSection()->sh_offset =
-          NextOffset<Elf_Word, Elf_Shdr>(*symtab_builder_.GetSection(),
-                                         *dynamic_builder_.GetSection());
-      symtab_builder_.GetSection()->sh_addr = 0;
-      // Add to leave space for the null symbol.
-      symtab_builder_.GetSection()->sh_size = symtab_builder_.GetSize() * sizeof(Elf_Sym);
-      symtab_builder_.GetSection()->sh_link = symtab_builder_.GetLink();
-
-      // Get the layout of the dynstr section.
-      symtab_builder_.GetStrTab()->GetSection()->sh_offset =
-          NextOffset<Elf_Word, Elf_Shdr>(*symtab_builder_.GetStrTab()->GetSection(),
-                                         *symtab_builder_.GetSection());
-      symtab_builder_.GetStrTab()->GetSection()->sh_addr = 0;
-      symtab_builder_.GetStrTab()->GetSection()->sh_size = strtab.size();
-      symtab_builder_.GetStrTab()->GetSection()->sh_link = symtab_builder_.GetStrTab()->GetLink();
-
-      prev = symtab_builder_.GetStrTab()->GetSection();
-      if (debug_logging_) {
-        LOG(INFO) << "symtab off=" << symtab_builder_.GetSection()->sh_offset
-                  << " symtab size=" << symtab_builder_.GetSection()->sh_size;
-        LOG(INFO) << "strtab off=" << symtab_builder_.GetStrTab()->GetSection()->sh_offset
-                  << " strtab size=" << symtab_builder_.GetStrTab()->GetSection()->sh_size;
-      }
-    }
-
-    // Get the layout of the extra sections without SHF_ALLOC flag.
-    // (This will deal with the debug sections if they are there)
-    for (auto* it : other_builders_) {
-      if ((it->GetSection()->sh_flags & SHF_ALLOC) == 0) {
-        it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev);
-        it->GetSection()->sh_addr = 0;
-        it->GetSection()->sh_size = it->GetBuffer()->size();
-        it->GetSection()->sh_link = it->GetLink();
-
-        // We postpone adding an ElfFilePiece to keep the order in "pieces."
-
-        prev = it->GetSection();
-        if (debug_logging_) {
-          LOG(INFO) << it->GetName() << " off=" << it->GetSection()->sh_offset
-                    << " size=" << it->GetSection()->sh_size;
-        }
-      }
-    }
-
-    // Get the layout of the shstrtab section
-    shstrtab_builder_.GetSection()->sh_offset =
-        NextOffset<Elf_Word, Elf_Shdr>(*shstrtab_builder_.GetSection(), *prev);
-    shstrtab_builder_.GetSection()->sh_addr = 0;
-    shstrtab_builder_.GetSection()->sh_size = shstrtab_.size();
-    shstrtab_builder_.GetSection()->sh_link = shstrtab_builder_.GetLink();
-    if (debug_logging_) {
-        LOG(INFO) << "shstrtab off=" << shstrtab_builder_.GetSection()->sh_offset
-                  << " shstrtab size=" << shstrtab_builder_.GetSection()->sh_size;
-    }
-
-    // The section list comes after come after.
-    Elf_Word sections_offset = RoundUp(
-        shstrtab_builder_.GetSection()->sh_offset + shstrtab_builder_.GetSection()->sh_size,
-        sizeof(Elf_Word));
-
-    // Setup the actual symbol arrays.
-    std::vector<Elf_Sym> dynsym = dynsym_builder_.GenerateSymtab();
-    CHECK_EQ(dynsym.size() * sizeof(Elf_Sym), dynsym_builder_.GetSection()->sh_size);
-    std::vector<Elf_Sym> symtab;
-    if (IncludingDebugSymbols()) {
-      symtab = symtab_builder_.GenerateSymtab();
-      CHECK_EQ(symtab.size() * sizeof(Elf_Sym), symtab_builder_.GetSection()->sh_size);
-    }
-
-    // Setup the dynamic section.
-    // This will add the 2 values we cannot know until now time, namely the size
-    // and the soname_offset.
-    std::vector<Elf_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr_.size(),
-                                                                  dynstr_soname_offset_);
-    CHECK_EQ(dynamic.size() * sizeof(Elf_Dyn), dynamic_builder_.GetSection()->sh_size);
-
-    // Finish setup of the program headers now that we know the layout of the
-    // whole file.
-    Elf_Word load_r_size =
-        rodata_builder_.GetSection()->sh_offset + rodata_builder_.GetSection()->sh_size;
-    program_headers_[PH_LOAD_R__].p_filesz = load_r_size;
-    program_headers_[PH_LOAD_R__].p_memsz =  load_r_size;
-    program_headers_[PH_LOAD_R__].p_align =  rodata_builder_.GetSection()->sh_addralign;
-
-    Elf_Word load_rx_size = text_builder_.GetSection()->sh_size;
-    program_headers_[PH_LOAD_R_X].p_offset = text_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_R_X].p_vaddr  = text_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_R_X].p_paddr  = text_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_R_X].p_filesz = load_rx_size;
-    program_headers_[PH_LOAD_R_X].p_memsz  = load_rx_size;
-    program_headers_[PH_LOAD_R_X].p_align  = text_builder_.GetSection()->sh_addralign;
-
-    program_headers_[PH_LOAD_RW_BSS].p_offset = bss_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_RW_BSS].p_vaddr  = bss_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_RW_BSS].p_paddr  = bss_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_RW_BSS].p_filesz = 0;
-    program_headers_[PH_LOAD_RW_BSS].p_memsz  = bss_builder_.GetSection()->sh_size;
-    program_headers_[PH_LOAD_RW_BSS].p_align  = bss_builder_.GetSection()->sh_addralign;
-
-    program_headers_[PH_LOAD_RW_DYNAMIC].p_offset = dynamic_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_RW_DYNAMIC].p_vaddr  = dynamic_builder_.GetSection()->sh_addr;
-    program_headers_[PH_LOAD_RW_DYNAMIC].p_paddr  = dynamic_builder_.GetSection()->sh_addr;
-    program_headers_[PH_LOAD_RW_DYNAMIC].p_filesz = dynamic_builder_.GetSection()->sh_size;
-    program_headers_[PH_LOAD_RW_DYNAMIC].p_memsz  = dynamic_builder_.GetSection()->sh_size;
-    program_headers_[PH_LOAD_RW_DYNAMIC].p_align  = dynamic_builder_.GetSection()->sh_addralign;
-
-    program_headers_[PH_DYNAMIC].p_offset = dynamic_builder_.GetSection()->sh_offset;
-    program_headers_[PH_DYNAMIC].p_vaddr  = dynamic_builder_.GetSection()->sh_addr;
-    program_headers_[PH_DYNAMIC].p_paddr  = dynamic_builder_.GetSection()->sh_addr;
-    program_headers_[PH_DYNAMIC].p_filesz = dynamic_builder_.GetSection()->sh_size;
-    program_headers_[PH_DYNAMIC].p_memsz  = dynamic_builder_.GetSection()->sh_size;
-    program_headers_[PH_DYNAMIC].p_align  = dynamic_builder_.GetSection()->sh_addralign;
-
-    const auto* eh_frame_hdr = FindRawSection(".eh_frame_hdr");
+    program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_W, dynamic_));
+    program_headers.push_back(MakeProgramHeader(PT_DYNAMIC, PF_R | PF_W, dynamic_));
+    const Section* eh_frame_hdr = FindSection(".eh_frame_hdr");
     if (eh_frame_hdr != nullptr) {
-      const auto* eh_frame = FindRawSection(".eh_frame");
-      // Check layout:
-      // 1) eh_frame is before eh_frame_hdr.
-      // 2) There's no gap.
+      const Section* eh_frame = FindSection(".eh_frame");
+      // Check layout: eh_frame is before eh_frame_hdr and there is no gap.
       CHECK(eh_frame != nullptr);
-      CHECK_LE(eh_frame->GetSection()->sh_offset, eh_frame_hdr->GetSection()->sh_offset);
-      CHECK_EQ(eh_frame->GetSection()->sh_offset + eh_frame->GetSection()->sh_size,
-               eh_frame_hdr->GetSection()->sh_offset);
-
-      program_headers_[PH_EH_FRAME_HDR].p_type   = PT_GNU_EH_FRAME;
-      program_headers_[PH_EH_FRAME_HDR].p_offset = eh_frame_hdr->GetSection()->sh_offset;
-      program_headers_[PH_EH_FRAME_HDR].p_vaddr  = eh_frame_hdr->GetSection()->sh_addr;
-      program_headers_[PH_EH_FRAME_HDR].p_paddr  = eh_frame_hdr->GetSection()->sh_addr;
-      program_headers_[PH_EH_FRAME_HDR].p_filesz = eh_frame_hdr->GetSection()->sh_size;
-      program_headers_[PH_EH_FRAME_HDR].p_memsz  = eh_frame_hdr->GetSection()->sh_size;
-      program_headers_[PH_EH_FRAME_HDR].p_align  = eh_frame_hdr->GetSection()->sh_addralign;
+      CHECK_LE(eh_frame->GetHeader()->sh_offset, eh_frame_hdr->GetHeader()->sh_offset);
+      CHECK_EQ(eh_frame->GetHeader()->sh_offset + eh_frame->GetHeader()->sh_size,
+               eh_frame_hdr->GetHeader()->sh_offset);
+      program_headers.push_back(MakeProgramHeader(PT_GNU_EH_FRAME, PF_R, *eh_frame_hdr));
     }
+    CHECK_LE(program_headers.size(), kMaxProgramHeaders);
 
-    // Finish setup of the Ehdr values.
-    elf_header_.e_phoff = PHDR_OFFSET;
-    elf_header_.e_shoff = sections_offset;
-    elf_header_.e_phnum = PH_NUM - (bss_builder_.GetSection()->sh_size == 0u ? 1 : 0)
-                                 - (eh_frame_hdr == nullptr ? 1 : 0);
-    elf_header_.e_shnum = section_ptrs_.size();
-    elf_header_.e_shstrndx = shstrtab_builder_.GetSectionIndex();
+    // Create the main ELF header.
+    Elf_Ehdr elf_header = MakeElfHeader(isa_);
+    elf_header.e_phoff = kProgramHeadersOffset;
+    elf_header.e_shoff = section_headers_offset;
+    elf_header.e_phnum = program_headers.size();
+    elf_header.e_shnum = section_headers.size();
+    elf_header.e_shstrndx = shstrtab_.GetSectionIndex();
 
-    // Add the rest of the pieces to the list.
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Elf Header", 0, &elf_header_,
-                                                      sizeof(elf_header_)));
-    if (bss_builder_.GetSection()->sh_size != 0u) {
-      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Program headers", PHDR_OFFSET,
-                                                        &program_headers_[0],
-                                                        elf_header_.e_phnum * sizeof(Elf_Phdr)));
-    } else {
-      // Skip PH_LOAD_RW_BSS.
-      Elf_Word part1_size = PH_LOAD_RW_BSS * sizeof(Elf_Phdr);
-      Elf_Word part2_size = (elf_header_.e_phnum - PH_LOAD_RW_BSS) * sizeof(Elf_Phdr);
-      CHECK_EQ(part1_size + part2_size, elf_header_.e_phnum * sizeof(Elf_Phdr));
-      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Program headers", PHDR_OFFSET,
-                                                        &program_headers_[0], part1_size));
-      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Program headers part 2",
-                                                        PHDR_OFFSET + part1_size,
-                                                        &program_headers_[PH_LOAD_RW_BSS + 1],
-                                                        part2_size));
-    }
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynamic",
-                                                      dynamic_builder_.GetSection()->sh_offset,
-                                                      dynamic.data(),
-                                                      dynamic_builder_.GetSection()->sh_size));
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynsym", dynsym_builder_.GetSection()->sh_offset,
-                                                      dynsym.data(),
-                                                      dynsym.size() * sizeof(Elf_Sym)));
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynstr",
-                                                    dynsym_builder_.GetStrTab()->GetSection()->sh_offset,
-                                                    dynstr_.c_str(), dynstr_.size()));
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".hash", hash_builder_.GetSection()->sh_offset,
-                                                      hash_.data(),
-                                                      hash_.size() * sizeof(Elf_Word)));
-    pieces.push_back(new ElfFileRodataPiece<Elf_Word>(rodata_builder_.GetSection()->sh_offset,
-                                                      oat_writer_));
-    pieces.push_back(new ElfFileOatTextPiece<Elf_Word>(text_builder_.GetSection()->sh_offset,
-                                                       oat_writer_));
-    if (IncludingDebugSymbols()) {
-      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".symtab",
-                                                        symtab_builder_.GetSection()->sh_offset,
-                                                        symtab.data(),
-                                                        symtab.size() * sizeof(Elf_Sym)));
-      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".strtab",
-                                                    symtab_builder_.GetStrTab()->GetSection()->sh_offset,
-                                                    strtab.c_str(), strtab.size()));
-    }
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".shstrtab",
-                                                      shstrtab_builder_.GetSection()->sh_offset,
-                                                      &shstrtab_[0], shstrtab_.size()));
-    for (uint32_t i = 0; i < section_ptrs_.size(); ++i) {
-      // Just add all the sections in induvidually since they are all over the
-      // place on the heap/stack.
-      Elf_Word cur_off = sections_offset + i * sizeof(Elf_Shdr);
-      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("section table piece", cur_off,
-                                                        section_ptrs_[i], sizeof(Elf_Shdr)));
-    }
-
-    // Postponed debug info.
-    for (auto* it : other_builders_) {
-      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(it->GetName(), it->GetSection()->sh_offset,
-                                                        it->GetBuffer()->data(),
-                                                        it->GetBuffer()->size()));
-    }
-
-    if (!WriteOutFile(pieces)) {
-      LOG(ERROR) << "Unable to write to file " << elf_file_->GetPath();
-
-      STLDeleteElements(&pieces);  // Have to manually clean pieces.
+    // Write all headers and section content to the file.
+    // Depending on the implementations of Section::Write, this
+    // might be just memory copies or some more elaborate operations.
+    if (!WriteArray(elf_file, &elf_header, 1)) {
+      LOG(INFO) << "Failed to write the ELF header";
       return false;
     }
-
-    STLDeleteElements(&pieces);  // Have to manually clean pieces.
+    if (!WriteArray(elf_file, program_headers.data(), program_headers.size())) {
+      LOG(INFO) << "Failed to write the program headers";
+      return false;
+    }
+    for (Section* section : sections) {
+      const Elf_Shdr* header = section->GetHeader();
+      if (header->sh_type != SHT_NOBITS) {
+        if (!SeekTo(elf_file, header->sh_offset) || !section->Write(elf_file)) {
+          LOG(INFO) << "Failed to write section " << section->GetName();
+          return false;
+        }
+        Elf_Word current_offset = lseek(elf_file->Fd(), 0, SEEK_CUR);
+        CHECK_EQ(current_offset, header->sh_offset + header->sh_size)
+          << "The number of bytes written does not match GetSize()";
+      }
+    }
+    if (!SeekTo(elf_file, section_headers_offset) ||
+        !WriteArray(elf_file, section_headers.data(), section_headers.size())) {
+      LOG(INFO) << "Failed to write the section headers";
+      return false;
+    }
     return true;
   }
 
-  // Adds the given raw section to the builder.  It does not take ownership.
-  void RegisterRawSection(ElfRawSectionBuilder* bld) {
-    other_builders_.push_back(bld);
+  // Adds the given section to the builder.  It does not take ownership.
+  void RegisterSection(Section* section) {
+    other_sections_.push_back(section);
   }
 
-  const ElfRawSectionBuilder* FindRawSection(const char* name) {
-    for (const auto* other_builder : other_builders_) {
-      if (other_builder->GetName() == name) {
-        return other_builder;
+  const Section* FindSection(const char* name) {
+    for (const auto* section : other_sections_) {
+      if (section->GetName() == name) {
+        return section;
       }
     }
     return nullptr;
   }
 
  private:
-  void SetISA(InstructionSet isa) {
+  static bool SeekTo(File* elf_file, Elf_Word offset) {
+    DCHECK_LE(lseek(elf_file->Fd(), 0, SEEK_CUR), static_cast<off_t>(offset))
+      << "Seeking backwards";
+    if (static_cast<off_t>(offset) != lseek(elf_file->Fd(), offset, SEEK_SET)) {
+      PLOG(ERROR) << "Failed to seek in file " << elf_file->GetPath();
+      return false;
+    }
+    return true;
+  }
+
+  template<typename T>
+  static bool WriteArray(File* elf_file, const T* data, size_t count) {
+    DCHECK(data != nullptr);
+    if (!elf_file->WriteFully(data, count * sizeof(T))) {
+      PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath();
+      return false;
+    }
+    return true;
+  }
+
+  // Helper - create segment header based on memory range.
+  static Elf_Phdr MakeProgramHeader(Elf_Word type, Elf_Word flags,
+                                    Elf_Off offset, Elf_Word size, Elf_Word align) {
+    Elf_Phdr phdr = Elf_Phdr();
+    phdr.p_type    = type;
+    phdr.p_flags   = flags;
+    phdr.p_offset  = offset;
+    phdr.p_vaddr   = offset;
+    phdr.p_paddr   = offset;
+    phdr.p_filesz  = size;
+    phdr.p_memsz   = size;
+    phdr.p_align   = align;
+    return phdr;
+  }
+
+  // Helper - create segment header based on section header.
+  static Elf_Phdr MakeProgramHeader(Elf_Word type, Elf_Word flags,
+                                    const Section& section) {
+    const Elf_Shdr* shdr = section.GetHeader();
+    // Only run-time allocated sections should be in segment headers.
+    CHECK_NE(shdr->sh_flags & SHF_ALLOC, 0u);
+    Elf_Phdr phdr = Elf_Phdr();
+    phdr.p_type   = type;
+    phdr.p_flags  = flags;
+    phdr.p_offset = shdr->sh_offset;
+    phdr.p_vaddr  = shdr->sh_addr;
+    phdr.p_paddr  = shdr->sh_addr;
+    phdr.p_filesz = shdr->sh_type != SHT_NOBITS ? shdr->sh_size : 0u;
+    phdr.p_memsz  = shdr->sh_size;
+    phdr.p_align  = shdr->sh_addralign;
+    return phdr;
+  }
+
+  static Elf_Ehdr MakeElfHeader(InstructionSet isa) {
+    Elf_Ehdr elf_header = Elf_Ehdr();
     switch (isa) {
       case kArm:
         // Fall through.
       case kThumb2: {
-        elf_header_.e_machine = EM_ARM;
-        elf_header_.e_flags = EF_ARM_EABI_VER5;
+        elf_header.e_machine = EM_ARM;
+        elf_header.e_flags = EF_ARM_EABI_VER5;
         break;
       }
       case kArm64: {
-        elf_header_.e_machine = EM_AARCH64;
-        elf_header_.e_flags = 0;
+        elf_header.e_machine = EM_AARCH64;
+        elf_header.e_flags = 0;
         break;
       }
       case kX86: {
-        elf_header_.e_machine = EM_386;
-        elf_header_.e_flags = 0;
+        elf_header.e_machine = EM_386;
+        elf_header.e_flags = 0;
         break;
       }
       case kX86_64: {
-        elf_header_.e_machine = EM_X86_64;
-        elf_header_.e_flags = 0;
+        elf_header.e_machine = EM_X86_64;
+        elf_header.e_flags = 0;
         break;
       }
       case kMips: {
-        elf_header_.e_machine = EM_MIPS;
-        elf_header_.e_flags = (EF_MIPS_NOREORDER |
+        elf_header.e_machine = EM_MIPS;
+        elf_header.e_flags = (EF_MIPS_NOREORDER |
                                EF_MIPS_PIC       |
                                EF_MIPS_CPIC      |
                                EF_MIPS_ABI_O32   |
@@ -1242,147 +870,82 @@
         break;
       }
       case kMips64: {
-        elf_header_.e_machine = EM_MIPS;
-        elf_header_.e_flags = (EF_MIPS_NOREORDER |
+        elf_header.e_machine = EM_MIPS;
+        elf_header.e_flags = (EF_MIPS_NOREORDER |
                                EF_MIPS_PIC       |
                                EF_MIPS_CPIC      |
                                EF_MIPS_ARCH_64R6);
         break;
       }
-      default: {
-        fatal_error_ = true;
-        LOG(FATAL) << "Unknown instruction set: " << isa;
-        break;
+      case kNone: {
+        LOG(FATAL) << "No instruction set";
       }
     }
-  }
 
-  void SetupEhdr() {
-    memset(&elf_header_, 0, sizeof(elf_header_));
-    elf_header_.e_ident[EI_MAG0]       = ELFMAG0;
-    elf_header_.e_ident[EI_MAG1]       = ELFMAG1;
-    elf_header_.e_ident[EI_MAG2]       = ELFMAG2;
-    elf_header_.e_ident[EI_MAG3]       = ELFMAG3;
-    elf_header_.e_ident[EI_CLASS]      = (sizeof(Elf_Addr) == sizeof(Elf32_Addr))
+    elf_header.e_ident[EI_MAG0]       = ELFMAG0;
+    elf_header.e_ident[EI_MAG1]       = ELFMAG1;
+    elf_header.e_ident[EI_MAG2]       = ELFMAG2;
+    elf_header.e_ident[EI_MAG3]       = ELFMAG3;
+    elf_header.e_ident[EI_CLASS]      = (sizeof(Elf_Addr) == sizeof(Elf32_Addr))
                                          ? ELFCLASS32 : ELFCLASS64;;
-    elf_header_.e_ident[EI_DATA]       = ELFDATA2LSB;
-    elf_header_.e_ident[EI_VERSION]    = EV_CURRENT;
-    elf_header_.e_ident[EI_OSABI]      = ELFOSABI_LINUX;
-    elf_header_.e_ident[EI_ABIVERSION] = 0;
-    elf_header_.e_type = ET_DYN;
-    elf_header_.e_version = 1;
-    elf_header_.e_entry = 0;
-    elf_header_.e_ehsize = sizeof(Elf_Ehdr);
-    elf_header_.e_phentsize = sizeof(Elf_Phdr);
-    elf_header_.e_shentsize = sizeof(Elf_Shdr);
-    elf_header_.e_phoff = sizeof(Elf_Ehdr);
+    elf_header.e_ident[EI_DATA]       = ELFDATA2LSB;
+    elf_header.e_ident[EI_VERSION]    = EV_CURRENT;
+    elf_header.e_ident[EI_OSABI]      = ELFOSABI_LINUX;
+    elf_header.e_ident[EI_ABIVERSION] = 0;
+    elf_header.e_type = ET_DYN;
+    elf_header.e_version = 1;
+    elf_header.e_entry = 0;
+    elf_header.e_ehsize = sizeof(Elf_Ehdr);
+    elf_header.e_phentsize = sizeof(Elf_Phdr);
+    elf_header.e_shentsize = sizeof(Elf_Shdr);
+    elf_header.e_phoff = sizeof(Elf_Ehdr);
+    return elf_header;
   }
 
-  // Sets up a bunch of the required Dynamic Section entries.
-  // Namely it will initialize all the mandatory ones that it can.
-  // Specifically:
-  // DT_HASH
-  // DT_STRTAB
-  // DT_SYMTAB
-  // DT_SYMENT
-  //
-  // Some such as DT_SONAME, DT_STRSZ and DT_NULL will be put in later.
-  void SetupDynamic() {
-    dynamic_builder_.AddDynamicTag(DT_HASH, 0, &hash_builder_);
-    dynamic_builder_.AddDynamicTag(DT_STRTAB, 0, dynsym_builder_.GetStrTab());
-    dynamic_builder_.AddDynamicTag(DT_SYMTAB, 0, &dynsym_builder_);
-    dynamic_builder_.AddDynamicTag(DT_SYMENT, sizeof(Elf_Sym));
+  void BuildDynamicSection(const std::string& elf_file_path) {
+    std::string soname(elf_file_path);
+    size_t directory_separator_pos = soname.rfind('/');
+    if (directory_separator_pos != std::string::npos) {
+      soname = soname.substr(directory_separator_pos + 1);
+    }
+    // NB: We must add the name before adding DT_STRSZ.
+    Elf_Word soname_offset = dynstr_.AddName(soname);
+
+    dynamic_.AddDynamicTag(DT_HASH, 0, &hash_);
+    dynamic_.AddDynamicTag(DT_STRTAB, 0, &dynstr_);
+    dynamic_.AddDynamicTag(DT_SYMTAB, 0, &dynsym_);
+    dynamic_.AddDynamicTag(DT_SYMENT, sizeof(Elf_Sym), nullptr);
+    dynamic_.AddDynamicTag(DT_STRSZ, dynstr_.GetSize(), nullptr);
+    dynamic_.AddDynamicTag(DT_SONAME, soname_offset, nullptr);
   }
 
-  // Sets up the basic dynamic symbols that are needed, namely all those we
-  // can know already.
-  //
-  // Specifically adds:
-  // oatdata
-  // oatexec
-  // oatlastword
-  void SetupRequiredSymbols() {
-    dynsym_builder_.AddSymbol("oatdata", &rodata_builder_, 0, true,
-                              rodata_builder_.GetSize(), STB_GLOBAL, STT_OBJECT);
-    dynsym_builder_.AddSymbol("oatexec", &text_builder_, 0, true,
-                              text_builder_.GetSize(), STB_GLOBAL, STT_OBJECT);
-    dynsym_builder_.AddSymbol("oatlastword", &text_builder_, text_builder_.GetSize() - 4,
-                              true, 4, STB_GLOBAL, STT_OBJECT);
-    if (bss_builder_.GetSize() != 0u) {
-      dynsym_builder_.AddSymbol("oatbss", &bss_builder_, 0, true,
-                                bss_builder_.GetSize(), STB_GLOBAL, STT_OBJECT);
-      dynsym_builder_.AddSymbol("oatbsslastword", &bss_builder_, bss_builder_.GetSize() - 4,
-                                true, 4, STB_GLOBAL, STT_OBJECT);
+  void BuildDynsymSection() {
+    dynsym_.AddSymbol("oatdata", &rodata_, 0, true,
+                      rodata_.GetSize(), STB_GLOBAL, STT_OBJECT);
+    dynsym_.AddSymbol("oatexec", &text_, 0, true,
+                      text_.GetSize(), STB_GLOBAL, STT_OBJECT);
+    dynsym_.AddSymbol("oatlastword", &text_, text_.GetSize() - 4,
+                      true, 4, STB_GLOBAL, STT_OBJECT);
+    if (bss_.GetSize() != 0u) {
+      dynsym_.AddSymbol("oatbss", &bss_, 0, true,
+                        bss_.GetSize(), STB_GLOBAL, STT_OBJECT);
+      dynsym_.AddSymbol("oatbsslastword", &bss_, bss_.GetSize() - 4,
+                        true, 4, STB_GLOBAL, STT_OBJECT);
     }
   }
 
-  void AssignSectionStr(ElfSectionBuilder* builder, std::string* strtab) {
-    builder->GetSection()->sh_name = strtab->size();
-    *strtab += builder->GetName();
-    *strtab += '\0';
-    if (debug_logging_) {
-      LOG(INFO) << "adding section name \"" << builder->GetName() << "\" "
-                << "to shstrtab at offset " << builder->GetSection()->sh_name;
-    }
-  }
-
-
-  // Write each of the pieces out to the file.
-  bool WriteOutFile(const std::vector<ElfFilePiece<Elf_Word>*>& pieces) {
-    for (auto it = pieces.begin(); it != pieces.end(); ++it) {
-      if (!(*it)->Write(elf_file_)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  bool IncludingDebugSymbols() const {
-    return add_symbols_ && symtab_builder_.GetSize() > 1;
-  }
-
-  CodeOutput* const oat_writer_;
-  File* const elf_file_;
-  const bool add_symbols_;
-  const bool debug_logging_;
-
-  bool fatal_error_ = false;
-
-  // What phdr is.
-  static const uint32_t PHDR_OFFSET = sizeof(Elf_Ehdr);
-  enum : uint8_t {
-    PH_PHDR             = 0,
-    PH_LOAD_R__         = 1,
-    PH_LOAD_R_X         = 2,
-    PH_LOAD_RW_BSS      = 3,
-    PH_LOAD_RW_DYNAMIC  = 4,
-    PH_DYNAMIC          = 5,
-    PH_EH_FRAME_HDR     = 6,
-    PH_NUM              = 7,
-  };
-  static const uint32_t PHDR_SIZE = sizeof(Elf_Phdr) * PH_NUM;
-  Elf_Phdr program_headers_[PH_NUM];
-
-  Elf_Ehdr elf_header_;
-
-  Elf_Shdr null_hdr_;
-  std::string shstrtab_;
-  // The index of the current section being built. The first being 1.
-  uint32_t section_index_;
-  std::string dynstr_;
-  uint32_t dynstr_soname_offset_;
-  std::vector<const Elf_Shdr*> section_ptrs_;
-  std::vector<Elf_Word> hash_;
-
-  ElfOatSectionBuilder text_builder_;
-  ElfOatSectionBuilder rodata_builder_;
-  ElfOatSectionBuilder bss_builder_;
-  ElfSymtabBuilder dynsym_builder_;
-  ElfSymtabBuilder symtab_builder_;
-  ElfSectionBuilder hash_builder_;
-  ElfDynamicBuilder dynamic_builder_;
-  ElfSectionBuilder shstrtab_builder_;
-  std::vector<ElfRawSectionBuilder*> other_builders_;
+  InstructionSet isa_;
+  StrtabSection dynstr_;
+  SymtabSection dynsym_;
+  HashSection hash_;
+  OatSection rodata_;
+  OatSection text_;
+  NoBitsSection bss_;
+  DynamicSection dynamic_;
+  StrtabSection strtab_;
+  SymtabSection symtab_;
+  std::vector<Section*> other_sections_;
+  StrtabSection shstrtab_;
 
   DISALLOW_COPY_AND_ASSIGN(ElfBuilder);
 };
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 9ff94e9..d679468 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -21,7 +21,6 @@
 
 #include "base/logging.h"
 #include "base/unix_file/fd_file.h"
-#include "buffered_output_stream.h"
 #include "compiled_method.h"
 #include "dex_file-inl.h"
 #include "driver/compiler_driver.h"
@@ -30,7 +29,6 @@
 #include "elf_file.h"
 #include "elf_utils.h"
 #include "elf_writer_debug.h"
-#include "file_output_stream.h"
 #include "globals.h"
 #include "leb128.h"
 #include "oat.h"
@@ -50,20 +48,6 @@
   return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
 }
 
-class OatWriterWrapper FINAL : public CodeOutput {
- public:
-  explicit OatWriterWrapper(OatWriter* oat_writer) : oat_writer_(oat_writer) {}
-
-  void SetCodeOffset(size_t offset) {
-    oat_writer_->SetOatDataOffset(offset);
-  }
-  bool Write(OutputStream* out) OVERRIDE {
-    return oat_writer_->Write(out);
-  }
- private:
-  OatWriter* const oat_writer_;
-};
-
 template <typename ElfTypes>
 static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer);
 
@@ -99,18 +83,29 @@
   buffer->push_back(0);  // End of sections.
 }
 
-template<typename AddressType, bool SubtractPatchLocation = false>
-static void PatchAddresses(const std::vector<uintptr_t>* patch_locations,
-                           AddressType delta, std::vector<uint8_t>* buffer) {
-  // Addresses in .debug_* sections are unaligned.
-  typedef __attribute__((__aligned__(1))) AddressType UnalignedAddressType;
-  if (patch_locations != nullptr) {
-    for (uintptr_t patch_location : *patch_locations) {
-      *reinterpret_cast<UnalignedAddressType*>(buffer->data() + patch_location) +=
-          delta - (SubtractPatchLocation ? patch_location : 0);
-    }
+class RodataWriter FINAL : public CodeOutput {
+ public:
+  explicit RodataWriter(OatWriter* oat_writer) : oat_writer_(oat_writer) {}
+
+  bool Write(OutputStream* out) OVERRIDE {
+    return oat_writer_->WriteRodata(out);
   }
-}
+
+ private:
+  OatWriter* oat_writer_;
+};
+
+class TextWriter FINAL : public CodeOutput {
+ public:
+  explicit TextWriter(OatWriter* oat_writer) : oat_writer_(oat_writer) {}
+
+  bool Write(OutputStream* out) OVERRIDE {
+    return oat_writer_->WriteCode(out);
+  }
+
+ private:
+  OatWriter* oat_writer_;
+};
 
 template <typename ElfTypes>
 bool ElfWriterQuick<ElfTypes>::Write(
@@ -118,106 +113,82 @@
     const std::vector<const DexFile*>& dex_files_unused ATTRIBUTE_UNUSED,
     const std::string& android_root_unused ATTRIBUTE_UNUSED,
     bool is_host_unused ATTRIBUTE_UNUSED) {
-  constexpr bool debug = false;
-  const OatHeader& oat_header = oat_writer->GetOatHeader();
-  typename ElfTypes::Word oat_data_size = oat_header.GetExecutableOffset();
-  uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size;
-  uint32_t oat_bss_size = oat_writer->GetBssSize();
+  const InstructionSet isa = compiler_driver_->GetInstructionSet();
 
-  OatWriterWrapper wrapper(oat_writer);
-
+  // Setup the builder with the main OAT sections (.rodata .text .bss).
+  const size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset();
+  const size_t text_size = oat_writer->GetSize() - rodata_size;
+  const size_t bss_size = oat_writer->GetBssSize();
+  RodataWriter rodata_writer(oat_writer);
+  TextWriter text_writer(oat_writer);
   std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(
-      &wrapper,
-      elf_file_,
-      compiler_driver_->GetInstructionSet(),
-      0,
-      oat_data_size,
-      oat_data_size,
-      oat_exec_size,
-      RoundUp(oat_data_size + oat_exec_size, kPageSize),
-      oat_bss_size,
-      compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(),
-      debug));
+      isa, rodata_size, &rodata_writer, text_size, &text_writer, bss_size));
 
-  InstructionSet isa = compiler_driver_->GetInstructionSet();
-  int alignment = GetInstructionSetPointerSize(isa);
-  typedef typename ElfBuilder<ElfTypes>::ElfRawSectionBuilder RawSection;
-  RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, alignment, 0);
-  RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
-  RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-  RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-  RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-  RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+  // Add debug sections.
+  // They are stack allocated here (in the same scope as the builder),
+  // but they are registred with the builder only if they are used.
+  using RawSection = typename ElfBuilder<ElfTypes>::RawSection;
+  const int pointer_size = GetInstructionSetPointerSize(isa);
+  const auto* text = builder->GetText();
+  constexpr bool absolute = false;  // patch to make absolute addresses.
+  constexpr bool relative = true;  // patch to make relative addresses.
+  const bool is64bit = Is64BitInstructionSet(isa);
+  RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC,
+                      nullptr, 0, pointer_size, 0, text, relative, is64bit);
+  RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC,
+                          nullptr, 0, 4, 0);
+  RawSection debug_info(".debug_info", SHT_PROGBITS, 0,
+                        nullptr, 0, 1, 0, text, absolute, false /* 32bit */);
+  RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0,
+                          nullptr, 0, 1, 0);
+  RawSection debug_str(".debug_str", SHT_PROGBITS, 0,
+                       nullptr, 0, 1, 0);
+  RawSection debug_line(".debug_line", SHT_PROGBITS, 0,
+                        nullptr, 0, 1, 0, text, absolute, false /* 32bit */);
+  if (!oat_writer->GetMethodDebugInfo().empty()) {
+    if (compiler_driver_->GetCompilerOptions().GetIncludeCFI()) {
+      dwarf::WriteEhFrame(
+          compiler_driver_, oat_writer, dwarf::DW_EH_PE_pcrel,
+          eh_frame.GetBuffer(), eh_frame.GetPatchLocations(),
+          eh_frame_hdr.GetBuffer());
+      builder->RegisterSection(&eh_frame);
+      builder->RegisterSection(&eh_frame_hdr);
+    }
+    if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
+      // Add methods to .symtab.
+      WriteDebugSymbols(builder.get(), oat_writer);
+      // Generate DWARF .debug_* sections.
+      dwarf::WriteDebugSections(
+          compiler_driver_, oat_writer,
+          debug_info.GetBuffer(), debug_info.GetPatchLocations(),
+          debug_abbrev.GetBuffer(),
+          debug_str.GetBuffer(),
+          debug_line.GetBuffer(), debug_line.GetPatchLocations());
+      builder->RegisterSection(&debug_info);
+      builder->RegisterSection(&debug_abbrev);
+      builder->RegisterSection(&debug_str);
+      builder->RegisterSection(&debug_line);
+      *oat_writer->GetAbsolutePatchLocationsFor(".debug_info") =
+          *debug_info.GetPatchLocations();
+      *oat_writer->GetAbsolutePatchLocationsFor(".debug_line") =
+          *debug_line.GetPatchLocations();
+    }
+  }
+
+  // Add relocation section.
   RawSection oat_patches(".oat_patches", SHT_OAT_PATCH, 0, nullptr, 0, 1, 0);
-
-  // Do not add to .oat_patches since we will make the addresses relative.
-  std::vector<uintptr_t> eh_frame_patches;
-  if (compiler_driver_->GetCompilerOptions().GetIncludeCFI() &&
-      !oat_writer->GetMethodDebugInfo().empty()) {
-    dwarf::WriteEhFrame(compiler_driver_, oat_writer,
-                        dwarf::DW_EH_PE_pcrel,
-                        eh_frame.GetBuffer(), &eh_frame_patches,
-                        eh_frame_hdr.GetBuffer());
-    builder->RegisterRawSection(&eh_frame);
-    builder->RegisterRawSection(&eh_frame_hdr);
-  }
-
-  // Must be done after .eh_frame is created since it is used in the Elf layout.
-  if (!builder->Init()) {
-    return false;
-  }
-
-  std::vector<uintptr_t>* debug_info_patches = nullptr;
-  std::vector<uintptr_t>* debug_line_patches = nullptr;
-  if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols() &&
-      !oat_writer->GetMethodDebugInfo().empty()) {
-    // Add methods to .symtab.
-    WriteDebugSymbols(builder.get(), oat_writer);
-    // Generate DWARF .debug_* sections.
-    debug_info_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_info");
-    debug_line_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_line");
-    dwarf::WriteDebugSections(compiler_driver_, oat_writer,
-                              debug_info.GetBuffer(), debug_info_patches,
-                              debug_abbrev.GetBuffer(),
-                              debug_str.GetBuffer(),
-                              debug_line.GetBuffer(), debug_line_patches);
-    builder->RegisterRawSection(&debug_info);
-    builder->RegisterRawSection(&debug_abbrev);
-    builder->RegisterRawSection(&debug_str);
-    builder->RegisterRawSection(&debug_line);
-  }
-
   if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation() ||
       // ElfWriter::Fixup will be called regardless and it needs to be able
       // to patch debug sections so we have to include patches for them.
       compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
     EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer());
-    builder->RegisterRawSection(&oat_patches);
+    builder->RegisterSection(&oat_patches);
   }
 
-  // We know where .text and .eh_frame will be located, so patch the addresses.
-  typename ElfTypes::Addr text_addr = builder->GetTextBuilder().GetSection()->sh_addr;
-  // TODO: Simplify once we use Elf64 - we can use ElfTypes::Addr instead of branching.
-  if (Is64BitInstructionSet(compiler_driver_->GetInstructionSet())) {
-    // relative_address = (text_addr + address) - (eh_frame_addr + patch_location);
-    PatchAddresses<uint64_t, true>(&eh_frame_patches,
-        text_addr - eh_frame.GetSection()->sh_addr, eh_frame.GetBuffer());
-    PatchAddresses<uint64_t>(debug_info_patches, text_addr, debug_info.GetBuffer());
-    PatchAddresses<uint64_t>(debug_line_patches, text_addr, debug_line.GetBuffer());
-  } else {
-    // relative_address = (text_addr + address) - (eh_frame_addr + patch_location);
-    PatchAddresses<uint32_t, true>(&eh_frame_patches,
-        text_addr - eh_frame.GetSection()->sh_addr, eh_frame.GetBuffer());
-    PatchAddresses<uint32_t>(debug_info_patches, text_addr, debug_info.GetBuffer());
-    PatchAddresses<uint32_t>(debug_line_patches, text_addr, debug_line.GetBuffer());
-  }
-
-  return builder->Write();
+  return builder->Write(elf_file_);
 }
 
 template <typename ElfTypes>
-// Do not inline to avoid Clang stack frame problems. b/18738594
-NO_INLINE
 static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer) {
   const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetMethodDebugInfo();
 
@@ -230,7 +201,7 @@
     }
   }
 
-  auto* symtab = builder->GetSymtabBuilder();
+  auto* symtab = builder->GetSymtab();
   for (auto it = method_info.begin(); it != method_info.end(); ++it) {
     std::string name = PrettyMethod(it->dex_method_index_, *it->dex_file_, true);
     if (deduped_addresses.find(it->low_pc_) != deduped_addresses.end()) {
@@ -240,13 +211,13 @@
     uint32_t low_pc = it->low_pc_;
     // Add in code delta, e.g., thumb bit 0 for Thumb2 code.
     low_pc += it->compiled_method_->CodeDelta();
-    symtab->AddSymbol(name, &builder->GetTextBuilder(), low_pc,
+    symtab->AddSymbol(name, builder->GetText(), low_pc,
                       true, it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC);
 
     // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
     // instructions, so that disassembler tools can correctly disassemble.
     if (it->compiled_method_->GetInstructionSet() == kThumb2) {
-      symtab->AddSymbol("$t", &builder->GetTextBuilder(), it->low_pc_ & ~1, true,
+      symtab->AddSymbol("$t", builder->GetText(), it->low_pc_ & ~1, true,
                         0, STB_LOCAL, STT_NOTYPE);
     }
   }
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index d2d38da..15b4017 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -1112,13 +1112,14 @@
   return offset;
 }
 
-bool OatWriter::Write(OutputStream* out) {
+bool OatWriter::WriteRodata(OutputStream* out) {
   const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
   if (raw_file_offset == (off_t) -1) {
     LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
     return false;
   }
   const size_t file_offset = static_cast<size_t>(raw_file_offset);
+  oat_data_offset_ = file_offset;
 
   // Reserve space for header. It will be written last - after updating the checksum.
   size_t header_size = oat_header_->GetHeaderSize();
@@ -1146,6 +1147,27 @@
     return false;
   }
 
+  // Write padding.
+  off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
+  relative_offset += size_executable_offset_alignment_;
+  DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
+  size_t expected_file_offset = file_offset + relative_offset;
+  if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
+    PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
+                << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
+    return 0;
+  }
+  DCHECK_OFFSET();
+
+  return true;
+}
+
+bool OatWriter::WriteCode(OutputStream* out) {
+  size_t header_size = oat_header_->GetHeaderSize();
+  const size_t file_offset = oat_data_offset_;
+  size_t relative_offset = oat_header_->GetExecutableOffset();
+  DCHECK_OFFSET();
+
   relative_offset = WriteCode(out, file_offset, relative_offset);
   if (relative_offset == 0) {
     LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
@@ -1215,7 +1237,7 @@
     PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
     return false;
   }
-  DCHECK_EQ(raw_file_offset, out->Seek(0, kSeekCurrent));
+  DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
   if (!out->WriteFully(oat_header_, header_size)) {
     PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
     return false;
@@ -1290,16 +1312,6 @@
 }
 
 size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {
-  off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
-  relative_offset += size_executable_offset_alignment_;
-  DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
-  size_t expected_file_offset = file_offset + relative_offset;
-  if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
-    PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
-                << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
-    return 0;
-  }
-  DCHECK_OFFSET();
   if (compiler_driver_->IsImage()) {
     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
 
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 8c79b44..6f1b4ec 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -118,11 +118,8 @@
     return it.first->second.get();
   }
 
-  void SetOatDataOffset(size_t oat_data_offset) {
-    oat_data_offset_ = oat_data_offset;
-  }
-
-  bool Write(OutputStream* out);
+  bool WriteRodata(OutputStream* out);
+  bool WriteCode(OutputStream* out);
 
   ~OatWriter();
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index e142742..b9a3d37 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -76,41 +76,38 @@
   "kClassRoots",
 };
 
-class OatSymbolizer FINAL : public CodeOutput {
+class OatSymbolizer FINAL {
  public:
-  explicit OatSymbolizer(const OatFile* oat_file, const std::string& output_name) :
-      oat_file_(oat_file), builder_(nullptr), elf_output_(nullptr),
-      output_name_(output_name.empty() ? "symbolized.oat" : output_name) {
-  }
+  class RodataWriter FINAL : public CodeOutput {
+   public:
+    explicit RodataWriter(const OatFile* oat_file) : oat_file_(oat_file) {}
 
-  bool Init() {
-    Elf32_Word oat_data_size = oat_file_->GetOatHeader().GetExecutableOffset();
-
-    uint32_t diff = static_cast<uint32_t>(oat_file_->End() - oat_file_->Begin());
-    uint32_t oat_exec_size = diff - oat_data_size;
-    uint32_t oat_bss_size = oat_file_->BssSize();
-
-    elf_output_ = OS::CreateEmptyFile(output_name_.c_str());
-
-    builder_.reset(new ElfBuilder<ElfTypes32>(
-        this,
-        elf_output_,
-        oat_file_->GetOatHeader().GetInstructionSet(),
-        0,
-        oat_data_size,
-        oat_data_size,
-        oat_exec_size,
-        RoundUp(oat_data_size + oat_exec_size, kPageSize),
-        oat_bss_size,
-        true,
-        false));
-
-    if (!builder_->Init()) {
-      builder_.reset(nullptr);
-      return false;
+    bool Write(OutputStream* out) OVERRIDE {
+      const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
+      return out->WriteFully(oat_file_->Begin(), rodata_size);
     }
 
-    return true;
+   private:
+    const OatFile* oat_file_;
+  };
+
+  class TextWriter FINAL : public CodeOutput {
+   public:
+    explicit TextWriter(const OatFile* oat_file) : oat_file_(oat_file) {}
+
+    bool Write(OutputStream* out) OVERRIDE {
+      const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
+      const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
+      return out->WriteFully(text_begin, oat_file_->End() - text_begin);
+    }
+
+   private:
+    const OatFile* oat_file_;
+  };
+
+  explicit OatSymbolizer(const OatFile* oat_file, const std::string& output_name) :
+      oat_file_(oat_file), builder_(nullptr),
+      output_name_(output_name.empty() ? "symbolized.oat" : output_name) {
   }
 
   typedef void (OatSymbolizer::*Callback)(const DexFile::ClassDef&,
@@ -122,9 +119,17 @@
                                           uint32_t);
 
   bool Symbolize() {
-    if (builder_.get() == nullptr) {
-      return false;
-    }
+    Elf32_Word rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
+    uint32_t size = static_cast<uint32_t>(oat_file_->End() - oat_file_->Begin());
+    uint32_t text_size = size - rodata_size;
+    uint32_t bss_size = oat_file_->BssSize();
+    RodataWriter rodata_writer(oat_file_);
+    TextWriter text_writer(oat_file_);
+    builder_.reset(new ElfBuilder<ElfTypes32>(
+        oat_file_->GetOatHeader().GetInstructionSet(),
+        rodata_size, &rodata_writer,
+        text_size, &text_writer,
+        bss_size));
 
     Walk(&art::OatSymbolizer::RegisterForDedup);
 
@@ -132,10 +137,11 @@
 
     Walk(&art::OatSymbolizer::AddSymbol);
 
-    bool result = builder_->Write();
+    File* elf_output = OS::CreateEmptyFile(output_name_.c_str());
+    bool result = builder_->Write(elf_output);
 
     // Ignore I/O errors.
-    UNUSED(elf_output_->FlushClose());
+    UNUSED(elf_output->FlushClose());
 
     return result;
   }
@@ -269,24 +275,14 @@
         pretty_name = "[Dedup]" + pretty_name;
       }
 
-      auto* symtab = builder_->GetSymtabBuilder();
+      auto* symtab = builder_->GetSymtab();
 
-      symtab->AddSymbol(pretty_name, &builder_->GetTextBuilder(),
+      symtab->AddSymbol(pretty_name, builder_->GetText(),
           oat_method.GetCodeOffset() - oat_file_->GetOatHeader().GetExecutableOffset(),
           true, oat_method.GetQuickCodeSize(), STB_GLOBAL, STT_FUNC);
     }
   }
 
-  // Set oat data offset. Required by ElfBuilder/CodeOutput.
-  void SetCodeOffset(size_t offset ATTRIBUTE_UNUSED) {
-    // Nothing to do.
-  }
-
-  // Write oat code. Required by ElfBuilder/CodeOutput.
-  bool Write(OutputStream* out) {
-    return out->WriteFully(oat_file_->Begin(), oat_file_->End() - oat_file_->Begin());
-  }
-
  private:
   static void SkipAllFields(ClassDataItemIterator* it) {
     while (it->HasNextStaticField()) {
@@ -299,7 +295,6 @@
 
   const OatFile* oat_file_;
   std::unique_ptr<ElfBuilder<ElfTypes32> > builder_;
-  File* elf_output_;
   std::unordered_map<uint32_t, uint32_t> state_;
   const std::string output_name_;
 };
@@ -2203,10 +2198,6 @@
   }
 
   OatSymbolizer oat_symbolizer(oat_file, output_name);
-  if (!oat_symbolizer.Init()) {
-    fprintf(stderr, "Failed to initialize symbolizer\n");
-    return EXIT_FAILURE;
-  }
   if (!oat_symbolizer.Symbolize()) {
     fprintf(stderr, "Failed to symbolize\n");
     return EXIT_FAILURE;