asan_asm_test.cc revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
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 21namespace { 22 23template<typename T> void asm_write(T *ptr, T val); 24template<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 32namespace { 33 34#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \ 35template<> 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) \ 45template<> 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 56DECLARE_ASM_WRITE(U8, "8", "movq", "r"); 57DECLARE_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 65namespace { 66 67#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \ 68template<> 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) \ 78template<> 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 95namespace { 96 97DECLARE_ASM_WRITE(U1, "1", "movb", "r"); 98DECLARE_ASM_WRITE(U2, "2", "movw", "r"); 99DECLARE_ASM_WRITE(U4, "4", "movl", "r"); 100DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x"); 101 102DECLARE_ASM_READ(U1, "1", "movb", "=r"); 103DECLARE_ASM_READ(U2, "2", "movw", "=r"); 104DECLARE_ASM_READ(U4, "4", "movl", "=r"); 105DECLARE_ASM_READ(__m128i, "16", "movaps", "=x"); 106 107template<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 116template<> 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 130template<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 138template<> 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 150U4 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 156void 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 162TEST(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 169TEST(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 187TEST(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