1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2015 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 "linker/arm/relative_patcher_thumb2.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <sstream>
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include "arch/arm/asm_support_arm.h"
22*795d594fSAndroid Build Coastguard Worker #include "art_method.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/malloc_arena_pool.h"
25*795d594fSAndroid Build Coastguard Worker #include "driver/compiled_method.h"
26*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints_enum.h"
27*795d594fSAndroid Build Coastguard Worker #include "linker/linker_patch.h"
28*795d594fSAndroid Build Coastguard Worker #include "lock_word.h"
29*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
30*795d594fSAndroid Build Coastguard Worker #include "mirror/object.h"
31*795d594fSAndroid Build Coastguard Worker #include "read_barrier.h"
32*795d594fSAndroid Build Coastguard Worker
33*795d594fSAndroid Build Coastguard Worker namespace art {
34*795d594fSAndroid Build Coastguard Worker namespace linker {
35*795d594fSAndroid Build Coastguard Worker
36*795d594fSAndroid Build Coastguard Worker // PC displacement from patch location; Thumb2 PC is always at instruction address + 4.
37*795d594fSAndroid Build Coastguard Worker static constexpr int32_t kPcDisplacement = 4;
38*795d594fSAndroid Build Coastguard Worker
39*795d594fSAndroid Build Coastguard Worker // Maximum positive and negative displacement for method call measured from the patch location.
40*795d594fSAndroid Build Coastguard Worker // (Signed 25 bit displacement with the last bit 0 has range [-2^24, 2^24-2] measured from
41*795d594fSAndroid Build Coastguard Worker // the Thumb2 PC pointing right after the BL, i.e. 4 bytes later than the patch location.)
42*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kMaxMethodCallPositiveDisplacement = (1u << 24) - 2 + kPcDisplacement;
43*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kMaxMethodCallNegativeDisplacement = (1u << 24) - kPcDisplacement;
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard Worker // Maximum positive and negative displacement for a conditional branch measured from the patch
46*795d594fSAndroid Build Coastguard Worker // location. (Signed 21 bit displacement with the last bit 0 has range [-2^20, 2^20-2] measured
47*795d594fSAndroid Build Coastguard Worker // from the Thumb2 PC pointing right after the B.cond, i.e. 4 bytes later than the patch location.)
48*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kMaxBcondPositiveDisplacement = (1u << 20) - 2u + kPcDisplacement;
49*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kMaxBcondNegativeDisplacement = (1u << 20) - kPcDisplacement;
50*795d594fSAndroid Build Coastguard Worker
Thumb2RelativePatcher(RelativePatcherThunkProvider * thunk_provider,RelativePatcherTargetProvider * target_provider)51*795d594fSAndroid Build Coastguard Worker Thumb2RelativePatcher::Thumb2RelativePatcher(RelativePatcherThunkProvider* thunk_provider,
52*795d594fSAndroid Build Coastguard Worker RelativePatcherTargetProvider* target_provider)
53*795d594fSAndroid Build Coastguard Worker : ArmBaseRelativePatcher(thunk_provider, target_provider, InstructionSet::kThumb2) {
54*795d594fSAndroid Build Coastguard Worker }
55*795d594fSAndroid Build Coastguard Worker
PatchCall(std::vector<uint8_t> * code,uint32_t literal_offset,uint32_t patch_offset,uint32_t target_offset)56*795d594fSAndroid Build Coastguard Worker void Thumb2RelativePatcher::PatchCall(std::vector<uint8_t>* code,
57*795d594fSAndroid Build Coastguard Worker uint32_t literal_offset,
58*795d594fSAndroid Build Coastguard Worker uint32_t patch_offset,
59*795d594fSAndroid Build Coastguard Worker uint32_t target_offset) {
60*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(patch_offset, 2u);
61*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(target_offset & 1u, 1u); // Thumb2 mode bit.
62*795d594fSAndroid Build Coastguard Worker uint32_t displacement = CalculateMethodCallDisplacement(patch_offset, target_offset & ~1u);
63*795d594fSAndroid Build Coastguard Worker PatchBl(code, literal_offset, displacement);
64*795d594fSAndroid Build Coastguard Worker }
65*795d594fSAndroid Build Coastguard Worker
PatchPcRelativeReference(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset,uint32_t target_offset)66*795d594fSAndroid Build Coastguard Worker void Thumb2RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code,
67*795d594fSAndroid Build Coastguard Worker const LinkerPatch& patch,
68*795d594fSAndroid Build Coastguard Worker uint32_t patch_offset,
69*795d594fSAndroid Build Coastguard Worker uint32_t target_offset) {
70*795d594fSAndroid Build Coastguard Worker uint32_t literal_offset = patch.LiteralOffset();
71*795d594fSAndroid Build Coastguard Worker uint32_t pc_literal_offset = patch.PcInsnOffset();
72*795d594fSAndroid Build Coastguard Worker uint32_t pc_base = patch_offset + (pc_literal_offset - literal_offset) + 4u /* PC adjustment */;
73*795d594fSAndroid Build Coastguard Worker uint32_t diff = target_offset - pc_base;
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker uint32_t insn = GetInsn32(code, literal_offset);
76*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn & 0xff7ff0ffu, 0xf2400000u); // MOVW/MOVT, unpatched (imm16 == 0).
77*795d594fSAndroid Build Coastguard Worker uint32_t diff16 = ((insn & 0x00800000u) != 0u) ? (diff >> 16) : (diff & 0xffffu);
78*795d594fSAndroid Build Coastguard Worker uint32_t imm4 = (diff16 >> 12) & 0xfu;
79*795d594fSAndroid Build Coastguard Worker uint32_t imm = (diff16 >> 11) & 0x1u;
80*795d594fSAndroid Build Coastguard Worker uint32_t imm3 = (diff16 >> 8) & 0x7u;
81*795d594fSAndroid Build Coastguard Worker uint32_t imm8 = diff16 & 0xffu;
82*795d594fSAndroid Build Coastguard Worker insn = (insn & 0xfbf08f00u) | (imm << 26) | (imm4 << 16) | (imm3 << 12) | imm8;
83*795d594fSAndroid Build Coastguard Worker SetInsn32(code, literal_offset, insn);
84*795d594fSAndroid Build Coastguard Worker }
85*795d594fSAndroid Build Coastguard Worker
PatchEntrypointCall(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)86*795d594fSAndroid Build Coastguard Worker void Thumb2RelativePatcher::PatchEntrypointCall(std::vector<uint8_t>* code,
87*795d594fSAndroid Build Coastguard Worker const LinkerPatch& patch,
88*795d594fSAndroid Build Coastguard Worker uint32_t patch_offset) {
89*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(patch_offset, 2u);
90*795d594fSAndroid Build Coastguard Worker ThunkKey key = GetEntrypointCallKey(patch);
91*795d594fSAndroid Build Coastguard Worker uint32_t target_offset = GetThunkTargetOffset(key, patch_offset);
92*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(target_offset, 4u);
93*795d594fSAndroid Build Coastguard Worker uint32_t displacement = target_offset - patch_offset;
94*795d594fSAndroid Build Coastguard Worker PatchBl(code, patch.LiteralOffset(), displacement);
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker
PatchBakerReadBarrierBranch(std::vector<uint8_t> * code,const LinkerPatch & patch,uint32_t patch_offset)97*795d594fSAndroid Build Coastguard Worker void Thumb2RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
98*795d594fSAndroid Build Coastguard Worker const LinkerPatch& patch,
99*795d594fSAndroid Build Coastguard Worker uint32_t patch_offset) {
100*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(patch_offset, 2u);
101*795d594fSAndroid Build Coastguard Worker uint32_t literal_offset = patch.LiteralOffset();
102*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(literal_offset, 2u);
103*795d594fSAndroid Build Coastguard Worker DCHECK_LT(literal_offset, code->size());
104*795d594fSAndroid Build Coastguard Worker uint32_t insn = GetInsn32(code, literal_offset);
105*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(insn, 0xf0408000); // BNE +0 (unpatched)
106*795d594fSAndroid Build Coastguard Worker ThunkKey key = GetBakerThunkKey(patch);
107*795d594fSAndroid Build Coastguard Worker uint32_t target_offset = GetThunkTargetOffset(key, patch_offset);
108*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(target_offset, 4u);
109*795d594fSAndroid Build Coastguard Worker uint32_t disp = target_offset - (patch_offset + kPcDisplacement);
110*795d594fSAndroid Build Coastguard Worker DCHECK((disp >> 20) == 0u || (disp >> 20) == 0xfffu); // 21-bit signed.
111*795d594fSAndroid Build Coastguard Worker insn |= ((disp << (26 - 20)) & 0x04000000u) | // Shift bit 20 to 26, "S".
112*795d594fSAndroid Build Coastguard Worker ((disp >> (19 - 11)) & 0x00000800u) | // Shift bit 19 to 13, "J1".
113*795d594fSAndroid Build Coastguard Worker ((disp >> (18 - 13)) & 0x00002000u) | // Shift bit 18 to 11, "J2".
114*795d594fSAndroid Build Coastguard Worker ((disp << (16 - 12)) & 0x003f0000u) | // Shift bits 12-17 to 16-25, "imm6".
115*795d594fSAndroid Build Coastguard Worker ((disp >> (1 - 0)) & 0x000007ffu); // Shift bits 1-12 to 0-11, "imm11".
116*795d594fSAndroid Build Coastguard Worker SetInsn32(code, literal_offset, insn);
117*795d594fSAndroid Build Coastguard Worker }
118*795d594fSAndroid Build Coastguard Worker
MaxPositiveDisplacement(const ThunkKey & key)119*795d594fSAndroid Build Coastguard Worker uint32_t Thumb2RelativePatcher::MaxPositiveDisplacement(const ThunkKey& key) {
120*795d594fSAndroid Build Coastguard Worker switch (key.GetType()) {
121*795d594fSAndroid Build Coastguard Worker case ThunkType::kMethodCall:
122*795d594fSAndroid Build Coastguard Worker case ThunkType::kEntrypointCall:
123*795d594fSAndroid Build Coastguard Worker return kMaxMethodCallPositiveDisplacement;
124*795d594fSAndroid Build Coastguard Worker case ThunkType::kBakerReadBarrier:
125*795d594fSAndroid Build Coastguard Worker return kMaxBcondPositiveDisplacement;
126*795d594fSAndroid Build Coastguard Worker }
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker
MaxNegativeDisplacement(const ThunkKey & key)129*795d594fSAndroid Build Coastguard Worker uint32_t Thumb2RelativePatcher::MaxNegativeDisplacement(const ThunkKey& key) {
130*795d594fSAndroid Build Coastguard Worker switch (key.GetType()) {
131*795d594fSAndroid Build Coastguard Worker case ThunkType::kMethodCall:
132*795d594fSAndroid Build Coastguard Worker case ThunkType::kEntrypointCall:
133*795d594fSAndroid Build Coastguard Worker return kMaxMethodCallNegativeDisplacement;
134*795d594fSAndroid Build Coastguard Worker case ThunkType::kBakerReadBarrier:
135*795d594fSAndroid Build Coastguard Worker return kMaxBcondNegativeDisplacement;
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker
PatchBl(std::vector<uint8_t> * code,uint32_t literal_offset,uint32_t displacement)139*795d594fSAndroid Build Coastguard Worker void Thumb2RelativePatcher::PatchBl(std::vector<uint8_t>* code,
140*795d594fSAndroid Build Coastguard Worker uint32_t literal_offset,
141*795d594fSAndroid Build Coastguard Worker uint32_t displacement) {
142*795d594fSAndroid Build Coastguard Worker displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch.
143*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(displacement & 1u, 0u);
144*795d594fSAndroid Build Coastguard Worker DCHECK((displacement >> 24) == 0u || (displacement >> 24) == 255u); // 25-bit signed.
145*795d594fSAndroid Build Coastguard Worker uint32_t signbit = (displacement >> 31) & 0x1;
146*795d594fSAndroid Build Coastguard Worker uint32_t i1 = (displacement >> 23) & 0x1;
147*795d594fSAndroid Build Coastguard Worker uint32_t i2 = (displacement >> 22) & 0x1;
148*795d594fSAndroid Build Coastguard Worker uint32_t imm10 = (displacement >> 12) & 0x03ff;
149*795d594fSAndroid Build Coastguard Worker uint32_t imm11 = (displacement >> 1) & 0x07ff;
150*795d594fSAndroid Build Coastguard Worker uint32_t j1 = i1 ^ (signbit ^ 1);
151*795d594fSAndroid Build Coastguard Worker uint32_t j2 = i2 ^ (signbit ^ 1);
152*795d594fSAndroid Build Coastguard Worker uint32_t value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | imm11;
153*795d594fSAndroid Build Coastguard Worker value |= 0xf000d000; // BL
154*795d594fSAndroid Build Coastguard Worker
155*795d594fSAndroid Build Coastguard Worker // Check that we're just overwriting an existing BL.
156*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(GetInsn32(code, literal_offset) & 0xf800d000, 0xf000d000);
157*795d594fSAndroid Build Coastguard Worker // Write the new BL.
158*795d594fSAndroid Build Coastguard Worker SetInsn32(code, literal_offset, value);
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker
SetInsn32(std::vector<uint8_t> * code,uint32_t offset,uint32_t value)161*795d594fSAndroid Build Coastguard Worker void Thumb2RelativePatcher::SetInsn32(std::vector<uint8_t>* code, uint32_t offset, uint32_t value) {
162*795d594fSAndroid Build Coastguard Worker DCHECK_LE(offset + 4u, code->size());
163*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(offset, 2u);
164*795d594fSAndroid Build Coastguard Worker uint8_t* addr = &(*code)[offset];
165*795d594fSAndroid Build Coastguard Worker addr[0] = (value >> 16) & 0xff;
166*795d594fSAndroid Build Coastguard Worker addr[1] = (value >> 24) & 0xff;
167*795d594fSAndroid Build Coastguard Worker addr[2] = (value >> 0) & 0xff;
168*795d594fSAndroid Build Coastguard Worker addr[3] = (value >> 8) & 0xff;
169*795d594fSAndroid Build Coastguard Worker }
170*795d594fSAndroid Build Coastguard Worker
GetInsn32(ArrayRef<const uint8_t> code,uint32_t offset)171*795d594fSAndroid Build Coastguard Worker uint32_t Thumb2RelativePatcher::GetInsn32(ArrayRef<const uint8_t> code, uint32_t offset) {
172*795d594fSAndroid Build Coastguard Worker DCHECK_LE(offset + 4u, code.size());
173*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(offset, 2u);
174*795d594fSAndroid Build Coastguard Worker const uint8_t* addr = &code[offset];
175*795d594fSAndroid Build Coastguard Worker return
176*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(addr[0]) << 16) +
177*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(addr[1]) << 24) +
178*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(addr[2]) << 0)+
179*795d594fSAndroid Build Coastguard Worker (static_cast<uint32_t>(addr[3]) << 8);
180*795d594fSAndroid Build Coastguard Worker }
181*795d594fSAndroid Build Coastguard Worker
182*795d594fSAndroid Build Coastguard Worker template <typename Vector>
GetInsn32(Vector * code,uint32_t offset)183*795d594fSAndroid Build Coastguard Worker uint32_t Thumb2RelativePatcher::GetInsn32(Vector* code, uint32_t offset) {
184*795d594fSAndroid Build Coastguard Worker static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
185*795d594fSAndroid Build Coastguard Worker return GetInsn32(ArrayRef<const uint8_t>(*code), offset);
186*795d594fSAndroid Build Coastguard Worker }
187*795d594fSAndroid Build Coastguard Worker
GetInsn16(ArrayRef<const uint8_t> code,uint32_t offset)188*795d594fSAndroid Build Coastguard Worker uint32_t Thumb2RelativePatcher::GetInsn16(ArrayRef<const uint8_t> code, uint32_t offset) {
189*795d594fSAndroid Build Coastguard Worker DCHECK_LE(offset + 2u, code.size());
190*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(offset, 2u);
191*795d594fSAndroid Build Coastguard Worker const uint8_t* addr = &code[offset];
192*795d594fSAndroid Build Coastguard Worker return (static_cast<uint32_t>(addr[0]) << 0) + (static_cast<uint32_t>(addr[1]) << 8);
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker
195*795d594fSAndroid Build Coastguard Worker template <typename Vector>
GetInsn16(Vector * code,uint32_t offset)196*795d594fSAndroid Build Coastguard Worker uint32_t Thumb2RelativePatcher::GetInsn16(Vector* code, uint32_t offset) {
197*795d594fSAndroid Build Coastguard Worker static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
198*795d594fSAndroid Build Coastguard Worker return GetInsn16(ArrayRef<const uint8_t>(*code), offset);
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker
201*795d594fSAndroid Build Coastguard Worker } // namespace linker
202*795d594fSAndroid Build Coastguard Worker } // namespace art
203