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