mach_dep.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3. * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
  4. *
  5. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  6. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  7. *
  8. * Permission is hereby granted to use or copy this program
  9. * for any purpose, provided the above notices are retained on all copies.
  10. * Permission to modify the code and to distribute modified code is granted,
  11. * provided the above notices are retained, and a notice that the code was
  12. * modified is included with the above copyright notice.
  13. */
  14. #include "private/gc_priv.h"
  15. #if !defined(PLATFORM_MACH_DEP) && !defined(SN_TARGET_PSP2)
  16. #include <stdio.h>
  17. #ifdef AMIGA
  18. # ifndef __GNUC__
  19. # include <dos.h>
  20. # else
  21. # include <machine/reg.h>
  22. # endif
  23. #endif
  24. #if defined(MACOS) && defined(__MWERKS__)
  25. #if defined(POWERPC)
  26. # define NONVOLATILE_GPR_COUNT 19
  27. struct ppc_registers {
  28. unsigned long gprs[NONVOLATILE_GPR_COUNT]; /* R13-R31 */
  29. };
  30. typedef struct ppc_registers ppc_registers;
  31. # if defined(CPPCHECK)
  32. void getRegisters(ppc_registers* regs);
  33. # else
  34. asm static void getRegisters(register ppc_registers* regs)
  35. {
  36. stmw r13,regs->gprs /* save R13-R31 */
  37. blr
  38. }
  39. # endif
  40. static void PushMacRegisters(void)
  41. {
  42. ppc_registers regs;
  43. int i;
  44. getRegisters(&regs);
  45. for (i = 0; i < NONVOLATILE_GPR_COUNT; i++)
  46. GC_push_one(regs.gprs[i]);
  47. }
  48. #else /* M68K */
  49. asm static void PushMacRegisters(void)
  50. {
  51. sub.w #4,sp /* reserve space for one parameter */
  52. move.l a2,(sp)
  53. jsr GC_push_one
  54. move.l a3,(sp)
  55. jsr GC_push_one
  56. move.l a4,(sp)
  57. jsr GC_push_one
  58. # if !__option(a6frames)
  59. /* <pcb> perhaps a6 should be pushed if stack frames are not being used */
  60. move.l a6,(sp)
  61. jsr GC_push_one
  62. # endif
  63. /* skip a5 (globals), a6 (frame pointer), and a7 (stack pointer) */
  64. move.l d2,(sp)
  65. jsr GC_push_one
  66. move.l d3,(sp)
  67. jsr GC_push_one
  68. move.l d4,(sp)
  69. jsr GC_push_one
  70. move.l d5,(sp)
  71. jsr GC_push_one
  72. move.l d6,(sp)
  73. jsr GC_push_one
  74. move.l d7,(sp)
  75. jsr GC_push_one
  76. add.w #4,sp /* fix stack */
  77. rts
  78. }
  79. #endif /* M68K */
  80. #endif /* MACOS && __MWERKS__ */
  81. # if defined(SPARC) || defined(IA64)
  82. /* Value returned from register flushing routine; either sp (SPARC) */
  83. /* or ar.bsp (IA64). */
  84. GC_INNER ptr_t GC_save_regs_ret_val = NULL;
  85. # endif
  86. /* Routine to mark from registers that are preserved by the C compiler. */
  87. /* This must be ported to every new architecture. It is not optional, */
  88. /* and should not be used on platforms that are either UNIX-like, or */
  89. /* require thread support. */
  90. #undef HAVE_PUSH_REGS
  91. #if defined(USE_ASM_PUSH_REGS)
  92. # define HAVE_PUSH_REGS
  93. #else /* No asm implementation */
  94. # ifdef STACK_NOT_SCANNED
  95. void GC_push_regs(void)
  96. {
  97. /* empty */
  98. }
  99. # define HAVE_PUSH_REGS
  100. # elif defined(M68K) && defined(AMIGA)
  101. /* This function is not static because it could also be */
  102. /* erroneously defined in .S file, so this error would be caught */
  103. /* by the linker. */
  104. void GC_push_regs(void)
  105. {
  106. /* AMIGA - could be replaced by generic code */
  107. /* a0, a1, d0 and d1 are caller save */
  108. # ifdef __GNUC__
  109. asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
  110. asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
  111. asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
  112. asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
  113. asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
  114. asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
  115. /* Skip frame pointer and stack pointer */
  116. asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
  117. asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
  118. asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
  119. asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
  120. asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
  121. asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
  122. asm("addq.w &0x4,%sp"); /* put stack back where it was */
  123. # else /* !__GNUC__ */
  124. GC_push_one(getreg(REG_A2));
  125. GC_push_one(getreg(REG_A3));
  126. # ifndef __SASC
  127. /* Can probably be changed to #if 0 -Kjetil M. (a4=globals) */
  128. GC_push_one(getreg(REG_A4));
  129. # endif
  130. GC_push_one(getreg(REG_A5));
  131. GC_push_one(getreg(REG_A6));
  132. /* Skip stack pointer */
  133. GC_push_one(getreg(REG_D2));
  134. GC_push_one(getreg(REG_D3));
  135. GC_push_one(getreg(REG_D4));
  136. GC_push_one(getreg(REG_D5));
  137. GC_push_one(getreg(REG_D6));
  138. GC_push_one(getreg(REG_D7));
  139. # endif /* !__GNUC__ */
  140. }
  141. # define HAVE_PUSH_REGS
  142. # elif defined(MACOS)
  143. # if defined(M68K) && defined(THINK_C) && !defined(CPPCHECK)
  144. # define PushMacReg(reg) \
  145. move.l reg,(sp) \
  146. jsr GC_push_one
  147. void GC_push_regs(void)
  148. {
  149. asm {
  150. sub.w #4,sp ; reserve space for one parameter.
  151. PushMacReg(a2);
  152. PushMacReg(a3);
  153. PushMacReg(a4);
  154. ; skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
  155. PushMacReg(d2);
  156. PushMacReg(d3);
  157. PushMacReg(d4);
  158. PushMacReg(d5);
  159. PushMacReg(d6);
  160. PushMacReg(d7);
  161. add.w #4,sp ; fix stack.
  162. }
  163. }
  164. # define HAVE_PUSH_REGS
  165. # undef PushMacReg
  166. # elif defined(__MWERKS__)
  167. void GC_push_regs(void)
  168. {
  169. PushMacRegisters();
  170. }
  171. # define HAVE_PUSH_REGS
  172. # endif /* __MWERKS__ */
  173. # endif /* MACOS */
  174. #endif /* !USE_ASM_PUSH_REGS */
  175. #if defined(HAVE_PUSH_REGS) && defined(THREADS)
  176. # error GC_push_regs cannot be used with threads
  177. /* Would fail for GC_do_blocking. There are probably other safety */
  178. /* issues. */
  179. # undef HAVE_PUSH_REGS
  180. #endif
  181. #if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
  182. # include <signal.h>
  183. # ifndef NO_GETCONTEXT
  184. # if defined(DARWIN) \
  185. && (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 /*MAC_OS_X_VERSION_10_6*/)
  186. # include <sys/ucontext.h>
  187. # else
  188. # include <ucontext.h>
  189. # endif /* !DARWIN */
  190. # ifdef GETCONTEXT_FPU_EXCMASK_BUG
  191. # include <fenv.h>
  192. # endif
  193. # endif
  194. #endif /* !HAVE_PUSH_REGS */
  195. /* Ensure that either registers are pushed, or callee-save registers */
  196. /* are somewhere on the stack, and then call fn(arg, ctxt). */
  197. /* ctxt is either a pointer to a ucontext_t we generated, or NULL. */
  198. GC_ATTR_NO_SANITIZE_ADDR
  199. GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
  200. volatile ptr_t arg)
  201. {
  202. volatile int dummy;
  203. void * volatile context = 0;
  204. # if defined(HAVE_PUSH_REGS)
  205. GC_push_regs();
  206. # else
  207. # if defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
  208. /* Older versions of Darwin seem to lack getcontext(). */
  209. /* ARM and MIPS Linux often doesn't support a real */
  210. /* getcontext(). */
  211. static signed char getcontext_works = 0; /* (-1) - broken, 1 - works */
  212. ucontext_t ctxt;
  213. # ifdef GETCONTEXT_FPU_EXCMASK_BUG
  214. /* Workaround a bug (clearing the FPU exception mask) in */
  215. /* getcontext on Linux/x86_64. */
  216. # ifdef X86_64
  217. /* We manipulate FPU control word here just not to force the */
  218. /* client application to use -lm linker option. */
  219. unsigned short old_fcw;
  220. # if defined(CPPCHECK)
  221. GC_noop1((word)&old_fcw);
  222. # endif
  223. __asm__ __volatile__ ("fstcw %0" : "=m" (*&old_fcw));
  224. # else
  225. int except_mask = fegetexcept();
  226. # endif
  227. # endif
  228. if (getcontext_works >= 0) {
  229. if (getcontext(&ctxt) < 0) {
  230. WARN("getcontext failed:"
  231. " using another register retrieval method...\n", 0);
  232. /* getcontext() is broken, do not try again. */
  233. /* E.g., to workaround a bug in Docker ubuntu_32bit. */
  234. } else {
  235. context = &ctxt;
  236. }
  237. if (EXPECT(0 == getcontext_works, FALSE))
  238. getcontext_works = context != NULL ? 1 : -1;
  239. }
  240. # ifdef GETCONTEXT_FPU_EXCMASK_BUG
  241. # ifdef X86_64
  242. __asm__ __volatile__ ("fldcw %0" : : "m" (*&old_fcw));
  243. {
  244. unsigned mxcsr;
  245. /* And now correct the exception mask in SSE MXCSR. */
  246. __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr));
  247. mxcsr = (mxcsr & ~(FE_ALL_EXCEPT << 7)) |
  248. ((old_fcw & FE_ALL_EXCEPT) << 7);
  249. __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr));
  250. }
  251. # else /* !X86_64 */
  252. if (feenableexcept(except_mask) < 0)
  253. ABORT("feenableexcept failed");
  254. # endif
  255. # endif /* GETCONTEXT_FPU_EXCMASK_BUG */
  256. # if defined(SPARC) || defined(IA64)
  257. /* On a register window machine, we need to save register */
  258. /* contents on the stack for this to work. This may already be */
  259. /* subsumed by the getcontext() call. */
  260. GC_save_regs_ret_val = GC_save_regs_in_stack();
  261. # endif
  262. if (NULL == context) /* getcontext failed */
  263. # endif /* !NO_GETCONTEXT */
  264. {
  265. # if defined(HAVE_BUILTIN_UNWIND_INIT)
  266. /* This was suggested by Richard Henderson as the way to */
  267. /* force callee-save registers and register windows onto */
  268. /* the stack. */
  269. __builtin_unwind_init();
  270. # elif defined(NO_CRT) && defined(MSWIN32)
  271. CONTEXT ctx;
  272. RtlCaptureContext(&ctx);
  273. # else
  274. /* Generic code */
  275. /* The idea is due to Parag Patel at HP. */
  276. /* We're not sure whether he would like */
  277. /* to be acknowledged for it or not. */
  278. jmp_buf regs;
  279. word * i = (word *)&regs;
  280. ptr_t lim = (ptr_t)(&regs) + sizeof(regs);
  281. /* Setjmp doesn't always clear all of the buffer. */
  282. /* That tends to preserve garbage. Clear it. */
  283. for (; (word)i < (word)lim; i++) {
  284. *i = 0;
  285. }
  286. # if defined(MSWIN32) || defined(MSWINCE) || defined(UTS4) \
  287. || defined(OS2) || defined(CX_UX) || defined(__CC_ARM) \
  288. || defined(LINUX) || defined(EWS4800) || defined(RTEMS)
  289. (void) setjmp(regs);
  290. # else
  291. (void) _setjmp(regs);
  292. /* We don't want to mess with signals. According to */
  293. /* SUSV3, setjmp() may or may not save signal mask. */
  294. /* _setjmp won't, but is less portable. */
  295. # endif
  296. # endif /* !HAVE_BUILTIN_UNWIND_INIT */
  297. }
  298. # endif /* !HAVE_PUSH_REGS */
  299. /* FIXME: context here is sometimes just zero. At the moment the */
  300. /* callees don't really need it. */
  301. fn(arg, context);
  302. /* Strongly discourage the compiler from treating the above */
  303. /* as a tail-call, since that would pop the register */
  304. /* contents before we get a chance to look at them. */
  305. GC_noop1((word)(&dummy));
  306. }
  307. #endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */