1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "linker/mips64/relative_patcher_mips64.h" 18 19 #include "compiled_method.h" 20 #include "debug/method_debug_info.h" 21 #include "linker/linker_patch.h" 22 23 namespace art { 24 namespace linker { 25 26 uint32_t Mips64RelativePatcher::ReserveSpace( 27 uint32_t offset, 28 const CompiledMethod* compiled_method ATTRIBUTE_UNUSED, 29 MethodReference method_ref ATTRIBUTE_UNUSED) { 30 return offset; // No space reserved; no limit on relative call distance. 31 } 32 33 uint32_t Mips64RelativePatcher::ReserveSpaceEnd(uint32_t offset) { 34 return offset; // No space reserved; no limit on relative call distance. 35 } 36 37 uint32_t Mips64RelativePatcher::WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) { 38 return offset; // No thunks added; no limit on relative call distance. 39 } 40 41 void Mips64RelativePatcher::PatchCall(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, 42 uint32_t literal_offset ATTRIBUTE_UNUSED, 43 uint32_t patch_offset ATTRIBUTE_UNUSED, 44 uint32_t target_offset ATTRIBUTE_UNUSED) { 45 UNIMPLEMENTED(FATAL) << "PatchCall unimplemented on MIPS64"; 46 } 47 48 void Mips64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, 49 const LinkerPatch& patch, 50 uint32_t patch_offset, 51 uint32_t target_offset) { 52 uint32_t anchor_literal_offset = patch.PcInsnOffset(); 53 uint32_t literal_offset = patch.LiteralOffset(); 54 bool high_patch = ((*code)[literal_offset + 0] == 0x34) && ((*code)[literal_offset + 1] == 0x12); 55 56 // Perform basic sanity checks. 57 if (high_patch) { 58 // auipc reg, offset_high 59 DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E); 60 DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC); 61 } else { 62 // instr reg(s), offset_low 63 CHECK_EQ((*code)[literal_offset + 0], 0x78); 64 CHECK_EQ((*code)[literal_offset + 1], 0x56); 65 } 66 67 // Apply patch. 68 uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset; 69 uint32_t diff = target_offset - anchor_offset; 70 // Note that a combination of auipc with an instruction that adds a sign-extended 71 // 16-bit immediate operand (e.g. ld) provides a PC-relative range of 72 // PC-0x80000000 to PC+0x7FFF7FFF on MIPS64, that is, short of 2GB on one end 73 // by 32KB. 74 diff += (diff & 0x8000) << 1; // Account for sign extension in "instr reg(s), offset_low". 75 76 if (high_patch) { 77 // auipc reg, offset_high 78 (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16); 79 (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24); 80 } else { 81 // instr reg(s), offset_low 82 (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 0); 83 (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 8); 84 } 85 } 86 87 void Mips64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, 88 const LinkerPatch& patch ATTRIBUTE_UNUSED, 89 uint32_t patch_offset ATTRIBUTE_UNUSED) { 90 LOG(FATAL) << "UNIMPLEMENTED"; 91 } 92 93 std::vector<debug::MethodDebugInfo> Mips64RelativePatcher::GenerateThunkDebugInfo( 94 uint32_t executable_offset ATTRIBUTE_UNUSED) { 95 return std::vector<debug::MethodDebugInfo>(); // No thunks added. 96 } 97 98 } // namespace linker 99 } // namespace art 100