1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
5 * (C) Copyright 2016-2022 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 #include "rseq-bits-template.h"
12 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
13 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
15 static inline __attribute__((always_inline
))
16 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
20 __asm__ __volatile__
goto (
21 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
22 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
23 #ifdef RSEQ_COMPARE_TWICE
24 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
25 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
27 /* Start rseq by storing table entry pointer into rseq_cs. */
28 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
29 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
31 "cmpq %[v], %[expect]\n\t"
34 #ifdef RSEQ_COMPARE_TWICE
35 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
36 "cmpq %[v], %[expect]\n\t"
40 "movq %[newv], %[v]\n\t"
43 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
44 : /* gcc asm goto does not allow outputs */
46 [rseq_offset
] "r" (rseq_offset
),
48 [expect
] "r" (expect
),
50 : "memory", "cc", "rax"
53 #ifdef RSEQ_COMPARE_TWICE
57 rseq_after_asm_goto();
60 rseq_after_asm_goto();
64 rseq_after_asm_goto();
66 #ifdef RSEQ_COMPARE_TWICE
68 rseq_after_asm_goto();
69 rseq_bug("cpu_id comparison failed");
71 rseq_after_asm_goto();
72 rseq_bug("expected value comparison failed");
77 * Compare @v against @expectnot. When it does _not_ match, load @v
78 * into @load, and store the content of *@v + voffp into @v.
80 static inline __attribute__((always_inline
))
81 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load
)(intptr_t *v
, intptr_t expectnot
,
82 long voffp
, intptr_t *load
, int cpu
)
86 __asm__ __volatile__
goto (
87 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
88 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
89 #ifdef RSEQ_COMPARE_TWICE
90 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
91 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
93 /* Start rseq by storing table entry pointer into rseq_cs. */
94 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
95 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
97 "movq %[v], %%rbx\n\t"
98 "cmpq %%rbx, %[expectnot]\n\t"
101 #ifdef RSEQ_COMPARE_TWICE
102 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
103 "movq %[v], %%rbx\n\t"
104 "cmpq %%rbx, %[expectnot]\n\t"
107 "movq %%rbx, %[load]\n\t"
108 "addq %[voffp], %%rbx\n\t"
109 "movq (%%rbx), %%rbx\n\t"
111 "movq %%rbx, %[v]\n\t"
114 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
115 : /* gcc asm goto does not allow outputs */
116 : [cpu_id
] "r" (cpu
),
117 [rseq_offset
] "r" (rseq_offset
),
118 /* final store input */
120 [expectnot
] "r" (expectnot
),
121 [voffp
] "er" (voffp
),
123 : "memory", "cc", "rax", "rbx"
126 #ifdef RSEQ_COMPARE_TWICE
130 rseq_after_asm_goto();
133 rseq_after_asm_goto();
137 rseq_after_asm_goto();
139 #ifdef RSEQ_COMPARE_TWICE
141 rseq_after_asm_goto();
142 rseq_bug("cpu_id comparison failed");
144 rseq_after_asm_goto();
145 rseq_bug("expected value comparison failed");
149 static inline __attribute__((always_inline
))
150 int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv
)(intptr_t *v
, intptr_t count
, int cpu
)
154 __asm__ __volatile__
goto (
155 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
156 #ifdef RSEQ_COMPARE_TWICE
157 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
159 /* Start rseq by storing table entry pointer into rseq_cs. */
160 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
161 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
163 #ifdef RSEQ_COMPARE_TWICE
164 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
167 "addq %[count], %[v]\n\t"
170 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
171 : /* gcc asm goto does not allow outputs */
172 : [cpu_id
] "r" (cpu
),
173 [rseq_offset
] "r" (rseq_offset
),
174 /* final store input */
177 : "memory", "cc", "rax"
180 #ifdef RSEQ_COMPARE_TWICE
184 rseq_after_asm_goto();
187 rseq_after_asm_goto();
190 #ifdef RSEQ_COMPARE_TWICE
192 rseq_after_asm_goto();
193 rseq_bug("cpu_id comparison failed");
197 #define RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
203 static inline __attribute__((always_inline
))
204 int RSEQ_TEMPLATE_IDENTIFIER(rseq_offset_deref_addv
)(intptr_t *ptr
, long off
, intptr_t inc
, int cpu
)
208 __asm__ __volatile__
goto (
209 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
210 #ifdef RSEQ_COMPARE_TWICE
211 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
213 /* Start rseq by storing table entry pointer into rseq_cs. */
214 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
215 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
217 #ifdef RSEQ_COMPARE_TWICE
218 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
221 "movq %[ptr], %%rbx\n\t"
222 "addq %[off], %%rbx\n\t"
224 "movq (%%rbx), %%rcx\n\t"
226 "addq %[inc], (%%rcx)\n\t"
229 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
230 : /* gcc asm goto does not allow outputs */
231 : [cpu_id
] "r" (cpu
),
232 [rseq_offset
] "r" (rseq_offset
),
233 /* final store input */
237 : "memory", "cc", "rax", "rbx", "rcx"
240 #ifdef RSEQ_COMPARE_TWICE
248 #ifdef RSEQ_COMPARE_TWICE
250 rseq_bug("cpu_id comparison failed");
254 static inline __attribute__((always_inline
))
255 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
,
256 intptr_t *v2
, intptr_t expect2
,
257 intptr_t newv
, int cpu
)
261 __asm__ __volatile__
goto (
262 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
263 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
264 #ifdef RSEQ_COMPARE_TWICE
265 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
266 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
267 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
269 /* Start rseq by storing table entry pointer into rseq_cs. */
270 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
271 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
273 "cmpq %[v], %[expect]\n\t"
274 "jnz %l[cmpfail]\n\t"
276 "cmpq %[v2], %[expect2]\n\t"
277 "jnz %l[cmpfail]\n\t"
279 #ifdef RSEQ_COMPARE_TWICE
280 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
281 "cmpq %[v], %[expect]\n\t"
283 "cmpq %[v2], %[expect2]\n\t"
287 "movq %[newv], %[v]\n\t"
290 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
291 : /* gcc asm goto does not allow outputs */
292 : [cpu_id
] "r" (cpu
),
293 [rseq_offset
] "r" (rseq_offset
),
296 [expect2
] "r" (expect2
),
297 /* final store input */
299 [expect
] "r" (expect
),
301 : "memory", "cc", "rax"
304 #ifdef RSEQ_COMPARE_TWICE
305 , error1
, error2
, error3
308 rseq_after_asm_goto();
311 rseq_after_asm_goto();
315 rseq_after_asm_goto();
317 #ifdef RSEQ_COMPARE_TWICE
319 rseq_after_asm_goto();
320 rseq_bug("cpu_id comparison failed");
322 rseq_after_asm_goto();
323 rseq_bug("1st expected value comparison failed");
325 rseq_after_asm_goto();
326 rseq_bug("2nd expected value comparison failed");
330 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
331 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
333 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
334 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
336 static inline __attribute__((always_inline
))
337 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev
)(intptr_t *v
, intptr_t expect
,
338 intptr_t *v2
, intptr_t newv2
,
339 intptr_t newv
, int cpu
)
343 __asm__ __volatile__
goto (
344 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
345 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
346 #ifdef RSEQ_COMPARE_TWICE
347 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
348 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
350 /* Start rseq by storing table entry pointer into rseq_cs. */
351 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
352 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
354 "cmpq %[v], %[expect]\n\t"
355 "jnz %l[cmpfail]\n\t"
357 #ifdef RSEQ_COMPARE_TWICE
358 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
359 "cmpq %[v], %[expect]\n\t"
363 "movq %[newv2], %[v2]\n\t"
366 "movq %[newv], %[v]\n\t"
369 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
370 : /* gcc asm goto does not allow outputs */
371 : [cpu_id
] "r" (cpu
),
372 [rseq_offset
] "r" (rseq_offset
),
373 /* try store input */
376 /* final store input */
378 [expect
] "r" (expect
),
380 : "memory", "cc", "rax"
383 #ifdef RSEQ_COMPARE_TWICE
387 rseq_after_asm_goto();
390 rseq_after_asm_goto();
394 rseq_after_asm_goto();
396 #ifdef RSEQ_COMPARE_TWICE
398 rseq_after_asm_goto();
399 rseq_bug("cpu_id comparison failed");
401 rseq_after_asm_goto();
402 rseq_bug("expected value comparison failed");
406 static inline __attribute__((always_inline
))
407 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev
)(intptr_t *v
, intptr_t expect
,
408 void *dst
, void *src
, size_t len
,
409 intptr_t newv
, int cpu
)
411 uint64_t rseq_scratch
[3];
415 __asm__ __volatile__
goto (
416 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
417 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
418 #ifdef RSEQ_COMPARE_TWICE
419 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
420 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
422 "movq %[src], %[rseq_scratch0]\n\t"
423 "movq %[dst], %[rseq_scratch1]\n\t"
424 "movq %[len], %[rseq_scratch2]\n\t"
425 /* Start rseq by storing table entry pointer into rseq_cs. */
426 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
427 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
429 "cmpq %[v], %[expect]\n\t"
432 #ifdef RSEQ_COMPARE_TWICE
433 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 6f
)
434 "cmpq %[v], %[expect]\n\t"
438 "test %[len], %[len]\n\t" \
441 "movb (%[src]), %%al\n\t" \
442 "movb %%al, (%[dst])\n\t" \
450 "movq %[newv], %[v]\n\t"
454 "movq %[rseq_scratch2], %[len]\n\t"
455 "movq %[rseq_scratch1], %[dst]\n\t"
456 "movq %[rseq_scratch0], %[src]\n\t"
457 RSEQ_ASM_DEFINE_ABORT(4,
458 "movq %[rseq_scratch2], %[len]\n\t"
459 "movq %[rseq_scratch1], %[dst]\n\t"
460 "movq %[rseq_scratch0], %[src]\n\t",
462 RSEQ_ASM_DEFINE_CMPFAIL(5,
463 "movq %[rseq_scratch2], %[len]\n\t"
464 "movq %[rseq_scratch1], %[dst]\n\t"
465 "movq %[rseq_scratch0], %[src]\n\t",
467 #ifdef RSEQ_COMPARE_TWICE
468 RSEQ_ASM_DEFINE_CMPFAIL(6,
469 "movq %[rseq_scratch2], %[len]\n\t"
470 "movq %[rseq_scratch1], %[dst]\n\t"
471 "movq %[rseq_scratch0], %[src]\n\t",
473 RSEQ_ASM_DEFINE_CMPFAIL(7,
474 "movq %[rseq_scratch2], %[len]\n\t"
475 "movq %[rseq_scratch1], %[dst]\n\t"
476 "movq %[rseq_scratch0], %[src]\n\t",
479 : /* gcc asm goto does not allow outputs */
480 : [cpu_id
] "r" (cpu
),
481 [rseq_offset
] "r" (rseq_offset
),
482 /* final store input */
484 [expect
] "r" (expect
),
486 /* try memcpy input */
490 [rseq_scratch0
] "m" (rseq_scratch
[0]),
491 [rseq_scratch1
] "m" (rseq_scratch
[1]),
492 [rseq_scratch2
] "m" (rseq_scratch
[2])
493 : "memory", "cc", "rax"
496 #ifdef RSEQ_COMPARE_TWICE
500 rseq_after_asm_goto();
503 rseq_after_asm_goto();
507 rseq_after_asm_goto();
509 #ifdef RSEQ_COMPARE_TWICE
511 rseq_after_asm_goto();
512 rseq_bug("cpu_id comparison failed");
514 rseq_after_asm_goto();
515 rseq_bug("expected value comparison failed");
519 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
520 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
522 #elif defined(__i386__)
524 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
525 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
527 static inline __attribute__((always_inline
))
528 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
532 __asm__ __volatile__
goto (
533 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
534 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
535 #ifdef RSEQ_COMPARE_TWICE
536 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
537 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
539 /* Start rseq by storing table entry pointer into rseq_cs. */
540 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
541 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
543 "cmpl %[v], %[expect]\n\t"
544 "jnz %l[cmpfail]\n\t"
546 #ifdef RSEQ_COMPARE_TWICE
547 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
548 "cmpl %[v], %[expect]\n\t"
552 "movl %[newv], %[v]\n\t"
555 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
556 : /* gcc asm goto does not allow outputs */
557 : [cpu_id
] "r" (cpu
),
558 [rseq_offset
] "r" (rseq_offset
),
560 [expect
] "r" (expect
),
562 : "memory", "cc", "eax"
565 #ifdef RSEQ_COMPARE_TWICE
569 rseq_after_asm_goto();
572 rseq_after_asm_goto();
576 rseq_after_asm_goto();
578 #ifdef RSEQ_COMPARE_TWICE
580 rseq_after_asm_goto();
581 rseq_bug("cpu_id comparison failed");
583 rseq_after_asm_goto();
584 rseq_bug("expected value comparison failed");
589 * Compare @v against @expectnot. When it does _not_ match, load @v
590 * into @load, and store the content of *@v + voffp into @v.
592 static inline __attribute__((always_inline
))
593 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load
)(intptr_t *v
, intptr_t expectnot
,
594 long voffp
, intptr_t *load
, int cpu
)
598 __asm__ __volatile__
goto (
599 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
600 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
601 #ifdef RSEQ_COMPARE_TWICE
602 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
603 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
605 /* Start rseq by storing table entry pointer into rseq_cs. */
606 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
607 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
609 "movl %[v], %%ebx\n\t"
610 "cmpl %%ebx, %[expectnot]\n\t"
613 #ifdef RSEQ_COMPARE_TWICE
614 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
615 "movl %[v], %%ebx\n\t"
616 "cmpl %%ebx, %[expectnot]\n\t"
619 "movl %%ebx, %[load]\n\t"
620 "addl %[voffp], %%ebx\n\t"
621 "movl (%%ebx), %%ebx\n\t"
623 "movl %%ebx, %[v]\n\t"
626 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
627 : /* gcc asm goto does not allow outputs */
628 : [cpu_id
] "r" (cpu
),
629 [rseq_offset
] "r" (rseq_offset
),
630 /* final store input */
632 [expectnot
] "r" (expectnot
),
633 [voffp
] "ir" (voffp
),
635 : "memory", "cc", "eax", "ebx"
638 #ifdef RSEQ_COMPARE_TWICE
642 rseq_after_asm_goto();
645 rseq_after_asm_goto();
649 rseq_after_asm_goto();
651 #ifdef RSEQ_COMPARE_TWICE
653 rseq_after_asm_goto();
654 rseq_bug("cpu_id comparison failed");
656 rseq_after_asm_goto();
657 rseq_bug("expected value comparison failed");
661 static inline __attribute__((always_inline
))
662 int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv
)(intptr_t *v
, intptr_t count
, int cpu
)
666 __asm__ __volatile__
goto (
667 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
668 #ifdef RSEQ_COMPARE_TWICE
669 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
671 /* Start rseq by storing table entry pointer into rseq_cs. */
672 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
673 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
675 #ifdef RSEQ_COMPARE_TWICE
676 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
679 "addl %[count], %[v]\n\t"
682 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
683 : /* gcc asm goto does not allow outputs */
684 : [cpu_id
] "r" (cpu
),
685 [rseq_offset
] "r" (rseq_offset
),
686 /* final store input */
689 : "memory", "cc", "eax"
692 #ifdef RSEQ_COMPARE_TWICE
696 rseq_after_asm_goto();
699 rseq_after_asm_goto();
702 #ifdef RSEQ_COMPARE_TWICE
704 rseq_after_asm_goto();
705 rseq_bug("cpu_id comparison failed");
709 static inline __attribute__((always_inline
))
710 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
,
711 intptr_t *v2
, intptr_t expect2
,
712 intptr_t newv
, int cpu
)
716 __asm__ __volatile__
goto (
717 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
718 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
719 #ifdef RSEQ_COMPARE_TWICE
720 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
721 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
722 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
724 /* Start rseq by storing table entry pointer into rseq_cs. */
725 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
726 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
728 "cmpl %[v], %[expect]\n\t"
729 "jnz %l[cmpfail]\n\t"
731 "cmpl %[expect2], %[v2]\n\t"
732 "jnz %l[cmpfail]\n\t"
734 #ifdef RSEQ_COMPARE_TWICE
735 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
736 "cmpl %[v], %[expect]\n\t"
738 "cmpl %[expect2], %[v2]\n\t"
741 "movl %[newv], %%eax\n\t"
743 "movl %%eax, %[v]\n\t"
746 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
747 : /* gcc asm goto does not allow outputs */
748 : [cpu_id
] "r" (cpu
),
749 [rseq_offset
] "r" (rseq_offset
),
752 [expect2
] "r" (expect2
),
753 /* final store input */
755 [expect
] "r" (expect
),
757 : "memory", "cc", "eax"
760 #ifdef RSEQ_COMPARE_TWICE
761 , error1
, error2
, error3
764 rseq_after_asm_goto();
767 rseq_after_asm_goto();
771 rseq_after_asm_goto();
773 #ifdef RSEQ_COMPARE_TWICE
775 rseq_after_asm_goto();
776 rseq_bug("cpu_id comparison failed");
778 rseq_after_asm_goto();
779 rseq_bug("1st expected value comparison failed");
781 rseq_after_asm_goto();
782 rseq_bug("2nd expected value comparison failed");
786 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
787 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
789 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
790 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
792 static inline __attribute__((always_inline
))
793 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev
)(intptr_t *v
, intptr_t expect
,
794 intptr_t *v2
, intptr_t newv2
,
795 intptr_t newv
, int cpu
)
799 __asm__ __volatile__
goto (
800 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
801 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
802 #ifdef RSEQ_COMPARE_TWICE
803 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
804 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
806 /* Start rseq by storing table entry pointer into rseq_cs. */
807 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
808 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
810 "movl %[expect], %%eax\n\t"
811 "cmpl %[v], %%eax\n\t"
812 "jnz %l[cmpfail]\n\t"
814 #ifdef RSEQ_COMPARE_TWICE
815 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
816 "movl %[expect], %%eax\n\t"
817 "cmpl %[v], %%eax\n\t"
821 "movl %[newv2], %[v2]\n\t"
823 #ifdef RSEQ_TEMPLATE_MO_RELEASE
824 "lock; addl $0,-128(%%esp)\n\t"
827 "movl %[newv], %[v]\n\t"
830 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
831 : /* gcc asm goto does not allow outputs */
832 : [cpu_id
] "r" (cpu
),
833 [rseq_offset
] "r" (rseq_offset
),
834 /* try store input */
837 /* final store input */
839 [expect
] "m" (expect
),
841 : "memory", "cc", "eax"
844 #ifdef RSEQ_COMPARE_TWICE
848 rseq_after_asm_goto();
851 rseq_after_asm_goto();
855 rseq_after_asm_goto();
857 #ifdef RSEQ_COMPARE_TWICE
859 rseq_after_asm_goto();
860 rseq_bug("cpu_id comparison failed");
862 rseq_after_asm_goto();
863 rseq_bug("expected value comparison failed");
868 /* TODO: implement a faster memcpy. */
869 static inline __attribute__((always_inline
))
870 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev
)(intptr_t *v
, intptr_t expect
,
871 void *dst
, void *src
, size_t len
,
872 intptr_t newv
, int cpu
)
874 uint32_t rseq_scratch
[3];
878 __asm__ __volatile__
goto (
879 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
880 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
881 #ifdef RSEQ_COMPARE_TWICE
882 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
883 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
885 "movl %[src], %[rseq_scratch0]\n\t"
886 "movl %[dst], %[rseq_scratch1]\n\t"
887 "movl %[len], %[rseq_scratch2]\n\t"
888 /* Start rseq by storing table entry pointer into rseq_cs. */
889 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_CS_OFFSET(%[rseq_offset
]))
890 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
892 "movl %[expect], %%eax\n\t"
893 "cmpl %%eax, %[v]\n\t"
896 #ifdef RSEQ_COMPARE_TWICE
897 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_CPU_ID_OFFSET(%[rseq_offset
]), 6f
)
898 "movl %[expect], %%eax\n\t"
899 "cmpl %%eax, %[v]\n\t"
903 "test %[len], %[len]\n\t" \
906 "movb (%[src]), %%al\n\t" \
907 "movb %%al, (%[dst])\n\t" \
914 #ifdef RSEQ_TEMPLATE_MO_RELEASE
915 "lock; addl $0,-128(%%esp)\n\t"
917 "movl %[newv], %%eax\n\t"
919 "movl %%eax, %[v]\n\t"
923 "movl %[rseq_scratch2], %[len]\n\t"
924 "movl %[rseq_scratch1], %[dst]\n\t"
925 "movl %[rseq_scratch0], %[src]\n\t"
926 RSEQ_ASM_DEFINE_ABORT(4,
927 "movl %[rseq_scratch2], %[len]\n\t"
928 "movl %[rseq_scratch1], %[dst]\n\t"
929 "movl %[rseq_scratch0], %[src]\n\t",
931 RSEQ_ASM_DEFINE_CMPFAIL(5,
932 "movl %[rseq_scratch2], %[len]\n\t"
933 "movl %[rseq_scratch1], %[dst]\n\t"
934 "movl %[rseq_scratch0], %[src]\n\t",
936 #ifdef RSEQ_COMPARE_TWICE
937 RSEQ_ASM_DEFINE_CMPFAIL(6,
938 "movl %[rseq_scratch2], %[len]\n\t"
939 "movl %[rseq_scratch1], %[dst]\n\t"
940 "movl %[rseq_scratch0], %[src]\n\t",
942 RSEQ_ASM_DEFINE_CMPFAIL(7,
943 "movl %[rseq_scratch2], %[len]\n\t"
944 "movl %[rseq_scratch1], %[dst]\n\t"
945 "movl %[rseq_scratch0], %[src]\n\t",
948 : /* gcc asm goto does not allow outputs */
949 : [cpu_id
] "r" (cpu
),
950 [rseq_offset
] "r" (rseq_offset
),
951 /* final store input */
953 [expect
] "m" (expect
),
955 /* try memcpy input */
959 [rseq_scratch0
] "m" (rseq_scratch
[0]),
960 [rseq_scratch1
] "m" (rseq_scratch
[1]),
961 [rseq_scratch2
] "m" (rseq_scratch
[2])
962 : "memory", "cc", "eax"
965 #ifdef RSEQ_COMPARE_TWICE
969 rseq_after_asm_goto();
972 rseq_after_asm_goto();
976 rseq_after_asm_goto();
978 #ifdef RSEQ_COMPARE_TWICE
980 rseq_after_asm_goto();
981 rseq_bug("cpu_id comparison failed");
983 rseq_after_asm_goto();
984 rseq_bug("expected value comparison failed");
988 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
989 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
993 #include "rseq-bits-reset.h"