rseq-x86.h 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
  2. /*
  3. * rseq-x86.h
  4. *
  5. * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  6. */
  7. #include <stdint.h>
  8. #define RSEQ_SIG 0x53053053
  9. #ifdef __x86_64__
  10. #define rseq_smp_mb() \
  11. __asm__ __volatile__ ("lock; addl $0,-128(%%rsp)" ::: "memory", "cc")
  12. #define rseq_smp_rmb() rseq_barrier()
  13. #define rseq_smp_wmb() rseq_barrier()
  14. #define rseq_smp_load_acquire(p) \
  15. __extension__ ({ \
  16. __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
  17. rseq_barrier(); \
  18. ____p1; \
  19. })
  20. #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
  21. #define rseq_smp_store_release(p, v) \
  22. do { \
  23. rseq_barrier(); \
  24. RSEQ_WRITE_ONCE(*p, v); \
  25. } while (0)
  26. #ifdef RSEQ_SKIP_FASTPATH
  27. #include "rseq-skip.h"
  28. #else /* !RSEQ_SKIP_FASTPATH */
  29. #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
  30. start_ip, post_commit_offset, abort_ip) \
  31. ".pushsection __rseq_table, \"aw\"\n\t" \
  32. ".balign 32\n\t" \
  33. __rseq_str(label) ":\n\t" \
  34. ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
  35. ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
  36. ".popsection\n\t"
  37. #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
  38. __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
  39. (post_commit_ip - start_ip), abort_ip)
  40. #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
  41. RSEQ_INJECT_ASM(1) \
  42. "leaq " __rseq_str(cs_label) "(%%rip), %%rax\n\t" \
  43. "movq %%rax, %[" __rseq_str(rseq_cs) "]\n\t" \
  44. __rseq_str(label) ":\n\t"
  45. #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
  46. RSEQ_INJECT_ASM(2) \
  47. "cmpl %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \
  48. "jnz " __rseq_str(label) "\n\t"
  49. #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
  50. ".pushsection __rseq_failure, \"ax\"\n\t" \
  51. /* Disassembler-friendly signature: nopl <sig>(%rip). */\
  52. ".byte 0x0f, 0x1f, 0x05\n\t" \
  53. ".long " __rseq_str(RSEQ_SIG) "\n\t" \
  54. __rseq_str(label) ":\n\t" \
  55. teardown \
  56. "jmp %l[" __rseq_str(abort_label) "]\n\t" \
  57. ".popsection\n\t"
  58. #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
  59. ".pushsection __rseq_failure, \"ax\"\n\t" \
  60. __rseq_str(label) ":\n\t" \
  61. teardown \
  62. "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
  63. ".popsection\n\t"
  64. static inline __attribute__((always_inline))
  65. int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
  66. {
  67. RSEQ_INJECT_C(9)
  68. __asm__ __volatile__ goto (
  69. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  70. /* Start rseq by storing table entry pointer into rseq_cs. */
  71. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  72. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  73. RSEQ_INJECT_ASM(3)
  74. "cmpq %[v], %[expect]\n\t"
  75. "jnz %l[cmpfail]\n\t"
  76. RSEQ_INJECT_ASM(4)
  77. #ifdef RSEQ_COMPARE_TWICE
  78. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  79. "cmpq %[v], %[expect]\n\t"
  80. "jnz %l[error2]\n\t"
  81. #endif
  82. /* final store */
  83. "movq %[newv], %[v]\n\t"
  84. "2:\n\t"
  85. RSEQ_INJECT_ASM(5)
  86. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  87. : /* gcc asm goto does not allow outputs */
  88. : [cpu_id] "r" (cpu),
  89. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  90. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  91. [v] "m" (*v),
  92. [expect] "r" (expect),
  93. [newv] "r" (newv)
  94. : "memory", "cc", "rax"
  95. RSEQ_INJECT_CLOBBER
  96. : abort, cmpfail
  97. #ifdef RSEQ_COMPARE_TWICE
  98. , error1, error2
  99. #endif
  100. );
  101. return 0;
  102. abort:
  103. RSEQ_INJECT_FAILED
  104. return -1;
  105. cmpfail:
  106. return 1;
  107. #ifdef RSEQ_COMPARE_TWICE
  108. error1:
  109. rseq_bug("cpu_id comparison failed");
  110. error2:
  111. rseq_bug("expected value comparison failed");
  112. #endif
  113. }
  114. /*
  115. * Compare @v against @expectnot. When it does _not_ match, load @v
  116. * into @load, and store the content of *@v + voffp into @v.
  117. */
  118. static inline __attribute__((always_inline))
  119. int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
  120. off_t voffp, intptr_t *load, int cpu)
  121. {
  122. RSEQ_INJECT_C(9)
  123. __asm__ __volatile__ goto (
  124. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  125. /* Start rseq by storing table entry pointer into rseq_cs. */
  126. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  127. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  128. RSEQ_INJECT_ASM(3)
  129. "movq %[v], %%rbx\n\t"
  130. "cmpq %%rbx, %[expectnot]\n\t"
  131. "je %l[cmpfail]\n\t"
  132. RSEQ_INJECT_ASM(4)
  133. #ifdef RSEQ_COMPARE_TWICE
  134. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  135. "movq %[v], %%rbx\n\t"
  136. "cmpq %%rbx, %[expectnot]\n\t"
  137. "je %l[error2]\n\t"
  138. #endif
  139. "movq %%rbx, %[load]\n\t"
  140. "addq %[voffp], %%rbx\n\t"
  141. "movq (%%rbx), %%rbx\n\t"
  142. /* final store */
  143. "movq %%rbx, %[v]\n\t"
  144. "2:\n\t"
  145. RSEQ_INJECT_ASM(5)
  146. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  147. : /* gcc asm goto does not allow outputs */
  148. : [cpu_id] "r" (cpu),
  149. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  150. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  151. /* final store input */
  152. [v] "m" (*v),
  153. [expectnot] "r" (expectnot),
  154. [voffp] "er" (voffp),
  155. [load] "m" (*load)
  156. : "memory", "cc", "rax", "rbx"
  157. RSEQ_INJECT_CLOBBER
  158. : abort, cmpfail
  159. #ifdef RSEQ_COMPARE_TWICE
  160. , error1, error2
  161. #endif
  162. );
  163. return 0;
  164. abort:
  165. RSEQ_INJECT_FAILED
  166. return -1;
  167. cmpfail:
  168. return 1;
  169. #ifdef RSEQ_COMPARE_TWICE
  170. error1:
  171. rseq_bug("cpu_id comparison failed");
  172. error2:
  173. rseq_bug("expected value comparison failed");
  174. #endif
  175. }
  176. static inline __attribute__((always_inline))
  177. int rseq_addv(intptr_t *v, intptr_t count, int cpu)
  178. {
  179. RSEQ_INJECT_C(9)
  180. __asm__ __volatile__ goto (
  181. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  182. /* Start rseq by storing table entry pointer into rseq_cs. */
  183. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  184. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  185. RSEQ_INJECT_ASM(3)
  186. #ifdef RSEQ_COMPARE_TWICE
  187. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  188. #endif
  189. /* final store */
  190. "addq %[count], %[v]\n\t"
  191. "2:\n\t"
  192. RSEQ_INJECT_ASM(4)
  193. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  194. : /* gcc asm goto does not allow outputs */
  195. : [cpu_id] "r" (cpu),
  196. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  197. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  198. /* final store input */
  199. [v] "m" (*v),
  200. [count] "er" (count)
  201. : "memory", "cc", "rax"
  202. RSEQ_INJECT_CLOBBER
  203. : abort
  204. #ifdef RSEQ_COMPARE_TWICE
  205. , error1
  206. #endif
  207. );
  208. return 0;
  209. abort:
  210. RSEQ_INJECT_FAILED
  211. return -1;
  212. #ifdef RSEQ_COMPARE_TWICE
  213. error1:
  214. rseq_bug("cpu_id comparison failed");
  215. #endif
  216. }
  217. static inline __attribute__((always_inline))
  218. int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
  219. intptr_t *v2, intptr_t newv2,
  220. intptr_t newv, int cpu)
  221. {
  222. RSEQ_INJECT_C(9)
  223. __asm__ __volatile__ goto (
  224. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  225. /* Start rseq by storing table entry pointer into rseq_cs. */
  226. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  227. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  228. RSEQ_INJECT_ASM(3)
  229. "cmpq %[v], %[expect]\n\t"
  230. "jnz %l[cmpfail]\n\t"
  231. RSEQ_INJECT_ASM(4)
  232. #ifdef RSEQ_COMPARE_TWICE
  233. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  234. "cmpq %[v], %[expect]\n\t"
  235. "jnz %l[error2]\n\t"
  236. #endif
  237. /* try store */
  238. "movq %[newv2], %[v2]\n\t"
  239. RSEQ_INJECT_ASM(5)
  240. /* final store */
  241. "movq %[newv], %[v]\n\t"
  242. "2:\n\t"
  243. RSEQ_INJECT_ASM(6)
  244. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  245. : /* gcc asm goto does not allow outputs */
  246. : [cpu_id] "r" (cpu),
  247. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  248. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  249. /* try store input */
  250. [v2] "m" (*v2),
  251. [newv2] "r" (newv2),
  252. /* final store input */
  253. [v] "m" (*v),
  254. [expect] "r" (expect),
  255. [newv] "r" (newv)
  256. : "memory", "cc", "rax"
  257. RSEQ_INJECT_CLOBBER
  258. : abort, cmpfail
  259. #ifdef RSEQ_COMPARE_TWICE
  260. , error1, error2
  261. #endif
  262. );
  263. return 0;
  264. abort:
  265. RSEQ_INJECT_FAILED
  266. return -1;
  267. cmpfail:
  268. return 1;
  269. #ifdef RSEQ_COMPARE_TWICE
  270. error1:
  271. rseq_bug("cpu_id comparison failed");
  272. error2:
  273. rseq_bug("expected value comparison failed");
  274. #endif
  275. }
  276. /* x86-64 is TSO. */
  277. static inline __attribute__((always_inline))
  278. int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
  279. intptr_t *v2, intptr_t newv2,
  280. intptr_t newv, int cpu)
  281. {
  282. return rseq_cmpeqv_trystorev_storev(v, expect, v2, newv2, newv, cpu);
  283. }
  284. static inline __attribute__((always_inline))
  285. int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
  286. intptr_t *v2, intptr_t expect2,
  287. intptr_t newv, int cpu)
  288. {
  289. RSEQ_INJECT_C(9)
  290. __asm__ __volatile__ goto (
  291. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  292. /* Start rseq by storing table entry pointer into rseq_cs. */
  293. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  294. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  295. RSEQ_INJECT_ASM(3)
  296. "cmpq %[v], %[expect]\n\t"
  297. "jnz %l[cmpfail]\n\t"
  298. RSEQ_INJECT_ASM(4)
  299. "cmpq %[v2], %[expect2]\n\t"
  300. "jnz %l[cmpfail]\n\t"
  301. RSEQ_INJECT_ASM(5)
  302. #ifdef RSEQ_COMPARE_TWICE
  303. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  304. "cmpq %[v], %[expect]\n\t"
  305. "jnz %l[error2]\n\t"
  306. "cmpq %[v2], %[expect2]\n\t"
  307. "jnz %l[error3]\n\t"
  308. #endif
  309. /* final store */
  310. "movq %[newv], %[v]\n\t"
  311. "2:\n\t"
  312. RSEQ_INJECT_ASM(6)
  313. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  314. : /* gcc asm goto does not allow outputs */
  315. : [cpu_id] "r" (cpu),
  316. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  317. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  318. /* cmp2 input */
  319. [v2] "m" (*v2),
  320. [expect2] "r" (expect2),
  321. /* final store input */
  322. [v] "m" (*v),
  323. [expect] "r" (expect),
  324. [newv] "r" (newv)
  325. : "memory", "cc", "rax"
  326. RSEQ_INJECT_CLOBBER
  327. : abort, cmpfail
  328. #ifdef RSEQ_COMPARE_TWICE
  329. , error1, error2, error3
  330. #endif
  331. );
  332. return 0;
  333. abort:
  334. RSEQ_INJECT_FAILED
  335. return -1;
  336. cmpfail:
  337. return 1;
  338. #ifdef RSEQ_COMPARE_TWICE
  339. error1:
  340. rseq_bug("cpu_id comparison failed");
  341. error2:
  342. rseq_bug("1st expected value comparison failed");
  343. error3:
  344. rseq_bug("2nd expected value comparison failed");
  345. #endif
  346. }
  347. static inline __attribute__((always_inline))
  348. int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
  349. void *dst, void *src, size_t len,
  350. intptr_t newv, int cpu)
  351. {
  352. uint64_t rseq_scratch[3];
  353. RSEQ_INJECT_C(9)
  354. __asm__ __volatile__ goto (
  355. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  356. "movq %[src], %[rseq_scratch0]\n\t"
  357. "movq %[dst], %[rseq_scratch1]\n\t"
  358. "movq %[len], %[rseq_scratch2]\n\t"
  359. /* Start rseq by storing table entry pointer into rseq_cs. */
  360. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  361. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  362. RSEQ_INJECT_ASM(3)
  363. "cmpq %[v], %[expect]\n\t"
  364. "jnz 5f\n\t"
  365. RSEQ_INJECT_ASM(4)
  366. #ifdef RSEQ_COMPARE_TWICE
  367. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
  368. "cmpq %[v], %[expect]\n\t"
  369. "jnz 7f\n\t"
  370. #endif
  371. /* try memcpy */
  372. "test %[len], %[len]\n\t" \
  373. "jz 333f\n\t" \
  374. "222:\n\t" \
  375. "movb (%[src]), %%al\n\t" \
  376. "movb %%al, (%[dst])\n\t" \
  377. "inc %[src]\n\t" \
  378. "inc %[dst]\n\t" \
  379. "dec %[len]\n\t" \
  380. "jnz 222b\n\t" \
  381. "333:\n\t" \
  382. RSEQ_INJECT_ASM(5)
  383. /* final store */
  384. "movq %[newv], %[v]\n\t"
  385. "2:\n\t"
  386. RSEQ_INJECT_ASM(6)
  387. /* teardown */
  388. "movq %[rseq_scratch2], %[len]\n\t"
  389. "movq %[rseq_scratch1], %[dst]\n\t"
  390. "movq %[rseq_scratch0], %[src]\n\t"
  391. RSEQ_ASM_DEFINE_ABORT(4,
  392. "movq %[rseq_scratch2], %[len]\n\t"
  393. "movq %[rseq_scratch1], %[dst]\n\t"
  394. "movq %[rseq_scratch0], %[src]\n\t",
  395. abort)
  396. RSEQ_ASM_DEFINE_CMPFAIL(5,
  397. "movq %[rseq_scratch2], %[len]\n\t"
  398. "movq %[rseq_scratch1], %[dst]\n\t"
  399. "movq %[rseq_scratch0], %[src]\n\t",
  400. cmpfail)
  401. #ifdef RSEQ_COMPARE_TWICE
  402. RSEQ_ASM_DEFINE_CMPFAIL(6,
  403. "movq %[rseq_scratch2], %[len]\n\t"
  404. "movq %[rseq_scratch1], %[dst]\n\t"
  405. "movq %[rseq_scratch0], %[src]\n\t",
  406. error1)
  407. RSEQ_ASM_DEFINE_CMPFAIL(7,
  408. "movq %[rseq_scratch2], %[len]\n\t"
  409. "movq %[rseq_scratch1], %[dst]\n\t"
  410. "movq %[rseq_scratch0], %[src]\n\t",
  411. error2)
  412. #endif
  413. : /* gcc asm goto does not allow outputs */
  414. : [cpu_id] "r" (cpu),
  415. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  416. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  417. /* final store input */
  418. [v] "m" (*v),
  419. [expect] "r" (expect),
  420. [newv] "r" (newv),
  421. /* try memcpy input */
  422. [dst] "r" (dst),
  423. [src] "r" (src),
  424. [len] "r" (len),
  425. [rseq_scratch0] "m" (rseq_scratch[0]),
  426. [rseq_scratch1] "m" (rseq_scratch[1]),
  427. [rseq_scratch2] "m" (rseq_scratch[2])
  428. : "memory", "cc", "rax"
  429. RSEQ_INJECT_CLOBBER
  430. : abort, cmpfail
  431. #ifdef RSEQ_COMPARE_TWICE
  432. , error1, error2
  433. #endif
  434. );
  435. return 0;
  436. abort:
  437. RSEQ_INJECT_FAILED
  438. return -1;
  439. cmpfail:
  440. return 1;
  441. #ifdef RSEQ_COMPARE_TWICE
  442. error1:
  443. rseq_bug("cpu_id comparison failed");
  444. error2:
  445. rseq_bug("expected value comparison failed");
  446. #endif
  447. }
  448. /* x86-64 is TSO. */
  449. static inline __attribute__((always_inline))
  450. int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
  451. void *dst, void *src, size_t len,
  452. intptr_t newv, int cpu)
  453. {
  454. return rseq_cmpeqv_trymemcpy_storev(v, expect, dst, src, len,
  455. newv, cpu);
  456. }
  457. #endif /* !RSEQ_SKIP_FASTPATH */
  458. #elif __i386__
  459. #define rseq_smp_mb() \
  460. __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
  461. #define rseq_smp_rmb() \
  462. __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
  463. #define rseq_smp_wmb() \
  464. __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
  465. #define rseq_smp_load_acquire(p) \
  466. __extension__ ({ \
  467. __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
  468. rseq_smp_mb(); \
  469. ____p1; \
  470. })
  471. #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
  472. #define rseq_smp_store_release(p, v) \
  473. do { \
  474. rseq_smp_mb(); \
  475. RSEQ_WRITE_ONCE(*p, v); \
  476. } while (0)
  477. #ifdef RSEQ_SKIP_FASTPATH
  478. #include "rseq-skip.h"
  479. #else /* !RSEQ_SKIP_FASTPATH */
  480. /*
  481. * Use eax as scratch register and take memory operands as input to
  482. * lessen register pressure. Especially needed when compiling in O0.
  483. */
  484. #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
  485. start_ip, post_commit_offset, abort_ip) \
  486. ".pushsection __rseq_table, \"aw\"\n\t" \
  487. ".balign 32\n\t" \
  488. __rseq_str(label) ":\n\t" \
  489. ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
  490. ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
  491. ".popsection\n\t"
  492. #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
  493. __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
  494. (post_commit_ip - start_ip), abort_ip)
  495. #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
  496. RSEQ_INJECT_ASM(1) \
  497. "movl $" __rseq_str(cs_label) ", %[rseq_cs]\n\t" \
  498. __rseq_str(label) ":\n\t"
  499. #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
  500. RSEQ_INJECT_ASM(2) \
  501. "cmpl %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \
  502. "jnz " __rseq_str(label) "\n\t"
  503. #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
  504. ".pushsection __rseq_failure, \"ax\"\n\t" \
  505. /* Disassembler-friendly signature: nopl <sig>. */ \
  506. ".byte 0x0f, 0x1f, 0x05\n\t" \
  507. ".long " __rseq_str(RSEQ_SIG) "\n\t" \
  508. __rseq_str(label) ":\n\t" \
  509. teardown \
  510. "jmp %l[" __rseq_str(abort_label) "]\n\t" \
  511. ".popsection\n\t"
  512. #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
  513. ".pushsection __rseq_failure, \"ax\"\n\t" \
  514. __rseq_str(label) ":\n\t" \
  515. teardown \
  516. "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
  517. ".popsection\n\t"
  518. static inline __attribute__((always_inline))
  519. int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
  520. {
  521. RSEQ_INJECT_C(9)
  522. __asm__ __volatile__ goto (
  523. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  524. /* Start rseq by storing table entry pointer into rseq_cs. */
  525. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  526. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  527. RSEQ_INJECT_ASM(3)
  528. "cmpl %[v], %[expect]\n\t"
  529. "jnz %l[cmpfail]\n\t"
  530. RSEQ_INJECT_ASM(4)
  531. #ifdef RSEQ_COMPARE_TWICE
  532. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  533. "cmpl %[v], %[expect]\n\t"
  534. "jnz %l[error2]\n\t"
  535. #endif
  536. /* final store */
  537. "movl %[newv], %[v]\n\t"
  538. "2:\n\t"
  539. RSEQ_INJECT_ASM(5)
  540. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  541. : /* gcc asm goto does not allow outputs */
  542. : [cpu_id] "r" (cpu),
  543. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  544. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  545. [v] "m" (*v),
  546. [expect] "r" (expect),
  547. [newv] "r" (newv)
  548. : "memory", "cc", "eax"
  549. RSEQ_INJECT_CLOBBER
  550. : abort, cmpfail
  551. #ifdef RSEQ_COMPARE_TWICE
  552. , error1, error2
  553. #endif
  554. );
  555. return 0;
  556. abort:
  557. RSEQ_INJECT_FAILED
  558. return -1;
  559. cmpfail:
  560. return 1;
  561. #ifdef RSEQ_COMPARE_TWICE
  562. error1:
  563. rseq_bug("cpu_id comparison failed");
  564. error2:
  565. rseq_bug("expected value comparison failed");
  566. #endif
  567. }
  568. /*
  569. * Compare @v against @expectnot. When it does _not_ match, load @v
  570. * into @load, and store the content of *@v + voffp into @v.
  571. */
  572. static inline __attribute__((always_inline))
  573. int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
  574. off_t voffp, intptr_t *load, int cpu)
  575. {
  576. RSEQ_INJECT_C(9)
  577. __asm__ __volatile__ goto (
  578. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  579. /* Start rseq by storing table entry pointer into rseq_cs. */
  580. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  581. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  582. RSEQ_INJECT_ASM(3)
  583. "movl %[v], %%ebx\n\t"
  584. "cmpl %%ebx, %[expectnot]\n\t"
  585. "je %l[cmpfail]\n\t"
  586. RSEQ_INJECT_ASM(4)
  587. #ifdef RSEQ_COMPARE_TWICE
  588. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  589. "movl %[v], %%ebx\n\t"
  590. "cmpl %%ebx, %[expectnot]\n\t"
  591. "je %l[error2]\n\t"
  592. #endif
  593. "movl %%ebx, %[load]\n\t"
  594. "addl %[voffp], %%ebx\n\t"
  595. "movl (%%ebx), %%ebx\n\t"
  596. /* final store */
  597. "movl %%ebx, %[v]\n\t"
  598. "2:\n\t"
  599. RSEQ_INJECT_ASM(5)
  600. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  601. : /* gcc asm goto does not allow outputs */
  602. : [cpu_id] "r" (cpu),
  603. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  604. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  605. /* final store input */
  606. [v] "m" (*v),
  607. [expectnot] "r" (expectnot),
  608. [voffp] "ir" (voffp),
  609. [load] "m" (*load)
  610. : "memory", "cc", "eax", "ebx"
  611. RSEQ_INJECT_CLOBBER
  612. : abort, cmpfail
  613. #ifdef RSEQ_COMPARE_TWICE
  614. , error1, error2
  615. #endif
  616. );
  617. return 0;
  618. abort:
  619. RSEQ_INJECT_FAILED
  620. return -1;
  621. cmpfail:
  622. return 1;
  623. #ifdef RSEQ_COMPARE_TWICE
  624. error1:
  625. rseq_bug("cpu_id comparison failed");
  626. error2:
  627. rseq_bug("expected value comparison failed");
  628. #endif
  629. }
  630. static inline __attribute__((always_inline))
  631. int rseq_addv(intptr_t *v, intptr_t count, int cpu)
  632. {
  633. RSEQ_INJECT_C(9)
  634. __asm__ __volatile__ goto (
  635. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  636. /* Start rseq by storing table entry pointer into rseq_cs. */
  637. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  638. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  639. RSEQ_INJECT_ASM(3)
  640. #ifdef RSEQ_COMPARE_TWICE
  641. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  642. #endif
  643. /* final store */
  644. "addl %[count], %[v]\n\t"
  645. "2:\n\t"
  646. RSEQ_INJECT_ASM(4)
  647. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  648. : /* gcc asm goto does not allow outputs */
  649. : [cpu_id] "r" (cpu),
  650. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  651. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  652. /* final store input */
  653. [v] "m" (*v),
  654. [count] "ir" (count)
  655. : "memory", "cc", "eax"
  656. RSEQ_INJECT_CLOBBER
  657. : abort
  658. #ifdef RSEQ_COMPARE_TWICE
  659. , error1
  660. #endif
  661. );
  662. return 0;
  663. abort:
  664. RSEQ_INJECT_FAILED
  665. return -1;
  666. #ifdef RSEQ_COMPARE_TWICE
  667. error1:
  668. rseq_bug("cpu_id comparison failed");
  669. #endif
  670. }
  671. static inline __attribute__((always_inline))
  672. int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
  673. intptr_t *v2, intptr_t newv2,
  674. intptr_t newv, int cpu)
  675. {
  676. RSEQ_INJECT_C(9)
  677. __asm__ __volatile__ goto (
  678. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  679. /* Start rseq by storing table entry pointer into rseq_cs. */
  680. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  681. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  682. RSEQ_INJECT_ASM(3)
  683. "cmpl %[v], %[expect]\n\t"
  684. "jnz %l[cmpfail]\n\t"
  685. RSEQ_INJECT_ASM(4)
  686. #ifdef RSEQ_COMPARE_TWICE
  687. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  688. "cmpl %[v], %[expect]\n\t"
  689. "jnz %l[error2]\n\t"
  690. #endif
  691. /* try store */
  692. "movl %[newv2], %%eax\n\t"
  693. "movl %%eax, %[v2]\n\t"
  694. RSEQ_INJECT_ASM(5)
  695. /* final store */
  696. "movl %[newv], %[v]\n\t"
  697. "2:\n\t"
  698. RSEQ_INJECT_ASM(6)
  699. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  700. : /* gcc asm goto does not allow outputs */
  701. : [cpu_id] "r" (cpu),
  702. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  703. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  704. /* try store input */
  705. [v2] "m" (*v2),
  706. [newv2] "m" (newv2),
  707. /* final store input */
  708. [v] "m" (*v),
  709. [expect] "r" (expect),
  710. [newv] "r" (newv)
  711. : "memory", "cc", "eax"
  712. RSEQ_INJECT_CLOBBER
  713. : abort, cmpfail
  714. #ifdef RSEQ_COMPARE_TWICE
  715. , error1, error2
  716. #endif
  717. );
  718. return 0;
  719. abort:
  720. RSEQ_INJECT_FAILED
  721. return -1;
  722. cmpfail:
  723. return 1;
  724. #ifdef RSEQ_COMPARE_TWICE
  725. error1:
  726. rseq_bug("cpu_id comparison failed");
  727. error2:
  728. rseq_bug("expected value comparison failed");
  729. #endif
  730. }
  731. static inline __attribute__((always_inline))
  732. int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
  733. intptr_t *v2, intptr_t newv2,
  734. intptr_t newv, int cpu)
  735. {
  736. RSEQ_INJECT_C(9)
  737. __asm__ __volatile__ goto (
  738. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  739. /* Start rseq by storing table entry pointer into rseq_cs. */
  740. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  741. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  742. RSEQ_INJECT_ASM(3)
  743. "movl %[expect], %%eax\n\t"
  744. "cmpl %[v], %%eax\n\t"
  745. "jnz %l[cmpfail]\n\t"
  746. RSEQ_INJECT_ASM(4)
  747. #ifdef RSEQ_COMPARE_TWICE
  748. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  749. "movl %[expect], %%eax\n\t"
  750. "cmpl %[v], %%eax\n\t"
  751. "jnz %l[error2]\n\t"
  752. #endif
  753. /* try store */
  754. "movl %[newv2], %[v2]\n\t"
  755. RSEQ_INJECT_ASM(5)
  756. "lock; addl $0,-128(%%esp)\n\t"
  757. /* final store */
  758. "movl %[newv], %[v]\n\t"
  759. "2:\n\t"
  760. RSEQ_INJECT_ASM(6)
  761. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  762. : /* gcc asm goto does not allow outputs */
  763. : [cpu_id] "r" (cpu),
  764. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  765. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  766. /* try store input */
  767. [v2] "m" (*v2),
  768. [newv2] "r" (newv2),
  769. /* final store input */
  770. [v] "m" (*v),
  771. [expect] "m" (expect),
  772. [newv] "r" (newv)
  773. : "memory", "cc", "eax"
  774. RSEQ_INJECT_CLOBBER
  775. : abort, cmpfail
  776. #ifdef RSEQ_COMPARE_TWICE
  777. , error1, error2
  778. #endif
  779. );
  780. return 0;
  781. abort:
  782. RSEQ_INJECT_FAILED
  783. return -1;
  784. cmpfail:
  785. return 1;
  786. #ifdef RSEQ_COMPARE_TWICE
  787. error1:
  788. rseq_bug("cpu_id comparison failed");
  789. error2:
  790. rseq_bug("expected value comparison failed");
  791. #endif
  792. }
  793. static inline __attribute__((always_inline))
  794. int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
  795. intptr_t *v2, intptr_t expect2,
  796. intptr_t newv, int cpu)
  797. {
  798. RSEQ_INJECT_C(9)
  799. __asm__ __volatile__ goto (
  800. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  801. /* Start rseq by storing table entry pointer into rseq_cs. */
  802. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  803. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  804. RSEQ_INJECT_ASM(3)
  805. "cmpl %[v], %[expect]\n\t"
  806. "jnz %l[cmpfail]\n\t"
  807. RSEQ_INJECT_ASM(4)
  808. "cmpl %[expect2], %[v2]\n\t"
  809. "jnz %l[cmpfail]\n\t"
  810. RSEQ_INJECT_ASM(5)
  811. #ifdef RSEQ_COMPARE_TWICE
  812. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  813. "cmpl %[v], %[expect]\n\t"
  814. "jnz %l[error2]\n\t"
  815. "cmpl %[expect2], %[v2]\n\t"
  816. "jnz %l[error3]\n\t"
  817. #endif
  818. "movl %[newv], %%eax\n\t"
  819. /* final store */
  820. "movl %%eax, %[v]\n\t"
  821. "2:\n\t"
  822. RSEQ_INJECT_ASM(6)
  823. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  824. : /* gcc asm goto does not allow outputs */
  825. : [cpu_id] "r" (cpu),
  826. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  827. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  828. /* cmp2 input */
  829. [v2] "m" (*v2),
  830. [expect2] "r" (expect2),
  831. /* final store input */
  832. [v] "m" (*v),
  833. [expect] "r" (expect),
  834. [newv] "m" (newv)
  835. : "memory", "cc", "eax"
  836. RSEQ_INJECT_CLOBBER
  837. : abort, cmpfail
  838. #ifdef RSEQ_COMPARE_TWICE
  839. , error1, error2, error3
  840. #endif
  841. );
  842. return 0;
  843. abort:
  844. RSEQ_INJECT_FAILED
  845. return -1;
  846. cmpfail:
  847. return 1;
  848. #ifdef RSEQ_COMPARE_TWICE
  849. error1:
  850. rseq_bug("cpu_id comparison failed");
  851. error2:
  852. rseq_bug("1st expected value comparison failed");
  853. error3:
  854. rseq_bug("2nd expected value comparison failed");
  855. #endif
  856. }
  857. /* TODO: implement a faster memcpy. */
  858. static inline __attribute__((always_inline))
  859. int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
  860. void *dst, void *src, size_t len,
  861. intptr_t newv, int cpu)
  862. {
  863. uint32_t rseq_scratch[3];
  864. RSEQ_INJECT_C(9)
  865. __asm__ __volatile__ goto (
  866. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  867. "movl %[src], %[rseq_scratch0]\n\t"
  868. "movl %[dst], %[rseq_scratch1]\n\t"
  869. "movl %[len], %[rseq_scratch2]\n\t"
  870. /* Start rseq by storing table entry pointer into rseq_cs. */
  871. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  872. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  873. RSEQ_INJECT_ASM(3)
  874. "movl %[expect], %%eax\n\t"
  875. "cmpl %%eax, %[v]\n\t"
  876. "jnz 5f\n\t"
  877. RSEQ_INJECT_ASM(4)
  878. #ifdef RSEQ_COMPARE_TWICE
  879. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
  880. "movl %[expect], %%eax\n\t"
  881. "cmpl %%eax, %[v]\n\t"
  882. "jnz 7f\n\t"
  883. #endif
  884. /* try memcpy */
  885. "test %[len], %[len]\n\t" \
  886. "jz 333f\n\t" \
  887. "222:\n\t" \
  888. "movb (%[src]), %%al\n\t" \
  889. "movb %%al, (%[dst])\n\t" \
  890. "inc %[src]\n\t" \
  891. "inc %[dst]\n\t" \
  892. "dec %[len]\n\t" \
  893. "jnz 222b\n\t" \
  894. "333:\n\t" \
  895. RSEQ_INJECT_ASM(5)
  896. "movl %[newv], %%eax\n\t"
  897. /* final store */
  898. "movl %%eax, %[v]\n\t"
  899. "2:\n\t"
  900. RSEQ_INJECT_ASM(6)
  901. /* teardown */
  902. "movl %[rseq_scratch2], %[len]\n\t"
  903. "movl %[rseq_scratch1], %[dst]\n\t"
  904. "movl %[rseq_scratch0], %[src]\n\t"
  905. RSEQ_ASM_DEFINE_ABORT(4,
  906. "movl %[rseq_scratch2], %[len]\n\t"
  907. "movl %[rseq_scratch1], %[dst]\n\t"
  908. "movl %[rseq_scratch0], %[src]\n\t",
  909. abort)
  910. RSEQ_ASM_DEFINE_CMPFAIL(5,
  911. "movl %[rseq_scratch2], %[len]\n\t"
  912. "movl %[rseq_scratch1], %[dst]\n\t"
  913. "movl %[rseq_scratch0], %[src]\n\t",
  914. cmpfail)
  915. #ifdef RSEQ_COMPARE_TWICE
  916. RSEQ_ASM_DEFINE_CMPFAIL(6,
  917. "movl %[rseq_scratch2], %[len]\n\t"
  918. "movl %[rseq_scratch1], %[dst]\n\t"
  919. "movl %[rseq_scratch0], %[src]\n\t",
  920. error1)
  921. RSEQ_ASM_DEFINE_CMPFAIL(7,
  922. "movl %[rseq_scratch2], %[len]\n\t"
  923. "movl %[rseq_scratch1], %[dst]\n\t"
  924. "movl %[rseq_scratch0], %[src]\n\t",
  925. error2)
  926. #endif
  927. : /* gcc asm goto does not allow outputs */
  928. : [cpu_id] "r" (cpu),
  929. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  930. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  931. /* final store input */
  932. [v] "m" (*v),
  933. [expect] "m" (expect),
  934. [newv] "m" (newv),
  935. /* try memcpy input */
  936. [dst] "r" (dst),
  937. [src] "r" (src),
  938. [len] "r" (len),
  939. [rseq_scratch0] "m" (rseq_scratch[0]),
  940. [rseq_scratch1] "m" (rseq_scratch[1]),
  941. [rseq_scratch2] "m" (rseq_scratch[2])
  942. : "memory", "cc", "eax"
  943. RSEQ_INJECT_CLOBBER
  944. : abort, cmpfail
  945. #ifdef RSEQ_COMPARE_TWICE
  946. , error1, error2
  947. #endif
  948. );
  949. return 0;
  950. abort:
  951. RSEQ_INJECT_FAILED
  952. return -1;
  953. cmpfail:
  954. return 1;
  955. #ifdef RSEQ_COMPARE_TWICE
  956. error1:
  957. rseq_bug("cpu_id comparison failed");
  958. error2:
  959. rseq_bug("expected value comparison failed");
  960. #endif
  961. }
  962. /* TODO: implement a faster memcpy. */
  963. static inline __attribute__((always_inline))
  964. int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
  965. void *dst, void *src, size_t len,
  966. intptr_t newv, int cpu)
  967. {
  968. uint32_t rseq_scratch[3];
  969. RSEQ_INJECT_C(9)
  970. __asm__ __volatile__ goto (
  971. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  972. "movl %[src], %[rseq_scratch0]\n\t"
  973. "movl %[dst], %[rseq_scratch1]\n\t"
  974. "movl %[len], %[rseq_scratch2]\n\t"
  975. /* Start rseq by storing table entry pointer into rseq_cs. */
  976. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  977. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  978. RSEQ_INJECT_ASM(3)
  979. "movl %[expect], %%eax\n\t"
  980. "cmpl %%eax, %[v]\n\t"
  981. "jnz 5f\n\t"
  982. RSEQ_INJECT_ASM(4)
  983. #ifdef RSEQ_COMPARE_TWICE
  984. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
  985. "movl %[expect], %%eax\n\t"
  986. "cmpl %%eax, %[v]\n\t"
  987. "jnz 7f\n\t"
  988. #endif
  989. /* try memcpy */
  990. "test %[len], %[len]\n\t" \
  991. "jz 333f\n\t" \
  992. "222:\n\t" \
  993. "movb (%[src]), %%al\n\t" \
  994. "movb %%al, (%[dst])\n\t" \
  995. "inc %[src]\n\t" \
  996. "inc %[dst]\n\t" \
  997. "dec %[len]\n\t" \
  998. "jnz 222b\n\t" \
  999. "333:\n\t" \
  1000. RSEQ_INJECT_ASM(5)
  1001. "lock; addl $0,-128(%%esp)\n\t"
  1002. "movl %[newv], %%eax\n\t"
  1003. /* final store */
  1004. "movl %%eax, %[v]\n\t"
  1005. "2:\n\t"
  1006. RSEQ_INJECT_ASM(6)
  1007. /* teardown */
  1008. "movl %[rseq_scratch2], %[len]\n\t"
  1009. "movl %[rseq_scratch1], %[dst]\n\t"
  1010. "movl %[rseq_scratch0], %[src]\n\t"
  1011. RSEQ_ASM_DEFINE_ABORT(4,
  1012. "movl %[rseq_scratch2], %[len]\n\t"
  1013. "movl %[rseq_scratch1], %[dst]\n\t"
  1014. "movl %[rseq_scratch0], %[src]\n\t",
  1015. abort)
  1016. RSEQ_ASM_DEFINE_CMPFAIL(5,
  1017. "movl %[rseq_scratch2], %[len]\n\t"
  1018. "movl %[rseq_scratch1], %[dst]\n\t"
  1019. "movl %[rseq_scratch0], %[src]\n\t",
  1020. cmpfail)
  1021. #ifdef RSEQ_COMPARE_TWICE
  1022. RSEQ_ASM_DEFINE_CMPFAIL(6,
  1023. "movl %[rseq_scratch2], %[len]\n\t"
  1024. "movl %[rseq_scratch1], %[dst]\n\t"
  1025. "movl %[rseq_scratch0], %[src]\n\t",
  1026. error1)
  1027. RSEQ_ASM_DEFINE_CMPFAIL(7,
  1028. "movl %[rseq_scratch2], %[len]\n\t"
  1029. "movl %[rseq_scratch1], %[dst]\n\t"
  1030. "movl %[rseq_scratch0], %[src]\n\t",
  1031. error2)
  1032. #endif
  1033. : /* gcc asm goto does not allow outputs */
  1034. : [cpu_id] "r" (cpu),
  1035. [current_cpu_id] "m" (__rseq_abi.cpu_id),
  1036. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  1037. /* final store input */
  1038. [v] "m" (*v),
  1039. [expect] "m" (expect),
  1040. [newv] "m" (newv),
  1041. /* try memcpy input */
  1042. [dst] "r" (dst),
  1043. [src] "r" (src),
  1044. [len] "r" (len),
  1045. [rseq_scratch0] "m" (rseq_scratch[0]),
  1046. [rseq_scratch1] "m" (rseq_scratch[1]),
  1047. [rseq_scratch2] "m" (rseq_scratch[2])
  1048. : "memory", "cc", "eax"
  1049. RSEQ_INJECT_CLOBBER
  1050. : abort, cmpfail
  1051. #ifdef RSEQ_COMPARE_TWICE
  1052. , error1, error2
  1053. #endif
  1054. );
  1055. return 0;
  1056. abort:
  1057. RSEQ_INJECT_FAILED
  1058. return -1;
  1059. cmpfail:
  1060. return 1;
  1061. #ifdef RSEQ_COMPARE_TWICE
  1062. error1:
  1063. rseq_bug("cpu_id comparison failed");
  1064. error2:
  1065. rseq_bug("expected value comparison failed");
  1066. #endif
  1067. }
  1068. #endif /* !RSEQ_SKIP_FASTPATH */
  1069. #endif