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