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
156 rseq_after_asm_goto();
159 rseq_after_asm_goto();
163 rseq_after_asm_goto();
165 #ifdef RSEQ_COMPARE_TWICE
167 rseq_after_asm_goto();
168 rseq_bug("cpu_id comparison failed");
170 rseq_after_asm_goto();
171 rseq_bug("expected value comparison failed");
176 * Compare @v against @expectnot. When it does _not_ match, load @v
177 * into @load, and store the content of *@v + voffp into @v.
179 static inline __attribute__((always_inline
))
180 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
181 long voffp
, intptr_t *load
, int cpu
)
185 __asm__ __volatile__
goto (
186 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
187 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
188 #ifdef RSEQ_COMPARE_TWICE
189 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
190 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
192 /* Start rseq by storing table entry pointer into rseq_cs. */
193 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
194 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
196 "movq %[v], %%rbx\n\t"
197 "cmpq %%rbx, %[expectnot]\n\t"
200 #ifdef RSEQ_COMPARE_TWICE
201 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
202 "movq %[v], %%rbx\n\t"
203 "cmpq %%rbx, %[expectnot]\n\t"
206 "movq %%rbx, %[load]\n\t"
207 "addq %[voffp], %%rbx\n\t"
208 "movq (%%rbx), %%rbx\n\t"
210 "movq %%rbx, %[v]\n\t"
213 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
214 : /* gcc asm goto does not allow outputs */
215 : [cpu_id
] "r" (cpu
),
216 [rseq_abi
] "r" (rseq_get_abi()),
217 /* final store input */
219 [expectnot
] "r" (expectnot
),
220 [voffp
] "er" (voffp
),
222 : "memory", "cc", "rax", "rbx"
225 #ifdef RSEQ_COMPARE_TWICE
229 rseq_after_asm_goto();
232 rseq_after_asm_goto();
236 rseq_after_asm_goto();
238 #ifdef RSEQ_COMPARE_TWICE
240 rseq_after_asm_goto();
241 rseq_bug("cpu_id comparison failed");
243 rseq_after_asm_goto();
244 rseq_bug("expected value comparison failed");
248 static inline __attribute__((always_inline
))
249 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
253 __asm__ __volatile__
goto (
254 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
255 #ifdef RSEQ_COMPARE_TWICE
256 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
258 /* Start rseq by storing table entry pointer into rseq_cs. */
259 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
260 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
262 #ifdef RSEQ_COMPARE_TWICE
263 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
266 "addq %[count], %[v]\n\t"
269 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
270 : /* gcc asm goto does not allow outputs */
271 : [cpu_id
] "r" (cpu
),
272 [rseq_abi
] "r" (rseq_get_abi()),
273 /* final store input */
276 : "memory", "cc", "rax"
279 #ifdef RSEQ_COMPARE_TWICE
283 rseq_after_asm_goto();
286 rseq_after_asm_goto();
289 #ifdef RSEQ_COMPARE_TWICE
291 rseq_after_asm_goto();
292 rseq_bug("cpu_id comparison failed");
296 #define RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
302 static inline __attribute__((always_inline
))
303 int rseq_offset_deref_addv(intptr_t *ptr
, long off
, intptr_t inc
, int cpu
)
307 __asm__ __volatile__
goto (
308 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
309 #ifdef RSEQ_COMPARE_TWICE
310 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
312 /* Start rseq by storing table entry pointer into rseq_cs. */
313 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
314 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
316 #ifdef RSEQ_COMPARE_TWICE
317 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
320 "movq %[ptr], %%rbx\n\t"
321 "addq %[off], %%rbx\n\t"
323 "movq (%%rbx), %%rcx\n\t"
325 "addq %[inc], (%%rcx)\n\t"
328 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
329 : /* gcc asm goto does not allow outputs */
330 : [cpu_id
] "r" (cpu
),
331 [rseq_abi
] "r" (rseq_get_abi()),
332 /* final store input */
336 : "memory", "cc", "rax", "rbx", "rcx"
339 #ifdef RSEQ_COMPARE_TWICE
343 rseq_after_asm_goto();
346 rseq_after_asm_goto();
349 #ifdef RSEQ_COMPARE_TWICE
351 rseq_after_asm_goto();
352 rseq_bug("cpu_id comparison failed");
356 static inline __attribute__((always_inline
))
357 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
358 intptr_t *v2
, intptr_t newv2
,
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
])
370 /* Start rseq by storing table entry pointer into rseq_cs. */
371 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
372 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
374 "cmpq %[v], %[expect]\n\t"
375 "jnz %l[cmpfail]\n\t"
377 #ifdef RSEQ_COMPARE_TWICE
378 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
379 "cmpq %[v], %[expect]\n\t"
383 "movq %[newv2], %[v2]\n\t"
386 "movq %[newv], %[v]\n\t"
389 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
390 : /* gcc asm goto does not allow outputs */
391 : [cpu_id
] "r" (cpu
),
392 [rseq_abi
] "r" (rseq_get_abi()),
393 /* try store input */
396 /* final store input */
398 [expect
] "r" (expect
),
400 : "memory", "cc", "rax"
403 #ifdef RSEQ_COMPARE_TWICE
407 rseq_after_asm_goto();
410 rseq_after_asm_goto();
414 rseq_after_asm_goto();
416 #ifdef RSEQ_COMPARE_TWICE
418 rseq_after_asm_goto();
419 rseq_bug("cpu_id comparison failed");
421 rseq_after_asm_goto();
422 rseq_bug("expected value comparison failed");
427 static inline __attribute__((always_inline
))
428 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
429 intptr_t *v2
, intptr_t newv2
,
430 intptr_t newv
, int cpu
)
432 return rseq_cmpeqv_trystorev_storev(v
, expect
, v2
, newv2
, newv
, cpu
);
435 static inline __attribute__((always_inline
))
436 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
437 intptr_t *v2
, intptr_t expect2
,
438 intptr_t newv
, int cpu
)
442 __asm__ __volatile__
goto (
443 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
444 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
445 #ifdef RSEQ_COMPARE_TWICE
446 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
447 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
448 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
450 /* Start rseq by storing table entry pointer into rseq_cs. */
451 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
452 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
454 "cmpq %[v], %[expect]\n\t"
455 "jnz %l[cmpfail]\n\t"
457 "cmpq %[v2], %[expect2]\n\t"
458 "jnz %l[cmpfail]\n\t"
460 #ifdef RSEQ_COMPARE_TWICE
461 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
462 "cmpq %[v], %[expect]\n\t"
464 "cmpq %[v2], %[expect2]\n\t"
468 "movq %[newv], %[v]\n\t"
471 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
472 : /* gcc asm goto does not allow outputs */
473 : [cpu_id
] "r" (cpu
),
474 [rseq_abi
] "r" (rseq_get_abi()),
477 [expect2
] "r" (expect2
),
478 /* final store input */
480 [expect
] "r" (expect
),
482 : "memory", "cc", "rax"
485 #ifdef RSEQ_COMPARE_TWICE
486 , error1
, error2
, error3
489 rseq_after_asm_goto();
492 rseq_after_asm_goto();
496 rseq_after_asm_goto();
498 #ifdef RSEQ_COMPARE_TWICE
500 rseq_after_asm_goto();
501 rseq_bug("cpu_id comparison failed");
503 rseq_after_asm_goto();
504 rseq_bug("1st expected value comparison failed");
506 rseq_after_asm_goto();
507 rseq_bug("2nd expected value comparison failed");
511 static inline __attribute__((always_inline
))
512 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
513 void *dst
, void *src
, size_t len
,
514 intptr_t newv
, int cpu
)
516 uint64_t rseq_scratch
[3];
520 __asm__ __volatile__
goto (
521 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
522 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
523 #ifdef RSEQ_COMPARE_TWICE
524 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
525 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
527 "movq %[src], %[rseq_scratch0]\n\t"
528 "movq %[dst], %[rseq_scratch1]\n\t"
529 "movq %[len], %[rseq_scratch2]\n\t"
530 /* Start rseq by storing table entry pointer into rseq_cs. */
531 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
532 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
534 "cmpq %[v], %[expect]\n\t"
537 #ifdef RSEQ_COMPARE_TWICE
538 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
539 "cmpq %[v], %[expect]\n\t"
543 "test %[len], %[len]\n\t" \
546 "movb (%[src]), %%al\n\t" \
547 "movb %%al, (%[dst])\n\t" \
555 "movq %[newv], %[v]\n\t"
559 "movq %[rseq_scratch2], %[len]\n\t"
560 "movq %[rseq_scratch1], %[dst]\n\t"
561 "movq %[rseq_scratch0], %[src]\n\t"
562 RSEQ_ASM_DEFINE_ABORT(4,
563 "movq %[rseq_scratch2], %[len]\n\t"
564 "movq %[rseq_scratch1], %[dst]\n\t"
565 "movq %[rseq_scratch0], %[src]\n\t",
567 RSEQ_ASM_DEFINE_CMPFAIL(5,
568 "movq %[rseq_scratch2], %[len]\n\t"
569 "movq %[rseq_scratch1], %[dst]\n\t"
570 "movq %[rseq_scratch0], %[src]\n\t",
572 #ifdef RSEQ_COMPARE_TWICE
573 RSEQ_ASM_DEFINE_CMPFAIL(6,
574 "movq %[rseq_scratch2], %[len]\n\t"
575 "movq %[rseq_scratch1], %[dst]\n\t"
576 "movq %[rseq_scratch0], %[src]\n\t",
578 RSEQ_ASM_DEFINE_CMPFAIL(7,
579 "movq %[rseq_scratch2], %[len]\n\t"
580 "movq %[rseq_scratch1], %[dst]\n\t"
581 "movq %[rseq_scratch0], %[src]\n\t",
584 : /* gcc asm goto does not allow outputs */
585 : [cpu_id
] "r" (cpu
),
586 [rseq_abi
] "r" (rseq_get_abi()),
587 /* final store input */
589 [expect
] "r" (expect
),
591 /* try memcpy input */
595 [rseq_scratch0
] "m" (rseq_scratch
[0]),
596 [rseq_scratch1
] "m" (rseq_scratch
[1]),
597 [rseq_scratch2
] "m" (rseq_scratch
[2])
598 : "memory", "cc", "rax"
601 #ifdef RSEQ_COMPARE_TWICE
605 rseq_after_asm_goto();
608 rseq_after_asm_goto();
612 rseq_after_asm_goto();
614 #ifdef RSEQ_COMPARE_TWICE
616 rseq_after_asm_goto();
617 rseq_bug("cpu_id comparison failed");
619 rseq_after_asm_goto();
620 rseq_bug("expected value comparison failed");
625 static inline __attribute__((always_inline
))
626 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
627 void *dst
, void *src
, size_t len
,
628 intptr_t newv
, int cpu
)
630 return rseq_cmpeqv_trymemcpy_storev(v
, expect
, dst
, src
, len
,
635 * Dereference @p. Add voffp to the dereferenced pointer, and load its content
638 static inline __attribute__((always_inline
))
639 int rseq_deref_loadoffp(intptr_t *p
, long voffp
, intptr_t *load
, int cpu
)
643 __asm__ __volatile__
goto (
644 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
645 #ifdef RSEQ_COMPARE_TWICE
646 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
648 /* Start rseq by storing table entry pointer into rseq_cs. */
649 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
650 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
652 "movq %[p], %%rbx\n\t"
654 #ifdef RSEQ_COMPARE_TWICE
655 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
657 "addq %[voffp], %%rbx\n\t"
658 "movq (%%rbx), %%rbx\n\t"
659 "movq %%rbx, %[load]\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_get_abi()),
666 /* final store input */
668 [voffp
] "er" (voffp
),
670 : "memory", "cc", "rax", "rbx"
673 #ifdef RSEQ_COMPARE_TWICE
677 rseq_after_asm_goto();
680 rseq_after_asm_goto();
683 #ifdef RSEQ_COMPARE_TWICE
685 rseq_after_asm_goto();
686 rseq_bug("cpu_id comparison failed");
690 #endif /* !RSEQ_SKIP_FASTPATH */
692 #elif defined(__i386__)
694 #define rseq_smp_mb() \
695 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
696 #define rseq_smp_rmb() \
697 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
698 #define rseq_smp_wmb() \
699 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
701 #define rseq_smp_load_acquire(p) \
703 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
708 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
710 #define rseq_smp_store_release(p, v) \
713 RSEQ_WRITE_ONCE(*p, v); \
716 #ifdef RSEQ_SKIP_FASTPATH
717 #include "rseq-skip.h"
718 #else /* !RSEQ_SKIP_FASTPATH */
721 * Use eax as scratch register and take memory operands as input to
722 * lessen register pressure. Especially needed when compiling in O0.
724 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
725 start_ip, post_commit_offset, abort_ip) \
726 ".pushsection __rseq_cs, \"aw\"\n\t" \
728 __rseq_str(label) ":\n\t" \
729 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
730 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
732 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
733 ".long " __rseq_str(label) "b, 0x0\n\t" \
736 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
737 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
738 (post_commit_ip - start_ip), abort_ip)
741 * Exit points of a rseq critical section consist of all instructions outside
742 * of the critical section where a critical section can either branch to or
743 * reach through the normal course of its execution. The abort IP and the
744 * post-commit IP are already part of the __rseq_cs section and should not be
745 * explicitly defined as additional exit points. Knowing all exit points is
746 * useful to assist debuggers stepping over the critical section.
748 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
749 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
750 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
753 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
755 "movl $" __rseq_str(cs_label) ", " __rseq_str(rseq_cs) "\n\t" \
756 __rseq_str(label) ":\n\t"
758 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
760 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
761 "jnz " __rseq_str(label) "\n\t"
763 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
764 ".pushsection __rseq_failure, \"ax\"\n\t" \
765 /* Disassembler-friendly signature: ud1 <sig>,%edi. */ \
766 ".byte 0x0f, 0xb9, 0x3d\n\t" \
767 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
768 __rseq_str(label) ":\n\t" \
770 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
773 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
774 ".pushsection __rseq_failure, \"ax\"\n\t" \
775 __rseq_str(label) ":\n\t" \
777 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
780 static inline __attribute__((always_inline
))
781 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
785 __asm__ __volatile__
goto (
786 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
787 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
788 #ifdef RSEQ_COMPARE_TWICE
789 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
790 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
792 /* Start rseq by storing table entry pointer into rseq_cs. */
793 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
794 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
796 "cmpl %[v], %[expect]\n\t"
797 "jnz %l[cmpfail]\n\t"
799 #ifdef RSEQ_COMPARE_TWICE
800 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
801 "cmpl %[v], %[expect]\n\t"
805 "movl %[newv], %[v]\n\t"
808 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
809 : /* gcc asm goto does not allow outputs */
810 : [cpu_id
] "r" (cpu
),
811 [rseq_abi
] "r" (rseq_get_abi()),
813 [expect
] "r" (expect
),
815 : "memory", "cc", "eax"
818 #ifdef RSEQ_COMPARE_TWICE
822 rseq_after_asm_goto();
825 rseq_after_asm_goto();
829 rseq_after_asm_goto();
831 #ifdef RSEQ_COMPARE_TWICE
833 rseq_after_asm_goto();
834 rseq_bug("cpu_id comparison failed");
836 rseq_after_asm_goto();
837 rseq_bug("expected value comparison failed");
842 * Compare @v against @expectnot. When it does _not_ match, load @v
843 * into @load, and store the content of *@v + voffp into @v.
845 static inline __attribute__((always_inline
))
846 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
847 long voffp
, intptr_t *load
, int cpu
)
851 __asm__ __volatile__
goto (
852 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
853 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
854 #ifdef RSEQ_COMPARE_TWICE
855 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
856 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
858 /* Start rseq by storing table entry pointer into rseq_cs. */
859 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
860 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
862 "movl %[v], %%ebx\n\t"
863 "cmpl %%ebx, %[expectnot]\n\t"
866 #ifdef RSEQ_COMPARE_TWICE
867 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
868 "movl %[v], %%ebx\n\t"
869 "cmpl %%ebx, %[expectnot]\n\t"
872 "movl %%ebx, %[load]\n\t"
873 "addl %[voffp], %%ebx\n\t"
874 "movl (%%ebx), %%ebx\n\t"
876 "movl %%ebx, %[v]\n\t"
879 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
880 : /* gcc asm goto does not allow outputs */
881 : [cpu_id
] "r" (cpu
),
882 [rseq_abi
] "r" (rseq_get_abi()),
883 /* final store input */
885 [expectnot
] "r" (expectnot
),
886 [voffp
] "ir" (voffp
),
888 : "memory", "cc", "eax", "ebx"
891 #ifdef RSEQ_COMPARE_TWICE
895 rseq_after_asm_goto();
898 rseq_after_asm_goto();
902 rseq_after_asm_goto();
904 #ifdef RSEQ_COMPARE_TWICE
906 rseq_after_asm_goto();
907 rseq_bug("cpu_id comparison failed");
909 rseq_after_asm_goto();
910 rseq_bug("expected value comparison failed");
914 static inline __attribute__((always_inline
))
915 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
919 __asm__ __volatile__
goto (
920 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
921 #ifdef RSEQ_COMPARE_TWICE
922 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
924 /* Start rseq by storing table entry pointer into rseq_cs. */
925 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
926 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
928 #ifdef RSEQ_COMPARE_TWICE
929 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
932 "addl %[count], %[v]\n\t"
935 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
936 : /* gcc asm goto does not allow outputs */
937 : [cpu_id
] "r" (cpu
),
938 [rseq_abi
] "r" (rseq_get_abi()),
939 /* final store input */
942 : "memory", "cc", "eax"
945 #ifdef RSEQ_COMPARE_TWICE
949 rseq_after_asm_goto();
952 rseq_after_asm_goto();
955 #ifdef RSEQ_COMPARE_TWICE
957 rseq_after_asm_goto();
958 rseq_bug("cpu_id comparison failed");
962 static inline __attribute__((always_inline
))
963 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
964 intptr_t *v2
, intptr_t newv2
,
965 intptr_t newv
, int cpu
)
969 __asm__ __volatile__
goto (
970 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
971 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
972 #ifdef RSEQ_COMPARE_TWICE
973 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
974 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
976 /* Start rseq by storing table entry pointer into rseq_cs. */
977 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
978 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
980 "cmpl %[v], %[expect]\n\t"
981 "jnz %l[cmpfail]\n\t"
983 #ifdef RSEQ_COMPARE_TWICE
984 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
985 "cmpl %[v], %[expect]\n\t"
989 "movl %[newv2], %%eax\n\t"
990 "movl %%eax, %[v2]\n\t"
993 "movl %[newv], %[v]\n\t"
996 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
997 : /* gcc asm goto does not allow outputs */
998 : [cpu_id
] "r" (cpu
),
999 [rseq_abi
] "r" (rseq_get_abi()),
1000 /* try store input */
1002 [newv2
] "m" (newv2
),
1003 /* final store input */
1005 [expect
] "r" (expect
),
1007 : "memory", "cc", "eax"
1010 #ifdef RSEQ_COMPARE_TWICE
1014 rseq_after_asm_goto();
1017 rseq_after_asm_goto();
1021 rseq_after_asm_goto();
1023 #ifdef RSEQ_COMPARE_TWICE
1025 rseq_after_asm_goto();
1026 rseq_bug("cpu_id comparison failed");
1028 rseq_after_asm_goto();
1029 rseq_bug("expected value comparison failed");
1033 static inline __attribute__((always_inline
))
1034 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
1035 intptr_t *v2
, intptr_t newv2
,
1036 intptr_t newv
, int cpu
)
1040 __asm__ __volatile__
goto (
1041 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1042 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1043 #ifdef RSEQ_COMPARE_TWICE
1044 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1045 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1047 /* Start rseq by storing table entry pointer into rseq_cs. */
1048 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1049 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1051 "movl %[expect], %%eax\n\t"
1052 "cmpl %[v], %%eax\n\t"
1053 "jnz %l[cmpfail]\n\t"
1055 #ifdef RSEQ_COMPARE_TWICE
1056 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
1057 "movl %[expect], %%eax\n\t"
1058 "cmpl %[v], %%eax\n\t"
1059 "jnz %l[error2]\n\t"
1062 "movl %[newv2], %[v2]\n\t"
1064 "lock; addl $0,-128(%%esp)\n\t"
1066 "movl %[newv], %[v]\n\t"
1069 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
1070 : /* gcc asm goto does not allow outputs */
1071 : [cpu_id
] "r" (cpu
),
1072 [rseq_abi
] "r" (rseq_get_abi()),
1073 /* try store input */
1075 [newv2
] "r" (newv2
),
1076 /* final store input */
1078 [expect
] "m" (expect
),
1080 : "memory", "cc", "eax"
1083 #ifdef RSEQ_COMPARE_TWICE
1087 rseq_after_asm_goto();
1090 rseq_after_asm_goto();
1094 rseq_after_asm_goto();
1096 #ifdef RSEQ_COMPARE_TWICE
1098 rseq_after_asm_goto();
1099 rseq_bug("cpu_id comparison failed");
1101 rseq_after_asm_goto();
1102 rseq_bug("expected value comparison failed");
1107 static inline __attribute__((always_inline
))
1108 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
1109 intptr_t *v2
, intptr_t expect2
,
1110 intptr_t newv
, int cpu
)
1114 __asm__ __volatile__
goto (
1115 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1116 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1117 #ifdef RSEQ_COMPARE_TWICE
1118 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1119 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1120 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
1122 /* Start rseq by storing table entry pointer into rseq_cs. */
1123 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1124 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1126 "cmpl %[v], %[expect]\n\t"
1127 "jnz %l[cmpfail]\n\t"
1129 "cmpl %[expect2], %[v2]\n\t"
1130 "jnz %l[cmpfail]\n\t"
1132 #ifdef RSEQ_COMPARE_TWICE
1133 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
1134 "cmpl %[v], %[expect]\n\t"
1135 "jnz %l[error2]\n\t"
1136 "cmpl %[expect2], %[v2]\n\t"
1137 "jnz %l[error3]\n\t"
1139 "movl %[newv], %%eax\n\t"
1141 "movl %%eax, %[v]\n\t"
1144 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
1145 : /* gcc asm goto does not allow outputs */
1146 : [cpu_id
] "r" (cpu
),
1147 [rseq_abi
] "r" (rseq_get_abi()),
1150 [expect2
] "r" (expect2
),
1151 /* final store input */
1153 [expect
] "r" (expect
),
1155 : "memory", "cc", "eax"
1158 #ifdef RSEQ_COMPARE_TWICE
1159 , error1
, error2
, error3
1162 rseq_after_asm_goto();
1165 rseq_after_asm_goto();
1169 rseq_after_asm_goto();
1171 #ifdef RSEQ_COMPARE_TWICE
1173 rseq_after_asm_goto();
1174 rseq_bug("cpu_id comparison failed");
1176 rseq_after_asm_goto();
1177 rseq_bug("1st expected value comparison failed");
1179 rseq_after_asm_goto();
1180 rseq_bug("2nd expected value comparison failed");
1184 /* TODO: implement a faster memcpy. */
1185 static inline __attribute__((always_inline
))
1186 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
1187 void *dst
, void *src
, size_t len
,
1188 intptr_t newv
, int cpu
)
1190 uint32_t rseq_scratch
[3];
1194 __asm__ __volatile__
goto (
1195 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1196 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1197 #ifdef RSEQ_COMPARE_TWICE
1198 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1199 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1201 "movl %[src], %[rseq_scratch0]\n\t"
1202 "movl %[dst], %[rseq_scratch1]\n\t"
1203 "movl %[len], %[rseq_scratch2]\n\t"
1204 /* Start rseq by storing table entry pointer into rseq_cs. */
1205 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1206 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1208 "movl %[expect], %%eax\n\t"
1209 "cmpl %%eax, %[v]\n\t"
1212 #ifdef RSEQ_COMPARE_TWICE
1213 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
1214 "movl %[expect], %%eax\n\t"
1215 "cmpl %%eax, %[v]\n\t"
1219 "test %[len], %[len]\n\t" \
1222 "movb (%[src]), %%al\n\t" \
1223 "movb %%al, (%[dst])\n\t" \
1230 "movl %[newv], %%eax\n\t"
1232 "movl %%eax, %[v]\n\t"
1236 "movl %[rseq_scratch2], %[len]\n\t"
1237 "movl %[rseq_scratch1], %[dst]\n\t"
1238 "movl %[rseq_scratch0], %[src]\n\t"
1239 RSEQ_ASM_DEFINE_ABORT(4,
1240 "movl %[rseq_scratch2], %[len]\n\t"
1241 "movl %[rseq_scratch1], %[dst]\n\t"
1242 "movl %[rseq_scratch0], %[src]\n\t",
1244 RSEQ_ASM_DEFINE_CMPFAIL(5,
1245 "movl %[rseq_scratch2], %[len]\n\t"
1246 "movl %[rseq_scratch1], %[dst]\n\t"
1247 "movl %[rseq_scratch0], %[src]\n\t",
1249 #ifdef RSEQ_COMPARE_TWICE
1250 RSEQ_ASM_DEFINE_CMPFAIL(6,
1251 "movl %[rseq_scratch2], %[len]\n\t"
1252 "movl %[rseq_scratch1], %[dst]\n\t"
1253 "movl %[rseq_scratch0], %[src]\n\t",
1255 RSEQ_ASM_DEFINE_CMPFAIL(7,
1256 "movl %[rseq_scratch2], %[len]\n\t"
1257 "movl %[rseq_scratch1], %[dst]\n\t"
1258 "movl %[rseq_scratch0], %[src]\n\t",
1261 : /* gcc asm goto does not allow outputs */
1262 : [cpu_id
] "r" (cpu
),
1263 [rseq_abi
] "r" (rseq_get_abi()),
1264 /* final store input */
1266 [expect
] "m" (expect
),
1268 /* try memcpy input */
1272 [rseq_scratch0
] "m" (rseq_scratch
[0]),
1273 [rseq_scratch1
] "m" (rseq_scratch
[1]),
1274 [rseq_scratch2
] "m" (rseq_scratch
[2])
1275 : "memory", "cc", "eax"
1278 #ifdef RSEQ_COMPARE_TWICE
1282 rseq_after_asm_goto();
1285 rseq_after_asm_goto();
1289 rseq_after_asm_goto();
1291 #ifdef RSEQ_COMPARE_TWICE
1293 rseq_after_asm_goto();
1294 rseq_bug("cpu_id comparison failed");
1296 rseq_after_asm_goto();
1297 rseq_bug("expected value comparison failed");
1301 /* TODO: implement a faster memcpy. */
1302 static inline __attribute__((always_inline
))
1303 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
1304 void *dst
, void *src
, size_t len
,
1305 intptr_t newv
, int cpu
)
1307 uint32_t rseq_scratch
[3];
1311 __asm__ __volatile__
goto (
1312 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1313 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
1314 #ifdef RSEQ_COMPARE_TWICE
1315 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1316 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
1318 "movl %[src], %[rseq_scratch0]\n\t"
1319 "movl %[dst], %[rseq_scratch1]\n\t"
1320 "movl %[len], %[rseq_scratch2]\n\t"
1321 /* Start rseq by storing table entry pointer into rseq_cs. */
1322 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1323 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1325 "movl %[expect], %%eax\n\t"
1326 "cmpl %%eax, %[v]\n\t"
1329 #ifdef RSEQ_COMPARE_TWICE
1330 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 6f
)
1331 "movl %[expect], %%eax\n\t"
1332 "cmpl %%eax, %[v]\n\t"
1336 "test %[len], %[len]\n\t" \
1339 "movb (%[src]), %%al\n\t" \
1340 "movb %%al, (%[dst])\n\t" \
1347 "lock; addl $0,-128(%%esp)\n\t"
1348 "movl %[newv], %%eax\n\t"
1350 "movl %%eax, %[v]\n\t"
1354 "movl %[rseq_scratch2], %[len]\n\t"
1355 "movl %[rseq_scratch1], %[dst]\n\t"
1356 "movl %[rseq_scratch0], %[src]\n\t"
1357 RSEQ_ASM_DEFINE_ABORT(4,
1358 "movl %[rseq_scratch2], %[len]\n\t"
1359 "movl %[rseq_scratch1], %[dst]\n\t"
1360 "movl %[rseq_scratch0], %[src]\n\t",
1362 RSEQ_ASM_DEFINE_CMPFAIL(5,
1363 "movl %[rseq_scratch2], %[len]\n\t"
1364 "movl %[rseq_scratch1], %[dst]\n\t"
1365 "movl %[rseq_scratch0], %[src]\n\t",
1367 #ifdef RSEQ_COMPARE_TWICE
1368 RSEQ_ASM_DEFINE_CMPFAIL(6,
1369 "movl %[rseq_scratch2], %[len]\n\t"
1370 "movl %[rseq_scratch1], %[dst]\n\t"
1371 "movl %[rseq_scratch0], %[src]\n\t",
1373 RSEQ_ASM_DEFINE_CMPFAIL(7,
1374 "movl %[rseq_scratch2], %[len]\n\t"
1375 "movl %[rseq_scratch1], %[dst]\n\t"
1376 "movl %[rseq_scratch0], %[src]\n\t",
1379 : /* gcc asm goto does not allow outputs */
1380 : [cpu_id
] "r" (cpu
),
1381 [rseq_abi
] "r" (rseq_get_abi()),
1382 /* final store input */
1384 [expect
] "m" (expect
),
1386 /* try memcpy input */
1390 [rseq_scratch0
] "m" (rseq_scratch
[0]),
1391 [rseq_scratch1
] "m" (rseq_scratch
[1]),
1392 [rseq_scratch2
] "m" (rseq_scratch
[2])
1393 : "memory", "cc", "eax"
1396 #ifdef RSEQ_COMPARE_TWICE
1400 rseq_after_asm_goto();
1403 rseq_after_asm_goto();
1407 rseq_after_asm_goto();
1409 #ifdef RSEQ_COMPARE_TWICE
1411 rseq_after_asm_goto();
1412 rseq_bug("cpu_id comparison failed");
1414 rseq_after_asm_goto();
1415 rseq_bug("expected value comparison failed");
1420 * Dereference @p. Add voffp to the dereferenced pointer, and load its content
1423 static inline __attribute__((always_inline
))
1424 int rseq_deref_loadoffp(intptr_t *p
, long voffp
, intptr_t *load
, int cpu
)
1428 __asm__ __volatile__
goto (
1429 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1430 #ifdef RSEQ_COMPARE_TWICE
1431 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
1433 /* Start rseq by storing table entry pointer into rseq_cs. */
1434 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_CS_OFFSET(%[rseq_abi
]))
1435 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), 4f
)
1437 "movl %[p], %%ebx\n\t"
1439 #ifdef RSEQ_COMPARE_TWICE
1440 RSEQ_ASM_CMP_CPU_ID(cpu_id
, RSEQ_CPU_ID_OFFSET(%[rseq_abi
]), %l
[error1
])
1442 "addl %[voffp], %%ebx\n\t"
1443 "movl (%%ebx), %%ebx\n\t"
1444 "movl %%ebx, %[load]\n\t"
1447 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
1448 : /* gcc asm goto does not allow outputs */
1449 : [cpu_id
] "r" (cpu
),
1450 [rseq_abi
] "r" (rseq_get_abi()),
1451 /* final store input */
1453 [voffp
] "ir" (voffp
),
1455 : "memory", "cc", "eax", "ebx"
1458 #ifdef RSEQ_COMPARE_TWICE
1462 rseq_after_asm_goto();
1465 rseq_after_asm_goto();
1468 #ifdef RSEQ_COMPARE_TWICE
1470 rseq_after_asm_goto();
1471 rseq_bug("cpu_id comparison failed");
1475 #endif /* !RSEQ_SKIP_FASTPATH */
This page took 0.082574 seconds and 4 git commands to generate.