xref: /aosp_15_r20/art/dex2oat/linker/riscv64/relative_patcher_riscv64.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "relative_patcher_riscv64.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
20*795d594fSAndroid Build Coastguard Worker #include "debug/method_debug_info.h"
21*795d594fSAndroid Build Coastguard Worker #include "linker/linker_patch.h"
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker namespace art {
24*795d594fSAndroid Build Coastguard Worker namespace linker {
25*795d594fSAndroid Build Coastguard Worker 
Riscv64RelativePatcher(RelativePatcherThunkProvider * thunk_provider,RelativePatcherTargetProvider * target_provider,const Riscv64InstructionSetFeatures * features)26*795d594fSAndroid Build Coastguard Worker Riscv64RelativePatcher::Riscv64RelativePatcher(
27*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] RelativePatcherThunkProvider* thunk_provider,
28*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] RelativePatcherTargetProvider* target_provider,
29*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] const Riscv64InstructionSetFeatures* features)
30*795d594fSAndroid Build Coastguard Worker     : RelativePatcher() {
31*795d594fSAndroid Build Coastguard Worker }
32*795d594fSAndroid Build Coastguard Worker 
ReserveSpace(uint32_t offset,const CompiledMethod * compiled_method,MethodReference method_ref)33*795d594fSAndroid Build Coastguard Worker uint32_t Riscv64RelativePatcher::ReserveSpace(
34*795d594fSAndroid Build Coastguard Worker     uint32_t offset,
35*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] const CompiledMethod* compiled_method,
36*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] MethodReference method_ref) {
37*795d594fSAndroid Build Coastguard Worker   // TODO(riscv64): Reduce code size for AOT by using shared trampolines for slow path
38*795d594fSAndroid Build Coastguard Worker   // runtime calls across the entire oat file. These need space reserved here.
39*795d594fSAndroid Build Coastguard Worker   return offset;
40*795d594fSAndroid Build Coastguard Worker }
41*795d594fSAndroid Build Coastguard Worker 
ReserveSpaceEnd(uint32_t offset)42*795d594fSAndroid Build Coastguard Worker uint32_t Riscv64RelativePatcher::ReserveSpaceEnd(uint32_t offset) {
43*795d594fSAndroid Build Coastguard Worker   // TODO(riscv64): Reduce code size for AOT by using shared trampolines for slow path
44*795d594fSAndroid Build Coastguard Worker   // runtime calls across the entire oat file. These need space reserved here.
45*795d594fSAndroid Build Coastguard Worker   return offset;
46*795d594fSAndroid Build Coastguard Worker }
47*795d594fSAndroid Build Coastguard Worker 
WriteThunks(OutputStream * out,uint32_t offset)48*795d594fSAndroid Build Coastguard Worker uint32_t Riscv64RelativePatcher::WriteThunks([[maybe_unused]] OutputStream* out, uint32_t offset) {
49*795d594fSAndroid Build Coastguard Worker   // TODO(riscv64): Reduce code size for AOT by using shared trampolines for slow path
50*795d594fSAndroid Build Coastguard Worker   // runtime calls across the entire oat file. These need to be written here.
51*795d594fSAndroid Build Coastguard Worker   return offset;
52*795d594fSAndroid Build Coastguard Worker }
53*795d594fSAndroid Build Coastguard Worker 
PatchCall(std::vector<uint8_t> * code,uint32_t literal_offset,uint32_t patch_offset,uint32_t target_offset)54*795d594fSAndroid Build Coastguard Worker void Riscv64RelativePatcher::PatchCall([[maybe_unused]] std::vector<uint8_t>* code,
55*795d594fSAndroid Build Coastguard Worker                                        [[maybe_unused]] uint32_t literal_offset,
56*795d594fSAndroid Build Coastguard Worker                                        [[maybe_unused]] uint32_t patch_offset,
57*795d594fSAndroid Build Coastguard Worker                                        [[maybe_unused]] uint32_t target_offset) {
58*795d594fSAndroid Build Coastguard Worker   // Direct calls are currently not used on any architecture.
59*795d594fSAndroid Build Coastguard Worker   UNIMPLEMENTED(FATAL) << "Unsupported direct call.";
60*795d594fSAndroid Build Coastguard Worker }
61*795d594fSAndroid Build Coastguard Worker 
PatchPcRelativeReference(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset,uint32_t target_offset)62*795d594fSAndroid Build Coastguard Worker void Riscv64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code,
63*795d594fSAndroid Build Coastguard Worker                                                       const LinkerPatch& patch,
64*795d594fSAndroid Build Coastguard Worker                                                       uint32_t patch_offset,
65*795d594fSAndroid Build Coastguard Worker                                                       uint32_t target_offset) {
66*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(patch_offset, 2u);
67*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(target_offset, 2u);
68*795d594fSAndroid Build Coastguard Worker   uint32_t literal_offset = patch.LiteralOffset();
69*795d594fSAndroid Build Coastguard Worker   uint32_t insn = GetInsn(code, literal_offset);
70*795d594fSAndroid Build Coastguard Worker   uint32_t pc_insn_offset = patch.PcInsnOffset();
71*795d594fSAndroid Build Coastguard Worker   uint32_t disp = target_offset - (patch_offset - literal_offset + pc_insn_offset);
72*795d594fSAndroid Build Coastguard Worker   if (literal_offset == pc_insn_offset) {
73*795d594fSAndroid Build Coastguard Worker     // Check it's an AUIPC with imm == 0x12345 (unset).
74*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ((insn & 0xfffff07fu), 0x12345017u)
75*795d594fSAndroid Build Coastguard Worker         << literal_offset << ", " << pc_insn_offset << ", 0x" << std::hex << insn;
76*795d594fSAndroid Build Coastguard Worker     insn = PatchAuipc(insn, disp);
77*795d594fSAndroid Build Coastguard Worker   } else {
78*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ((insn & 0xfff00000u), 0x67800000u);
79*795d594fSAndroid Build Coastguard Worker     CHECK((insn & 0x0000707fu) == 0x00000013u ||  // ADD
80*795d594fSAndroid Build Coastguard Worker           (insn & 0x0000707fu) == 0x00006003u ||  // LWU
81*795d594fSAndroid Build Coastguard Worker           (insn & 0x0000707fu) == 0x00003003u)    // LD
82*795d594fSAndroid Build Coastguard Worker         << "insn: 0x" << std::hex << insn << ", type: " << patch.GetType();
83*795d594fSAndroid Build Coastguard Worker     // Check that pc_insn_offset points to AUIPC with matching register.
84*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(GetInsn(code, pc_insn_offset) & 0x00000fffu,
85*795d594fSAndroid Build Coastguard Worker               0x00000017 | (((insn >> 15) & 0x1fu) << 7));
86*795d594fSAndroid Build Coastguard Worker     uint32_t imm12 = disp & 0xfffu;  // The instruction shall sign-extend this immediate.
87*795d594fSAndroid Build Coastguard Worker     insn = (insn & ~(0xfffu << 20)) | (imm12 << 20);
88*795d594fSAndroid Build Coastguard Worker   }
89*795d594fSAndroid Build Coastguard Worker   SetInsn(code, literal_offset, insn);
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker 
PatchEntrypointCall(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)92*795d594fSAndroid Build Coastguard Worker void Riscv64RelativePatcher::PatchEntrypointCall([[maybe_unused]] std::vector<uint8_t>* code,
93*795d594fSAndroid Build Coastguard Worker                                                  [[maybe_unused]] const LinkerPatch& patch,
94*795d594fSAndroid Build Coastguard Worker                                                  [[maybe_unused]] uint32_t patch_offset) {
95*795d594fSAndroid Build Coastguard Worker   // TODO(riscv64): Reduce code size for AOT by using shared trampolines for slow path
96*795d594fSAndroid Build Coastguard Worker   // runtime calls across the entire oat file. Calls to these trapolines need to be patched here.
97*795d594fSAndroid Build Coastguard Worker   UNIMPLEMENTED(FATAL) << "Shared entrypoint trampolines are not implemented.";
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker 
PatchBakerReadBarrierBranch(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)100*795d594fSAndroid Build Coastguard Worker void Riscv64RelativePatcher::PatchBakerReadBarrierBranch(
101*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] std::vector<uint8_t>* code,
102*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] const LinkerPatch& patch,
103*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] uint32_t patch_offset) {
104*795d594fSAndroid Build Coastguard Worker   // Baker read barrier with introspection is not implemented.
105*795d594fSAndroid Build Coastguard Worker   // Such implementation is impractical given the short reach of conditional branches.
106*795d594fSAndroid Build Coastguard Worker   UNIMPLEMENTED(FATAL) << "Baker read barrier branches are not used on riscv64.";
107*795d594fSAndroid Build Coastguard Worker }
108*795d594fSAndroid Build Coastguard Worker 
GenerateThunkDebugInfo(uint32_t executable_offset)109*795d594fSAndroid Build Coastguard Worker std::vector<debug::MethodDebugInfo> Riscv64RelativePatcher::GenerateThunkDebugInfo(
110*795d594fSAndroid Build Coastguard Worker       [[maybe_unused]] uint32_t executable_offset) {
111*795d594fSAndroid Build Coastguard Worker   // TODO(riscv64): Reduce code size for AOT by using shared trampolines for slow path
112*795d594fSAndroid Build Coastguard Worker   // runtime calls across the entire oat file. These need debug info generated here.
113*795d594fSAndroid Build Coastguard Worker   return {};
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker 
PatchAuipc(uint32_t auipc,int32_t offset)116*795d594fSAndroid Build Coastguard Worker uint32_t Riscv64RelativePatcher::PatchAuipc(uint32_t auipc, int32_t offset) {
117*795d594fSAndroid Build Coastguard Worker   // The highest 0x800 values are out of range.
118*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(offset, 0x7ffff800);
119*795d594fSAndroid Build Coastguard Worker   // Round `offset` to nearest 4KiB offset because short offset has range [-0x800, 0x800).
120*795d594fSAndroid Build Coastguard Worker   int32_t near_offset = (offset + 0x800) & ~0xfff;
121*795d594fSAndroid Build Coastguard Worker   // Extract the `imm20`.
122*795d594fSAndroid Build Coastguard Worker   uint32_t imm20 = static_cast<uint32_t>(near_offset) >> 12;
123*795d594fSAndroid Build Coastguard Worker   return (auipc & 0x00000fffu) |  // Clear offset bits, keep AUIPC with destination reg.
124*795d594fSAndroid Build Coastguard Worker          (imm20 << 12);           // Encode the immediate.
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker 
SetInsn(std::vector<uint8_t> * code,uint32_t offset,uint32_t value)127*795d594fSAndroid Build Coastguard Worker void Riscv64RelativePatcher::SetInsn(std::vector<uint8_t>* code, uint32_t offset, uint32_t value) {
128*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(offset + 4u, code->size());
129*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(offset, 2u);
130*795d594fSAndroid Build Coastguard Worker   uint8_t* addr = &(*code)[offset];
131*795d594fSAndroid Build Coastguard Worker   addr[0] = (value >> 0) & 0xff;
132*795d594fSAndroid Build Coastguard Worker   addr[1] = (value >> 8) & 0xff;
133*795d594fSAndroid Build Coastguard Worker   addr[2] = (value >> 16) & 0xff;
134*795d594fSAndroid Build Coastguard Worker   addr[3] = (value >> 24) & 0xff;
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker 
GetInsn(ArrayRef<const uint8_t> code,uint32_t offset)137*795d594fSAndroid Build Coastguard Worker uint32_t Riscv64RelativePatcher::GetInsn(ArrayRef<const uint8_t> code, uint32_t offset) {
138*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(offset + 4u, code.size());
139*795d594fSAndroid Build Coastguard Worker   DCHECK_ALIGNED(offset, 2u);
140*795d594fSAndroid Build Coastguard Worker   const uint8_t* addr = &code[offset];
141*795d594fSAndroid Build Coastguard Worker   return
142*795d594fSAndroid Build Coastguard Worker       (static_cast<uint32_t>(addr[0]) << 0) +
143*795d594fSAndroid Build Coastguard Worker       (static_cast<uint32_t>(addr[1]) << 8) +
144*795d594fSAndroid Build Coastguard Worker       (static_cast<uint32_t>(addr[2]) << 16)+
145*795d594fSAndroid Build Coastguard Worker       (static_cast<uint32_t>(addr[3]) << 24);
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker template <typename Alloc>
GetInsn(std::vector<uint8_t,Alloc> * code,uint32_t offset)149*795d594fSAndroid Build Coastguard Worker uint32_t Riscv64RelativePatcher::GetInsn(std::vector<uint8_t, Alloc>* code, uint32_t offset) {
150*795d594fSAndroid Build Coastguard Worker   return GetInsn(ArrayRef<const uint8_t>(*code), offset);
151*795d594fSAndroid Build Coastguard Worker }
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker }  // namespace linker
154*795d594fSAndroid Build Coastguard Worker }  // namespace art
155