10eae32dcSDimitry Andric#include "asan_mapping.h"
20eae32dcSDimitry Andric#include "sanitizer_common/sanitizer_asm.h"
30eae32dcSDimitry Andric
40eae32dcSDimitry Andric#if defined(__x86_64__)
50eae32dcSDimitry Andric#include "sanitizer_common/sanitizer_platform.h"
60eae32dcSDimitry Andric
70eae32dcSDimitry Andric.file "asan_rtl_x86_64.S"
80eae32dcSDimitry Andric
90eae32dcSDimitry Andric#define NAME(n, reg, op, s, i) n##_##op##_##i##_##s##_##reg
100eae32dcSDimitry Andric
110eae32dcSDimitry Andric#define FNAME(reg, op, s, i) NAME(__asan_check, reg, op, s, i)
120eae32dcSDimitry Andric#define RLABEL(reg, op, s, i) NAME(.return, reg, op, s, i)
130eae32dcSDimitry Andric#define CLABEL(reg, op, s, i) NAME(.check, reg, op, s, i)
140eae32dcSDimitry Andric#define FLABEL(reg, op, s, i) NAME(.fail, reg, op, s, i)
150eae32dcSDimitry Andric
160eae32dcSDimitry Andric#define BEGINF(reg, op, s, i) \
1781ad6265SDimitry Andric.section .text.FNAME(reg, op, s, i),"ax",@progbits ;\
180eae32dcSDimitry Andric.globl  FNAME(reg, op, s, i) ;\
190eae32dcSDimitry Andric.hidden  FNAME(reg, op, s, i) ;\
200eae32dcSDimitry AndricASM_TYPE_FUNCTION(FNAME(reg, op, s, i)) ;\
210eae32dcSDimitry Andric.cfi_startproc ;\
220eae32dcSDimitry AndricFNAME(reg, op, s, i): ;\
230eae32dcSDimitry Andric
240eae32dcSDimitry Andric#define ENDF .cfi_endproc ;\
250eae32dcSDimitry Andric
260eae32dcSDimitry Andric// Access check functions for 1,2 and 4 byte types, which require extra checks.
270eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, s) \
280eae32dcSDimitry Andric        mov    %##reg,%r10 ;\
290eae32dcSDimitry Andric        shr    $0x3,%r10 ;\
30*cb14a3feSDimitry Andric        .if ASAN_SHADOW_OFFSET_CONST < 0x80000000   ;\
310eae32dcSDimitry Andric        movsbl ASAN_SHADOW_OFFSET_CONST(%r10),%r10d ;\
32*cb14a3feSDimitry Andric        .else                                       ;\
33*cb14a3feSDimitry Andric        movabsq $ASAN_SHADOW_OFFSET_CONST,%r11      ;\
34*cb14a3feSDimitry Andric        movsbl (%r10,%r11),%r10d                    ;\
35*cb14a3feSDimitry Andric        .endif                                      ;\
360eae32dcSDimitry Andric        test   %r10d,%r10d ;\
370eae32dcSDimitry Andric        jne    CLABEL(reg, op, s, add) ;\
380eae32dcSDimitry AndricRLABEL(reg, op, s, add): ;\
390eae32dcSDimitry Andric        retq  ;\
400eae32dcSDimitry Andric
410eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_1(reg, op, i) \
420eae32dcSDimitry AndricCLABEL(reg, op, 1, i): ;\
435f757f3fSDimitry Andric        mov    %##reg,%r11 ;\
445f757f3fSDimitry Andric        and    $0x7,%r11d ;\
455f757f3fSDimitry Andric        cmp    %r10d,%r11d ;\
460eae32dcSDimitry Andric        jl     RLABEL(reg, op, 1, i);\
470eae32dcSDimitry Andric        mov    %##reg,%rdi ;\
4881ad6265SDimitry Andric        jmp    __asan_report_##op##1_asm ;\
490eae32dcSDimitry Andric
500eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_2(reg, op, i) \
510eae32dcSDimitry AndricCLABEL(reg, op, 2, i): ;\
525f757f3fSDimitry Andric        mov    %##reg,%r11 ;\
535f757f3fSDimitry Andric        and    $0x7,%r11d ;\
545f757f3fSDimitry Andric        add    $0x1,%r11d ;\
555f757f3fSDimitry Andric        cmp    %r10d,%r11d ;\
560eae32dcSDimitry Andric        jl     RLABEL(reg, op, 2, i);\
570eae32dcSDimitry Andric        mov    %##reg,%rdi ;\
5881ad6265SDimitry Andric        jmp    __asan_report_##op##2_asm ;\
590eae32dcSDimitry Andric
600eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_4(reg, op, i) \
610eae32dcSDimitry AndricCLABEL(reg, op, 4, i): ;\
625f757f3fSDimitry Andric        mov    %##reg,%r11 ;\
635f757f3fSDimitry Andric        and    $0x7,%r11d ;\
645f757f3fSDimitry Andric        add    $0x3,%r11d ;\
655f757f3fSDimitry Andric        cmp    %r10d,%r11d ;\
660eae32dcSDimitry Andric        jl     RLABEL(reg, op, 4, i);\
670eae32dcSDimitry Andric        mov    %##reg,%rdi ;\
6881ad6265SDimitry Andric        jmp    __asan_report_##op##4_asm ;\
690eae32dcSDimitry Andric
700eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, op) \
710eae32dcSDimitry AndricBEGINF(reg, op, 1, add) ;\
720eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 1) ;\
730eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_EXTRA_CHECK_1(reg, op, add) ;\
740eae32dcSDimitry AndricENDF
750eae32dcSDimitry Andric
760eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, op) \
770eae32dcSDimitry AndricBEGINF(reg, op, 2, add) ;\
780eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 2) ;\
790eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_EXTRA_CHECK_2(reg, op, add) ;\
800eae32dcSDimitry AndricENDF
810eae32dcSDimitry Andric
820eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, op) \
830eae32dcSDimitry AndricBEGINF(reg, op, 4, add) ;\
840eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 4) ;\
850eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_EXTRA_CHECK_4(reg, op, add) ;\
860eae32dcSDimitry AndricENDF
870eae32dcSDimitry Andric
880eae32dcSDimitry Andric// Access check functions for 8 and 16 byte types: no extra checks required.
890eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, s, c) \
900eae32dcSDimitry Andric        mov    %##reg,%r10 ;\
910eae32dcSDimitry Andric        shr    $0x3,%r10 ;\
92*cb14a3feSDimitry Andric        .if ASAN_SHADOW_OFFSET_CONST < 0x80000000  ;\
930eae32dcSDimitry Andric        ##c    $0x0,ASAN_SHADOW_OFFSET_CONST(%r10) ;\
94*cb14a3feSDimitry Andric        .else                                      ;\
95*cb14a3feSDimitry Andric        movabsq $ASAN_SHADOW_OFFSET_CONST,%r11     ;\
96*cb14a3feSDimitry Andric        ##c    $0x0,(%r10,%r11)                    ;\
97*cb14a3feSDimitry Andric        .endif                                     ;\
980eae32dcSDimitry Andric        jne    FLABEL(reg, op, s, add) ;\
990eae32dcSDimitry Andric        retq  ;\
1000eae32dcSDimitry Andric
1010eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_FAIL(reg, op, s, i) \
1020eae32dcSDimitry AndricFLABEL(reg, op, s, i): ;\
1030eae32dcSDimitry Andric        mov    %##reg,%rdi ;\
10481ad6265SDimitry Andric        jmp    __asan_report_##op##s##_asm;\
1050eae32dcSDimitry Andric
1060eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, op) \
1070eae32dcSDimitry AndricBEGINF(reg, op, 8, add) ;\
1080eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, 8, cmpb) ;\
1090eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_FAIL(reg, op, 8, add) ;\
1100eae32dcSDimitry AndricENDF
1110eae32dcSDimitry Andric
1120eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, op) \
1130eae32dcSDimitry AndricBEGINF(reg, op, 16, add) ;\
1140eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, 16, cmpw) ;\
1150eae32dcSDimitry Andric        ASAN_MEMORY_ACCESS_FAIL(reg, op, 16, add) ;\
1160eae32dcSDimitry AndricENDF
1170eae32dcSDimitry Andric
1180eae32dcSDimitry Andric#define ASAN_MEMORY_ACCESS_CALLBACKS_ADD(reg) \
1190eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, load) \
1200eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, store) \
1210eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, load) \
1220eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, store) \
1230eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, load) \
1240eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, store) \
1250eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, load) \
1260eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, store) \
1270eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, load) \
1280eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, store) \
1290eae32dcSDimitry Andric
1300eae32dcSDimitry Andric
1310eae32dcSDimitry Andric// Instantiate all but R10 and R11 callbacks. We are using PLTSafe class with
1320eae32dcSDimitry Andric// the intrinsic, which guarantees that the code generation will never emit
1330eae32dcSDimitry Andric// R10 or R11 callback.
1340eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RAX)
1350eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBX)
1360eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RCX)
1370eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDX)
1380eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RSI)
1390eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDI)
1400eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBP)
1410eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R8)
1420eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R9)
1430eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R12)
1440eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R13)
1450eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R14)
1460eae32dcSDimitry AndricASAN_MEMORY_ACCESS_CALLBACKS_ADD(R15)
1470eae32dcSDimitry Andric
1480eae32dcSDimitry Andric#endif
1490eae32dcSDimitry Andric
1500eae32dcSDimitry AndricNO_EXEC_STACK_DIRECTIVE
151