1 /* SPDX-License-Identifier: LGPL-2.1-only 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.
23 * (TODO: revisit after migration to glibc's ABI)
26 /* Offset of cpu_id and rseq_cs fields in struct rseq. */
27 #define RSEQ_CPU_ID_OFFSET 4
28 #define RSEQ_CS_OFFSET 8
32 #define rseq_smp_mb() \
33 __asm__ __volatile__ ("lock; addl $0,-128(%%rsp)" ::: "memory", "cc")
34 #define rseq_smp_rmb() rseq_barrier()
35 #define rseq_smp_wmb() rseq_barrier()
37 #define rseq_smp_load_acquire(p) \
39 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
44 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
46 #define rseq_smp_store_release(p, v) \
49 RSEQ_WRITE_ONCE(*p, v); \
52 #ifdef RSEQ_SKIP_FASTPATH
53 #include "rseq-skip.h"
54 #else /* !RSEQ_SKIP_FASTPATH */
56 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
57 start_ip, post_commit_offset, abort_ip) \
58 ".pushsection __rseq_cs, \"aw\"\n\t" \
60 __rseq_str(label) ":\n\t" \
61 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
62 ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
64 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
65 ".quad " __rseq_str(label) "b\n\t" \
69 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
70 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
71 (post_commit_ip - start_ip), abort_ip)
74 * Exit points of a rseq critical section consist of all instructions outside
75 * of the critical section where a critical section can either branch to or
76 * reach through the normal course of its execution. The abort IP and the
77 * post-commit IP are already part of the __rseq_cs section and should not be
78 * explicitly defined as additional exit points. Knowing all exit points is
79 * useful to assist debuggers stepping over the critical section.
81 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
82 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
83 ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
86 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
88 "leaq " __rseq_str(cs_label) "(%%rip), %%rax\n\t" \
89 "movq %%rax, " __rseq_str(rseq_cs) "\n\t" \
90 __rseq_str(label) ":\n\t"
92 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
94 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
95 "jnz " __rseq_str(label) "\n\t"
97 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
98 ".pushsection __rseq_failure, \"ax\"\n\t" \
99 /* Disassembler-friendly signature: ud1 <sig>(%rip),%edi. */ \
100 ".byte 0x0f, 0xb9, 0x3d\n\t" \
101 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
102 __rseq_str(label) ":\n\t" \
104 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
107 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
108 ".pushsection __rseq_failure, \"ax\"\n\t" \
109 __rseq_str(label) ":\n\t" \
111 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
114 static inline __attribute__((always_inline
))
115 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
119 __asm__ __volatile__
goto (
120 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
121 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
122 #ifdef RSEQ_COMPARE_TWICE
123 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
124 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
126 /* Start rseq by storing table entry pointer into rseq_cs. */
127 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
128 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
130 "cmpq %[v], %[expect]\n\t"
131 "jnz %l[cmpfail]\n\t"
133 #ifdef RSEQ_COMPARE_TWICE
134 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
135 "cmpq %[v], %[expect]\n\t"
139 "movq %[newv], %[v]\n\t"
142 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
143 : /* gcc asm goto does not allow outputs */
144 : [cpu_id
] "r" (cpu
),
145 [rseq_abi
] "r" (rseq_get_abi()),
147 [expect
] "r" (expect
),
149 : "memory", "cc", "rax"
152 #ifdef RSEQ_COMPARE_TWICE
162 #ifdef RSEQ_COMPARE_TWICE
164 rseq_bug("cpu_id comparison failed");
166 rseq_bug("expected value comparison failed");
171 * Compare @v against @expectnot. When it does _not_ match, load @v
172 * into @load, and store the content of *@v + voffp into @v.
174 static inline __attribute__((always_inline
))
175 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
176 off_t voffp
, intptr_t *load
, int cpu
)
180 __asm__ __volatile__
goto (
181 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
182 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
183 #ifdef RSEQ_COMPARE_TWICE
184 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
185 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
187 /* Start rseq by storing table entry pointer into rseq_cs. */
188 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
189 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
191 "movq %[v], %%rbx\n\t"
192 "cmpq %%rbx, %[expectnot]\n\t"
195 #ifdef RSEQ_COMPARE_TWICE
196 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
197 "movq %[v], %%rbx\n\t"
198 "cmpq %%rbx, %[expectnot]\n\t"
201 "movq %%rbx, %[load]\n\t"
202 "addq %[voffp], %%rbx\n\t"
203 "movq (%%rbx), %%rbx\n\t"
205 "movq %%rbx, %[v]\n\t"
208 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
209 : /* gcc asm goto does not allow outputs */
210 : [cpu_id
] "r" (cpu
),
211 [rseq_abi
] "r" (rseq_get_abi()),
212 /* final store input */
214 [expectnot
] "r" (expectnot
),
215 [voffp
] "er" (voffp
),
217 : "memory", "cc", "rax", "rbx"
220 #ifdef RSEQ_COMPARE_TWICE
230 #ifdef RSEQ_COMPARE_TWICE
232 rseq_bug("cpu_id comparison failed");
234 rseq_bug("expected value comparison failed");
238 static inline __attribute__((always_inline
))
239 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
243 __asm__ __volatile__
goto (
244 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
245 #ifdef RSEQ_COMPARE_TWICE
246 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
248 /* Start rseq by storing table entry pointer into rseq_cs. */
249 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
250 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
252 #ifdef RSEQ_COMPARE_TWICE
253 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
256 "addq %[count], %[v]\n\t"
259 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
260 : /* gcc asm goto does not allow outputs */
261 : [cpu_id
] "r" (cpu
),
262 [rseq_abi
] "r" (rseq_get_abi()),
263 /* final store input */
266 : "memory", "cc", "rax"
269 #ifdef RSEQ_COMPARE_TWICE
277 #ifdef RSEQ_COMPARE_TWICE
279 rseq_bug("cpu_id comparison failed");
283 static inline __attribute__((always_inline
))
284 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
285 intptr_t *v2
, intptr_t newv2
,
286 intptr_t newv
, int cpu
)
290 __asm__ __volatile__
goto (
291 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
292 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
293 #ifdef RSEQ_COMPARE_TWICE
294 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
295 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
297 /* Start rseq by storing table entry pointer into rseq_cs. */
298 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
299 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
301 "cmpq %[v], %[expect]\n\t"
302 "jnz %l[cmpfail]\n\t"
304 #ifdef RSEQ_COMPARE_TWICE
305 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
306 "cmpq %[v], %[expect]\n\t"
310 "movq %[newv2], %[v2]\n\t"
313 "movq %[newv], %[v]\n\t"
316 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
317 : /* gcc asm goto does not allow outputs */
318 : [cpu_id
] "r" (cpu
),
319 [rseq_abi
] "r" (rseq_get_abi()),
320 /* try store input */
323 /* final store input */
325 [expect
] "r" (expect
),
327 : "memory", "cc", "rax"
330 #ifdef RSEQ_COMPARE_TWICE
340 #ifdef RSEQ_COMPARE_TWICE
342 rseq_bug("cpu_id comparison failed");
344 rseq_bug("expected value comparison failed");
349 static inline __attribute__((always_inline
))
350 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
351 intptr_t *v2
, intptr_t newv2
,
352 intptr_t newv
, int cpu
)
354 return rseq_cmpeqv_trystorev_storev(v
, expect
, v2
, newv2
, newv
, cpu
);
357 static inline __attribute__((always_inline
))
358 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
359 intptr_t *v2
, intptr_t expect2
,
360 intptr_t newv
, int cpu
)
364 __asm__ __volatile__
goto (
365 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
366 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
367 #ifdef RSEQ_COMPARE_TWICE
368 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
369 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
370 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
372 /* Start rseq by storing table entry pointer into rseq_cs. */
373 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
374 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
376 "cmpq %[v], %[expect]\n\t"
377 "jnz %l[cmpfail]\n\t"
379 "cmpq %[v2], %[expect2]\n\t"
380 "jnz %l[cmpfail]\n\t"
382 #ifdef RSEQ_COMPARE_TWICE
383 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
384 "cmpq %[v], %[expect]\n\t"
386 "cmpq %[v2], %[expect2]\n\t"
390 "movq %[newv], %[v]\n\t"
393 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
394 : /* gcc asm goto does not allow outputs */
395 : [cpu_id
] "r" (cpu
),
396 [rseq_abi
] "r" (rseq_get_abi()),
399 [expect2
] "r" (expect2
),
400 /* final store input */
402 [expect
] "r" (expect
),
404 : "memory", "cc", "rax"
407 #ifdef RSEQ_COMPARE_TWICE
408 , error1
, error2
, error3
417 #ifdef RSEQ_COMPARE_TWICE
419 rseq_bug("cpu_id comparison failed");
421 rseq_bug("1st expected value comparison failed");
423 rseq_bug("2nd expected value comparison failed");
427 static inline __attribute__((always_inline
))
428 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
429 void *dst
, void *src
, size_t len
,
430 intptr_t newv
, int cpu
)
432 uint64_t rseq_scratch
[3];
436 __asm__ __volatile__
goto (
437 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
438 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
439 #ifdef RSEQ_COMPARE_TWICE
440 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
441 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
443 "movq %[src], %[rseq_scratch0]\n\t"
444 "movq %[dst], %[rseq_scratch1]\n\t"
445 "movq %[len], %[rseq_scratch2]\n\t"
446 /* Start rseq by storing table entry pointer into rseq_cs. */
447 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
448 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
450 "cmpq %[v], %[expect]\n\t"
453 #ifdef RSEQ_COMPARE_TWICE
454 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
455 "cmpq %[v], %[expect]\n\t"
459 "test %[len], %[len]\n\t" \
462 "movb (%[src]), %%al\n\t" \
463 "movb %%al, (%[dst])\n\t" \
471 "movq %[newv], %[v]\n\t"
475 "movq %[rseq_scratch2], %[len]\n\t"
476 "movq %[rseq_scratch1], %[dst]\n\t"
477 "movq %[rseq_scratch0], %[src]\n\t"
478 RSEQ_ASM_DEFINE_ABORT(4,
479 "movq %[rseq_scratch2], %[len]\n\t"
480 "movq %[rseq_scratch1], %[dst]\n\t"
481 "movq %[rseq_scratch0], %[src]\n\t",
483 RSEQ_ASM_DEFINE_CMPFAIL(5,
484 "movq %[rseq_scratch2], %[len]\n\t"
485 "movq %[rseq_scratch1], %[dst]\n\t"
486 "movq %[rseq_scratch0], %[src]\n\t",
488 #ifdef RSEQ_COMPARE_TWICE
489 RSEQ_ASM_DEFINE_CMPFAIL(6,
490 "movq %[rseq_scratch2], %[len]\n\t"
491 "movq %[rseq_scratch1], %[dst]\n\t"
492 "movq %[rseq_scratch0], %[src]\n\t",
494 RSEQ_ASM_DEFINE_CMPFAIL(7,
495 "movq %[rseq_scratch2], %[len]\n\t"
496 "movq %[rseq_scratch1], %[dst]\n\t"
497 "movq %[rseq_scratch0], %[src]\n\t",
500 : /* gcc asm goto does not allow outputs */
501 : [cpu_id
] "r" (cpu
),
502 [rseq_abi
] "r" (rseq_get_abi()),
503 /* final store input */
505 [expect
] "r" (expect
),
507 /* try memcpy input */
511 [rseq_scratch0
] "m" (rseq_scratch
[0]),
512 [rseq_scratch1
] "m" (rseq_scratch
[1]),
513 [rseq_scratch2
] "m" (rseq_scratch
[2])
514 : "memory", "cc", "rax"
517 #ifdef RSEQ_COMPARE_TWICE
527 #ifdef RSEQ_COMPARE_TWICE
529 rseq_bug("cpu_id comparison failed");
531 rseq_bug("expected value comparison failed");
536 static inline __attribute__((always_inline
))
537 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
538 void *dst
, void *src
, size_t len
,
539 intptr_t newv
, int cpu
)
541 return rseq_cmpeqv_trymemcpy_storev(v
, expect
, dst
, src
, len
,
546 * Dereference @p. Add voffp to the dereferenced pointer, and load its content
549 static inline __attribute__((always_inline
))
550 int rseq_deref_loadoffp(intptr_t *p
, off_t voffp
, intptr_t *load
, int cpu
)
554 __asm__ __volatile__
goto (
555 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
556 #ifdef RSEQ_COMPARE_TWICE
557 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
559 /* Start rseq by storing table entry pointer into rseq_cs. */
560 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
561 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
563 "movq %[p], %%rbx\n\t"
565 #ifdef RSEQ_COMPARE_TWICE
566 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
568 "addq %[voffp], %%rbx\n\t"
569 "movq (%%rbx), %%rbx\n\t"
570 "movq %%rbx, %[load]\n\t"
573 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
574 : /* gcc asm goto does not allow outputs */
575 : [cpu_id
] "r" (cpu
),
576 [rseq_abi
] "r" (rseq_get_abi()),
577 /* final store input */
579 [voffp
] "er" (voffp
),
581 : "memory", "cc", "rax", "rbx"
584 #ifdef RSEQ_COMPARE_TWICE
592 #ifdef RSEQ_COMPARE_TWICE
594 rseq_bug("cpu_id comparison failed");
598 #endif /* !RSEQ_SKIP_FASTPATH */
602 #define rseq_smp_mb() \
603 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
604 #define rseq_smp_rmb() \
605 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
606 #define rseq_smp_wmb() \
607 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
609 #define rseq_smp_load_acquire(p) \
611 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
616 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
618 #define rseq_smp_store_release(p, v) \
621 RSEQ_WRITE_ONCE(*p, v); \
624 #ifdef RSEQ_SKIP_FASTPATH
625 #include "rseq-skip.h"
626 #else /* !RSEQ_SKIP_FASTPATH */
629 * Use eax as scratch register and take memory operands as input to
630 * lessen register pressure. Especially needed when compiling in O0.
632 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
633 start_ip, post_commit_offset, abort_ip) \
634 ".pushsection __rseq_cs, \"aw\"\n\t" \
636 __rseq_str(label) ":\n\t" \
637 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
638 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
640 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
641 ".long " __rseq_str(label) "b, 0x0\n\t" \
644 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
645 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
646 (post_commit_ip - start_ip), abort_ip)
649 * Exit points of a rseq critical section consist of all instructions outside
650 * of the critical section where a critical section can either branch to or
651 * reach through the normal course of its execution. The abort IP and the
652 * post-commit IP are already part of the __rseq_cs section and should not be
653 * explicitly defined as additional exit points. Knowing all exit points is
654 * useful to assist debuggers stepping over the critical section.
656 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
657 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
658 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
661 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
663 "movl $" __rseq_str(cs_label) ", " __rseq_str(rseq_cs) "\n\t" \
664 __rseq_str(label) ":\n\t"
666 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
668 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
669 "jnz " __rseq_str(label) "\n\t"
671 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
672 ".pushsection __rseq_failure, \"ax\"\n\t" \
673 /* Disassembler-friendly signature: ud1 <sig>,%edi. */ \
674 ".byte 0x0f, 0xb9, 0x3d\n\t" \
675 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
676 __rseq_str(label) ":\n\t" \
678 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
681 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
682 ".pushsection __rseq_failure, \"ax\"\n\t" \
683 __rseq_str(label) ":\n\t" \
685 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
688 static inline __attribute__((always_inline
))
689 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
693 __asm__ __volatile__
goto (
694 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
695 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
696 #ifdef RSEQ_COMPARE_TWICE
697 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
698 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
700 /* Start rseq by storing table entry pointer into rseq_cs. */
701 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
702 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
704 "cmpl %[v], %[expect]\n\t"
705 "jnz %l[cmpfail]\n\t"
707 #ifdef RSEQ_COMPARE_TWICE
708 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
709 "cmpl %[v], %[expect]\n\t"
713 "movl %[newv], %[v]\n\t"
716 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
717 : /* gcc asm goto does not allow outputs */
718 : [cpu_id
] "r" (cpu
),
719 [rseq_abi
] "r" (rseq_get_abi()),
721 [expect
] "r" (expect
),
723 : "memory", "cc", "eax"
726 #ifdef RSEQ_COMPARE_TWICE
736 #ifdef RSEQ_COMPARE_TWICE
738 rseq_bug("cpu_id comparison failed");
740 rseq_bug("expected value comparison failed");
745 * Compare @v against @expectnot. When it does _not_ match, load @v
746 * into @load, and store the content of *@v + voffp into @v.
748 static inline __attribute__((always_inline
))
749 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
750 off_t voffp
, intptr_t *load
, int cpu
)
754 __asm__ __volatile__
goto (
755 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
756 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
757 #ifdef RSEQ_COMPARE_TWICE
758 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
759 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
761 /* Start rseq by storing table entry pointer into rseq_cs. */
762 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
763 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
765 "movl %[v], %%ebx\n\t"
766 "cmpl %%ebx, %[expectnot]\n\t"
769 #ifdef RSEQ_COMPARE_TWICE
770 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
771 "movl %[v], %%ebx\n\t"
772 "cmpl %%ebx, %[expectnot]\n\t"
775 "movl %%ebx, %[load]\n\t"
776 "addl %[voffp], %%ebx\n\t"
777 "movl (%%ebx), %%ebx\n\t"
779 "movl %%ebx, %[v]\n\t"
782 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
783 : /* gcc asm goto does not allow outputs */
784 : [cpu_id
] "r" (cpu
),
785 [rseq_abi
] "r" (rseq_get_abi()),
786 /* final store input */
788 [expectnot
] "r" (expectnot
),
789 [voffp
] "ir" (voffp
),
791 : "memory", "cc", "eax", "ebx"
794 #ifdef RSEQ_COMPARE_TWICE
804 #ifdef RSEQ_COMPARE_TWICE
806 rseq_bug("cpu_id comparison failed");
808 rseq_bug("expected value comparison failed");
812 static inline __attribute__((always_inline
))
813 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
817 __asm__ __volatile__
goto (
818 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
819 #ifdef RSEQ_COMPARE_TWICE
820 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
822 /* Start rseq by storing table entry pointer into rseq_cs. */
823 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
824 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
826 #ifdef RSEQ_COMPARE_TWICE
827 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
830 "addl %[count], %[v]\n\t"
833 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
834 : /* gcc asm goto does not allow outputs */
835 : [cpu_id
] "r" (cpu
),
836 [rseq_abi
] "r" (rseq_get_abi()),
837 /* final store input */
840 : "memory", "cc", "eax"
843 #ifdef RSEQ_COMPARE_TWICE
851 #ifdef RSEQ_COMPARE_TWICE
853 rseq_bug("cpu_id comparison failed");
857 static inline __attribute__((always_inline
))
858 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
859 intptr_t *v2
, intptr_t newv2
,
860 intptr_t newv
, int cpu
)
864 __asm__ __volatile__
goto (
865 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
866 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
867 #ifdef RSEQ_COMPARE_TWICE
868 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
869 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
871 /* Start rseq by storing table entry pointer into rseq_cs. */
872 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
873 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
875 "cmpl %[v], %[expect]\n\t"
876 "jnz %l[cmpfail]\n\t"
878 #ifdef RSEQ_COMPARE_TWICE
879 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
880 "cmpl %[v], %[expect]\n\t"
884 "movl %[newv2], %%eax\n\t"
885 "movl %%eax, %[v2]\n\t"
888 "movl %[newv], %[v]\n\t"
891 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
892 : /* gcc asm goto does not allow outputs */
893 : [cpu_id
] "r" (cpu
),
894 [rseq_abi
] "r" (rseq_get_abi()),
895 /* try store input */
898 /* final store input */
900 [expect
] "r" (expect
),
902 : "memory", "cc", "eax"
905 #ifdef RSEQ_COMPARE_TWICE
915 #ifdef RSEQ_COMPARE_TWICE
917 rseq_bug("cpu_id comparison failed");
919 rseq_bug("expected value comparison failed");
923 static inline __attribute__((always_inline
))
924 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
925 intptr_t *v2
, intptr_t newv2
,
926 intptr_t newv
, int cpu
)
930 __asm__ __volatile__
goto (
931 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
932 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
933 #ifdef RSEQ_COMPARE_TWICE
934 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
935 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
937 /* Start rseq by storing table entry pointer into rseq_cs. */
938 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
939 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
941 "movl %[expect], %%eax\n\t"
942 "cmpl %[v], %%eax\n\t"
943 "jnz %l[cmpfail]\n\t"
945 #ifdef RSEQ_COMPARE_TWICE
946 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
947 "movl %[expect], %%eax\n\t"
948 "cmpl %[v], %%eax\n\t"
952 "movl %[newv2], %[v2]\n\t"
954 "lock; addl $0,-128(%%esp)\n\t"
956 "movl %[newv], %[v]\n\t"
959 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
960 : /* gcc asm goto does not allow outputs */
961 : [cpu_id
] "r" (cpu
),
962 [rseq_abi
] "r" (rseq_get_abi()),
963 /* try store input */
966 /* final store input */
968 [expect
] "m" (expect
),
970 : "memory", "cc", "eax"
973 #ifdef RSEQ_COMPARE_TWICE
983 #ifdef RSEQ_COMPARE_TWICE
985 rseq_bug("cpu_id comparison failed");
987 rseq_bug("expected value comparison failed");
992 static inline __attribute__((always_inline
))
993 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
994 intptr_t *v2
, intptr_t expect2
,
995 intptr_t newv
, int cpu
)
999 __asm__ __volatile__
goto (
1000 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1001 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1002 #ifdef RSEQ_COMPARE_TWICE
1003 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1004 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1005 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
1007 /* Start rseq by storing table entry pointer into rseq_cs. */
1008 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1009 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1011 "cmpl %[v], %[expect]\n\t"
1012 "jnz %l[cmpfail]\n\t"
1014 "cmpl %[expect2], %[v2]\n\t"
1015 "jnz %l[cmpfail]\n\t"
1017 #ifdef RSEQ_COMPARE_TWICE
1018 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
1019 "cmpl %[v], %[expect]\n\t"
1020 "jnz %l[error2]\n\t"
1021 "cmpl %[expect2], %[v2]\n\t"
1022 "jnz %l[error3]\n\t"
1024 "movl %[newv], %%eax\n\t"
1026 "movl %%eax, %[v]\n\t"
1029 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
1030 : /* gcc asm goto does not allow outputs */
1031 : [cpu_id
] "r" (cpu
),
1032 [rseq_abi
] "r" (rseq_get_abi()),
1035 [expect2
] "r" (expect2
),
1036 /* final store input */
1038 [expect
] "r" (expect
),
1040 : "memory", "cc", "eax"
1043 #ifdef RSEQ_COMPARE_TWICE
1044 , error1
, error2
, error3
1053 #ifdef RSEQ_COMPARE_TWICE
1055 rseq_bug("cpu_id comparison failed");
1057 rseq_bug("1st expected value comparison failed");
1059 rseq_bug("2nd expected value comparison failed");
1063 /* TODO: implement a faster memcpy. */
1064 static inline __attribute__((always_inline
))
1065 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
1066 void *dst
, void *src
, size_t len
,
1067 intptr_t newv
, int cpu
)
1069 uint32_t rseq_scratch
[3];
1073 __asm__ __volatile__
goto (
1074 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1075 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1076 #ifdef RSEQ_COMPARE_TWICE
1077 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1078 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1080 "movl %[src], %[rseq_scratch0]\n\t"
1081 "movl %[dst], %[rseq_scratch1]\n\t"
1082 "movl %[len], %[rseq_scratch2]\n\t"
1083 /* Start rseq by storing table entry pointer into rseq_cs. */
1084 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1085 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1087 "movl %[expect], %%eax\n\t"
1088 "cmpl %%eax, %[v]\n\t"
1091 #ifdef RSEQ_COMPARE_TWICE
1092 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
1093 "movl %[expect], %%eax\n\t"
1094 "cmpl %%eax, %[v]\n\t"
1098 "test %[len], %[len]\n\t" \
1101 "movb (%[src]), %%al\n\t" \
1102 "movb %%al, (%[dst])\n\t" \
1109 "movl %[newv], %%eax\n\t"
1111 "movl %%eax, %[v]\n\t"
1115 "movl %[rseq_scratch2], %[len]\n\t"
1116 "movl %[rseq_scratch1], %[dst]\n\t"
1117 "movl %[rseq_scratch0], %[src]\n\t"
1118 RSEQ_ASM_DEFINE_ABORT(4,
1119 "movl %[rseq_scratch2], %[len]\n\t"
1120 "movl %[rseq_scratch1], %[dst]\n\t"
1121 "movl %[rseq_scratch0], %[src]\n\t",
1123 RSEQ_ASM_DEFINE_CMPFAIL(5,
1124 "movl %[rseq_scratch2], %[len]\n\t"
1125 "movl %[rseq_scratch1], %[dst]\n\t"
1126 "movl %[rseq_scratch0], %[src]\n\t",
1128 #ifdef RSEQ_COMPARE_TWICE
1129 RSEQ_ASM_DEFINE_CMPFAIL(6,
1130 "movl %[rseq_scratch2], %[len]\n\t"
1131 "movl %[rseq_scratch1], %[dst]\n\t"
1132 "movl %[rseq_scratch0], %[src]\n\t",
1134 RSEQ_ASM_DEFINE_CMPFAIL(7,
1135 "movl %[rseq_scratch2], %[len]\n\t"
1136 "movl %[rseq_scratch1], %[dst]\n\t"
1137 "movl %[rseq_scratch0], %[src]\n\t",
1140 : /* gcc asm goto does not allow outputs */
1141 : [cpu_id
] "r" (cpu
),
1142 [rseq_abi
] "r" (rseq_get_abi()),
1143 /* final store input */
1145 [expect
] "m" (expect
),
1147 /* try memcpy input */
1151 [rseq_scratch0
] "m" (rseq_scratch
[0]),
1152 [rseq_scratch1
] "m" (rseq_scratch
[1]),
1153 [rseq_scratch2
] "m" (rseq_scratch
[2])
1154 : "memory", "cc", "eax"
1157 #ifdef RSEQ_COMPARE_TWICE
1167 #ifdef RSEQ_COMPARE_TWICE
1169 rseq_bug("cpu_id comparison failed");
1171 rseq_bug("expected value comparison failed");
1175 /* TODO: implement a faster memcpy. */
1176 static inline __attribute__((always_inline
))
1177 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
1178 void *dst
, void *src
, size_t len
,
1179 intptr_t newv
, int cpu
)
1181 uint32_t rseq_scratch
[3];
1185 __asm__ __volatile__
goto (
1186 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1187 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1188 #ifdef RSEQ_COMPARE_TWICE
1189 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1190 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1192 "movl %[src], %[rseq_scratch0]\n\t"
1193 "movl %[dst], %[rseq_scratch1]\n\t"
1194 "movl %[len], %[rseq_scratch2]\n\t"
1195 /* Start rseq by storing table entry pointer into rseq_cs. */
1196 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1197 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1199 "movl %[expect], %%eax\n\t"
1200 "cmpl %%eax, %[v]\n\t"
1203 #ifdef RSEQ_COMPARE_TWICE
1204 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
1205 "movl %[expect], %%eax\n\t"
1206 "cmpl %%eax, %[v]\n\t"
1210 "test %[len], %[len]\n\t" \
1213 "movb (%[src]), %%al\n\t" \
1214 "movb %%al, (%[dst])\n\t" \
1221 "lock; addl $0,-128(%%esp)\n\t"
1222 "movl %[newv], %%eax\n\t"
1224 "movl %%eax, %[v]\n\t"
1228 "movl %[rseq_scratch2], %[len]\n\t"
1229 "movl %[rseq_scratch1], %[dst]\n\t"
1230 "movl %[rseq_scratch0], %[src]\n\t"
1231 RSEQ_ASM_DEFINE_ABORT(4,
1232 "movl %[rseq_scratch2], %[len]\n\t"
1233 "movl %[rseq_scratch1], %[dst]\n\t"
1234 "movl %[rseq_scratch0], %[src]\n\t",
1236 RSEQ_ASM_DEFINE_CMPFAIL(5,
1237 "movl %[rseq_scratch2], %[len]\n\t"
1238 "movl %[rseq_scratch1], %[dst]\n\t"
1239 "movl %[rseq_scratch0], %[src]\n\t",
1241 #ifdef RSEQ_COMPARE_TWICE
1242 RSEQ_ASM_DEFINE_CMPFAIL(6,
1243 "movl %[rseq_scratch2], %[len]\n\t"
1244 "movl %[rseq_scratch1], %[dst]\n\t"
1245 "movl %[rseq_scratch0], %[src]\n\t",
1247 RSEQ_ASM_DEFINE_CMPFAIL(7,
1248 "movl %[rseq_scratch2], %[len]\n\t"
1249 "movl %[rseq_scratch1], %[dst]\n\t"
1250 "movl %[rseq_scratch0], %[src]\n\t",
1253 : /* gcc asm goto does not allow outputs */
1254 : [cpu_id
] "r" (cpu
),
1255 [rseq_abi
] "r" (rseq_get_abi()),
1256 /* final store input */
1258 [expect
] "m" (expect
),
1260 /* try memcpy input */
1264 [rseq_scratch0
] "m" (rseq_scratch
[0]),
1265 [rseq_scratch1
] "m" (rseq_scratch
[1]),
1266 [rseq_scratch2
] "m" (rseq_scratch
[2])
1267 : "memory", "cc", "eax"
1270 #ifdef RSEQ_COMPARE_TWICE
1280 #ifdef RSEQ_COMPARE_TWICE
1282 rseq_bug("cpu_id comparison failed");
1284 rseq_bug("expected value comparison failed");
1289 * Dereference @p. Add voffp to the dereferenced pointer, and load its content
1292 static inline __attribute__((always_inline
))
1293 int rseq_deref_loadoffp(intptr_t *p
, off_t voffp
, intptr_t *load
, int cpu
)
1297 __asm__ __volatile__
goto (
1298 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1299 #ifdef RSEQ_COMPARE_TWICE
1300 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1302 /* Start rseq by storing table entry pointer into rseq_cs. */
1303 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1304 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1306 "movl %[p], %%ebx\n\t"
1308 #ifdef RSEQ_COMPARE_TWICE
1309 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
1311 "addl %[voffp], %%ebx\n\t"
1312 "movl (%%ebx), %%ebx\n\t"
1313 "movl %%ebx, %[load]\n\t"
1316 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
1317 : /* gcc asm goto does not allow outputs */
1318 : [cpu_id
] "r" (cpu
),
1319 [rseq_abi
] "r" (rseq_get_abi()),
1320 /* final store input */
1322 [voffp
] "ir" (voffp
),
1324 : "memory", "cc", "eax", "ebx"
1327 #ifdef RSEQ_COMPARE_TWICE
1335 #ifdef RSEQ_COMPARE_TWICE
1337 rseq_bug("cpu_id comparison failed");
1341 #endif /* !RSEQ_SKIP_FASTPATH */
This page took 0.062068 seconds and 4 git commands to generate.