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