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