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/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