1e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze/*
2e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * Copyright (C) 2016 The Android Open Source Project
3e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze *
4e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * Licensed under the Apache License, Version 2.0 (the "License");
5e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * you may not use this file except in compliance with the License.
6e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * You may obtain a copy of the License at
7e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze *
8e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze *      http://www.apache.org/licenses/LICENSE-2.0
9e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze *
10e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * Unless required by applicable law or agreed to in writing, software
11e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * distributed under the License is distributed on an "AS IS" BASIS,
12e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * See the License for the specific language governing permissions and
14e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze * limitations under the License.
15e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze */
16e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
17e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze#include "linker/mips/relative_patcher_mips.h"
18e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
19e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze#include "compiled_method.h"
201b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko#include "debug/method_debug_info.h"
21d8dbc8da0e5cc6b5c2176ce2d3877e6194d72c0cVladimir Marko#include "linker/linker_patch.h"
22e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
23e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunzenamespace art {
24e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunzenamespace linker {
25e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
26e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunzeuint32_t MipsRelativePatcher::ReserveSpace(
27e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze    uint32_t offset,
28e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze    const CompiledMethod* compiled_method ATTRIBUTE_UNUSED,
29e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze    MethodReference method_ref ATTRIBUTE_UNUSED) {
30e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  return offset;  // No space reserved; no limit on relative call distance.
31e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze}
32e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
33e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunzeuint32_t MipsRelativePatcher::ReserveSpaceEnd(uint32_t offset) {
34e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  return offset;  // No space reserved; no limit on relative call distance.
35e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze}
36e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
37e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunzeuint32_t MipsRelativePatcher::WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) {
38e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  return offset;  // No thunks added; no limit on relative call distance.
39e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze}
40e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
41e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunzevoid MipsRelativePatcher::PatchCall(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
42e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze                                    uint32_t literal_offset ATTRIBUTE_UNUSED,
43e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze                                    uint32_t patch_offset ATTRIBUTE_UNUSED,
44e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze                                    uint32_t target_offset ATTRIBUTE_UNUSED) {
45e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  UNIMPLEMENTED(FATAL) << "PatchCall unimplemented on MIPS";
46e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze}
47e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
48e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunzevoid MipsRelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code,
49e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze                                                   const LinkerPatch& patch,
50e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze                                                   uint32_t patch_offset,
51e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze                                                   uint32_t target_offset) {
52e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  uint32_t anchor_literal_offset = patch.PcInsnOffset();
53e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  uint32_t literal_offset = patch.LiteralOffset();
545fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze  bool high_patch = ((*code)[literal_offset + 0] == 0x34) && ((*code)[literal_offset + 1] == 0x12);
55e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
565fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze  // Perform basic sanity checks.
575fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze  if (high_patch) {
585fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    if (is_r6) {
595fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze      // auipc reg, offset_high
605fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze      DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
615fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze      DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
625fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    } else {
635fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze      // lui reg, offset_high
645fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze      DCHECK_EQ(((*code)[literal_offset + 2] & 0xE0), 0x00);
655fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze      DCHECK_EQ((*code)[literal_offset + 3], 0x3C);
665fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    }
67e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  } else {
686b892cd757db7e163b54c8a0ef5ba777b1a4772cAlexey Frunze    // instr reg(s), offset_low
695fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    CHECK_EQ((*code)[literal_offset + 0], 0x78);
705fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    CHECK_EQ((*code)[literal_offset + 1], 0x56);
71e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  }
72e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
73e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  // Apply patch.
74e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze  uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset;
7506a46c44bf1a5cba6c78c3faffc4e7ec1442b210Alexey Frunze  uint32_t diff = target_offset - anchor_offset;
766b892cd757db7e163b54c8a0ef5ba777b1a4772cAlexey Frunze  diff += (diff & 0x8000) << 1;  // Account for sign extension in "instr reg(s), offset_low".
77e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
785fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze  if (high_patch) {
795fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    // lui reg, offset_high / auipc reg, offset_high
805fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
815fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
825fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze  } else {
835fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    // instr reg(s), offset_low
845fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 0);
855fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze    (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 8);
865fa5c04ca39fb9c46bfef0e0807a18d0cd9a4ba7Alexey Frunze  }
87e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze}
88e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze
89f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Markovoid MipsRelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
90f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko                                                      const LinkerPatch& patch ATTRIBUTE_UNUSED,
91f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko                                                      uint32_t patch_offset ATTRIBUTE_UNUSED) {
92f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko  LOG(FATAL) << "UNIMPLEMENTED";
93f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko}
94f4f2daafb38c9c07ea74044a0fb89a2a19288b7aVladimir Marko
951b404a8b34f6fa80342955cb0a61673503328b51Vladimir Markostd::vector<debug::MethodDebugInfo> MipsRelativePatcher::GenerateThunkDebugInfo(
961b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko    uint32_t executable_offset ATTRIBUTE_UNUSED) {
971b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko  return std::vector<debug::MethodDebugInfo>();  // No thunks added.
981b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko}
991b404a8b34f6fa80342955cb0a61673503328b51Vladimir Marko
100e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze}  // namespace linker
101e3fb245fbdb5e91cf8a9750504df40bd629e0080Alexey Frunze}  // namespace art
102