diff options
Diffstat (limited to 'compiler/image_writer.cc')
| -rw-r--r-- | compiler/image_writer.cc | 226 |
1 files changed, 24 insertions, 202 deletions
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 8ef2964270..d102bbcedc 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -29,6 +29,7 @@ #include "driver/compiler_driver.h" #include "elf_file.h" #include "elf_utils.h" +#include "elf_patcher.h" #include "elf_writer.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap.h" @@ -84,7 +85,7 @@ bool ImageWriter::Write(const std::string& image_filename, return false; } std::string error_msg; - oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location, &error_msg); + oat_file_ = OatFile::OpenReadable(oat_file.get(), oat_location, &error_msg); if (oat_file_ == nullptr) { LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location << ": " << error_msg; @@ -801,214 +802,35 @@ void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) { } } -static ArtMethod* GetTargetMethod(const CompilerDriver::CallPatchInformation* patch) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - StackHandleScope<1> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache( - hs.NewHandle(class_linker->FindDexCache(*patch->GetTargetDexFile()))); - ArtMethod* method = class_linker->ResolveMethod(*patch->GetTargetDexFile(), - patch->GetTargetMethodIdx(), - dex_cache, - NullHandle<mirror::ClassLoader>(), - NullHandle<mirror::ArtMethod>(), - patch->GetTargetInvokeType()); - CHECK(method != NULL) - << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetTargetMethodIdx(); - CHECK(!method->IsRuntimeMethod()) - << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetTargetMethodIdx(); - CHECK(dex_cache->GetResolvedMethods()->Get(patch->GetTargetMethodIdx()) == method) - << patch->GetTargetDexFile()->GetLocation() << " " << patch->GetReferrerMethodIdx() << " " - << PrettyMethod(dex_cache->GetResolvedMethods()->Get(patch->GetTargetMethodIdx())) << " " - << PrettyMethod(method); - return method; -} - -static Class* GetTargetType(const CompilerDriver::TypePatchInformation* patch) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - StackHandleScope<2> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(patch->GetDexFile()))); - Class* klass = class_linker->ResolveType(patch->GetDexFile(), patch->GetTargetTypeIdx(), - dex_cache, NullHandle<mirror::ClassLoader>()); - CHECK(klass != NULL) - << patch->GetDexFile().GetLocation() << " " << patch->GetTargetTypeIdx(); - CHECK(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx()) == klass) - << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx() << " " - << PrettyClass(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx())) << " " - << PrettyClass(klass); - return klass; +static OatHeader* GetOatHeaderFromElf(ElfFile* elf) { + Elf32_Shdr* data_sec = elf->FindSectionByName(".rodata"); + if (data_sec == nullptr) { + return nullptr; + } + return reinterpret_cast<OatHeader*>(elf->Begin() + data_sec->sh_offset); } void ImageWriter::PatchOatCodeAndMethods(File* elf_file) { - std::vector<uintptr_t> patches; - std::set<uintptr_t> patches_set; - auto maybe_push = [&patches, &patches_set] (uintptr_t p) { - if (patches_set.find(p) == patches_set.end()) { - patches.push_back(p); - patches_set.insert(p); - } - }; - const bool add_patches = compiler_driver_.GetCompilerOptions().GetIncludePatchInformation(); - if (add_patches) { - // TODO if we are adding patches the resulting ELF file might have a potentially rather large - // amount of free space where patches might have been placed. We should adjust the ELF file to - // get rid of this excess space. - patches.reserve(compiler_driver_.GetCodeToPatch().size() + - compiler_driver_.GetMethodsToPatch().size() + - compiler_driver_.GetClassesToPatch().size()); - } - uintptr_t loc = 0; - Thread* self = Thread::Current(); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); - - typedef std::vector<const CompilerDriver::CallPatchInformation*> CallPatches; - const CallPatches& code_to_patch = compiler_driver_.GetCodeToPatch(); - for (size_t i = 0; i < code_to_patch.size(); i++) { - const CompilerDriver::CallPatchInformation* patch = code_to_patch[i]; - ArtMethod* target = GetTargetMethod(patch); - uintptr_t quick_code = reinterpret_cast<uintptr_t>(class_linker->GetQuickOatCodeFor(target)); - DCHECK_NE(quick_code, 0U) << PrettyMethod(target); - uintptr_t code_base = reinterpret_cast<uintptr_t>(&oat_file_->GetOatHeader()); - uintptr_t code_offset = quick_code - code_base; - bool is_quick_offset = false; - if (quick_code == reinterpret_cast<uintptr_t>(GetQuickToInterpreterBridge())) { - is_quick_offset = true; - code_offset = quick_to_interpreter_bridge_offset_; - } else if (quick_code == - reinterpret_cast<uintptr_t>(class_linker->GetQuickGenericJniTrampoline())) { - CHECK(target->IsNative()); - is_quick_offset = true; - code_offset = quick_generic_jni_trampoline_offset_; - } - uintptr_t value; - if (patch->IsRelative()) { - // value to patch is relative to the location being patched - const void* quick_oat_code = - class_linker->GetQuickOatCodeFor(patch->GetDexFile(), - patch->GetReferrerClassDefIdx(), - patch->GetReferrerMethodIdx()); - if (is_quick_offset) { - // If its a quick offset it means that we are doing a relative patch from the class linker - // oat_file to the image writer oat_file so we need to adjust the quick oat code to be the - // one in the image writer oat_file. - quick_code = PointerToLowMemUInt32(GetOatAddress(code_offset)); - quick_oat_code = - reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(quick_oat_code) + - reinterpret_cast<uintptr_t>(oat_data_begin_) - code_base); - } - uintptr_t base = reinterpret_cast<uintptr_t>(quick_oat_code); - uintptr_t patch_location = base + patch->GetLiteralOffset(); - value = quick_code - patch_location + patch->RelativeOffset(); - } else { - value = PointerToLowMemUInt32(GetOatAddress(code_offset)); - } - SetPatchLocation(patch, value, &loc); - if (add_patches && !patch->AsCall()->IsRelative()) { - maybe_push(loc); - } - } - - const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch(); - for (size_t i = 0; i < methods_to_patch.size(); i++) { - const CompilerDriver::CallPatchInformation* patch = methods_to_patch[i]; - ArtMethod* target = GetTargetMethod(patch); - SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target)), &loc); - if (add_patches && !patch->AsCall()->IsRelative()) { - maybe_push(loc); - } + std::string error_msg; + std::unique_ptr<ElfFile> elf(ElfFile::Open(elf_file, PROT_READ|PROT_WRITE, + MAP_SHARED, &error_msg)); + if (elf.get() == nullptr) { + LOG(FATAL) << "Unable patch oat file: " << error_msg; + return; } - - const std::vector<const CompilerDriver::TypePatchInformation*>& classes_to_patch = - compiler_driver_.GetClassesToPatch(); - for (size_t i = 0; i < classes_to_patch.size(); i++) { - const CompilerDriver::TypePatchInformation* patch = classes_to_patch[i]; - Class* target = GetTargetType(patch); - SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target)), &loc); - if (add_patches) { - maybe_push(loc); - } + if (!ElfPatcher::Patch(&compiler_driver_, elf.get(), oat_file_, + reinterpret_cast<uintptr_t>(oat_data_begin_), + GetImageAddressCallback, reinterpret_cast<void*>(this), + &error_msg)) { + LOG(FATAL) << "unable to patch oat file: " << error_msg; + return; } + OatHeader* oat_header = GetOatHeaderFromElf(elf.get()); + CHECK(oat_header != nullptr); + CHECK(oat_header->IsValid()); - // Update the image header with the new checksum after patching ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); - image_header->SetOatChecksum(oat_file_->GetOatHeader().GetChecksum()); - self->EndAssertNoThreadSuspension(old_cause); - - // Update the ElfFiles SHT_OAT_PATCH section to include the patches. - if (add_patches) { - std::string err; - // TODO we are mapping in the contents of this file twice. We should be able - // to do it only once, which would be better. - std::unique_ptr<ElfFile> file(ElfFile::Open(elf_file, true, false, &err)); - if (file == nullptr) { - LOG(ERROR) << err; - } - Elf32_Shdr* shdr = file->FindSectionByName(".oat_patches"); - if (shdr != nullptr) { - CHECK_EQ(shdr, file->FindSectionByType(SHT_OAT_PATCH)) - << "Incorrect type for .oat_patches section"; - CHECK_LE(patches.size() * sizeof(uintptr_t), shdr->sh_size) - << "We got more patches than anticipated"; - CHECK_LE(reinterpret_cast<uintptr_t>(file->Begin()) + shdr->sh_offset + shdr->sh_size, - reinterpret_cast<uintptr_t>(file->End())) << "section is too large"; - CHECK(shdr == &file->GetSectionHeader(file->GetSectionHeaderNum() - 1) || - shdr->sh_offset + shdr->sh_size <= (shdr + 1)->sh_offset) - << "Section overlaps onto next section"; - // It's mmap'd so we can just memcpy. - memcpy(file->Begin() + shdr->sh_offset, patches.data(), patches.size()*sizeof(uintptr_t)); - // TODO We should fill in the newly empty space between the last patch and the start of the - // next section by moving the following sections down if possible. - shdr->sh_size = patches.size() * sizeof(uintptr_t); - } else { - LOG(ERROR) << "Unable to find section header for SHT_OAT_PATCH"; - } - } -} - -void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value, - uintptr_t* patched_ptr) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - const void* quick_oat_code = class_linker->GetQuickOatCodeFor(patch->GetDexFile(), - patch->GetReferrerClassDefIdx(), - patch->GetReferrerMethodIdx()); - OatHeader& oat_header = const_cast<OatHeader&>(oat_file_->GetOatHeader()); - // TODO: make this Thumb2 specific - uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(quick_oat_code) & ~0x1); - uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset()); - if (kIsDebugBuild) { - if (patch->IsCall()) { - const CompilerDriver::CallPatchInformation* cpatch = patch->AsCall(); - const DexFile::MethodId& id = cpatch->GetTargetDexFile()->GetMethodId(cpatch->GetTargetMethodIdx()); - uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF; - uint32_t actual = *patch_location; - CHECK(actual == expected || actual == value) << std::hex - << "actual=" << actual - << "expected=" << expected - << "value=" << value; - } - if (patch->IsType()) { - const CompilerDriver::TypePatchInformation* tpatch = patch->AsType(); - const DexFile::TypeId& id = tpatch->GetDexFile().GetTypeId(tpatch->GetTargetTypeIdx()); - uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF; - uint32_t actual = *patch_location; - CHECK(actual == expected || actual == value) << std::hex - << "actual=" << actual - << "expected=" << expected - << "value=" << value; - } - } - *patch_location = value; - oat_header.UpdateChecksum(patch_location, sizeof(value)); - - uintptr_t loc = reinterpret_cast<uintptr_t>(patch_location) - - (reinterpret_cast<uintptr_t>(oat_file_->Begin()) + oat_header.GetExecutableOffset()); - CHECK_GT(reinterpret_cast<uintptr_t>(patch_location), - reinterpret_cast<uintptr_t>(oat_file_->Begin()) + oat_header.GetExecutableOffset()); - CHECK_LT(loc, oat_file_->Size() - oat_header.GetExecutableOffset()); - - *patched_ptr = loc; + image_header->SetOatChecksum(oat_header->GetChecksum()); } } // namespace art |