0
|
1 /*
|
|
2
|
|
3 Package: dyncall
|
|
4 Library: dyncallback
|
|
5 File: dyncallback/dyncall_callback_ppc64.S
|
|
6 Description: Callback Thunk - Implementation for PowerPC 64-bit
|
|
7 License:
|
|
8
|
|
9 Copyright (c) 2014-2015 Masanori Mitsugi <mitsugi@linux.vnet.ibm.com>
|
|
10
|
|
11 Permission to use, copy, modify, and distribute this software for any
|
|
12 purpose with or without fee is hereby granted, provided that the above
|
|
13 copyright notice and this permission notice appear in all copies.
|
|
14
|
|
15 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
16 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
17 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
18 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
22
|
|
23 */
|
|
24
|
|
25 #include "../portasm/portasm-ppc.S"
|
|
26
|
|
27 /* Callback Thunk Entry code for PowerPC 64-bit. */
|
|
28
|
|
29 /* Stack Frame Layout:
|
|
30
|
|
31 296 DCValue ( 8 )
|
|
32 112 DCArgs ( 64+104+8+4+4 = 184 )
|
|
33 48 Parameter area ( 8*8 = 64 )
|
|
34 0 Linkage area ( 48 )
|
|
35
|
|
36
|
|
37 */
|
|
38
|
|
39 /* Constants. */
|
|
40 INT_REGS = 8
|
|
41 FLOAT_REGS = 13
|
|
42 SIZEOF_GPR = 8
|
|
43 SIZEOF_FPR = 8
|
|
44
|
|
45 /* Linkage area. */
|
|
46 LINK_SP = 0
|
|
47 LINK_CR = 8
|
|
48 LINK_LR = 16
|
|
49 LINK_OFFSET = 0
|
|
50 #if DC__ABI_PPC64_ELF_V == 2
|
|
51 LINK_TOC = 24
|
|
52 LINK_SIZE = 32
|
|
53 #else
|
|
54 LINK_TOC = 40
|
|
55 LINK_SIZE = 48
|
|
56 #endif
|
|
57 /* Parameter area. */
|
|
58 PAR_OFFSET = LINK_SIZE
|
|
59 #if DC__ABI_PPC64_ELF_V == 2
|
|
60 PAR_SIZE = 0
|
|
61 #else
|
|
62 PAR_SIZE = 64
|
|
63 #endif
|
|
64 /* local struct DCArgs */
|
|
65 ARGS_OFFSET = (PAR_OFFSET+PAR_SIZE)
|
|
66 ARGS_SIZE = (SIZEOF_GPR*INT_REGS)+(SIZEOF_FPR*FLOAT_REGS) + 8 + 4 * 4
|
|
67 /* local struct DCValue */
|
|
68 RESULT_OFFSET = (ARGS_OFFSET+ARGS_SIZE)
|
|
69 RESULT_SIZE = 8
|
|
70 /* additional locals (reg 30/31) */
|
|
71 LOCALS_OFFSET = (RESULT_OFFSET+RESULT_SIZE)
|
|
72 LOCALS_SIZE = 2*SIZEOF_GPR
|
|
73 /* total */
|
|
74 FRAME_SIZE = ( (LOCALS_OFFSET+LOCALS_SIZE)+15 & (-16) )
|
|
75
|
|
76 /* struct DCCallback */
|
|
77 #if DC__ABI_PPC64_ELF_V == 2
|
|
78 DCB_THUNK = 0
|
|
79 DCB_HANDLER = 48
|
|
80 DCB_STACKCLEAN = 56
|
|
81 DCB_USERDATA = 64
|
|
82 #else
|
|
83 DCB_THUNK = 0
|
|
84 DCB_HANDLER = 64
|
|
85 DCB_STACKCLEAN = 72
|
|
86 DCB_USERDATA = 80
|
|
87 #endif
|
|
88
|
|
89 /* struct DCArgs */
|
|
90 DCA_IARRAY = 0
|
|
91 DCA_FARRAY = SIZEOF_GPR*INT_REGS
|
|
92 DCA_SP = DCA_FARRAY + SIZEOF_FPR*FLOAT_REGS
|
|
93 DCA_ICOUNT = DCA_SP + 8
|
|
94 DCA_FCOUNT = DCA_ICOUNT + 4
|
|
95
|
|
96 /* struct DCValue */
|
|
97 DCV_INT = 0
|
|
98 DCV_FLOAT = 0
|
|
99 DCV_SIZE = 8
|
|
100
|
|
101 iregfile = ARGS_OFFSET+DCA_IARRAY
|
|
102 fregfile = ARGS_OFFSET+DCA_FARRAY
|
|
103 save_sp = ARGS_OFFSET+DCA_SP
|
|
104 icount = ARGS_OFFSET+DCA_ICOUNT
|
|
105 fcount = ARGS_OFFSET+DCA_FCOUNT
|
|
106
|
|
107 /*
|
|
108 Thunk entry:
|
|
109 R2 = DCCallback*
|
|
110 */
|
|
111 .text
|
|
112 .global dcCallbackThunkEntry
|
|
113 .type dcCallbackThunkEntry, @function
|
|
114 #if DC__ABI_PPC64_ELF_V != 2
|
|
115 .section .opd, "aw"
|
|
116 .align 3
|
|
117 #endif
|
|
118
|
|
119 dcCallbackThunkEntry:
|
|
120 #if DC__ABI_PPC64_ELF_V != 2
|
|
121 .quad .dcCallbackThunkEntry, .TOC.@tocbase, 0
|
|
122 .previous
|
|
123 .global .dcCallbackThunkEntry
|
|
124
|
|
125 .dcCallbackThunkEntry:
|
|
126 #endif
|
|
127 mflr r0
|
|
128 std r0, 16(r1) /* store return address */
|
|
129 std r31, -8(r1) /* store preserved registers (r31) */
|
|
130 addi r12, r1, PAR_OFFSET /* temporary r12 = parameter area on callers stack frame */
|
|
131 stdu r1, -FRAME_SIZE(r1) /* save callers stack pointer and make new stack frame. */
|
|
132
|
|
133 std r3, iregfile+0*8(r1) /* spill 8 integer parameter registers */
|
|
134 std r4, iregfile+1*8(r1)
|
|
135 std r5, iregfile+2*8(r1)
|
|
136 std r6, iregfile+3*8(r1)
|
|
137 std r7, iregfile+4*8(r1)
|
|
138 std r8, iregfile+5*8(r1)
|
|
139 std r9, iregfile+6*8(r1)
|
|
140 std r10,iregfile+7*8(r1)
|
|
141 stfd f1, fregfile+ 0*8(r1) /* spill 13 float parameter registers */
|
|
142 stfd f2, fregfile+ 1*8(r1)
|
|
143 stfd f3, fregfile+ 2*8(r1)
|
|
144 stfd f4, fregfile+ 3*8(r1)
|
|
145 stfd f5, fregfile+ 4*8(r1)
|
|
146 stfd f6, fregfile+ 5*8(r1)
|
|
147 stfd f7, fregfile+ 6*8(r1)
|
|
148 stfd f8, fregfile+ 7*8(r1)
|
|
149 stfd f9, fregfile+ 8*8(r1)
|
|
150 stfd f10,fregfile+ 9*8(r1)
|
|
151 stfd f11,fregfile+10*8(r1)
|
|
152 stfd f12,fregfile+11*8(r1)
|
|
153 stfd f13,fregfile+12*8(r1)
|
|
154 /* initialize struct DCCallback */
|
|
155 std r12,save_sp(r1) /* init stack pointer */
|
|
156 xor r0, r0, r0 /* init register counters */
|
|
157 std r0, icount(r1)
|
|
158 std r0, fcount(r1)
|
|
159 std r0, RESULT_OFFSET(r1)
|
|
160 /* invoke callback handler */
|
|
161 mr r3, r11 /* arg 1: DCCallback* pcb */
|
|
162 addi r4, r1, ARGS_OFFSET /* arg 2: DCArgs* args */
|
|
163 addi r5, r1, RESULT_OFFSET /* arg 3: DCValue* result */
|
|
164 ld r6, DCB_USERDATA(r11) /* arg 4: void* userdata */
|
|
165
|
|
166 /* branch-and-link to DCCallback.handler */
|
|
167 ld r12, DCB_HANDLER(r11)
|
|
168 std r2, LINK_TOC(r1)
|
|
169 #if DC__ABI_PPC64_ELF_V != 2
|
|
170 ld r2, 8(r12)
|
|
171 ld r0, 0(r12)
|
|
172 mtctr r0
|
|
173 #else
|
|
174 mtctr r12
|
|
175 #endif
|
|
176 bctrl
|
|
177
|
|
178 addi r0, r1, RESULT_OFFSET /* r0 = DCValue* */
|
|
179 /* switch on base result type */
|
|
180 cmpi cr0, r3, 'B
|
|
181 beq .i64
|
|
182 cmpi cr0, r3, 'i
|
|
183 beq .i64
|
|
184 cmpi cr0, r3, 'c
|
|
185 beq .i64
|
|
186 cmpi cr0, r3, 's
|
|
187 beq .i64
|
|
188 cmpi cr0, r3, 'l
|
|
189 beq .i64
|
|
190 cmpi cr0, r3, 'f
|
|
191 beq .f32
|
|
192 cmpi cr0, r3, 'd
|
|
193 beq .f64
|
|
194 cmpi cr0, r3, 'p
|
|
195 beq .i64
|
|
196 .void: /* ignore result (void call) */
|
|
197 b .end
|
|
198 .i64: /* result is 64-bit long long result */
|
|
199 ld r3, RESULT_OFFSET + DCV_INT(r1)
|
|
200 b .end
|
|
201 .f32: /* result is C float result */
|
|
202 lfs f1, RESULT_OFFSET + DCV_FLOAT(r1)
|
|
203 b .end
|
|
204 .f64: /* result is C double result */
|
|
205 lfd f1, RESULT_OFFSET + DCV_FLOAT(r1)
|
|
206 b .end
|
|
207 .end:
|
|
208
|
|
209 ld r2, LINK_TOC(r1)
|
|
210 ld r1, 0(r1) /* restore stack pointer */
|
|
211 ld r31, -8(r1) /* restore preserved registers */
|
|
212 ld r0, 16(r1) /* load link register with return address */
|
|
213 mtlr r0
|
|
214 blr /* branch back to link register */
|
|
215
|