Add support for .bss section in oat files.

Change-Id: I779b80b8139d9afdc28373f8c68edff5df7726ce
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index e8354b2..09be437 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -253,6 +253,7 @@
                                                 (size_t)100 * 1024 * 1024,  // 100MB
                                                 PROT_NONE,
                                                 false /* no need for 4gb flag with fixed mmap*/,
+                                                false /* not reusing existing reservation */,
                                                 &error_msg));
   CHECK(image_reservation_.get() != nullptr) << error_msg;
 }
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 94268de..9ab3602 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -538,6 +538,8 @@
              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),
@@ -547,6 +549,7 @@
       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),
@@ -569,6 +572,11 @@
   }
 
   bool Init() {
+    // 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
+    // .dynamic section and needs its own program header with LOAD RW.
+    //
     // The basic layout of the elf file. Order may be different in final output.
     // +-------------------------+
     // | Elf_Ehdr                |
@@ -576,6 +584,7 @@
     // | Elf_Phdr PHDR           |
     // | Elf_Phdr LOAD R         | .dynsym .dynstr .hash .rodata
     // | Elf_Phdr LOAD R X       | .text
+    // | Elf_Phdr LOAD RW        | .bss (Optional)
     // | Elf_Phdr LOAD RW        | .dynamic
     // | Elf_Phdr DYNAMIC        | .dynamic
     // +-------------------------+
@@ -584,6 +593,8 @@
     // | Elf_Sym  oatdata        |
     // | Elf_Sym  oatexec        |
     // | Elf_Sym  oatlastword    |
+    // | Elf_Sym  oatbss         | (Optional)
+    // | Elf_Sym  oatbsslastword | (Optional)
     // +-------------------------+
     // | .dynstr                 |
     // | \0                      |
@@ -631,6 +642,7 @@
     // | .hash\0                 |
     // | .rodata\0               |
     // | .text\0                 |
+    // | .bss\0                  |  (Optional)
     // | .shstrtab\0             |
     // | .symtab\0               |  (Optional)
     // | .strtab\0               |  (Optional)
@@ -654,8 +666,9 @@
     // | Elf_Shdr .dynsym        |
     // | Elf_Shdr .dynstr        |
     // | Elf_Shdr .hash          |
-    // | Elf_Shdr .text          |
     // | Elf_Shdr .rodata        |
+    // | Elf_Shdr .text          |
+    // | Elf_Shdr .bss           |  (Optional)
     // | Elf_Shdr .dynamic       |
     // | Elf_Shdr .shstrtab      |
     // | Elf_Shdr .debug_info    |  (Optional)
@@ -694,8 +707,11 @@
     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_].p_type    = PT_LOAD;
-    program_headers_[PH_LOAD_RW_].p_flags   = PF_R | PF_W;
+    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;
@@ -760,6 +776,14 @@
     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_++;
+    }
+
     // Setup .dynamic
     section_ptrs_.push_back(dynamic_builder_.GetSection());
     AssignSectionStr(&dynamic_builder_, &shstrtab_);
@@ -820,10 +844,20 @@
     CHECK_ALIGNED(rodata_builder_.GetSection()->sh_offset +
                   rodata_builder_.GetSection()->sh_size, kPageSize);
 
+    // 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.
-    dynamic_builder_.GetSection()->sh_offset =
-        NextOffset<Elf_Word, Elf_Shdr>(*dynamic_builder_.GetSection(), *text_builder_.GetSection());
-    dynamic_builder_.GetSection()->sh_addr = dynamic_builder_.GetSection()->sh_offset;
+    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();
 
@@ -987,16 +1021,23 @@
     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_].p_offset = dynamic_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_RW_].p_vaddr  = dynamic_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_RW_].p_paddr  = dynamic_builder_.GetSection()->sh_offset;
-    program_headers_[PH_LOAD_RW_].p_filesz = dynamic_builder_.GetSection()->sh_size;
-    program_headers_[PH_LOAD_RW_].p_memsz  = dynamic_builder_.GetSection()->sh_size;
-    program_headers_[PH_LOAD_RW_].p_align  = dynamic_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_offset;
-    program_headers_[PH_DYNAMIC].p_paddr  = 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;
@@ -1004,15 +1045,29 @@
     // Finish setup of the Ehdr values.
     elf_header_.e_phoff = PHDR_OFFSET;
     elf_header_.e_shoff = sections_offset;
-    elf_header_.e_phnum = PH_NUM;
+    elf_header_.e_phnum = (bss_builder_.GetSection()->sh_size != 0u) ? PH_NUM : PH_NUM - 1;
     elf_header_.e_shnum = section_ptrs_.size();
     elf_header_.e_shstrndx = shstrtab_builder_.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_)));
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Program headers", PHDR_OFFSET,
-                                                      &program_headers_, sizeof(program_headers_)));
+    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 = (PH_NUM - PH_LOAD_RW_BSS - 1) * 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(),
@@ -1175,6 +1230,12 @@
                               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 AssignSectionStr(ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* builder,
@@ -1213,12 +1274,13 @@
   // 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_ = 3,
-        PH_DYNAMIC  = 4,
-        PH_NUM      = 5,
+    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_NUM              = 6,
   };
   static const uint32_t PHDR_SIZE = sizeof(Elf_Phdr) * PH_NUM;
   Elf_Phdr program_headers_[PH_NUM];
@@ -1236,6 +1298,7 @@
 
   ElfOatSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> text_builder_;
   ElfOatSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> rodata_builder_;
+  ElfOatSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> bss_builder_;
   ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr> dynsym_builder_;
   ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr> symtab_builder_;
   ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> hash_builder_;
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 401d5a9..a822b24 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -229,6 +229,7 @@
   const OatHeader& oat_header = oat_writer->GetOatHeader();
   Elf_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();
 
   OatWriterWrapper wrapper(oat_writer);
 
@@ -243,6 +244,8 @@
           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));
 
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index c588e1a..f5f9320 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -408,8 +408,8 @@
 bool ImageWriter::AllocMemory() {
   size_t length = RoundUp(Runtime::Current()->GetHeap()->GetTotalMemory(), kPageSize);
   std::string error_msg;
-  image_.reset(MemMap::MapAnonymous("image writer image", NULL, length, PROT_READ | PROT_WRITE,
-                                    false, &error_msg));
+  image_.reset(MemMap::MapAnonymous("image writer image", nullptr, length, PROT_READ | PROT_WRITE,
+                                    false, false, &error_msg));
   if (UNLIKELY(image_.get() == nullptr)) {
     LOG(ERROR) << "Failed to allocate memory for image file generation: " << error_msg;
     return false;
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 8411091..c32a992 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -403,6 +403,7 @@
     image_writer_(image_writer),
     dex_files_(&dex_files),
     size_(0u),
+    bss_size_(0u),
     oat_data_offset_(0u),
     image_file_location_oat_checksum_(image_file_location_oat_checksum),
     image_file_location_oat_begin_(image_file_location_oat_begin),
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 980611f..fd2ccae 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -96,6 +96,10 @@
     return size_;
   }
 
+  size_t GetBssSize() const {
+    return bss_size_;
+  }
+
   const std::vector<uintptr_t>& GetAbsolutePatchLocations() const {
     return absolute_patch_locations_;
   }
@@ -266,6 +270,9 @@
   // Size required for Oat data structures.
   size_t size_;
 
+  // The size of the required .bss section holding the DexCache data.
+  size_t bss_size_;
+
   // Offset of the oat data from the start of the mmapped region of the elf file.
   size_t oat_data_offset_;