0001
0002
0003
0004
0005
0006
0007
0008 #include <stdint.h>
0009
0010
0011
0012
0013
0014
0015
0016
0017 #define RSEQ_SIG 0x53053053
0018
0019
0020
0021
0022
0023
0024
0025
0026 #define RSEQ_CPU_ID_OFFSET 4
0027 #define RSEQ_CS_OFFSET 8
0028
0029 #ifdef __x86_64__
0030
0031 #define RSEQ_ASM_TP_SEGMENT %%fs
0032
0033 #define rseq_smp_mb() \
0034 __asm__ __volatile__ ("lock; addl $0,-128(%%rsp)" ::: "memory", "cc")
0035 #define rseq_smp_rmb() rseq_barrier()
0036 #define rseq_smp_wmb() rseq_barrier()
0037
0038 #define rseq_smp_load_acquire(p) \
0039 __extension__ ({ \
0040 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
0041 rseq_barrier(); \
0042 ____p1; \
0043 })
0044
0045 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
0046
0047 #define rseq_smp_store_release(p, v) \
0048 do { \
0049 rseq_barrier(); \
0050 RSEQ_WRITE_ONCE(*p, v); \
0051 } while (0)
0052
0053 #ifdef RSEQ_SKIP_FASTPATH
0054 #include "rseq-skip.h"
0055 #else
0056
0057 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
0058 start_ip, post_commit_offset, abort_ip) \
0059 ".pushsection __rseq_cs, \"aw\"\n\t" \
0060 ".balign 32\n\t" \
0061 __rseq_str(label) ":\n\t" \
0062 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
0063 ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
0064 ".popsection\n\t" \
0065 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
0066 ".quad " __rseq_str(label) "b\n\t" \
0067 ".popsection\n\t"
0068
0069
0070 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
0071 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
0072 (post_commit_ip - start_ip), abort_ip)
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
0083 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
0084 ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
0085 ".popsection\n\t"
0086
0087 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
0088 RSEQ_INJECT_ASM(1) \
0089 "leaq " __rseq_str(cs_label) "(%%rip), %%rax\n\t" \
0090 "movq %%rax, " __rseq_str(rseq_cs) "\n\t" \
0091 __rseq_str(label) ":\n\t"
0092
0093 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
0094 RSEQ_INJECT_ASM(2) \
0095 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
0096 "jnz " __rseq_str(label) "\n\t"
0097
0098 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
0099 ".pushsection __rseq_failure, \"ax\"\n\t" \
0100 \
0101 ".byte 0x0f, 0xb9, 0x3d\n\t" \
0102 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
0103 __rseq_str(label) ":\n\t" \
0104 teardown \
0105 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
0106 ".popsection\n\t"
0107
0108 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
0109 ".pushsection __rseq_failure, \"ax\"\n\t" \
0110 __rseq_str(label) ":\n\t" \
0111 teardown \
0112 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
0113 ".popsection\n\t"
0114
0115 static inline __attribute__((always_inline))
0116 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
0117 {
0118 RSEQ_INJECT_C(9)
0119
0120 __asm__ __volatile__ goto (
0121 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0122 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0123 #ifdef RSEQ_COMPARE_TWICE
0124 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0125 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0126 #endif
0127
0128 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0129 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0130 RSEQ_INJECT_ASM(3)
0131 "cmpq %[v], %[expect]\n\t"
0132 "jnz %l[cmpfail]\n\t"
0133 RSEQ_INJECT_ASM(4)
0134 #ifdef RSEQ_COMPARE_TWICE
0135 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0136 "cmpq %[v], %[expect]\n\t"
0137 "jnz %l[error2]\n\t"
0138 #endif
0139
0140 "movq %[newv], %[v]\n\t"
0141 "2:\n\t"
0142 RSEQ_INJECT_ASM(5)
0143 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0144 :
0145 : [cpu_id] "r" (cpu),
0146 [rseq_offset] "r" (rseq_offset),
0147 [v] "m" (*v),
0148 [expect] "r" (expect),
0149 [newv] "r" (newv)
0150 : "memory", "cc", "rax"
0151 RSEQ_INJECT_CLOBBER
0152 : abort, cmpfail
0153 #ifdef RSEQ_COMPARE_TWICE
0154 , error1, error2
0155 #endif
0156 );
0157 rseq_after_asm_goto();
0158 return 0;
0159 abort:
0160 rseq_after_asm_goto();
0161 RSEQ_INJECT_FAILED
0162 return -1;
0163 cmpfail:
0164 rseq_after_asm_goto();
0165 return 1;
0166 #ifdef RSEQ_COMPARE_TWICE
0167 error1:
0168 rseq_after_asm_goto();
0169 rseq_bug("cpu_id comparison failed");
0170 error2:
0171 rseq_after_asm_goto();
0172 rseq_bug("expected value comparison failed");
0173 #endif
0174 }
0175
0176
0177
0178
0179
0180 static inline __attribute__((always_inline))
0181 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
0182 long voffp, intptr_t *load, int cpu)
0183 {
0184 RSEQ_INJECT_C(9)
0185
0186 __asm__ __volatile__ goto (
0187 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0188 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0189 #ifdef RSEQ_COMPARE_TWICE
0190 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0191 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0192 #endif
0193
0194 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0195 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0196 RSEQ_INJECT_ASM(3)
0197 "movq %[v], %%rbx\n\t"
0198 "cmpq %%rbx, %[expectnot]\n\t"
0199 "je %l[cmpfail]\n\t"
0200 RSEQ_INJECT_ASM(4)
0201 #ifdef RSEQ_COMPARE_TWICE
0202 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0203 "movq %[v], %%rbx\n\t"
0204 "cmpq %%rbx, %[expectnot]\n\t"
0205 "je %l[error2]\n\t"
0206 #endif
0207 "movq %%rbx, %[load]\n\t"
0208 "addq %[voffp], %%rbx\n\t"
0209 "movq (%%rbx), %%rbx\n\t"
0210
0211 "movq %%rbx, %[v]\n\t"
0212 "2:\n\t"
0213 RSEQ_INJECT_ASM(5)
0214 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0215 :
0216 : [cpu_id] "r" (cpu),
0217 [rseq_offset] "r" (rseq_offset),
0218
0219 [v] "m" (*v),
0220 [expectnot] "r" (expectnot),
0221 [voffp] "er" (voffp),
0222 [load] "m" (*load)
0223 : "memory", "cc", "rax", "rbx"
0224 RSEQ_INJECT_CLOBBER
0225 : abort, cmpfail
0226 #ifdef RSEQ_COMPARE_TWICE
0227 , error1, error2
0228 #endif
0229 );
0230 rseq_after_asm_goto();
0231 return 0;
0232 abort:
0233 rseq_after_asm_goto();
0234 RSEQ_INJECT_FAILED
0235 return -1;
0236 cmpfail:
0237 rseq_after_asm_goto();
0238 return 1;
0239 #ifdef RSEQ_COMPARE_TWICE
0240 error1:
0241 rseq_after_asm_goto();
0242 rseq_bug("cpu_id comparison failed");
0243 error2:
0244 rseq_after_asm_goto();
0245 rseq_bug("expected value comparison failed");
0246 #endif
0247 }
0248
0249 static inline __attribute__((always_inline))
0250 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
0251 {
0252 RSEQ_INJECT_C(9)
0253
0254 __asm__ __volatile__ goto (
0255 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0256 #ifdef RSEQ_COMPARE_TWICE
0257 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0258 #endif
0259
0260 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0261 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0262 RSEQ_INJECT_ASM(3)
0263 #ifdef RSEQ_COMPARE_TWICE
0264 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0265 #endif
0266
0267 "addq %[count], %[v]\n\t"
0268 "2:\n\t"
0269 RSEQ_INJECT_ASM(4)
0270 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0271 :
0272 : [cpu_id] "r" (cpu),
0273 [rseq_offset] "r" (rseq_offset),
0274
0275 [v] "m" (*v),
0276 [count] "er" (count)
0277 : "memory", "cc", "rax"
0278 RSEQ_INJECT_CLOBBER
0279 : abort
0280 #ifdef RSEQ_COMPARE_TWICE
0281 , error1
0282 #endif
0283 );
0284 rseq_after_asm_goto();
0285 return 0;
0286 abort:
0287 rseq_after_asm_goto();
0288 RSEQ_INJECT_FAILED
0289 return -1;
0290 #ifdef RSEQ_COMPARE_TWICE
0291 error1:
0292 rseq_after_asm_goto();
0293 rseq_bug("cpu_id comparison failed");
0294 #endif
0295 }
0296
0297 #define RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
0298
0299
0300
0301
0302
0303 static inline __attribute__((always_inline))
0304 int rseq_offset_deref_addv(intptr_t *ptr, long off, intptr_t inc, int cpu)
0305 {
0306 RSEQ_INJECT_C(9)
0307
0308 __asm__ __volatile__ goto (
0309 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0310 #ifdef RSEQ_COMPARE_TWICE
0311 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0312 #endif
0313
0314 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0315 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0316 RSEQ_INJECT_ASM(3)
0317 #ifdef RSEQ_COMPARE_TWICE
0318 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0319 #endif
0320
0321 "movq %[ptr], %%rbx\n\t"
0322 "addq %[off], %%rbx\n\t"
0323
0324 "movq (%%rbx), %%rcx\n\t"
0325
0326 "addq %[inc], (%%rcx)\n\t"
0327 "2:\n\t"
0328 RSEQ_INJECT_ASM(4)
0329 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0330 :
0331 : [cpu_id] "r" (cpu),
0332 [rseq_offset] "r" (rseq_offset),
0333
0334 [ptr] "m" (*ptr),
0335 [off] "er" (off),
0336 [inc] "er" (inc)
0337 : "memory", "cc", "rax", "rbx", "rcx"
0338 RSEQ_INJECT_CLOBBER
0339 : abort
0340 #ifdef RSEQ_COMPARE_TWICE
0341 , error1
0342 #endif
0343 );
0344 return 0;
0345 abort:
0346 RSEQ_INJECT_FAILED
0347 return -1;
0348 #ifdef RSEQ_COMPARE_TWICE
0349 error1:
0350 rseq_bug("cpu_id comparison failed");
0351 #endif
0352 }
0353
0354 static inline __attribute__((always_inline))
0355 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
0356 intptr_t *v2, intptr_t newv2,
0357 intptr_t newv, int cpu)
0358 {
0359 RSEQ_INJECT_C(9)
0360
0361 __asm__ __volatile__ goto (
0362 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0363 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0364 #ifdef RSEQ_COMPARE_TWICE
0365 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0366 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0367 #endif
0368
0369 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0370 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0371 RSEQ_INJECT_ASM(3)
0372 "cmpq %[v], %[expect]\n\t"
0373 "jnz %l[cmpfail]\n\t"
0374 RSEQ_INJECT_ASM(4)
0375 #ifdef RSEQ_COMPARE_TWICE
0376 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0377 "cmpq %[v], %[expect]\n\t"
0378 "jnz %l[error2]\n\t"
0379 #endif
0380
0381 "movq %[newv2], %[v2]\n\t"
0382 RSEQ_INJECT_ASM(5)
0383
0384 "movq %[newv], %[v]\n\t"
0385 "2:\n\t"
0386 RSEQ_INJECT_ASM(6)
0387 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0388 :
0389 : [cpu_id] "r" (cpu),
0390 [rseq_offset] "r" (rseq_offset),
0391
0392 [v2] "m" (*v2),
0393 [newv2] "r" (newv2),
0394
0395 [v] "m" (*v),
0396 [expect] "r" (expect),
0397 [newv] "r" (newv)
0398 : "memory", "cc", "rax"
0399 RSEQ_INJECT_CLOBBER
0400 : abort, cmpfail
0401 #ifdef RSEQ_COMPARE_TWICE
0402 , error1, error2
0403 #endif
0404 );
0405 rseq_after_asm_goto();
0406 return 0;
0407 abort:
0408 rseq_after_asm_goto();
0409 RSEQ_INJECT_FAILED
0410 return -1;
0411 cmpfail:
0412 rseq_after_asm_goto();
0413 return 1;
0414 #ifdef RSEQ_COMPARE_TWICE
0415 error1:
0416 rseq_after_asm_goto();
0417 rseq_bug("cpu_id comparison failed");
0418 error2:
0419 rseq_after_asm_goto();
0420 rseq_bug("expected value comparison failed");
0421 #endif
0422 }
0423
0424
0425 static inline __attribute__((always_inline))
0426 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
0427 intptr_t *v2, intptr_t newv2,
0428 intptr_t newv, int cpu)
0429 {
0430 return rseq_cmpeqv_trystorev_storev(v, expect, v2, newv2, newv, cpu);
0431 }
0432
0433 static inline __attribute__((always_inline))
0434 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
0435 intptr_t *v2, intptr_t expect2,
0436 intptr_t newv, int cpu)
0437 {
0438 RSEQ_INJECT_C(9)
0439
0440 __asm__ __volatile__ goto (
0441 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0442 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0443 #ifdef RSEQ_COMPARE_TWICE
0444 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0445 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0446 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
0447 #endif
0448
0449 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0450 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0451 RSEQ_INJECT_ASM(3)
0452 "cmpq %[v], %[expect]\n\t"
0453 "jnz %l[cmpfail]\n\t"
0454 RSEQ_INJECT_ASM(4)
0455 "cmpq %[v2], %[expect2]\n\t"
0456 "jnz %l[cmpfail]\n\t"
0457 RSEQ_INJECT_ASM(5)
0458 #ifdef RSEQ_COMPARE_TWICE
0459 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0460 "cmpq %[v], %[expect]\n\t"
0461 "jnz %l[error2]\n\t"
0462 "cmpq %[v2], %[expect2]\n\t"
0463 "jnz %l[error3]\n\t"
0464 #endif
0465
0466 "movq %[newv], %[v]\n\t"
0467 "2:\n\t"
0468 RSEQ_INJECT_ASM(6)
0469 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0470 :
0471 : [cpu_id] "r" (cpu),
0472 [rseq_offset] "r" (rseq_offset),
0473
0474 [v2] "m" (*v2),
0475 [expect2] "r" (expect2),
0476
0477 [v] "m" (*v),
0478 [expect] "r" (expect),
0479 [newv] "r" (newv)
0480 : "memory", "cc", "rax"
0481 RSEQ_INJECT_CLOBBER
0482 : abort, cmpfail
0483 #ifdef RSEQ_COMPARE_TWICE
0484 , error1, error2, error3
0485 #endif
0486 );
0487 rseq_after_asm_goto();
0488 return 0;
0489 abort:
0490 rseq_after_asm_goto();
0491 RSEQ_INJECT_FAILED
0492 return -1;
0493 cmpfail:
0494 rseq_after_asm_goto();
0495 return 1;
0496 #ifdef RSEQ_COMPARE_TWICE
0497 error1:
0498 rseq_after_asm_goto();
0499 rseq_bug("cpu_id comparison failed");
0500 error2:
0501 rseq_after_asm_goto();
0502 rseq_bug("1st expected value comparison failed");
0503 error3:
0504 rseq_after_asm_goto();
0505 rseq_bug("2nd expected value comparison failed");
0506 #endif
0507 }
0508
0509 static inline __attribute__((always_inline))
0510 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
0511 void *dst, void *src, size_t len,
0512 intptr_t newv, int cpu)
0513 {
0514 uint64_t rseq_scratch[3];
0515
0516 RSEQ_INJECT_C(9)
0517
0518 __asm__ __volatile__ goto (
0519 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0520 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0521 #ifdef RSEQ_COMPARE_TWICE
0522 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0523 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0524 #endif
0525 "movq %[src], %[rseq_scratch0]\n\t"
0526 "movq %[dst], %[rseq_scratch1]\n\t"
0527 "movq %[len], %[rseq_scratch2]\n\t"
0528
0529 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0530 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0531 RSEQ_INJECT_ASM(3)
0532 "cmpq %[v], %[expect]\n\t"
0533 "jnz 5f\n\t"
0534 RSEQ_INJECT_ASM(4)
0535 #ifdef RSEQ_COMPARE_TWICE
0536 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 6f)
0537 "cmpq %[v], %[expect]\n\t"
0538 "jnz 7f\n\t"
0539 #endif
0540
0541 "test %[len], %[len]\n\t" \
0542 "jz 333f\n\t" \
0543 "222:\n\t" \
0544 "movb (%[src]), %%al\n\t" \
0545 "movb %%al, (%[dst])\n\t" \
0546 "inc %[src]\n\t" \
0547 "inc %[dst]\n\t" \
0548 "dec %[len]\n\t" \
0549 "jnz 222b\n\t" \
0550 "333:\n\t" \
0551 RSEQ_INJECT_ASM(5)
0552
0553 "movq %[newv], %[v]\n\t"
0554 "2:\n\t"
0555 RSEQ_INJECT_ASM(6)
0556
0557 "movq %[rseq_scratch2], %[len]\n\t"
0558 "movq %[rseq_scratch1], %[dst]\n\t"
0559 "movq %[rseq_scratch0], %[src]\n\t"
0560 RSEQ_ASM_DEFINE_ABORT(4,
0561 "movq %[rseq_scratch2], %[len]\n\t"
0562 "movq %[rseq_scratch1], %[dst]\n\t"
0563 "movq %[rseq_scratch0], %[src]\n\t",
0564 abort)
0565 RSEQ_ASM_DEFINE_CMPFAIL(5,
0566 "movq %[rseq_scratch2], %[len]\n\t"
0567 "movq %[rseq_scratch1], %[dst]\n\t"
0568 "movq %[rseq_scratch0], %[src]\n\t",
0569 cmpfail)
0570 #ifdef RSEQ_COMPARE_TWICE
0571 RSEQ_ASM_DEFINE_CMPFAIL(6,
0572 "movq %[rseq_scratch2], %[len]\n\t"
0573 "movq %[rseq_scratch1], %[dst]\n\t"
0574 "movq %[rseq_scratch0], %[src]\n\t",
0575 error1)
0576 RSEQ_ASM_DEFINE_CMPFAIL(7,
0577 "movq %[rseq_scratch2], %[len]\n\t"
0578 "movq %[rseq_scratch1], %[dst]\n\t"
0579 "movq %[rseq_scratch0], %[src]\n\t",
0580 error2)
0581 #endif
0582 :
0583 : [cpu_id] "r" (cpu),
0584 [rseq_offset] "r" (rseq_offset),
0585
0586 [v] "m" (*v),
0587 [expect] "r" (expect),
0588 [newv] "r" (newv),
0589
0590 [dst] "r" (dst),
0591 [src] "r" (src),
0592 [len] "r" (len),
0593 [rseq_scratch0] "m" (rseq_scratch[0]),
0594 [rseq_scratch1] "m" (rseq_scratch[1]),
0595 [rseq_scratch2] "m" (rseq_scratch[2])
0596 : "memory", "cc", "rax"
0597 RSEQ_INJECT_CLOBBER
0598 : abort, cmpfail
0599 #ifdef RSEQ_COMPARE_TWICE
0600 , error1, error2
0601 #endif
0602 );
0603 rseq_after_asm_goto();
0604 return 0;
0605 abort:
0606 rseq_after_asm_goto();
0607 RSEQ_INJECT_FAILED
0608 return -1;
0609 cmpfail:
0610 rseq_after_asm_goto();
0611 return 1;
0612 #ifdef RSEQ_COMPARE_TWICE
0613 error1:
0614 rseq_after_asm_goto();
0615 rseq_bug("cpu_id comparison failed");
0616 error2:
0617 rseq_after_asm_goto();
0618 rseq_bug("expected value comparison failed");
0619 #endif
0620 }
0621
0622
0623 static inline __attribute__((always_inline))
0624 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
0625 void *dst, void *src, size_t len,
0626 intptr_t newv, int cpu)
0627 {
0628 return rseq_cmpeqv_trymemcpy_storev(v, expect, dst, src, len,
0629 newv, cpu);
0630 }
0631
0632 #endif
0633
0634 #elif defined(__i386__)
0635
0636 #define RSEQ_ASM_TP_SEGMENT %%gs
0637
0638 #define rseq_smp_mb() \
0639 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
0640 #define rseq_smp_rmb() \
0641 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
0642 #define rseq_smp_wmb() \
0643 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
0644
0645 #define rseq_smp_load_acquire(p) \
0646 __extension__ ({ \
0647 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
0648 rseq_smp_mb(); \
0649 ____p1; \
0650 })
0651
0652 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
0653
0654 #define rseq_smp_store_release(p, v) \
0655 do { \
0656 rseq_smp_mb(); \
0657 RSEQ_WRITE_ONCE(*p, v); \
0658 } while (0)
0659
0660 #ifdef RSEQ_SKIP_FASTPATH
0661 #include "rseq-skip.h"
0662 #else
0663
0664
0665
0666
0667
0668 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
0669 start_ip, post_commit_offset, abort_ip) \
0670 ".pushsection __rseq_cs, \"aw\"\n\t" \
0671 ".balign 32\n\t" \
0672 __rseq_str(label) ":\n\t" \
0673 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
0674 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
0675 ".popsection\n\t" \
0676 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
0677 ".long " __rseq_str(label) "b, 0x0\n\t" \
0678 ".popsection\n\t"
0679
0680 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
0681 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
0682 (post_commit_ip - start_ip), abort_ip)
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
0693 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
0694 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
0695 ".popsection\n\t"
0696
0697 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
0698 RSEQ_INJECT_ASM(1) \
0699 "movl $" __rseq_str(cs_label) ", " __rseq_str(rseq_cs) "\n\t" \
0700 __rseq_str(label) ":\n\t"
0701
0702 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
0703 RSEQ_INJECT_ASM(2) \
0704 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
0705 "jnz " __rseq_str(label) "\n\t"
0706
0707 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
0708 ".pushsection __rseq_failure, \"ax\"\n\t" \
0709 \
0710 ".byte 0x0f, 0xb9, 0x3d\n\t" \
0711 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
0712 __rseq_str(label) ":\n\t" \
0713 teardown \
0714 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
0715 ".popsection\n\t"
0716
0717 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
0718 ".pushsection __rseq_failure, \"ax\"\n\t" \
0719 __rseq_str(label) ":\n\t" \
0720 teardown \
0721 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
0722 ".popsection\n\t"
0723
0724 static inline __attribute__((always_inline))
0725 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
0726 {
0727 RSEQ_INJECT_C(9)
0728
0729 __asm__ __volatile__ goto (
0730 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0731 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0732 #ifdef RSEQ_COMPARE_TWICE
0733 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0734 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0735 #endif
0736
0737 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0738 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0739 RSEQ_INJECT_ASM(3)
0740 "cmpl %[v], %[expect]\n\t"
0741 "jnz %l[cmpfail]\n\t"
0742 RSEQ_INJECT_ASM(4)
0743 #ifdef RSEQ_COMPARE_TWICE
0744 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0745 "cmpl %[v], %[expect]\n\t"
0746 "jnz %l[error2]\n\t"
0747 #endif
0748
0749 "movl %[newv], %[v]\n\t"
0750 "2:\n\t"
0751 RSEQ_INJECT_ASM(5)
0752 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0753 :
0754 : [cpu_id] "r" (cpu),
0755 [rseq_offset] "r" (rseq_offset),
0756 [v] "m" (*v),
0757 [expect] "r" (expect),
0758 [newv] "r" (newv)
0759 : "memory", "cc", "eax"
0760 RSEQ_INJECT_CLOBBER
0761 : abort, cmpfail
0762 #ifdef RSEQ_COMPARE_TWICE
0763 , error1, error2
0764 #endif
0765 );
0766 rseq_after_asm_goto();
0767 return 0;
0768 abort:
0769 rseq_after_asm_goto();
0770 RSEQ_INJECT_FAILED
0771 return -1;
0772 cmpfail:
0773 rseq_after_asm_goto();
0774 return 1;
0775 #ifdef RSEQ_COMPARE_TWICE
0776 error1:
0777 rseq_after_asm_goto();
0778 rseq_bug("cpu_id comparison failed");
0779 error2:
0780 rseq_after_asm_goto();
0781 rseq_bug("expected value comparison failed");
0782 #endif
0783 }
0784
0785
0786
0787
0788
0789 static inline __attribute__((always_inline))
0790 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
0791 long voffp, intptr_t *load, int cpu)
0792 {
0793 RSEQ_INJECT_C(9)
0794
0795 __asm__ __volatile__ goto (
0796 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0797 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0798 #ifdef RSEQ_COMPARE_TWICE
0799 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0800 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0801 #endif
0802
0803 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0804 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0805 RSEQ_INJECT_ASM(3)
0806 "movl %[v], %%ebx\n\t"
0807 "cmpl %%ebx, %[expectnot]\n\t"
0808 "je %l[cmpfail]\n\t"
0809 RSEQ_INJECT_ASM(4)
0810 #ifdef RSEQ_COMPARE_TWICE
0811 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0812 "movl %[v], %%ebx\n\t"
0813 "cmpl %%ebx, %[expectnot]\n\t"
0814 "je %l[error2]\n\t"
0815 #endif
0816 "movl %%ebx, %[load]\n\t"
0817 "addl %[voffp], %%ebx\n\t"
0818 "movl (%%ebx), %%ebx\n\t"
0819
0820 "movl %%ebx, %[v]\n\t"
0821 "2:\n\t"
0822 RSEQ_INJECT_ASM(5)
0823 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0824 :
0825 : [cpu_id] "r" (cpu),
0826 [rseq_offset] "r" (rseq_offset),
0827
0828 [v] "m" (*v),
0829 [expectnot] "r" (expectnot),
0830 [voffp] "ir" (voffp),
0831 [load] "m" (*load)
0832 : "memory", "cc", "eax", "ebx"
0833 RSEQ_INJECT_CLOBBER
0834 : abort, cmpfail
0835 #ifdef RSEQ_COMPARE_TWICE
0836 , error1, error2
0837 #endif
0838 );
0839 rseq_after_asm_goto();
0840 return 0;
0841 abort:
0842 rseq_after_asm_goto();
0843 RSEQ_INJECT_FAILED
0844 return -1;
0845 cmpfail:
0846 rseq_after_asm_goto();
0847 return 1;
0848 #ifdef RSEQ_COMPARE_TWICE
0849 error1:
0850 rseq_after_asm_goto();
0851 rseq_bug("cpu_id comparison failed");
0852 error2:
0853 rseq_after_asm_goto();
0854 rseq_bug("expected value comparison failed");
0855 #endif
0856 }
0857
0858 static inline __attribute__((always_inline))
0859 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
0860 {
0861 RSEQ_INJECT_C(9)
0862
0863 __asm__ __volatile__ goto (
0864 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0865 #ifdef RSEQ_COMPARE_TWICE
0866 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0867 #endif
0868
0869 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0870 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0871 RSEQ_INJECT_ASM(3)
0872 #ifdef RSEQ_COMPARE_TWICE
0873 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0874 #endif
0875
0876 "addl %[count], %[v]\n\t"
0877 "2:\n\t"
0878 RSEQ_INJECT_ASM(4)
0879 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0880 :
0881 : [cpu_id] "r" (cpu),
0882 [rseq_offset] "r" (rseq_offset),
0883
0884 [v] "m" (*v),
0885 [count] "ir" (count)
0886 : "memory", "cc", "eax"
0887 RSEQ_INJECT_CLOBBER
0888 : abort
0889 #ifdef RSEQ_COMPARE_TWICE
0890 , error1
0891 #endif
0892 );
0893 rseq_after_asm_goto();
0894 return 0;
0895 abort:
0896 rseq_after_asm_goto();
0897 RSEQ_INJECT_FAILED
0898 return -1;
0899 #ifdef RSEQ_COMPARE_TWICE
0900 error1:
0901 rseq_after_asm_goto();
0902 rseq_bug("cpu_id comparison failed");
0903 #endif
0904 }
0905
0906 static inline __attribute__((always_inline))
0907 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
0908 intptr_t *v2, intptr_t newv2,
0909 intptr_t newv, int cpu)
0910 {
0911 RSEQ_INJECT_C(9)
0912
0913 __asm__ __volatile__ goto (
0914 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0915 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0916 #ifdef RSEQ_COMPARE_TWICE
0917 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0918 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0919 #endif
0920
0921 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0922 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0923 RSEQ_INJECT_ASM(3)
0924 "cmpl %[v], %[expect]\n\t"
0925 "jnz %l[cmpfail]\n\t"
0926 RSEQ_INJECT_ASM(4)
0927 #ifdef RSEQ_COMPARE_TWICE
0928 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
0929 "cmpl %[v], %[expect]\n\t"
0930 "jnz %l[error2]\n\t"
0931 #endif
0932
0933 "movl %[newv2], %%eax\n\t"
0934 "movl %%eax, %[v2]\n\t"
0935 RSEQ_INJECT_ASM(5)
0936
0937 "movl %[newv], %[v]\n\t"
0938 "2:\n\t"
0939 RSEQ_INJECT_ASM(6)
0940 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
0941 :
0942 : [cpu_id] "r" (cpu),
0943 [rseq_offset] "r" (rseq_offset),
0944
0945 [v2] "m" (*v2),
0946 [newv2] "m" (newv2),
0947
0948 [v] "m" (*v),
0949 [expect] "r" (expect),
0950 [newv] "r" (newv)
0951 : "memory", "cc", "eax"
0952 RSEQ_INJECT_CLOBBER
0953 : abort, cmpfail
0954 #ifdef RSEQ_COMPARE_TWICE
0955 , error1, error2
0956 #endif
0957 );
0958 rseq_after_asm_goto();
0959 return 0;
0960 abort:
0961 rseq_after_asm_goto();
0962 RSEQ_INJECT_FAILED
0963 return -1;
0964 cmpfail:
0965 rseq_after_asm_goto();
0966 return 1;
0967 #ifdef RSEQ_COMPARE_TWICE
0968 error1:
0969 rseq_after_asm_goto();
0970 rseq_bug("cpu_id comparison failed");
0971 error2:
0972 rseq_after_asm_goto();
0973 rseq_bug("expected value comparison failed");
0974 #endif
0975 }
0976
0977 static inline __attribute__((always_inline))
0978 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
0979 intptr_t *v2, intptr_t newv2,
0980 intptr_t newv, int cpu)
0981 {
0982 RSEQ_INJECT_C(9)
0983
0984 __asm__ __volatile__ goto (
0985 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
0986 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0987 #ifdef RSEQ_COMPARE_TWICE
0988 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0989 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0990 #endif
0991
0992 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
0993 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
0994 RSEQ_INJECT_ASM(3)
0995 "movl %[expect], %%eax\n\t"
0996 "cmpl %[v], %%eax\n\t"
0997 "jnz %l[cmpfail]\n\t"
0998 RSEQ_INJECT_ASM(4)
0999 #ifdef RSEQ_COMPARE_TWICE
1000 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
1001 "movl %[expect], %%eax\n\t"
1002 "cmpl %[v], %%eax\n\t"
1003 "jnz %l[error2]\n\t"
1004 #endif
1005
1006 "movl %[newv2], %[v2]\n\t"
1007 RSEQ_INJECT_ASM(5)
1008 "lock; addl $0,-128(%%esp)\n\t"
1009
1010 "movl %[newv], %[v]\n\t"
1011 "2:\n\t"
1012 RSEQ_INJECT_ASM(6)
1013 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
1014 :
1015 : [cpu_id] "r" (cpu),
1016 [rseq_offset] "r" (rseq_offset),
1017
1018 [v2] "m" (*v2),
1019 [newv2] "r" (newv2),
1020
1021 [v] "m" (*v),
1022 [expect] "m" (expect),
1023 [newv] "r" (newv)
1024 : "memory", "cc", "eax"
1025 RSEQ_INJECT_CLOBBER
1026 : abort, cmpfail
1027 #ifdef RSEQ_COMPARE_TWICE
1028 , error1, error2
1029 #endif
1030 );
1031 rseq_after_asm_goto();
1032 return 0;
1033 abort:
1034 rseq_after_asm_goto();
1035 RSEQ_INJECT_FAILED
1036 return -1;
1037 cmpfail:
1038 rseq_after_asm_goto();
1039 return 1;
1040 #ifdef RSEQ_COMPARE_TWICE
1041 error1:
1042 rseq_after_asm_goto();
1043 rseq_bug("cpu_id comparison failed");
1044 error2:
1045 rseq_after_asm_goto();
1046 rseq_bug("expected value comparison failed");
1047 #endif
1048
1049 }
1050
1051 static inline __attribute__((always_inline))
1052 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
1053 intptr_t *v2, intptr_t expect2,
1054 intptr_t newv, int cpu)
1055 {
1056 RSEQ_INJECT_C(9)
1057
1058 __asm__ __volatile__ goto (
1059 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
1060 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
1061 #ifdef RSEQ_COMPARE_TWICE
1062 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
1063 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
1064 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
1065 #endif
1066
1067 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
1068 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
1069 RSEQ_INJECT_ASM(3)
1070 "cmpl %[v], %[expect]\n\t"
1071 "jnz %l[cmpfail]\n\t"
1072 RSEQ_INJECT_ASM(4)
1073 "cmpl %[expect2], %[v2]\n\t"
1074 "jnz %l[cmpfail]\n\t"
1075 RSEQ_INJECT_ASM(5)
1076 #ifdef RSEQ_COMPARE_TWICE
1077 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), %l[error1])
1078 "cmpl %[v], %[expect]\n\t"
1079 "jnz %l[error2]\n\t"
1080 "cmpl %[expect2], %[v2]\n\t"
1081 "jnz %l[error3]\n\t"
1082 #endif
1083 "movl %[newv], %%eax\n\t"
1084
1085 "movl %%eax, %[v]\n\t"
1086 "2:\n\t"
1087 RSEQ_INJECT_ASM(6)
1088 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
1089 :
1090 : [cpu_id] "r" (cpu),
1091 [rseq_offset] "r" (rseq_offset),
1092
1093 [v2] "m" (*v2),
1094 [expect2] "r" (expect2),
1095
1096 [v] "m" (*v),
1097 [expect] "r" (expect),
1098 [newv] "m" (newv)
1099 : "memory", "cc", "eax"
1100 RSEQ_INJECT_CLOBBER
1101 : abort, cmpfail
1102 #ifdef RSEQ_COMPARE_TWICE
1103 , error1, error2, error3
1104 #endif
1105 );
1106 rseq_after_asm_goto();
1107 return 0;
1108 abort:
1109 rseq_after_asm_goto();
1110 RSEQ_INJECT_FAILED
1111 return -1;
1112 cmpfail:
1113 rseq_after_asm_goto();
1114 return 1;
1115 #ifdef RSEQ_COMPARE_TWICE
1116 error1:
1117 rseq_after_asm_goto();
1118 rseq_bug("cpu_id comparison failed");
1119 error2:
1120 rseq_after_asm_goto();
1121 rseq_bug("1st expected value comparison failed");
1122 error3:
1123 rseq_after_asm_goto();
1124 rseq_bug("2nd expected value comparison failed");
1125 #endif
1126 }
1127
1128
1129 static inline __attribute__((always_inline))
1130 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
1131 void *dst, void *src, size_t len,
1132 intptr_t newv, int cpu)
1133 {
1134 uint32_t rseq_scratch[3];
1135
1136 RSEQ_INJECT_C(9)
1137
1138 __asm__ __volatile__ goto (
1139 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
1140 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
1141 #ifdef RSEQ_COMPARE_TWICE
1142 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
1143 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
1144 #endif
1145 "movl %[src], %[rseq_scratch0]\n\t"
1146 "movl %[dst], %[rseq_scratch1]\n\t"
1147 "movl %[len], %[rseq_scratch2]\n\t"
1148
1149 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
1150 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
1151 RSEQ_INJECT_ASM(3)
1152 "movl %[expect], %%eax\n\t"
1153 "cmpl %%eax, %[v]\n\t"
1154 "jnz 5f\n\t"
1155 RSEQ_INJECT_ASM(4)
1156 #ifdef RSEQ_COMPARE_TWICE
1157 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 6f)
1158 "movl %[expect], %%eax\n\t"
1159 "cmpl %%eax, %[v]\n\t"
1160 "jnz 7f\n\t"
1161 #endif
1162
1163 "test %[len], %[len]\n\t" \
1164 "jz 333f\n\t" \
1165 "222:\n\t" \
1166 "movb (%[src]), %%al\n\t" \
1167 "movb %%al, (%[dst])\n\t" \
1168 "inc %[src]\n\t" \
1169 "inc %[dst]\n\t" \
1170 "dec %[len]\n\t" \
1171 "jnz 222b\n\t" \
1172 "333:\n\t" \
1173 RSEQ_INJECT_ASM(5)
1174 "movl %[newv], %%eax\n\t"
1175
1176 "movl %%eax, %[v]\n\t"
1177 "2:\n\t"
1178 RSEQ_INJECT_ASM(6)
1179
1180 "movl %[rseq_scratch2], %[len]\n\t"
1181 "movl %[rseq_scratch1], %[dst]\n\t"
1182 "movl %[rseq_scratch0], %[src]\n\t"
1183 RSEQ_ASM_DEFINE_ABORT(4,
1184 "movl %[rseq_scratch2], %[len]\n\t"
1185 "movl %[rseq_scratch1], %[dst]\n\t"
1186 "movl %[rseq_scratch0], %[src]\n\t",
1187 abort)
1188 RSEQ_ASM_DEFINE_CMPFAIL(5,
1189 "movl %[rseq_scratch2], %[len]\n\t"
1190 "movl %[rseq_scratch1], %[dst]\n\t"
1191 "movl %[rseq_scratch0], %[src]\n\t",
1192 cmpfail)
1193 #ifdef RSEQ_COMPARE_TWICE
1194 RSEQ_ASM_DEFINE_CMPFAIL(6,
1195 "movl %[rseq_scratch2], %[len]\n\t"
1196 "movl %[rseq_scratch1], %[dst]\n\t"
1197 "movl %[rseq_scratch0], %[src]\n\t",
1198 error1)
1199 RSEQ_ASM_DEFINE_CMPFAIL(7,
1200 "movl %[rseq_scratch2], %[len]\n\t"
1201 "movl %[rseq_scratch1], %[dst]\n\t"
1202 "movl %[rseq_scratch0], %[src]\n\t",
1203 error2)
1204 #endif
1205 :
1206 : [cpu_id] "r" (cpu),
1207 [rseq_offset] "r" (rseq_offset),
1208
1209 [v] "m" (*v),
1210 [expect] "m" (expect),
1211 [newv] "m" (newv),
1212
1213 [dst] "r" (dst),
1214 [src] "r" (src),
1215 [len] "r" (len),
1216 [rseq_scratch0] "m" (rseq_scratch[0]),
1217 [rseq_scratch1] "m" (rseq_scratch[1]),
1218 [rseq_scratch2] "m" (rseq_scratch[2])
1219 : "memory", "cc", "eax"
1220 RSEQ_INJECT_CLOBBER
1221 : abort, cmpfail
1222 #ifdef RSEQ_COMPARE_TWICE
1223 , error1, error2
1224 #endif
1225 );
1226 rseq_after_asm_goto();
1227 return 0;
1228 abort:
1229 rseq_after_asm_goto();
1230 RSEQ_INJECT_FAILED
1231 return -1;
1232 cmpfail:
1233 rseq_after_asm_goto();
1234 return 1;
1235 #ifdef RSEQ_COMPARE_TWICE
1236 error1:
1237 rseq_after_asm_goto();
1238 rseq_bug("cpu_id comparison failed");
1239 error2:
1240 rseq_after_asm_goto();
1241 rseq_bug("expected value comparison failed");
1242 #endif
1243 }
1244
1245
1246 static inline __attribute__((always_inline))
1247 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
1248 void *dst, void *src, size_t len,
1249 intptr_t newv, int cpu)
1250 {
1251 uint32_t rseq_scratch[3];
1252
1253 RSEQ_INJECT_C(9)
1254
1255 __asm__ __volatile__ goto (
1256 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f)
1257 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
1258 #ifdef RSEQ_COMPARE_TWICE
1259 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
1260 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
1261 #endif
1262 "movl %[src], %[rseq_scratch0]\n\t"
1263 "movl %[dst], %[rseq_scratch1]\n\t"
1264 "movl %[len], %[rseq_scratch2]\n\t"
1265
1266 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_ASM_TP_SEGMENT:RSEQ_CS_OFFSET(%[rseq_offset]))
1267 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 4f)
1268 RSEQ_INJECT_ASM(3)
1269 "movl %[expect], %%eax\n\t"
1270 "cmpl %%eax, %[v]\n\t"
1271 "jnz 5f\n\t"
1272 RSEQ_INJECT_ASM(4)
1273 #ifdef RSEQ_COMPARE_TWICE
1274 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_ASM_TP_SEGMENT:RSEQ_CPU_ID_OFFSET(%[rseq_offset]), 6f)
1275 "movl %[expect], %%eax\n\t"
1276 "cmpl %%eax, %[v]\n\t"
1277 "jnz 7f\n\t"
1278 #endif
1279
1280 "test %[len], %[len]\n\t" \
1281 "jz 333f\n\t" \
1282 "222:\n\t" \
1283 "movb (%[src]), %%al\n\t" \
1284 "movb %%al, (%[dst])\n\t" \
1285 "inc %[src]\n\t" \
1286 "inc %[dst]\n\t" \
1287 "dec %[len]\n\t" \
1288 "jnz 222b\n\t" \
1289 "333:\n\t" \
1290 RSEQ_INJECT_ASM(5)
1291 "lock; addl $0,-128(%%esp)\n\t"
1292 "movl %[newv], %%eax\n\t"
1293
1294 "movl %%eax, %[v]\n\t"
1295 "2:\n\t"
1296 RSEQ_INJECT_ASM(6)
1297
1298 "movl %[rseq_scratch2], %[len]\n\t"
1299 "movl %[rseq_scratch1], %[dst]\n\t"
1300 "movl %[rseq_scratch0], %[src]\n\t"
1301 RSEQ_ASM_DEFINE_ABORT(4,
1302 "movl %[rseq_scratch2], %[len]\n\t"
1303 "movl %[rseq_scratch1], %[dst]\n\t"
1304 "movl %[rseq_scratch0], %[src]\n\t",
1305 abort)
1306 RSEQ_ASM_DEFINE_CMPFAIL(5,
1307 "movl %[rseq_scratch2], %[len]\n\t"
1308 "movl %[rseq_scratch1], %[dst]\n\t"
1309 "movl %[rseq_scratch0], %[src]\n\t",
1310 cmpfail)
1311 #ifdef RSEQ_COMPARE_TWICE
1312 RSEQ_ASM_DEFINE_CMPFAIL(6,
1313 "movl %[rseq_scratch2], %[len]\n\t"
1314 "movl %[rseq_scratch1], %[dst]\n\t"
1315 "movl %[rseq_scratch0], %[src]\n\t",
1316 error1)
1317 RSEQ_ASM_DEFINE_CMPFAIL(7,
1318 "movl %[rseq_scratch2], %[len]\n\t"
1319 "movl %[rseq_scratch1], %[dst]\n\t"
1320 "movl %[rseq_scratch0], %[src]\n\t",
1321 error2)
1322 #endif
1323 :
1324 : [cpu_id] "r" (cpu),
1325 [rseq_offset] "r" (rseq_offset),
1326
1327 [v] "m" (*v),
1328 [expect] "m" (expect),
1329 [newv] "m" (newv),
1330
1331 [dst] "r" (dst),
1332 [src] "r" (src),
1333 [len] "r" (len),
1334 [rseq_scratch0] "m" (rseq_scratch[0]),
1335 [rseq_scratch1] "m" (rseq_scratch[1]),
1336 [rseq_scratch2] "m" (rseq_scratch[2])
1337 : "memory", "cc", "eax"
1338 RSEQ_INJECT_CLOBBER
1339 : abort, cmpfail
1340 #ifdef RSEQ_COMPARE_TWICE
1341 , error1, error2
1342 #endif
1343 );
1344 rseq_after_asm_goto();
1345 return 0;
1346 abort:
1347 rseq_after_asm_goto();
1348 RSEQ_INJECT_FAILED
1349 return -1;
1350 cmpfail:
1351 rseq_after_asm_goto();
1352 return 1;
1353 #ifdef RSEQ_COMPARE_TWICE
1354 error1:
1355 rseq_after_asm_goto();
1356 rseq_bug("cpu_id comparison failed");
1357 error2:
1358 rseq_after_asm_goto();
1359 rseq_bug("expected value comparison failed");
1360 #endif
1361 }
1362
1363 #endif
1364
1365 #endif