Allow method references across oat files for multi-image.

These were disabled because we didn't have sufficient
information about the multi-image layout when processing
link-time patches in OatWriter. This CL refactors the
ELF file creation so that the information is available.

Change-Id: I6f2e8dc8572d143c72cc2693bb0ba4fd76f889ab
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index e4bfac9..239bc59 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -194,16 +194,15 @@
                                             kind,
                                             isa,
                                             instruction_set_features_.get(),
-                                            true,
+                                            /* boot_image */ true,
                                             GetImageClasses(),
                                             GetCompiledClasses(),
                                             GetCompiledMethods(),
-                                            2,
-                                            true,
-                                            true,
+                                            /* thread_count */ 2,
+                                            /* dump_stats */ true,
+                                            /* dump_passes */ true,
                                             timer_.get(),
-                                            -1,
-                                            /* dex_to_oat_map */ nullptr,
+                                            /* swap_fd */ -1,
                                             GetProfileCompilationInfo()));
   // We typically don't generate an image in unit tests, disable this optimization by default.
   compiler_driver_->SetSupportBootImageFixup(false);
diff --git a/compiler/dex/quick/quick_cfi_test.cc b/compiler/dex/quick/quick_cfi_test.cc
index 0cd41bb..6c6c9cf 100644
--- a/compiler/dex/quick/quick_cfi_test.cc
+++ b/compiler/dex/quick/quick_cfi_test.cc
@@ -84,17 +84,16 @@
                           Compiler::kQuick,
                           isa,
                           isa_features.get(),
-                          false,
-                          nullptr,
-                          nullptr,
-                          nullptr,
-                          0,
-                          false,
-                          false,
-                          0,
-                          -1,
-                          nullptr,
-                          nullptr);
+                          /* boot_image */ false,
+                          /* image_classes */ nullptr,
+                          /* compiled_classes */ nullptr,
+                          /* compiled_methods */ nullptr,
+                          /* thread_count */ 0,
+                          /* dump_stats */ false,
+                          /* dump_passes */ false,
+                          /* timer */ nullptr,
+                          /* swap_fd */ -1,
+                          /* profile_compilation_info */ nullptr);
     ClassLinker* linker = nullptr;
     CompilationUnit cu(&pool, isa, &driver, linker);
     DexFile::CodeItem code_item { 0, 0, 0, 0, 0, 0, { 0 } };  // NOLINT
diff --git a/compiler/dex/quick/x86/quick_assemble_x86_test.cc b/compiler/dex/quick/x86/quick_assemble_x86_test.cc
index efdc333..ff0ecea 100644
--- a/compiler/dex/quick/x86/quick_assemble_x86_test.cc
+++ b/compiler/dex/quick/x86/quick_assemble_x86_test.cc
@@ -64,18 +64,17 @@
         method_inliner_map_.get(),
         Compiler::kQuick,
         isa_,
-        nullptr,
-        false,
-        nullptr,
-        nullptr,
-        nullptr,
-        0,
-        false,
-        false,
-        0,
-        -1,
-        nullptr,
-        nullptr));
+        /* instruction_set_features*/ nullptr,
+        /* boot_image */ false,
+        /* image_classes */ nullptr,
+        /* compiled_classes */ nullptr,
+        /* compiled_methods */ nullptr,
+        /* thread_count */ 0,
+        /* dump_stats */ false,
+        /* dump_passes */ false,
+        /* timer */ nullptr,
+        /* swap_fd */ -1,
+        /* profile_compilation_info */ nullptr));
     cu_.reset(new CompilationUnit(pool_.get(), isa_, compiler_driver_.get(), nullptr));
     DexFile::CodeItem* code_item = static_cast<DexFile::CodeItem*>(
         cu_->arena.Alloc(sizeof(DexFile::CodeItem), kArenaAllocMisc));
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index 2e2d1f9..0695cb5 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -32,19 +32,19 @@
   CompilerDriver driver(&compiler_options,
                         &verification_results,
                         &method_inliner_map,
-                        Compiler::kOptimizing, kNone,
-                        nullptr,
-                        false,
-                        nullptr,
-                        nullptr,
-                        nullptr,
-                        1u,
-                        false,
-                        false,
-                        nullptr,
-                        -1,
-                        nullptr,
-                        nullptr);
+                        Compiler::kOptimizing,
+                        /* instruction_set_ */ kNone,
+                        /* instruction_set_features */ nullptr,
+                        /* boot_image */ false,
+                        /* image_classes */ nullptr,
+                        /* compiled_classes */ nullptr,
+                        /* compiled_methods */ nullptr,
+                        /* thread_count */ 1u,
+                        /* dump_stats */ false,
+                        /* dump_passes */ false,
+                        /* timer */ nullptr,
+                        /* swap_fd */ -1,
+                        /* profile_compilation_info */ nullptr);
   CompiledMethodStorage* storage = driver.GetCompiledMethodStorage();
 
   ASSERT_TRUE(storage->DedupeEnabled());  // The default.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 670fe94..e80730f 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -342,12 +342,15 @@
     Compiler::Kind compiler_kind,
     InstructionSet instruction_set,
     const InstructionSetFeatures* instruction_set_features,
-    bool boot_image, std::unordered_set<std::string>* image_classes,
+    bool boot_image,
+    std::unordered_set<std::string>* image_classes,
     std::unordered_set<std::string>* compiled_classes,
     std::unordered_set<std::string>* compiled_methods,
-    size_t thread_count, bool dump_stats, bool dump_passes,
-    CumulativeLogger* timer, int swap_fd,
-    const std::unordered_map<const DexFile*, const char*>* dex_to_oat_map,
+    size_t thread_count,
+    bool dump_stats,
+    bool dump_passes,
+    CumulativeLogger* timer,
+    int swap_fd,
     const ProfileCompilationInfo* profile_compilation_info)
     : compiler_options_(compiler_options),
       verification_results_(verification_results),
@@ -374,7 +377,6 @@
       compiler_context_(nullptr),
       support_boot_image_fixup_(instruction_set != kMips && instruction_set != kMips64),
       dex_files_for_oat_file_(nullptr),
-      dex_file_oat_filename_map_(dex_to_oat_map),
       compiled_method_storage_(swap_fd),
       profile_compilation_info_(profile_compilation_info) {
   DCHECK(compiler_options_ != nullptr);
@@ -1678,12 +1680,6 @@
       use_dex_cache = true;
     }
   }
-  if (!use_dex_cache && IsBootImage()) {
-    if (!AreInSameOatFile(&(const_cast<mirror::Class*>(referrer_class)->GetDexFile()),
-                          &declaring_class->GetDexFile())) {
-      use_dex_cache = true;
-    }
-  }
   // The method is defined not within this dex file. We need a dex cache slot within the current
   // dex file or direct pointers.
   bool must_use_direct_pointers = false;
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 5e35cbb..ca340ee 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -94,9 +94,11 @@
                  bool boot_image, std::unordered_set<std::string>* image_classes,
                  std::unordered_set<std::string>* compiled_classes,
                  std::unordered_set<std::string>* compiled_methods,
-                 size_t thread_count, bool dump_stats, bool dump_passes,
-                 CumulativeLogger* timer, int swap_fd,
-                 const std::unordered_map<const DexFile*, const char*>* dex_to_oat_map,
+                 size_t thread_count,
+                 bool dump_stats,
+                 bool dump_passes,
+                 CumulativeLogger* timer,
+                 int swap_fd,
                  const ProfileCompilationInfo* profile_compilation_info);
 
   ~CompilerDriver();
@@ -113,20 +115,6 @@
         : ArrayRef<const DexFile* const>();
   }
 
-  // Are the given dex files compiled into the same oat file? Should only be called after
-  // GetDexFilesForOatFile, as the conservative answer (when we don't have a map) is true.
-  bool AreInSameOatFile(const DexFile* d1, const DexFile* d2) {
-    if (dex_file_oat_filename_map_ == nullptr) {
-      // TODO: Check for this wrt/ apps and boot image calls.
-      return true;
-    }
-    auto it1 = dex_file_oat_filename_map_->find(d1);
-    DCHECK(it1 != dex_file_oat_filename_map_->end());
-    auto it2 = dex_file_oat_filename_map_->find(d2);
-    DCHECK(it2 != dex_file_oat_filename_map_->end());
-    return it1->second == it2->second;
-  }
-
   void CompileAll(jobject class_loader,
                   const std::vector<const DexFile*>& dex_files,
                   TimingLogger* timings)
@@ -700,9 +688,6 @@
   // List of dex files that will be stored in the oat file.
   const std::vector<const DexFile*>* dex_files_for_oat_file_;
 
-  // Map from dex files to the oat file (name) they will be compiled into.
-  const std::unordered_map<const DexFile*, const char*>* dex_file_oat_filename_map_;
-
   CompiledMethodStorage compiled_method_storage_;
 
   // Info for profile guided compilation.
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index b673eeb..f7da609 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -86,12 +86,24 @@
   // Base class of all sections.
   class Section : public OutputStream {
    public:
-    Section(ElfBuilder<ElfTypes>* owner, const std::string& name,
-            Elf_Word type, Elf_Word flags, const Section* link,
-            Elf_Word info, Elf_Word align, Elf_Word entsize)
-        : OutputStream(name), owner_(owner), header_(),
-          section_index_(0), name_(name), link_(link),
-          started_(false), finished_(false), phdr_flags_(PF_R), phdr_type_(0) {
+    Section(ElfBuilder<ElfTypes>* owner,
+            const std::string& name,
+            Elf_Word type,
+            Elf_Word flags,
+            const Section* link,
+            Elf_Word info,
+            Elf_Word align,
+            Elf_Word entsize)
+        : OutputStream(name),
+          owner_(owner),
+          header_(),
+          section_index_(0),
+          name_(name),
+          link_(link),
+          started_(false),
+          finished_(false),
+          phdr_flags_(PF_R),
+          phdr_type_(0) {
       DCHECK_GE(align, 1u);
       header_.sh_type = type;
       header_.sh_flags = flags;
@@ -228,12 +240,84 @@
     DISALLOW_COPY_AND_ASSIGN(Section);
   };
 
-  // Writer of .dynstr .strtab and .shstrtab sections.
+  class CachedSection : public Section {
+   public:
+    CachedSection(ElfBuilder<ElfTypes>* owner,
+                  const std::string& name,
+                  Elf_Word type,
+                  Elf_Word flags,
+                  const Section* link,
+                  Elf_Word info,
+                  Elf_Word align,
+                  Elf_Word entsize)
+        : Section(owner, name, type, flags, link, info, align, entsize), cache_() { }
+
+    Elf_Word Add(const void* data, size_t length) {
+      Elf_Word offset = cache_.size();
+      const uint8_t* d = reinterpret_cast<const uint8_t*>(data);
+      cache_.insert(cache_.end(), d, d + length);
+      return offset;
+    }
+
+    Elf_Word GetCacheSize() {
+      return cache_.size();
+    }
+
+    void Write() {
+      this->WriteFully(cache_.data(), cache_.size());
+      cache_.clear();
+      cache_.shrink_to_fit();
+    }
+
+    void WriteCachedSection() {
+      this->Start();
+      Write();
+      this->End();
+    }
+
+   private:
+    std::vector<uint8_t> cache_;
+  };
+
+  // Writer of .dynstr section.
+  class CachedStringSection FINAL : public CachedSection {
+   public:
+    CachedStringSection(ElfBuilder<ElfTypes>* owner,
+                        const std::string& name,
+                        Elf_Word flags,
+                        Elf_Word align)
+        : CachedSection(owner,
+                        name,
+                        SHT_STRTAB,
+                        flags,
+                        /* link */ nullptr,
+                        /* info */ 0,
+                        align,
+                        /* entsize */ 0) { }
+
+    Elf_Word Add(const std::string& name) {
+      if (CachedSection::GetCacheSize() == 0u) {
+        DCHECK(name.empty());
+      }
+      return CachedSection::Add(name.c_str(), name.length() + 1);
+    }
+  };
+
+  // Writer of .strtab and .shstrtab sections.
   class StringSection FINAL : public Section {
    public:
-    StringSection(ElfBuilder<ElfTypes>* owner, const std::string& name,
-                  Elf_Word flags, Elf_Word align)
-        : Section(owner, name, SHT_STRTAB, flags, nullptr, 0, align, 0),
+    StringSection(ElfBuilder<ElfTypes>* owner,
+                  const std::string& name,
+                  Elf_Word flags,
+                  Elf_Word align)
+        : Section(owner,
+                  name,
+                  SHT_STRTAB,
+                  flags,
+                  /* link */ nullptr,
+                  /* info */ 0,
+                  align,
+                  /* entsize */ 0),
           current_offset_(0) {
     }
 
@@ -252,42 +336,60 @@
   };
 
   // Writer of .dynsym and .symtab sections.
-  class SymbolSection FINAL : public Section {
+  class SymbolSection FINAL : public CachedSection {
    public:
-    SymbolSection(ElfBuilder<ElfTypes>* owner, const std::string& name,
-                  Elf_Word type, Elf_Word flags, StringSection* strtab)
-        : Section(owner, name, type, flags, strtab, 0,
-                  sizeof(Elf_Off), sizeof(Elf_Sym)) {
+    SymbolSection(ElfBuilder<ElfTypes>* owner,
+                  const std::string& name,
+                  Elf_Word type,
+                  Elf_Word flags,
+                  Section* strtab)
+        : CachedSection(owner,
+                        name,
+                        type,
+                        flags,
+                        strtab,
+                        /* info */ 0,
+                        sizeof(Elf_Off),
+                        sizeof(Elf_Sym)) {
+      // The symbol table always has to start with NULL symbol.
+      Elf_Sym null_symbol = Elf_Sym();
+      CachedSection::Add(&null_symbol, sizeof(null_symbol));
     }
 
     // Buffer symbol for this section.  It will be written later.
     // If the symbol's section is null, it will be considered absolute (SHN_ABS).
     // (we use this in JIT to reference code which is stored outside the debug ELF file)
-    void Add(Elf_Word name, const Section* section,
-             Elf_Addr addr, bool is_relative, Elf_Word size,
-             uint8_t binding, uint8_t type, uint8_t other = 0) {
+    void Add(Elf_Word name,
+             const Section* section,
+             Elf_Addr addr,
+             bool is_relative,
+             Elf_Word size,
+             uint8_t binding,
+             uint8_t type,
+             uint8_t other = 0) {
+      DCHECK(section != nullptr || !is_relative);
+      Elf_Addr abs_addr = addr + (is_relative ? section->GetAddress() : 0);
+      Elf_Word section_index =
+          (section != nullptr) ? section->GetSectionIndex() : static_cast<Elf_Word>(SHN_ABS);
+      Add(name, section_index, abs_addr, size, binding, type, other);
+    }
+
+    void Add(Elf_Word name,
+             Elf_Word section_index,
+             Elf_Addr addr,
+             Elf_Word size,
+             uint8_t binding,
+             uint8_t type,
+             uint8_t other = 0) {
       Elf_Sym sym = Elf_Sym();
       sym.st_name = name;
-      sym.st_value = addr + (is_relative ? section->GetAddress() : 0);
+      sym.st_value = addr;
       sym.st_size = size;
       sym.st_other = other;
-      sym.st_shndx = (section != nullptr ? section->GetSectionIndex()
-                                         : static_cast<Elf_Word>(SHN_ABS));
+      sym.st_shndx = section_index;
       sym.st_info = (binding << 4) + (type & 0xf);
-      symbols_.push_back(sym);
+      CachedSection::Add(&sym, sizeof(sym));
     }
-
-    void Write() {
-      // The symbol table always has to start with NULL symbol.
-      Elf_Sym null_symbol = Elf_Sym();
-      this->WriteFully(&null_symbol, sizeof(null_symbol));
-      this->WriteFully(symbols_.data(), symbols_.size() * sizeof(symbols_[0]));
-      symbols_.clear();
-      symbols_.shrink_to_fit();
-    }
-
-   private:
-    std::vector<Elf_Sym> symbols_;
   };
 
   ElfBuilder(InstructionSet isa, OutputStream* output)
@@ -309,6 +411,8 @@
         debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0),
         shstrtab_(this, ".shstrtab", 0, 1),
         started_(false),
+        write_program_headers_(false),
+        loaded_size_(0u),
         virtual_address_(0) {
     text_.phdr_flags_ = PF_R | PF_X;
     bss_.phdr_flags_ = PF_R | PF_W;
@@ -380,6 +484,14 @@
   void End() {
     DCHECK(started_);
 
+    // Note: loaded_size_ == 0 for tests that don't write .rodata, .text, .bss,
+    // .dynstr, dynsym, .hash and .dynamic. These tests should not read loaded_size_.
+    // TODO: Either refactor the .eh_frame creation so that it counts towards loaded_size_,
+    // or remove all support for .eh_frame. (The currently unused .eh_frame counts towards
+    // the virtual_address_ but we don't consider it for loaded_size_.)
+    CHECK(loaded_size_ == 0 || loaded_size_ == RoundUp(virtual_address_, kPageSize))
+        << loaded_size_ << " " << virtual_address_;
+
     // Write section names and finish the section headers.
     shstrtab_.Start();
     shstrtab_.Write("");
@@ -434,45 +546,58 @@
   // 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.
-  void WriteDynamicSection(const std::string& elf_file_path) {
+  void PrepareDynamicSection(const std::string& elf_file_path,
+                             Elf_Word rodata_size,
+                             Elf_Word text_size,
+                             Elf_Word bss_size) {
     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);
     }
 
-    dynstr_.Start();
-    dynstr_.Write("");  // dynstr should start with empty string.
-    dynsym_.Add(dynstr_.Write("oatdata"), &rodata_, 0, true,
-                rodata_.GetSize(), STB_GLOBAL, STT_OBJECT);
-    if (text_.GetSize() != 0u) {
-      dynsym_.Add(dynstr_.Write("oatexec"), &text_, 0, true,
-                  text_.GetSize(), STB_GLOBAL, STT_OBJECT);
-      dynsym_.Add(dynstr_.Write("oatlastword"), &text_, text_.GetSize() - 4,
-                  true, 4, STB_GLOBAL, STT_OBJECT);
-    } else if (rodata_.GetSize() != 0) {
-      // rodata_ can be size 0 for dwarf_test.
-      dynsym_.Add(dynstr_.Write("oatlastword"), &rodata_, rodata_.GetSize() - 4,
-                  true, 4, STB_GLOBAL, STT_OBJECT);
-    }
-    if (bss_.finished_) {
-      dynsym_.Add(dynstr_.Write("oatbss"), &bss_,
-                  0, true, bss_.GetSize(), STB_GLOBAL, STT_OBJECT);
-      dynsym_.Add(dynstr_.Write("oatbsslastword"), &bss_,
-                  bss_.GetSize() - 4, true, 4, STB_GLOBAL, STT_OBJECT);
-    }
-    Elf_Word soname_offset = dynstr_.Write(soname);
-    dynstr_.End();
+    // 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 dynstr_address = RoundUp(bss_address + bss_size, kPageSize);
 
-    dynsym_.Start();
-    dynsym_.Write();
-    dynsym_.End();
+    // 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);
+    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);
+      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);
+    } 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);
+    }
+    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_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 soname_offset = dynstr_.Add(soname);
 
     // We do not really need a hash-table since there is so few entries.
     // However, the hash-table is the only way the linker can actually
     // determine the number of symbols in .dynsym so it is required.
-    hash_.Start();
-    int count = dynsym_.GetSize() / sizeof(Elf_Sym);  // Includes NULL.
+    int count = dynsym_.GetCacheSize() / sizeof(Elf_Sym);  // Includes NULL.
     std::vector<Elf_Word> hash;
     hash.push_back(1);  // Number of buckets.
     hash.push_back(count);  // Number of chains.
@@ -484,21 +609,44 @@
       hash.push_back(i + 1);  // Each symbol points to the next one.
     }
     hash.push_back(0);  // Last symbol terminates the chain.
-    hash_.WriteFully(hash.data(), hash.size() * sizeof(hash[0]));
-    hash_.End();
+    hash_.Add(hash.data(), hash.size() * sizeof(hash[0]));
 
-    dynamic_.Start();
+    // 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);
+
     Elf_Dyn dyns[] = {
-      { DT_HASH, { hash_.GetAddress() } },
-      { DT_STRTAB, { dynstr_.GetAddress() } },
-      { DT_SYMTAB, { dynsym_.GetAddress() } },
+      { DT_HASH, { hash_address } },
+      { DT_STRTAB, { dynstr_address } },
+      { DT_SYMTAB, { dynsym_address } },
       { DT_SYMENT, { sizeof(Elf_Sym) } },
-      { DT_STRSZ, { dynstr_.GetSize() } },
+      { DT_STRSZ, { dynstr_.GetCacheSize() } },
       { DT_SONAME, { soname_offset } },
       { DT_NULL, { 0 } },
     };
-    dynamic_.WriteFully(&dyns, sizeof(dyns));
-    dynamic_.End();
+    dynamic_.Add(&dyns, sizeof(dyns));
+
+    loaded_size_ = RoundUp(dynamic_address + dynamic_.GetCacheSize(), kPageSize);
+  }
+
+  void WriteDynamicSection() {
+    dynstr_.WriteCachedSection();
+    dynsym_.WriteCachedSection();
+    hash_.WriteCachedSection();
+    dynamic_.WriteCachedSection();
+
+    CHECK_EQ(loaded_size_, RoundUp(dynamic_.GetAddress() + dynamic_.GetSize(), kPageSize));
+  }
+
+  Elf_Word GetLoadedSize() {
+    CHECK_NE(loaded_size_, 0u);
+    return loaded_size_;
   }
 
   // Returns true if all writes and seeks on the output stream succeeded.
@@ -676,10 +824,10 @@
   Section rodata_;
   Section text_;
   Section bss_;
-  StringSection dynstr_;
+  CachedStringSection dynstr_;
   SymbolSection dynsym_;
-  Section hash_;
-  Section dynamic_;
+  CachedSection hash_;
+  CachedSection dynamic_;
   Section eh_frame_;
   Section eh_frame_hdr_;
   StringSection strtab_;
@@ -694,12 +842,14 @@
   std::vector<Section*> sections_;
 
   bool started_;
+  bool write_program_headers_;
+
+  // The size of the memory taken by the ELF file when loaded.
+  size_t loaded_size_;
 
   // Used for allocation of virtual address space.
   Elf_Addr virtual_address_;
 
-  size_t write_program_headers_;
-
   DISALLOW_COPY_AND_ASSIGN(ElfBuilder);
 };
 
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index d50a08c..c9ea0083 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -52,14 +52,12 @@
   virtual ~ElfWriter() {}
 
   virtual void Start() = 0;
-  virtual void PrepareDebugInfo(size_t rodata_section_size,
-                                size_t text_section_size,
-                                const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
+  virtual void SetLoadedSectionSizes(size_t rodata_size, size_t text_size, size_t bss_size) = 0;
+  virtual void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
   virtual OutputStream* StartRoData() = 0;
   virtual void EndRoData(OutputStream* rodata) = 0;
   virtual OutputStream* StartText() = 0;
   virtual void EndText(OutputStream* text) = 0;
-  virtual void SetBssSize(size_t bss_size) = 0;
   virtual void WriteDynamicSection() = 0;
   virtual void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
   virtual void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) = 0;
@@ -70,6 +68,9 @@
   // should Seek() back to the position where the stream was before this operation.
   virtual OutputStream* GetStream() = 0;
 
+  // Get the size that the loaded ELF file will occupy in memory.
+  virtual size_t GetLoadedSize() = 0;
+
  protected:
   ElfWriter() = default;
 };
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 1d71e57..19346ec 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -88,14 +88,12 @@
   ~ElfWriterQuick();
 
   void Start() OVERRIDE;
-  void PrepareDebugInfo(size_t rodata_section_size,
-                        size_t text_section_size,
-                        const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
+  void SetLoadedSectionSizes(size_t rodata_size, size_t text_size, size_t bss_size) OVERRIDE;
+  void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
   OutputStream* StartRoData() OVERRIDE;
   void EndRoData(OutputStream* rodata) OVERRIDE;
   OutputStream* StartText() OVERRIDE;
   void EndText(OutputStream* text) OVERRIDE;
-  void SetBssSize(size_t bss_size) OVERRIDE;
   void WriteDynamicSection() OVERRIDE;
   void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
   void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) OVERRIDE;
@@ -103,12 +101,17 @@
 
   virtual OutputStream* GetStream() OVERRIDE;
 
+  size_t GetLoadedSize() OVERRIDE;
+
   static void EncodeOatPatches(const std::vector<uintptr_t>& locations,
                                std::vector<uint8_t>* buffer);
 
  private:
   const CompilerOptions* const compiler_options_;
   File* const elf_file_;
+  size_t rodata_size_;
+  size_t text_size_;
+  size_t bss_size_;
   std::unique_ptr<BufferedOutputStream> output_stream_;
   std::unique_ptr<ElfBuilder<ElfTypes>> builder_;
   std::unique_ptr<DebugInfoTask> debug_info_task_;
@@ -134,6 +137,9 @@
     : ElfWriter(),
       compiler_options_(compiler_options),
       elf_file_(elf_file),
+      rodata_size_(0u),
+      text_size_(0u),
+      bss_size_(0u),
       output_stream_(MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(elf_file))),
       builder_(new ElfBuilder<ElfTypes>(instruction_set, output_stream_.get())) {}
 
@@ -146,6 +152,19 @@
 }
 
 template <typename ElfTypes>
+void ElfWriterQuick<ElfTypes>::SetLoadedSectionSizes(size_t rodata_size,
+                                                     size_t text_size,
+                                                     size_t bss_size) {
+  DCHECK_EQ(rodata_size_, 0u);
+  rodata_size_ = rodata_size;
+  DCHECK_EQ(text_size_, 0u);
+  text_size_ = text_size;
+  DCHECK_EQ(bss_size_, 0u);
+  bss_size_ = bss_size;
+  builder_->PrepareDynamicSection(elf_file_->GetPath(), rodata_size_, text_size_, bss_size_);
+}
+
+template <typename ElfTypes>
 OutputStream* ElfWriterQuick<ElfTypes>::StartRoData() {
   auto* rodata = builder_->GetRoData();
   rodata->Start();
@@ -172,31 +191,21 @@
 }
 
 template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::SetBssSize(size_t bss_size) {
-  auto* bss = builder_->GetBss();
-  if (bss_size != 0u) {
-    bss->WriteNoBitsSection(bss_size);
-  }
-}
-
-template <typename ElfTypes>
 void ElfWriterQuick<ElfTypes>::WriteDynamicSection() {
-  builder_->WriteDynamicSection(elf_file_->GetPath());
+  if (bss_size_ != 0u) {
+    builder_->GetBss()->WriteNoBitsSection(bss_size_);
+  }
+  builder_->WriteDynamicSection();
 }
 
 template <typename ElfTypes>
 void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(
-    size_t rodata_section_size,
-    size_t text_section_size,
     const ArrayRef<const debug::MethodDebugInfo>& method_infos) {
   if (!method_infos.empty() && compiler_options_->GetGenerateMiniDebugInfo()) {
     // Prepare the mini-debug-info in background while we do other I/O.
     Thread* self = Thread::Current();
     debug_info_task_ = std::unique_ptr<DebugInfoTask>(
-        new DebugInfoTask(builder_->GetIsa(),
-                          rodata_section_size,
-                          text_section_size,
-                          method_infos));
+        new DebugInfoTask(builder_->GetIsa(), rodata_size_, text_size_, method_infos));
     debug_info_thread_pool_ = std::unique_ptr<ThreadPool>(
         new ThreadPool("Mini-debug-info writer", 1));
     debug_info_thread_pool_->AddTask(self, debug_info_task_.get());
@@ -245,6 +254,11 @@
   return builder_->GetStream();
 }
 
+template <typename ElfTypes>
+size_t ElfWriterQuick<ElfTypes>::GetLoadedSize() {
+  return builder_->GetLoadedSize();
+}
+
 // Explicit instantiations
 template class ElfWriterQuick<ElfTypes32>;
 template class ElfWriterQuick<ElfTypes64>;
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 4920f9b..32f0a94 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -124,6 +124,10 @@
           &opened_dex_files);
       ASSERT_TRUE(dex_files_ok);
       oat_writer.PrepareLayout(compiler_driver_.get(), writer.get(), dex_files);
+      size_t rodata_size = oat_writer.GetOatHeader().GetExecutableOffset();
+      size_t text_size = oat_writer.GetSize() - rodata_size;
+      elf_writer->SetLoadedSectionSizes(rodata_size, text_size, oat_writer.GetBssSize());
+
       bool image_space_ok = writer->PrepareImageAddressSpace();
       ASSERT_TRUE(image_space_ok);
 
@@ -139,7 +143,6 @@
       bool header_ok = oat_writer.WriteHeader(elf_writer->GetStream(), 0u, 0u, 0u);
       ASSERT_TRUE(header_ok);
 
-      elf_writer->SetBssSize(oat_writer.GetBssSize());
       elf_writer->WriteDynamicSection();
       elf_writer->WriteDebugInfo(oat_writer.GetMethodDebugInfo());
       elf_writer->WritePatchLocations(oat_writer.GetAbsolutePatchLocations());
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 73574ba..09046c7 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -2274,25 +2274,18 @@
   return GetConstImageInfo(oat_filenames_[index]);
 }
 
-void ImageWriter::UpdateOatFile(File* oat_file, const char* oat_filename) {
-  DCHECK(oat_file != nullptr);
+void ImageWriter::UpdateOatFile(size_t index, size_t oat_loaded_size) {
   if (compile_app_image_) {
     CHECK_EQ(oat_filenames_.size(), 1u) << "App image should have no next image.";
     return;
   }
-  ImageInfo& cur_image_info = GetImageInfo(oat_filename);
 
   // Update the oat_offset of the next image info.
-  auto it = std::find(oat_filenames_.begin(), oat_filenames_.end(), oat_filename);
-  DCHECK(it != oat_filenames_.end());
-
-  it++;
-  if (it != oat_filenames_.end()) {
-    size_t oat_loaded_size = 0;
-    size_t oat_data_offset = 0;
-    ElfWriter::GetOatElfInformation(oat_file, &oat_loaded_size, &oat_data_offset);
+  DCHECK_LT(index, oat_filenames_.size());
+  if (index + 1u != oat_filenames_.size()) {
     // There is a following one.
-    ImageInfo& next_image_info = GetImageInfo(*it);
+    ImageInfo& cur_image_info = GetImageInfo(oat_filenames_[index]);
+    ImageInfo& next_image_info = GetImageInfo(oat_filenames_[index + 1u]);
     next_image_info.oat_offset_ = cur_image_info.oat_offset_ + oat_loaded_size;
   }
 }
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 9371d9f..a4a252e 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -123,7 +123,7 @@
 
   // Update the oat size for the given oat file. This will make the oat_offset for the next oat
   // file valid.
-  void UpdateOatFile(File* oat_file, const char* oat_filename);
+  void UpdateOatFile(size_t index, size_t oat_loaded_size);
 
  private:
   bool AllocMemory();
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 3fe7861..c2b29eb 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -172,7 +172,6 @@
       /* dump_passes */ false,
       cumulative_logger_.get(),
       /* swap_fd */ -1,
-      /* dex to oat map */ nullptr,
       /* profile_compilation_info */ nullptr));
   // Disable dedupe so we can remove compiled methods.
   compiler_driver_->SetDedupeEnabled(false);
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index bf8e786..8bff41c 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -44,10 +44,22 @@
       : compiler_options_(),
         verification_results_(&compiler_options_),
         inliner_map_(),
-        driver_(&compiler_options_, &verification_results_, &inliner_map_,
-                Compiler::kQuick, instruction_set, nullptr,
-                false, nullptr, nullptr, nullptr, 1u,
-                false, false, nullptr, -1, nullptr, nullptr),
+        driver_(&compiler_options_,
+                &verification_results_,
+                &inliner_map_,
+                Compiler::kQuick,
+                instruction_set,
+                /* instruction_set_features*/ nullptr,
+                /* boot_image */ false,
+                /* image_classes */ nullptr,
+                /* compiled_classes */ nullptr,
+                /* compiled_methods */ nullptr,
+                /* thread_count */ 1u,
+                /* dump_stats */ false,
+                /* dump_passes */ false,
+                /* timer */ nullptr,
+                /* swap_fd */ -1,
+                /* profile_compilation_info */ nullptr),
         error_msg_(),
         instruction_set_(instruction_set),
         features_(InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg_)),
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 894d29e..d03b4f1 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -111,17 +111,16 @@
                                               compiler_kind,
                                               insn_set,
                                               insn_features_.get(),
-                                              false,
-                                              nullptr,
-                                              nullptr,
-                                              nullptr,
-                                              2,
-                                              true,
-                                              true,
+                                              /* boot_image */ false,
+                                              /* image_classes */ nullptr,
+                                              /* compiled_classes */ nullptr,
+                                              /* compiled_methods */ nullptr,
+                                              /* thread_count */ 2,
+                                              /* dump_stats */ true,
+                                              /* dump_passes */ true,
                                               timer_.get(),
-                                              -1,
-                                              nullptr,
-                                              nullptr));
+                                              /* swap_fd */ -1,
+                                              /* profile_compilation_info */ nullptr));
   }
 
   bool WriteElf(File* file,
@@ -201,6 +200,10 @@
       class_linker->RegisterDexFile(*dex_file, runtime->GetLinearAlloc());
     }
     oat_writer.PrepareLayout(compiler_driver_.get(), nullptr, dex_files);
+    size_t rodata_size = oat_writer.GetOatHeader().GetExecutableOffset();
+    size_t text_size = oat_writer.GetSize() - rodata_size;
+    elf_writer->SetLoadedSectionSizes(rodata_size, text_size, oat_writer.GetBssSize());
+
     if (!oat_writer.WriteRodata(rodata)) {
       return false;
     }
@@ -216,7 +219,6 @@
       return false;
     }
 
-    elf_writer->SetBssSize(oat_writer.GetBssSize());
     elf_writer->WriteDynamicSection();
     elf_writer->WriteDebugInfo(oat_writer.GetMethodDebugInfo());
     elf_writer->WritePatchLocations(oat_writer.GetAbsolutePatchLocations());
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 541fb5a..7829268 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1557,13 +1557,12 @@
                                      IsBootImage(),
                                      image_classes_.release(),
                                      compiled_classes_.release(),
-                                     nullptr,
+                                     /* compiled_methods */ nullptr,
                                      thread_count_,
                                      dump_stats_,
                                      dump_passes_,
                                      compiler_phases_timings_.get(),
                                      swap_fd_,
-                                     &dex_file_oat_filename_map_,
                                      profile_compilation_info_.get()));
     driver_->SetDexFilesForOatFile(dex_files_);
     driver_->CompileAll(class_loader_, dex_files_, timings_);
@@ -1680,18 +1679,33 @@
     {
       TimingLogger::ScopedTiming t2("dex2oat Write ELF", timings_);
       for (size_t i = 0, size = oat_files_.size(); i != size; ++i) {
-        std::unique_ptr<File>& oat_file = oat_files_[i];
         std::unique_ptr<ElfWriter>& elf_writer = elf_writers_[i];
         std::unique_ptr<OatWriter>& oat_writer = oat_writers_[i];
 
         std::vector<const DexFile*>& dex_files = dex_files_per_oat_file_[i];
         oat_writer->PrepareLayout(driver_.get(), image_writer_.get(), dex_files);
 
-        // We need to mirror the layout of the ELF file in the compressed debug-info.
-        // Therefore we need to propagate the sizes of at least those sections.
         size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset();
         size_t text_size = oat_writer->GetSize() - rodata_size;
-        elf_writer->PrepareDebugInfo(rodata_size, text_size, oat_writer->GetMethodDebugInfo());
+        elf_writer->SetLoadedSectionSizes(rodata_size, text_size, oat_writer->GetBssSize());
+
+        if (IsImage()) {
+          // Update oat estimates.
+          DCHECK(image_writer_ != nullptr);
+          DCHECK_LT(i, oat_filenames_.size());
+
+          image_writer_->UpdateOatFile(i, elf_writer->GetLoadedSize());
+        }
+      }
+
+      for (size_t i = 0, size = oat_files_.size(); i != size; ++i) {
+        std::unique_ptr<File>& oat_file = oat_files_[i];
+        std::unique_ptr<ElfWriter>& elf_writer = elf_writers_[i];
+        std::unique_ptr<OatWriter>& oat_writer = oat_writers_[i];
+
+        // We need to mirror the layout of the ELF file in the compressed debug-info.
+        // Therefore we need to propagate the sizes of at least those sections.
+        elf_writer->PrepareDebugInfo(oat_writer->GetMethodDebugInfo());
 
         OutputStream*& rodata = rodata_[i];
         DCHECK(rodata != nullptr);
@@ -1717,7 +1731,6 @@
           return false;
         }
 
-        elf_writer->SetBssSize(oat_writer->GetBssSize());
         elf_writer->WriteDynamicSection();
         elf_writer->WriteDebugInfo(oat_writer->GetMethodDebugInfo());
         elf_writer->WritePatchLocations(oat_writer->GetAbsolutePatchLocations());
@@ -1731,19 +1744,10 @@
         if (oat_files_[i] != nullptr) {
           if (oat_files_[i]->Flush() != 0) {
             PLOG(ERROR) << "Failed to flush oat file: " << oat_filenames_[i];
-            oat_files_[i]->Erase();
             return false;
           }
         }
 
-        if (IsImage()) {
-          // Update oat estimates.
-          DCHECK(image_writer_ != nullptr);
-          DCHECK_LT(i, oat_filenames_.size());
-
-          image_writer_->UpdateOatFile(oat_file.get(), oat_filenames_[i]);
-        }
-
         VLOG(compiler) << "Oat file written successfully: " << oat_filenames_[i];
 
         oat_writer.reset();
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index af08fc4..e30b968 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -145,7 +145,9 @@
       bss->WriteNoBitsSection(oat_file_->BssSize());
     }
 
-    builder_->WriteDynamicSection(elf_file->GetPath());
+    builder_->PrepareDynamicSection(
+        elf_file->GetPath(), rodata_size, text_size, oat_file_->BssSize());
+    builder_->WriteDynamicSection();
 
     Walk(&art::OatSymbolizer::RegisterForDedup);