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, StringBssEntry) {
    111   bss_begin_ = 0x12345678;
    112   constexpr size_t kStringEntryOffset = 0x1234;
    113   constexpr uint32_t kStringIndex = 1u;
    114   string_index_to_offset_map_.Put(kStringIndex, kStringEntryOffset);
    115   static const uint8_t raw_code[] = {
    116       0xe8, 0x00, 0x00, 0x00, 0x00,         // call +0
    117       0x5b,                                 // pop ebx
    118       0x8b, 0x83, 0x00, 0x01, 0x00, 0x00,   // mov eax, [ebx + 256 (kDummy32BitValue)]
    119   };
    120   constexpr uint32_t anchor_offset = 5u;  // After call +0.
    121   ArrayRef<const uint8_t> code(raw_code);
    122   LinkerPatch patches[] = {
    123       LinkerPatch::StringBssEntryPatch(code.size() - 4u, nullptr, anchor_offset, kStringIndex),
    124   };
    125   AddCompiledMethod(MethodRef(1u), code, ArrayRef<const LinkerPatch>(patches));
    126   Link();
    127 
    128   auto result = method_offset_map_.FindMethodOffset(MethodRef(1u));
    129   ASSERT_TRUE(result.first);
    130   uint32_t diff = bss_begin_ + kStringEntryOffset - (result.second + anchor_offset);
    131   static const uint8_t expected_code[] = {
    132       0xe8, 0x00, 0x00, 0x00, 0x00,         // call +0
    133       0x5b,                                 // pop ebx
    134       0x8b, 0x83,                           // mov eax, [ebx + diff]
    135       static_cast<uint8_t>(diff),
    136       static_cast<uint8_t>(diff >> 8),
    137       static_cast<uint8_t>(diff >> 16),
    138       static_cast<uint8_t>(diff >> 24)
    139   };
    140   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
    141 }
    142 
    143 TEST_F(X86RelativePatcherTest, StringReference) {
    144   constexpr uint32_t kStringIndex = 1u;
    145   constexpr uint32_t kStringOffset = 0x12345678;
    146   string_index_to_offset_map_.Put(kStringIndex, kStringOffset);
    147   static const uint8_t raw_code[] = {
    148       0xe8, 0x00, 0x00, 0x00, 0x00,         // call +0
    149       0x5b,                                 // pop ebx
    150       0x8d, 0x83, 0x00, 0x01, 0x00, 0x00,   // lea eax, [ebx + 256 (kDummy32BitValue)]
    151   };
    152   constexpr uint32_t anchor_offset = 5u;  // After call +0.
    153   ArrayRef<const uint8_t> code(raw_code);
    154   LinkerPatch patches[] = {
    155       LinkerPatch::RelativeStringPatch(code.size() - 4u, nullptr, anchor_offset, kStringIndex),
    156   };
    157   AddCompiledMethod(MethodRef(1u), code, ArrayRef<const LinkerPatch>(patches));
    158   Link();
    159 
    160   auto result = method_offset_map_.FindMethodOffset(MethodRef(1u));
    161   ASSERT_TRUE(result.first);
    162   uint32_t diff = kStringOffset - (result.second + anchor_offset);
    163   static const uint8_t expected_code[] = {
    164       0xe8, 0x00, 0x00, 0x00, 0x00,         // call +0
    165       0x5b,                                 // pop ebx
    166       0x8d, 0x83,                           // lea eax, [ebx + diff]
    167       static_cast<uint8_t>(diff),
    168       static_cast<uint8_t>(diff >> 8),
    169       static_cast<uint8_t>(diff >> 16),
    170       static_cast<uint8_t>(diff >> 24)
    171   };
    172   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
    173 }
    174 
    175 }  // namespace linker
    176 }  // namespace art
    177