1 /*
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 
17 #include "linker/x86_64/relative_patcher_x86_64.h"
18 
19 #include "linker/relative_patcher_test.h"
20 
21 namespace art {
22 namespace linker {
23 
24 class X86_64RelativePatcherTest : public RelativePatcherTest {
25  public:
X86_64RelativePatcherTest()26   X86_64RelativePatcherTest() : RelativePatcherTest(InstructionSet::kX86_64, "default") { }
27 
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;
33   static const uint8_t kStringReferenceRawCode[];
34   static const ArrayRef<const uint8_t> kStringReferenceCode;
35 
GetMethodOffset(uint32_t method_idx)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   }
41 };
42 
43 const uint8_t X86_64RelativePatcherTest::kCallRawCode[] = {
44     0xe8, 0x00, 0x01, 0x00, 0x00
45 };
46 
47 const ArrayRef<const uint8_t> X86_64RelativePatcherTest::kCallCode(kCallRawCode);
48 
49 const uint8_t X86_64RelativePatcherTest::kDexCacheLoadRawCode[] = {
50     0x8b, 0x05,  // mov eax, [rip + <offset>]
51     0x00, 0x01, 0x00, 0x00
52 };
53 
54 const ArrayRef<const uint8_t> X86_64RelativePatcherTest::kDexCacheLoadCode(
55     kDexCacheLoadRawCode);
56 
57 const uint8_t X86_64RelativePatcherTest::kStringReferenceRawCode[] = {
58     0x8d, 0x05,  // lea eax, [rip + <offset>]
59     0x00, 0x01, 0x00, 0x00
60 };
61 
62 const ArrayRef<const uint8_t> X86_64RelativePatcherTest::kStringReferenceCode(
63     kStringReferenceRawCode);
64 
TEST_F(X86_64RelativePatcherTest,CallSelf)65 TEST_F(X86_64RelativePatcherTest, CallSelf) {
66   LinkerPatch patches[] = {
67       LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u),
68   };
69   AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches));
70   Link();
71 
72   static const uint8_t expected_code[] = {
73       0xe8, 0xfb, 0xff, 0xff, 0xff
74   };
75   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
76 }
77 
TEST_F(X86_64RelativePatcherTest,CallOther)78 TEST_F(X86_64RelativePatcherTest, CallOther) {
79   LinkerPatch method1_patches[] = {
80       LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u),
81   };
82   AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(method1_patches));
83   LinkerPatch method2_patches[] = {
84       LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u),
85   };
86   AddCompiledMethod(MethodRef(2u), kCallCode, ArrayRef<const LinkerPatch>(method2_patches));
87   Link();
88 
89   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[] = {
93       0xe8,
94       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)
98   };
99   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,
103       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)
107   };
108   EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code)));
109 }
110 
TEST_F(X86_64RelativePatcherTest,CallTrampoline)111 TEST_F(X86_64RelativePatcherTest, CallTrampoline) {
112   LinkerPatch patches[] = {
113       LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u),
114   };
115   AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches));
116   Link();
117 
118   auto result = method_offset_map_.FindMethodOffset(MethodRef(1u));
119   ASSERT_TRUE(result.first);
120   uint32_t diff = kTrampolineOffset - (result.second + kCallCode.size());
121   static const uint8_t expected_code[] = {
122       0xe8,
123       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)
127   };
128   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
129 }
130 
TEST_F(X86_64RelativePatcherTest,StringBssEntry)131 TEST_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);
136   LinkerPatch patches[] = {
137       LinkerPatch::StringBssEntryPatch(kDexCacheLoadCode.size() - 4u, nullptr, 0u, kStringIndex),
138   };
139   AddCompiledMethod(MethodRef(1u), kDexCacheLoadCode, ArrayRef<const LinkerPatch>(patches));
140   Link();
141 
142   auto result = method_offset_map_.FindMethodOffset(MethodRef(1u));
143   ASSERT_TRUE(result.first);
144   uint32_t diff = bss_begin_ + kStringEntryOffset - (result.second + kDexCacheLoadCode.size());
145   static const uint8_t expected_code[] = {
146       0x8b, 0x05,
147       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 
TEST_F(X86_64RelativePatcherTest,StringReference)155 TEST_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)
175   };
176   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
177 }
178 
179 }  // namespace linker
180 }  // namespace art
181