summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/linker/arm64/relative_patcher_arm64.cc4
-rw-r--r--compiler/linker/elf_builder.h27
-rw-r--r--compiler/linker/linker_patch.h28
-rw-r--r--compiler/optimizing/code_generator_arm64.cc33
-rw-r--r--compiler/optimizing/code_generator_arm64.h15
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc26
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.h3
-rw-r--r--compiler/optimizing/code_generator_mips.cc27
-rw-r--r--compiler/optimizing/code_generator_mips.h4
-rw-r--r--compiler/optimizing/code_generator_mips64.cc27
-rw-r--r--compiler/optimizing/code_generator_mips64.h4
-rw-r--r--compiler/optimizing/code_generator_x86.cc27
-rw-r--r--compiler/optimizing/code_generator_x86.h4
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc23
-rw-r--r--compiler/optimizing/code_generator_x86_64.h3
-rw-r--r--compiler/optimizing/nodes.cc2
-rw-r--r--compiler/optimizing/nodes.h5
-rw-r--r--compiler/optimizing/sharpening.cc8
-rw-r--r--dex2oat/dex2oat.cc18
-rw-r--r--dex2oat/linker/elf_writer.h3
-rw-r--r--dex2oat/linker/elf_writer_quick.cc22
-rw-r--r--dex2oat/linker/image_test.h14
-rw-r--r--dex2oat/linker/oat_writer.cc118
-rw-r--r--dex2oat/linker/oat_writer.h31
-rw-r--r--dex2oat/linker/oat_writer_test.cc15
-rw-r--r--oatdump/oatdump.cc1
-rw-r--r--runtime/class_linker.cc34
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/oat_file.cc75
-rw-r--r--runtime/oat_file.h22
-rw-r--r--test/552-checker-sharpening/src/Main.java28
31 files changed, 587 insertions, 68 deletions
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 52a07965b9..7230f11f73 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -60,6 +60,7 @@ inline bool IsAdrpPatch(const LinkerPatch& patch) {
case LinkerPatch::Type::kCallRelative:
case LinkerPatch::Type::kBakerReadBarrierBranch:
return false;
+ case LinkerPatch::Type::kDataBimgRelRo:
case LinkerPatch::Type::kMethodRelative:
case LinkerPatch::Type::kMethodBssEntry:
case LinkerPatch::Type::kTypeRelative:
@@ -271,7 +272,8 @@ void Arm64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code,
shift = 0u; // No shift for ADD.
} else {
// LDR/STR 32-bit or 64-bit with imm12 == 0 (unset).
- DCHECK(patch.GetType() == LinkerPatch::Type::kMethodBssEntry ||
+ DCHECK(patch.GetType() == LinkerPatch::Type::kDataBimgRelRo ||
+ patch.GetType() == LinkerPatch::Type::kMethodBssEntry ||
patch.GetType() == LinkerPatch::Type::kTypeClassTable ||
patch.GetType() == LinkerPatch::Type::kTypeBssEntry ||
patch.GetType() == LinkerPatch::Type::kStringInternTable ||
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index a5f60992ca..3da7a43762 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -529,6 +529,8 @@ class ElfBuilder FINAL {
stream_(output),
rodata_(this, ".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
text_(this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0),
+ data_bimg_rel_ro_(
+ this, ".data.bimg.rel.ro", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
bss_(this, ".bss", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
dex_(this, ".dex", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
dynstr_(this, ".dynstr", SHF_ALLOC, kPageSize),
@@ -552,6 +554,7 @@ class ElfBuilder FINAL {
loaded_size_(0u),
virtual_address_(0) {
text_.phdr_flags_ = PF_R | PF_X;
+ data_bimg_rel_ro_.phdr_flags_ = PF_R | PF_W; // Shall be made read-only at run time.
bss_.phdr_flags_ = PF_R | PF_W;
dex_.phdr_flags_ = PF_R;
dynamic_.phdr_flags_ = PF_R | PF_W;
@@ -566,6 +569,7 @@ class ElfBuilder FINAL {
BuildIdSection* GetBuildId() { return &build_id_; }
Section* GetRoData() { return &rodata_; }
Section* GetText() { return &text_; }
+ Section* GetDataBimgRelRo() { return &data_bimg_rel_ro_; }
Section* GetBss() { return &bss_; }
Section* GetDex() { return &dex_; }
StringSection* GetStrTab() { return &strtab_; }
@@ -694,6 +698,7 @@ class ElfBuilder FINAL {
void PrepareDynamicSection(const std::string& elf_file_path,
Elf_Word rodata_size,
Elf_Word text_size,
+ Elf_Word data_bimg_rel_ro_size,
Elf_Word bss_size,
Elf_Word bss_methods_offset,
Elf_Word bss_roots_offset,
@@ -707,6 +712,9 @@ class ElfBuilder FINAL {
// Allocate all pre-dynamic sections.
rodata_.AllocateVirtualMemory(rodata_size);
text_.AllocateVirtualMemory(text_size);
+ if (data_bimg_rel_ro_size != 0) {
+ data_bimg_rel_ro_.AllocateVirtualMemory(data_bimg_rel_ro_size);
+ }
if (bss_size != 0) {
bss_.AllocateVirtualMemory(bss_size);
}
@@ -735,6 +743,24 @@ class ElfBuilder FINAL {
Elf_Word oatlastword_address = rodata_.GetAddress() + rodata_size - 4;
dynsym_.Add(oatlastword, &rodata_, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
}
+ if (data_bimg_rel_ro_size != 0u) {
+ Elf_Word oatdatabimgrelro = dynstr_.Add("oatdatabimgrelro");
+ dynsym_.Add(oatdatabimgrelro,
+ &data_bimg_rel_ro_,
+ data_bimg_rel_ro_.GetAddress(),
+ data_bimg_rel_ro_size,
+ STB_GLOBAL,
+ STT_OBJECT);
+ Elf_Word oatdatabimgrelrolastword = dynstr_.Add("oatdatabimgrelrolastword");
+ Elf_Word oatdatabimgrelrolastword_address =
+ data_bimg_rel_ro_.GetAddress() + data_bimg_rel_ro_size - 4;
+ dynsym_.Add(oatdatabimgrelrolastword,
+ &data_bimg_rel_ro_,
+ oatdatabimgrelrolastword_address,
+ 4,
+ STB_GLOBAL,
+ STT_OBJECT);
+ }
DCHECK_LE(bss_roots_offset, bss_size);
if (bss_size != 0u) {
Elf_Word oatbss = dynstr_.Add("oatbss");
@@ -1010,6 +1036,7 @@ class ElfBuilder FINAL {
Section rodata_;
Section text_;
+ Section data_bimg_rel_ro_;
Section bss_;
Section dex_;
CachedStringSection dynstr_;
diff --git a/compiler/linker/linker_patch.h b/compiler/linker/linker_patch.h
index 6f4e7746a6..a3c737c4f9 100644
--- a/compiler/linker/linker_patch.h
+++ b/compiler/linker/linker_patch.h
@@ -41,6 +41,7 @@ class LinkerPatch {
// choose to squeeze the Type into fewer than 8 bits, we'll have to declare
// patch_type_ as an uintN_t and do explicit static_cast<>s.
enum class Type : uint8_t {
+ kDataBimgRelRo, // NOTE: Actual patching is instruction_set-dependent.
kMethodRelative, // NOTE: Actual patching is instruction_set-dependent.
kMethodBssEntry, // NOTE: Actual patching is instruction_set-dependent.
kCall,
@@ -54,6 +55,15 @@ class LinkerPatch {
kBakerReadBarrierBranch, // NOTE: Actual patching is instruction_set-dependent.
};
+ static LinkerPatch DataBimgRelRoPatch(size_t literal_offset,
+ uint32_t pc_insn_offset,
+ uint32_t boot_image_offset) {
+ LinkerPatch patch(literal_offset, Type::kDataBimgRelRo, /* target_dex_file */ nullptr);
+ patch.boot_image_offset_ = boot_image_offset;
+ patch.pc_insn_offset_ = pc_insn_offset;
+ return patch;
+ }
+
static LinkerPatch RelativeMethodPatch(size_t literal_offset,
const DexFile* target_dex_file,
uint32_t pc_insn_offset,
@@ -172,6 +182,7 @@ class LinkerPatch {
bool IsPcRelative() const {
switch (GetType()) {
+ case Type::kDataBimgRelRo:
case Type::kMethodRelative:
case Type::kMethodBssEntry:
case Type::kCallRelative:
@@ -188,6 +199,11 @@ class LinkerPatch {
}
}
+ uint32_t BootImageOffset() const {
+ DCHECK(patch_type_ == Type::kDataBimgRelRo);
+ return boot_image_offset_;
+ }
+
MethodReference TargetMethod() const {
DCHECK(patch_type_ == Type::kMethodRelative ||
patch_type_ == Type::kMethodBssEntry ||
@@ -225,7 +241,8 @@ class LinkerPatch {
}
uint32_t PcInsnOffset() const {
- DCHECK(patch_type_ == Type::kMethodRelative ||
+ DCHECK(patch_type_ == Type::kDataBimgRelRo ||
+ patch_type_ == Type::kMethodRelative ||
patch_type_ == Type::kMethodBssEntry ||
patch_type_ == Type::kTypeRelative ||
patch_type_ == Type::kTypeClassTable ||
@@ -263,10 +280,11 @@ class LinkerPatch {
uint32_t literal_offset_ : 24; // Method code size up to 16MiB.
Type patch_type_ : 8;
union {
- uint32_t cmp1_; // Used for relational operators.
- uint32_t method_idx_; // Method index for Call/Method patches.
- uint32_t type_idx_; // Type index for Type patches.
- uint32_t string_idx_; // String index for String patches.
+ uint32_t cmp1_; // Used for relational operators.
+ uint32_t boot_image_offset_; // Data to write to the .data.bimg.rel.ro entry.
+ uint32_t method_idx_; // Method index for Call/Method patches.
+ uint32_t type_idx_; // Type index for Type patches.
+ uint32_t string_idx_; // String index for String patches.
uint32_t baker_custom_value1_;
static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 04da898859..bc687e845b 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4460,12 +4460,23 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(
// Load method address from literal pool.
__ Ldr(XRegisterFrom(temp), DeduplicateUint64Literal(invoke->GetMethodAddress()));
break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo: {
+ // Add ADRP with its PC-relative .data.bimg.rel.ro patch.
+ uint32_t boot_image_offset = invoke->GetDispatchInfo().method_load_data;
+ vixl::aarch64::Label* adrp_label = NewBootImageRelRoPatch(boot_image_offset);
+ EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
+ // Add LDR with its PC-relative .data.bimg.rel.ro patch.
+ vixl::aarch64::Label* ldr_label = NewBootImageRelRoPatch(boot_image_offset, adrp_label);
+ // Note: Boot image is in the low 4GiB and the entry is 32-bit, so emit a 32-bit load.
+ EmitLdrOffsetPlaceholder(ldr_label, WRegisterFrom(temp), XRegisterFrom(temp));
+ break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
- // Add ADRP with its PC-relative DexCache access patch.
+ // Add ADRP with its PC-relative .bss entry patch.
MethodReference target_method(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex());
vixl::aarch64::Label* adrp_label = NewMethodBssEntryPatch(target_method);
EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
- // Add LDR with its PC-relative DexCache access patch.
+ // Add LDR with its PC-relative .bss entry patch.
vixl::aarch64::Label* ldr_label =
NewMethodBssEntryPatch(target_method, adrp_label);
EmitLdrOffsetPlaceholder(ldr_label, XRegisterFrom(temp), XRegisterFrom(temp));
@@ -4560,6 +4571,13 @@ void InstructionCodeGeneratorARM64::VisitInvokePolymorphic(HInvokePolymorphic* i
codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ __LINE__);
}
+vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageRelRoPatch(
+ uint32_t boot_image_offset,
+ vixl::aarch64::Label* adrp_label) {
+ return NewPcRelativePatch(
+ /* dex_file */ nullptr, boot_image_offset, adrp_label, &boot_image_method_patches_);
+}
+
vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageMethodPatch(
MethodReference target_method,
vixl::aarch64::Label* adrp_label) {
@@ -4682,6 +4700,14 @@ inline void CodeGeneratorARM64::EmitPcRelativeLinkerPatches(
}
}
+linker::LinkerPatch DataBimgRelRoPatchAdapter(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t pc_insn_offset,
+ uint32_t boot_image_offset) {
+ DCHECK(target_dex_file == nullptr); // Unused for DataBimgRelRoPatch(), should be null.
+ return linker::LinkerPatch::DataBimgRelRoPatch(literal_offset, pc_insn_offset, boot_image_offset);
+}
+
void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -4701,7 +4727,8 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* lin
EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
boot_image_string_patches_, linker_patches);
} else {
- DCHECK(boot_image_method_patches_.empty());
+ EmitPcRelativeLinkerPatches<DataBimgRelRoPatchAdapter>(
+ boot_image_method_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
boot_image_type_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 06cd540d0a..cb61b69609 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -565,7 +565,14 @@ class CodeGeneratorARM64 : public CodeGenerator {
UNIMPLEMENTED(FATAL);
}
- // Add a new PC-relative method patch for an instruction and return the label
+ // Add a new boot image relocation patch for an instruction and return the label
+ // to be bound before the instruction. The instruction will be either the
+ // ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` pointing
+ // to the associated ADRP patch label).
+ vixl::aarch64::Label* NewBootImageRelRoPatch(uint32_t boot_image_offset,
+ vixl::aarch64::Label* adrp_label = nullptr);
+
+ // Add a new boot image method patch for an instruction and return the label
// to be bound before the instruction. The instruction will be either the
// ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
// to the associated ADRP patch label).
@@ -579,7 +586,7 @@ class CodeGeneratorARM64 : public CodeGenerator {
vixl::aarch64::Label* NewMethodBssEntryPatch(MethodReference target_method,
vixl::aarch64::Label* adrp_label = nullptr);
- // Add a new PC-relative type patch for an instruction and return the label
+ // Add a new boot image type patch for an instruction and return the label
// to be bound before the instruction. The instruction will be either the
// ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
// to the associated ADRP patch label).
@@ -595,7 +602,7 @@ class CodeGeneratorARM64 : public CodeGenerator {
dex::TypeIndex type_index,
vixl::aarch64::Label* adrp_label = nullptr);
- // Add a new PC-relative string patch for an instruction and return the label
+ // Add a new boot image string patch for an instruction and return the label
// to be bound before the instruction. The instruction will be either the
// ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
// to the associated ADRP patch label).
@@ -824,7 +831,7 @@ class CodeGeneratorARM64 : public CodeGenerator {
Uint32ToLiteralMap uint32_literals_;
// Deduplication map for 64-bit literals, used for non-patchable method address or method code.
Uint64ToLiteralMap uint64_literals_;
- // PC-relative method patch info for kBootImageLinkTimePcRelative.
+ // PC-relative method patch info for kBootImageLinkTimePcRelative/BootImageRelRo.
ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
// PC-relative method patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 8222fc0a28..94438df898 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -9194,6 +9194,14 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall(
case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
__ Mov(RegisterFrom(temp), Operand::From(invoke->GetMethodAddress()));
break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo: {
+ uint32_t boot_image_offset = invoke->GetDispatchInfo().method_load_data;
+ PcRelativePatchInfo* labels = NewBootImageRelRoPatch(boot_image_offset);
+ vixl32::Register temp_reg = RegisterFrom(temp);
+ EmitMovwMovtPlaceholder(labels, temp_reg);
+ GetAssembler()->LoadFromOffset(kLoadWord, temp_reg, temp_reg, /* offset*/ 0);
+ break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
PcRelativePatchInfo* labels = NewMethodBssEntryPatch(
MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
@@ -9291,6 +9299,13 @@ void CodeGeneratorARMVIXL::GenerateVirtualCall(
}
}
+CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewBootImageRelRoPatch(
+ uint32_t boot_image_offset) {
+ return NewPcRelativePatch(/* dex_file */ nullptr,
+ boot_image_offset,
+ &boot_image_method_patches_);
+}
+
CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewBootImageMethodPatch(
MethodReference target_method) {
return NewPcRelativePatch(
@@ -9381,6 +9396,14 @@ inline void CodeGeneratorARMVIXL::EmitPcRelativeLinkerPatches(
}
}
+linker::LinkerPatch DataBimgRelRoPatchAdapter(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t pc_insn_offset,
+ uint32_t boot_image_offset) {
+ DCHECK(target_dex_file == nullptr); // Unused for DataBimgRelRoPatch(), should be null.
+ return linker::LinkerPatch::DataBimgRelRoPatch(literal_offset, pc_insn_offset, boot_image_offset);
+}
+
void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -9400,7 +9423,8 @@ void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* l
EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
boot_image_string_patches_, linker_patches);
} else {
- DCHECK(boot_image_method_patches_.empty());
+ EmitPcRelativeLinkerPatches<DataBimgRelRoPatchAdapter>(
+ boot_image_method_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
boot_image_type_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 8e6bc0627a..054acbc390 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -580,6 +580,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator {
vixl::aarch32::Label add_pc_label;
};
+ PcRelativePatchInfo* NewBootImageRelRoPatch(uint32_t boot_image_offset);
PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method);
PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
@@ -804,7 +805,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator {
// Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
Uint32ToLiteralMap uint32_literals_;
- // PC-relative method patch info for kBootImageLinkTimePcRelative.
+ // PC-relative method patch info for kBootImageLinkTimePcRelative/kBootImageRelRo.
ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
// PC-relative method patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 825b2377c8..11c1163119 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1597,6 +1597,14 @@ inline void CodeGeneratorMIPS::EmitPcRelativeLinkerPatches(
}
}
+linker::LinkerPatch DataBimgRelRoPatchAdapter(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t pc_insn_offset,
+ uint32_t boot_image_offset) {
+ DCHECK(target_dex_file == nullptr); // Unused for DataBimgRelRoPatch(), should be null.
+ return linker::LinkerPatch::DataBimgRelRoPatch(literal_offset, pc_insn_offset, boot_image_offset);
+}
+
void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -1615,7 +1623,8 @@ void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* link
EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
boot_image_string_patches_, linker_patches);
} else {
- DCHECK(boot_image_method_patches_.empty());
+ EmitPcRelativeLinkerPatches<DataBimgRelRoPatchAdapter>(
+ boot_image_method_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
boot_image_type_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
@@ -1630,6 +1639,13 @@ void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* link
DCHECK_EQ(size, linker_patches->size());
}
+CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageRelRoPatch(
+ uint32_t boot_image_offset,
+ const PcRelativePatchInfo* info_high) {
+ return NewPcRelativePatch(
+ /* dex_file */ nullptr, boot_image_offset, info_high, &boot_image_method_patches_);
+}
+
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageMethodPatch(
MethodReference target_method,
const PcRelativePatchInfo* info_high) {
@@ -7835,6 +7851,15 @@ void CodeGeneratorMIPS::GenerateStaticOrDirectCall(
case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
__ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo: {
+ uint32_t boot_image_offset = invoke->GetDispatchInfo().method_load_data;
+ PcRelativePatchInfo* info_high = NewBootImageRelRoPatch(boot_image_offset);
+ PcRelativePatchInfo* info_low = NewBootImageRelRoPatch(boot_image_offset, info_high);
+ Register temp_reg = temp.AsRegister<Register>();
+ EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg);
+ __ Lw(temp_reg, TMP, /* placeholder */ 0x5678, &info_low->label);
+ break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
PcRelativePatchInfo* info_high = NewMethodBssEntryPatch(
MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index b02a216aaf..2be8e2ead9 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -620,6 +620,8 @@ class CodeGeneratorMIPS : public CodeGenerator {
DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
};
+ PcRelativePatchInfo* NewBootImageRelRoPatch(uint32_t boot_image_offset,
+ const PcRelativePatchInfo* info_high = nullptr);
PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method,
const PcRelativePatchInfo* info_high = nullptr);
PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
@@ -694,7 +696,7 @@ class CodeGeneratorMIPS : public CodeGenerator {
// Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
Uint32ToLiteralMap uint32_literals_;
- // PC-relative method patch info for kBootImageLinkTimePcRelative.
+ // PC-relative method patch info for kBootImageLinkTimePcRelative/kBootImageRelRo.
ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
// PC-relative method patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 9bb1bfb596..d08a0658ec 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1509,6 +1509,14 @@ inline void CodeGeneratorMIPS64::EmitPcRelativeLinkerPatches(
}
}
+linker::LinkerPatch DataBimgRelRoPatchAdapter(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t pc_insn_offset,
+ uint32_t boot_image_offset) {
+ DCHECK(target_dex_file == nullptr); // Unused for DataBimgRelRoPatch(), should be null.
+ return linker::LinkerPatch::DataBimgRelRoPatch(literal_offset, pc_insn_offset, boot_image_offset);
+}
+
void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -1527,7 +1535,8 @@ void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* li
EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
boot_image_string_patches_, linker_patches);
} else {
- DCHECK(boot_image_method_patches_.empty());
+ EmitPcRelativeLinkerPatches<DataBimgRelRoPatchAdapter>(
+ boot_image_method_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
boot_image_type_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
@@ -1542,6 +1551,13 @@ void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* li
DCHECK_EQ(size, linker_patches->size());
}
+CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewBootImageRelRoPatch(
+ uint32_t boot_image_offset,
+ const PcRelativePatchInfo* info_high) {
+ return NewPcRelativePatch(
+ /* dex_file */ nullptr, boot_image_offset, info_high, &boot_image_method_patches_);
+}
+
CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewBootImageMethodPatch(
MethodReference target_method,
const PcRelativePatchInfo* info_high) {
@@ -5926,6 +5942,15 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(
kLoadDoubleword,
DeduplicateUint64Literal(invoke->GetMethodAddress()));
break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo: {
+ uint32_t boot_image_offset = invoke->GetDispatchInfo().method_load_data;
+ PcRelativePatchInfo* info_high = NewBootImageRelRoPatch(boot_image_offset);
+ PcRelativePatchInfo* info_low = NewBootImageRelRoPatch(boot_image_offset, info_high);
+ EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
+ // Note: Boot image is in the low 4GiB and the entry is 32-bit, so emit a 32-bit load.
+ __ Lwu(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
+ break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
PcRelativePatchInfo* info_high = NewMethodBssEntryPatch(
MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index ef4386bf4d..5d40307cc7 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -590,6 +590,8 @@ class CodeGeneratorMIPS64 : public CodeGenerator {
DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
};
+ PcRelativePatchInfo* NewBootImageRelRoPatch(uint32_t boot_image_offset,
+ const PcRelativePatchInfo* info_high = nullptr);
PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method,
const PcRelativePatchInfo* info_high = nullptr);
PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
@@ -659,7 +661,7 @@ class CodeGeneratorMIPS64 : public CodeGenerator {
// Deduplication map for 64-bit literals, used for non-patchable method address or method code
// address.
Uint64ToLiteralMap uint64_literals_;
- // PC-relative method patch info for kBootImageLinkTimePcRelative.
+ // PC-relative method patch info for kBootImageLinkTimePcRelative/kBootImageRelRo.
ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
// PC-relative method patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index c887d9ecc8..528930a503 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4832,6 +4832,15 @@ void CodeGeneratorX86::GenerateStaticOrDirectCall(
case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
__ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress()));
break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo: {
+ Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
+ temp.AsRegister<Register>());
+ __ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset));
+ RecordBootImageRelRoPatch(
+ invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress(),
+ invoke->GetDispatchInfo().method_load_data);
+ break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
temp.AsRegister<Register>());
@@ -4893,6 +4902,13 @@ void CodeGeneratorX86::GenerateVirtualCall(
RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
+void CodeGeneratorX86::RecordBootImageRelRoPatch(HX86ComputeBaseMethodAddress* method_address,
+ uint32_t boot_image_offset) {
+ boot_image_method_patches_.emplace_back(
+ method_address, /* target_dex_file */ nullptr, boot_image_offset);
+ __ Bind(&boot_image_method_patches_.back().label);
+}
+
void CodeGeneratorX86::RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke) {
DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
HX86ComputeBaseMethodAddress* method_address =
@@ -4962,6 +4978,14 @@ inline void CodeGeneratorX86::EmitPcRelativeLinkerPatches(
}
}
+linker::LinkerPatch DataBimgRelRoPatchAdapter(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t pc_insn_offset,
+ uint32_t boot_image_offset) {
+ DCHECK(target_dex_file == nullptr); // Unused for DataBimgRelRoPatch(), should be null.
+ return linker::LinkerPatch::DataBimgRelRoPatch(literal_offset, pc_insn_offset, boot_image_offset);
+}
+
void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -4980,7 +5004,8 @@ void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linke
EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
boot_image_string_patches_, linker_patches);
} else {
- DCHECK(boot_image_method_patches_.empty());
+ EmitPcRelativeLinkerPatches<DataBimgRelRoPatchAdapter>(
+ boot_image_method_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
boot_image_type_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index d5abf2a5fa..2dc34e859e 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -417,6 +417,8 @@ class CodeGeneratorX86 : public CodeGenerator {
void GenerateVirtualCall(
HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
+ void RecordBootImageRelRoPatch(HX86ComputeBaseMethodAddress* method_address,
+ uint32_t boot_image_offset);
void RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke);
void RecordMethodBssEntryPatch(HInvokeStaticOrDirect* invoke);
void RecordBootImageTypePatch(HLoadClass* load_class);
@@ -634,7 +636,7 @@ class CodeGeneratorX86 : public CodeGenerator {
X86Assembler assembler_;
const X86InstructionSetFeatures& isa_features_;
- // PC-relative method patch info for kBootImageLinkTimePcRelative.
+ // PC-relative method patch info for kBootImageLinkTimePcRelative/kBootImageRelRo.
ArenaDeque<X86PcRelativePatchInfo> boot_image_method_patches_;
// PC-relative method patch info for kBssEntry.
ArenaDeque<X86PcRelativePatchInfo> method_bss_entry_patches_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index d42990d51f..d5997245ef 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -998,6 +998,13 @@ void CodeGeneratorX86_64::GenerateStaticOrDirectCall(
case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
Load64BitValue(temp.AsRegister<CpuRegister>(), invoke->GetMethodAddress());
break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo: {
+ // Note: Boot image is in the low 4GiB and the entry is 32-bit, so emit a 32-bit load.
+ __ movl(temp.AsRegister<CpuRegister>(),
+ Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
+ RecordBootImageRelRoPatch(invoke->GetDispatchInfo().method_load_data);
+ break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
__ movq(temp.AsRegister<CpuRegister>(),
Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
@@ -1059,6 +1066,11 @@ void CodeGeneratorX86_64::GenerateVirtualCall(
RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
+void CodeGeneratorX86_64::RecordBootImageRelRoPatch(uint32_t boot_image_offset) {
+ boot_image_method_patches_.emplace_back(/* target_dex_file */ nullptr, boot_image_offset);
+ __ Bind(&boot_image_method_patches_.back().label);
+}
+
void CodeGeneratorX86_64::RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke) {
boot_image_method_patches_.emplace_back(
invoke->GetTargetMethod().dex_file, invoke->GetTargetMethod().index);
@@ -1110,6 +1122,14 @@ inline void CodeGeneratorX86_64::EmitPcRelativeLinkerPatches(
}
}
+linker::LinkerPatch DataBimgRelRoPatchAdapter(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t pc_insn_offset,
+ uint32_t boot_image_offset) {
+ DCHECK(target_dex_file == nullptr); // Unused for DataBimgRelRoPatch(), should be null.
+ return linker::LinkerPatch::DataBimgRelRoPatch(literal_offset, pc_insn_offset, boot_image_offset);
+}
+
void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -1128,7 +1148,8 @@ void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* li
EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
boot_image_string_patches_, linker_patches);
} else {
- DCHECK(boot_image_method_patches_.empty());
+ EmitPcRelativeLinkerPatches<DataBimgRelRoPatchAdapter>(
+ boot_image_method_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
boot_image_type_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 7fc36a9d66..5c8ed6cd8c 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -414,6 +414,7 @@ class CodeGeneratorX86_64 : public CodeGenerator {
void GenerateVirtualCall(
HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
+ void RecordBootImageRelRoPatch(uint32_t boot_image_offset);
void RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke);
void RecordMethodBssEntryPatch(HInvokeStaticOrDirect* invoke);
void RecordBootImageTypePatch(HLoadClass* load_class);
@@ -608,7 +609,7 @@ class CodeGeneratorX86_64 : public CodeGenerator {
// Used for fixups to the constant area.
int constant_area_start_;
- // PC-relative method patch info for kBootImageLinkTimePcRelative.
+ // PC-relative method patch info for kBootImageLinkTimePcRelative/kBootImageRelRo.
ArenaDeque<PatchInfo<Label>> boot_image_method_patches_;
// PC-relative method patch info for kBssEntry.
ArenaDeque<PatchInfo<Label>> method_bss_entry_patches_;
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index f6ba19f22a..a8ddb7cfdc 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2891,6 +2891,8 @@ std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind
return os << "BootImageLinkTimePcRelative";
case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
return os << "DirectAddress";
+ case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo:
+ return os << "BootImageRelRo";
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry:
return os << "BssEntry";
case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 9da46206da..d42f4a7e80 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4431,6 +4431,10 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
// Used for app->boot calls with non-relocatable image and for JIT-compiled calls.
kDirectAddress,
+ // Load from an entry in the .data.bimg.rel.ro using a PC-relative load.
+ // Used for app->boot calls with relocatable image.
+ kBootImageRelRo,
+
// Load from an entry in the .bss section using a PC-relative load.
// Used for classes outside boot image when .bss is accessible with a PC-relative load.
kBssEntry,
@@ -4563,6 +4567,7 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kDirectAddress; }
bool HasPcRelativeMethodLoadKind() const {
return GetMethodLoadKind() == MethodLoadKind::kBootImageLinkTimePcRelative ||
+ GetMethodLoadKind() == MethodLoadKind::kBootImageRelRo ||
GetMethodLoadKind() == MethodLoadKind::kBssEntry;
}
bool HasCurrentMethodInput() const {
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 1e49411c72..b65628e441 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -125,8 +125,14 @@ void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke,
BootImageAOTCanEmbedMethod(callee, compiler_driver)) {
method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative;
code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
+ } else if (IsInBootImage(callee)) {
+ // Use PC-relative access to the .data.bimg.rel.ro methods array.
+ method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo;
+ uint8_t* begin = Runtime::Current()->GetHeap()->GetBootImageSpaces().front()->Begin();
+ method_load_data = reinterpret_cast<uintptr_t>(callee) - reinterpret_cast<uintptr_t>(begin);
+ code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
} else {
- // Use PC-relative access to the .bss methods arrays.
+ // Use PC-relative access to the .bss methods array.
method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBssEntry;
code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 73afbad184..6eeec4e7e9 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -2069,11 +2069,9 @@ class Dex2Oat FINAL {
std::unique_ptr<linker::OatWriter>& oat_writer = oat_writers_[i];
oat_writer->PrepareLayout(&patcher);
-
- size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset();
- size_t text_size = oat_writer->GetOatSize() - rodata_size;
- elf_writer->PrepareDynamicSection(rodata_size,
- text_size,
+ elf_writer->PrepareDynamicSection(oat_writer->GetOatHeader().GetExecutableOffset(),
+ oat_writer->GetCodeSize(),
+ oat_writer->GetDataBimgRelRoSize(),
oat_writer->GetBssSize(),
oat_writer->GetBssMethodsOffset(),
oat_writer->GetBssRootsOffset(),
@@ -2123,6 +2121,16 @@ class Dex2Oat FINAL {
}
elf_writer->EndText(text);
+ if (oat_writer->GetDataBimgRelRoSize() != 0u) {
+ linker::OutputStream* data_bimg_rel_ro = elf_writer->StartDataBimgRelRo();
+ if (!oat_writer->WriteDataBimgRelRo(data_bimg_rel_ro)) {
+ LOG(ERROR) << "Failed to write .data.bimg.rel.ro section to the ELF file "
+ << oat_file->GetPath();
+ return false;
+ }
+ elf_writer->EndDataBimgRelRo(data_bimg_rel_ro);
+ }
+
if (!oat_writer->WriteHeader(elf_writer->GetStream(),
image_file_location_oat_checksum_,
image_file_location_oat_data_begin_,
diff --git a/dex2oat/linker/elf_writer.h b/dex2oat/linker/elf_writer.h
index bcf2cd7d4b..cd8cf4c54e 100644
--- a/dex2oat/linker/elf_writer.h
+++ b/dex2oat/linker/elf_writer.h
@@ -63,6 +63,7 @@ class ElfWriter {
// This method must be called before calling GetLoadedSize().
virtual void PrepareDynamicSection(size_t rodata_size,
size_t text_size,
+ size_t data_bimg_rel_ro_size,
size_t bss_size,
size_t bss_methods_offset,
size_t bss_roots_offset,
@@ -72,6 +73,8 @@ class ElfWriter {
virtual void EndRoData(OutputStream* rodata) = 0;
virtual OutputStream* StartText() = 0;
virtual void EndText(OutputStream* text) = 0;
+ virtual OutputStream* StartDataBimgRelRo() = 0;
+ virtual void EndDataBimgRelRo(OutputStream* data_bimg_rel_ro) = 0;
virtual void WriteDynamicSection() = 0;
virtual void WriteDebugInfo(const debug::DebugInfo& debug_info) = 0;
virtual bool End() = 0;
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index 07b02f1033..4ab2012376 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -105,6 +105,7 @@ class ElfWriterQuick FINAL : public ElfWriter {
void Start() OVERRIDE;
void PrepareDynamicSection(size_t rodata_size,
size_t text_size,
+ size_t data_bimg_rel_ro_size,
size_t bss_size,
size_t bss_methods_offset,
size_t bss_roots_offset,
@@ -114,6 +115,8 @@ class ElfWriterQuick FINAL : public ElfWriter {
void EndRoData(OutputStream* rodata) OVERRIDE;
OutputStream* StartText() OVERRIDE;
void EndText(OutputStream* text) OVERRIDE;
+ OutputStream* StartDataBimgRelRo() OVERRIDE;
+ void EndDataBimgRelRo(OutputStream* data_bimg_rel_ro) OVERRIDE;
void WriteDynamicSection() OVERRIDE;
void WriteDebugInfo(const debug::DebugInfo& debug_info) OVERRIDE;
bool End() OVERRIDE;
@@ -131,6 +134,7 @@ class ElfWriterQuick FINAL : public ElfWriter {
File* const elf_file_;
size_t rodata_size_;
size_t text_size_;
+ size_t data_bimg_rel_ro_size_;
size_t bss_size_;
size_t dex_section_size_;
std::unique_ptr<BufferedOutputStream> output_stream_;
@@ -171,6 +175,7 @@ ElfWriterQuick<ElfTypes>::ElfWriterQuick(InstructionSet instruction_set,
elf_file_(elf_file),
rodata_size_(0u),
text_size_(0u),
+ data_bimg_rel_ro_size_(0u),
bss_size_(0u),
dex_section_size_(0u),
output_stream_(
@@ -192,6 +197,7 @@ void ElfWriterQuick<ElfTypes>::Start() {
template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size,
size_t text_size,
+ size_t data_bimg_rel_ro_size,
size_t bss_size,
size_t bss_methods_offset,
size_t bss_roots_offset,
@@ -200,6 +206,8 @@ void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size,
rodata_size_ = rodata_size;
DCHECK_EQ(text_size_, 0u);
text_size_ = text_size;
+ DCHECK_EQ(data_bimg_rel_ro_size_, 0u);
+ data_bimg_rel_ro_size_ = data_bimg_rel_ro_size;
DCHECK_EQ(bss_size_, 0u);
bss_size_ = bss_size;
DCHECK_EQ(dex_section_size_, 0u);
@@ -207,6 +215,7 @@ void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size,
builder_->PrepareDynamicSection(elf_file_->GetPath(),
rodata_size_,
text_size_,
+ data_bimg_rel_ro_size_,
bss_size_,
bss_methods_offset,
bss_roots_offset,
@@ -240,6 +249,19 @@ void ElfWriterQuick<ElfTypes>::EndText(OutputStream* text) {
}
template <typename ElfTypes>
+OutputStream* ElfWriterQuick<ElfTypes>::StartDataBimgRelRo() {
+ auto* data_bimg_rel_ro = builder_->GetDataBimgRelRo();
+ data_bimg_rel_ro->Start();
+ return data_bimg_rel_ro;
+}
+
+template <typename ElfTypes>
+void ElfWriterQuick<ElfTypes>::EndDataBimgRelRo(OutputStream* data_bimg_rel_ro) {
+ CHECK_EQ(builder_->GetDataBimgRelRo(), data_bimg_rel_ro);
+ builder_->GetDataBimgRelRo()->End();
+}
+
+template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::WriteDynamicSection() {
if (builder_->GetIsa() == InstructionSet::kMips ||
builder_->GetIsa() == InstructionSet::kMips64) {
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 319c5fb675..7449191984 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -313,10 +313,9 @@ inline void CompilationHelper::Compile(CompilerDriver* driver,
oat_writer->WriteChecksumsAndVdexHeader(vdex_out.get());
oat_writer->PrepareLayout(&patcher);
- size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset();
- size_t text_size = oat_writer->GetOatSize() - rodata_size;
- elf_writer->PrepareDynamicSection(rodata_size,
- text_size,
+ elf_writer->PrepareDynamicSection(oat_writer->GetOatHeader().GetExecutableOffset(),
+ oat_writer->GetCodeSize(),
+ oat_writer->GetDataBimgRelRoSize(),
oat_writer->GetBssSize(),
oat_writer->GetBssMethodsOffset(),
oat_writer->GetBssRootsOffset(),
@@ -336,6 +335,13 @@ inline void CompilationHelper::Compile(CompilerDriver* driver,
ASSERT_TRUE(text_ok);
elf_writer->EndText(text);
+ if (oat_writer->GetDataBimgRelRoSize() != 0u) {
+ OutputStream* data_bimg_rel_ro = elf_writer->StartDataBimgRelRo();
+ bool data_bimg_rel_ro_ok = oat_writer->WriteDataBimgRelRo(data_bimg_rel_ro);
+ ASSERT_TRUE(data_bimg_rel_ro_ok);
+ elf_writer->EndDataBimgRelRo(data_bimg_rel_ro);
+ }
+
bool header_ok = oat_writer->WriteHeader(elf_writer->GetStream(), 0u, 0u, 0u);
ASSERT_TRUE(header_ok);
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index c72beea6ce..a7d1ee03bb 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -375,11 +375,15 @@ OatWriter::OatWriter(bool compiling_boot_image,
vdex_dex_shared_data_offset_(0u),
vdex_verifier_deps_offset_(0u),
vdex_quickening_info_offset_(0u),
+ code_size_(0u),
oat_size_(0u),
+ data_bimg_rel_ro_start_(0u),
+ data_bimg_rel_ro_size_(0u),
bss_start_(0u),
bss_size_(0u),
bss_methods_offset_(0u),
bss_roots_offset_(0u),
+ data_bimg_rel_ro_entries_(),
bss_method_entry_references_(),
bss_method_entries_(),
bss_type_entries_(),
@@ -409,6 +413,8 @@ OatWriter::OatWriter(bool compiling_boot_image,
size_method_header_(0),
size_code_(0),
size_code_alignment_(0),
+ size_data_bimg_rel_ro_(0),
+ size_data_bimg_rel_ro_alignment_(0),
size_relative_call_thunks_(0),
size_misc_thunks_(0),
size_vmap_table_(0),
@@ -737,8 +743,13 @@ void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) {
{
TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
offset = InitOatCodeDexFiles(offset);
+ code_size_ = offset - GetOatHeader().GetExecutableOffset();
}
- oat_size_ = offset;
+ {
+ TimingLogger::ScopedTiming split("InitDataBimgRelRoLayout", timings_);
+ offset = InitDataBimgRelRoLayout(offset);
+ }
+ oat_size_ = offset; // .bss does not count towards oat_size_.
bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
@@ -845,7 +856,10 @@ class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
MethodReference(dex_file_, it.GetMemberIndex()));
if (HasCompiledCode(compiled_method)) {
for (const LinkerPatch& patch : compiled_method->GetPatches()) {
- if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
+ if (patch.GetType() == LinkerPatch::Type::kDataBimgRelRo) {
+ writer_->data_bimg_rel_ro_entries_.Overwrite(patch.BootImageOffset(),
+ /* placeholder */ 0u);
+ } else if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
MethodReference target_method = patch.TargetMethod();
AddBssReference(target_method,
target_method.dex_file->NumMethodIds(),
@@ -1776,6 +1790,16 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor {
for (const LinkerPatch& patch : compiled_method->GetPatches()) {
uint32_t literal_offset = patch.LiteralOffset();
switch (patch.GetType()) {
+ case LinkerPatch::Type::kDataBimgRelRo: {
+ uint32_t target_offset =
+ writer_->data_bimg_rel_ro_start_ +
+ writer_->data_bimg_rel_ro_entries_.Get(patch.BootImageOffset());
+ writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+ patch,
+ offset_ + literal_offset,
+ target_offset);
+ break;
+ }
case LinkerPatch::Type::kMethodBssEntry: {
uint32_t target_offset =
writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
@@ -2510,6 +2534,25 @@ size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
return offset;
}
+size_t OatWriter::InitDataBimgRelRoLayout(size_t offset) {
+ DCHECK_EQ(data_bimg_rel_ro_size_, 0u);
+ if (data_bimg_rel_ro_entries_.empty()) {
+ // Nothing to put to the .data.bimg.rel.ro section.
+ return offset;
+ }
+
+ data_bimg_rel_ro_start_ = RoundUp(offset, kPageSize);
+
+ for (auto& entry : data_bimg_rel_ro_entries_) {
+ size_t& entry_offset = entry.second;
+ entry_offset = data_bimg_rel_ro_size_;
+ data_bimg_rel_ro_size_ += sizeof(uint32_t);
+ }
+
+ offset = data_bimg_rel_ro_start_ + data_bimg_rel_ro_size_;
+ return offset;
+}
+
void OatWriter::InitBssLayout(InstructionSet instruction_set) {
{
InitBssLayoutMethodVisitor visitor(this);
@@ -2905,6 +2948,49 @@ bool OatWriter::WriteCode(OutputStream* out) {
return false;
}
+ if (data_bimg_rel_ro_size_ != 0u) {
+ write_state_ = WriteState::kWriteDataBimgRelRo;
+ } else {
+ if (!CheckOatSize(out, file_offset, relative_offset)) {
+ return false;
+ }
+ write_state_ = WriteState::kWriteHeader;
+ }
+ return true;
+}
+
+bool OatWriter::WriteDataBimgRelRo(OutputStream* out) {
+ CHECK(write_state_ == WriteState::kWriteDataBimgRelRo);
+
+ // Wrap out to update checksum with each write.
+ ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
+ out = &checksum_updating_out;
+
+ const size_t file_offset = oat_data_offset_;
+ size_t relative_offset = data_bimg_rel_ro_start_;
+
+ // Record the padding before the .data.bimg.rel.ro section.
+ // Do not write anything, this zero-filled part was skipped (Seek()) when starting the section.
+ size_t code_end = GetOatHeader().GetExecutableOffset() + code_size_;
+ DCHECK_EQ(RoundUp(code_end, kPageSize), relative_offset);
+ size_t padding_size = relative_offset - code_end;
+ DCHECK_EQ(size_data_bimg_rel_ro_alignment_, 0u);
+ size_data_bimg_rel_ro_alignment_ = padding_size;
+
+ relative_offset = WriteDataBimgRelRo(out, file_offset, relative_offset);
+ if (relative_offset == 0) {
+ LOG(ERROR) << "Failed to write boot image relocations to " << out->GetLocation();
+ return false;
+ }
+
+ if (!CheckOatSize(out, file_offset, relative_offset)) {
+ return false;
+ }
+ write_state_ = WriteState::kWriteHeader;
+ return true;
+}
+
+bool OatWriter::CheckOatSize(OutputStream* out, size_t file_offset, size_t relative_offset) {
const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
if (oat_end_file_offset == static_cast<off_t>(-1)) {
LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
@@ -2939,6 +3025,8 @@ bool OatWriter::WriteCode(OutputStream* out) {
DO_STAT(size_method_header_);
DO_STAT(size_code_);
DO_STAT(size_code_alignment_);
+ DO_STAT(size_data_bimg_rel_ro_);
+ DO_STAT(size_data_bimg_rel_ro_alignment_);
DO_STAT(size_relative_call_thunks_);
DO_STAT(size_misc_thunks_);
DO_STAT(size_vmap_table_);
@@ -3316,6 +3404,32 @@ size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
return relative_offset;
}
+size_t OatWriter::WriteDataBimgRelRo(OutputStream* out,
+ size_t file_offset,
+ size_t relative_offset) {
+ if (data_bimg_rel_ro_entries_.empty()) {
+ return relative_offset;
+ }
+
+ // Write the entire .data.bimg.rel.ro with a single WriteFully().
+ std::vector<uint32_t> data;
+ data.reserve(data_bimg_rel_ro_entries_.size());
+ for (const auto& entry : data_bimg_rel_ro_entries_) {
+ uint32_t boot_image_offset = entry.first;
+ data.push_back(boot_image_offset);
+ }
+ DCHECK_EQ(data.size(), data_bimg_rel_ro_entries_.size());
+ DCHECK_OFFSET();
+ if (!out->WriteFully(data.data(), data.size() * sizeof(data[0]))) {
+ PLOG(ERROR) << "Failed to write .data.bimg.rel.ro in " << out->GetLocation();
+ return 0u;
+ }
+ DCHECK_EQ(size_data_bimg_rel_ro_, 0u);
+ size_data_bimg_rel_ro_ = data.size() * sizeof(data[0]);
+ relative_offset += size_data_bimg_rel_ro_;
+ return relative_offset;
+}
+
bool OatWriter::RecordOatDataOffset(OutputStream* out) {
// Get the elf file offset of the oat file.
const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index 0cb0ef20df..db249c0933 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -137,6 +137,7 @@ class OatWriter {
// - PrepareLayout(),
// - WriteRodata(),
// - WriteCode(),
+ // - WriteDataBimgRelRo() iff GetDataBimgRelRoSize() != 0,
// - WriteHeader().
// Add dex file source(s) from a file, either a plain dex file or
@@ -197,6 +198,10 @@ class OatWriter {
bool WriteRodata(OutputStream* out);
// Write the code to the .text section.
bool WriteCode(OutputStream* out);
+ // Write the boot image relocation data to the .data.bimg.rel.ro section.
+ bool WriteDataBimgRelRo(OutputStream* out);
+ // Check the size of the written oat file.
+ bool CheckOatSize(OutputStream* out, size_t file_offset, size_t relative_offset);
// Write the oat header. This finalizes the oat file.
bool WriteHeader(OutputStream* out,
uint32_t image_file_location_oat_checksum,
@@ -218,10 +223,18 @@ class OatWriter {
return *oat_header_;
}
+ size_t GetCodeSize() const {
+ return code_size_;
+ }
+
size_t GetOatSize() const {
return oat_size_;
}
+ size_t GetDataBimgRelRoSize() const {
+ return data_bimg_rel_ro_size_;
+ }
+
size_t GetBssSize() const {
return bss_size_;
}
@@ -323,6 +336,7 @@ class OatWriter {
size_t InitOatDexFiles(size_t offset);
size_t InitOatCode(size_t offset);
size_t InitOatCodeDexFiles(size_t offset);
+ size_t InitDataBimgRelRoLayout(size_t offset);
void InitBssLayout(InstructionSet instruction_set);
size_t WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset);
@@ -332,6 +346,7 @@ class OatWriter {
size_t WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset);
size_t WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset);
size_t WriteCodeDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset);
+ size_t WriteDataBimgRelRo(OutputStream* out, size_t file_offset, size_t relative_offset);
bool RecordOatDataOffset(OutputStream* out);
bool WriteTypeLookupTables(OutputStream* oat_rodata,
@@ -360,6 +375,7 @@ class OatWriter {
kPrepareLayout,
kWriteRoData,
kWriteText,
+ kWriteDataBimgRelRo,
kWriteHeader,
kDone
};
@@ -401,9 +417,18 @@ class OatWriter {
// Offset of section holding quickening info inside Vdex.
size_t vdex_quickening_info_offset_;
+ // Size of the .text segment.
+ size_t code_size_;
+
// Size required for Oat data structures.
size_t oat_size_;
+ // The start of the required .data.bimg.rel.ro section.
+ size_t data_bimg_rel_ro_start_;
+
+ // The size of the required .data.bimg.rel.ro section holding the boot image relocations.
+ size_t data_bimg_rel_ro_size_;
+
// The start of the required .bss section.
size_t bss_start_;
@@ -416,6 +441,10 @@ class OatWriter {
// The offset of the GC roots in .bss section.
size_t bss_roots_offset_;
+ // Map for allocating .data.bimg.rel.ro entries. Indexed by the boot image offset of the
+ // relocation. The value is the assigned offset within the .data.bimg.rel.ro section.
+ SafeMap<uint32_t, size_t> data_bimg_rel_ro_entries_;
+
// Map for recording references to ArtMethod entries in .bss.
SafeMap<const DexFile*, BitVector> bss_method_entry_references_;
@@ -484,6 +513,8 @@ class OatWriter {
uint32_t size_method_header_;
uint32_t size_code_;
uint32_t size_code_alignment_;
+ uint32_t size_data_bimg_rel_ro_;
+ uint32_t size_data_bimg_rel_ro_alignment_;
uint32_t size_relative_call_thunks_;
uint32_t size_misc_thunks_;
uint32_t size_vmap_table_;
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 00b9abe69b..f713ed6faa 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -216,10 +216,9 @@ class OatTest : public CommonCompilerTest {
instruction_set_features_.get());
oat_writer.Initialize(compiler_driver_.get(), nullptr, dex_files);
oat_writer.PrepareLayout(&patcher);
- size_t rodata_size = oat_writer.GetOatHeader().GetExecutableOffset();
- size_t text_size = oat_writer.GetOatSize() - rodata_size;
- elf_writer->PrepareDynamicSection(rodata_size,
- text_size,
+ elf_writer->PrepareDynamicSection(oat_writer.GetOatHeader().GetExecutableOffset(),
+ oat_writer.GetCodeSize(),
+ oat_writer.GetDataBimgRelRoSize(),
oat_writer.GetBssSize(),
oat_writer.GetBssMethodsOffset(),
oat_writer.GetBssRootsOffset(),
@@ -248,6 +247,14 @@ class OatTest : public CommonCompilerTest {
}
elf_writer->EndText(text);
+ if (oat_writer.GetDataBimgRelRoSize() != 0u) {
+ OutputStream* data_bimg_rel_ro = elf_writer->StartDataBimgRelRo();
+ if (!oat_writer.WriteDataBimgRelRo(data_bimg_rel_ro)) {
+ return false;
+ }
+ elf_writer->EndDataBimgRelRo(data_bimg_rel_ro);
+ }
+
if (!oat_writer.WriteHeader(elf_writer->GetStream(), 42U, 4096U, 0)) {
return false;
}
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 8069408b5a..c8903db5eb 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -172,6 +172,7 @@ class OatSymbolizer FINAL {
builder_->PrepareDynamicSection(elf_file->GetPath(),
rodata_size,
text_size,
+ oat_file_->DataBimgRelRoSize(),
oat_file_->BssSize(),
oat_file_->BssMethodsOffset(),
oat_file_->BssRootsOffset(),
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 1d72875269..7a1c3deaa7 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3361,9 +3361,10 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
CHECK_EQ(dex_cache_location, dex_file_suffix);
const OatFile* oat_file =
(dex_file.GetOatDexFile() != nullptr) ? dex_file.GetOatDexFile()->GetOatFile() : nullptr;
- // Clean up pass to remove null dex caches. Also check if we need to initialize OatFile .bss.
- // Null dex caches can occur due to class unloading and we are lazily removing null entries.
- bool initialize_oat_file_bss = (oat_file != nullptr);
+ // Clean up pass to remove null dex caches; null dex caches can occur due to class unloading
+ // and we are lazily removing null entries. Also check if we need to initialize OatFile data
+ // (.data.bimg.rel.ro and .bss sections) needed for code execution.
+ bool initialize_oat_file_data = (oat_file != nullptr) && oat_file->IsExecutable();
JavaVMExt* const vm = self->GetJniEnv()->GetVm();
for (auto it = dex_caches_.begin(); it != dex_caches_.end(); ) {
DexCacheData data = *it;
@@ -3371,15 +3372,36 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
vm->DeleteWeakGlobalRef(self, data.weak_root);
it = dex_caches_.erase(it);
} else {
- if (initialize_oat_file_bss &&
+ if (initialize_oat_file_data &&
it->dex_file->GetOatDexFile() != nullptr &&
it->dex_file->GetOatDexFile()->GetOatFile() == oat_file) {
- initialize_oat_file_bss = false; // Already initialized.
+ initialize_oat_file_data = false; // Already initialized.
}
++it;
}
}
- if (initialize_oat_file_bss) {
+ if (initialize_oat_file_data) {
+ // Initialize the .data.bimg.rel.ro section.
+ if (!oat_file->GetBootImageRelocations().empty()) {
+ uint8_t* reloc_begin = const_cast<uint8_t*>(oat_file->DataBimgRelRoBegin());
+ CheckedCall(mprotect,
+ "un-protect boot image relocations",
+ reloc_begin,
+ oat_file->DataBimgRelRoSize(),
+ PROT_READ | PROT_WRITE);
+ uint32_t boot_image_begin = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(
+ Runtime::Current()->GetHeap()->GetBootImageSpaces().front()->Begin()));
+ for (const uint32_t& relocation : oat_file->GetBootImageRelocations()) {
+ const_cast<uint32_t&>(relocation) += boot_image_begin;
+ }
+ CheckedCall(mprotect,
+ "protect boot image relocations",
+ reloc_begin,
+ oat_file->DataBimgRelRoSize(),
+ PROT_READ);
+ }
+
+ // Initialize the .bss section.
// TODO: Pre-initialize from boot/app image?
ArtMethod* resolution_method = Runtime::Current()->GetResolutionMethod();
for (ArtMethod*& entry : oat_file->GetBssMethods()) {
diff --git a/runtime/oat.h b/runtime/oat.h
index 292c9d6f41..0fa1d4b4c2 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@ class InstructionSetFeatures;
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: Math.pow() intrinsic.
- static constexpr uint8_t kOatVersion[] = { '1', '3', '8', '\0' };
+ // Last oat version changed reason: Retrieve ArtMethod* from .data.bimg.rel.ro .
+ static constexpr uint8_t kOatVersion[] = { '1', '3', '9', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index b0e1de2b81..66347e92e2 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -343,6 +343,19 @@ bool OatFileBase::ComputeFields(uint8_t* requested_base,
// Readjust to be non-inclusive upper bound.
end_ += sizeof(uint32_t);
+ data_bimg_rel_ro_begin_ = FindDynamicSymbolAddress("oatdatabimgrelro", &symbol_error_msg);
+ if (data_bimg_rel_ro_begin_ != nullptr) {
+ data_bimg_rel_ro_end_ =
+ FindDynamicSymbolAddress("oatdatabimgrelrolastword", &symbol_error_msg);
+ if (data_bimg_rel_ro_end_ == nullptr) {
+ *error_msg =
+ StringPrintf("Failed to find oatdatabimgrelrolastword symbol in '%s'", file_path.c_str());
+ return false;
+ }
+ // Readjust to be non-inclusive upper bound.
+ data_bimg_rel_ro_end_ += sizeof(uint32_t);
+ }
+
bss_begin_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbss", &symbol_error_msg));
if (bss_begin_ == nullptr) {
// No .bss section.
@@ -536,6 +549,17 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) {
}
const uint8_t* oat = Begin() + oat_dex_files_offset; // Jump to the OatDexFile records.
+ if (!IsAligned<sizeof(uint32_t)>(data_bimg_rel_ro_begin_) ||
+ !IsAligned<sizeof(uint32_t)>(data_bimg_rel_ro_end_) ||
+ data_bimg_rel_ro_begin_ > data_bimg_rel_ro_end_) {
+ *error_msg = StringPrintf("In oat file '%s' found unaligned or unordered databimgrelro "
+ "symbol(s): begin = %p, end = %p",
+ GetLocation().c_str(),
+ data_bimg_rel_ro_begin_,
+ data_bimg_rel_ro_end_);
+ return false;
+ }
+
DCHECK_GE(static_cast<size_t>(pointer_size), alignof(GcRoot<mirror::Object>));
if (!IsAligned<kPageSize>(bss_begin_) ||
!IsAlignedParam(bss_methods_, static_cast<size_t>(pointer_size)) ||
@@ -849,8 +873,29 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) {
}
}
+ Runtime* runtime = Runtime::Current();
+
+ if (DataBimgRelRoBegin() != nullptr) {
+ // Make .data.bimg.rel.ro read only. ClassLinker shall make it writable for relocation.
+ uint8_t* reloc_begin = const_cast<uint8_t*>(DataBimgRelRoBegin());
+ CheckedCall(mprotect, "protect relocations", reloc_begin, DataBimgRelRoSize(), PROT_READ);
+ if (UNLIKELY(runtime == nullptr)) {
+ // This must be oatdump without boot image.
+ } else if (!IsExecutable()) {
+ // Do not check whether we have a boot image if the oat file is not executable.
+ } else if (UNLIKELY(runtime->GetHeap()->GetBootImageSpaces().empty())) {
+ *error_msg = StringPrintf("Cannot load oat file '%s' with .data.bimg.rel.ro as executable "
+ "without boot image.",
+ GetLocation().c_str());
+ return false;
+ } else {
+ // ClassLinker shall perform the relocation when we register a dex file from
+ // this oat file. We do not do the relocation here to avoid dirtying the pages
+ // if the code is never actually ready to be executed.
+ }
+ }
+
if (boot_image_tables != nullptr) {
- Runtime* runtime = Runtime::Current();
if (UNLIKELY(runtime == nullptr)) {
// This must be oatdump without boot image. Make sure the .bss is inaccessible.
CheckedCall(mprotect, "protect bss", const_cast<uint8_t*>(BssBegin()), BssSize(), PROT_NONE);
@@ -1513,6 +1558,8 @@ OatFile::OatFile(const std::string& location, bool is_executable)
vdex_(nullptr),
begin_(nullptr),
end_(nullptr),
+ data_bimg_rel_ro_begin_(nullptr),
+ data_bimg_rel_ro_end_(nullptr),
bss_begin_(nullptr),
bss_end_(nullptr),
bss_methods_(nullptr),
@@ -1542,22 +1589,6 @@ const uint8_t* OatFile::End() const {
return end_;
}
-const uint8_t* OatFile::BssBegin() const {
- return bss_begin_;
-}
-
-const uint8_t* OatFile::BssEnd() const {
- return bss_end_;
-}
-
-const uint8_t* OatFile::VdexBegin() const {
- return vdex_begin_;
-}
-
-const uint8_t* OatFile::VdexEnd() const {
- return vdex_end_;
-}
-
const uint8_t* OatFile::DexBegin() const {
return vdex_->Begin();
}
@@ -1566,6 +1597,16 @@ const uint8_t* OatFile::DexEnd() const {
return vdex_->End();
}
+ArrayRef<const uint32_t> OatFile::GetBootImageRelocations() const {
+ if (data_bimg_rel_ro_begin_ != nullptr) {
+ const uint32_t* relocations = reinterpret_cast<const uint32_t*>(data_bimg_rel_ro_begin_);
+ const uint32_t* relocations_end = reinterpret_cast<const uint32_t*>(data_bimg_rel_ro_end_);
+ return ArrayRef<const uint32_t>(relocations, relocations_end - relocations);
+ } else {
+ return ArrayRef<const uint32_t>();
+ }
+}
+
ArrayRef<ArtMethod*> OatFile::GetBssMethods() const {
if (bss_methods_ != nullptr) {
ArtMethod** methods = reinterpret_cast<ArtMethod**>(bss_methods_);
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 3c2cd00c8d..24868dd55d 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -275,6 +275,10 @@ class OatFile {
return p >= Begin() && p < End();
}
+ size_t DataBimgRelRoSize() const {
+ return DataBimgRelRoEnd() - DataBimgRelRoBegin();
+ }
+
size_t BssSize() const {
return BssEnd() - BssBegin();
}
@@ -300,15 +304,19 @@ class OatFile {
const uint8_t* Begin() const;
const uint8_t* End() const;
- const uint8_t* BssBegin() const;
- const uint8_t* BssEnd() const;
+ const uint8_t* DataBimgRelRoBegin() const { return data_bimg_rel_ro_begin_; }
+ const uint8_t* DataBimgRelRoEnd() const { return data_bimg_rel_ro_end_; }
+
+ const uint8_t* BssBegin() const { return bss_begin_; }
+ const uint8_t* BssEnd() const { return bss_end_; }
- const uint8_t* VdexBegin() const;
- const uint8_t* VdexEnd() const;
+ const uint8_t* VdexBegin() const { return vdex_begin_; }
+ const uint8_t* VdexEnd() const { return vdex_end_; }
const uint8_t* DexBegin() const;
const uint8_t* DexEnd() const;
+ ArrayRef<const uint32_t> GetBootImageRelocations() const;
ArrayRef<ArtMethod*> GetBssMethods() const;
ArrayRef<GcRoot<mirror::Object>> GetBssGcRoots() const;
@@ -355,6 +363,12 @@ class OatFile {
// Pointer to end of oat region for bounds checking.
const uint8_t* end_;
+ // Pointer to the .data.bimg.rel.ro section, if present, otherwise null.
+ const uint8_t* data_bimg_rel_ro_begin_;
+
+ // Pointer to the end of the .data.bimg.rel.ro section, if present, otherwise null.
+ const uint8_t* data_bimg_rel_ro_end_;
+
// Pointer to the .bss section, if present, otherwise null.
uint8_t* bss_begin_;
diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java
index 3173afdfcd..121e8f2014 100644
--- a/test/552-checker-sharpening/src/Main.java
+++ b/test/552-checker-sharpening/src/Main.java
@@ -195,6 +195,32 @@ public class Main {
return Other.class;
}
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexString(int) builder (after)
+ /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall
+
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexString(int) sharpening (after)
+ // Note: load kind depends on PIC/non-PIC
+ /// CHECK: InvokeStaticOrDirect method_load_kind:{{BootImageRelRo|DirectAddress}}
+ public static String $noinline$toHexString(int value) {
+ return Integer.toString(value, 16);
+ }
+
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexStringIndirect(int) builder (after)
+ /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall
+
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexStringIndirect(int) sharpening (after)
+ /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
+
+ /// CHECK-START-X86: java.lang.String Main.$noinline$toHexStringIndirect(int) pc_relative_fixups_x86 (before)
+ /// CHECK-NOT: X86ComputeBaseMethodAddress
+
+ /// CHECK-START-X86: java.lang.String Main.$noinline$toHexStringIndirect(int) pc_relative_fixups_x86 (after)
+ /// CHECK-DAG: X86ComputeBaseMethodAddress
+ /// CHECK-DAG: InvokeStaticOrDirect method_load_kind:BssEntry
+ public static String $noinline$toHexStringIndirect(int value) {
+ return $noinline$toHexString(value);
+ }
+
public static void main(String[] args) {
assertIntEquals(1, testSimple(1));
assertIntEquals(1, testDiamond(false, 1));
@@ -208,6 +234,8 @@ public class Main {
assertStringEquals("non-boot-image-string", $noinline$getNonBootImageString());
assertClassEquals(String.class, $noinline$getStringClass());
assertClassEquals(Other.class, $noinline$getOtherClass());
+ assertStringEquals("12345678", $noinline$toHexString(0x12345678));
+ assertStringEquals("76543210", $noinline$toHexStringIndirect(0x76543210));
}
}