diff options
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)); } } |