blob: 335ce2e476814fc7eca4df591484fb2602a8f07c [file] [log] [blame]
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001/*
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/relative_patcher_test.h"
18#include "linker/mips/relative_patcher_mips.h"
19
20namespace art {
21namespace linker {
22
23// We'll maximize the range of a single load instruction for dex cache array accesses
24// by aligning offset -32768 with the offset of the first used element.
25static constexpr uint32_t kDexCacheArrayLwOffset = 0x8000;
26
27class MipsRelativePatcherTest : public RelativePatcherTest {
28 public:
29 MipsRelativePatcherTest() : RelativePatcherTest(kMips, "mips32r2") {}
30
31 protected:
Alexey Frunze06a46c42016-07-19 15:00:40 -070032 static const uint8_t UnpatchedPcRelativeRawCode[];
33 static const uint32_t LiteralOffset;
34 static const uint32_t AnchorOffset;
35 static const ArrayRef<const uint8_t> UnpatchedPcRelativeCode;
36
Alexey Frunzee3fb2452016-05-10 16:08:05 -070037 uint32_t GetMethodOffset(uint32_t method_idx) {
38 auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx));
39 CHECK(result.first);
40 return result.second;
41 }
Alexey Frunze06a46c42016-07-19 15:00:40 -070042
43 void CheckPcRelativePatch(const ArrayRef<const LinkerPatch>& patches, uint32_t target_offset);
44 void TestDexCacheReference(uint32_t dex_cache_arrays_begin, uint32_t element_offset);
45 void TestStringReference(uint32_t string_offset);
Alexey Frunzee3fb2452016-05-10 16:08:05 -070046};
47
Alexey Frunze06a46c42016-07-19 15:00:40 -070048const uint8_t MipsRelativePatcherTest::UnpatchedPcRelativeRawCode[] = {
49 0x00, 0x00, 0x10, 0x04, // nal
50 0x34, 0x12, 0x12, 0x3C, // lui s2, high(diff); placeholder = 0x1234
51 0x78, 0x56, 0x52, 0x36, // ori s2, s2, low(diff); placeholder = 0x5678
52 0x21, 0x90, 0x5F, 0x02, // addu s2, s2, ra
53};
54const uint32_t MipsRelativePatcherTest::LiteralOffset = 4; // At lui (where patching starts).
55const uint32_t MipsRelativePatcherTest::AnchorOffset = 8; // At ori (where PC+0 points).
56const ArrayRef<const uint8_t> MipsRelativePatcherTest::UnpatchedPcRelativeCode(
57 UnpatchedPcRelativeRawCode);
58
59void MipsRelativePatcherTest::CheckPcRelativePatch(const ArrayRef<const LinkerPatch>& patches,
60 uint32_t target_offset) {
61 AddCompiledMethod(MethodRef(1u), UnpatchedPcRelativeCode, ArrayRef<const LinkerPatch>(patches));
Alexey Frunzee3fb2452016-05-10 16:08:05 -070062 Link();
63
64 auto result = method_offset_map_.FindMethodOffset(MethodRef(1u));
65 ASSERT_TRUE(result.first);
Alexey Frunze06a46c42016-07-19 15:00:40 -070066
67 uint32_t diff = target_offset - (result.second + AnchorOffset);
68 if (patches[0].GetType() == LinkerPatch::Type::kDexCacheArray) {
69 diff += kDexCacheArrayLwOffset;
70 }
71
72 const uint8_t expected_code[] = {
Alexey Frunzee3fb2452016-05-10 16:08:05 -070073 0x00, 0x00, 0x10, 0x04,
74 static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x12, 0x3C,
75 static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x36,
76 0x21, 0x90, 0x5F, 0x02,
77 };
78 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
79}
80
Alexey Frunze06a46c42016-07-19 15:00:40 -070081void MipsRelativePatcherTest::TestDexCacheReference(uint32_t dex_cache_arrays_begin,
82 uint32_t element_offset) {
83 dex_cache_arrays_begin_ = dex_cache_arrays_begin;
84 LinkerPatch patches[] = {
85 LinkerPatch::DexCacheArrayPatch(LiteralOffset, nullptr, AnchorOffset, element_offset)
86 };
87 CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches),
88 dex_cache_arrays_begin_ + element_offset);
89}
90
91void MipsRelativePatcherTest::TestStringReference(uint32_t string_offset) {
92 constexpr uint32_t kStringIndex = 1u;
93 string_index_to_offset_map_.Put(kStringIndex, string_offset);
94 LinkerPatch patches[] = {
95 LinkerPatch::RelativeStringPatch(LiteralOffset, nullptr, AnchorOffset, kStringIndex)
96 };
97 CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), string_offset);
98}
99
100TEST_F(MipsRelativePatcherTest, DexCacheReference) {
101 TestDexCacheReference(/* dex_cache_arrays_begin */ 0x12345678, /* element_offset */ 0x1234);
102}
103
104TEST_F(MipsRelativePatcherTest, StringReference) {
105 TestStringReference(/* string_offset*/ 0x87651234);
106}
107
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700108} // namespace linker
109} // namespace art