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 #if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__)) 18 19 #include <emmintrin.h> 20 21 namespace { 22 23 template<typename T> void asm_write(T *ptr, T val); 24 template<typename T> T asm_read(T *ptr); 25 26 } // End of anonymous namespace 27 28 #endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__)) 29 30 #if defined(__x86_64__) 31 32 namespace { 33 34 #define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \ 35 template<> void asm_write<Type>(Type *ptr, Type val) { \ 36 __asm__( \ 37 Mov " %[val], (%[ptr]) \n\t" \ 38 : \ 39 : [ptr] "r" (ptr), [val] Reg (val) \ 40 : "memory" \ 41 ); \ 42 } 43 44 #define DECLARE_ASM_READ(Type, Size, Mov, Reg) \ 45 template<> Type asm_read<Type>(Type *ptr) { \ 46 Type res; \ 47 __asm__( \ 48 Mov " (%[ptr]), %[res] \n\t" \ 49 : [res] Reg (res) \ 50 : [ptr] "r" (ptr) \ 51 : "memory" \ 52 ); \ 53 return res; \ 54 } 55 56 DECLARE_ASM_WRITE(U8, "8", "movq", "r"); 57 DECLARE_ASM_READ(U8, "8", "movq", "=r"); 58 59 } // End of anonymous namespace 60 61 #endif // defined(__x86_64__) 62 63 #if defined(__i386__) && defined(__SSE2__) 64 65 namespace { 66 67 #define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \ 68 template<> void asm_write<Type>(Type *ptr, Type val) { \ 69 __asm__( \ 70 Mov " %[val], (%[ptr]) \n\t" \ 71 : \ 72 : [ptr] "r" (ptr), [val] Reg (val) \ 73 : "memory" \ 74 ); \ 75 } 76 77 #define DECLARE_ASM_READ(Type, Size, Mov, Reg) \ 78 template<> Type asm_read<Type>(Type *ptr) { \ 79 Type res; \ 80 __asm__( \ 81 Mov " (%[ptr]), %[res] \n\t" \ 82 : [res] Reg (res) \ 83 : [ptr] "r" (ptr) \ 84 : "memory" \ 85 ); \ 86 return res; \ 87 } 88 89 } // End of anonymous namespace 90 91 #endif // defined(__i386__) && defined(__SSE2__) 92 93 #if defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__)) 94 95 namespace { 96 97 DECLARE_ASM_WRITE(U1, "1", "movb", "r"); 98 DECLARE_ASM_WRITE(U2, "2", "movw", "r"); 99 DECLARE_ASM_WRITE(U4, "4", "movl", "r"); 100 DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x"); 101 102 DECLARE_ASM_READ(U1, "1", "movb", "=r"); 103 DECLARE_ASM_READ(U2, "2", "movw", "=r"); 104 DECLARE_ASM_READ(U4, "4", "movl", "=r"); 105 DECLARE_ASM_READ(__m128i, "16", "movaps", "=x"); 106 107 template<typename T> void TestAsmWrite(const char *DeathPattern) { 108 T *buf = new T; 109 EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern); 110 T var = 0x12; 111 asm_write(&var, static_cast<T>(0x21)); 112 ASSERT_EQ(static_cast<T>(0x21), var); 113 delete buf; 114 } 115 116 template<> void TestAsmWrite<__m128i>(const char *DeathPattern) { 117 char *buf = new char[16]; 118 char *p = buf + 16; 119 if (((uintptr_t) p % 16) != 0) 120 p = buf + 8; 121 assert(((uintptr_t) p % 16) == 0); 122 __m128i val = _mm_set1_epi16(0x1234); 123 EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern); 124 __m128i var = _mm_set1_epi16(0x4321); 125 asm_write(&var, val); 126 ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0)); 127 delete [] buf; 128 } 129 130 template<typename T> void TestAsmRead(const char *DeathPattern) { 131 T *buf = new T; 132 EXPECT_DEATH(asm_read(&buf[1]), DeathPattern); 133 T var = 0x12; 134 ASSERT_EQ(static_cast<T>(0x12), asm_read(&var)); 135 delete buf; 136 } 137 138 template<> void TestAsmRead<__m128i>(const char *DeathPattern) { 139 char *buf = new char[16]; 140 char *p = buf + 16; 141 if (((uintptr_t) p % 16) != 0) 142 p = buf + 8; 143 assert(((uintptr_t) p % 16) == 0); 144 EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern); 145 __m128i val = _mm_set1_epi16(0x1234); 146 ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0)); 147 delete [] buf; 148 } 149 150 U4 AsmLoad(U4 *a) { 151 U4 r; 152 __asm__("movl (%[a]), %[r] \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory"); 153 return r; 154 } 155 156 void AsmStore(U4 r, U4 *a) { 157 __asm__("movl %[r], (%[a]) \n\t" : : [a] "r" (a), [r] "r" (r) : "memory"); 158 } 159 160 } // End of anonymous namespace 161 162 TEST(AddressSanitizer, asm_load_store) { 163 U4* buf = new U4[2]; 164 EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4"); 165 EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4"); 166 delete [] buf; 167 } 168 169 TEST(AddressSanitizer, asm_rw) { 170 TestAsmWrite<U1>("WRITE of size 1"); 171 TestAsmWrite<U2>("WRITE of size 2"); 172 TestAsmWrite<U4>("WRITE of size 4"); 173 #if defined(__x86_64__) 174 TestAsmWrite<U8>("WRITE of size 8"); 175 #endif // defined(__x86_64__) 176 TestAsmWrite<__m128i>("WRITE of size 16"); 177 178 TestAsmRead<U1>("READ of size 1"); 179 TestAsmRead<U2>("READ of size 2"); 180 TestAsmRead<U4>("READ of size 4"); 181 #if defined(__x86_64__) 182 TestAsmRead<U8>("READ of size 8"); 183 #endif // defined(__x86_64__) 184 TestAsmRead<__m128i>("READ of size 16"); 185 } 186 187 TEST(AddressSanitizer, asm_flags) { 188 long magic = 0x1234; 189 long r = 0x0; 190 191 #if defined(__x86_64__) 192 __asm__("xorq %%rax, %%rax \n\t" 193 "movq (%[p]), %%rax \n\t" 194 "sete %%al \n\t" 195 "movzbq %%al, %[r] \n\t" 196 : [r] "=r"(r) 197 : [p] "r"(&magic) 198 : "rax", "memory"); 199 #else 200 __asm__("xorl %%eax, %%eax \n\t" 201 "movl (%[p]), %%eax \n\t" 202 "sete %%al \n\t" 203 "movzbl %%al, %[r] \n\t" 204 : [r] "=r"(r) 205 : [p] "r"(&magic) 206 : "eax", "memory"); 207 #endif // defined(__x86_64__) 208 209 ASSERT_EQ(0x1, r); 210 } 211 212 #endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__)) 213 214 #endif // defined(__linux__) 215