diff options
author | Igor Murashkin <iam@google.com> | 2014-10-22 11:37:02 -0700 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2014-10-27 20:19:37 -0700 |
commit | 46774767fcf7780d1455e755729198648d08742e (patch) | |
tree | 09a5d87ff0acbc7eb1fa94ec901ba10009178f03 | |
parent | 11bd683f6dbebe2f3d02fa383fc9dbc69a83ace8 (diff) | |
download | android_art-46774767fcf7780d1455e755729198648d08742e.tar.gz android_art-46774767fcf7780d1455e755729198648d08742e.tar.bz2 android_art-46774767fcf7780d1455e755729198648d08742e.zip |
ART: Add support for patching and loading OAT files compiled with PIC
* Images (.art) compiled with pic now have a new field added.
* isDexOptNeeded will now skip patch-ing for apps compiled PIC
* First-boot patching now only copies boot.art, boot.oat is linked
As a result, all system preopted dex files (with --compile-pic) no
longer take up any space in /data/dalvik-cache/<isa>.
Bug: 18035729
Change-Id: Ie1acad81a0fd8b2f24e1f3f07a06e6fdb548be62
-rw-r--r-- | compiler/image_test.cc | 7 | ||||
-rw-r--r-- | compiler/image_writer.cc | 3 | ||||
-rw-r--r-- | compiler/image_writer.h | 21 | ||||
-rw-r--r-- | compiler/oat_test.cc | 2 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 16 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 8 | ||||
-rw-r--r-- | patchoat/patchoat.cc | 224 | ||||
-rw-r--r-- | patchoat/patchoat.h | 41 | ||||
-rw-r--r-- | runtime/class_linker.cc | 12 | ||||
-rw-r--r-- | runtime/elf_file.cc | 45 | ||||
-rw-r--r-- | runtime/elf_file.h | 5 | ||||
-rw-r--r-- | runtime/elf_file_impl.h | 8 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 5 | ||||
-rw-r--r-- | runtime/image.cc | 6 | ||||
-rw-r--r-- | runtime/image.h | 12 | ||||
-rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 25 | ||||
-rw-r--r-- | runtime/oat.cc | 6 | ||||
-rw-r--r-- | runtime/oat.h | 1 | ||||
-rw-r--r-- | runtime/oat_file.cc | 22 | ||||
-rw-r--r-- | runtime/oat_file.h | 6 |
20 files changed, 391 insertions, 84 deletions
diff --git a/compiler/image_test.cc b/compiler/image_test.cc index d5d487f03c..7e2be3ee0c 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -63,7 +63,9 @@ TEST_F(ImageTest, WriteRead) { ScratchFile oat_file(OS::CreateEmptyFile(oat_filename.c_str())); const uintptr_t requested_image_base = ART_BASE_ADDRESS; - std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_driver_, requested_image_base)); + std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_driver_, requested_image_base, + /*compile_pic*/false)); + // TODO: compile_pic should be a test argument. { { jobject class_loader = NULL; @@ -212,7 +214,8 @@ TEST_F(ImageTest, ImageHeaderIsValid) { oat_file_begin, oat_data_begin, oat_data_end, - oat_file_end); + oat_file_end, + /*compile_pic*/false); ASSERT_TRUE(image_header.IsValid()); char* magic = const_cast<char*>(image_header.GetMagic()); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 7baae6e754..861a182a71 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -580,7 +580,8 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { PointerToLowMemUInt32(oat_file_begin), PointerToLowMemUInt32(oat_data_begin_), PointerToLowMemUInt32(oat_data_end), - PointerToLowMemUInt32(oat_file_end)); + PointerToLowMemUInt32(oat_file_end), + compile_pic_); } diff --git a/compiler/image_writer.h b/compiler/image_writer.h index e6a98d1143..b0cf2b20ad 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -24,6 +24,7 @@ #include <set> #include <string> +#include "base/macros.h" #include "driver/compiler_driver.h" #include "mem_map.h" #include "oat_file.h" @@ -35,17 +36,18 @@ namespace art { // Write a Space built during compilation for use during execution. -class ImageWriter { +class ImageWriter FINAL { public: - ImageWriter(const CompilerDriver& compiler_driver, uintptr_t image_begin) + ImageWriter(const CompilerDriver& compiler_driver, uintptr_t image_begin, + bool compile_pic) : compiler_driver_(compiler_driver), image_begin_(reinterpret_cast<uint8_t*>(image_begin)), - image_end_(0), image_roots_address_(0), oat_file_(NULL), - oat_data_begin_(NULL), interpreter_to_interpreter_bridge_offset_(0), + image_end_(0), image_roots_address_(0), oat_file_(nullptr), + oat_data_begin_(nullptr), interpreter_to_interpreter_bridge_offset_(0), interpreter_to_compiled_code_bridge_offset_(0), jni_dlsym_lookup_offset_(0), portable_imt_conflict_trampoline_offset_(0), portable_resolution_trampoline_offset_(0), portable_to_interpreter_bridge_offset_(0), quick_generic_jni_trampoline_offset_(0), quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0), - quick_to_interpreter_bridge_offset_(0) { + quick_to_interpreter_bridge_offset_(0), compile_pic_(compile_pic) { CHECK_NE(image_begin, 0U); } @@ -59,8 +61,8 @@ class ImageWriter { mirror::Object* GetImageAddress(mirror::Object* object) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (object == NULL) { - return NULL; + if (object == nullptr) { + return nullptr; } return reinterpret_cast<mirror::Object*>(image_begin_ + GetImageOffset(object)); } @@ -111,8 +113,8 @@ class ImageWriter { // different .o ELF objects. DCHECK_LT(offset, oat_file_->Size()); #endif - if (offset == 0) { - return NULL; + if (offset == 0u) { + return nullptr; } return oat_data_begin_ + offset; } @@ -217,6 +219,7 @@ class ImageWriter { uint32_t quick_imt_conflict_trampoline_offset_; uint32_t quick_resolution_trampoline_offset_; uint32_t quick_to_interpreter_bridge_offset_; + const bool compile_pic_; friend class FixupVisitor; friend class FixupClassVisitor; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 847fa0d08f..4cb7d9cdd6 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -139,7 +139,7 @@ TEST_F(OatTest, WriteRead) { compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings); } std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), nullptr, - false, &error_msg)); + nullptr, false, &error_msg)); ASSERT_TRUE(oat_file.get() != nullptr) << error_msg; const OatHeader& oat_header = oat_file->GetOatHeader(); ASSERT_TRUE(oat_header.IsValid()); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 1eb5718d69..bdb2b513b0 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -157,6 +157,9 @@ static void UsageError(const char* fmt, ...) { UsageError(" Example: --instruction-set-features=div"); UsageError(" Default: default"); UsageError(""); + UsageError(" --compile-pic: Force indirect use of code, methods, and classes"); + UsageError(" Default: disabled"); + UsageError(""); UsageError(" --compiler-backend=(Quick|Optimizing|Portable): select compiler backend"); UsageError(" set."); UsageError(" Example: --compiler-backend=Portable"); @@ -401,7 +404,7 @@ class Dex2Oat { } void PrepareImageWriter(uintptr_t image_base) { - image_writer_.reset(new ImageWriter(*driver_, image_base)); + image_writer_.reset(new ImageWriter(*driver_, image_base, compiler_options_->GetCompilePic())); } bool CreateOatFile(const std::vector<const DexFile*>& dex_files, @@ -485,10 +488,15 @@ class Dex2Oat { PLOG(ERROR) << "Failed to open ELF file: " << oat_filename; return false; } - if (!ElfWriter::Fixup(oat_file.get(), oat_data_begin)) { - LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath(); - return false; + + // Do not fix up the ELF file if we are --compile-pic + if (!compiler_options_->GetCompilePic()) { + if (!ElfWriter::Fixup(oat_file.get(), oat_data_begin)) { + LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath(); + return false; + } } + return true; } diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 2f91f1d824..f5652779d3 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1273,6 +1273,8 @@ class ImageDumper { os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n"; + os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n"; + { os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n"; Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count); @@ -1323,7 +1325,7 @@ class ImageDumper { std::string error_msg; const OatFile* oat_file = class_linker->FindOpenedOatFileFromOatLocation(oat_location); if (oat_file == nullptr) { - oat_file = OatFile::Open(oat_location, oat_location, nullptr, false, &error_msg); + oat_file = OatFile::Open(oat_location, oat_location, nullptr, nullptr, false, &error_msg); if (oat_file == nullptr) { os << "NOT FOUND: " << error_msg << "\n"; return false; @@ -2087,7 +2089,7 @@ static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, s static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options, std::ostream* os) { std::string error_msg; - OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, false, &error_msg); + OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false, &error_msg); if (oat_file == nullptr) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); return EXIT_FAILURE; @@ -2102,7 +2104,7 @@ static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* static int SymbolizeOat(const char* oat_filename, std::string& output_name) { std::string error_msg; - OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, false, &error_msg); + OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false, &error_msg); if (oat_file == nullptr) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); return EXIT_FAILURE; diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 8e5af53e66..629330b9b1 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -74,7 +74,7 @@ static bool LocationToFilename(const std::string& location, InstructionSet isa, bool has_system = false; bool has_cache = false; // image_location = /system/framework/boot.art - // system_image_location = /system/framework/<image_isa>/boot.art + // system_image_filename = /system/framework/<image_isa>/boot.art std::string system_filename(GetSystemImageFilename(location.c_str(), isa)); if (OS::FileExists(system_filename.c_str())) { has_system = true; @@ -133,6 +133,7 @@ bool PatchOat::Patch(const std::string& image_location, off_t delta, << " for location " << image_location; return false; } + int64_t image_len = input_image->GetLength(); if (image_len < 0) { LOG(ERROR) << "Error while getting image length"; @@ -145,6 +146,10 @@ bool PatchOat::Patch(const std::string& image_location, off_t delta, return false; } + /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath()); + // Nothing special to do right now since the image always needs to get patched. + // Perhaps in some far-off future we may have images with relative addresses that are true-PIC. + // Set up the runtime RuntimeOptions options; NoopCompilerCallbacks callbacks; @@ -189,9 +194,11 @@ bool PatchOat::Patch(const std::string& image_location, off_t delta, return true; } -bool PatchOat::Patch(const File* input_oat, const std::string& image_location, off_t delta, +bool PatchOat::Patch(File* input_oat, const std::string& image_location, off_t delta, File* output_oat, File* output_image, InstructionSet isa, - TimingLogger* timings) { + TimingLogger* timings, + bool output_oat_opened_from_fd, + bool new_oat_out) { CHECK(Runtime::Current() == nullptr); CHECK(output_image != nullptr); CHECK_GE(output_image->Fd(), 0); @@ -234,6 +241,10 @@ bool PatchOat::Patch(const File* input_oat, const std::string& image_location, o LOG(ERROR) << "Unable to read image header from image file " << input_image->GetPath(); } + /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath()); + // Nothing special to do right now since the image always needs to get patched. + // Perhaps in some far-off future we may have images with relative addresses that are true-PIC. + // Set up the runtime RuntimeOptions options; NoopCompilerCallbacks callbacks; @@ -263,17 +274,37 @@ bool PatchOat::Patch(const File* input_oat, const std::string& image_location, o } gc::space::ImageSpace* ispc = Runtime::Current()->GetHeap()->GetImageSpace(); - std::unique_ptr<ElfFile> elf(ElfFile::Open(const_cast<File*>(input_oat), + std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat, PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg)); if (elf.get() == nullptr) { LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg; return false; } + bool skip_patching_oat = false; + MaybePic is_oat_pic = IsOatPic(elf.get()); + if (is_oat_pic >= ERROR_FIRST) { + // Error logged by IsOatPic + return false; + } else if (is_oat_pic == PIC) { + // Do not need to do ELF-file patching. Create a symlink and skip the ELF patching. + if (!ReplaceOatFileWithSymlink(input_oat->GetPath(), + output_oat->GetPath(), + output_oat_opened_from_fd, + new_oat_out)) { + // Errors already logged by above call. + return false; + } + // Don't patch the OAT, since we just symlinked it. Image still needs patching. + skip_patching_oat = true; + } else { + CHECK(is_oat_pic == NOT_PIC); + } + PatchOat p(elf.release(), image.release(), ispc->GetLiveBitmap(), ispc->GetMemMap(), delta, timings); t.NewTiming("Patching files"); - if (!p.PatchElf()) { + if (!skip_patching_oat && !p.PatchElf()) { LOG(ERROR) << "Failed to patch oat file " << input_oat->GetPath(); return false; } @@ -283,10 +314,12 @@ bool PatchOat::Patch(const File* input_oat, const std::string& image_location, o } t.NewTiming("Writing files"); - if (!p.WriteElf(output_oat)) { + if (!skip_patching_oat && !p.WriteElf(output_oat)) { + LOG(ERROR) << "Failed to write oat file " << input_oat->GetPath(); return false; } if (!p.WriteImage(output_image)) { + LOG(ERROR) << "Failed to write image file " << input_image->GetPath(); return false; } return true; @@ -326,6 +359,83 @@ bool PatchOat::WriteImage(File* out) { } } +bool PatchOat::IsImagePic(const ImageHeader& image_header, const std::string& image_path) { + if (!image_header.CompilePic()) { + if (kIsDebugBuild) { + LOG(INFO) << "image at location " << image_path << " was *not* compiled pic"; + } + return false; + } + + if (kIsDebugBuild) { + LOG(INFO) << "image at location " << image_path << " was compiled PIC"; + } + + return true; +} + +PatchOat::MaybePic PatchOat::IsOatPic(const ElfFile* oat_in) { + if (oat_in == nullptr) { + LOG(ERROR) << "No ELF input oat fie available"; + return ERROR_OAT_FILE; + } + + const std::string& file_path = oat_in->GetFile().GetPath(); + + const OatHeader* oat_header = GetOatHeader(oat_in); + if (oat_header == nullptr) { + LOG(ERROR) << "Failed to find oat header in oat file " << file_path; + return ERROR_OAT_FILE; + } + + if (!oat_header->IsValid()) { + LOG(ERROR) << "Elf file " << file_path << " has an invalid oat header"; + return ERROR_OAT_FILE; + } + + bool is_pic = oat_header->IsPic(); + if (kIsDebugBuild) { + LOG(INFO) << "Oat file at " << file_path << " is " << (is_pic ? "PIC" : "not pic"); + } + + return is_pic ? PIC : NOT_PIC; +} + +bool PatchOat::ReplaceOatFileWithSymlink(const std::string& input_oat_filename, + const std::string& output_oat_filename, + bool output_oat_opened_from_fd, + bool new_oat_out) { + // Need a file when we are PIC, since we symlink over it. Refusing to symlink into FD. + if (output_oat_opened_from_fd) { + // TODO: installd uses --output-oat-fd. Should we change class linking logic for PIC? + LOG(ERROR) << "No output oat filename specified, needs filename for when we are PIC"; + return false; + } + + // Image was PIC. Create symlink where the oat is supposed to go. + if (!new_oat_out) { + LOG(ERROR) << "Oat file " << output_oat_filename << " already exists, refusing to overwrite"; + return false; + } + + // Delete the original file, since we won't need it. + TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str())); + + // Create a symlink from the old oat to the new oat + if (symlink(input_oat_filename.c_str(), output_oat_filename.c_str()) < 0) { + int err = errno; + LOG(ERROR) << "Failed to create symlink at " << output_oat_filename + << " error(" << err << "): " << strerror(err); + return false; + } + + if (kIsDebugBuild) { + LOG(INFO) << "Created symlink " << output_oat_filename << " -> " << input_oat_filename; + } + + return true; +} + bool PatchOat::PatchImage() { ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); CHECK_GT(image_->Size(), sizeof(ImageHeader)); @@ -391,6 +501,25 @@ mirror::Object* PatchOat::RelocatedAddressOf(mirror::Object* obj) { } } +const OatHeader* PatchOat::GetOatHeader(const ElfFile* elf_file) { + if (elf_file->Is64Bit()) { + return GetOatHeader<ElfFileImpl64>(elf_file->GetImpl64()); + } else { + return GetOatHeader<ElfFileImpl32>(elf_file->GetImpl32()); + } +} + +template <typename ElfFileImpl> +const OatHeader* PatchOat::GetOatHeader(const ElfFileImpl* elf_file) { + auto rodata_sec = elf_file->FindSectionByName(".rodata"); + if (rodata_sec == nullptr) { + return nullptr; + } + + OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + rodata_sec->sh_offset); + return oat_header; +} + // Called by BitmapCallback void PatchOat::VisitObject(mirror::Object* object) { mirror::Object* copy = RelocatedCopyOf(object); @@ -442,7 +571,8 @@ void PatchOat::FixupMethod(mirror::ArtMethod* object, mirror::ArtMethod* copy) { } } -bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogger* timings) { +bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogger* timings, + bool output_oat_opened_from_fd, bool new_oat_out) { CHECK(input_oat != nullptr); CHECK(output_oat != nullptr); CHECK_GE(input_oat->Fd(), 0); @@ -450,13 +580,28 @@ bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogge TimingLogger::ScopedTiming t("Setup Oat File Patching", timings); std::string error_msg; - std::unique_ptr<ElfFile> elf(ElfFile::Open(const_cast<File*>(input_oat), + std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat, PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg)); if (elf.get() == nullptr) { LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg; return false; } + MaybePic is_oat_pic = IsOatPic(elf.get()); + if (is_oat_pic >= ERROR_FIRST) { + // Error logged by IsOatPic + return false; + } else if (is_oat_pic == PIC) { + // Do not need to do ELF-file patching. Create a symlink and skip the rest. + // Any errors will be logged by the function call. + return ReplaceOatFileWithSymlink(input_oat->GetPath(), + output_oat->GetPath(), + output_oat_opened_from_fd, + new_oat_out); + } else { + CHECK(is_oat_pic == NOT_PIC); + } + PatchOat p(elf.release(), delta, timings); t.NewTiming("Patch Oat file"); if (!p.PatchElf()) { @@ -1043,11 +1188,17 @@ static int patchoat(int argc, char **argv) { input_oat_filename = "input-oat-file"; } input_oat.reset(new File(input_oat_fd, input_oat_filename)); + if (input_oat == nullptr) { + // Unlikely, but ensure exhaustive logging in non-0 exit code case + LOG(ERROR) << "Failed to open input oat file by its FD" << input_oat_fd; + } } else { CHECK(!input_oat_filename.empty()); input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str())); - if (input_oat.get() == nullptr) { - LOG(ERROR) << "Could not open input oat file: " << strerror(errno); + if (input_oat == nullptr) { + int err = errno; + LOG(ERROR) << "Failed to open input oat file " << input_oat_filename + << ": " << strerror(err) << "(" << err << ")"; } } @@ -1056,12 +1207,22 @@ static int patchoat(int argc, char **argv) { output_oat_filename = "output-oat-file"; } output_oat.reset(new File(output_oat_fd, output_oat_filename)); + if (output_oat == nullptr) { + // Unlikely, but ensure exhaustive logging in non-0 exit code case + LOG(ERROR) << "Failed to open output oat file by its FD" << output_oat_fd; + } } else { CHECK(!output_oat_filename.empty()); output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out)); + if (output_oat == nullptr) { + int err = errno; + LOG(ERROR) << "Failed to open output oat file " << output_oat_filename + << ": " << strerror(err) << "(" << err << ")"; + } } } + // TODO: get rid of this. auto cleanup = [&output_image_filename, &output_oat_filename, &new_oat_out, &new_image_out, &timings, &dump_timings](bool success) { timings.EndTiming(); @@ -1078,14 +1239,29 @@ static int patchoat(int argc, char **argv) { if (dump_timings) { LOG(INFO) << Dumpable<TimingLogger>(timings); } + + if (kIsDebugBuild) { + LOG(INFO) << "Cleaning up.. success? " << success; + } }; - if ((have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) || - (have_image_files && output_image.get() == nullptr)) { + if (have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) { + LOG(ERROR) << "Failed to open input/output oat files"; cleanup(false); return EXIT_FAILURE; + } else if (have_image_files && output_image.get() == nullptr) { + LOG(ERROR) << "Failed to open output image file"; + cleanup(false); + return EXIT_FAILURE; + } + + if (debug) { + LOG(INFO) << "moving offset by " << base_delta + << " (0x" << std::hex << base_delta << ") bytes or " + << std::dec << (base_delta/kPageSize) << " pages."; } + // TODO: is it going to be promatic to unlink a file that was flock-ed? ScopedFlock output_oat_lock; if (lock_output) { std::string error_msg; @@ -1096,24 +1272,28 @@ static int patchoat(int argc, char **argv) { } } - if (debug) { - LOG(INFO) << "moving offset by " << base_delta - << " (0x" << std::hex << base_delta << ") bytes or " - << std::dec << (base_delta/kPageSize) << " pages."; - } - bool ret; if (have_image_files && have_oat_files) { TimingLogger::ScopedTiming pt("patch image and oat", &timings); ret = PatchOat::Patch(input_oat.get(), input_image_location, base_delta, - output_oat.get(), output_image.get(), isa, &timings); + output_oat.get(), output_image.get(), isa, &timings, + output_oat_fd >= 0, // was it opened from FD? + new_oat_out); } else if (have_oat_files) { TimingLogger::ScopedTiming pt("patch oat", &timings); - ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings); - } else { + ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings, + output_oat_fd >= 0, // was it opened from FD? + new_oat_out); + } else if (have_image_files) { TimingLogger::ScopedTiming pt("patch image", &timings); - CHECK(have_image_files); ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings); + } else { + CHECK(false); + ret = true; + } + + if (kIsDebugBuild) { + LOG(INFO) << "Exiting with return ... " << ret; } cleanup(ret); return (ret) ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index fd36ad59a3..0ceef6430b 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -30,6 +30,7 @@ namespace art { class ImageHeader; +class OatHeader; namespace mirror { class Object; @@ -40,14 +41,21 @@ class ArtMethod; class PatchOat { public: - static bool Patch(File* oat_in, off_t delta, File* oat_out, TimingLogger* timings); + // Patch only the oat file + static bool Patch(File* oat_in, off_t delta, File* oat_out, TimingLogger* timings, + bool output_oat_opened_from_fd, // Was this using --oatput-oat-fd ? + bool new_oat_out); // Output oat was a new file created by us? + // Patch only the image (art file) static bool Patch(const std::string& art_location, off_t delta, File* art_out, InstructionSet isa, TimingLogger* timings); - static bool Patch(const File* oat_in, const std::string& art_location, + // Patch both the image and the oat file + static bool Patch(File* oat_in, const std::string& art_location, off_t delta, File* oat_out, File* art_out, InstructionSet isa, - TimingLogger* timings); + TimingLogger* timings, + bool output_oat_opened_from_fd, // Was this using --oatput-oat-fd ? + bool new_oat_out); // Output oat was a new file created by us? private: // Takes ownership only of the ElfFile. All other pointers are only borrowed. @@ -64,6 +72,26 @@ class PatchOat { delta_(delta), timings_(timings) {} ~PatchOat() {} + // Was the .art image at image_path made with --compile-pic ? + static bool IsImagePic(const ImageHeader& image_header, const std::string& image_path); + + enum MaybePic { + NOT_PIC, // Code not pic. Patch as usual. + PIC, // Code was pic. Create symlink; skip OAT patching. + ERROR_OAT_FILE, // Failed to symlink oat file + ERROR_FIRST = ERROR_OAT_FILE, + }; + + // Was the .oat image at oat_in made with --compile-pic ? + static MaybePic IsOatPic(const ElfFile* oat_in); + + // Attempt to replace the file with a symlink + // Returns false if it fails + static bool ReplaceOatFileWithSymlink(const std::string& input_oat_filename, + const std::string& output_oat_filename, + bool output_oat_opened_from_fd, + bool new_oat_out); // Output oat was newly created? + static void BitmapCallback(mirror::Object* obj, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { reinterpret_cast<PatchOat*>(arg)->VisitObject(obj); @@ -95,6 +123,13 @@ class PatchOat { mirror::Object* RelocatedCopyOf(mirror::Object*); mirror::Object* RelocatedAddressOf(mirror::Object* obj); + // Look up the oat header from any elf file. + static const OatHeader* GetOatHeader(const ElfFile* elf_file); + + // Templatized version to actually look up the oat header + template <typename ElfFileImpl> + static const OatHeader* GetOatHeader(const ElfFileImpl* elf_file); + // Walks through the old image and patches the mmap'd copy of it to the new offset. It does not // change the heap. class PatchVisitor { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 1676eafab3..f01f2c64b6 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1028,7 +1028,7 @@ const OatFile* ClassLinker::FindOatFileInOatLocationForDexFile(const char* dex_l uint32_t dex_location_checksum, const char* oat_location, std::string* error_msg) { - std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr, + std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr, nullptr, !Runtime::Current()->IsCompiler(), error_msg)); if (oat_file.get() == nullptr) { @@ -1100,7 +1100,7 @@ const OatFile* ClassLinker::CreateOatFileForDexLocation(const char* dex_location error_msgs->push_back(error_msg); return nullptr; } - std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr, + std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr, nullptr, !Runtime::Current()->IsCompiler(), &error_msg)); if (oat_file.get() == nullptr) { @@ -1348,6 +1348,7 @@ const OatFile* ClassLinker::OpenOatFileFromDexLocation(const std::string& dex_lo // There is a high probability that both these oat files map similar/the same address // spaces so we must scope them like this so they each gets its turn. std::unique_ptr<OatFile> odex_oat_file(OatFile::Open(odex_filename, odex_filename, nullptr, + nullptr, executable, &odex_error_msg)); if (odex_oat_file.get() != nullptr && CheckOatFile(runtime, odex_oat_file.get(), isa, &odex_checksum_verified, @@ -1370,6 +1371,7 @@ const OatFile* ClassLinker::OpenOatFileFromDexLocation(const std::string& dex_lo bool cache_checksum_verified = false; if (have_dalvik_cache) { std::unique_ptr<OatFile> cache_oat_file(OatFile::Open(cache_filename, cache_filename, nullptr, + nullptr, executable, &cache_error_msg)); if (cache_oat_file.get() != nullptr && CheckOatFile(runtime, cache_oat_file.get(), isa, &cache_checksum_verified, @@ -1446,7 +1448,7 @@ const OatFile* ClassLinker::GetInterpretedOnlyOat(const std::string& oat_path, InstructionSet isa, std::string* error_msg) { // We open it non-executable - std::unique_ptr<OatFile> output(OatFile::Open(oat_path, oat_path, nullptr, false, error_msg)); + std::unique_ptr<OatFile> output(OatFile::Open(oat_path, oat_path, nullptr, nullptr, false, error_msg)); if (output.get() == nullptr) { return nullptr; } @@ -1503,7 +1505,7 @@ const OatFile* ClassLinker::PatchAndRetrieveOat(const std::string& input_oat, LOG(INFO) << "Relocate Oat File: " << command_line; bool success = Exec(argv, error_msg); if (success) { - std::unique_ptr<OatFile> output(OatFile::Open(output_oat, output_oat, nullptr, + std::unique_ptr<OatFile> output(OatFile::Open(output_oat, output_oat, nullptr, nullptr, !runtime->IsCompiler(), error_msg)); bool checksum_verified = false; if (output.get() != nullptr && CheckOatFile(runtime, output.get(), isa, &checksum_verified, @@ -1606,7 +1608,7 @@ const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_lo return oat_file; } - return OatFile::Open(oat_location, oat_location, nullptr, !Runtime::Current()->IsCompiler(), + return OatFile::Open(oat_location, oat_location, nullptr, nullptr, !Runtime::Current()->IsCompiler(), error_msg); } diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index 18053c3fb9..fb53271157 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -115,7 +115,7 @@ template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_ typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> - ::ElfFileImpl(File* file, bool writable, bool program_header_only) + ::ElfFileImpl(File* file, bool writable, bool program_header_only, uint8_t* requested_base) : file_(file), writable_(writable), program_header_only_(program_header_only), @@ -133,7 +133,8 @@ ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, symtab_symbol_table_(nullptr), dynsym_symbol_table_(nullptr), jit_elf_image_(nullptr), - jit_gdb_entry_(nullptr) { + jit_gdb_entry_(nullptr), + requested_base_(requested_base) { CHECK(file != nullptr); } @@ -145,12 +146,12 @@ ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> ::Open(File* file, bool writable, bool program_header_only, - std::string* error_msg) { + std::string* error_msg, uint8_t* requested_base) { std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>> elf_file(new ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> - (file, writable, program_header_only)); + (file, writable, program_header_only, requested_base)); int prot; int flags; if (writable) { @@ -178,7 +179,8 @@ ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>> elf_file(new ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> - (file, (prot & PROT_WRITE) == PROT_WRITE, false)); + (file, (prot & PROT_WRITE) == PROT_WRITE, /*program_header_only*/false, + /*requested_base*/nullptr)); if (!elf_file->Setup(prot, flags, error_msg)) { return nullptr; } @@ -919,6 +921,8 @@ const uint8_t* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, } const Elf_Sym* sym = FindDynamicSymbol(symbol_name); if (sym != nullptr) { + // TODO: we need to change this to calculate base_address_ in ::Open, + // otherwise it will be wrongly 0 if ::Load has not yet been called. return base_address_ + sym->st_value; } else { return nullptr; @@ -1364,12 +1368,16 @@ bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, } size_t file_length = static_cast<size_t>(temp_file_length); if (!reserved) { - uint8_t* reserve_base = ((program_header->p_vaddr != 0) ? - reinterpret_cast<uint8_t*>(program_header->p_vaddr) : nullptr); + uint8_t* reserve_base = reinterpret_cast<uint8_t*>(program_header->p_vaddr); + uint8_t* reserve_base_override = reserve_base; + // Override the base (e.g. when compiling with --compile-pic) + if (requested_base_ != nullptr) { + reserve_base_override = requested_base_; + } std::string reservation_name("ElfFile reservation for "); reservation_name += file_->GetPath(); std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(), - reserve_base, + reserve_base_override, GetLoadedSize(), PROT_NONE, false, error_msg)); if (reserve.get() == nullptr) { @@ -1378,9 +1386,15 @@ bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, return false; } reserved = true; - if (reserve_base == nullptr) { - base_address_ = reserve->Begin(); - } + + // Base address is the difference of actual mapped location and the p_vaddr + base_address_ = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(reserve->Begin()) + - reinterpret_cast<uintptr_t>(reserve_base)); + // By adding the p_vaddr of a section/symbol to base_address_ we will always get the + // dynamic memory address of where that object is actually mapped + // + // TODO: base_address_ needs to be calculated in ::Open, otherwise + // FindDynamicSymbolAddress returns the wrong values until Load is called. segments_.push_back(reserve.release()); } // empty segment, nothing to map @@ -2425,7 +2439,8 @@ ElfFile::~ElfFile() { CHECK_NE(elf32_.get() == nullptr, elf64_.get() == nullptr); } -ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std::string* error_msg) { +ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std::string* error_msg, + uint8_t* requested_base) { if (file->GetLength() < EI_NIDENT) { *error_msg = StringPrintf("File %s is too short to be a valid ELF file", file->GetPath().c_str()); @@ -2438,12 +2453,14 @@ ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std: } uint8_t* header = map->Begin(); if (header[EI_CLASS] == ELFCLASS64) { - ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, writable, program_header_only, error_msg); + ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, writable, program_header_only, + error_msg, requested_base); if (elf_file_impl == nullptr) return nullptr; return new ElfFile(elf_file_impl); } else if (header[EI_CLASS] == ELFCLASS32) { - ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, writable, program_header_only, error_msg); + ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, writable, program_header_only, + error_msg, requested_base); if (elf_file_impl == nullptr) { return nullptr; } diff --git a/runtime/elf_file.h b/runtime/elf_file.h index 10d6360fcc..41c54bce7b 100644 --- a/runtime/elf_file.h +++ b/runtime/elf_file.h @@ -42,7 +42,8 @@ typedef ElfFileImpl<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Word, Elf64_Sword, // ELFObjectFile. class ElfFile { public: - static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg); + static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg, + uint8_t* requested_base = nullptr); // TODO: move arg to before error_msg. // Open with specific mmap flags, Always maps in the whole file, not just the // program header sections. static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg); @@ -55,8 +56,10 @@ class ElfFile { size_t Size() const; + // The start of the memory map address range for this ELF file. uint8_t* Begin() const; + // The end of the memory map address range for this ELF file. uint8_t* End() const; const File& GetFile() const; diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h index a8bb465817..a70fa17868 100644 --- a/runtime/elf_file_impl.h +++ b/runtime/elf_file_impl.h @@ -36,7 +36,8 @@ template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_ typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> class ElfFileImpl { public: - static ElfFileImpl* Open(File* file, bool writable, bool program_header_only, std::string* error_msg); + static ElfFileImpl* Open(File* file, bool writable, bool program_header_only, + std::string* error_msg, uint8_t* requested_base = nullptr); static ElfFileImpl* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg); ~ElfFileImpl(); @@ -112,7 +113,7 @@ class ElfFileImpl { bool Strip(std::string* error_msg); private: - ElfFileImpl(File* file, bool writable, bool program_header_only); + ElfFileImpl(File* file, bool writable, bool program_header_only, uint8_t* requested_base); bool Setup(int prot, int flags, std::string* error_msg); @@ -206,6 +207,9 @@ class ElfFileImpl { Elf_Rela, Elf_Dyn, Elf_Off>> gdb_file_mapping_; void GdbJITSupport(); + // Override the 'base' p_vaddr in the first LOAD segment with this value (if non-null). + uint8_t* requested_base_; + DISALLOW_COPY_AND_ASSIGN(ElfFileImpl); }; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 414c5ea777..be426255f7 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -657,7 +657,10 @@ OatFile* ImageSpace::OpenOatFile(const char* image_path, std::string* error_msg) const ImageHeader& image_header = GetImageHeader(); std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(image_path); + CHECK(image_header.GetOatDataBegin() != nullptr); + OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(), + image_header.GetOatFileBegin(), !Runtime::Current()->IsCompiler(), error_msg); if (oat_file == NULL) { *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s", @@ -673,7 +676,7 @@ OatFile* ImageSpace::OpenOatFile(const char* image_path, std::string* error_msg) } int32_t image_patch_delta = image_header.GetPatchDelta(); int32_t oat_patch_delta = oat_file->GetOatHeader().GetImagePatchDelta(); - if (oat_patch_delta != image_patch_delta) { + if (oat_patch_delta != image_patch_delta && !image_header.CompilePic()) { // We should have already relocated by this point. Bail out. *error_msg = StringPrintf("Failed to match oat file patch delta %d to expected patch delta %d " "in image %s", oat_patch_delta, image_patch_delta, GetName()); diff --git a/runtime/image.cc b/runtime/image.cc index 2ee3fa4b17..40f43463ef 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -35,7 +35,8 @@ ImageHeader::ImageHeader(uint32_t image_begin, uint32_t oat_file_begin, uint32_t oat_data_begin, uint32_t oat_data_end, - uint32_t oat_file_end) + uint32_t oat_file_end, + bool compile_pic) : image_begin_(image_begin), image_size_(image_size), image_bitmap_offset_(image_bitmap_offset), @@ -46,7 +47,8 @@ ImageHeader::ImageHeader(uint32_t image_begin, oat_data_end_(oat_data_end), oat_file_end_(oat_file_end), patch_delta_(0), - image_roots_(image_roots) { + image_roots_(image_roots), + compile_pic_(compile_pic) { CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize)); CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize)); CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kPageSize)); diff --git a/runtime/image.h b/runtime/image.h index 03de509e67..7e2b8470a0 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -28,7 +28,7 @@ namespace art { // header of image files written by ImageWriter, read and validated by Space. class PACKED(4) ImageHeader { public: - ImageHeader() {} + ImageHeader() : compile_pic_(0) {} ImageHeader(uint32_t image_begin, uint32_t image_size_, @@ -39,7 +39,8 @@ class PACKED(4) ImageHeader { uint32_t oat_file_begin, uint32_t oat_data_begin, uint32_t oat_data_end, - uint32_t oat_file_end); + uint32_t oat_file_end, + bool compile_pic_); bool IsValid() const; const char* GetMagic() const; @@ -121,6 +122,10 @@ class PACKED(4) ImageHeader { void RelocateImage(off_t delta); + bool CompilePic() const { + return compile_pic_ != 0; + } + private: static const uint8_t kImageMagic[4]; static const uint8_t kImageVersion[4]; @@ -162,6 +167,9 @@ class PACKED(4) ImageHeader { // Absolute address of an Object[] of objects needed to reinitialize from an image. uint32_t image_roots_; + // Boolean (0 or 1) to denote if the image was compiled with --compile-pic option + const uint32_t compile_pic_; + friend class ImageWriter; }; diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 11e9efcfb4..2d038cfc46 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -288,9 +288,11 @@ static const jbyte kDexoptNeeded = 2; template <const bool kVerboseLogging, const bool kReasonLogging> static jbyte IsDexOptNeededForFile(const std::string& oat_filename, const char* filename, - InstructionSet target_instruction_set) { + InstructionSet target_instruction_set, + bool* oat_is_pic) { std::string error_msg; std::unique_ptr<const OatFile> oat_file(OatFile::Open(oat_filename, oat_filename, nullptr, + nullptr, false, &error_msg)); if (oat_file.get() == nullptr) { if (kReasonLogging) { @@ -300,6 +302,11 @@ static jbyte IsDexOptNeededForFile(const std::string& oat_filename, const char* error_msg.clear(); return kDexoptNeeded; } + + // Pass-up the information about if this is PIC. + // TODO: Refactor this function to be less complicated. + *oat_is_pic = oat_file->IsPic(); + bool should_relocate_if_possible = Runtime::Current()->ShouldRelocate(); uint32_t location_checksum = 0; const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename, nullptr, @@ -527,10 +534,16 @@ static jbyte IsDexOptNeededInternal(JNIEnv* env, const char* filename, // Lets try the cache first (since we want to load from there since thats where the relocated // versions will be). if (have_cache_filename && !force_system_only) { + bool oat_is_pic; // We can use the dalvik-cache if we find a good file. dalvik_cache_decision = IsDexOptNeededForFile<kVerboseLogging, kReasonLogging>(cache_filename, filename, - target_instruction_set); + target_instruction_set, &oat_is_pic); + + // Apps that are compiled with --compile-pic never need to be patchoat-d + if (oat_is_pic && dalvik_cache_decision == kPatchoatNeeded) { + dalvik_cache_decision = kUpToDate; + } // We will only return DexOptNeeded if both the cache and system return it. if (dalvik_cache_decision != kDexoptNeeded && !require_system_version) { CHECK(!(dalvik_cache_decision == kPatchoatNeeded && !should_relocate_if_possible)) @@ -540,12 +553,18 @@ static jbyte IsDexOptNeededInternal(JNIEnv* env, const char* filename, // We couldn't find one thats easy. We should now try the system. } + bool oat_is_pic; jbyte system_decision = IsDexOptNeededForFile<kVerboseLogging, kReasonLogging>(odex_filename, filename, - target_instruction_set); + target_instruction_set, &oat_is_pic); CHECK(!(system_decision == kPatchoatNeeded && !should_relocate_if_possible)) << "May not return PatchoatNeeded when patching is disabled."; + // Apps that are compiled with --compile-pic never need to be patchoat-d + if (oat_is_pic && system_decision == kPatchoatNeeded) { + system_decision = kUpToDate; + } + if (require_system_version && system_decision == kPatchoatNeeded && dalvik_cache_decision == kUpToDate) { // We have a version from system relocated to the cache. Return it. diff --git a/runtime/oat.cc b/runtime/oat.cc index 95c4716acc..d39b55cfcb 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -470,6 +470,12 @@ size_t OatHeader::GetHeaderSize() const { return sizeof(OatHeader) + key_value_store_size_; } +bool OatHeader::IsPic() const { + const char* pic_string = GetStoreValueByKey(OatHeader::kPicKey); + static const char kTrue[] = "true"; + return (pic_string != nullptr && strncmp(pic_string, kTrue, sizeof(kTrue)) == 0); +} + void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) { char* data_ptr = reinterpret_cast<char*>(&key_value_store_); if (key_value_store != nullptr) { diff --git a/runtime/oat.h b/runtime/oat.h index 5de440372e..f577b077bf 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -104,6 +104,7 @@ class PACKED(4) OatHeader { bool GetStoreKeyValuePairByIndex(size_t index, const char** key, const char** value) const; size_t GetHeaderSize() const; + bool IsPic() const; private: OatHeader(InstructionSet instruction_set, diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 0f0e33c8ba..4214bdf4a3 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -69,6 +69,7 @@ OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents, OatFile* OatFile::Open(const std::string& filename, const std::string& location, uint8_t* requested_base, + uint8_t* oat_file_begin, bool executable, std::string* error_msg) { CHECK(!filename.empty()) << location; @@ -93,7 +94,8 @@ OatFile* OatFile::Open(const std::string& filename, *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno)); return nullptr; } - ret.reset(OpenElfFile(file.get(), location, requested_base, false, executable, error_msg)); + ret.reset(OpenElfFile(file.get(), location, requested_base, oat_file_begin, false, executable, + error_msg)); // It would be nice to unlink here. But we might have opened the file created by the // ScopedLock, which we better not delete to avoid races. TODO: Investigate how to fix the API @@ -104,12 +106,12 @@ OatFile* OatFile::Open(const std::string& filename, OatFile* OatFile::OpenWritable(File* file, const std::string& location, std::string* error_msg) { CheckLocation(location); - return OpenElfFile(file, location, NULL, true, false, error_msg); + return OpenElfFile(file, location, nullptr, nullptr, true, false, error_msg); } OatFile* OatFile::OpenReadable(File* file, const std::string& location, std::string* error_msg) { CheckLocation(location); - return OpenElfFile(file, location, NULL, false, false, error_msg); + return OpenElfFile(file, location, nullptr, nullptr, false, false, error_msg); } OatFile* OatFile::OpenDlopen(const std::string& elf_filename, @@ -127,11 +129,13 @@ OatFile* OatFile::OpenDlopen(const std::string& elf_filename, OatFile* OatFile::OpenElfFile(File* file, const std::string& location, uint8_t* requested_base, + uint8_t* oat_file_begin, bool writable, bool executable, std::string* error_msg) { std::unique_ptr<OatFile> oat_file(new OatFile(location, executable)); - bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable, error_msg); + bool success = oat_file->ElfFileOpen(file, requested_base, oat_file_begin, writable, executable, + error_msg); if (!success) { CHECK(!error_msg->empty()); return nullptr; @@ -190,9 +194,12 @@ bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base, return Setup(error_msg); } -bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, bool writable, bool executable, +bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin, + bool writable, bool executable, std::string* error_msg) { - elf_file_.reset(ElfFile::Open(file, writable, true, error_msg)); + // TODO: rename requested_base to oat_data_begin + elf_file_.reset(ElfFile::Open(file, writable, /*program_header_only*/true, error_msg, + oat_file_begin)); if (elf_file_.get() == nullptr) { DCHECK(!error_msg->empty()); return false; @@ -593,8 +600,7 @@ void OatFile::OatMethod::LinkMethod(mirror::ArtMethod* method) const { } bool OatFile::IsPic() const { - const char* pic_string = GetOatHeader().GetStoreValueByKey(OatHeader::kPicKey); - return (pic_string != nullptr && strncmp(pic_string, "true", 5) == 0); + return GetOatHeader().IsPic(); // TODO: Check against oat_patches. b/18144996 } diff --git a/runtime/oat_file.h b/runtime/oat_file.h index ad6871d637..2b94249958 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -49,6 +49,7 @@ class OatFile { static OatFile* Open(const std::string& filename, const std::string& location, uint8_t* requested_base, + uint8_t* oat_file_begin, bool executable, std::string* error_msg); @@ -315,13 +316,16 @@ class OatFile { static OatFile* OpenElfFile(File* file, const std::string& location, uint8_t* requested_base, + uint8_t* oat_file_begin, // Override base if not null bool writable, bool executable, 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, bool writable, bool executable, + 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, std::string* error_msg); bool Setup(std::string* error_msg); |