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