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