119f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze/* 219f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * Copyright (C) 2016 The Android Open Source Project 319f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * 419f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * Licensed under the Apache License, Version 2.0 (the "License"); 519f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * you may not use this file except in compliance with the License. 619f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * You may obtain a copy of the License at 719f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * 819f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * http://www.apache.org/licenses/LICENSE-2.0 919f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * 1019f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * Unless required by applicable law or agreed to in writing, software 1119f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * distributed under the License is distributed on an "AS IS" BASIS, 1219f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1319f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * See the License for the specific language governing permissions and 1419f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze * limitations under the License. 1519f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze */ 1619f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 1719f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze#include "linker/mips64/relative_patcher_mips64.h" 1819f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 1919f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze#include "compiled_method.h" 201b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko#include "debug/method_debug_info.h" 21d8dbc8da0e5cc6b5c2176ce2d3877e6194d72c0cVladimir Marko#include "linker/linker_patch.h" 2219f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 2319f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunzenamespace art { 2419f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunzenamespace linker { 2519f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 2619f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunzeuint32_t Mips64RelativePatcher::ReserveSpace( 2719f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze uint32_t offset, 2819f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze const CompiledMethod* compiled_method ATTRIBUTE_UNUSED, 2919f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze MethodReference method_ref ATTRIBUTE_UNUSED) { 3019f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze return offset; // No space reserved; no limit on relative call distance. 3119f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze} 3219f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 3319f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunzeuint32_t Mips64RelativePatcher::ReserveSpaceEnd(uint32_t offset) { 3419f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze return offset; // No space reserved; no limit on relative call distance. 3519f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze} 3619f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 3719f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunzeuint32_t Mips64RelativePatcher::WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) { 3819f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze return offset; // No thunks added; no limit on relative call distance. 3919f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze} 4019f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 415fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunzevoid Mips64RelativePatcher::PatchCall(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, 425fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze uint32_t literal_offset ATTRIBUTE_UNUSED, 435fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze uint32_t patch_offset ATTRIBUTE_UNUSED, 445fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze uint32_t target_offset ATTRIBUTE_UNUSED) { 455fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze UNIMPLEMENTED(FATAL) << "PatchCall unimplemented on MIPS64"; 4619f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze} 4719f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 4819f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunzevoid Mips64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, 4919f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze const LinkerPatch& patch, 5019f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze uint32_t patch_offset, 5119f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze uint32_t target_offset) { 5219f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze uint32_t anchor_literal_offset = patch.PcInsnOffset(); 5319f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze uint32_t literal_offset = patch.LiteralOffset(); 545fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze bool high_patch = ((*code)[literal_offset + 0] == 0x34) && ((*code)[literal_offset + 1] == 0x12); 5519f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 565fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze // Perform basic sanity checks. 575fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze if (high_patch) { 585fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze // auipc reg, offset_high 595fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E); 605fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC); 615fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze } else { 625fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze // instr reg(s), offset_low 635fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze CHECK_EQ((*code)[literal_offset + 0], 0x78); 645fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze CHECK_EQ((*code)[literal_offset + 1], 0x56); 655fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze } 6619f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 6719f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze // Apply patch. 6819f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset; 6919f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze uint32_t diff = target_offset - anchor_offset; 7019f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze // Note that a combination of auipc with an instruction that adds a sign-extended 7119f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze // 16-bit immediate operand (e.g. ld) provides a PC-relative range of 7219f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze // PC-0x80000000 to PC+0x7FFF7FFF on MIPS64, that is, short of 2GB on one end 7319f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze // by 32KB. 745fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze diff += (diff & 0x8000) << 1; // Account for sign extension in "instr reg(s), offset_low". 7519f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 765fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze if (high_patch) { 775fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze // auipc reg, offset_high 785fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16); 795fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24); 805fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze } else { 815fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze // instr reg(s), offset_low 825fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 0); 835fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 8); 845fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze } 8519f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze} 8619f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze 87f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Markovoid Mips64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, 88f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko const LinkerPatch& patch ATTRIBUTE_UNUSED, 89f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko uint32_t patch_offset ATTRIBUTE_UNUSED) { 90f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko LOG(FATAL) << "UNIMPLEMENTED"; 91f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko} 92f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko 931b404a8b34f6fa80342955cb0a61673503328b51Vladimir Markostd::vector<debug::MethodDebugInfo> Mips64RelativePatcher::GenerateThunkDebugInfo( 941b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko uint32_t executable_offset ATTRIBUTE_UNUSED) { 951b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko return std::vector<debug::MethodDebugInfo>(); // No thunks added. 961b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko} 971b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko 9819f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze} // namespace linker 9919f6c696bbb7a17d8ac521b316c40f9cbef32151Alexey Frunze} // namespace art 100