1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
11 * RSEQ_SIG is used with the following reserved undefined instructions, which
14 * x86-32: 0f b9 3d 53 30 05 53 ud1 0x53053053,%edi
15 * x86-64: 0f b9 3d 53 30 05 53 ud1 0x53053053(%rip),%edi
17 #define RSEQ_SIG 0x53053053
20 * Due to a compiler optimization bug in gcc-8 with asm goto and TLS asm input
21 * operands, we cannot use "m" input operands, and rather pass the __rseq_abi
22 * address through a "r" input operand.
25 /* Offset of cpu_id and rseq_cs fields in struct rseq. */
26 #define RSEQ_CPU_ID_OFFSET 4
27 #define RSEQ_CS_OFFSET 8
31 #define rseq_smp_mb() \
32 __asm__ __volatile__ ("lock; addl $0,-128(%%rsp)" ::: "memory", "cc")
33 #define rseq_smp_rmb() rseq_barrier()
34 #define rseq_smp_wmb() rseq_barrier()
36 #define rseq_smp_load_acquire(p) \
38 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
43 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
45 #define rseq_smp_store_release(p, v) \
48 RSEQ_WRITE_ONCE(*p, v); \
51 #ifdef RSEQ_SKIP_FASTPATH
52 #include "rseq-skip.h"
53 #else /* !RSEQ_SKIP_FASTPATH */
55 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
56 start_ip, post_commit_offset, abort_ip) \
57 ".pushsection __rseq_cs, \"aw\"\n\t" \
59 __rseq_str(label) ":\n\t" \
60 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
61 ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
63 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
64 ".quad " __rseq_str(label) "b\n\t" \
68 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
69 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
70 (post_commit_ip - start_ip), abort_ip)
73 * Exit points of a rseq critical section consist of all instructions outside
74 * of the critical section where a critical section can either branch to or
75 * reach through the normal course of its execution. The abort IP and the
76 * post-commit IP are already part of the __rseq_cs section and should not be
77 * explicitly defined as additional exit points. Knowing all exit points is
78 * useful to assist debuggers stepping over the critical section.
80 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
81 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
82 ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
85 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
87 "leaq " __rseq_str(cs_label) "(%%rip), %%rax\n\t" \
88 "movq %%rax, " __rseq_str(rseq_cs) "\n\t" \
89 __rseq_str(label) ":\n\t"
91 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
93 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
94 "jnz " __rseq_str(label) "\n\t"
96 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
97 ".pushsection __rseq_failure, \"ax\"\n\t" \
98 /* Disassembler-friendly signature: ud1 <sig>(%rip),%edi. */ \
99 ".byte 0x0f, 0xb9, 0x3d\n\t" \
100 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
101 __rseq_str(label) ":\n\t" \
103 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
106 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
107 ".pushsection __rseq_failure, \"ax\"\n\t" \
108 __rseq_str(label) ":\n\t" \
110 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
113 static inline __attribute__((always_inline
))
114 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
118 __asm__ __volatile__
goto (
119 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
120 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
121 #ifdef RSEQ_COMPARE_TWICE
122 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
123 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
125 /* Start rseq by storing table entry pointer into rseq_cs. */
126 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
127 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
129 "cmpq %[v], %[expect]\n\t"
130 "jnz %l[cmpfail]\n\t"
132 #ifdef RSEQ_COMPARE_TWICE
133 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
134 "cmpq %[v], %[expect]\n\t"
138 "movq %[newv], %[v]\n\t"
141 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
142 : /* gcc asm goto does not allow outputs */
143 : [cpu_id
] "r" (cpu
),
144 [rseq_abi
] "r" (&__rseq_abi
),
146 [expect
] "r" (expect
),
148 : "memory", "cc", "rax"
151 #ifdef RSEQ_COMPARE_TWICE
161 #ifdef RSEQ_COMPARE_TWICE
163 rseq_bug("cpu_id comparison failed");
165 rseq_bug("expected value comparison failed");
170 * Compare @v against @expectnot. When it does _not_ match, load @v
171 * into @load, and store the content of *@v + voffp into @v.
173 static inline __attribute__((always_inline
))
174 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
175 off_t voffp
, intptr_t *load
, int cpu
)
179 __asm__ __volatile__
goto (
180 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
181 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
182 #ifdef RSEQ_COMPARE_TWICE
183 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
184 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
186 /* Start rseq by storing table entry pointer into rseq_cs. */
187 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
188 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
190 "movq %[v], %%rbx\n\t"
191 "cmpq %%rbx, %[expectnot]\n\t"
194 #ifdef RSEQ_COMPARE_TWICE
195 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
196 "movq %[v], %%rbx\n\t"
197 "cmpq %%rbx, %[expectnot]\n\t"
200 "movq %%rbx, %[load]\n\t"
201 "addq %[voffp], %%rbx\n\t"
202 "movq (%%rbx), %%rbx\n\t"
204 "movq %%rbx, %[v]\n\t"
207 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
208 : /* gcc asm goto does not allow outputs */
209 : [cpu_id
] "r" (cpu
),
210 [rseq_abi
] "r" (&__rseq_abi
),
211 /* final store input */
213 [expectnot
] "r" (expectnot
),
214 [voffp
] "er" (voffp
),
216 : "memory", "cc", "rax", "rbx"
219 #ifdef RSEQ_COMPARE_TWICE
229 #ifdef RSEQ_COMPARE_TWICE
231 rseq_bug("cpu_id comparison failed");
233 rseq_bug("expected value comparison failed");
237 static inline __attribute__((always_inline
))
238 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
242 __asm__ __volatile__
goto (
243 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
244 #ifdef RSEQ_COMPARE_TWICE
245 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
247 /* Start rseq by storing table entry pointer into rseq_cs. */
248 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
249 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
251 #ifdef RSEQ_COMPARE_TWICE
252 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
255 "addq %[count], %[v]\n\t"
258 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
259 : /* gcc asm goto does not allow outputs */
260 : [cpu_id
] "r" (cpu
),
261 [rseq_abi
] "r" (&__rseq_abi
),
262 /* final store input */
265 : "memory", "cc", "rax"
268 #ifdef RSEQ_COMPARE_TWICE
276 #ifdef RSEQ_COMPARE_TWICE
278 rseq_bug("cpu_id comparison failed");
282 static inline __attribute__((always_inline
))
283 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
284 intptr_t *v2
, intptr_t newv2
,
285 intptr_t newv
, int cpu
)
289 __asm__ __volatile__
goto (
290 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
291 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
292 #ifdef RSEQ_COMPARE_TWICE
293 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
294 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
296 /* Start rseq by storing table entry pointer into rseq_cs. */
297 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
298 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
300 "cmpq %[v], %[expect]\n\t"
301 "jnz %l[cmpfail]\n\t"
303 #ifdef RSEQ_COMPARE_TWICE
304 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
305 "cmpq %[v], %[expect]\n\t"
309 "movq %[newv2], %[v2]\n\t"
312 "movq %[newv], %[v]\n\t"
315 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
316 : /* gcc asm goto does not allow outputs */
317 : [cpu_id
] "r" (cpu
),
318 [rseq_abi
] "r" (&__rseq_abi
),
319 /* try store input */
322 /* final store input */
324 [expect
] "r" (expect
),
326 : "memory", "cc", "rax"
329 #ifdef RSEQ_COMPARE_TWICE
339 #ifdef RSEQ_COMPARE_TWICE
341 rseq_bug("cpu_id comparison failed");
343 rseq_bug("expected value comparison failed");
348 static inline __attribute__((always_inline
))
349 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
350 intptr_t *v2
, intptr_t newv2
,
351 intptr_t newv
, int cpu
)
353 return rseq_cmpeqv_trystorev_storev(v
, expect
, v2
, newv2
, newv
, cpu
);
356 static inline __attribute__((always_inline
))
357 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
358 intptr_t *v2
, intptr_t expect2
,
359 intptr_t newv
, int cpu
)
363 __asm__ __volatile__
goto (
364 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
365 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
366 #ifdef RSEQ_COMPARE_TWICE
367 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
368 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
369 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
371 /* Start rseq by storing table entry pointer into rseq_cs. */
372 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
373 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
375 "cmpq %[v], %[expect]\n\t"
376 "jnz %l[cmpfail]\n\t"
378 "cmpq %[v2], %[expect2]\n\t"
379 "jnz %l[cmpfail]\n\t"
381 #ifdef RSEQ_COMPARE_TWICE
382 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
383 "cmpq %[v], %[expect]\n\t"
385 "cmpq %[v2], %[expect2]\n\t"
389 "movq %[newv], %[v]\n\t"
392 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
393 : /* gcc asm goto does not allow outputs */
394 : [cpu_id
] "r" (cpu
),
395 [rseq_abi
] "r" (&__rseq_abi
),
398 [expect2
] "r" (expect2
),
399 /* final store input */
401 [expect
] "r" (expect
),
403 : "memory", "cc", "rax"
406 #ifdef RSEQ_COMPARE_TWICE
407 , error1
, error2
, error3
416 #ifdef RSEQ_COMPARE_TWICE
418 rseq_bug("cpu_id comparison failed");
420 rseq_bug("1st expected value comparison failed");
422 rseq_bug("2nd expected value comparison failed");
426 static inline __attribute__((always_inline
))
427 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
428 void *dst
, void *src
, size_t len
,
429 intptr_t newv
, int cpu
)
431 uint64_t rseq_scratch
[3];
435 __asm__ __volatile__
goto (
436 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
437 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
438 #ifdef RSEQ_COMPARE_TWICE
439 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
440 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
442 "movq %[src], %[rseq_scratch0]\n\t"
443 "movq %[dst], %[rseq_scratch1]\n\t"
444 "movq %[len], %[rseq_scratch2]\n\t"
445 /* Start rseq by storing table entry pointer into rseq_cs. */
446 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
447 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
449 "cmpq %[v], %[expect]\n\t"
452 #ifdef RSEQ_COMPARE_TWICE
453 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
454 "cmpq %[v], %[expect]\n\t"
458 "test %[len], %[len]\n\t" \
461 "movb (%[src]), %%al\n\t" \
462 "movb %%al, (%[dst])\n\t" \
470 "movq %[newv], %[v]\n\t"
474 "movq %[rseq_scratch2], %[len]\n\t"
475 "movq %[rseq_scratch1], %[dst]\n\t"
476 "movq %[rseq_scratch0], %[src]\n\t"
477 RSEQ_ASM_DEFINE_ABORT(4,
478 "movq %[rseq_scratch2], %[len]\n\t"
479 "movq %[rseq_scratch1], %[dst]\n\t"
480 "movq %[rseq_scratch0], %[src]\n\t",
482 RSEQ_ASM_DEFINE_CMPFAIL(5,
483 "movq %[rseq_scratch2], %[len]\n\t"
484 "movq %[rseq_scratch1], %[dst]\n\t"
485 "movq %[rseq_scratch0], %[src]\n\t",
487 #ifdef RSEQ_COMPARE_TWICE
488 RSEQ_ASM_DEFINE_CMPFAIL(6,
489 "movq %[rseq_scratch2], %[len]\n\t"
490 "movq %[rseq_scratch1], %[dst]\n\t"
491 "movq %[rseq_scratch0], %[src]\n\t",
493 RSEQ_ASM_DEFINE_CMPFAIL(7,
494 "movq %[rseq_scratch2], %[len]\n\t"
495 "movq %[rseq_scratch1], %[dst]\n\t"
496 "movq %[rseq_scratch0], %[src]\n\t",
499 : /* gcc asm goto does not allow outputs */
500 : [cpu_id
] "r" (cpu
),
501 [rseq_abi
] "r" (&__rseq_abi
),
502 /* final store input */
504 [expect
] "r" (expect
),
506 /* try memcpy input */
510 [rseq_scratch0
] "m" (rseq_scratch
[0]),
511 [rseq_scratch1
] "m" (rseq_scratch
[1]),
512 [rseq_scratch2
] "m" (rseq_scratch
[2])
513 : "memory", "cc", "rax"
516 #ifdef RSEQ_COMPARE_TWICE
526 #ifdef RSEQ_COMPARE_TWICE
528 rseq_bug("cpu_id comparison failed");
530 rseq_bug("expected value comparison failed");
535 static inline __attribute__((always_inline
))
536 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
537 void *dst
, void *src
, size_t len
,
538 intptr_t newv
, int cpu
)
540 return rseq_cmpeqv_trymemcpy_storev(v
, expect
, dst
, src
, len
,
544 #endif /* !RSEQ_SKIP_FASTPATH */
548 #define rseq_smp_mb() \
549 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
550 #define rseq_smp_rmb() \
551 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
552 #define rseq_smp_wmb() \
553 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
555 #define rseq_smp_load_acquire(p) \
557 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
562 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
564 #define rseq_smp_store_release(p, v) \
567 RSEQ_WRITE_ONCE(*p, v); \
570 #ifdef RSEQ_SKIP_FASTPATH
571 #include "rseq-skip.h"
572 #else /* !RSEQ_SKIP_FASTPATH */
575 * Use eax as scratch register and take memory operands as input to
576 * lessen register pressure. Especially needed when compiling in O0.
578 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
579 start_ip, post_commit_offset, abort_ip) \
580 ".pushsection __rseq_cs, \"aw\"\n\t" \
582 __rseq_str(label) ":\n\t" \
583 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
584 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
586 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
587 ".long " __rseq_str(label) "b, 0x0\n\t" \
590 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
591 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
592 (post_commit_ip - start_ip), abort_ip)
595 * Exit points of a rseq critical section consist of all instructions outside
596 * of the critical section where a critical section can either branch to or
597 * reach through the normal course of its execution. The abort IP and the
598 * post-commit IP are already part of the __rseq_cs section and should not be
599 * explicitly defined as additional exit points. Knowing all exit points is
600 * useful to assist debuggers stepping over the critical section.
602 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
603 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
604 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
607 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
609 "movl $" __rseq_str(cs_label) ", " __rseq_str(rseq_cs) "\n\t" \
610 __rseq_str(label) ":\n\t"
612 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
614 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
615 "jnz " __rseq_str(label) "\n\t"
617 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
618 ".pushsection __rseq_failure, \"ax\"\n\t" \
619 /* Disassembler-friendly signature: ud1 <sig>,%edi. */ \
620 ".byte 0x0f, 0xb9, 0x3d\n\t" \
621 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
622 __rseq_str(label) ":\n\t" \
624 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
627 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
628 ".pushsection __rseq_failure, \"ax\"\n\t" \
629 __rseq_str(label) ":\n\t" \
631 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
634 static inline __attribute__((always_inline
))
635 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
639 __asm__ __volatile__
goto (
640 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
641 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
642 #ifdef RSEQ_COMPARE_TWICE
643 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
644 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
646 /* Start rseq by storing table entry pointer into rseq_cs. */
647 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
648 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
650 "cmpl %[v], %[expect]\n\t"
651 "jnz %l[cmpfail]\n\t"
653 #ifdef RSEQ_COMPARE_TWICE
654 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
655 "cmpl %[v], %[expect]\n\t"
659 "movl %[newv], %[v]\n\t"
662 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
663 : /* gcc asm goto does not allow outputs */
664 : [cpu_id
] "r" (cpu
),
665 [rseq_abi
] "r" (&__rseq_abi
),
667 [expect
] "r" (expect
),
669 : "memory", "cc", "eax"
672 #ifdef RSEQ_COMPARE_TWICE
682 #ifdef RSEQ_COMPARE_TWICE
684 rseq_bug("cpu_id comparison failed");
686 rseq_bug("expected value comparison failed");
691 * Compare @v against @expectnot. When it does _not_ match, load @v
692 * into @load, and store the content of *@v + voffp into @v.
694 static inline __attribute__((always_inline
))
695 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
696 off_t voffp
, intptr_t *load
, int cpu
)
700 __asm__ __volatile__
goto (
701 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
702 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
703 #ifdef RSEQ_COMPARE_TWICE
704 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
705 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
707 /* Start rseq by storing table entry pointer into rseq_cs. */
708 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
709 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
711 "movl %[v], %%ebx\n\t"
712 "cmpl %%ebx, %[expectnot]\n\t"
715 #ifdef RSEQ_COMPARE_TWICE
716 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
717 "movl %[v], %%ebx\n\t"
718 "cmpl %%ebx, %[expectnot]\n\t"
721 "movl %%ebx, %[load]\n\t"
722 "addl %[voffp], %%ebx\n\t"
723 "movl (%%ebx), %%ebx\n\t"
725 "movl %%ebx, %[v]\n\t"
728 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
729 : /* gcc asm goto does not allow outputs */
730 : [cpu_id
] "r" (cpu
),
731 [rseq_abi
] "r" (&__rseq_abi
),
732 /* final store input */
734 [expectnot
] "r" (expectnot
),
735 [voffp
] "ir" (voffp
),
737 : "memory", "cc", "eax", "ebx"
740 #ifdef RSEQ_COMPARE_TWICE
750 #ifdef RSEQ_COMPARE_TWICE
752 rseq_bug("cpu_id comparison failed");
754 rseq_bug("expected value comparison failed");
758 static inline __attribute__((always_inline
))
759 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
763 __asm__ __volatile__
goto (
764 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
765 #ifdef RSEQ_COMPARE_TWICE
766 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
768 /* Start rseq by storing table entry pointer into rseq_cs. */
769 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
770 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
772 #ifdef RSEQ_COMPARE_TWICE
773 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
776 "addl %[count], %[v]\n\t"
779 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
780 : /* gcc asm goto does not allow outputs */
781 : [cpu_id
] "r" (cpu
),
782 [rseq_abi
] "r" (&__rseq_abi
),
783 /* final store input */
786 : "memory", "cc", "eax"
789 #ifdef RSEQ_COMPARE_TWICE
797 #ifdef RSEQ_COMPARE_TWICE
799 rseq_bug("cpu_id comparison failed");
803 static inline __attribute__((always_inline
))
804 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
805 intptr_t *v2
, intptr_t newv2
,
806 intptr_t newv
, int cpu
)
810 __asm__ __volatile__
goto (
811 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
812 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
813 #ifdef RSEQ_COMPARE_TWICE
814 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
815 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
817 /* Start rseq by storing table entry pointer into rseq_cs. */
818 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
819 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
821 "cmpl %[v], %[expect]\n\t"
822 "jnz %l[cmpfail]\n\t"
824 #ifdef RSEQ_COMPARE_TWICE
825 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
826 "cmpl %[v], %[expect]\n\t"
830 "movl %[newv2], %%eax\n\t"
831 "movl %%eax, %[v2]\n\t"
834 "movl %[newv], %[v]\n\t"
837 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
838 : /* gcc asm goto does not allow outputs */
839 : [cpu_id
] "r" (cpu
),
840 [rseq_abi
] "r" (&__rseq_abi
),
841 /* try store input */
844 /* final store input */
846 [expect
] "r" (expect
),
848 : "memory", "cc", "eax"
851 #ifdef RSEQ_COMPARE_TWICE
861 #ifdef RSEQ_COMPARE_TWICE
863 rseq_bug("cpu_id comparison failed");
865 rseq_bug("expected value comparison failed");
869 static inline __attribute__((always_inline
))
870 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
871 intptr_t *v2
, intptr_t newv2
,
872 intptr_t newv
, int cpu
)
876 __asm__ __volatile__
goto (
877 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
878 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
879 #ifdef RSEQ_COMPARE_TWICE
880 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
881 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
883 /* Start rseq by storing table entry pointer into rseq_cs. */
884 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
885 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
887 "movl %[expect], %%eax\n\t"
888 "cmpl %[v], %%eax\n\t"
889 "jnz %l[cmpfail]\n\t"
891 #ifdef RSEQ_COMPARE_TWICE
892 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
893 "movl %[expect], %%eax\n\t"
894 "cmpl %[v], %%eax\n\t"
898 "movl %[newv2], %[v2]\n\t"
900 "lock; addl $0,-128(%%esp)\n\t"
902 "movl %[newv], %[v]\n\t"
905 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
906 : /* gcc asm goto does not allow outputs */
907 : [cpu_id
] "r" (cpu
),
908 [rseq_abi
] "r" (&__rseq_abi
),
909 /* try store input */
912 /* final store input */
914 [expect
] "m" (expect
),
916 : "memory", "cc", "eax"
919 #ifdef RSEQ_COMPARE_TWICE
929 #ifdef RSEQ_COMPARE_TWICE
931 rseq_bug("cpu_id comparison failed");
933 rseq_bug("expected value comparison failed");
938 static inline __attribute__((always_inline
))
939 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
940 intptr_t *v2
, intptr_t expect2
,
941 intptr_t newv
, int cpu
)
945 __asm__ __volatile__
goto (
946 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
947 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
948 #ifdef RSEQ_COMPARE_TWICE
949 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
950 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
951 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
953 /* Start rseq by storing table entry pointer into rseq_cs. */
954 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
955 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
957 "cmpl %[v], %[expect]\n\t"
958 "jnz %l[cmpfail]\n\t"
960 "cmpl %[expect2], %[v2]\n\t"
961 "jnz %l[cmpfail]\n\t"
963 #ifdef RSEQ_COMPARE_TWICE
964 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
965 "cmpl %[v], %[expect]\n\t"
967 "cmpl %[expect2], %[v2]\n\t"
970 "movl %[newv], %%eax\n\t"
972 "movl %%eax, %[v]\n\t"
975 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
976 : /* gcc asm goto does not allow outputs */
977 : [cpu_id
] "r" (cpu
),
978 [rseq_abi
] "r" (&__rseq_abi
),
981 [expect2
] "r" (expect2
),
982 /* final store input */
984 [expect
] "r" (expect
),
986 : "memory", "cc", "eax"
989 #ifdef RSEQ_COMPARE_TWICE
990 , error1
, error2
, error3
999 #ifdef RSEQ_COMPARE_TWICE
1001 rseq_bug("cpu_id comparison failed");
1003 rseq_bug("1st expected value comparison failed");
1005 rseq_bug("2nd expected value comparison failed");
1009 /* TODO: implement a faster memcpy. */
1010 static inline __attribute__((always_inline
))
1011 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
1012 void *dst
, void *src
, size_t len
,
1013 intptr_t newv
, int cpu
)
1015 uint32_t rseq_scratch
[3];
1019 __asm__ __volatile__
goto (
1020 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1021 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1022 #ifdef RSEQ_COMPARE_TWICE
1023 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1024 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1026 "movl %[src], %[rseq_scratch0]\n\t"
1027 "movl %[dst], %[rseq_scratch1]\n\t"
1028 "movl %[len], %[rseq_scratch2]\n\t"
1029 /* Start rseq by storing table entry pointer into rseq_cs. */
1030 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1031 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1033 "movl %[expect], %%eax\n\t"
1034 "cmpl %%eax, %[v]\n\t"
1037 #ifdef RSEQ_COMPARE_TWICE
1038 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
1039 "movl %[expect], %%eax\n\t"
1040 "cmpl %%eax, %[v]\n\t"
1044 "test %[len], %[len]\n\t" \
1047 "movb (%[src]), %%al\n\t" \
1048 "movb %%al, (%[dst])\n\t" \
1055 "movl %[newv], %%eax\n\t"
1057 "movl %%eax, %[v]\n\t"
1061 "movl %[rseq_scratch2], %[len]\n\t"
1062 "movl %[rseq_scratch1], %[dst]\n\t"
1063 "movl %[rseq_scratch0], %[src]\n\t"
1064 RSEQ_ASM_DEFINE_ABORT(4,
1065 "movl %[rseq_scratch2], %[len]\n\t"
1066 "movl %[rseq_scratch1], %[dst]\n\t"
1067 "movl %[rseq_scratch0], %[src]\n\t",
1069 RSEQ_ASM_DEFINE_CMPFAIL(5,
1070 "movl %[rseq_scratch2], %[len]\n\t"
1071 "movl %[rseq_scratch1], %[dst]\n\t"
1072 "movl %[rseq_scratch0], %[src]\n\t",
1074 #ifdef RSEQ_COMPARE_TWICE
1075 RSEQ_ASM_DEFINE_CMPFAIL(6,
1076 "movl %[rseq_scratch2], %[len]\n\t"
1077 "movl %[rseq_scratch1], %[dst]\n\t"
1078 "movl %[rseq_scratch0], %[src]\n\t",
1080 RSEQ_ASM_DEFINE_CMPFAIL(7,
1081 "movl %[rseq_scratch2], %[len]\n\t"
1082 "movl %[rseq_scratch1], %[dst]\n\t"
1083 "movl %[rseq_scratch0], %[src]\n\t",
1086 : /* gcc asm goto does not allow outputs */
1087 : [cpu_id
] "r" (cpu
),
1088 [rseq_abi
] "r" (&__rseq_abi
),
1089 /* final store input */
1091 [expect
] "m" (expect
),
1093 /* try memcpy input */
1097 [rseq_scratch0
] "m" (rseq_scratch
[0]),
1098 [rseq_scratch1
] "m" (rseq_scratch
[1]),
1099 [rseq_scratch2
] "m" (rseq_scratch
[2])
1100 : "memory", "cc", "eax"
1103 #ifdef RSEQ_COMPARE_TWICE
1113 #ifdef RSEQ_COMPARE_TWICE
1115 rseq_bug("cpu_id comparison failed");
1117 rseq_bug("expected value comparison failed");
1121 /* TODO: implement a faster memcpy. */
1122 static inline __attribute__((always_inline
))
1123 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
1124 void *dst
, void *src
, size_t len
,
1125 intptr_t newv
, int cpu
)
1127 uint32_t rseq_scratch
[3];
1131 __asm__ __volatile__
goto (
1132 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1133 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1134 #ifdef RSEQ_COMPARE_TWICE
1135 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1136 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1138 "movl %[src], %[rseq_scratch0]\n\t"
1139 "movl %[dst], %[rseq_scratch1]\n\t"
1140 "movl %[len], %[rseq_scratch2]\n\t"
1141 /* Start rseq by storing table entry pointer into rseq_cs. */
1142 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1143 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1145 "movl %[expect], %%eax\n\t"
1146 "cmpl %%eax, %[v]\n\t"
1149 #ifdef RSEQ_COMPARE_TWICE
1150 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
1151 "movl %[expect], %%eax\n\t"
1152 "cmpl %%eax, %[v]\n\t"
1156 "test %[len], %[len]\n\t" \
1159 "movb (%[src]), %%al\n\t" \
1160 "movb %%al, (%[dst])\n\t" \
1167 "lock; addl $0,-128(%%esp)\n\t"
1168 "movl %[newv], %%eax\n\t"
1170 "movl %%eax, %[v]\n\t"
1174 "movl %[rseq_scratch2], %[len]\n\t"
1175 "movl %[rseq_scratch1], %[dst]\n\t"
1176 "movl %[rseq_scratch0], %[src]\n\t"
1177 RSEQ_ASM_DEFINE_ABORT(4,
1178 "movl %[rseq_scratch2], %[len]\n\t"
1179 "movl %[rseq_scratch1], %[dst]\n\t"
1180 "movl %[rseq_scratch0], %[src]\n\t",
1182 RSEQ_ASM_DEFINE_CMPFAIL(5,
1183 "movl %[rseq_scratch2], %[len]\n\t"
1184 "movl %[rseq_scratch1], %[dst]\n\t"
1185 "movl %[rseq_scratch0], %[src]\n\t",
1187 #ifdef RSEQ_COMPARE_TWICE
1188 RSEQ_ASM_DEFINE_CMPFAIL(6,
1189 "movl %[rseq_scratch2], %[len]\n\t"
1190 "movl %[rseq_scratch1], %[dst]\n\t"
1191 "movl %[rseq_scratch0], %[src]\n\t",
1193 RSEQ_ASM_DEFINE_CMPFAIL(7,
1194 "movl %[rseq_scratch2], %[len]\n\t"
1195 "movl %[rseq_scratch1], %[dst]\n\t"
1196 "movl %[rseq_scratch0], %[src]\n\t",
1199 : /* gcc asm goto does not allow outputs */
1200 : [cpu_id
] "r" (cpu
),
1201 [rseq_abi
] "r" (&__rseq_abi
),
1202 /* final store input */
1204 [expect
] "m" (expect
),
1206 /* try memcpy input */
1210 [rseq_scratch0
] "m" (rseq_scratch
[0]),
1211 [rseq_scratch1
] "m" (rseq_scratch
[1]),
1212 [rseq_scratch2
] "m" (rseq_scratch
[2])
1213 : "memory", "cc", "eax"
1216 #ifdef RSEQ_COMPARE_TWICE
1226 #ifdef RSEQ_COMPARE_TWICE
1228 rseq_bug("cpu_id comparison failed");
1230 rseq_bug("expected value comparison failed");
1234 #endif /* !RSEQ_SKIP_FASTPATH */