2018-06-02 08:44:04 -04:00
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* rseq - x86 . h
*
* ( C ) Copyright 2016 - 2018 - Mathieu Desnoyers < mathieu . desnoyers @ efficios . com >
*/
# include <stdint.h>
2019-04-29 11:27:57 -04:00
/*
* RSEQ_SIG is used with the following reserved undefined instructions , which
* trap in user - space :
*
* x86 - 32 : 0f b9 3 d 53 30 05 53 ud1 0x53053053 , % edi
* x86 - 64 : 0f b9 3 d 53 30 05 53 ud1 0x53053053 ( % rip ) , % edi
*/
2018-06-02 08:44:04 -04:00
# define RSEQ_SIG 0x53053053
2019-04-29 11:27:52 -04:00
/*
* Due to a compiler optimization bug in gcc - 8 with asm goto and TLS asm input
* operands , we cannot use " m " input operands , and rather pass the __rseq_abi
* address through a " r " input operand .
*/
/* Offset of cpu_id and rseq_cs fields in struct rseq. */
# define RSEQ_CPU_ID_OFFSET 4
# define RSEQ_CS_OFFSET 8
2018-06-02 08:44:04 -04:00
# ifdef __x86_64__
2022-01-24 12:12:52 -05:00
# define RSEQ_ASM_TP_SEGMENT %%fs
2018-06-02 08:44:04 -04:00
# define rseq_smp_mb() \
__asm__ __volatile__ ( " lock; addl $0,-128(%%rsp) " : : : " memory " , " cc " )
# define rseq_smp_rmb() rseq_barrier()
# define rseq_smp_wmb() rseq_barrier()
# define rseq_smp_load_acquire(p) \
__extension__ ( { \
__typeof ( * p ) ____p1 = RSEQ_READ_ONCE ( * p ) ; \
rseq_barrier ( ) ; \
____p1 ; \
} )
# define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
# define rseq_smp_store_release(p, v) \
do { \
rseq_barrier ( ) ; \
RSEQ_WRITE_ONCE ( * p , v ) ; \
} while ( 0 )
# ifdef RSEQ_SKIP_FASTPATH
# include "rseq-skip.h"
# else /* !RSEQ_SKIP_FASTPATH */
# define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
start_ip , post_commit_offset , abort_ip ) \
2019-04-29 11:27:54 -04:00
" .pushsection __rseq_cs, \" aw \" \n \t " \
2018-06-02 08:44:04 -04:00
" .balign 32 \n \t " \
__rseq_str ( label ) " : \n \t " \
" .long " __rseq_str ( version ) " , " __rseq_str ( flags ) " \n \t " \
" .quad " __rseq_str ( start_ip ) " , " __rseq_str ( post_commit_offset ) " , " __rseq_str ( abort_ip ) " \n \t " \
2019-04-29 11:27:54 -04:00
" .popsection \n \t " \
" .pushsection __rseq_cs_ptr_array, \" aw \" \n \t " \
" .quad " __rseq_str ( label ) " b \n \t " \
2018-06-02 08:44:04 -04:00
" .popsection \n \t "
2019-04-29 11:27:54 -04:00
2018-06-02 08:44:04 -04:00
# define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
__RSEQ_ASM_DEFINE_TABLE ( label , 0x0 , 0x0 , start_ip , \
( post_commit_ip - start_ip ) , abort_ip )
2019-04-29 11:27:53 -04:00
/*
* Exit points of a rseq critical section consist of all instructions outside
* of the critical section where a critical section can either branch to or
* reach through the normal course of its execution . The abort IP and the
2019-04-29 11:27:54 -04:00
* post - commit IP are already part of the __rseq_cs section and should not be
* explicitly defined as additional exit points . Knowing all exit points is
2019-04-29 11:27:53 -04:00
* useful to assist debuggers stepping over the critical section .
*/
# define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
" .pushsection __rseq_exit_point_array, \" aw \" \n \t " \
" .quad " __rseq_str ( start_ip ) " , " __rseq_str ( exit_ip ) " \n \t " \
" .popsection \n \t "
2018-06-02 08:44:04 -04:00
# define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
RSEQ_INJECT_ASM ( 1 ) \
" leaq " __rseq_str ( cs_label ) " (%%rip), %%rax \n \t " \
2019-04-29 11:27:52 -04:00
" movq %%rax, " __rseq_str ( rseq_cs ) " \n \t " \
2018-06-02 08:44:04 -04:00
__rseq_str ( label ) " : \n \t "
# define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
RSEQ_INJECT_ASM ( 2 ) \
2019-04-29 11:27:52 -04:00
" cmpl %[ " __rseq_str ( cpu_id ) " ], " __rseq_str ( current_cpu_id ) " \n \t " \
2018-06-02 08:44:04 -04:00
" jnz " __rseq_str ( label ) " \n \t "
# define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
" .pushsection __rseq_failure, \" ax \" \n \t " \
2019-04-29 11:27:57 -04:00
/* Disassembler-friendly signature: ud1 <sig>(%rip),%edi. */ \
" .byte 0x0f, 0xb9, 0x3d \n \t " \
2018-06-02 08:44:04 -04:00
" .long " __rseq_str ( RSEQ_SIG ) " \n \t " \
__rseq_str ( label ) " : \n \t " \
teardown \
" jmp %l[ " __rseq_str ( abort_label ) " ] \n \t " \
" .popsection \n \t "
# define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
" .pushsection __rseq_failure, \" ax \" \n \t " \
__rseq_str ( label ) " : \n \t " \
teardown \
" jmp %l[ " __rseq_str ( cmpfail_label ) " ] \n \t " \
" .popsection \n \t "
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_storev ( intptr_t * v , intptr_t expect , intptr_t newv , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:52 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" cmpq %[v], %[expect] \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:52 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" cmpq %[v], %[expect] \n \t "
" jnz %l[error2] \n \t "
# endif
/* final store */
" movq %[newv], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 5 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-02-03 10:05:32 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
[ v ] " m " ( * v ) ,
[ expect ] " r " ( expect ) ,
[ newv ] " r " ( newv )
: " memory " , " cc " , " rax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
/*
* Compare @ v against @ expectnot . When it does _not_ match , load @ v
* into @ load , and store the content of * @ v + voffp into @ v .
*/
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpnev_storeoffp_load ( intptr_t * v , intptr_t expectnot ,
2022-01-24 12:12:48 -05:00
long voffp , intptr_t * load , int cpu )
2018-06-02 08:44:04 -04:00
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:52 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" movq %[v], %%rbx \n \t "
" cmpq %%rbx, %[expectnot] \n \t "
" je %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:52 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" movq %[v], %%rbx \n \t "
" cmpq %%rbx, %[expectnot] \n \t "
" je %l[error2] \n \t "
# endif
" movq %%rbx, %[load] \n \t "
" addq %[voffp], %%rbx \n \t "
" movq (%%rbx), %%rbx \n \t "
/* final store */
" movq %%rbx, %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 5 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-02-03 10:05:32 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* final store input */
[ v ] " m " ( * v ) ,
[ expectnot ] " r " ( expectnot ) ,
[ voffp ] " er " ( voffp ) ,
[ load ] " m " ( * load )
: " memory " , " cc " , " rax " , " rbx "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
static inline __attribute__ ( ( always_inline ) )
int rseq_addv ( intptr_t * v , intptr_t count , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:52 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:52 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
# endif
/* final store */
" addq %[count], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 4 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-02-03 10:05:32 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* final store input */
[ v ] " m " ( * v ) ,
[ count ] " er " ( count )
: " memory " , " cc " , " rax "
RSEQ_INJECT_CLOBBER
: abort
2020-09-23 16:36:17 -07:00
# ifdef RSEQ_COMPARE_TWICE
, error1
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2020-09-23 16:36:17 -07:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2020-09-23 16:36:17 -07:00
RSEQ_INJECT_FAILED
return - 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2020-09-23 16:36:17 -07:00
rseq_bug ( " cpu_id comparison failed " ) ;
# endif
}
# define RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
/*
* pval = * ( ptr + off )
* * pval + = inc ;
*/
static inline __attribute__ ( ( always_inline ) )
2022-01-24 12:12:48 -05:00
int rseq_offset_deref_addv ( intptr_t * ptr , long off , intptr_t inc , int cpu )
2020-09-23 16:36:17 -07:00
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
# endif
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:52 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2020-09-23 16:36:17 -07:00
RSEQ_INJECT_ASM ( 3 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:52 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2020-09-23 16:36:17 -07:00
# endif
/* get p+v */
" movq %[ptr], %%rbx \n \t "
" addq %[off], %%rbx \n \t "
/* get pv */
" movq (%%rbx), %%rcx \n \t "
/* *pv += inc */
" addq %[inc], (%%rcx) \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 4 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-02-03 10:05:32 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2020-09-23 16:36:17 -07:00
/* final store input */
[ ptr ] " m " ( * ptr ) ,
[ off ] " er " ( off ) ,
[ inc ] " er " ( inc )
: " memory " , " cc " , " rax " , " rbx " , " rcx "
RSEQ_INJECT_CLOBBER
: abort
2018-06-02 08:44:04 -04:00
# ifdef RSEQ_COMPARE_TWICE
, error1
# endif
) ;
return 0 ;
abort :
RSEQ_INJECT_FAILED
return - 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
rseq_bug ( " cpu_id comparison failed " ) ;
# endif
}
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_trystorev_storev ( intptr_t * v , intptr_t expect ,
intptr_t * v2 , intptr_t newv2 ,
intptr_t newv , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:52 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" cmpq %[v], %[expect] \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:52 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" cmpq %[v], %[expect] \n \t "
" jnz %l[error2] \n \t "
# endif
/* try store */
" movq %[newv2], %[v2] \n \t "
RSEQ_INJECT_ASM ( 5 )
/* final store */
" movq %[newv], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 6 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-02-03 10:05:32 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* try store input */
[ v2 ] " m " ( * v2 ) ,
[ newv2 ] " r " ( newv2 ) ,
/* final store input */
[ v ] " m " ( * v ) ,
[ expect ] " r " ( expect ) ,
[ newv ] " r " ( newv )
: " memory " , " cc " , " rax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
/* x86-64 is TSO. */
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_trystorev_storev_release ( intptr_t * v , intptr_t expect ,
intptr_t * v2 , intptr_t newv2 ,
intptr_t newv , int cpu )
{
return rseq_cmpeqv_trystorev_storev ( v , expect , v2 , newv2 , newv , cpu ) ;
}
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_cmpeqv_storev ( intptr_t * v , intptr_t expect ,
intptr_t * v2 , intptr_t expect2 ,
intptr_t newv , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error3 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:52 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" cmpq %[v], %[expect] \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
" cmpq %[v2], %[expect2] \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 5 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:52 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" cmpq %[v], %[expect] \n \t "
" jnz %l[error2] \n \t "
" cmpq %[v2], %[expect2] \n \t "
" jnz %l[error3] \n \t "
# endif
/* final store */
" movq %[newv], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 6 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-02-03 10:05:32 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* cmp2 input */
[ v2 ] " m " ( * v2 ) ,
[ expect2 ] " r " ( expect2 ) ,
/* final store input */
[ v ] " m " ( * v ) ,
[ expect ] " r " ( expect ) ,
[ newv ] " r " ( newv )
: " memory " , " cc " , " rax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2 , error3
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " 1st expected value comparison failed " ) ;
error3 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " 2nd expected value comparison failed " ) ;
# endif
}
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_trymemcpy_storev ( intptr_t * v , intptr_t expect ,
void * dst , void * src , size_t len ,
intptr_t newv , int cpu )
{
uint64_t rseq_scratch [ 3 ] ;
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
" movq %[src], %[rseq_scratch0] \n \t "
" movq %[dst], %[rseq_scratch1] \n \t "
" movq %[len], %[rseq_scratch2] \n \t "
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:52 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" cmpq %[v], %[expect] \n \t "
" jnz 5f \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:52 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 6f )
2018-06-02 08:44:04 -04:00
" cmpq %[v], %[expect] \n \t "
" jnz 7f \n \t "
# endif
/* try memcpy */
" test %[len], %[len] \n \t " \
" jz 333f \n \t " \
" 222: \n \t " \
" movb (%[src]), %%al \n \t " \
" movb %%al, (%[dst]) \n \t " \
" inc %[src] \n \t " \
" inc %[dst] \n \t " \
" dec %[len] \n \t " \
" jnz 222b \n \t " \
" 333: \n \t " \
RSEQ_INJECT_ASM ( 5 )
/* final store */
" movq %[newv], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 6 )
/* teardown */
" movq %[rseq_scratch2], %[len] \n \t "
" movq %[rseq_scratch1], %[dst] \n \t "
" movq %[rseq_scratch0], %[src] \n \t "
RSEQ_ASM_DEFINE_ABORT ( 4 ,
" movq %[rseq_scratch2], %[len] \n \t "
" movq %[rseq_scratch1], %[dst] \n \t "
" movq %[rseq_scratch0], %[src] \n \t " ,
abort )
RSEQ_ASM_DEFINE_CMPFAIL ( 5 ,
" movq %[rseq_scratch2], %[len] \n \t "
" movq %[rseq_scratch1], %[dst] \n \t "
" movq %[rseq_scratch0], %[src] \n \t " ,
cmpfail )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_CMPFAIL ( 6 ,
" movq %[rseq_scratch2], %[len] \n \t "
" movq %[rseq_scratch1], %[dst] \n \t "
" movq %[rseq_scratch0], %[src] \n \t " ,
error1 )
RSEQ_ASM_DEFINE_CMPFAIL ( 7 ,
" movq %[rseq_scratch2], %[len] \n \t "
" movq %[rseq_scratch1], %[dst] \n \t "
" movq %[rseq_scratch0], %[src] \n \t " ,
error2 )
# endif
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-02-03 10:05:32 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* final store input */
[ v ] " m " ( * v ) ,
[ expect ] " r " ( expect ) ,
[ newv ] " r " ( newv ) ,
/* try memcpy input */
[ dst ] " r " ( dst ) ,
[ src ] " r " ( src ) ,
[ len ] " r " ( len ) ,
[ rseq_scratch0 ] " m " ( rseq_scratch [ 0 ] ) ,
[ rseq_scratch1 ] " m " ( rseq_scratch [ 1 ] ) ,
[ rseq_scratch2 ] " m " ( rseq_scratch [ 2 ] )
: " memory " , " cc " , " rax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
/* x86-64 is TSO. */
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_trymemcpy_storev_release ( intptr_t * v , intptr_t expect ,
void * dst , void * src , size_t len ,
intptr_t newv , int cpu )
{
return rseq_cmpeqv_trymemcpy_storev ( v , expect , dst , src , len ,
newv , cpu ) ;
}
# endif /* !RSEQ_SKIP_FASTPATH */
2022-01-24 12:12:49 -05:00
# elif defined(__i386__)
2018-06-02 08:44:04 -04:00
2022-01-24 12:12:53 -05:00
# define RSEQ_ASM_TP_SEGMENT %%gs
2018-06-02 08:44:04 -04:00
# define rseq_smp_mb() \
__asm__ __volatile__ ( " lock; addl $0,-128(%%esp) " : : : " memory " , " cc " )
# define rseq_smp_rmb() \
__asm__ __volatile__ ( " lock; addl $0,-128(%%esp) " : : : " memory " , " cc " )
# define rseq_smp_wmb() \
__asm__ __volatile__ ( " lock; addl $0,-128(%%esp) " : : : " memory " , " cc " )
# define rseq_smp_load_acquire(p) \
__extension__ ( { \
__typeof ( * p ) ____p1 = RSEQ_READ_ONCE ( * p ) ; \
rseq_smp_mb ( ) ; \
____p1 ; \
} )
# define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
# define rseq_smp_store_release(p, v) \
do { \
rseq_smp_mb ( ) ; \
RSEQ_WRITE_ONCE ( * p , v ) ; \
} while ( 0 )
# ifdef RSEQ_SKIP_FASTPATH
# include "rseq-skip.h"
# else /* !RSEQ_SKIP_FASTPATH */
/*
* Use eax as scratch register and take memory operands as input to
* lessen register pressure . Especially needed when compiling in O0 .
*/
# define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
start_ip , post_commit_offset , abort_ip ) \
2019-04-29 11:27:54 -04:00
" .pushsection __rseq_cs, \" aw \" \n \t " \
2018-06-02 08:44:04 -04:00
" .balign 32 \n \t " \
__rseq_str ( label ) " : \n \t " \
" .long " __rseq_str ( version ) " , " __rseq_str ( flags ) " \n \t " \
" .long " __rseq_str ( start_ip ) " , 0x0, " __rseq_str ( post_commit_offset ) " , 0x0, " __rseq_str ( abort_ip ) " , 0x0 \n \t " \
2019-04-29 11:27:54 -04:00
" .popsection \n \t " \
" .pushsection __rseq_cs_ptr_array, \" aw \" \n \t " \
" .long " __rseq_str ( label ) " b, 0x0 \n \t " \
2018-06-02 08:44:04 -04:00
" .popsection \n \t "
# define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
__RSEQ_ASM_DEFINE_TABLE ( label , 0x0 , 0x0 , start_ip , \
( post_commit_ip - start_ip ) , abort_ip )
2019-04-29 11:27:53 -04:00
/*
* Exit points of a rseq critical section consist of all instructions outside
* of the critical section where a critical section can either branch to or
* reach through the normal course of its execution . The abort IP and the
2019-04-29 11:27:54 -04:00
* post - commit IP are already part of the __rseq_cs section and should not be
* explicitly defined as additional exit points . Knowing all exit points is
2019-04-29 11:27:53 -04:00
* useful to assist debuggers stepping over the critical section .
*/
# define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
" .pushsection __rseq_exit_point_array, \" aw \" \n \t " \
" .long " __rseq_str ( start_ip ) " , 0x0, " __rseq_str ( exit_ip ) " , 0x0 \n \t " \
" .popsection \n \t "
2018-06-02 08:44:04 -04:00
# define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
RSEQ_INJECT_ASM ( 1 ) \
2019-04-29 11:27:52 -04:00
" movl $ " __rseq_str ( cs_label ) " , " __rseq_str ( rseq_cs ) " \n \t " \
2018-06-02 08:44:04 -04:00
__rseq_str ( label ) " : \n \t "
# define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
RSEQ_INJECT_ASM ( 2 ) \
2019-04-29 11:27:52 -04:00
" cmpl %[ " __rseq_str ( cpu_id ) " ], " __rseq_str ( current_cpu_id ) " \n \t " \
2018-06-02 08:44:04 -04:00
" jnz " __rseq_str ( label ) " \n \t "
# define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
" .pushsection __rseq_failure, \" ax \" \n \t " \
2019-04-29 11:27:57 -04:00
/* Disassembler-friendly signature: ud1 <sig>,%edi. */ \
" .byte 0x0f, 0xb9, 0x3d \n \t " \
2018-06-02 08:44:04 -04:00
" .long " __rseq_str ( RSEQ_SIG ) " \n \t " \
__rseq_str ( label ) " : \n \t " \
teardown \
" jmp %l[ " __rseq_str ( abort_label ) " ] \n \t " \
" .popsection \n \t "
# define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
" .pushsection __rseq_failure, \" ax \" \n \t " \
__rseq_str ( label ) " : \n \t " \
teardown \
" jmp %l[ " __rseq_str ( cmpfail_label ) " ] \n \t " \
" .popsection \n \t "
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_storev ( intptr_t * v , intptr_t expect , intptr_t newv , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:53 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" cmpl %[v], %[expect] \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:53 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" cmpl %[v], %[expect] \n \t "
" jnz %l[error2] \n \t "
# endif
/* final store */
" movl %[newv], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 5 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-01-24 12:12:53 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
[ v ] " m " ( * v ) ,
[ expect ] " r " ( expect ) ,
[ newv ] " r " ( newv )
: " memory " , " cc " , " eax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
/*
* Compare @ v against @ expectnot . When it does _not_ match , load @ v
* into @ load , and store the content of * @ v + voffp into @ v .
*/
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpnev_storeoffp_load ( intptr_t * v , intptr_t expectnot ,
2022-01-24 12:12:48 -05:00
long voffp , intptr_t * load , int cpu )
2018-06-02 08:44:04 -04:00
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:53 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" movl %[v], %%ebx \n \t "
" cmpl %%ebx, %[expectnot] \n \t "
" je %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:53 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" movl %[v], %%ebx \n \t "
" cmpl %%ebx, %[expectnot] \n \t "
" je %l[error2] \n \t "
# endif
" movl %%ebx, %[load] \n \t "
" addl %[voffp], %%ebx \n \t "
" movl (%%ebx), %%ebx \n \t "
/* final store */
" movl %%ebx, %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 5 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-01-24 12:12:53 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* final store input */
[ v ] " m " ( * v ) ,
[ expectnot ] " r " ( expectnot ) ,
[ voffp ] " ir " ( voffp ) ,
[ load ] " m " ( * load )
: " memory " , " cc " , " eax " , " ebx "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
static inline __attribute__ ( ( always_inline ) )
int rseq_addv ( intptr_t * v , intptr_t count , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:53 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:53 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
# endif
/* final store */
" addl %[count], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 4 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-01-24 12:12:53 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* final store input */
[ v ] " m " ( * v ) ,
[ count ] " ir " ( count )
: " memory " , " cc " , " eax "
RSEQ_INJECT_CLOBBER
: abort
# ifdef RSEQ_COMPARE_TWICE
, error1
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
# endif
}
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_trystorev_storev ( intptr_t * v , intptr_t expect ,
intptr_t * v2 , intptr_t newv2 ,
intptr_t newv , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:53 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" cmpl %[v], %[expect] \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:53 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" cmpl %[v], %[expect] \n \t "
" jnz %l[error2] \n \t "
# endif
/* try store */
" movl %[newv2], %%eax \n \t "
" movl %%eax, %[v2] \n \t "
RSEQ_INJECT_ASM ( 5 )
/* final store */
" movl %[newv], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 6 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-01-24 12:12:53 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* try store input */
[ v2 ] " m " ( * v2 ) ,
[ newv2 ] " m " ( newv2 ) ,
/* final store input */
[ v ] " m " ( * v ) ,
[ expect ] " r " ( expect ) ,
[ newv ] " r " ( newv )
: " memory " , " cc " , " eax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_trystorev_storev_release ( intptr_t * v , intptr_t expect ,
intptr_t * v2 , intptr_t newv2 ,
intptr_t newv , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:53 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" movl %[expect], %%eax \n \t "
" cmpl %[v], %%eax \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:53 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" movl %[expect], %%eax \n \t "
" cmpl %[v], %%eax \n \t "
" jnz %l[error2] \n \t "
# endif
/* try store */
" movl %[newv2], %[v2] \n \t "
RSEQ_INJECT_ASM ( 5 )
" lock; addl $0,-128(%%esp) \n \t "
/* final store */
" movl %[newv], %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 6 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-01-24 12:12:53 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* try store input */
[ v2 ] " m " ( * v2 ) ,
[ newv2 ] " r " ( newv2 ) ,
/* final store input */
[ v ] " m " ( * v ) ,
[ expect ] " m " ( expect ) ,
[ newv ] " r " ( newv )
: " memory " , " cc " , " eax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_cmpeqv_storev ( intptr_t * v , intptr_t expect ,
intptr_t * v2 , intptr_t expect2 ,
intptr_t newv , int cpu )
{
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error3 ] )
# endif
2018-06-02 08:44:04 -04:00
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:53 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" cmpl %[v], %[expect] \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 4 )
" cmpl %[expect2], %[v2] \n \t "
" jnz %l[cmpfail] \n \t "
RSEQ_INJECT_ASM ( 5 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:53 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , % l [ error1 ] )
2018-06-02 08:44:04 -04:00
" cmpl %[v], %[expect] \n \t "
" jnz %l[error2] \n \t "
" cmpl %[expect2], %[v2] \n \t "
" jnz %l[error3] \n \t "
# endif
" movl %[newv], %%eax \n \t "
/* final store */
" movl %%eax, %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 6 )
RSEQ_ASM_DEFINE_ABORT ( 4 , " " , abort )
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-01-24 12:12:53 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* cmp2 input */
[ v2 ] " m " ( * v2 ) ,
[ expect2 ] " r " ( expect2 ) ,
/* final store input */
[ v ] " m " ( * v ) ,
[ expect ] " r " ( expect ) ,
[ newv ] " m " ( newv )
: " memory " , " cc " , " eax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2 , error3
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " 1st expected value comparison failed " ) ;
error3 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " 2nd expected value comparison failed " ) ;
# endif
}
/* TODO: implement a faster memcpy. */
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_trymemcpy_storev ( intptr_t * v , intptr_t expect ,
void * dst , void * src , size_t len ,
intptr_t newv , int cpu )
{
uint32_t rseq_scratch [ 3 ] ;
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
" movl %[src], %[rseq_scratch0] \n \t "
" movl %[dst], %[rseq_scratch1] \n \t "
" movl %[len], %[rseq_scratch2] \n \t "
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:53 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" movl %[expect], %%eax \n \t "
" cmpl %%eax, %[v] \n \t "
" jnz 5f \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:53 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 6f )
2018-06-02 08:44:04 -04:00
" movl %[expect], %%eax \n \t "
" cmpl %%eax, %[v] \n \t "
" jnz 7f \n \t "
# endif
/* try memcpy */
" test %[len], %[len] \n \t " \
" jz 333f \n \t " \
" 222: \n \t " \
" movb (%[src]), %%al \n \t " \
" movb %%al, (%[dst]) \n \t " \
" inc %[src] \n \t " \
" inc %[dst] \n \t " \
" dec %[len] \n \t " \
" jnz 222b \n \t " \
" 333: \n \t " \
RSEQ_INJECT_ASM ( 5 )
" movl %[newv], %%eax \n \t "
/* final store */
" movl %%eax, %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 6 )
/* teardown */
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t "
RSEQ_ASM_DEFINE_ABORT ( 4 ,
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t " ,
abort )
RSEQ_ASM_DEFINE_CMPFAIL ( 5 ,
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t " ,
cmpfail )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_CMPFAIL ( 6 ,
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t " ,
error1 )
RSEQ_ASM_DEFINE_CMPFAIL ( 7 ,
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t " ,
error2 )
# endif
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-01-24 12:12:53 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* final store input */
[ v ] " m " ( * v ) ,
[ expect ] " m " ( expect ) ,
[ newv ] " m " ( newv ) ,
/* try memcpy input */
[ dst ] " r " ( dst ) ,
[ src ] " r " ( src ) ,
[ len ] " r " ( len ) ,
[ rseq_scratch0 ] " m " ( rseq_scratch [ 0 ] ) ,
[ rseq_scratch1 ] " m " ( rseq_scratch [ 1 ] ) ,
[ rseq_scratch2 ] " m " ( rseq_scratch [ 2 ] )
: " memory " , " cc " , " eax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
/* TODO: implement a faster memcpy. */
static inline __attribute__ ( ( always_inline ) )
int rseq_cmpeqv_trymemcpy_storev_release ( intptr_t * v , intptr_t expect ,
void * dst , void * src , size_t len ,
intptr_t newv , int cpu )
{
uint32_t rseq_scratch [ 3 ] ;
RSEQ_INJECT_C ( 9 )
__asm__ __volatile__ goto (
RSEQ_ASM_DEFINE_TABLE ( 3 , 1f , 2f , 4f ) /* start, commit, abort */
2019-04-29 11:27:53 -04:00
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ cmpfail ] )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error1 ] )
RSEQ_ASM_DEFINE_EXIT_POINT ( 1f , % l [ error2 ] )
# endif
2018-06-02 08:44:04 -04:00
" movl %[src], %[rseq_scratch0] \n \t "
" movl %[dst], %[rseq_scratch1] \n \t "
" movl %[len], %[rseq_scratch2] \n \t "
/* Start rseq by storing table entry pointer into rseq_cs. */
2022-01-24 12:12:53 -05:00
RSEQ_ASM_STORE_RSEQ_CS ( 1 , 3 b , RSEQ_ASM_TP_SEGMENT : RSEQ_CS_OFFSET ( % [ rseq_offset ] ) )
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 4f )
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_ASM ( 3 )
" movl %[expect], %%eax \n \t "
" cmpl %%eax, %[v] \n \t "
" jnz 5f \n \t "
RSEQ_INJECT_ASM ( 4 )
# ifdef RSEQ_COMPARE_TWICE
2022-01-24 12:12:53 -05:00
RSEQ_ASM_CMP_CPU_ID ( cpu_id , RSEQ_ASM_TP_SEGMENT : RSEQ_CPU_ID_OFFSET ( % [ rseq_offset ] ) , 6f )
2018-06-02 08:44:04 -04:00
" movl %[expect], %%eax \n \t "
" cmpl %%eax, %[v] \n \t "
" jnz 7f \n \t "
# endif
/* try memcpy */
" test %[len], %[len] \n \t " \
" jz 333f \n \t " \
" 222: \n \t " \
" movb (%[src]), %%al \n \t " \
" movb %%al, (%[dst]) \n \t " \
" inc %[src] \n \t " \
" inc %[dst] \n \t " \
" dec %[len] \n \t " \
" jnz 222b \n \t " \
" 333: \n \t " \
RSEQ_INJECT_ASM ( 5 )
" lock; addl $0,-128(%%esp) \n \t "
" movl %[newv], %%eax \n \t "
/* final store */
" movl %%eax, %[v] \n \t "
" 2: \n \t "
RSEQ_INJECT_ASM ( 6 )
/* teardown */
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t "
RSEQ_ASM_DEFINE_ABORT ( 4 ,
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t " ,
abort )
RSEQ_ASM_DEFINE_CMPFAIL ( 5 ,
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t " ,
cmpfail )
# ifdef RSEQ_COMPARE_TWICE
RSEQ_ASM_DEFINE_CMPFAIL ( 6 ,
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t " ,
error1 )
RSEQ_ASM_DEFINE_CMPFAIL ( 7 ,
" movl %[rseq_scratch2], %[len] \n \t "
" movl %[rseq_scratch1], %[dst] \n \t "
" movl %[rseq_scratch0], %[src] \n \t " ,
error2 )
# endif
: /* gcc asm goto does not allow outputs */
: [ cpu_id ] " r " ( cpu ) ,
2022-01-24 12:12:53 -05:00
[ rseq_offset ] " r " ( rseq_offset ) ,
2018-06-02 08:44:04 -04:00
/* final store input */
[ v ] " m " ( * v ) ,
[ expect ] " m " ( expect ) ,
[ newv ] " m " ( newv ) ,
/* try memcpy input */
[ dst ] " r " ( dst ) ,
[ src ] " r " ( src ) ,
[ len ] " r " ( len ) ,
[ rseq_scratch0 ] " m " ( rseq_scratch [ 0 ] ) ,
[ rseq_scratch1 ] " m " ( rseq_scratch [ 1 ] ) ,
[ rseq_scratch2 ] " m " ( rseq_scratch [ 2 ] )
: " memory " , " cc " , " eax "
RSEQ_INJECT_CLOBBER
: abort , cmpfail
# ifdef RSEQ_COMPARE_TWICE
, error1 , error2
# endif
) ;
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 0 ;
abort :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
RSEQ_INJECT_FAILED
return - 1 ;
cmpfail :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
return 1 ;
# ifdef RSEQ_COMPARE_TWICE
error1 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " cpu_id comparison failed " ) ;
error2 :
2022-01-24 12:12:51 -05:00
rseq_after_asm_goto ( ) ;
2018-06-02 08:44:04 -04:00
rseq_bug ( " expected value comparison failed " ) ;
# endif
}
# endif /* !RSEQ_SKIP_FASTPATH */
# endif