Decouple virtual memory allocation in ElfBuilder.

Multi-boot-image requires knowing the loaded size ahead of time,
and calculating that size ended up being fairly hacky.

Decouple allocation of virtual memory and allocation of file space,
so that we have more flexibility when we do those.

Test: The generated boot image is bit-for-bit identical as before.

Change-Id: I012b55a71e7625f2310570f9b91447c9db73578b
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
index d0c98a7..27b70c8 100644
--- a/compiler/debug/elf_debug_frame_writer.h
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -207,13 +207,12 @@
   }
 
   // Write .eh_frame/.debug_frame section.
-  auto* cfi_section = (format == dwarf::DW_DEBUG_FRAME_FORMAT
-                       ? builder->GetDebugFrame()
-                       : builder->GetEhFrame());
+  const bool is_debug_frame = format == dwarf::DW_DEBUG_FRAME_FORMAT;
+  auto* cfi_section = (is_debug_frame ? builder->GetDebugFrame() : builder->GetEhFrame());
   {
     cfi_section->Start();
     const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
-    const Elf_Addr cfi_address = cfi_section->GetAddress();
+    const Elf_Addr cfi_address = (is_debug_frame ? 0 : cfi_section->GetAddress());
     const Elf_Addr cie_address = cfi_address;
     Elf_Addr buffer_address = cfi_address;
     std::vector<uint8_t> buffer;  // Small temporary buffer.
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index d599994..2c5a2f4 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -296,7 +296,7 @@
     CHECK_EQ(info_.Depth(), 0);
     std::vector<uint8_t> buffer;
     buffer.reserve(info_.data()->size() + KB);
-    const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+    const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
     // All compilation units share single table which is at the start of .debug_abbrev.
     const size_t debug_abbrev_offset = 0;
     WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
@@ -461,7 +461,7 @@
     CHECK_EQ(info_.Depth(), 0);
     std::vector<uint8_t> buffer;
     buffer.reserve(info_.data()->size() + KB);
-    const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+    const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
     // All compilation units share single table which is at the start of .debug_abbrev.
     const size_t debug_abbrev_offset = 0;
     WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index 943e03a..f8e1bf7 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -60,7 +60,7 @@
         ? builder_->GetText()->GetAddress()
         : 0;
 
-    compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetSize();
+    compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetPosition();
 
     std::vector<dwarf::FileEntry> files;
     std::unordered_map<std::string, size_t> files_map;
@@ -268,7 +268,7 @@
     }
     std::vector<uint8_t> buffer;
     buffer.reserve(opcodes.data()->size() + KB);
-    size_t offset = builder_->GetDebugLine()->GetSize();
+    size_t offset = builder_->GetDebugLine()->GetPosition();
     WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches_);
     builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
     return buffer.size();
diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h
index 1cdf6b0..9b8ec35 100644
--- a/compiler/debug/elf_gnu_debugdata_writer.h
+++ b/compiler/debug/elf_gnu_debugdata_writer.h
@@ -91,8 +91,8 @@
   builder->Start();
   // Mirror .rodata and .text as NOBITS sections.
   // It is needed to detected relocations after compression.
-  builder->GetRoData()->WriteNoBitsSection(rodata_section_size);
-  builder->GetText()->WriteNoBitsSection(text_section_size);
+  builder->GetRoData()->AllocateVirtualMemory(rodata_section_size);
+  builder->GetText()->AllocateVirtualMemory(text_section_size);
   WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
   WriteCFISection(builder.get(),
                   method_infos,
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index b30b55e..3710878 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -108,8 +108,6 @@
           section_index_(0),
           name_(name),
           link_(link),
-          started_(false),
-          finished_(false),
           phdr_flags_(PF_R),
           phdr_type_(0) {
       DCHECK_GE(align, 1u);
@@ -120,90 +118,62 @@
       header_.sh_entsize = entsize;
     }
 
-    // Start writing of this section.
-    void Start() {
-      CHECK(!started_);
-      CHECK(!finished_);
-      started_ = true;
-      auto& sections = owner_->sections_;
-      // Check that the previous section is complete.
-      CHECK(sections.empty() || sections.back()->finished_);
-      // The first ELF section index is 1. Index 0 is reserved for NULL.
-      section_index_ = sections.size() + 1;
-      // Page-align if we switch between allocated and non-allocated sections,
-      // or if we change the type of allocation (e.g. executable vs non-executable).
-      if (!sections.empty()) {
-        if (header_.sh_flags != sections.back()->header_.sh_flags) {
-          header_.sh_addralign = kPageSize;
-        }
-      }
-      // Align file position.
-      if (header_.sh_type != SHT_NOBITS) {
-        header_.sh_offset = owner_->AlignFileOffset(header_.sh_addralign);
-      } else {
-        header_.sh_offset = 0;
-      }
-      // Align virtual memory address.
-      if ((header_.sh_flags & SHF_ALLOC) != 0) {
-        header_.sh_addr = owner_->AlignVirtualAddress(header_.sh_addralign);
-      } else {
-        header_.sh_addr = 0;
-      }
-      // Push this section on the list of written sections.
-      sections.push_back(this);
+    // Allocate chunk of virtual memory for this section from the owning ElfBuilder.
+    // This must be done at the start for all SHF_ALLOC sections (i.e. mmaped by linker).
+    // It is fine to allocate section but never call Start/End() (e.g. the .bss section).
+    void AllocateVirtualMemory(Elf_Word size) {
+      AllocateVirtualMemory(owner_->virtual_address_, size);
     }
 
-    // Finish writing of this section.
+    void AllocateVirtualMemory(Elf_Addr addr, Elf_Word size) {
+      CHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
+      Elf_Word align = AddSection();
+      CHECK_EQ(header_.sh_addr, 0u);
+      header_.sh_addr = RoundUp(addr, align);
+      CHECK(header_.sh_size == 0u || header_.sh_size == size);
+      header_.sh_size = size;
+      CHECK_LE(owner_->virtual_address_, header_.sh_addr);
+      owner_->virtual_address_ = header_.sh_addr + header_.sh_size;
+    }
+
+    // Start writing file data of this section.
+    void Start() {
+      CHECK(owner_->current_section_ == nullptr);
+      Elf_Word align = AddSection();
+      CHECK_EQ(header_.sh_offset, 0u);
+      header_.sh_offset = owner_->AlignFileOffset(align);
+      owner_->current_section_ = this;
+    }
+
+    // Finish writing file data of this section.
     void End() {
-      CHECK(started_);
-      CHECK(!finished_);
-      finished_ = true;
-      if (header_.sh_type == SHT_NOBITS) {
-        CHECK_GT(header_.sh_size, 0u);
-      } else {
-        // Use the current file position to determine section size.
-        off_t file_offset = owner_->stream_.Seek(0, kSeekCurrent);
-        CHECK_GE(file_offset, (off_t)header_.sh_offset);
-        header_.sh_size = file_offset - header_.sh_offset;
-      }
-      if ((header_.sh_flags & SHF_ALLOC) != 0) {
-        owner_->virtual_address_ += header_.sh_size;
-      }
+      CHECK(owner_->current_section_ == this);
+      Elf_Word position = GetPosition();
+      CHECK(header_.sh_size == 0u || header_.sh_size == position);
+      header_.sh_size = position;
+      owner_->current_section_ = nullptr;
+    }
+
+    // Get the number of bytes written so far.
+    // Only valid while writing the section.
+    Elf_Word GetPosition() const {
+      CHECK(owner_->current_section_ == this);
+      off_t file_offset = owner_->stream_.Seek(0, kSeekCurrent);
+      DCHECK_GE(file_offset, (off_t)header_.sh_offset);
+      return file_offset - header_.sh_offset;
     }
 
     // Get the location of this section in virtual memory.
     Elf_Addr GetAddress() const {
-      CHECK(started_);
-      return header_.sh_addr;
-    }
-
-    // Returns the size of the content of this section.
-    Elf_Word GetSize() const {
-      if (finished_) {
-        return header_.sh_size;
-      } else {
-        CHECK(started_);
-        CHECK_NE(header_.sh_type, (Elf_Word)SHT_NOBITS);
-        return owner_->stream_.Seek(0, kSeekCurrent) - header_.sh_offset;
-      }
-    }
-
-    // Write this section as "NOBITS" section. (used for the .bss section)
-    // This means that the ELF file does not contain the initial data for this section
-    // and it will be zero-initialized when the ELF file is loaded in the running program.
-    void WriteNoBitsSection(Elf_Word size) {
       DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
-      header_.sh_type = SHT_NOBITS;
-      Start();
-      header_.sh_size = size;
-      End();
+      DCHECK_NE(header_.sh_addr, 0u);
+      return header_.sh_addr;
     }
 
     // This function always succeeds to simplify code.
     // Use builder's Good() to check the actual status.
     bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
-      CHECK(started_);
-      CHECK(!finished_);
+      CHECK(owner_->current_section_ == this);
       return owner_->stream_.WriteFully(buffer, byte_count);
     }
 
@@ -221,19 +191,32 @@
     }
 
     Elf_Word GetSectionIndex() const {
-      DCHECK(started_);
       DCHECK_NE(section_index_, 0u);
       return section_index_;
     }
 
    private:
+    // Add this section to the list of generated ELF sections (if not there already).
+    // It also ensures the alignment is sufficient to generate valid program headers,
+    // since that depends on the previous section. It returns the required alignment.
+    Elf_Word AddSection() {
+      if (section_index_ == 0) {
+        std::vector<Section*>& sections = owner_->sections_;
+        Elf_Word last = sections.empty() ? PF_R : sections.back()->phdr_flags_;
+        if (owner_->write_program_headers_ && phdr_flags_ != last) {
+          header_.sh_addralign = kPageSize;  // Page-align if R/W/X flags changed.
+        }
+        sections.push_back(this);
+        section_index_ = sections.size();  // First ELF section has index 1.
+      }
+      return header_.sh_addralign;
+    }
+
     ElfBuilder<ElfTypes>* owner_;
     Elf_Shdr header_;
     Elf_Word section_index_;
     const std::string name_;
     const Section* const link_;
-    bool started_;
-    bool finished_;
     Elf_Word phdr_flags_;
     Elf_Word phdr_type_;
 
@@ -370,7 +353,7 @@
       Elf_Word section_index;
       if (section != nullptr) {
         DCHECK_LE(section->GetAddress(), addr);
-        DCHECK_LE(addr, section->GetAddress() + section->GetSize());
+        DCHECK_LE(addr, section->GetAddress() + section->header_.sh_size);
         section_index = section->GetSectionIndex();
       } else {
         section_index = static_cast<Elf_Word>(SHN_ABS);
@@ -479,6 +462,10 @@
           digest_start_(-1) {
     }
 
+    Elf_Word GetSize() {
+      return 16 + kBuildIdLen;
+    }
+
     void Write() {
       // The size fields are 32-bit on both 32-bit and 64-bit systems, confirmed
       // with the 64-bit linker and libbfd code. The size of name and desc must
@@ -490,6 +477,7 @@
       digest_start_ = this->Seek(0, kSeekCurrent);
       static_assert(kBuildIdLen % 4 == 0, "expecting a mutliple of 4 for build ID length");
       this->WriteFully(std::string(kBuildIdLen, '\0').c_str(), kBuildIdLen);  // desc.
+      DCHECK_EQ(this->GetPosition(), GetSize());
     }
 
     off_t GetDigestStart() {
@@ -530,6 +518,7 @@
         abiflags_(this, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
                   isa, features),
         build_id_(this, ".note.gnu.build-id", SHT_NOTE, SHF_ALLOC, nullptr, 0, 4, 0),
+        current_section_(nullptr),
         started_(false),
         write_program_headers_(false),
         loaded_size_(0u),
@@ -545,6 +534,7 @@
   ~ElfBuilder() {}
 
   InstructionSet GetIsa() { return isa_; }
+  BuildIdSection* GetBuildId() { return &build_id_; }
   Section* GetRoData() { return &rodata_; }
   Section* GetText() { return &text_; }
   Section* GetBss() { return &bss_; }
@@ -622,6 +612,9 @@
       if (section->link_ != nullptr) {
         section->header_.sh_link = section->link_->GetSectionIndex();
       }
+      if (section->header_.sh_offset == 0) {
+        section->header_.sh_type = SHT_NOBITS;
+      }
     }
     shstrtab_.End();
 
@@ -680,65 +673,57 @@
       soname = soname.substr(directory_separator_pos + 1);
     }
 
-    // Calculate addresses of .text, .bss and .dynstr.
-    DCHECK_EQ(rodata_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    DCHECK_EQ(text_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    DCHECK_EQ(bss_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    DCHECK_EQ(dynstr_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    Elf_Word rodata_address = rodata_.GetAddress();
-    Elf_Word text_address = RoundUp(rodata_address + rodata_size, kPageSize);
-    Elf_Word bss_address = RoundUp(text_address + text_size, kPageSize);
-    Elf_Word abiflags_address = RoundUp(bss_address + bss_size, kPageSize);
-    Elf_Word abiflags_size = 0;
-    if (isa_ == InstructionSet::kMips || isa_ == InstructionSet::kMips64) {
-      abiflags_size = abiflags_.GetSize();
+    // Allocate all pre-dynamic sections.
+    rodata_.AllocateVirtualMemory(rodata_size);
+    text_.AllocateVirtualMemory(text_size);
+    if (bss_size != 0) {
+      bss_.AllocateVirtualMemory(bss_size);
     }
-    Elf_Word dynstr_address = RoundUp(abiflags_address + abiflags_size, kPageSize);
+    if (isa_ == InstructionSet::kMips || isa_ == InstructionSet::kMips64) {
+      abiflags_.AllocateVirtualMemory(abiflags_.GetSize());
+    }
 
     // Cache .dynstr, .dynsym and .hash data.
     dynstr_.Add("");  // dynstr should start with empty string.
-    Elf_Word rodata_index = rodata_.GetSectionIndex();
     Elf_Word oatdata = dynstr_.Add("oatdata");
-    dynsym_.Add(oatdata, rodata_index, rodata_address, rodata_size, STB_GLOBAL, STT_OBJECT);
+    dynsym_.Add(oatdata, &rodata_, rodata_.GetAddress(), rodata_size, STB_GLOBAL, STT_OBJECT);
     if (text_size != 0u) {
-      Elf_Word text_index = rodata_index + 1u;
       Elf_Word oatexec = dynstr_.Add("oatexec");
-      dynsym_.Add(oatexec, text_index, text_address, text_size, STB_GLOBAL, STT_OBJECT);
+      dynsym_.Add(oatexec, &text_, text_.GetAddress(), text_size, STB_GLOBAL, STT_OBJECT);
       Elf_Word oatlastword = dynstr_.Add("oatlastword");
-      Elf_Word oatlastword_address = text_address + text_size - 4;
-      dynsym_.Add(oatlastword, text_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
+      Elf_Word oatlastword_address = text_.GetAddress() + text_size - 4;
+      dynsym_.Add(oatlastword, &text_, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
     } else if (rodata_size != 0) {
       // rodata_ can be size 0 for dwarf_test.
       Elf_Word oatlastword = dynstr_.Add("oatlastword");
-      Elf_Word oatlastword_address = rodata_address + rodata_size - 4;
-      dynsym_.Add(oatlastword, rodata_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
+      Elf_Word oatlastword_address = rodata_.GetAddress() + rodata_size - 4;
+      dynsym_.Add(oatlastword, &rodata_, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
     }
     DCHECK_LE(bss_roots_offset, bss_size);
     if (bss_size != 0u) {
-      Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u);
       Elf_Word oatbss = dynstr_.Add("oatbss");
-      dynsym_.Add(oatbss, bss_index, bss_address, bss_roots_offset, STB_GLOBAL, STT_OBJECT);
+      dynsym_.Add(oatbss, &bss_, bss_.GetAddress(), bss_roots_offset, STB_GLOBAL, STT_OBJECT);
       DCHECK_LE(bss_methods_offset, bss_roots_offset);
       DCHECK_LE(bss_roots_offset, bss_size);
       // Add a symbol marking the start of the methods part of the .bss, if not empty.
       if (bss_methods_offset != bss_roots_offset) {
-        Elf_Word bss_methods_address = bss_address + bss_methods_offset;
+        Elf_Word bss_methods_address = bss_.GetAddress() + bss_methods_offset;
         Elf_Word bss_methods_size = bss_roots_offset - bss_methods_offset;
         Elf_Word oatbssroots = dynstr_.Add("oatbssmethods");
         dynsym_.Add(
-            oatbssroots, bss_index, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT);
+            oatbssroots, &bss_, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT);
       }
       // Add a symbol marking the start of the GC roots part of the .bss, if not empty.
       if (bss_roots_offset != bss_size) {
-        Elf_Word bss_roots_address = bss_address + bss_roots_offset;
+        Elf_Word bss_roots_address = bss_.GetAddress() + bss_roots_offset;
         Elf_Word bss_roots_size = bss_size - bss_roots_offset;
         Elf_Word oatbssroots = dynstr_.Add("oatbssroots");
         dynsym_.Add(
-            oatbssroots, bss_index, bss_roots_address, bss_roots_size, STB_GLOBAL, STT_OBJECT);
+            oatbssroots, &bss_, bss_roots_address, bss_roots_size, STB_GLOBAL, STT_OBJECT);
       }
       Elf_Word oatbsslastword = dynstr_.Add("oatbsslastword");
-      Elf_Word bsslastword_address = bss_address + bss_size - 4;
-      dynsym_.Add(oatbsslastword, bss_index, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
+      Elf_Word bsslastword_address = bss_.GetAddress() + bss_size - 4;
+      dynsym_.Add(oatbsslastword, &bss_, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
     }
     Elf_Word soname_offset = dynstr_.Add(soname);
 
@@ -759,28 +744,24 @@
     hash.push_back(0);  // Last symbol terminates the chain.
     hash_.Add(hash.data(), hash.size() * sizeof(hash[0]));
 
-    // Calculate addresses of .dynsym, .hash and .dynamic.
-    DCHECK_EQ(dynstr_.header_.sh_flags, dynsym_.header_.sh_flags);
-    DCHECK_EQ(dynsym_.header_.sh_flags, hash_.header_.sh_flags);
-    Elf_Word dynsym_address =
-        RoundUp(dynstr_address + dynstr_.GetCacheSize(), dynsym_.header_.sh_addralign);
-    Elf_Word hash_address =
-        RoundUp(dynsym_address + dynsym_.GetCacheSize(), hash_.header_.sh_addralign);
-    DCHECK_EQ(dynamic_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    Elf_Word dynamic_address = RoundUp(hash_address + dynsym_.GetCacheSize(), kPageSize);
+    // Allocate all remaining sections.
+    dynstr_.AllocateVirtualMemory(dynstr_.GetCacheSize());
+    dynsym_.AllocateVirtualMemory(dynsym_.GetCacheSize());
+    hash_.AllocateVirtualMemory(hash_.GetCacheSize());
 
     Elf_Dyn dyns[] = {
-      { DT_HASH, { hash_address } },
-      { DT_STRTAB, { dynstr_address } },
-      { DT_SYMTAB, { dynsym_address } },
+      { DT_HASH, { hash_.GetAddress() } },
+      { DT_STRTAB, { dynstr_.GetAddress() } },
+      { DT_SYMTAB, { dynsym_.GetAddress() } },
       { DT_SYMENT, { sizeof(Elf_Sym) } },
       { DT_STRSZ, { dynstr_.GetCacheSize() } },
       { DT_SONAME, { soname_offset } },
       { DT_NULL, { 0 } },
     };
     dynamic_.Add(&dyns, sizeof(dyns));
+    dynamic_.AllocateVirtualMemory(dynamic_.GetCacheSize());
 
-    loaded_size_ = RoundUp(dynamic_address + dynamic_.GetCacheSize(), kPageSize);
+    loaded_size_ = RoundUp(virtual_address_, kPageSize);
   }
 
   void WriteDynamicSection() {
@@ -788,8 +769,6 @@
     dynsym_.WriteCachedSection();
     hash_.WriteCachedSection();
     dynamic_.WriteCachedSection();
-
-    CHECK_EQ(loaded_size_, RoundUp(dynamic_.GetAddress() + dynamic_.GetSize(), kPageSize));
   }
 
   Elf_Word GetLoadedSize() {
@@ -828,10 +807,6 @@
      return stream_.Seek(RoundUp(stream_.Seek(0, kSeekCurrent), alignment), kSeekSet);
   }
 
-  Elf_Addr AlignVirtualAddress(size_t alignment) {
-     return virtual_address_ = RoundUp(virtual_address_, alignment);
-  }
-
  private:
   static Elf_Ehdr MakeElfHeader(InstructionSet isa, const InstructionSetFeatures* features) {
     Elf_Ehdr elf_header = Elf_Ehdr();
@@ -902,7 +877,6 @@
     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;
   }
 
@@ -933,6 +907,7 @@
     for (auto* section : sections_) {
       const Elf_Shdr& shdr = section->header_;
       if ((shdr.sh_flags & SHF_ALLOC) != 0 && shdr.sh_size != 0) {
+        DCHECK(shdr.sh_addr != 0u) << "Allocate virtual memory for the section";
         // PT_LOAD tells the linker to mmap part of the file.
         // The linker can only mmap page-aligned sections.
         // Single PT_LOAD may contain several ELF sections.
@@ -1010,6 +985,7 @@
 
   // List of used section in the order in which they were written.
   std::vector<Section*> sections_;
+  Section* current_section_;  // The section which is currently being written.
 
   bool started_;
   bool write_program_headers_;
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index 5fc33dd..758e21d 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -173,6 +173,7 @@
 void ElfWriterQuick<ElfTypes>::Start() {
   builder_->Start();
   if (compiler_options_->GetGenerateBuildId()) {
+    builder_->GetBuildId()->AllocateVirtualMemory(builder_->GetBuildId()->GetSize());
     builder_->WriteBuildIdSection();
   }
 }
@@ -225,9 +226,6 @@
 
 template <typename ElfTypes>
 void ElfWriterQuick<ElfTypes>::WriteDynamicSection() {
-  if (bss_size_ != 0u) {
-    builder_->GetBss()->WriteNoBitsSection(bss_size_);
-  }
   if (builder_->GetIsa() == InstructionSet::kMips ||
       builder_->GetIsa() == InstructionSet::kMips64) {
     builder_->WriteMIPSabiflagsSection();
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 1b4485b..1a1d8cc 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -146,13 +146,10 @@
 
     auto* rodata = builder_->GetRoData();
     auto* text = builder_->GetText();
-    auto* bss = builder_->GetBss();
 
     const uint8_t* rodata_begin = oat_file_->Begin();
     const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
-    if (no_bits_) {
-      rodata->WriteNoBitsSection(rodata_size);
-    } else {
+    if (!no_bits_) {
       rodata->Start();
       rodata->WriteFully(rodata_begin, rodata_size);
       rodata->End();
@@ -160,18 +157,12 @@
 
     const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
     const size_t text_size = oat_file_->End() - text_begin;
-    if (no_bits_) {
-      text->WriteNoBitsSection(text_size);
-    } else {
+    if (!no_bits_) {
       text->Start();
       text->WriteFully(text_begin, text_size);
       text->End();
     }
 
-    if (oat_file_->BssSize() != 0) {
-      bss->WriteNoBitsSection(oat_file_->BssSize());
-    }
-
     if (isa == InstructionSet::kMips || isa == InstructionSet::kMips64) {
       builder_->WriteMIPSabiflagsSection();
     }