Home | History | Annotate | Download | only in x86
      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