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/relative_patcher_test.h" 18 #include "linker/x86/relative_patcher_x86.h" 19 20 namespace art { 21 namespace linker { 22 23 class X86RelativePatcherTest : public RelativePatcherTest { 24 public: 25 X86RelativePatcherTest() : RelativePatcherTest(kX86, "default") { } 26 27 protected: 28 static const uint8_t kCallRawCode[]; 29 static const ArrayRef<const uint8_t> kCallCode; 30 31 uint32_t GetMethodOffset(uint32_t method_idx) { 32 auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx)); 33 CHECK(result.first); 34 return result.second; 35 } 36 }; 37 38 const uint8_t X86RelativePatcherTest::kCallRawCode[] = { 39 0xe8, 0x00, 0x01, 0x00, 0x00 40 }; 41 42 const ArrayRef<const uint8_t> X86RelativePatcherTest::kCallCode(kCallRawCode); 43 44 TEST_F(X86RelativePatcherTest, CallSelf) { 45 LinkerPatch patches[] = { 46 LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u), 47 }; 48 AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches)); 49 Link(); 50 51 static const uint8_t expected_code[] = { 52 0xe8, 0xfb, 0xff, 0xff, 0xff 53 }; 54 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); 55 } 56 57 TEST_F(X86RelativePatcherTest, CallOther) { 58 LinkerPatch method1_patches[] = { 59 LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u), 60 }; 61 AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(method1_patches)); 62 LinkerPatch method2_patches[] = { 63 LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u), 64 }; 65 AddCompiledMethod(MethodRef(2u), kCallCode, ArrayRef<const LinkerPatch>(method2_patches)); 66 Link(); 67 68 uint32_t method1_offset = GetMethodOffset(1u); 69 uint32_t method2_offset = GetMethodOffset(2u); 70 uint32_t diff_after = method2_offset - (method1_offset + kCallCode.size() /* PC adjustment */); 71 static const uint8_t method1_expected_code[] = { 72 0xe8, 73 static_cast<uint8_t>(diff_after), 74 static_cast<uint8_t>(diff_after >> 8), 75 static_cast<uint8_t>(diff_after >> 16), 76 static_cast<uint8_t>(diff_after >> 24) 77 }; 78 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code))); 79 uint32_t diff_before = method1_offset - (method2_offset + kCallCode.size() /* PC adjustment */); 80 static const uint8_t method2_expected_code[] = { 81 0xe8, 82 static_cast<uint8_t>(diff_before), 83 static_cast<uint8_t>(diff_before >> 8), 84 static_cast<uint8_t>(diff_before >> 16), 85 static_cast<uint8_t>(diff_before >> 24) 86 }; 87 EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code))); 88 } 89 90 TEST_F(X86RelativePatcherTest, CallTrampoline) { 91 LinkerPatch patches[] = { 92 LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u), 93 }; 94 AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches)); 95 Link(); 96 97 auto result = method_offset_map_.FindMethodOffset(MethodRef(1)); 98 ASSERT_TRUE(result.first); 99 uint32_t diff = kTrampolineOffset - (result.second + kCallCode.size()); 100 static const uint8_t expected_code[] = { 101 0xe8, 102 static_cast<uint8_t>(diff), 103 static_cast<uint8_t>(diff >> 8), 104 static_cast<uint8_t>(diff >> 16), 105 static_cast<uint8_t>(diff >> 24) 106 }; 107 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); 108 } 109 110 TEST_F(X86RelativePatcherTest, DexCacheReference) { 111 dex_cache_arrays_begin_ = 0x12345678; 112 constexpr size_t kElementOffset = 0x1234; 113 static const uint8_t raw_code[] = { 114 0xe8, 0x00, 0x00, 0x00, 0x00, // call +0 115 0x5b, // pop ebx 116 0x8b, 0x83, 0x00, 0x01, 0x00, 0x00, // mov eax, [ebx + 256 (kDummy32BitValue)] 117 }; 118 constexpr uint32_t anchor_offset = 5u; // After call +0. 119 ArrayRef<const uint8_t> code(raw_code); 120 LinkerPatch patches[] = { 121 LinkerPatch::DexCacheArrayPatch(code.size() - 4u, nullptr, anchor_offset, kElementOffset), 122 }; 123 AddCompiledMethod(MethodRef(1u), code, ArrayRef<const LinkerPatch>(patches)); 124 Link(); 125 126 auto result = method_offset_map_.FindMethodOffset(MethodRef(1u)); 127 ASSERT_TRUE(result.first); 128 uint32_t diff = 129 dex_cache_arrays_begin_ + kElementOffset - (result.second + anchor_offset); 130 static const uint8_t expected_code[] = { 131 0xe8, 0x00, 0x00, 0x00, 0x00, // call +0 132 0x5b, // pop ebx 133 0x8b, 0x83, // mov eax, [ebx + diff] 134 static_cast<uint8_t>(diff), 135 static_cast<uint8_t>(diff >> 8), 136 static_cast<uint8_t>(diff >> 16), 137 static_cast<uint8_t>(diff >> 24) 138 }; 139 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); 140 } 141 142 TEST_F(X86RelativePatcherTest, StringReference) { 143 constexpr uint32_t kStringIndex = 1u; 144 constexpr uint32_t kStringOffset = 0x12345678; 145 string_index_to_offset_map_.Put(kStringIndex, kStringOffset); 146 static const uint8_t raw_code[] = { 147 0xe8, 0x00, 0x00, 0x00, 0x00, // call +0 148 0x5b, // pop ebx 149 0x8d, 0x83, 0x00, 0x01, 0x00, 0x00, // lea eax, [ebx + 256 (kDummy32BitValue)] 150 }; 151 constexpr uint32_t anchor_offset = 5u; // After call +0. 152 ArrayRef<const uint8_t> code(raw_code); 153 LinkerPatch patches[] = { 154 LinkerPatch::RelativeStringPatch(code.size() - 4u, nullptr, anchor_offset, kStringIndex), 155 }; 156 AddCompiledMethod(MethodRef(1u), code, ArrayRef<const LinkerPatch>(patches)); 157 Link(); 158 159 auto result = method_offset_map_.FindMethodOffset(MethodRef(1u)); 160 ASSERT_TRUE(result.first); 161 uint32_t diff = kStringOffset - (result.second + anchor_offset); 162 static const uint8_t expected_code[] = { 163 0xe8, 0x00, 0x00, 0x00, 0x00, // call +0 164 0x5b, // pop ebx 165 0x8d, 0x83, // lea eax, [ebx + diff] 166 static_cast<uint8_t>(diff), 167 static_cast<uint8_t>(diff >> 8), 168 static_cast<uint8_t>(diff >> 16), 169 static_cast<uint8_t>(diff >> 24) 170 }; 171 EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); 172 } 173 174 } // namespace linker 175 } // namespace art 176