1*0eae32dcSDimitry Andric#include "asan_mapping.h" 2*0eae32dcSDimitry Andric#include "sanitizer_common/sanitizer_asm.h" 3*0eae32dcSDimitry Andric 4*0eae32dcSDimitry Andric#if defined(__x86_64__) 5*0eae32dcSDimitry Andric#include "sanitizer_common/sanitizer_platform.h" 6*0eae32dcSDimitry Andric 7*0eae32dcSDimitry Andric.section .text 8*0eae32dcSDimitry Andric.file "asan_rtl_x86_64.S" 9*0eae32dcSDimitry Andric 10*0eae32dcSDimitry Andric#define NAME(n, reg, op, s, i) n##_##op##_##i##_##s##_##reg 11*0eae32dcSDimitry Andric 12*0eae32dcSDimitry Andric#define FNAME(reg, op, s, i) NAME(__asan_check, reg, op, s, i) 13*0eae32dcSDimitry Andric#define RLABEL(reg, op, s, i) NAME(.return, reg, op, s, i) 14*0eae32dcSDimitry Andric#define CLABEL(reg, op, s, i) NAME(.check, reg, op, s, i) 15*0eae32dcSDimitry Andric#define FLABEL(reg, op, s, i) NAME(.fail, reg, op, s, i) 16*0eae32dcSDimitry Andric 17*0eae32dcSDimitry Andric#define BEGINF(reg, op, s, i) \ 18*0eae32dcSDimitry Andric.globl FNAME(reg, op, s, i) ;\ 19*0eae32dcSDimitry Andric.hidden FNAME(reg, op, s, i) ;\ 20*0eae32dcSDimitry AndricASM_TYPE_FUNCTION(FNAME(reg, op, s, i)) ;\ 21*0eae32dcSDimitry Andric.cfi_startproc ;\ 22*0eae32dcSDimitry AndricFNAME(reg, op, s, i): ;\ 23*0eae32dcSDimitry Andric 24*0eae32dcSDimitry Andric#define ENDF .cfi_endproc ;\ 25*0eae32dcSDimitry Andric 26*0eae32dcSDimitry Andric// Access check functions for 1,2 and 4 byte types, which require extra checks. 27*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, s) \ 28*0eae32dcSDimitry Andric mov %##reg,%r10 ;\ 29*0eae32dcSDimitry Andric shr $0x3,%r10 ;\ 30*0eae32dcSDimitry Andric movsbl ASAN_SHADOW_OFFSET_CONST(%r10),%r10d ;\ 31*0eae32dcSDimitry Andric test %r10d,%r10d ;\ 32*0eae32dcSDimitry Andric jne CLABEL(reg, op, s, add) ;\ 33*0eae32dcSDimitry AndricRLABEL(reg, op, s, add): ;\ 34*0eae32dcSDimitry Andric retq ;\ 35*0eae32dcSDimitry Andric 36*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_1(reg, op, i) \ 37*0eae32dcSDimitry AndricCLABEL(reg, op, 1, i): ;\ 38*0eae32dcSDimitry Andric push %rcx ;\ 39*0eae32dcSDimitry Andric mov %##reg,%rcx ;\ 40*0eae32dcSDimitry Andric and $0x7,%ecx ;\ 41*0eae32dcSDimitry Andric cmp %r10d,%ecx ;\ 42*0eae32dcSDimitry Andric pop %rcx ;\ 43*0eae32dcSDimitry Andric jl RLABEL(reg, op, 1, i);\ 44*0eae32dcSDimitry Andric mov %##reg,%rdi ;\ 45*0eae32dcSDimitry Andric jmp __asan_report_##op##1@PLT ;\ 46*0eae32dcSDimitry Andric 47*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_2(reg, op, i) \ 48*0eae32dcSDimitry AndricCLABEL(reg, op, 2, i): ;\ 49*0eae32dcSDimitry Andric push %rcx ;\ 50*0eae32dcSDimitry Andric mov %##reg,%rcx ;\ 51*0eae32dcSDimitry Andric and $0x7,%ecx ;\ 52*0eae32dcSDimitry Andric add $0x1,%ecx ;\ 53*0eae32dcSDimitry Andric cmp %r10d,%ecx ;\ 54*0eae32dcSDimitry Andric pop %rcx ;\ 55*0eae32dcSDimitry Andric jl RLABEL(reg, op, 2, i);\ 56*0eae32dcSDimitry Andric mov %##reg,%rdi ;\ 57*0eae32dcSDimitry Andric jmp __asan_report_##op##2@PLT ;\ 58*0eae32dcSDimitry Andric 59*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_4(reg, op, i) \ 60*0eae32dcSDimitry AndricCLABEL(reg, op, 4, i): ;\ 61*0eae32dcSDimitry Andric push %rcx ;\ 62*0eae32dcSDimitry Andric mov %##reg,%rcx ;\ 63*0eae32dcSDimitry Andric and $0x7,%ecx ;\ 64*0eae32dcSDimitry Andric add $0x3,%ecx ;\ 65*0eae32dcSDimitry Andric cmp %r10d,%ecx ;\ 66*0eae32dcSDimitry Andric pop %rcx ;\ 67*0eae32dcSDimitry Andric jl RLABEL(reg, op, 4, i);\ 68*0eae32dcSDimitry Andric mov %##reg,%rdi ;\ 69*0eae32dcSDimitry Andric jmp __asan_report_##op##4@PLT ;\ 70*0eae32dcSDimitry Andric 71*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, op) \ 72*0eae32dcSDimitry AndricBEGINF(reg, op, 1, add) ;\ 73*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 1) ;\ 74*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_EXTRA_CHECK_1(reg, op, add) ;\ 75*0eae32dcSDimitry AndricENDF 76*0eae32dcSDimitry Andric 77*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, op) \ 78*0eae32dcSDimitry AndricBEGINF(reg, op, 2, add) ;\ 79*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 2) ;\ 80*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_EXTRA_CHECK_2(reg, op, add) ;\ 81*0eae32dcSDimitry AndricENDF 82*0eae32dcSDimitry Andric 83*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, op) \ 84*0eae32dcSDimitry AndricBEGINF(reg, op, 4, add) ;\ 85*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 4) ;\ 86*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_EXTRA_CHECK_4(reg, op, add) ;\ 87*0eae32dcSDimitry AndricENDF 88*0eae32dcSDimitry Andric 89*0eae32dcSDimitry Andric// Access check functions for 8 and 16 byte types: no extra checks required. 90*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, s, c) \ 91*0eae32dcSDimitry Andric mov %##reg,%r10 ;\ 92*0eae32dcSDimitry Andric shr $0x3,%r10 ;\ 93*0eae32dcSDimitry Andric ##c $0x0,ASAN_SHADOW_OFFSET_CONST(%r10) ;\ 94*0eae32dcSDimitry Andric jne FLABEL(reg, op, s, add) ;\ 95*0eae32dcSDimitry Andric retq ;\ 96*0eae32dcSDimitry Andric 97*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_FAIL(reg, op, s, i) \ 98*0eae32dcSDimitry AndricFLABEL(reg, op, s, i): ;\ 99*0eae32dcSDimitry Andric mov %##reg,%rdi ;\ 100*0eae32dcSDimitry Andric jmp __asan_report_##op##s@PLT;\ 101*0eae32dcSDimitry Andric 102*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, op) \ 103*0eae32dcSDimitry AndricBEGINF(reg, op, 8, add) ;\ 104*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, 8, cmpb) ;\ 105*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_FAIL(reg, op, 8, add) ;\ 106*0eae32dcSDimitry AndricENDF 107*0eae32dcSDimitry Andric 108*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, op) \ 109*0eae32dcSDimitry AndricBEGINF(reg, op, 16, add) ;\ 110*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, 16, cmpw) ;\ 111*0eae32dcSDimitry Andric ASAN_MEMORY_ACCESS_FAIL(reg, op, 16, add) ;\ 112*0eae32dcSDimitry AndricENDF 113*0eae32dcSDimitry Andric 114*0eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACKS_ADD(reg) \ 115*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, load) \ 116*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, store) \ 117*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, load) \ 118*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, store) \ 119*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, load) \ 120*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, store) \ 121*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, load) \ 122*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, store) \ 123*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, load) \ 124*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, store) \ 125*0eae32dcSDimitry Andric 126*0eae32dcSDimitry Andric 127*0eae32dcSDimitry Andric// Instantiate all but R10 and R11 callbacks. We are using PLTSafe class with 128*0eae32dcSDimitry Andric// the intrinsic, which guarantees that the code generation will never emit 129*0eae32dcSDimitry Andric// R10 or R11 callback. 130*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RAX) 131*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBX) 132*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RCX) 133*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDX) 134*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RSI) 135*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDI) 136*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBP) 137*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R8) 138*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R9) 139*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R12) 140*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R13) 141*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R14) 142*0eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R15) 143*0eae32dcSDimitry Andric 144*0eae32dcSDimitry Andric#endif 145*0eae32dcSDimitry Andric 146*0eae32dcSDimitry AndricNO_EXEC_STACK_DIRECTIVE 147