rseq-x86-bits.h 27 KB

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