blob: 6baa92de36cedcdd17fe1bb31bd0203f5817771b [file] [log] [blame]
Vladimir Markob163bb72015-03-31 21:49:49 +01001/*
2 * Copyright (C) 2015 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
Vladimir Markob163bb72015-03-31 21:49:49 +010017#include "linker/x86_64/relative_patcher_x86_64.h"
18
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070019#include "linker/relative_patcher_test.h"
20
Vladimir Markob163bb72015-03-31 21:49:49 +010021namespace art {
22namespace linker {
23
24class X86_64RelativePatcherTest : public RelativePatcherTest {
25 public:
Vladimir Marko33bff252017-11-01 14:35:42 +000026 X86_64RelativePatcherTest() : RelativePatcherTest(InstructionSet::kX86_64, "default") { }
Vladimir Markob163bb72015-03-31 21:49:49 +010027
28 protected:
29 static const uint8_t kCallRawCode[];
30 static const ArrayRef<const uint8_t> kCallCode;
31 static const uint8_t kDexCacheLoadRawCode[];
32 static const ArrayRef<const uint8_t> kDexCacheLoadCode;
Vladimir Markocac5a7e2016-02-22 10:39:50 +000033 static const uint8_t kStringReferenceRawCode[];
34 static const ArrayRef<const uint8_t> kStringReferenceCode;
Vladimir Marko4d23c9d2015-04-01 23:03:09 +010035
36 uint32_t GetMethodOffset(uint32_t method_idx) {
37 auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx));
38 CHECK(result.first);
39 return result.second;
40 }
Vladimir Markob163bb72015-03-31 21:49:49 +010041};
42
43const uint8_t X86_64RelativePatcherTest::kCallRawCode[] = {
44 0xe8, 0x00, 0x01, 0x00, 0x00
45};
46
47const ArrayRef<const uint8_t> X86_64RelativePatcherTest::kCallCode(kCallRawCode);
48
49const uint8_t X86_64RelativePatcherTest::kDexCacheLoadRawCode[] = {
50 0x8b, 0x05, // mov eax, [rip + <offset>]
51 0x00, 0x01, 0x00, 0x00
52};
53
54const ArrayRef<const uint8_t> X86_64RelativePatcherTest::kDexCacheLoadCode(
55 kDexCacheLoadRawCode);
56
Vladimir Markocac5a7e2016-02-22 10:39:50 +000057const uint8_t X86_64RelativePatcherTest::kStringReferenceRawCode[] = {
58 0x8d, 0x05, // lea eax, [rip + <offset>]
59 0x00, 0x01, 0x00, 0x00
60};
61
62const ArrayRef<const uint8_t> X86_64RelativePatcherTest::kStringReferenceCode(
63 kStringReferenceRawCode);
64
Vladimir Markob163bb72015-03-31 21:49:49 +010065TEST_F(X86_64RelativePatcherTest, CallSelf) {
66 LinkerPatch patches[] = {
Vladimir Marko4d23c9d2015-04-01 23:03:09 +010067 LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u),
Vladimir Markob163bb72015-03-31 21:49:49 +010068 };
Vladimir Markob207e142015-04-02 21:25:21 +010069 AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches));
Vladimir Markob163bb72015-03-31 21:49:49 +010070 Link();
71
72 static const uint8_t expected_code[] = {
73 0xe8, 0xfb, 0xff, 0xff, 0xff
74 };
Vladimir Marko4d23c9d2015-04-01 23:03:09 +010075 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
Vladimir Markob163bb72015-03-31 21:49:49 +010076}
77
78TEST_F(X86_64RelativePatcherTest, CallOther) {
Vladimir Marko4d23c9d2015-04-01 23:03:09 +010079 LinkerPatch method1_patches[] = {
80 LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u),
81 };
Vladimir Markob207e142015-04-02 21:25:21 +010082 AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(method1_patches));
Vladimir Marko4d23c9d2015-04-01 23:03:09 +010083 LinkerPatch method2_patches[] = {
Vladimir Markob163bb72015-03-31 21:49:49 +010084 LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u),
85 };
Vladimir Markob207e142015-04-02 21:25:21 +010086 AddCompiledMethod(MethodRef(2u), kCallCode, ArrayRef<const LinkerPatch>(method2_patches));
Vladimir Markob163bb72015-03-31 21:49:49 +010087 Link();
88
Vladimir Marko4d23c9d2015-04-01 23:03:09 +010089 uint32_t method1_offset = GetMethodOffset(1u);
90 uint32_t method2_offset = GetMethodOffset(2u);
91 uint32_t diff_after = method2_offset - (method1_offset + kCallCode.size() /* PC adjustment */);
92 static const uint8_t method1_expected_code[] = {
Vladimir Markob163bb72015-03-31 21:49:49 +010093 0xe8,
Vladimir Markocac5a7e2016-02-22 10:39:50 +000094 static_cast<uint8_t>(diff_after),
95 static_cast<uint8_t>(diff_after >> 8),
96 static_cast<uint8_t>(diff_after >> 16),
97 static_cast<uint8_t>(diff_after >> 24)
Vladimir Markob163bb72015-03-31 21:49:49 +010098 };
Vladimir Marko4d23c9d2015-04-01 23:03:09 +010099 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code)));
100 uint32_t diff_before = method1_offset - (method2_offset + kCallCode.size() /* PC adjustment */);
101 static const uint8_t method2_expected_code[] = {
102 0xe8,
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000103 static_cast<uint8_t>(diff_before),
104 static_cast<uint8_t>(diff_before >> 8),
105 static_cast<uint8_t>(diff_before >> 16),
106 static_cast<uint8_t>(diff_before >> 24)
Vladimir Marko4d23c9d2015-04-01 23:03:09 +0100107 };
108 EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code)));
Vladimir Markob163bb72015-03-31 21:49:49 +0100109}
110
111TEST_F(X86_64RelativePatcherTest, CallTrampoline) {
112 LinkerPatch patches[] = {
Vladimir Marko4d23c9d2015-04-01 23:03:09 +0100113 LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u),
Vladimir Markob163bb72015-03-31 21:49:49 +0100114 };
Vladimir Markob207e142015-04-02 21:25:21 +0100115 AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches));
Vladimir Markob163bb72015-03-31 21:49:49 +0100116 Link();
117
Vladimir Marko4d23c9d2015-04-01 23:03:09 +0100118 auto result = method_offset_map_.FindMethodOffset(MethodRef(1u));
Vladimir Markob163bb72015-03-31 21:49:49 +0100119 ASSERT_TRUE(result.first);
120 uint32_t diff = kTrampolineOffset - (result.second + kCallCode.size());
121 static const uint8_t expected_code[] = {
122 0xe8,
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000123 static_cast<uint8_t>(diff),
124 static_cast<uint8_t>(diff >> 8),
125 static_cast<uint8_t>(diff >> 16),
126 static_cast<uint8_t>(diff >> 24)
Vladimir Markob163bb72015-03-31 21:49:49 +0100127 };
Vladimir Marko4d23c9d2015-04-01 23:03:09 +0100128 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
Vladimir Markob163bb72015-03-31 21:49:49 +0100129}
130
Vladimir Marko5f078202017-05-18 13:32:53 +0100131TEST_F(X86_64RelativePatcherTest, StringBssEntry) {
132 bss_begin_ = 0x12345678;
133 constexpr size_t kStringEntryOffset = 0x1234;
134 constexpr uint32_t kStringIndex = 1u;
135 string_index_to_offset_map_.Put(kStringIndex, kStringEntryOffset);
Vladimir Markob163bb72015-03-31 21:49:49 +0100136 LinkerPatch patches[] = {
Vladimir Marko5f078202017-05-18 13:32:53 +0100137 LinkerPatch::StringBssEntryPatch(kDexCacheLoadCode.size() - 4u, nullptr, 0u, kStringIndex),
Vladimir Markob163bb72015-03-31 21:49:49 +0100138 };
Vladimir Markob207e142015-04-02 21:25:21 +0100139 AddCompiledMethod(MethodRef(1u), kDexCacheLoadCode, ArrayRef<const LinkerPatch>(patches));
Vladimir Markob163bb72015-03-31 21:49:49 +0100140 Link();
141
Vladimir Marko4d23c9d2015-04-01 23:03:09 +0100142 auto result = method_offset_map_.FindMethodOffset(MethodRef(1u));
Vladimir Markob163bb72015-03-31 21:49:49 +0100143 ASSERT_TRUE(result.first);
Vladimir Marko5f078202017-05-18 13:32:53 +0100144 uint32_t diff = bss_begin_ + kStringEntryOffset - (result.second + kDexCacheLoadCode.size());
Vladimir Markob163bb72015-03-31 21:49:49 +0100145 static const uint8_t expected_code[] = {
146 0x8b, 0x05,
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000147 static_cast<uint8_t>(diff),
148 static_cast<uint8_t>(diff >> 8),
149 static_cast<uint8_t>(diff >> 16),
150 static_cast<uint8_t>(diff >> 24)
151 };
152 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
153}
154
155TEST_F(X86_64RelativePatcherTest, StringReference) {
156 constexpr uint32_t kStringIndex = 1u;
157 constexpr uint32_t kStringOffset = 0x12345678;
158 string_index_to_offset_map_.Put(kStringIndex, kStringOffset);
159 LinkerPatch patches[] = {
160 LinkerPatch::RelativeStringPatch(
161 kStringReferenceCode.size() - 4u, nullptr, 0u, kStringIndex),
162 };
163 AddCompiledMethod(MethodRef(1u), kStringReferenceCode, ArrayRef<const LinkerPatch>(patches));
164 Link();
165
166 auto result = method_offset_map_.FindMethodOffset(MethodRef(1u));
167 ASSERT_TRUE(result.first);
168 uint32_t diff = kStringOffset - (result.second + kStringReferenceCode.size());
169 static const uint8_t expected_code[] = {
170 0x8d, 0x05,
171 static_cast<uint8_t>(diff),
172 static_cast<uint8_t>(diff >> 8),
173 static_cast<uint8_t>(diff >> 16),
174 static_cast<uint8_t>(diff >> 24)
Vladimir Markob163bb72015-03-31 21:49:49 +0100175 };
Vladimir Marko4d23c9d2015-04-01 23:03:09 +0100176 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
Vladimir Markob163bb72015-03-31 21:49:49 +0100177}
178
179} // namespace linker
180} // namespace art