summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2014-10-22 11:37:02 -0700
committerIgor Murashkin <iam@google.com>2014-10-27 20:19:37 -0700
commit46774767fcf7780d1455e755729198648d08742e (patch)
tree09a5d87ff0acbc7eb1fa94ec901ba10009178f03
parent11bd683f6dbebe2f3d02fa383fc9dbc69a83ace8 (diff)
downloadandroid_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.cc7
-rw-r--r--compiler/image_writer.cc3
-rw-r--r--compiler/image_writer.h21
-rw-r--r--compiler/oat_test.cc2
-rw-r--r--dex2oat/dex2oat.cc16
-rw-r--r--oatdump/oatdump.cc8
-rw-r--r--patchoat/patchoat.cc224
-rw-r--r--patchoat/patchoat.h41
-rw-r--r--runtime/class_linker.cc12
-rw-r--r--runtime/elf_file.cc45
-rw-r--r--runtime/elf_file.h5
-rw-r--r--runtime/elf_file_impl.h8
-rw-r--r--runtime/gc/space/image_space.cc5
-rw-r--r--runtime/image.cc6
-rw-r--r--runtime/image.h12
-rw-r--r--runtime/native/dalvik_system_DexFile.cc25
-rw-r--r--runtime/oat.cc6
-rw-r--r--runtime/oat.h1
-rw-r--r--runtime/oat_file.cc22
-rw-r--r--runtime/oat_file.h6
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);