libphobos: Fix backtraces in Fibers on AArch64.
[official-gcc.git] / libphobos / libdruntime / core / threadasm.S
blob140e5f9a9e4f30a089a01c3169d9766c34d05714
1 /**
2  * Support code for mutithreading.
3  *
4  * Copyright: Copyright Mikola Lysenko 2005 - 2012.
5  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6  * Authors:   Mikola Lysenko, Martin Nowak, Kai Nacke
7  */
9 /*
10  *          Copyright Mikola Lysenko 2005 - 2012.
11  * Distributed under the Boost Software License, Version 1.0.
12  *    (See accompanying file LICENSE_1_0.txt or copy at
13  *          http://www.boost.org/LICENSE_1_0.txt)
14  */
16 /* NOTE: This file has been patched from the original DMD distribution to
17  * work with the GDC compiler.
18  */
19 #if (__linux__ || __FreeBSD__ || __NetBSD__ || __DragonFly__) && __ELF__
21  * Mark the resulting object file as not requiring execution permissions on
22  * stack memory. The absence of this section would mark the whole resulting
23  * library as requiring an executable stack, making it impossible to
24  * dynamically load druntime on several Linux platforms where this is
25  * forbidden due to security policies.
26  * Use %progbits instead of @progbits to support ARM and X86.
27  */
28 .section .note.GNU-stack,"",%progbits
29 #endif
31 /* Let preprocessor tell us if C symbols have a prefix: __USER_LABEL_PREFIX__ */
32 #ifdef __USER_LABEL_PREFIX__
33 #define GLUE2(a, b) a ## b
34 #define GLUE(a, b) GLUE2(a, b)
35 #define CSYM(name) GLUE(__USER_LABEL_PREFIX__, name)
36 #else
37 #define CSYM(name) name
38 #endif
40 /************************************************************************************
41  * POWER PC ASM BITS
42  ************************************************************************************/
43 #if defined( __PPC64__ )
45 #if defined(_CALL_ELF) && _CALL_ELF == 2
46 #define USE_ABI_2
47 #define LINKAGE_SZ   32
48 #define LR_OFS       16
49 #define TOC_OFS      24
50 #define GPR_OFS      32
51 #define STACK_SZ     (LINKAGE_SZ + 26*8)
52 #define OFS_R3_R10   GPR_OFS
53 #define OFS_R14_R31  (GPR_OFS+8*8)
54 #else
55 #define LINKAGE_SZ   48
56 #define LR_OFS       16
57 #define TOC_OFS      40
58 #define GPR_OFS      112
59 #define STACK_SZ     (LINKAGE_SZ + 8*8 + 18*8)
60 #define OFS_R3_R10   (STACK_SZ+LINKAGE_SZ)
61 #define OFS_R14_R31  GPR_OFS
62 #endif
64     .text
65 #if defined( USE_ABI_2 )
66     .abiversion 2
67 #endif
68     .globl  _D4core6thread18callWithStackShellFNbMDFNbPvZvZv
69     .align  2
70     .type   _D4core6thread18callWithStackShellFNbMDFNbPvZvZv,@function
71 #if defined( USE_ABI_2 )
72     .section .text._D4core6thread18callWithStackShellFNbMDFNbPvZvZv,"a",@progbits
73 #else
74     .section .opd,"aw",@progbits
75 #endif
76 _D4core6thread18callWithStackShellFNbMDFNbPvZvZv:
77 #if !defined( USE_ABI_2 )
78     .align  3
79     .quad .L._D4core6thread18callWithStackShellFNbMDFNbPvZvZv
80     .quad .TOC.@tocbase
81     .quad 0
82 #endif
83     .text
85  * Called with:
86  * r3: pointer context
87  * r4: pointer to function
88  */
89 .L._D4core6thread18callWithStackShellFNbMDFNbPvZvZv:
90     .cfi_startproc
91     stdu    1, -STACK_SZ(1)
92     mflr    0
93     std     0, LR_OFS(1)
94     .cfi_def_cfa_offset 256
95     .cfi_offset lr, 16
97     /* Save r14-r31 in general register save area */
98     std     14, (OFS_R14_R31 + 0 * 8)(1)
99     std     15, (OFS_R14_R31 + 1 * 8)(1)
100     std     16, (OFS_R14_R31 + 2 * 8)(1)
101     std     17, (OFS_R14_R31 + 3 * 8)(1)
102     std     18, (OFS_R14_R31 + 4 * 8)(1)
103     std     19, (OFS_R14_R31 + 5 * 8)(1)
104     std     20, (OFS_R14_R31 + 6 * 8)(1)
105     std     21, (OFS_R14_R31 + 7 * 8)(1)
106     std     22, (OFS_R14_R31 + 8 * 8)(1)
107     std     23, (OFS_R14_R31 + 9 * 8)(1)
108     std     24, (OFS_R14_R31 + 10 * 8)(1)
109     std     25, (OFS_R14_R31 + 11 * 8)(1)
110     std     26, (OFS_R14_R31 + 12 * 8)(1)
111     std     27, (OFS_R14_R31 + 13 * 8)(1)
112     std     28, (OFS_R14_R31 + 14 * 8)(1)
113     std     29, (OFS_R14_R31 + 15 * 8)(1)
114     std     30, (OFS_R14_R31 + 16 * 8)(1)
115     std     31, (OFS_R14_R31 + 17 * 8)(1)
117     /* Save r3-r10 in parameter save area of caller */
118     std     3, (OFS_R3_R10 + 0 * 8)(1)
119     std     4, (OFS_R3_R10 + 1 * 8)(1)
120     std     5, (OFS_R3_R10 + 2 * 8)(1)
121     std     6, (OFS_R3_R10 + 3 * 8)(1)
122     std     7, (OFS_R3_R10 + 4 * 8)(1)
123     std     8, (OFS_R3_R10 + 5 * 8)(1)
124     std     9, (OFS_R3_R10 + 6 * 8)(1)
125     std     10, (OFS_R3_R10 + 7 * 8)(1)
127     /* Save r2 in TOC save area */
128     std     2, TOC_OFS(1)
130     /* Do not save r11, r12 and r13. */
132     /* Call delegate:
133      * r3: pointer to context
134      * r4: pointer to stack
135      */
136     mr      5, 4
137     mr      4, 1
138     ld      6, 0(5)
139     ld      11, 16(5)
140     ld      2, 8(5)
141     mtctr   6
142     bctrl
143     nop
145     /* Restore r2 from TOC save area */
146     ld      2, TOC_OFS(1)
148     /* Restore r3-r10 from local variable space */
149     ld      3, (OFS_R3_R10 + 0 * 8)(1)
150     ld      4, (OFS_R3_R10 + 1 * 8)(1)
151     ld      5, (OFS_R3_R10 + 2 * 8)(1)
152     ld      6, (OFS_R3_R10 + 3 * 8)(1)
153     ld      7, (OFS_R3_R10 + 4 * 8)(1)
154     ld      8, (OFS_R3_R10 + 5 * 8)(1)
155     ld      9, (OFS_R3_R10 + 6 * 8)(1)
156     ld      10, (OFS_R3_R10 + 7 * 8)(1)
158     /* Restore r14-r31 from general register save area */
159     ld      14, (OFS_R14_R31 + 0 * 8)(1)
160     ld      15, (OFS_R14_R31 + 1 * 8)(1)
161     ld      16, (OFS_R14_R31 + 2 * 8)(1)
162     ld      17, (OFS_R14_R31 + 3 * 8)(1)
163     ld      18, (OFS_R14_R31 + 4 * 8)(1)
164     ld      19, (OFS_R14_R31 + 5 * 8)(1)
165     ld      20, (OFS_R14_R31 + 6 * 8)(1)
166     ld      21, (OFS_R14_R31 + 7 * 8)(1)
167     ld      22, (OFS_R14_R31 + 8 * 8)(1)
168     ld      23, (OFS_R14_R31 + 9 * 8)(1)
169     ld      24, (OFS_R14_R31 + 10 * 8)(1)
170     ld      25, (OFS_R14_R31 + 11 * 8)(1)
171     ld      26, (OFS_R14_R31 + 12 * 8)(1)
172     ld      27, (OFS_R14_R31 + 13 * 8)(1)
173     ld      28, (OFS_R14_R31 + 14 * 8)(1)
174     ld      29, (OFS_R14_R31 + 15 * 8)(1)
175     ld      30, (OFS_R14_R31 + 16 * 8)(1)
176     ld      31, (OFS_R14_R31 + 17 * 8)(1)
178     ld      0, LR_OFS(1)
179     mtlr    0
180     addi    1, 1, STACK_SZ
181     blr
182     .long 0
183     .quad 0
184 .Lend:
185     .size _D4core6thread18callWithStackShellFNbMDFNbPvZvZv, .Lend-.L._D4core6thread18callWithStackShellFNbMDFNbPvZvZv
186     .cfi_endproc
188 #elif defined( __ppc__ ) || defined( __PPC__ ) || defined( __powerpc__ )
192  * Performs a context switch.
194  * r3 - old context pointer
195  * r4 - new context pointer
197  */
198 .text
199 .align 2
200 .globl _fiber_switchContext
201 _fiber_switchContext:
203     /* Save linkage area */
204     mflr        0
205     mfcr        5
206     stw     0, 8(1)
207     stw     5, 4(1)
209     /* Save GPRs */
210     stw     11, (-1 * 4)(1)
211     stw     13, (-2 * 4)(1)
212     stw     14, (-3 * 4)(1)
213     stw     15, (-4 * 4)(1)
214     stw     16, (-5 * 4)(1)
215     stw     17, (-6 * 4)(1)
216     stw     18, (-7 * 4)(1)
217     stw     19, (-8 * 4)(1)
218     stw     20, (-9 * 4)(1)
219     stw     21, (-10 * 4)(1)
220     stw     22, (-11 * 4)(1)
221     stw     23, (-12 * 4)(1)
222     stw     24, (-13 * 4)(1)
223     stw     25, (-14 * 4)(1)
224     stw     26, (-15 * 4)(1)
225     stw     27, (-16 * 4)(1)
226     stw     28, (-17 * 4)(1)
227     stw     29, (-18 * 4)(1)
228     stw     30, (-19 * 4)(1)
229     stwu    31, (-20 * 4)(1)
231     /* We update the stack pointer here, since we do not want the GC to
232        scan the floating point registers. */
234     /* Save FPRs */
235     stfd    14, (-1 * 8)(1)
236     stfd    15, (-2 * 8)(1)
237     stfd    16, (-3 * 8)(1)
238     stfd    17, (-4 * 8)(1)
239     stfd    18, (-5 * 8)(1)
240     stfd    19, (-6 * 8)(1)
241     stfd    20, (-7 * 8)(1)
242     stfd    21, (-8 * 8)(1)
243     stfd    22, (-9 * 8)(1)
244     stfd    23, (-10 * 8)(1)
245     stfd    24, (-11 * 8)(1)
246     stfd    25, (-12 * 8)(1)
247     stfd    26, (-13 * 8)(1)
248     stfd    27, (-14 * 8)(1)
249     stfd    28, (-15 * 8)(1)
250     stfd    29, (-16 * 8)(1)
251     stfd    30, (-17 * 8)(1)
252     stfd    31, (-18 * 8)(1)
254     /* Update the old stack pointer */
255     stw     1, 0(3)
257     /* Set new stack pointer */
258     addi        1, 4, 20 * 4
260     /* Restore linkage area */
261     lwz     0, 8(1)
262     lwz     5, 4(1)
264     /* Restore GPRs */
265     lwz     11, (-1 * 4)(1)
266     lwz     13, (-2 * 4)(1)
267     lwz     14, (-3 * 4)(1)
268     lwz     15, (-4 * 4)(1)
269     lwz     16, (-5 * 4)(1)
270     lwz     17, (-6 * 4)(1)
271     lwz     18, (-7 * 4)(1)
272     lwz     19, (-8 * 4)(1)
273     lwz     20, (-9 * 4)(1)
274     lwz     21, (-10 * 4)(1)
275     lwz     22, (-11 * 4)(1)
276     lwz     23, (-12 * 4)(1)
277     lwz     24, (-13 * 4)(1)
278     lwz     25, (-14 * 4)(1)
279     lwz     26, (-15 * 4)(1)
280     lwz     27, (-16 * 4)(1)
281     lwz     28, (-17 * 4)(1)
282     lwz     29, (-18 * 4)(1)
283     lwz     30, (-19 * 4)(1)
284     lwz     31, (-20 * 4)(1)
287     /* Restore FPRs */
288     lfd     14, (-1 * 8)(4)
289     lfd     15, (-2 * 8)(4)
290     lfd     16, (-3 * 8)(4)
291     lfd     17, (-4 * 8)(4)
292     lfd     18, (-5 * 8)(4)
293     lfd     19, (-6 * 8)(4)
294     lfd     20, (-7 * 8)(4)
295     lfd     21, (-8 * 8)(4)
296     lfd     22, (-9 * 8)(4)
297     lfd     23, (-10 * 8)(4)
298     lfd     24, (-11 * 8)(4)
299     lfd     25, (-12 * 8)(4)
300     lfd     26, (-13 * 8)(4)
301     lfd     27, (-14 * 8)(4)
302     lfd     28, (-15 * 8)(4)
303     lfd     29, (-16 * 8)(4)
304     lfd     30, (-17 * 8)(4)
305     lfd     31, (-18 * 8)(4)
307     /* Set condition and link register */
308     mtcr        5
309     mtlr        0
311     /* Return and switch context */
312     blr
314 #elif defined(__mips__) && _MIPS_SIM == _ABIO32
315 /************************************************************************************
316  * MIPS ASM BITS
317  ************************************************************************************/
320  * Performs a context switch.
322  * $a0 - void** - ptr to old stack pointer
323  * $a1 - void*  - new stack pointer
325  */
326 .text
327 .globl fiber_switchContext
328 fiber_switchContext:
329     addiu $sp, $sp, -(10 * 4)
331     // fp regs and return address are stored below the stack
332     // because we don't want the GC to scan them.
334 #ifdef __mips_hard_float
335 #define ALIGN8(val) (val + (-val & 7))
336 #define BELOW (ALIGN8(6 * 8 + 4))
337     sdc1 $f20, (0 * 8 - BELOW)($sp)
338     sdc1 $f22, (1 * 8 - BELOW)($sp)
339     sdc1 $f24, (2 * 8 - BELOW)($sp)
340     sdc1 $f26, (3 * 8 - BELOW)($sp)
341     sdc1 $f28, (4 * 8 - BELOW)($sp)
342     sdc1 $f30, (5 * 8 - BELOW)($sp)
343 #endif
344     sw $ra, -4($sp)
346     sw $s0, (0 * 4)($sp)
347     sw $s1, (1 * 4)($sp)
348     sw $s2, (2 * 4)($sp)
349     sw $s3, (3 * 4)($sp)
350     sw $s4, (4 * 4)($sp)
351     sw $s5, (5 * 4)($sp)
352     sw $s6, (6 * 4)($sp)
353     sw $s7, (7 * 4)($sp)
354     sw $s8, (8 * 4)($sp)
355     sw $gp, (9 * 4)($sp)
357     // swap stack pointer
358     sw $sp, 0($a0)
359     move $sp, $a1
361 #ifdef __mips_hard_float
362     ldc1 $f20, (0 * 8 - BELOW)($sp)
363     ldc1 $f22, (1 * 8 - BELOW)($sp)
364     ldc1 $f24, (2 * 8 - BELOW)($sp)
365     ldc1 $f26, (3 * 8 - BELOW)($sp)
366     ldc1 $f28, (4 * 8 - BELOW)($sp)
367     ldc1 $f30, (5 * 8 - BELOW)($sp)
368 #endif
369     lw $ra, -4($sp)
371     lw $s0, (0 * 4)($sp)
372     lw $s1, (1 * 4)($sp)
373     lw $s2, (2 * 4)($sp)
374     lw $s3, (3 * 4)($sp)
375     lw $s4, (4 * 4)($sp)
376     lw $s5, (5 * 4)($sp)
377     lw $s6, (6 * 4)($sp)
378     lw $s7, (7 * 4)($sp)
379     lw $s8, (8 * 4)($sp)
380     lw $gp, (9 * 4)($sp)
382     addiu $sp, $sp, (10 * 4)
384     jr $ra // return
386 #elif defined(__arm__) && defined(__ARM_EABI__)
387 /************************************************************************************
388  * ARM ASM BITS
389  ************************************************************************************/
392  * Performs a context switch.
394  * Parameters:
395  * r0 - void** - ptr to old stack pointer
396  * r1 - void*  - new stack pointer
398  * ARM EABI registers:
399  * r0-r3   : argument/scratch registers
400  * r4-r10  : callee-save registers
401  * r11     : frame pointer (or a callee save register if fp isn't needed)
402  * r12 =ip : inter procedure register. We can treat it like any other scratch register
403  * r13 =sp : stack pointer
404  * r14 =lr : link register, it contains the return address (belonging to the function which called us)
405  * r15 =pc : program counter
407  * For floating point registers:
408  * According to AAPCS (version 2.09, section 5.1.2) only the d8-d15 registers need to be preserved
409  * across method calls. This applies to all ARM FPU variants, whether they have 16 or 32 double registers
410  * NEON support or not, half-float support or not and so on does not matter.
412  * Note: If this file was compiled with -mfloat-abi=soft but the code runs on a softfp system with fpu the d8-d15
413  * registers won't be saved (we do not know that the system has got a fpu in that case) but the registers might actually
414  * be used by other code if it was compiled with -mfloat-abi=softfp.
416  * Interworking is only supported on ARMv5+, not on ARM v4T as ARM v4t requires special stubs when changing
417  * from thumb to arm mode or the other way round.
418  */
420 .text
421 .align  2
422 .global fiber_switchContext
423 #if defined(__ARM_PCS_VFP) || (defined(__ARM_PCS) && !defined(__SOFTFP__)) // ARM_HardFloat  || ARM_SoftFP
424   .fpu vfp
425 #endif
426 .type   fiber_switchContext, %function
427 fiber_switchContext:
428     .fnstart
429     push {r4-r11}
430     // update the oldp pointer. Link register and floating point registers stored later to prevent the GC from
431     // scanning them.
432     str sp, [r0]
433     // push r0 (or any other register) as well to keep stack 8byte aligned
434     push {r0, lr}
436     #if defined(__ARM_PCS_VFP) || (defined(__ARM_PCS) && !defined(__SOFTFP__)) // ARM_HardFloat  || ARM_SoftFP
437       vpush {d8-d15}
438       // now switch over to the new stack. Need to subtract (8*8[d8-d15]+2*4[r0, lr]) to position stack pointer
439       // below the last saved register. Remember we saved the SP before pushing [r0, lr, d8-d15]
440       sub sp, r1, #72
441       vpop {d8-d15}
442     #else
443       sub sp, r1, #8
444     #endif
446     // we don't really care about r0, we only used that for padding.
447     // r1 is now what used to be in the link register when saving.
448     pop {r0, r1, r4-r11}
449     /**
450      * The link register for the initial jump to fiber_entryPoint must be zero: The jump actually
451      * looks like a normal method call as we jump to the start of the fiber_entryPoint function.
452      * Although fiber_entryPoint never returns and therefore never accesses lr, it saves lr to the stack.
453      * ARM unwinding will then look at the stack, find lr and think that fiber_entryPoint was called by
454      * the function in lr! So if we have some address in lr the unwinder will try to continue stack unwinding,
455      * although it's already at the stack base and crash.
456      * In all other cases the content of lr doesn't matter.
457      * Note: If we simply loaded into lr above and then moved lr into pc, the initial method call
458      * to fiber_entryPoint would look as if it was called from fiber_entryPoint itself, as the fiber_entryPoint
459      * address is in lr on the initial context switch.
460      */
461     mov lr, #0
462     // return by writing lr into pc
463     mov pc, r1
464     .fnend
466 #elif defined(__aarch64__)
467 /************************************************************************************
468  * AArch64 (arm64) ASM BITS
469  ************************************************************************************/
471  * preserve/restore AAPCS64 registers
472  *   x19-x28 5.1.1 64-bit callee saved
473  *   x29 fp, or possibly callee saved reg - depends on platform choice 5.2.3)
474  *   x30 lr
475  *   d8-d15  5.1.2 says callee only must save bottom 64-bits (the "d" regs)
477  * saved regs on stack will look like:
478  *   19: x19
479  *   18: x20
480  *   ...
481  *   10: x28
482  *    9: x29 (fp)  <-- oldp / *newp save stack top
483  *    8: x30 (lr)
484  *    7: d8
485  *   ...
486  *    0: d15       <-- sp
487  */
488         .text
489         .global CSYM(fiber_switchContext)
490         .type   fiber_switchContext, %function
491         .p2align  2
492 CSYM(fiber_switchContext):
493         stp     d15, d14, [sp, #-20*8]!
494         stp     d13, d12, [sp, #2*8]
495         stp     d11, d10, [sp, #4*8]
496         stp     d9, d8,   [sp, #6*8]
497         stp     x30, x29, [sp, #8*8] // lr, fp
498         stp     x28, x27, [sp, #10*8]
499         stp     x26, x25, [sp, #12*8]
500         stp     x24, x23, [sp, #14*8]
501         stp     x22, x21, [sp, #16*8]
502         stp     x20, x19, [sp, #18*8]
504         // oldp is set above saved lr (x30) to hide it and float regs
505         // from GC
506         add     x19, sp, #9*8
507         str     x19, [x0]       // *oldp tstack
508         sub     sp, x1, #9*8    // switch to newp sp
510         ldp     x20, x19, [sp, #18*8]
511         ldp     x22, x21, [sp, #16*8]
512         ldp     x24, x23, [sp, #14*8]
513         ldp     x26, x25, [sp, #12*8]
514         ldp     x28, x27, [sp, #10*8]
515         ldp     x30, x29, [sp, #8*8] // lr, fp
516         ldp     d9, d8,   [sp, #6*8]
517         ldp     d11, d10, [sp, #4*8]
518         ldp     d13, d12, [sp, #2*8]
519         ldp     d15, d14, [sp], #20*8
520         ret
524  * When generating any kind of backtrace (gdb, exception handling) for
525  * a function called in a Fiber, we need to tell the unwinder to stop
526  * at our Fiber main entry point, i.e. we need to mark the bottom of
527  * the call stack. This can be done by clearing the link register lr
528  * prior to calling fiber_entryPoint (i.e. in fiber_switchContext) or
529  * using a .cfi_undefined directive for the link register in the
530  * Fiber entry point. cfi_undefined seems to yield better results in gdb.
531  * Unfortunately we can't place it into fiber_entryPoint using inline
532  * asm, so we use this trampoline instead.
533  */
534         .text
535         .global CSYM(fiber_trampoline)
536         .p2align  2
537         .type   fiber_trampoline, %function
538 CSYM(fiber_trampoline):
539         .cfi_startproc
540         .cfi_undefined x30
541         // fiber_entryPoint never returns
542         bl fiber_entryPoint
543         .cfi_endproc
545 #elif defined(__MINGW32__)
546 /************************************************************************************
547  * GDC MinGW ASM BITS
548  ************************************************************************************/
549 #if defined(__x86_64__)
550 .global fiber_switchContext
551 fiber_switchContext:
552     pushq %RBP;
553     movq %RSP, %RBP;
554     pushq %RBX;
555     pushq %R12;
556     pushq %R13;
557     pushq %R14;
558     pushq %R15;
559     pushq %GS:0;
560     pushq %GS:8;
561     pushq %GS:16;
563     // store oldp
564     movq %RSP, (%RCX);
565     // load newp to begin context switch
566     movq %RDX, %RSP;
568     // load saved state from new stack
569     popq %GS:16;
570     popq %GS:8;
571     popq %GS:0;
572     popq %R15;
573     popq %R14;
574     popq %R13;
575     popq %R12;
576     popq %RBX;
577     popq %RBP;
579     // 'return' to complete switch
580     popq %RCX;
581     jmp *%RCX;
582 #elif defined(_X86_)
583 .global _fiber_switchContext
584 _fiber_switchContext:
585     // Save current stack state.save current stack state
586     // Standard CDECL prologue.
587     push %EBP;
588     mov  %ESP, %EBP;
589     push %EDI;
590     push %ESI;
591     push %EBX;
592     push %FS:0;
593     push %FS:4;
594     push %FS:8;
595     push %EAX;
597     // store oldp again with more accurate address
598     mov 8(%EBP), %EAX;
599     mov %ESP, (%EAX);
600     // load newp to begin context switch
601     mov 12(%EBP), %ESP;
603     // load saved state from new stack
604     pop %EAX;
605     pop %FS:8;
606     pop %FS:4;
607     pop %FS:0;
608     pop %EBX;
609     pop %ESI;
610     pop %EDI;
611     pop %EBP;
613     // 'return' to complete switch
614     ret;
615 #endif
617 // if POSIX boils down to this (reference http://nadeausoftware.com)
618 #elif !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
619 /************************************************************************************
620  * i386- and x86_64-apple-darwin POSIX ASM BITS
621  ************************************************************************************/
622 #if defined(__i386__)
623 .text
624 .p2align 4
625 .globl CSYM(fiber_switchContext)
626 CSYM(fiber_switchContext):
627     // save current stack state
628     push %ebp
629     mov  %esp, %ebp
630     push %edi
631     push %esi
632     push %ebx
633     push %eax
635     // store oldp again with more accurate address
636     mov 8(%ebp), %eax
637     mov %esp, (%eax)
638     // load newp to begin context switch
639     mov 12(%ebp), %esp
641     // load saved state from new stack
642     pop %eax
643     pop %ebx
644     pop %esi
645     pop %edi
646     pop %ebp
648     // 'return' to complete switch
649     ret
651 #elif defined(__x86_64__) && !defined(__ILP32__)
652 .text
653 .p2align 4
654 .globl CSYM(fiber_switchContext)
655 CSYM(fiber_switchContext):
656     // Save current stack state.save current stack state
657     push %rbp
658     mov  %rsp, %rbp
659     push %rbx
660     push %r12
661     push %r13
662     push %r14
663     push %r15
665     // store oldp again with more accurate address
666     mov %rsp, (%rdi)
667     // load newp to begin context switch
668     mov %rsi, %rsp
670     // load saved state from new stack
671     pop %r15
672     pop %r14
673     pop %r13
674     pop %r12
675     pop %rbx
676     pop %rbp
678     // 'return' to complete switch
679     ret
680 #endif  // __x86_64__ && !__ILP32__
682 #endif  // posix