1 /* SPDX-License-Identifier: MIT */
2 /* SPDX-FileCopyrightText: 2016-2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> */
7 #include "rseq-bits-template.h"
10 * Refer to rseq-pseudocode.h for pseudo-code of the rseq critical
13 #include "rseq-pseudocode.h"
17 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
18 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
20 static inline __attribute__((always_inline
))
21 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
25 __asm__ __volatile__
goto (
26 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
27 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
28 #ifdef RSEQ_COMPARE_TWICE
29 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
30 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
32 /* Start rseq by storing table entry pointer into rseq_cs. */
33 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
34 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
36 "cmpq %[v], %[expect]\n\t"
39 #ifdef RSEQ_COMPARE_TWICE
40 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
41 "cmpq %[v], %[expect]\n\t"
45 "movq %[newv], %[v]\n\t"
48 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
49 : /* gcc asm goto does not allow outputs */
51 [rseq_offset
] "r" (rseq_offset
),
53 [expect
] "r" (expect
),
55 : "memory", "cc", "rax"
58 #ifdef RSEQ_COMPARE_TWICE
62 rseq_after_asm_goto();
65 rseq_after_asm_goto();
69 rseq_after_asm_goto();
71 #ifdef RSEQ_COMPARE_TWICE
73 rseq_after_asm_goto();
74 rseq_bug("cpu_id comparison failed");
76 rseq_after_asm_goto();
77 rseq_bug("expected value comparison failed");
82 * Compare @v against @expectnot. When it does _not_ match, load @v
83 * into @load, and store the content of *@v + voffp into @v.
85 static inline __attribute__((always_inline
))
86 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load
)(intptr_t *v
, intptr_t expectnot
,
87 long voffp
, intptr_t *load
, int cpu
)
91 __asm__ __volatile__
goto (
92 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
93 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
94 #ifdef RSEQ_COMPARE_TWICE
95 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
96 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
98 /* Start rseq by storing table entry pointer into rseq_cs. */
99 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
100 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
102 "movq %[v], %%rbx\n\t"
103 "cmpq %%rbx, %[expectnot]\n\t"
106 #ifdef RSEQ_COMPARE_TWICE
107 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
108 "movq %[v], %%rbx\n\t"
109 "cmpq %%rbx, %[expectnot]\n\t"
112 "movq %%rbx, %[load]\n\t"
113 "addq %[voffp], %%rbx\n\t"
114 "movq (%%rbx), %%rbx\n\t"
116 "movq %%rbx, %[v]\n\t"
119 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
120 : /* gcc asm goto does not allow outputs */
121 : [cpu_id
] "r" (cpu
),
122 [rseq_offset
] "r" (rseq_offset
),
123 /* final store input */
125 [expectnot
] "r" (expectnot
),
126 [voffp
] "er" (voffp
),
128 : "memory", "cc", "rax", "rbx"
131 #ifdef RSEQ_COMPARE_TWICE
135 rseq_after_asm_goto();
138 rseq_after_asm_goto();
142 rseq_after_asm_goto();
144 #ifdef RSEQ_COMPARE_TWICE
146 rseq_after_asm_goto();
147 rseq_bug("cpu_id comparison failed");
149 rseq_after_asm_goto();
150 rseq_bug("expected value comparison failed");
154 static inline __attribute__((always_inline
))
155 int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv
)(intptr_t *v
, intptr_t count
, int cpu
)
159 __asm__ __volatile__
goto (
160 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
161 #ifdef RSEQ_COMPARE_TWICE
162 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
164 /* Start rseq by storing table entry pointer into rseq_cs. */
165 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
166 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
168 #ifdef RSEQ_COMPARE_TWICE
169 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
172 "addq %[count], %[v]\n\t"
175 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
176 : /* gcc asm goto does not allow outputs */
177 : [cpu_id
] "r" (cpu
),
178 [rseq_offset
] "r" (rseq_offset
),
179 /* final store input */
182 : "memory", "cc", "rax"
185 #ifdef RSEQ_COMPARE_TWICE
189 rseq_after_asm_goto();
192 rseq_after_asm_goto();
195 #ifdef RSEQ_COMPARE_TWICE
197 rseq_after_asm_goto();
198 rseq_bug("cpu_id comparison failed");
202 #define RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
208 static inline __attribute__((always_inline
))
209 int RSEQ_TEMPLATE_IDENTIFIER(rseq_offset_deref_addv
)(intptr_t *ptr
, long off
, intptr_t inc
, int cpu
)
213 __asm__ __volatile__
goto (
214 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
215 #ifdef RSEQ_COMPARE_TWICE
216 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
218 /* Start rseq by storing table entry pointer into rseq_cs. */
219 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
220 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
222 #ifdef RSEQ_COMPARE_TWICE
223 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
226 "movq %[ptr], %%rbx\n\t"
227 "addq %[off], %%rbx\n\t"
229 "movq (%%rbx), %%rcx\n\t"
231 "addq %[inc], (%%rcx)\n\t"
234 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
235 : /* gcc asm goto does not allow outputs */
236 : [cpu_id
] "r" (cpu
),
237 [rseq_offset
] "r" (rseq_offset
),
238 /* final store input */
242 : "memory", "cc", "rax", "rbx", "rcx"
245 #ifdef RSEQ_COMPARE_TWICE
253 #ifdef RSEQ_COMPARE_TWICE
255 rseq_bug("cpu_id comparison failed");
259 static inline __attribute__((always_inline
))
260 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
,
261 intptr_t *v2
, intptr_t expect2
,
262 intptr_t newv
, int cpu
)
266 __asm__ __volatile__
goto (
267 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
268 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
269 #ifdef RSEQ_COMPARE_TWICE
270 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
271 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
272 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
274 /* Start rseq by storing table entry pointer into rseq_cs. */
275 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
276 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
278 "cmpq %[v], %[expect]\n\t"
279 "jnz %l[cmpfail]\n\t"
281 "cmpq %[v2], %[expect2]\n\t"
282 "jnz %l[cmpfail]\n\t"
284 #ifdef RSEQ_COMPARE_TWICE
285 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
286 "cmpq %[v], %[expect]\n\t"
288 "cmpq %[v2], %[expect2]\n\t"
292 "movq %[newv], %[v]\n\t"
295 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
296 : /* gcc asm goto does not allow outputs */
297 : [cpu_id
] "r" (cpu
),
298 [rseq_offset
] "r" (rseq_offset
),
301 [expect2
] "r" (expect2
),
302 /* final store input */
304 [expect
] "r" (expect
),
306 : "memory", "cc", "rax"
309 #ifdef RSEQ_COMPARE_TWICE
310 , error1
, error2
, error3
313 rseq_after_asm_goto();
316 rseq_after_asm_goto();
320 rseq_after_asm_goto();
322 #ifdef RSEQ_COMPARE_TWICE
324 rseq_after_asm_goto();
325 rseq_bug("cpu_id comparison failed");
327 rseq_after_asm_goto();
328 rseq_bug("1st expected value comparison failed");
330 rseq_after_asm_goto();
331 rseq_bug("2nd expected value comparison failed");
335 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
336 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
338 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
339 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
341 static inline __attribute__((always_inline
))
342 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev
)(intptr_t *v
, intptr_t expect
,
343 intptr_t *v2
, intptr_t newv2
,
344 intptr_t newv
, int cpu
)
348 __asm__ __volatile__
goto (
349 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
350 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
351 #ifdef RSEQ_COMPARE_TWICE
352 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
353 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
355 /* Start rseq by storing table entry pointer into rseq_cs. */
356 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
357 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
359 "cmpq %[v], %[expect]\n\t"
360 "jnz %l[cmpfail]\n\t"
362 #ifdef RSEQ_COMPARE_TWICE
363 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
364 "cmpq %[v], %[expect]\n\t"
368 "movq %[newv2], %[v2]\n\t"
371 "movq %[newv], %[v]\n\t"
374 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
375 : /* gcc asm goto does not allow outputs */
376 : [cpu_id
] "r" (cpu
),
377 [rseq_offset
] "r" (rseq_offset
),
378 /* try store input */
381 /* final store input */
383 [expect
] "r" (expect
),
385 : "memory", "cc", "rax"
388 #ifdef RSEQ_COMPARE_TWICE
392 rseq_after_asm_goto();
395 rseq_after_asm_goto();
399 rseq_after_asm_goto();
401 #ifdef RSEQ_COMPARE_TWICE
403 rseq_after_asm_goto();
404 rseq_bug("cpu_id comparison failed");
406 rseq_after_asm_goto();
407 rseq_bug("expected value comparison failed");
411 static inline __attribute__((always_inline
))
412 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev
)(intptr_t *v
, intptr_t expect
,
413 void *dst
, void *src
, size_t len
,
414 intptr_t newv
, int cpu
)
416 uint64_t rseq_scratch
[3];
420 __asm__ __volatile__
goto (
421 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
422 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
423 #ifdef RSEQ_COMPARE_TWICE
424 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
425 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
427 "movq %[src], %[rseq_scratch0]\n\t"
428 "movq %[dst], %[rseq_scratch1]\n\t"
429 "movq %[len], %[rseq_scratch2]\n\t"
430 /* Start rseq by storing table entry pointer into rseq_cs. */
431 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
432 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
434 "cmpq %[v], %[expect]\n\t"
437 #ifdef RSEQ_COMPARE_TWICE
438 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 6f
)
439 "cmpq %[v], %[expect]\n\t"
443 "test %[len], %[len]\n\t" \
446 "movb (%[src]), %%al\n\t" \
447 "movb %%al, (%[dst])\n\t" \
455 "movq %[newv], %[v]\n\t"
459 "movq %[rseq_scratch2], %[len]\n\t"
460 "movq %[rseq_scratch1], %[dst]\n\t"
461 "movq %[rseq_scratch0], %[src]\n\t"
462 RSEQ_ASM_DEFINE_ABORT(4,
463 "movq %[rseq_scratch2], %[len]\n\t"
464 "movq %[rseq_scratch1], %[dst]\n\t"
465 "movq %[rseq_scratch0], %[src]\n\t",
467 RSEQ_ASM_DEFINE_CMPFAIL(5,
468 "movq %[rseq_scratch2], %[len]\n\t"
469 "movq %[rseq_scratch1], %[dst]\n\t"
470 "movq %[rseq_scratch0], %[src]\n\t",
472 #ifdef RSEQ_COMPARE_TWICE
473 RSEQ_ASM_DEFINE_CMPFAIL(6,
474 "movq %[rseq_scratch2], %[len]\n\t"
475 "movq %[rseq_scratch1], %[dst]\n\t"
476 "movq %[rseq_scratch0], %[src]\n\t",
478 RSEQ_ASM_DEFINE_CMPFAIL(7,
479 "movq %[rseq_scratch2], %[len]\n\t"
480 "movq %[rseq_scratch1], %[dst]\n\t"
481 "movq %[rseq_scratch0], %[src]\n\t",
484 : /* gcc asm goto does not allow outputs */
485 : [cpu_id
] "r" (cpu
),
486 [rseq_offset
] "r" (rseq_offset
),
487 /* final store input */
489 [expect
] "r" (expect
),
491 /* try memcpy input */
495 [rseq_scratch0
] "m" (rseq_scratch
[0]),
496 [rseq_scratch1
] "m" (rseq_scratch
[1]),
497 [rseq_scratch2
] "m" (rseq_scratch
[2])
498 : "memory", "cc", "rax"
501 #ifdef RSEQ_COMPARE_TWICE
505 rseq_after_asm_goto();
508 rseq_after_asm_goto();
512 rseq_after_asm_goto();
514 #ifdef RSEQ_COMPARE_TWICE
516 rseq_after_asm_goto();
517 rseq_bug("cpu_id comparison failed");
519 rseq_after_asm_goto();
520 rseq_bug("expected value comparison failed");
524 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
525 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
527 #elif defined(__i386__)
529 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
530 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
532 static inline __attribute__((always_inline
))
533 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
537 __asm__ __volatile__
goto (
538 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
539 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
540 #ifdef RSEQ_COMPARE_TWICE
541 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
542 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
544 /* Start rseq by storing table entry pointer into rseq_cs. */
545 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
546 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
548 "cmpl %[v], %[expect]\n\t"
549 "jnz %l[cmpfail]\n\t"
551 #ifdef RSEQ_COMPARE_TWICE
552 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
553 "cmpl %[v], %[expect]\n\t"
557 "movl %[newv], %[v]\n\t"
560 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
561 : /* gcc asm goto does not allow outputs */
562 : [cpu_id
] "r" (cpu
),
563 [rseq_offset
] "r" (rseq_offset
),
565 [expect
] "r" (expect
),
567 : "memory", "cc", "eax"
570 #ifdef RSEQ_COMPARE_TWICE
574 rseq_after_asm_goto();
577 rseq_after_asm_goto();
581 rseq_after_asm_goto();
583 #ifdef RSEQ_COMPARE_TWICE
585 rseq_after_asm_goto();
586 rseq_bug("cpu_id comparison failed");
588 rseq_after_asm_goto();
589 rseq_bug("expected value comparison failed");
594 * Compare @v against @expectnot. When it does _not_ match, load @v
595 * into @load, and store the content of *@v + voffp into @v.
597 static inline __attribute__((always_inline
))
598 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load
)(intptr_t *v
, intptr_t expectnot
,
599 long voffp
, intptr_t *load
, int cpu
)
603 __asm__ __volatile__
goto (
604 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
605 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
606 #ifdef RSEQ_COMPARE_TWICE
607 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
608 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
610 /* Start rseq by storing table entry pointer into rseq_cs. */
611 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
612 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
614 "movl %[v], %%ebx\n\t"
615 "cmpl %%ebx, %[expectnot]\n\t"
618 #ifdef RSEQ_COMPARE_TWICE
619 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
620 "movl %[v], %%ebx\n\t"
621 "cmpl %%ebx, %[expectnot]\n\t"
624 "movl %%ebx, %[load]\n\t"
625 "addl %[voffp], %%ebx\n\t"
626 "movl (%%ebx), %%ebx\n\t"
628 "movl %%ebx, %[v]\n\t"
631 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
632 : /* gcc asm goto does not allow outputs */
633 : [cpu_id
] "r" (cpu
),
634 [rseq_offset
] "r" (rseq_offset
),
635 /* final store input */
637 [expectnot
] "r" (expectnot
),
638 [voffp
] "ir" (voffp
),
640 : "memory", "cc", "eax", "ebx"
643 #ifdef RSEQ_COMPARE_TWICE
647 rseq_after_asm_goto();
650 rseq_after_asm_goto();
654 rseq_after_asm_goto();
656 #ifdef RSEQ_COMPARE_TWICE
658 rseq_after_asm_goto();
659 rseq_bug("cpu_id comparison failed");
661 rseq_after_asm_goto();
662 rseq_bug("expected value comparison failed");
666 static inline __attribute__((always_inline
))
667 int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv
)(intptr_t *v
, intptr_t count
, int cpu
)
671 __asm__ __volatile__
goto (
672 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
673 #ifdef RSEQ_COMPARE_TWICE
674 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
676 /* Start rseq by storing table entry pointer into rseq_cs. */
677 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
678 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
680 #ifdef RSEQ_COMPARE_TWICE
681 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
684 "addl %[count], %[v]\n\t"
687 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
688 : /* gcc asm goto does not allow outputs */
689 : [cpu_id
] "r" (cpu
),
690 [rseq_offset
] "r" (rseq_offset
),
691 /* final store input */
694 : "memory", "cc", "eax"
697 #ifdef RSEQ_COMPARE_TWICE
701 rseq_after_asm_goto();
704 rseq_after_asm_goto();
707 #ifdef RSEQ_COMPARE_TWICE
709 rseq_after_asm_goto();
710 rseq_bug("cpu_id comparison failed");
714 static inline __attribute__((always_inline
))
715 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
,
716 intptr_t *v2
, intptr_t expect2
,
717 intptr_t newv
, int cpu
)
721 __asm__ __volatile__
goto (
722 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
723 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
724 #ifdef RSEQ_COMPARE_TWICE
725 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
726 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
727 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
729 /* Start rseq by storing table entry pointer into rseq_cs. */
730 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
731 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
733 "cmpl %[v], %[expect]\n\t"
734 "jnz %l[cmpfail]\n\t"
736 "cmpl %[expect2], %[v2]\n\t"
737 "jnz %l[cmpfail]\n\t"
739 #ifdef RSEQ_COMPARE_TWICE
740 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
741 "cmpl %[v], %[expect]\n\t"
743 "cmpl %[expect2], %[v2]\n\t"
746 "movl %[newv], %%eax\n\t"
748 "movl %%eax, %[v]\n\t"
751 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
752 : /* gcc asm goto does not allow outputs */
753 : [cpu_id
] "r" (cpu
),
754 [rseq_offset
] "r" (rseq_offset
),
757 [expect2
] "r" (expect2
),
758 /* final store input */
760 [expect
] "r" (expect
),
762 : "memory", "cc", "eax"
765 #ifdef RSEQ_COMPARE_TWICE
766 , error1
, error2
, error3
769 rseq_after_asm_goto();
772 rseq_after_asm_goto();
776 rseq_after_asm_goto();
778 #ifdef RSEQ_COMPARE_TWICE
780 rseq_after_asm_goto();
781 rseq_bug("cpu_id comparison failed");
783 rseq_after_asm_goto();
784 rseq_bug("1st expected value comparison failed");
786 rseq_after_asm_goto();
787 rseq_bug("2nd expected value comparison failed");
791 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
792 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
794 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
795 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
797 static inline __attribute__((always_inline
))
798 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev
)(intptr_t *v
, intptr_t expect
,
799 intptr_t *v2
, intptr_t newv2
,
800 intptr_t newv
, int cpu
)
804 __asm__ __volatile__
goto (
805 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
806 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
807 #ifdef RSEQ_COMPARE_TWICE
808 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
809 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
811 /* Start rseq by storing table entry pointer into rseq_cs. */
812 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
813 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
815 "movl %[expect], %%eax\n\t"
816 "cmpl %[v], %%eax\n\t"
817 "jnz %l[cmpfail]\n\t"
819 #ifdef RSEQ_COMPARE_TWICE
820 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
821 "movl %[expect], %%eax\n\t"
822 "cmpl %[v], %%eax\n\t"
826 "movl %[newv2], %[v2]\n\t"
828 #ifdef RSEQ_TEMPLATE_MO_RELEASE
829 "lock; addl $0,-128(%%esp)\n\t"
832 "movl %[newv], %[v]\n\t"
835 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
836 : /* gcc asm goto does not allow outputs */
837 : [cpu_id
] "r" (cpu
),
838 [rseq_offset
] "r" (rseq_offset
),
839 /* try store input */
842 /* final store input */
844 [expect
] "m" (expect
),
846 : "memory", "cc", "eax"
849 #ifdef RSEQ_COMPARE_TWICE
853 rseq_after_asm_goto();
856 rseq_after_asm_goto();
860 rseq_after_asm_goto();
862 #ifdef RSEQ_COMPARE_TWICE
864 rseq_after_asm_goto();
865 rseq_bug("cpu_id comparison failed");
867 rseq_after_asm_goto();
868 rseq_bug("expected value comparison failed");
873 /* TODO: implement a faster memcpy. */
874 static inline __attribute__((always_inline
))
875 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev
)(intptr_t *v
, intptr_t expect
,
876 void *dst
, void *src
, size_t len
,
877 intptr_t newv
, int cpu
)
879 uint32_t rseq_scratch
[3];
883 __asm__ __volatile__
goto (
884 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
885 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
886 #ifdef RSEQ_COMPARE_TWICE
887 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
888 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
890 "movl %[src], %[rseq_scratch0]\n\t"
891 "movl %[dst], %[rseq_scratch1]\n\t"
892 "movl %[len], %[rseq_scratch2]\n\t"
893 /* Start rseq by storing table entry pointer into rseq_cs. */
894 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
895 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
897 "movl %[expect], %%eax\n\t"
898 "cmpl %%eax, %[v]\n\t"
901 #ifdef RSEQ_COMPARE_TWICE
902 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 6f
)
903 "movl %[expect], %%eax\n\t"
904 "cmpl %%eax, %[v]\n\t"
908 "test %[len], %[len]\n\t" \
911 "movb (%[src]), %%al\n\t" \
912 "movb %%al, (%[dst])\n\t" \
919 #ifdef RSEQ_TEMPLATE_MO_RELEASE
920 "lock; addl $0,-128(%%esp)\n\t"
922 "movl %[newv], %%eax\n\t"
924 "movl %%eax, %[v]\n\t"
928 "movl %[rseq_scratch2], %[len]\n\t"
929 "movl %[rseq_scratch1], %[dst]\n\t"
930 "movl %[rseq_scratch0], %[src]\n\t"
931 RSEQ_ASM_DEFINE_ABORT(4,
932 "movl %[rseq_scratch2], %[len]\n\t"
933 "movl %[rseq_scratch1], %[dst]\n\t"
934 "movl %[rseq_scratch0], %[src]\n\t",
936 RSEQ_ASM_DEFINE_CMPFAIL(5,
937 "movl %[rseq_scratch2], %[len]\n\t"
938 "movl %[rseq_scratch1], %[dst]\n\t"
939 "movl %[rseq_scratch0], %[src]\n\t",
941 #ifdef RSEQ_COMPARE_TWICE
942 RSEQ_ASM_DEFINE_CMPFAIL(6,
943 "movl %[rseq_scratch2], %[len]\n\t"
944 "movl %[rseq_scratch1], %[dst]\n\t"
945 "movl %[rseq_scratch0], %[src]\n\t",
947 RSEQ_ASM_DEFINE_CMPFAIL(7,
948 "movl %[rseq_scratch2], %[len]\n\t"
949 "movl %[rseq_scratch1], %[dst]\n\t"
950 "movl %[rseq_scratch0], %[src]\n\t",
953 : /* gcc asm goto does not allow outputs */
954 : [cpu_id
] "r" (cpu
),
955 [rseq_offset
] "r" (rseq_offset
),
956 /* final store input */
958 [expect
] "m" (expect
),
960 /* try memcpy input */
964 [rseq_scratch0
] "m" (rseq_scratch
[0]),
965 [rseq_scratch1
] "m" (rseq_scratch
[1]),
966 [rseq_scratch2
] "m" (rseq_scratch
[2])
967 : "memory", "cc", "eax"
970 #ifdef RSEQ_COMPARE_TWICE
974 rseq_after_asm_goto();
977 rseq_after_asm_goto();
981 rseq_after_asm_goto();
983 #ifdef RSEQ_COMPARE_TWICE
985 rseq_after_asm_goto();
986 rseq_bug("cpu_id comparison failed");
988 rseq_after_asm_goto();
989 rseq_bug("expected value comparison failed");
993 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
994 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
998 #include "rseq-bits-reset.h"