sysdep-cancel.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright (C) 2016-2017 Andes Technology, Inc.
  3. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  4. */
  5. /* Copyright (C) 2003-2013 Free Software Foundation, Inc.
  6. The GNU C Library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  10. The GNU C Library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public
  15. License along with the GNU C Library. If not, see
  16. <http://www.gnu.org/licenses/>. */
  17. #include <sysdep.h>
  18. #include <tls.h>
  19. #ifndef __ASSEMBLER__
  20. # include <pthreadP.h>
  21. #endif
  22. #define PUSHARGS_0
  23. #define PUSHARGS_1 smw.adm $r0, [$sp], $r0, #0; \
  24. cfi_adjust_cfa_offset(4); \
  25. cfi_rel_offset(r0,0); \
  26. addi $sp, $sp, -4; \
  27. cfi_adjust_cfa_offset(4);
  28. #define PUSHARGS_2 smw.adm $r0, [$sp], $r1, #0; \
  29. cfi_adjust_cfa_offset(8); \
  30. cfi_rel_offset(r1, 4); \
  31. cfi_rel_offset(r0, 0);
  32. #define PUSHARGS_3 smw.adm $r0, [$sp], $r2, #0; \
  33. cfi_adjust_cfa_offset(12); \
  34. cfi_rel_offset(r2, 8); \
  35. cfi_rel_offset(r1, 4); \
  36. cfi_rel_offset(r0, 0); \
  37. addi $sp, $sp, -4; \
  38. cfi_adjust_cfa_offset(4);
  39. #define PUSHARGS_4 smw.adm $r0, [$sp], $r3, #0; \
  40. cfi_adjust_cfa_offset(16); \
  41. cfi_rel_offset(r3, 12); \
  42. cfi_rel_offset(r2, 8); \
  43. cfi_rel_offset(r1, 4); \
  44. cfi_rel_offset(r0, 0);
  45. #define PUSHARGS_5 smw.adm $r0, [$sp], $r4, #0; \
  46. cfi_adjust_cfa_offset(20); \
  47. cfi_rel_offset(r4, 16); \
  48. cfi_rel_offset(r3, 12); \
  49. cfi_rel_offset(r2, 8); \
  50. cfi_rel_offset(r1, 4); \
  51. cfi_rel_offset(r0, 0); \
  52. addi $sp, $sp, -4; \
  53. cfi_adjust_cfa_offset(4);
  54. #define PUSHARGS_6 smw.adm $r0, [$sp], $r5, #0; \
  55. cfi_adjust_cfa_offset(24); \
  56. cfi_rel_offset(r5, 20); \
  57. cfi_rel_offset(r4, 16); \
  58. cfi_rel_offset(r3, 12); \
  59. cfi_rel_offset(r2, 8); \
  60. cfi_rel_offset(r1, 4); \
  61. cfi_rel_offset(r0, 0);
  62. #define POPARGS2_0
  63. #define POPARGS2_1 addi $sp, $sp, 4; \
  64. cfi_adjust_cfa_offset(-4); \
  65. lmw.bim $r0, [$sp], $r0, #0; \
  66. cfi_adjust_cfa_offset(-4); \
  67. cfi_restore(r0);
  68. #define POPARGS2_2 lmw.bim $r0, [$sp], $r1, #0; \
  69. cfi_adjust_cfa_offset(-8); \
  70. cfi_restore(r0); \
  71. cfi_restore(r1);
  72. #define POPARGS2_3 addi $sp, $sp, 4; \
  73. cfi_adjust_cfa_offset(-4); \
  74. lmw.bim $r0, [$sp], $r2, #0; \
  75. cfi_adjust_cfa_offset(-12); \
  76. cfi_restore(r0); \
  77. cfi_restore(r1); \
  78. cfi_restore(r2);
  79. #define POPARGS2_4 lmw.bim $r0, [$sp], $r3, #0; \
  80. cfi_adjust_cfa_offset(-16); \
  81. cfi_restore(r0); \
  82. cfi_restore(r1); \
  83. cfi_restore(r2); \
  84. cfi_restore(r3);
  85. #define POPARGS2_5 addi $sp, $sp, 4; \
  86. cfi_adjust_cfa_offset(-4); \
  87. lmw.bim $r0, [$sp], $r4, #0; \
  88. cfi_adjust_cfa_offset(-20); \
  89. cfi_restore(r0); \
  90. cfi_restore(r1); \
  91. cfi_restore(r2); \
  92. cfi_restore(r3); \
  93. cfi_restore(r4);
  94. #define POPARGS2_6 lmw.bim $r0, [$sp], $r5, #0; \
  95. cfi_adjust_cfa_offset(-24); \
  96. cfi_restore(r0); \
  97. cfi_restore(r1); \
  98. cfi_restore(r2); \
  99. cfi_restore(r3); \
  100. cfi_restore(r4); \
  101. cfi_restore(r5);
  102. #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
  103. /* NOTE: We do mark syscalls with unwind annotations, for the benefit of
  104. cancellation; but they're really only accurate at the point of the
  105. syscall. The ARM unwind directives are not rich enough without adding
  106. a custom personality function. */
  107. # undef PSEUDO
  108. # define PSEUDO(name, syscall_name, args) \
  109. .align 2; \
  110. ENTRY (__##syscall_name##_nocancel); \
  111. __do_syscall(syscall_name); \
  112. PSEUDO_RET; \
  113. ret; \
  114. END (__##syscall_name##_nocancel); \
  115. ENTRY (name); \
  116. smw.adm $r6,[$sp],$r6,0x2; \
  117. cfi_adjust_cfa_offset(8); \
  118. cfi_offset(r6,-8); \
  119. cfi_offset(lp,-4); \
  120. SINGLE_THREAD_P ($r15); \
  121. bgtz $r15, .Lpseudo_cancel; \
  122. __do_syscall(syscall_name); \
  123. j 50f; \
  124. .Lpseudo_cancel: \
  125. PUSHARGS_##args; /* save syscall args etc. around CENABLE. */ \
  126. CENABLE ($r5); \
  127. mov55 $r6, $r0; /* put mask in safe place. */ \
  128. POPARGS2_##args; \
  129. __do_syscall(syscall_name); /* do the call. */ \
  130. push $r0; \
  131. cfi_adjust_cfa_offset(4); \
  132. cfi_rel_offset(r0, 0); \
  133. addi $sp, $sp, -4; \
  134. cfi_adjust_cfa_offset(4); \
  135. mov55 $r0, $r6; /* save syscall return value. */\
  136. CDISABLE($r5); \
  137. addi $sp, $sp, 4; \
  138. cfi_adjust_cfa_offset(-4); \
  139. pop $r0; /* retrieve return value. */ \
  140. cfi_adjust_cfa_offset(-4); \
  141. cfi_restore(r0); \
  142. 50: \
  143. lmw.bim $r6,[$sp],$r6, 0x2; \
  144. cfi_adjust_cfa_offset(-8); \
  145. cfi_restore(lp); \
  146. cfi_restore(r6); \
  147. PSEUDO_RET;
  148. # ifndef __ASSEMBLER__
  149. //# if defined IS_IN_libpthread || !defined NOT_IN_libc
  150. //extern int __local_multiple_threads attribute_hidden;
  151. //# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
  152. //# else
  153. /* There is no __local_multiple_threads for librt */
  154. # define SINGLE_THREAD_P __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
  155. header.multiple_threads) == 0, 1)
  156. //# endif
  157. # else
  158. # define SINGLE_THREAD_P(reg) \
  159. addi reg, $r25, MULTIPLE_THREADS_OFFSET; \
  160. lw reg, [reg];
  161. # define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P(x)
  162. # endif
  163. # ifdef IS_IN_libpthread
  164. # define CENABLE(reg) jmp(reg, __pthread_enable_asynccancel)
  165. # define CDISABLE(reg) jmp(reg, __pthread_disable_asynccancel)
  166. # define __local_multiple_threads __pthread_multiple_threads
  167. # elif !defined NOT_IN_libc
  168. # define CENABLE(reg) jmp(reg, __libc_enable_asynccancel)
  169. # define CDISABLE(reg) jmp(reg, __libc_disable_asynccancel)
  170. # define __local_multiple_threads __libc_multiple_threads
  171. # elif defined IS_IN_librt
  172. # define CENABLE(reg) jmp(reg, __librt_enable_asynccancel)
  173. # define CDISABLE(reg) jmp(reg, __librt_disable_asynccancel)
  174. # else
  175. # error Unsupported library
  176. # endif
  177. #elif !defined __ASSEMBLER__
  178. /* For rtld, et cetera. */
  179. # define SINGLE_THREAD_P 1
  180. # define NO_CANCELLATION 1
  181. #endif
  182. #ifndef __ASSEMBLER__
  183. # define RTLD_SINGLE_THREAD_P \
  184. __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
  185. header.multiple_threads) == 0, 1)
  186. #endif
  187. #ifdef PIC
  188. #define PSEUDO_RET \
  189. .pic \
  190. .align 2; \
  191. bgez $r0, 1f; \
  192. sltsi $r1, $r0, -4096; \
  193. bgtz $r1, 1f; \
  194. PIC_jmp_err \
  195. nop; \
  196. 1:
  197. #else /* PIC*/
  198. #define PSEUDO_RET \
  199. .align 2; \
  200. bgez $r0, 1f; \
  201. sltsi $r1, $r0, -4096; \
  202. bgtz $r1, 1f; \
  203. j SYSCALL_ERROR; \
  204. 1:
  205. #endif
  206. #ifdef PIC
  207. #define jmp(reg, symble) PIC_jmpr(reg, symble)
  208. /* reg: available register */
  209. #define PIC_jmp_err \
  210. smw.adm $sp,[$sp],$sp,#0x6; \
  211. mfusr $r15, $PC; \
  212. sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \
  213. ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \
  214. add $gp, $r15, $gp; \
  215. sethi $r15, hi20(SYSCALL_ERROR@PLT); \
  216. ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \
  217. add $r15, $r15, $gp; \
  218. jral $r15; \
  219. lmw.bim $sp,[$sp],$sp,#0x6; \
  220. ret;
  221. #define PIC_jmp(reg, symble) \
  222. mfusr $r15, $PC; \
  223. sethi reg, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \
  224. ori reg, reg, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \
  225. add reg, $r15, reg; \
  226. sethi $r15, hi20(symble@PLT); \
  227. ori $r15, $r15, lo12(symble@PLT); \
  228. add $r15, $r15, reg; \
  229. jr $r15;
  230. #define PIC_jmpr(reg, symble) \
  231. mfusr $r15, $PC; \
  232. sethi reg, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \
  233. ori reg, reg, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \
  234. add reg, $r15, reg; \
  235. sethi $r15, hi20(symble@PLT); \
  236. ori $r15, $r15, lo12(symble@PLT); \
  237. add $r15, $r15, reg; \
  238. jral $r15;
  239. #else
  240. #define jmp(reg, symble) jal symble
  241. #endif