From 5c42c29b89286e5efa4a4613132b09051ce5945b Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Wed, 25 Feb 2015 12:02:49 +0000 Subject: [PATCH] Add support for .bss section in oat files. Change-Id: I779b80b8139d9afdc28373f8c68edff5df7726ce --- compiler/common_compiler_test.cc | 1 + compiler/elf_builder.h | 109 ++++++++++++++++++++------ compiler/elf_writer_quick.cc | 3 + compiler/image_writer.cc | 4 +- compiler/oat_writer.cc | 1 + compiler/oat_writer.h | 7 ++ oatdump/oatdump.cc | 3 + runtime/base/arena_allocator.cc | 2 +- runtime/elf_file.cc | 80 ++++++++++++++----- runtime/gc/accounting/atomic_stack.h | 4 +- runtime/gc/accounting/bitmap.cc | 3 +- runtime/gc/accounting/card_table.cc | 2 +- runtime/gc/accounting/read_barrier_table.h | 2 +- runtime/gc/accounting/space_bitmap.cc | 3 +- runtime/gc/allocator/rosalloc.cc | 5 +- runtime/gc/collector/mark_sweep.cc | 2 +- runtime/gc/heap.cc | 5 +- runtime/gc/space/bump_pointer_space.cc | 3 +- runtime/gc/space/large_object_space.cc | 13 ++-- runtime/gc/space/malloc_space.cc | 2 +- runtime/gc/space/region_space.cc | 3 +- runtime/indirect_reference_table.cc | 2 +- runtime/jit/jit_code_cache.cc | 2 +- runtime/mem_map.cc | 22 ++++-- runtime/mem_map.h | 3 +- runtime/mem_map_test.cc | 121 +++++++++++++++++++---------- runtime/oat_file.cc | 90 +++++++-------------- runtime/oat_file.h | 24 +++--- runtime/thread_pool.cc | 2 +- runtime/zip_archive.cc | 3 +- 30 files changed, 334 insertions(+), 192 deletions(-) diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index e8354b2a1..09be4372a 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -253,6 +253,7 @@ void CommonCompilerTest::ReserveImageSpace() { (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 94268de07..9ab360260 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -538,6 +538,8 @@ class ElfBuilder FINAL { 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 @@ class ElfBuilder FINAL { 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 @@ class ElfBuilder FINAL { } 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 @@ class ElfBuilder FINAL { // | 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 @@ class ElfBuilder FINAL { // | Elf_Sym oatdata | // | Elf_Sym oatexec | // | Elf_Sym oatlastword | + // | Elf_Sym oatbss | (Optional) + // | Elf_Sym oatbsslastword | (Optional) // +-------------------------+ // | .dynstr | // | \0 | @@ -631,6 +642,7 @@ class ElfBuilder FINAL { // | .hash\0 | // | .rodata\0 | // | .text\0 | + // | .bss\0 | (Optional) // | .shstrtab\0 | // | .symtab\0 | (Optional) // | .strtab\0 | (Optional) @@ -654,8 +666,9 @@ class ElfBuilder FINAL { // | 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 @@ class ElfBuilder FINAL { 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 @@ class ElfBuilder FINAL { 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 @@ class ElfBuilder FINAL { 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(*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(*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(*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 @@ class ElfBuilder FINAL { 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 @@ class ElfBuilder FINAL { // 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 Header", 0, &elf_header_, sizeof(elf_header_))); - pieces.push_back(new ElfFileMemoryPiece("Program headers", PHDR_OFFSET, - &program_headers_, sizeof(program_headers_))); + if (bss_builder_.GetSection()->sh_size != 0u) { + pieces.push_back(new ElfFileMemoryPiece("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("Program headers", PHDR_OFFSET, + &program_headers_[0], part1_size)); + pieces.push_back(new ElfFileMemoryPiece("Program headers part 2", + PHDR_OFFSET + part1_size, + &program_headers_[PH_LOAD_RW_BSS + 1], + part2_size)); + } pieces.push_back(new ElfFileMemoryPiece(".dynamic", dynamic_builder_.GetSection()->sh_offset, dynamic.data(), @@ -1175,6 +1230,12 @@ class ElfBuilder FINAL { 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* builder, @@ -1213,12 +1274,13 @@ class ElfBuilder FINAL { // 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 @@ class ElfBuilder FINAL { ElfOatSectionBuilder text_builder_; ElfOatSectionBuilder rodata_builder_; + ElfOatSectionBuilder bss_builder_; ElfSymtabBuilder dynsym_builder_; ElfSymtabBuilder symtab_builder_; ElfSectionBuilder hash_builder_; diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 401d5a951..a822b24cd 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -229,6 +229,7 @@ bool ElfWriterQuickGetOatHeader(); 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 @@ bool ElfWriterQuickGetCompilerOptions().GetIncludeDebugSymbols(), debug)); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index c588e1a53..f5f932053 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -408,8 +408,8 @@ ImageWriter::BinSlot ImageWriter::GetImageBinSlot(mirror::Object* object) const 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 841109105..c32a99226 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -403,6 +403,7 @@ OatWriter::OatWriter(const std::vector& dex_files, 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 980611fe9..fd2ccae4a 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -96,6 +96,10 @@ class OatWriter { return size_; } + size_t GetBssSize() const { + return bss_size_; + } + const std::vector& GetAbsolutePatchLocations() const { return absolute_patch_locations_; } @@ -266,6 +270,9 @@ class OatWriter { // 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_; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 3ce86d872..aab4f8bc0 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -88,6 +88,7 @@ class OatSymbolizer FINAL : public CodeOutput { uint32_t diff = static_cast(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()); @@ -100,6 +101,8 @@ class OatSymbolizer FINAL : public CodeOutput { oat_data_size, oat_data_size, oat_exec_size, + RoundUp(oat_data_size + oat_exec_size, kPageSize), + oat_bss_size, true, false)); diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc index b3f812e5e..e6380bfe5 100644 --- a/runtime/base/arena_allocator.cc +++ b/runtime/base/arena_allocator.cc @@ -129,7 +129,7 @@ Arena::Arena(size_t size) next_(nullptr) { if (kUseMemMap) { std::string error_msg; - map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE, false, + map_ = MemMap::MapAnonymous("dalvik-arena", nullptr, size, PROT_READ | PROT_WRITE, false, false, &error_msg); CHECK(map_ != nullptr) << error_msg; memory_ = map_->Begin(); diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index a22e2741c..3490bcf86 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -1370,7 +1370,7 @@ bool ElfFileImplGetPath(); std::unique_ptr reserve(MemMap::MapAnonymous(reservation_name.c_str(), reserve_base_override, - GetLoadedSize(), PROT_NONE, false, + GetLoadedSize(), PROT_NONE, false, false, error_msg)); if (reserve.get() == nullptr) { *error_msg = StringPrintf("Failed to allocate %s: %s", @@ -1411,32 +1411,72 @@ bool ElfFileImplp_offset + program_header->p_memsz)) { - *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment " - "%d of %" PRIu64 " bytes: '%s'", file_length, i, - static_cast(program_header->p_offset + program_header->p_memsz), + if (program_header->p_filesz > program_header->p_memsz) { + *error_msg = StringPrintf("Invalid p_filesz > p_memsz (%" PRIu64 " > %" PRIu64 "): %s", + static_cast(program_header->p_filesz), + static_cast(program_header->p_memsz), file_->GetPath().c_str()); return false; } - std::unique_ptr segment(MemMap::MapFileAtAddress(p_vaddr, - program_header->p_memsz, - prot, flags, file_->Fd(), - program_header->p_offset, - true, // implies MAP_FIXED - file_->GetPath().c_str(), - error_msg)); - if (segment.get() == nullptr) { - *error_msg = StringPrintf("Failed to map ELF file segment %d from %s: %s", - i, file_->GetPath().c_str(), error_msg->c_str()); + if (program_header->p_filesz < program_header->p_memsz && + !IsAligned(program_header->p_filesz)) { + *error_msg = StringPrintf("Unsupported unaligned p_filesz < p_memsz (%" PRIu64 + " < %" PRIu64 "): %s", + static_cast(program_header->p_filesz), + static_cast(program_header->p_memsz), + file_->GetPath().c_str()); return false; } - if (segment->Begin() != p_vaddr) { - *error_msg = StringPrintf("Failed to map ELF file segment %d from %s at expected address %p, " - "instead mapped to %p", - i, file_->GetPath().c_str(), p_vaddr, segment->Begin()); + if (file_length < (program_header->p_offset + program_header->p_filesz)) { + *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment " + "%d of %" PRIu64 " bytes: '%s'", file_length, i, + static_cast(program_header->p_offset + program_header->p_filesz), + file_->GetPath().c_str()); return false; } - segments_.push_back(segment.release()); + if (program_header->p_filesz != 0u) { + std::unique_ptr segment( + MemMap::MapFileAtAddress(p_vaddr, + program_header->p_filesz, + prot, flags, file_->Fd(), + program_header->p_offset, + true, // implies MAP_FIXED + file_->GetPath().c_str(), + error_msg)); + if (segment.get() == nullptr) { + *error_msg = StringPrintf("Failed to map ELF file segment %d from %s: %s", + i, file_->GetPath().c_str(), error_msg->c_str()); + return false; + } + if (segment->Begin() != p_vaddr) { + *error_msg = StringPrintf("Failed to map ELF file segment %d from %s at expected address %p, " + "instead mapped to %p", + i, file_->GetPath().c_str(), p_vaddr, segment->Begin()); + return false; + } + segments_.push_back(segment.release()); + } + if (program_header->p_filesz < program_header->p_memsz) { + std::string name = StringPrintf("Zero-initialized segment %" PRIu64 " of ELF file %s", + static_cast(i), file_->GetPath().c_str()); + std::unique_ptr segment( + MemMap::MapAnonymous(name.c_str(), + p_vaddr + program_header->p_filesz, + program_header->p_memsz - program_header->p_filesz, + prot, false, true /* reuse */, error_msg)); + if (segment == nullptr) { + *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s: %s", + i, file_->GetPath().c_str(), error_msg->c_str()); + return false; + } + if (segment->Begin() != p_vaddr) { + *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s " + "at expected address %p, instead mapped to %p", + i, file_->GetPath().c_str(), p_vaddr, segment->Begin()); + return false; + } + segments_.push_back(segment.release()); + } } // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index 72734e95a..5224d64ef 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -236,8 +236,8 @@ class AtomicStack { // Size in number of elements. void Init() { std::string error_msg; - mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(begin_[0]), - PROT_READ | PROT_WRITE, false, &error_msg)); + mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), nullptr, capacity_ * sizeof(begin_[0]), + PROT_READ | PROT_WRITE, false, false, &error_msg)); CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack.\n" << error_msg; uint8_t* addr = mem_map_->Begin(); CHECK(addr != NULL); diff --git a/runtime/gc/accounting/bitmap.cc b/runtime/gc/accounting/bitmap.cc index de47f6094..20984fda9 100644 --- a/runtime/gc/accounting/bitmap.cc +++ b/runtime/gc/accounting/bitmap.cc @@ -40,7 +40,8 @@ MemMap* Bitmap::AllocateMemMap(const std::string& name, size_t num_bits) { RoundUp(num_bits, kBitsPerBitmapWord) / kBitsPerBitmapWord * sizeof(uintptr_t), kPageSize); std::string error_msg; std::unique_ptr mem_map(MemMap::MapAnonymous(name.c_str(), nullptr, bitmap_size, - PROT_READ | PROT_WRITE, false, &error_msg)); + PROT_READ | PROT_WRITE, false, false, + &error_msg)); if (UNLIKELY(mem_map.get() == nullptr)) { LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg; return nullptr; diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index ca1e7c131..ad1f192dd 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -62,7 +62,7 @@ CardTable* CardTable::Create(const uint8_t* heap_begin, size_t heap_capacity) { std::string error_msg; std::unique_ptr mem_map( MemMap::MapAnonymous("card table", nullptr, capacity + 256, PROT_READ | PROT_WRITE, - false, &error_msg)); + false, false, &error_msg)); CHECK(mem_map.get() != NULL) << "couldn't allocate card table: " << error_msg; // All zeros is the correct initial value; all clean. Anonymous mmaps are initialized to zero, we // don't clear the card table to avoid unnecessary pages being allocated diff --git a/runtime/gc/accounting/read_barrier_table.h b/runtime/gc/accounting/read_barrier_table.h index 84d5da3ba..bb9aae788 100644 --- a/runtime/gc/accounting/read_barrier_table.h +++ b/runtime/gc/accounting/read_barrier_table.h @@ -37,7 +37,7 @@ class ReadBarrierTable { static_cast(static_cast(kHeapCapacity / kRegionSize))); std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous("read barrier table", nullptr, capacity, - PROT_READ | PROT_WRITE, false, &error_msg); + PROT_READ | PROT_WRITE, false, false, &error_msg); CHECK(mem_map != nullptr && mem_map->Begin() != nullptr) << "couldn't allocate read barrier table: " << error_msg; mem_map_.reset(mem_map); diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc index f5d3b47d4..ad8d9884e 100644 --- a/runtime/gc/accounting/space_bitmap.cc +++ b/runtime/gc/accounting/space_bitmap.cc @@ -63,7 +63,8 @@ SpaceBitmap* SpaceBitmap::Create( const size_t bitmap_size = ComputeBitmapSize(heap_capacity); std::string error_msg; std::unique_ptr mem_map(MemMap::MapAnonymous(name.c_str(), nullptr, bitmap_size, - PROT_READ | PROT_WRITE, false, &error_msg)); + PROT_READ | PROT_WRITE, false, false, + &error_msg)); if (UNLIKELY(mem_map.get() == nullptr)) { LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg; return nullptr; diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc index 72aacf515..f51093aa5 100644 --- a/runtime/gc/allocator/rosalloc.cc +++ b/runtime/gc/allocator/rosalloc.cc @@ -80,8 +80,9 @@ RosAlloc::RosAlloc(void* base, size_t capacity, size_t max_capacity, size_t num_of_pages = footprint_ / kPageSize; size_t max_num_of_pages = max_capacity_ / kPageSize; std::string error_msg; - page_map_mem_map_.reset(MemMap::MapAnonymous("rosalloc page map", NULL, RoundUp(max_num_of_pages, kPageSize), - PROT_READ | PROT_WRITE, false, &error_msg)); + page_map_mem_map_.reset(MemMap::MapAnonymous("rosalloc page map", nullptr, + RoundUp(max_num_of_pages, kPageSize), + PROT_READ | PROT_WRITE, false, false, &error_msg)); CHECK(page_map_mem_map_.get() != nullptr) << "Couldn't allocate the page map : " << error_msg; page_map_ = page_map_mem_map_->Begin(); page_map_size_ = num_of_pages; diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index cd63d2646..8aac484f7 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -106,7 +106,7 @@ MarkSweep::MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_pre MemMap* mem_map = MemMap::MapAnonymous( "mark sweep sweep array free buffer", nullptr, RoundUp(kSweepArrayChunkFreeSize * sizeof(mirror::Object*), kPageSize), - PROT_READ | PROT_WRITE, false, &error_msg); + PROT_READ | PROT_WRITE, false, false, &error_msg); CHECK(mem_map != nullptr) << "Couldn't allocate sweep array free buffer: " << error_msg; sweep_array_free_buffer_mem_map_.reset(mem_map); } diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index a4bc941a6..9343622fd 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -284,7 +284,8 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max // address. non_moving_space_mem_map.reset( MemMap::MapAnonymous(space_name, requested_alloc_space_begin, - non_moving_space_capacity, PROT_READ | PROT_WRITE, true, &error_str)); + non_moving_space_capacity, PROT_READ | PROT_WRITE, true, false, + &error_str)); CHECK(non_moving_space_mem_map != nullptr) << error_str; // Try to reserve virtual memory at a lower address if we have a separate non moving space. request_begin = reinterpret_cast(300 * MB); @@ -476,7 +477,7 @@ MemMap* Heap::MapAnonymousPreferredAddress(const char* name, uint8_t* request_be size_t capacity, std::string* out_error_str) { while (true) { MemMap* map = MemMap::MapAnonymous(name, request_begin, capacity, - PROT_READ | PROT_WRITE, true, out_error_str); + PROT_READ | PROT_WRITE, true, false, out_error_str); if (map != nullptr || request_begin == nullptr) { return map; } diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc index 9675ba6f5..fbfc4495e 100644 --- a/runtime/gc/space/bump_pointer_space.cc +++ b/runtime/gc/space/bump_pointer_space.cc @@ -29,7 +29,8 @@ BumpPointerSpace* BumpPointerSpace::Create(const std::string& name, size_t capac capacity = RoundUp(capacity, kPageSize); std::string error_msg; std::unique_ptr mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity, - PROT_READ | PROT_WRITE, true, &error_msg)); + PROT_READ | PROT_WRITE, true, false, + &error_msg)); if (mem_map.get() == nullptr) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " << PrettySize(capacity) << " with message " << error_msg; diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc index c0c644430..7523de58b 100644 --- a/runtime/gc/space/large_object_space.cc +++ b/runtime/gc/space/large_object_space.cc @@ -110,8 +110,8 @@ LargeObjectMapSpace* LargeObjectMapSpace::Create(const std::string& name) { mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated, size_t* usable_size) { std::string error_msg; - MemMap* mem_map = MemMap::MapAnonymous("large object space allocation", NULL, num_bytes, - PROT_READ | PROT_WRITE, true, &error_msg); + MemMap* mem_map = MemMap::MapAnonymous("large object space allocation", nullptr, num_bytes, + PROT_READ | PROT_WRITE, true, false, &error_msg); if (UNLIKELY(mem_map == NULL)) { LOG(WARNING) << "Large object allocation failed: " << error_msg; return NULL; @@ -291,7 +291,7 @@ FreeListSpace* FreeListSpace::Create(const std::string& name, uint8_t* requested CHECK_EQ(size % kAlignment, 0U); std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, size, - PROT_READ | PROT_WRITE, true, &error_msg); + PROT_READ | PROT_WRITE, true, false, &error_msg); CHECK(mem_map != NULL) << "Failed to allocate large object space mem map: " << error_msg; return new FreeListSpace(name, mem_map, mem_map->Begin(), mem_map->End()); } @@ -305,9 +305,10 @@ FreeListSpace::FreeListSpace(const std::string& name, MemMap* mem_map, uint8_t* CHECK_ALIGNED(space_capacity, kAlignment); const size_t alloc_info_size = sizeof(AllocationInfo) * (space_capacity / kAlignment); std::string error_msg; - allocation_info_map_.reset(MemMap::MapAnonymous("large object free list space allocation info map", - nullptr, alloc_info_size, PROT_READ | PROT_WRITE, - false, &error_msg)); + allocation_info_map_.reset( + MemMap::MapAnonymous("large object free list space allocation info map", + nullptr, alloc_info_size, PROT_READ | PROT_WRITE, + false, false, &error_msg)); CHECK(allocation_info_map_.get() != nullptr) << "Failed to allocate allocation info map" << error_msg; allocation_info_ = reinterpret_cast(allocation_info_map_->Begin()); diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc index 9bbbb3cbd..67e8847ac 100644 --- a/runtime/gc/space/malloc_space.cc +++ b/runtime/gc/space/malloc_space.cc @@ -90,7 +90,7 @@ MemMap* MallocSpace::CreateMemMap(const std::string& name, size_t starting_size, std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, *capacity, - PROT_READ | PROT_WRITE, true, &error_msg); + PROT_READ | PROT_WRITE, true, false, &error_msg); if (mem_map == nullptr) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " << PrettySize(*capacity) << ": " << error_msg; diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc index 2c556d9ff..8bb73d614 100644 --- a/runtime/gc/space/region_space.cc +++ b/runtime/gc/space/region_space.cc @@ -33,7 +33,8 @@ RegionSpace* RegionSpace::Create(const std::string& name, size_t capacity, capacity = RoundUp(capacity, kRegionSize); std::string error_msg; std::unique_ptr mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity, - PROT_READ | PROT_WRITE, true, &error_msg)); + PROT_READ | PROT_WRITE, true, false, + &error_msg)); if (mem_map.get() == nullptr) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " << PrettySize(capacity) << " with message " << error_msg; diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc index aa2a6b58f..1a3f1074e 100644 --- a/runtime/indirect_reference_table.cc +++ b/runtime/indirect_reference_table.cc @@ -74,7 +74,7 @@ IndirectReferenceTable::IndirectReferenceTable(size_t initialCount, std::string error_str; const size_t table_bytes = maxCount * sizeof(IrtEntry); table_mem_map_.reset(MemMap::MapAnonymous("indirect ref table", nullptr, table_bytes, - PROT_READ | PROT_WRITE, false, &error_str)); + PROT_READ | PROT_WRITE, false, false, &error_str)); CHECK(table_mem_map_.get() != nullptr) << error_str; CHECK_EQ(table_mem_map_->Size(), table_bytes); table_ = reinterpret_cast(table_mem_map_->Begin()); diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 8d4965e70..4ae4d570f 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -31,7 +31,7 @@ JitCodeCache* JitCodeCache::Create(size_t capacity, std::string* error_msg) { std::string error_str; // Map name specific for android_os_Debug.cpp accounting. MemMap* map = MemMap::MapAnonymous("jit-code-cache", nullptr, capacity, - PROT_READ | PROT_WRITE | PROT_EXEC, false, &error_str); + PROT_READ | PROT_WRITE | PROT_EXEC, false, false, &error_str); if (map == nullptr) { std::ostringstream oss; oss << "Failed to create read write execute cache: " << error_str << " size=" << capacity; diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index 4b85469fd..588615f9d 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -138,9 +138,10 @@ uintptr_t MemMap::next_mem_pos_ = GenerateNextMemPos(); #endif // Return true if the address range is contained in a single /proc/self/map entry. -static bool ContainedWithinExistingMap(uintptr_t begin, - uintptr_t end, +static bool ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* error_msg) { + uintptr_t begin = reinterpret_cast(ptr); + uintptr_t end = begin + size; std::unique_ptr map(BacktraceMap::Create(getpid(), true)); if (map.get() == nullptr) { *error_msg = StringPrintf("Failed to build process map"); @@ -240,7 +241,7 @@ static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte } MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byte_count, int prot, - bool low_4gb, std::string* error_msg) { + bool low_4gb, bool reuse, std::string* error_msg) { #ifndef __LP64__ UNUSED(low_4gb); #endif @@ -250,6 +251,15 @@ MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byt size_t page_aligned_byte_count = RoundUp(byte_count, kPageSize); int flags = MAP_PRIVATE | MAP_ANONYMOUS; + if (reuse) { + // reuse means it is okay that it overlaps an existing page mapping. + // Only use this if you actually made the page reservation yourself. + CHECK(expected_ptr != nullptr); + + DCHECK(ContainedWithinExistingMap(expected_ptr, byte_count, error_msg)) << error_msg; + flags |= MAP_FIXED; + } + ScopedFd fd(-1); #ifdef USE_ASHMEM @@ -273,7 +283,7 @@ MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byt *error_msg = StringPrintf("ashmem_create_region failed for '%s': %s", name, strerror(errno)); return nullptr; } - flags = MAP_PRIVATE; + flags &= ~MAP_ANONYMOUS; } #endif @@ -393,8 +403,6 @@ MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, size_t byte_count, int p std::string* error_msg) { CHECK_NE(0, prot); CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE)); - uintptr_t expected = reinterpret_cast(expected_ptr); - uintptr_t limit = expected + byte_count; // Note that we do not allow MAP_FIXED unless reuse == true, i.e we // expect his mapping to be contained within an existing map. @@ -403,7 +411,7 @@ MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, size_t byte_count, int p // Only use this if you actually made the page reservation yourself. CHECK(expected_ptr != nullptr); - DCHECK(ContainedWithinExistingMap(expected, limit, error_msg)); + DCHECK(ContainedWithinExistingMap(expected_ptr, byte_count, error_msg)) << error_msg; flags |= MAP_FIXED; } else { CHECK_EQ(0, flags & MAP_FIXED); diff --git a/runtime/mem_map.h b/runtime/mem_map.h index dc337e056..11b2569c3 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -54,6 +54,7 @@ class MemMap { public: // Request an anonymous region of length 'byte_count' and a requested base address. // Use NULL as the requested base address if you don't care. + // "reuse" allows re-mapping an address range from an existing mapping. // // The word "anonymous" in this context means "not backed by a file". The supplied // 'ashmem_name' will be used -- on systems that support it -- to give the mapping @@ -61,7 +62,7 @@ class MemMap { // // On success, returns returns a MemMap instance. On failure, returns a NULL; static MemMap* MapAnonymous(const char* ashmem_name, uint8_t* addr, size_t byte_count, int prot, - bool low_4gb, std::string* error_msg); + bool low_4gb, bool reuse, std::string* error_msg); // Map part of a file, taking care of non-page aligned offsets. The // "start" offset is absolute, not relative. diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc index 14a72b9b1..f635b5d62 100644 --- a/runtime/mem_map_test.cc +++ b/runtime/mem_map_test.cc @@ -43,6 +43,7 @@ class MemMapTest : public testing::Test { 2 * page_size, PROT_READ | PROT_WRITE, low_4gb, + false, &error_msg); // Check its state and write to it. uint8_t* base0 = m0->Begin(); @@ -129,11 +130,12 @@ TEST_F(MemMapTest, MapAnonymousEmpty) { CommonInit(); std::string error_msg; std::unique_ptr map(MemMap::MapAnonymous("MapAnonymousEmpty", - nullptr, - 0, - PROT_READ, - false, - &error_msg)); + nullptr, + 0, + PROT_READ, + false, + false, + &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); map.reset(MemMap::MapAnonymous("MapAnonymousEmpty", @@ -141,6 +143,7 @@ TEST_F(MemMapTest, MapAnonymousEmpty) { kPageSize, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -151,11 +154,12 @@ TEST_F(MemMapTest, MapAnonymousEmpty32bit) { CommonInit(); std::string error_msg; std::unique_ptr map(MemMap::MapAnonymous("MapAnonymousEmpty", - nullptr, - kPageSize, - PROT_READ | PROT_WRITE, - true, - &error_msg)); + nullptr, + kPageSize, + PROT_READ | PROT_WRITE, + true, + false, + &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); ASSERT_LT(reinterpret_cast(BaseBegin(map.get())), 1ULL << 32); @@ -167,31 +171,34 @@ TEST_F(MemMapTest, MapAnonymousExactAddr) { std::string error_msg; // Map at an address that should work, which should succeed. std::unique_ptr map0(MemMap::MapAnonymous("MapAnonymous0", - reinterpret_cast(ART_BASE_ADDRESS), - kPageSize, - PROT_READ | PROT_WRITE, - false, - &error_msg)); + reinterpret_cast(ART_BASE_ADDRESS), + kPageSize, + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); ASSERT_TRUE(map0.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); ASSERT_TRUE(map0->BaseBegin() == reinterpret_cast(ART_BASE_ADDRESS)); // Map at an unspecified address, which should succeed. std::unique_ptr map1(MemMap::MapAnonymous("MapAnonymous1", - nullptr, - kPageSize, - PROT_READ | PROT_WRITE, - false, - &error_msg)); + nullptr, + kPageSize, + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); ASSERT_TRUE(map1.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); ASSERT_TRUE(map1->BaseBegin() != nullptr); // Attempt to map at the same address, which should fail. std::unique_ptr map2(MemMap::MapAnonymous("MapAnonymous2", - reinterpret_cast(map1->BaseBegin()), - kPageSize, - PROT_READ | PROT_WRITE, - false, - &error_msg)); + reinterpret_cast(map1->BaseBegin()), + kPageSize, + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); ASSERT_TRUE(map2.get() == nullptr) << error_msg; ASSERT_TRUE(!error_msg.empty()); } @@ -217,6 +224,7 @@ TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) { 0x21000000, PROT_READ | PROT_WRITE, true, + false, &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -230,11 +238,12 @@ TEST_F(MemMapTest, MapAnonymousOverflow) { uintptr_t ptr = 0; ptr -= kPageSize; // Now it's close to the top. std::unique_ptr map(MemMap::MapAnonymous("MapAnonymousOverflow", - reinterpret_cast(ptr), - 2 * kPageSize, // brings it over the top. - PROT_READ | PROT_WRITE, - false, - &error_msg)); + reinterpret_cast(ptr), + 2 * kPageSize, // brings it over the top. + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); ASSERT_EQ(nullptr, map.get()); ASSERT_FALSE(error_msg.empty()); } @@ -243,12 +252,14 @@ TEST_F(MemMapTest, MapAnonymousOverflow) { TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) { CommonInit(); std::string error_msg; - std::unique_ptr map(MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh", - reinterpret_cast(UINT64_C(0x100000000)), - kPageSize, - PROT_READ | PROT_WRITE, - true, - &error_msg)); + std::unique_ptr map( + MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh", + reinterpret_cast(UINT64_C(0x100000000)), + kPageSize, + PROT_READ | PROT_WRITE, + true, + false, + &error_msg)); ASSERT_EQ(nullptr, map.get()); ASSERT_FALSE(error_msg.empty()); } @@ -257,16 +268,40 @@ TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) { CommonInit(); std::string error_msg; std::unique_ptr map(MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh", - reinterpret_cast(0xF0000000), - 0x20000000, - PROT_READ | PROT_WRITE, - true, - &error_msg)); + reinterpret_cast(0xF0000000), + 0x20000000, + PROT_READ | PROT_WRITE, + true, + false, + &error_msg)); ASSERT_EQ(nullptr, map.get()); ASSERT_FALSE(error_msg.empty()); } #endif +TEST_F(MemMapTest, MapAnonymousReuse) { + CommonInit(); + std::string error_msg; + std::unique_ptr map(MemMap::MapAnonymous("MapAnonymousReserve", + nullptr, + 0x20000, + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); + ASSERT_NE(nullptr, map.get()); + ASSERT_TRUE(error_msg.empty()); + std::unique_ptr map2(MemMap::MapAnonymous("MapAnonymousReused", + reinterpret_cast(map->BaseBegin()), + 0x10000, + PROT_READ | PROT_WRITE, + false, + true, + &error_msg)); + ASSERT_NE(nullptr, map2.get()); + ASSERT_TRUE(error_msg.empty()); +} + TEST_F(MemMapTest, CheckNoGaps) { CommonInit(); std::string error_msg; @@ -277,6 +312,7 @@ TEST_F(MemMapTest, CheckNoGaps) { kPageSize * kNumPages, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -292,6 +328,7 @@ TEST_F(MemMapTest, CheckNoGaps) { kPageSize, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map0.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -300,6 +337,7 @@ TEST_F(MemMapTest, CheckNoGaps) { kPageSize, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map1.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -308,6 +346,7 @@ TEST_F(MemMapTest, CheckNoGaps) { kPageSize, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map2.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 739d62cb3..356e3d250 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -52,17 +52,7 @@ OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file, CHECK(has_section); oat_file->begin_ = elf_file->Begin() + offset; oat_file->end_ = elf_file->Begin() + size + offset; - return oat_file->Setup(error_msg) ? oat_file.release() : nullptr; -} - -OatFile* OatFile::OpenMemory(std::vector& oat_contents, - const std::string& location, - std::string* error_msg) { - CHECK(!oat_contents.empty()) << location; - CheckLocation(location); - std::unique_ptr oat_file(new OatFile(location, false)); - oat_file->begin_ = &oat_contents[0]; - oat_file->end_ = &oat_contents[oat_contents.size()]; + // Ignore the optional .bss section when opening non-executable. return oat_file->Setup(error_msg) ? oat_file.release() : nullptr; } @@ -108,18 +98,6 @@ OatFile* OatFile::OpenReadable(File* file, const std::string& location, std::str return OpenElfFile(file, location, nullptr, nullptr, false, false, error_msg); } -OatFile* OatFile::OpenDlopen(const std::string& elf_filename, - const std::string& location, - uint8_t* requested_base, - std::string* error_msg) { - std::unique_ptr oat_file(new OatFile(location, true)); - bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg); - if (!success) { - return nullptr; - } - return oat_file.release(); -} - OatFile* OatFile::OpenElfFile(File* file, const std::string& location, uint8_t* requested_base, @@ -138,8 +116,8 @@ OatFile* OatFile::OpenElfFile(File* file, } OatFile::OatFile(const std::string& location, bool is_executable) - : location_(location), begin_(NULL), end_(NULL), is_executable_(is_executable), - dlopen_handle_(NULL), + : location_(location), begin_(NULL), end_(NULL), bss_begin_(nullptr), bss_end_(nullptr), + is_executable_(is_executable), dlopen_handle_(NULL), secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) { CHECK(!location_.empty()); } @@ -151,43 +129,6 @@ OatFile::~OatFile() { } } -bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base, - std::string* error_msg) { - char* absolute_path = realpath(elf_filename.c_str(), NULL); - if (absolute_path == NULL) { - *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str()); - return false; - } - dlopen_handle_ = dlopen(absolute_path, RTLD_NOW); - free(absolute_path); - if (dlopen_handle_ == NULL) { - *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror()); - return false; - } - begin_ = reinterpret_cast(dlsym(dlopen_handle_, "oatdata")); - if (begin_ == NULL) { - *error_msg = StringPrintf("Failed to find oatdata symbol in '%s': %s", elf_filename.c_str(), - dlerror()); - return false; - } - if (requested_base != NULL && begin_ != requested_base) { - PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); - *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: " - "oatdata=%p != expected=%p. See process maps in the log.", - begin_, requested_base); - return false; - } - end_ = reinterpret_cast(dlsym(dlopen_handle_, "oatlastword")); - if (end_ == NULL) { - *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s': %s", elf_filename.c_str(), - dlerror()); - return false; - } - // Readjust to be non-inclusive upper bound. - end_ += sizeof(uint32_t); - return Setup(error_msg); -} - bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin, bool writable, bool executable, std::string* error_msg) { @@ -222,6 +163,23 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file } // Readjust to be non-inclusive upper bound. end_ += sizeof(uint32_t); + + bss_begin_ = elf_file_->FindDynamicSymbolAddress("oatbss"); + if (bss_begin_ == nullptr) { + // No .bss section. Clear dlerror(). + bss_end_ = nullptr; + dlerror(); + } else { + bss_end_ = elf_file_->FindDynamicSymbolAddress("oatbsslastword"); + if (bss_end_ == nullptr) { + *error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'", + file->GetPath().c_str()); + return false; + } + // Readjust to be non-inclusive upper bound. + bss_end_ += sizeof(uint32_t); + } + return Setup(error_msg); } @@ -363,6 +321,14 @@ const uint8_t* OatFile::End() const { return end_; } +const uint8_t* OatFile::BssBegin() const { + return bss_begin_; +} + +const uint8_t* OatFile::BssEnd() const { + return bss_end_; +} + const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, const uint32_t* dex_location_checksum, bool warn_if_not_found) const { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 5e6843923..564185cc7 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -62,11 +62,6 @@ class OatFile { // Opens an oat file from an already opened File. Maps it PROT_READ, MAP_PRIVATE. static OatFile* OpenReadable(File* file, const std::string& location, std::string* error_msg); - // Open an oat file backed by a std::vector with the given location. - static OatFile* OpenMemory(std::vector& oat_contents, - const std::string& location, - std::string* error_msg); - ~OatFile(); bool IsExecutable() const { @@ -274,17 +269,19 @@ class OatFile { return End() - Begin(); } + size_t BssSize() const { + return BssEnd() - BssBegin(); + } + const uint8_t* Begin() const; const uint8_t* End() const; + const uint8_t* BssBegin() const; + const uint8_t* BssEnd() const; + private: static void CheckLocation(const std::string& location); - static OatFile* OpenDlopen(const std::string& elf_filename, - const std::string& location, - uint8_t* requested_base, - std::string* error_msg); - static OatFile* OpenElfFile(File* file, const std::string& location, uint8_t* requested_base, @@ -294,7 +291,6 @@ class OatFile { std::string* error_msg); explicit OatFile(const std::string& filename, bool executable); - bool Dlopen(const std::string& elf_filename, uint8_t* requested_base, std::string* error_msg); bool ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin, // Override where the file is loaded to if not null bool writable, bool executable, @@ -312,6 +308,12 @@ class OatFile { // Pointer to end of oat region for bounds checking. const uint8_t* end_; + // Pointer to the .bss section, if present, otherwise nullptr. + const uint8_t* bss_begin_; + + // Pointer to the end of the .bss section, if present, otherwise nullptr. + const uint8_t* bss_end_; + // Was this oat_file loaded executable? const bool is_executable_; diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc index 587eb320c..2a82285bb 100644 --- a/runtime/thread_pool.cc +++ b/runtime/thread_pool.cc @@ -31,7 +31,7 @@ ThreadPoolWorker::ThreadPoolWorker(ThreadPool* thread_pool, const std::string& n name_(name) { std::string error_msg; stack_.reset(MemMap::MapAnonymous(name.c_str(), nullptr, stack_size, PROT_READ | PROT_WRITE, - false, &error_msg)); + false, false, &error_msg)); CHECK(stack_.get() != nullptr) << error_msg; const char* reason = "new thread pool worker thread"; pthread_attr_t attr; diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc index 63bfc4479..ffab674be 100644 --- a/runtime/zip_archive.cc +++ b/runtime/zip_archive.cc @@ -57,7 +57,8 @@ MemMap* ZipEntry::ExtractToMemMap(const char* zip_filename, const char* entry_fi name += zip_filename; std::unique_ptr map(MemMap::MapAnonymous(name.c_str(), NULL, GetUncompressedLength(), - PROT_READ | PROT_WRITE, false, error_msg)); + PROT_READ | PROT_WRITE, false, false, + error_msg)); if (map.get() == nullptr) { DCHECK(!error_msg->empty()); return nullptr; -- 2.11.0