Mercurial > pub > dyncall > dyncall
diff dyncallback/dyncall_callback_ppc64.S @ 0:3e629dc19168
initial from svn dyncall-1745
author | Daniel Adler |
---|---|
date | Thu, 19 Mar 2015 22:24:28 +0100 |
parents | |
children | 7ca57dbefed4 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncallback/dyncall_callback_ppc64.S Thu Mar 19 22:24:28 2015 +0100 @@ -0,0 +1,215 @@ +/* + + Package: dyncall + Library: dyncallback + File: dyncallback/dyncall_callback_ppc64.S + Description: Callback Thunk - Implementation for PowerPC 64-bit + License: + + Copyright (c) 2014-2015 Masanori Mitsugi <mitsugi@linux.vnet.ibm.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +#include "../portasm/portasm-ppc.S" + +/* Callback Thunk Entry code for PowerPC 64-bit. */ + +/* Stack Frame Layout: + + 296 DCValue ( 8 ) + 112 DCArgs ( 64+104+8+4+4 = 184 ) + 48 Parameter area ( 8*8 = 64 ) + 0 Linkage area ( 48 ) + + +*/ + +/* Constants. */ +INT_REGS = 8 +FLOAT_REGS = 13 +SIZEOF_GPR = 8 +SIZEOF_FPR = 8 + +/* Linkage area. */ +LINK_SP = 0 +LINK_CR = 8 +LINK_LR = 16 +LINK_OFFSET = 0 +#if DC__ABI_PPC64_ELF_V == 2 +LINK_TOC = 24 +LINK_SIZE = 32 +#else +LINK_TOC = 40 +LINK_SIZE = 48 +#endif +/* Parameter area. */ +PAR_OFFSET = LINK_SIZE +#if DC__ABI_PPC64_ELF_V == 2 +PAR_SIZE = 0 +#else +PAR_SIZE = 64 +#endif +/* local struct DCArgs */ +ARGS_OFFSET = (PAR_OFFSET+PAR_SIZE) +ARGS_SIZE = (SIZEOF_GPR*INT_REGS)+(SIZEOF_FPR*FLOAT_REGS) + 8 + 4 * 4 +/* local struct DCValue */ +RESULT_OFFSET = (ARGS_OFFSET+ARGS_SIZE) +RESULT_SIZE = 8 +/* additional locals (reg 30/31) */ +LOCALS_OFFSET = (RESULT_OFFSET+RESULT_SIZE) +LOCALS_SIZE = 2*SIZEOF_GPR +/* total */ +FRAME_SIZE = ( (LOCALS_OFFSET+LOCALS_SIZE)+15 & (-16) ) + +/* struct DCCallback */ +#if DC__ABI_PPC64_ELF_V == 2 +DCB_THUNK = 0 +DCB_HANDLER = 48 +DCB_STACKCLEAN = 56 +DCB_USERDATA = 64 +#else +DCB_THUNK = 0 +DCB_HANDLER = 64 +DCB_STACKCLEAN = 72 +DCB_USERDATA = 80 +#endif + +/* struct DCArgs */ +DCA_IARRAY = 0 +DCA_FARRAY = SIZEOF_GPR*INT_REGS +DCA_SP = DCA_FARRAY + SIZEOF_FPR*FLOAT_REGS +DCA_ICOUNT = DCA_SP + 8 +DCA_FCOUNT = DCA_ICOUNT + 4 + +/* struct DCValue */ +DCV_INT = 0 +DCV_FLOAT = 0 +DCV_SIZE = 8 + +iregfile = ARGS_OFFSET+DCA_IARRAY +fregfile = ARGS_OFFSET+DCA_FARRAY +save_sp = ARGS_OFFSET+DCA_SP +icount = ARGS_OFFSET+DCA_ICOUNT +fcount = ARGS_OFFSET+DCA_FCOUNT + +/* + Thunk entry: + R2 = DCCallback* +*/ +.text + .global dcCallbackThunkEntry + .type dcCallbackThunkEntry, @function +#if DC__ABI_PPC64_ELF_V != 2 + .section .opd, "aw" + .align 3 +#endif + +dcCallbackThunkEntry: +#if DC__ABI_PPC64_ELF_V != 2 + .quad .dcCallbackThunkEntry, .TOC.@tocbase, 0 + .previous + .global .dcCallbackThunkEntry + +.dcCallbackThunkEntry: +#endif + mflr r0 + std r0, 16(r1) /* store return address */ + std r31, -8(r1) /* store preserved registers (r31) */ + addi r12, r1, PAR_OFFSET /* temporary r12 = parameter area on callers stack frame */ + stdu r1, -FRAME_SIZE(r1) /* save callers stack pointer and make new stack frame. */ + + std r3, iregfile+0*8(r1) /* spill 8 integer parameter registers */ + std r4, iregfile+1*8(r1) + std r5, iregfile+2*8(r1) + std r6, iregfile+3*8(r1) + std r7, iregfile+4*8(r1) + std r8, iregfile+5*8(r1) + std r9, iregfile+6*8(r1) + std r10,iregfile+7*8(r1) + stfd f1, fregfile+ 0*8(r1) /* spill 13 float parameter registers */ + stfd f2, fregfile+ 1*8(r1) + stfd f3, fregfile+ 2*8(r1) + stfd f4, fregfile+ 3*8(r1) + stfd f5, fregfile+ 4*8(r1) + stfd f6, fregfile+ 5*8(r1) + stfd f7, fregfile+ 6*8(r1) + stfd f8, fregfile+ 7*8(r1) + stfd f9, fregfile+ 8*8(r1) + stfd f10,fregfile+ 9*8(r1) + stfd f11,fregfile+10*8(r1) + stfd f12,fregfile+11*8(r1) + stfd f13,fregfile+12*8(r1) + /* initialize struct DCCallback */ + std r12,save_sp(r1) /* init stack pointer */ + xor r0, r0, r0 /* init register counters */ + std r0, icount(r1) + std r0, fcount(r1) + std r0, RESULT_OFFSET(r1) + /* invoke callback handler */ + mr r3, r11 /* arg 1: DCCallback* pcb */ + addi r4, r1, ARGS_OFFSET /* arg 2: DCArgs* args */ + addi r5, r1, RESULT_OFFSET /* arg 3: DCValue* result */ + ld r6, DCB_USERDATA(r11) /* arg 4: void* userdata */ + + /* branch-and-link to DCCallback.handler */ + ld r12, DCB_HANDLER(r11) + std r2, LINK_TOC(r1) +#if DC__ABI_PPC64_ELF_V != 2 + ld r2, 8(r12) + ld r0, 0(r12) + mtctr r0 +#else + mtctr r12 +#endif + bctrl + + addi r0, r1, RESULT_OFFSET /* r0 = DCValue* */ + /* switch on base result type */ + cmpi cr0, r3, 'B + beq .i64 + cmpi cr0, r3, 'i + beq .i64 + cmpi cr0, r3, 'c + beq .i64 + cmpi cr0, r3, 's + beq .i64 + cmpi cr0, r3, 'l + beq .i64 + cmpi cr0, r3, 'f + beq .f32 + cmpi cr0, r3, 'd + beq .f64 + cmpi cr0, r3, 'p + beq .i64 +.void: /* ignore result (void call) */ + b .end +.i64: /* result is 64-bit long long result */ + ld r3, RESULT_OFFSET + DCV_INT(r1) + b .end +.f32: /* result is C float result */ + lfs f1, RESULT_OFFSET + DCV_FLOAT(r1) + b .end +.f64: /* result is C double result */ + lfd f1, RESULT_OFFSET + DCV_FLOAT(r1) + b .end +.end: + + ld r2, LINK_TOC(r1) + ld r1, 0(r1) /* restore stack pointer */ + ld r31, -8(r1) /* restore preserved registers */ + ld r0, 16(r1) /* load link register with return address */ + mtlr r0 + blr /* branch back to link register */ +