trts_pic.S 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /*
  2. * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. /*
  32. * Description:
  33. * The file provides `enclave_entry' function to switch code between
  34. * trusted and untrusted envronment.
  35. */
  36. .file "trts_pic.S"
  37. #include "trts_pic.h"
  38. .text
  39. DECLARE_LOCAL_FUNC get_enclave_base
  40. lea_pic __ImageBase, %xax
  41. ret
  42. DECLARE_LOCAL_FUNC get_enclave_state
  43. lea_pic g_enclave_state, %xcx
  44. xor %xax, %xax
  45. movl (%xcx), %eax
  46. ret
  47. DECLARE_LOCAL_FUNC set_enclave_state
  48. lea_pic g_enclave_state, %xax
  49. #ifdef LINUX32
  50. mov SE_WORDSIZE(%esp), %edi
  51. #endif
  52. movl %edi, (%xax)
  53. ret
  54. DECLARE_LOCAL_FUNC lock_enclave
  55. lea_pic g_enclave_state, %xdx
  56. xor %xax, %xax
  57. mov $ENCLAVE_INIT_NOT_STARTED, %eax
  58. xor %xcx, %xcx
  59. mov $ENCLAVE_INIT_IN_PROGRESS, %ecx /* if (g_global_data.enclave_state == ENCLAVE_INIT_NOT_STARTED) */
  60. lock cmpxchgl %ecx, (%xdx) /* g_global_data.enclave_state == ENCLAVE_INIT_IN_PROGRESS */
  61. ret /* xax: the initial value of enclave state */
  62. /*
  63. * ---------------------------------------------------------------------
  64. * Function: thread_data_t* get_thread_data(void);
  65. *
  66. * Get the address of thread_data
  67. * ---------------------------------------------------------------------
  68. */
  69. DECLARE_LOCAL_FUNC get_thread_data
  70. READ_TD_DATA self_addr
  71. ret
  72. /*
  73. * ---------------------------------------------------------------------
  74. * Function: sys_word_t get_stack_guard(void);
  75. *
  76. * Get the value of stack_guard
  77. * ---------------------------------------------------------------------
  78. */
  79. DECLARE_LOCAL_FUNC get_stack_guard
  80. READ_TD_DATA stack_guard
  81. ret
  82. /*
  83. * ---------------------------------------------------------------------
  84. * Function: enclave_entry
  85. * The entry point of the enclave.
  86. *
  87. * Registers:
  88. * XAX - TCS.CSSA
  89. * XBX - the address of a TCS
  90. * XCX - the address of the instruction following the EENTER
  91. * XDI - the reason of entering the enclave
  92. * XSI - the pointer to the marshalling structure
  93. */
  94. DECLARE_GLOBAL_FUNC enclave_entry
  95. /*
  96. * ----------------------------------------------------------------------
  97. * Dispatch code according to CSSA and the reason of EENTER
  98. * eax > 0 - exception handler
  99. * edi >= 0 - ecall
  100. * edi == -1 - do_init_enclave
  101. * edi == -2 - oret
  102. * Registers
  103. * No need to use any register during the dipatch
  104. * ----------------------------------------------------------------------
  105. */
  106. .cfi_startproc
  107. cmp $0, %xax
  108. jne .Ldo_handler /* handle exception state */
  109. xor %xdx, %xdx
  110. READ_TD_DATA last_sp
  111. cmp $0, %xax
  112. jne .Lswitch_stack
  113. GET_STACK_BASE %xbx /* if last_sp == 0, set sp to stack base */
  114. sub $STATIC_STACK_SIZE, %xax /* give space for static stack */
  115. .Lswitch_stack:
  116. xchg %xsp, %xax
  117. push %xcx
  118. push %xbp
  119. .cfi_def_cfa_offset 2 * SE_WORDSIZE
  120. .cfi_offset xbp, -2 * SE_WORDSIZE
  121. mov %xsp, %xbp
  122. .cfi_def_cfa_register xbp
  123. /* Save the registers */
  124. sub $(6*SE_WORDSIZE), %xsp
  125. mov %xax, -1*SE_WORDSIZE(%xbp) /* xsp_u */
  126. mov %xdx, -3*SE_WORDSIZE(%xbp) /* cssa */
  127. mov %xbx, -4*SE_WORDSIZE(%xbp) /* TCS */
  128. mov %xsi, -5*SE_WORDSIZE(%xbp) /* XSI */
  129. mov %xdi, -6*SE_WORDSIZE(%xbp) /* XDI */
  130. #ifdef LINUX64
  131. mov %rdx, %rcx
  132. mov %rbx, %rdx
  133. #endif
  134. call enter_enclave
  135. mov %xax, %xbx
  136. .Lexit_enclave:
  137. /* clean extended feature registers */
  138. lea_pic SYNTHETIC_STATE, %xdi
  139. #ifdef LINUX32
  140. mov %xdi, (%xsp)
  141. #endif
  142. call restore_xregs
  143. /* set xdi and xsi */
  144. mov $OCMD_ERET, %xdi
  145. mov %xbx, %xsi
  146. /* restore stack */
  147. mov -1*SE_WORDSIZE(%xbp), %xdx /* xdx: xsp_u */
  148. mov %xbp, %xsp
  149. pop %xbp /* xbp_u */
  150. pop %xbx /* ret_u */
  151. mov %xdx, %xsp /* xsp_u */
  152. .Lclear_and_exit_enclave:
  153. /* Clear all GPRs, except xax, xbx, xdi and xsi */
  154. xor %xcx, %xcx
  155. xor %xdx, %xdx
  156. #if defined(LINUX64)
  157. xor %r8, %r8
  158. xor %r9, %r9
  159. xor %r10, %r10
  160. xor %r11, %r11
  161. xor %r12, %r12
  162. xor %r13, %r13
  163. xor %r14, %r14
  164. xor %r15, %r15
  165. #endif
  166. /* Set status flags to pre-defined values */
  167. add %xdx, %xdx /* OF = SF = AF = CF = 0; ZF = PF = 1 */
  168. /* EEXIT */
  169. mov $SE_EEXIT, %xax /* EEXIT leaf */
  170. ENCLU
  171. /* Should not come here */
  172. ud2
  173. .Ldo_handler:
  174. mov %xax, %xdx /* XDX: cssa */
  175. GET_STACK_BASE %xbx /* XAX: static stack, set sp to stack base */
  176. jmp .Lswitch_stack
  177. /* Should not come here */
  178. ud2
  179. .cfi_endproc
  180. /*
  181. * -------------------------------------------------------------------------
  182. * sgx_status_t do_ocall(unsigned int index, void *ms);
  183. *
  184. * Function: do_ocall
  185. * The entry point of the enclave
  186. * Parameters:
  187. * func_addr - target function address
  188. * ms - marshalling structure
  189. *
  190. * Stack: (same as do_oret)
  191. * bottom of stack ->
  192. * -----------------
  193. * | ECALL/OCALL |
  194. * previous TD.last_sp -> | frames |
  195. * -----------------
  196. * | ECALL frame |
  197. * | do_ocall param 2| 3
  198. * | do_ocall param 1| 2
  199. * |do_ocall ret_addr| 1
  200. * | xbp | 0 + xbp
  201. * | .... |
  202. * | xsave buffer |
  203. * | .... |
  204. * | xsave pointer | 19
  205. * | ocall_depth | 18
  206. * | reserved | 17
  207. * | reserved | 16
  208. * | reserved | 15
  209. * | rbx | 14
  210. * | rsi | 13
  211. * | rdi | 12
  212. * | rbp | 11
  213. * | r12 | 10
  214. * | r13 | 9
  215. * | r14 | 8
  216. * | r15 | 7
  217. * | prev TD.last_sp | 6
  218. * | ocall_index | 5
  219. * | OCALL FLAG | 4
  220. * | shadow | 3
  221. * | shadow | 2
  222. * | shadow | 1
  223. * TD.last_sp -> | shadow | 0 + xsp
  224. * -----------------
  225. * -------------------------------------------------------------------------
  226. */
  227. DECLARE_LOCAL_FUNC do_ocall
  228. /*
  229. * 8 for GPR, 1 for TD.last_sp, 1 for ocall_index
  230. * 1 for OCALL_FLAG, 4 for shadow space.
  231. * Stack Pointer is 16-byte aligned under x86_64.
  232. */
  233. push %xbp
  234. mov %xsp, %xbp
  235. /* save parameters in stack */
  236. #ifdef LINUX64
  237. mov %xdi, 2*SE_WORDSIZE(%xbp)
  238. mov %xsi, 3*SE_WORDSIZE(%xbp)
  239. #endif
  240. /* save and clean extended feature registers */
  241. READ_TD_DATA xsave_size
  242. sub %xax, %xsp /* allocate buffer to save xregs */
  243. mov $0x3f, %xax
  244. not %xax
  245. and %xax, %xsp /* xsave requires 64 byte aligned */
  246. mov %xsp, %xcx # xsave pointer
  247. sub $(20*SE_WORDSIZE), %xsp /* 20 slots for GPRs and other info */
  248. mov %xcx, SE_WORDSIZE*19(%xsp) /* addr for xsave */
  249. /* save non-volatile registers, except xsp */
  250. mov %xbx, SE_WORDSIZE*14(%xsp)
  251. mov %xsi, SE_WORDSIZE*13(%xsp)
  252. mov %xdi, SE_WORDSIZE*12(%xsp)
  253. mov %xbp, SE_WORDSIZE*11(%xsp)
  254. #ifdef LINUX64
  255. mov %r12, SE_WORDSIZE*10(%rsp)
  256. mov %r13, SE_WORDSIZE* 9(%rsp)
  257. mov %r14, SE_WORDSIZE* 8(%rsp)
  258. mov %r15, SE_WORDSIZE* 7(%rsp)
  259. #endif
  260. /* save and clean extended feature registers */
  261. mov SE_WORDSIZE*19(%xsp), %xdi /* xsave pointer */
  262. READ_TD_DATA xsave_size
  263. mov %xax, %xcx
  264. shr $2, %xcx /* xsave size in dword */
  265. xor %xax, %xax
  266. cld
  267. rep stos %eax, %es:(%xdi)
  268. mov SE_WORDSIZE*19(%xsp), %xdi # xsave pointer
  269. mov %xdi, (%xsp)
  270. call save_xregs
  271. lea_pic SYNTHETIC_STATE, %xdi
  272. mov %xdi, (%xsp)
  273. call restore_xregs
  274. /* set xdi and xsi using the input parameters */
  275. #ifdef LINUX64
  276. mov SE_WORDSIZE*12(%xsp), %xdi
  277. mov SE_WORDSIZE*13(%xsp), %xsi
  278. #else
  279. mov SE_WORDSIZE*2(%ebp), %edi
  280. mov SE_WORDSIZE*3(%ebp), %esi
  281. #endif
  282. /* save ocall index to the stack */
  283. mov $OCALL_FLAG, %xax
  284. mov %xax, SE_WORDSIZE*4(%xsp) /* save OCALL_FLAG */
  285. mov %xdi, SE_WORDSIZE*5(%xsp) /* save ocall_index */
  286. /*
  287. * save the inside stack context
  288. * push TD.last_sp
  289. * set TD.last_sp = xsp
  290. */
  291. READ_TD_DATA self_addr
  292. mov %xax, %xbx
  293. /* call update_ocall_lastsp */
  294. #ifdef LINUX32
  295. mov %xsp, (%xsp)
  296. #else
  297. mov %xsp, %xdi
  298. #endif
  299. call update_ocall_lastsp /* xax: td.last_sp */
  300. #ifdef LINUX64
  301. mov SE_WORDSIZE*12(%xsp), %xdi /* restore xdi */
  302. mov SE_WORDSIZE*13(%xsp), %xsi /* restore xdi */
  303. #endif
  304. /* restore outside stack context */
  305. mov first_ssa_gpr(%xbx), %xdx
  306. mov ssa_bp_u(%xdx), %xbp
  307. mov ssa_sp_u(%xdx), %xsp
  308. /*
  309. * set EEXIT registers
  310. * return address can be read from the ECALL frame:
  311. * TD.last_sp ->
  312. * -------------
  313. * | ret_addr |
  314. * | xbp_u |
  315. * | xsp_u |
  316. * | ... |
  317. */
  318. mov -1*SE_WORDSIZE(%xax), %xbx /* return address */
  319. mov $SE_EEXIT, %xax /* EEXIT leaf */
  320. /* Clear all GPRs, except xax, xbx, xdi, and xsi*/
  321. xor %xcx, %xcx
  322. xor %xdx, %xdx
  323. #ifdef LINUX64
  324. xor %r8, %r8
  325. xor %r9, %r9
  326. xor %r10, %r10
  327. xor %r11, %r11
  328. xor %r12, %r12
  329. xor %r13, %r13
  330. xor %r14, %r14
  331. xor %r15, %r15
  332. #endif
  333. /* Set status flags to pre-defined values */
  334. add %xdx, %xdx /* OF = SF = AF = CF = 0; ZF = PF = 1 */
  335. ENCLU
  336. /*
  337. * ------------------------------------------------------------------
  338. * this function is the wrapper of do_ocall, which is used to
  339. * stick ocall bridge and proxy frame together
  340. * ------------------------------------------------------------------
  341. */
  342. DECLARE_LOCAL_FUNC __morestack
  343. .cfi_startproc
  344. push %xbp
  345. .cfi_def_cfa_offset 2*SE_WORDSIZE
  346. .cfi_offset xbp,-2*SE_WORDSIZE
  347. mov %xsp, %xbp
  348. .cfi_def_cfa_register xbp
  349. sub $(4*SE_WORDSIZE), %xsp
  350. #ifdef LINUX32
  351. /* save the 2 parameters */
  352. mov (2*SE_WORDSIZE)(%xbp), %xax
  353. mov %xax, (0*SE_WORDSIZE)(%xsp)
  354. mov (3*SE_WORDSIZE)(%xbp), %xax
  355. mov %xax, (1*SE_WORDSIZE)(%xsp)
  356. #endif
  357. call do_ocall
  358. leave
  359. ret
  360. .cfi_endproc
  361. DECLARE_GLOBAL_FUNC asm_oret
  362. mov %xsp, %xbx
  363. #ifdef LINUX64
  364. mov %xdi, SE_WORDSIZE(%xsp)
  365. mov %xsi, 2*SE_WORDSIZE(%xsp)
  366. #endif
  367. mov SE_WORDSIZE(%xbx), %xsp /* restore thread_data.last_sp */
  368. /* restore extended feature registers */
  369. mov 19*SE_WORDSIZE(%xsp), %xdi
  370. #ifdef LINUX32
  371. mov %xdi, (%xsp)
  372. #endif
  373. call restore_xregs
  374. /* memset_s */
  375. xor %xax, %xax
  376. mov 11*SE_WORDSIZE(%xsp), %xcx
  377. sub %xdi, %xcx
  378. sub $SE_WORDSIZE, %xcx
  379. shr $2, %xcx
  380. cld
  381. rep stos %eax,%es:(%xdi)
  382. mov 2*SE_WORDSIZE(%xbx), %xax /* ocall return value */
  383. #ifdef LINUX64
  384. mov 7*SE_WORDSIZE(%xsp), %r15
  385. mov 8*SE_WORDSIZE(%xsp), %r14
  386. mov 9*SE_WORDSIZE(%xsp), %r13
  387. mov 10*SE_WORDSIZE(%xsp), %r12
  388. #endif
  389. mov 11*SE_WORDSIZE(%xsp), %xbp
  390. mov 12*SE_WORDSIZE(%xsp), %xdi
  391. mov 13*SE_WORDSIZE(%xsp), %xsi
  392. mov 14*SE_WORDSIZE(%xsp), %xbx
  393. mov %xbp, %xsp
  394. pop %xbp
  395. ret
  396. /* should not come here */
  397. ud2
  398. /*
  399. * ------------------------------------------------------------------------
  400. * extern "C" int do_egetkey(key_request_t *key_request, key_128bit_t *key)
  401. * return value:
  402. * 0 - success
  403. * none-zeor - EGETKEY error code
  404. * EGETKEY: rbx - the address of KEYREQUEST structure
  405. * rcx - the address where the key is outputted
  406. * ------------------------------------------------------------------------
  407. */
  408. DECLARE_LOCAL_FUNC do_egetkey
  409. SE_PROLOG
  410. mov $SE_EGETKEY, %xax /* EGETKEY leaf */
  411. ENCLU
  412. #ifdef SE_SIM
  413. cmp $SGX_SUCCESS, %xax /* In simulation mode, ZF flag will not be set */
  414. jnz .Legetkey_done /* because the stack clean operation will always clean ZF flag */
  415. #else
  416. jz .Legetkey_done /* if EGETKEY error, ZF flag is set and error code is set to xax */
  417. #endif
  418. xor %xax, %xax
  419. .Legetkey_done:
  420. SE_EPILOG
  421. /*
  422. * -------------------------------------------------------------------------
  423. * extern "C" void do_ereport(sgx_target_info_t *target_info, sgx_report_data_t *report_data, sgx_report_t *report);
  424. * EREPORT: rbx - the address of TARGETINFO;
  425. * rcx - the address of REPORTDATA;
  426. * rdx - the address where REPORT is outputted
  427. * -------------------------------------------------------------------------
  428. */
  429. DECLARE_LOCAL_FUNC do_ereport
  430. SE_PROLOG
  431. mov $SE_EREPORT, %xax /* EREPORT leaf */
  432. ENCLU
  433. SE_EPILOG
  434. DECLARE_GLOBAL_FUNC do_eaccept
  435. SE_PROLOG
  436. mov $SE_EACCEPT, %eax
  437. ENCLU
  438. cmp $SGX_SUCCESS, %eax
  439. jnz abort
  440. SE_EPILOG
  441. DECLARE_GLOBAL_FUNC do_emodpe
  442. SE_PROLOG
  443. mov $SE_EMODPE, %eax
  444. ENCLU
  445. SE_EPILOG
  446. #define _RDRAND_RETRY_TIMES 10
  447. /*
  448. * -------------------------------------
  449. * extern "C" uint32_t do_rdrand(uint32_t *rand);
  450. * return value:
  451. * non-zero: rdrand succeeded
  452. * zero: rdrand failed
  453. * -------------------------------------
  454. */
  455. DECLARE_LOCAL_FUNC do_rdrand
  456. mov $_RDRAND_RETRY_TIMES, %ecx
  457. .Lrdrand_retry:
  458. .byte 0x0F, 0xC7, 0xF0 /* rdrand %eax */
  459. jc .Lrdrand_return
  460. dec %ecx
  461. jnz .Lrdrand_retry
  462. xor %xax, %xax
  463. ret
  464. .Lrdrand_return:
  465. #ifdef LINUX32
  466. mov SE_WORDSIZE(%esp), %ecx
  467. #else
  468. mov %rdi, %rcx
  469. #endif
  470. movl %eax, (%xcx)
  471. mov $1, %xax
  472. ret
  473. /*
  474. * -------------------------------------------------------------------------
  475. * extern "C" void abort(void) __attribute__(__noreturn__);
  476. * -------------------------------------------------------------------------
  477. */
  478. DECLARE_LOCAL_FUNC abort
  479. lea_pic g_enclave_state, %xax
  480. movl $ENCLAVE_CRASHED, (%xax)
  481. ud2
  482. /*
  483. * -------------------------------------------------------------------------
  484. * extern "C" __attribute__((regparm(1))) void continue_execution(sgx_exception_info_t *info);
  485. * -------------------------------------------------------------------------
  486. */
  487. DECLARE_LOCAL_FUNC continue_execution
  488. #ifdef LINUX32
  489. mov %xax, %xcx
  490. #else
  491. mov %xdi, %xcx
  492. #endif
  493. mov SE_WORDSIZE*0(%xcx), %xax
  494. push %xax # push xax
  495. mov SE_WORDSIZE*1(%xcx), %xax
  496. push %xax # push xcx
  497. mov SE_WORDSIZE*4(%xcx), %xax # xax: xsp
  498. # x86_64 requires a 128-bytes red zone. We need to allocate buffer to avoid touching the red zone.
  499. sub $(SE_WORDSIZE + RED_ZONE_SIZE), %xax # allocate buffer to skip the red zone (if any) and save the xip
  500. # RED_ZONE_SIZE: 0(i386), 128-bytes(x86_64)
  501. # restore registers except xax, xcx, xsp
  502. mov SE_WORDSIZE*2(%xcx), %xdx
  503. mov SE_WORDSIZE*3(%xcx), %xbx
  504. mov SE_WORDSIZE*5(%xcx), %xbp
  505. mov SE_WORDSIZE*6(%xcx), %xsi
  506. mov SE_WORDSIZE*7(%xcx), %xdi
  507. #ifdef LINUX64
  508. mov SE_WORDSIZE*8(%xcx), %r8
  509. mov SE_WORDSIZE*9(%xcx), %r9
  510. mov SE_WORDSIZE*10(%xcx), %r10
  511. mov SE_WORDSIZE*11(%xcx), %r11
  512. mov SE_WORDSIZE*12(%xcx), %r12
  513. mov SE_WORDSIZE*13(%xcx), %r13
  514. mov SE_WORDSIZE*14(%xcx), %r14
  515. mov SE_WORDSIZE*15(%xcx), %r15
  516. push SE_WORDSIZE*16(%xcx)
  517. popf # make sure the following instructions do not affect flags
  518. #else
  519. push SE_WORDSIZE*8(%xcx)
  520. popf
  521. #endif
  522. #ifdef LINUX64
  523. mov SE_WORDSIZE*17(%xcx), %xcx
  524. #else
  525. mov SE_WORDSIZE*9(%xcx), %xcx # xcx: xip
  526. #endif
  527. # do not setup the new stack until info is not needed any more
  528. # otherwise, info will be overwritten
  529. mov %xcx, (%xax) # save xip to the new stack
  530. pop %xcx # restore xcx
  531. pop %xsp # xsp: xax
  532. xchg %xax, %xsp
  533. ret $(RED_ZONE_SIZE) # pop xip and red zone (if any)