Home | History | Annotate | Line # | Download | only in tests
      1 //===-- asan_asm_test.cc --------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is a part of AddressSanitizer, an address sanity checker.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 #include "asan_test_utils.h"
     14 
     15 #if defined(__linux__) &&                                                      \
     16     (!defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3)
     17 
     18 // Assembly instrumentation is broken on x86 Android (x86 + PIC + shared runtime
     19 // library). See https://github.com/google/sanitizers/issues/353
     20 #if defined(__x86_64__) ||                                                     \
     21     (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))
     22 
     23 #include <emmintrin.h>
     24 
     25 namespace {
     26 
     27 template<typename T> void asm_write(T *ptr, T val);
     28 template<typename T> T asm_read(T *ptr);
     29 template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);
     30 
     31 } // End of anonymous namespace
     32 
     33 #endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
     34 
     35 #if defined(__x86_64__)
     36 
     37 namespace {
     38 
     39 #define DECLARE_ASM_WRITE(Type, Size, Mov, Reg)        \
     40 template<> void asm_write<Type>(Type *ptr, Type val) { \
     41   __asm__(                                             \
     42     Mov " %[val], (%[ptr])  \n\t"                      \
     43     :                                                  \
     44     : [ptr] "r" (ptr), [val] Reg (val)                 \
     45     : "memory"                                         \
     46   );                                                   \
     47 }
     48 
     49 #define DECLARE_ASM_READ(Type, Size, Mov, Reg)     \
     50 template<> Type asm_read<Type>(Type *ptr) {        \
     51   Type res;                                        \
     52   __asm__(                                         \
     53     Mov " (%[ptr]), %[res]  \n\t"                  \
     54     : [res] Reg (res)                              \
     55     : [ptr] "r" (ptr)                              \
     56     : "memory"                                     \
     57   );                                               \
     58   return res;                                      \
     59 }
     60 
     61 #define DECLARE_ASM_REP_MOVS(Type, Movs)                         \
     62   template <>                                                    \
     63   void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
     64     __asm__("rep " Movs " \n\t"                                  \
     65             : "+D"(dst), "+S"(src), "+c"(size)                   \
     66             :                                                    \
     67             : "memory");                                         \
     68   }
     69 
     70 DECLARE_ASM_WRITE(U8, "8", "movq", "r");
     71 DECLARE_ASM_READ(U8, "8", "movq", "=r");
     72 DECLARE_ASM_REP_MOVS(U8, "movsq");
     73 
     74 } // End of anonymous namespace
     75 
     76 #endif // defined(__x86_64__)
     77 
     78 #if defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__)
     79 
     80 namespace {
     81 
     82 #define DECLARE_ASM_WRITE(Type, Size, Mov, Reg)        \
     83 template<> void asm_write<Type>(Type *ptr, Type val) { \
     84   __asm__(                                             \
     85     Mov " %[val], (%[ptr])  \n\t"                      \
     86     :                                                  \
     87     : [ptr] "r" (ptr), [val] Reg (val)                 \
     88     : "memory"                                         \
     89   );                                                   \
     90 }
     91 
     92 #define DECLARE_ASM_READ(Type, Size, Mov, Reg)     \
     93 template<> Type asm_read<Type>(Type *ptr) {        \
     94   Type res;                                        \
     95   __asm__(                                         \
     96     Mov " (%[ptr]), %[res]  \n\t"                  \
     97     : [res] Reg (res)                              \
     98     : [ptr] "r" (ptr)                              \
     99     : "memory"                                     \
    100   );                                               \
    101   return res;                                      \
    102 }
    103 
    104 #define DECLARE_ASM_REP_MOVS(Type, Movs)                         \
    105   template <>                                                    \
    106   void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
    107     __asm__("rep " Movs " \n\t"                                  \
    108             : "+D"(dst), "+S"(src), "+c"(size)                   \
    109             :                                                    \
    110             : "memory");                                         \
    111   }
    112 
    113 } // End of anonymous namespace
    114 
    115 #endif  // defined(__i386__) && defined(__SSE2__)
    116 
    117 #if defined(__x86_64__) ||                                                     \
    118     (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))
    119 
    120 namespace {
    121 
    122 DECLARE_ASM_WRITE(U1, "1", "movb", "r");
    123 DECLARE_ASM_WRITE(U2, "2", "movw", "r");
    124 DECLARE_ASM_WRITE(U4, "4", "movl", "r");
    125 DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");
    126 
    127 DECLARE_ASM_READ(U1, "1", "movb", "=r");
    128 DECLARE_ASM_READ(U2, "2", "movw", "=r");
    129 DECLARE_ASM_READ(U4, "4", "movl", "=r");
    130 DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");
    131 
    132 DECLARE_ASM_REP_MOVS(U1, "movsb");
    133 DECLARE_ASM_REP_MOVS(U2, "movsw");
    134 DECLARE_ASM_REP_MOVS(U4, "movsl");
    135 
    136 template<typename T> void TestAsmWrite(const char *DeathPattern) {
    137   T *buf = new T;
    138   EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
    139   T var = 0x12;
    140   asm_write(&var, static_cast<T>(0x21));
    141   ASSERT_EQ(static_cast<T>(0x21), var);
    142   delete buf;
    143 }
    144 
    145 template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
    146   char *buf = new char[16];
    147   char *p = buf + 16;
    148   if (((uintptr_t) p % 16) != 0)
    149     p = buf + 8;
    150   assert(((uintptr_t) p % 16) == 0);
    151   __m128i val = _mm_set1_epi16(0x1234);
    152   EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
    153   __m128i var = _mm_set1_epi16(0x4321);
    154   asm_write(&var, val);
    155   ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
    156   delete [] buf;
    157 }
    158 
    159 template<typename T> void TestAsmRead(const char *DeathPattern) {
    160   T *buf = new T;
    161   EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
    162   T var = 0x12;
    163   ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
    164   delete buf;
    165 }
    166 
    167 template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
    168   char *buf = new char[16];
    169   char *p = buf + 16;
    170   if (((uintptr_t) p % 16) != 0)
    171     p = buf + 8;
    172   assert(((uintptr_t) p % 16) == 0);
    173   EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
    174   __m128i val = _mm_set1_epi16(0x1234);
    175   ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
    176   delete [] buf;
    177 }
    178 
    179 U4 AsmLoad(U4 *a) {
    180   U4 r;
    181   __asm__("movl (%[a]), %[r]  \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
    182   return r;
    183 }
    184 
    185 void AsmStore(U4 r, U4 *a) {
    186   __asm__("movl %[r], (%[a])  \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
    187 }
    188 
    189 template <typename T>
    190 void TestAsmRepMovs(const char *DeathPatternRead,
    191                     const char *DeathPatternWrite) {
    192   T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
    193   T dst_good[4] = {};
    194   asm_rep_movs(dst_good, src_good, 4);
    195   ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
    196   ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
    197   ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
    198   ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);
    199 
    200   T dst_bad[3];
    201   EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);
    202 
    203   T src_bad[3] = { 0x0, 0x1, 0x2 };
    204   EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);
    205 
    206   T* dp = dst_bad + 4;
    207   T* sp = src_bad + 4;
    208   asm_rep_movs(dp, sp, 0);
    209 }
    210 
    211 } // End of anonymous namespace
    212 
    213 TEST(AddressSanitizer, asm_load_store) {
    214   U4* buf = new U4[2];
    215   EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
    216   EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
    217   delete [] buf;
    218 }
    219 
    220 TEST(AddressSanitizer, asm_rw) {
    221   TestAsmWrite<U1>("WRITE of size 1");
    222   TestAsmWrite<U2>("WRITE of size 2");
    223   TestAsmWrite<U4>("WRITE of size 4");
    224 #if defined(__x86_64__)
    225   TestAsmWrite<U8>("WRITE of size 8");
    226 #endif // defined(__x86_64__)
    227   TestAsmWrite<__m128i>("WRITE of size 16");
    228 
    229   TestAsmRead<U1>("READ of size 1");
    230   TestAsmRead<U2>("READ of size 2");
    231   TestAsmRead<U4>("READ of size 4");
    232 #if defined(__x86_64__)
    233   TestAsmRead<U8>("READ of size 8");
    234 #endif // defined(__x86_64__)
    235   TestAsmRead<__m128i>("READ of size 16");
    236 }
    237 
    238 TEST(AddressSanitizer, asm_flags) {
    239   long magic = 0x1234;
    240   long r = 0x0;
    241 
    242 #if defined(__x86_64__) && !defined(__ILP32__)
    243   __asm__("xorq %%rax, %%rax  \n\t"
    244           "movq (%[p]), %%rax \n\t"
    245           "sete %%al          \n\t"
    246           "movzbq %%al, %[r]  \n\t"
    247           : [r] "=r"(r)
    248           : [p] "r"(&magic)
    249           : "rax", "memory");
    250 #else
    251   __asm__("xorl %%eax, %%eax  \n\t"
    252           "movl (%[p]), %%eax \n\t"
    253           "sete %%al          \n\t"
    254           "movzbl %%al, %[r]  \n\t"
    255           : [r] "=r"(r)
    256           : [p] "r"(&magic)
    257           : "eax", "memory");
    258 #endif // defined(__x86_64__) && !defined(__ILP32__)
    259 
    260   ASSERT_EQ(0x1, r);
    261 }
    262 
    263 TEST(AddressSanitizer, asm_rep_movs) {
    264   TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
    265   TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
    266   TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
    267 #if defined(__x86_64__)
    268   TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
    269 #endif  // defined(__x86_64__)
    270 }
    271 
    272 #endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
    273 
    274 #endif // defined(__linux__)
    275