111
|
1 /* -----------------------------------------------------------------------
|
|
2 sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
|
|
3 Copyright (c) 2011 Plausible Labs Cooperative, Inc.
|
|
4
|
|
5 ARM Foreign Function Interface
|
|
6
|
|
7 Permission is hereby granted, free of charge, to any person obtaining
|
|
8 a copy of this software and associated documentation files (the
|
|
9 ``Software''), to deal in the Software without restriction, including
|
|
10 without limitation the rights to use, copy, modify, merge, publish,
|
|
11 distribute, sublicense, and/or sell copies of the Software, and to
|
|
12 permit persons to whom the Software is furnished to do so, subject to
|
|
13 the following conditions:
|
|
14
|
|
15 The above copyright notice and this permission notice shall be included
|
|
16 in all copies or substantial portions of the Software.
|
|
17
|
|
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
|
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
25 DEALINGS IN THE SOFTWARE.
|
|
26 ----------------------------------------------------------------------- */
|
|
27
|
|
28 #define LIBFFI_ASM
|
|
29 #include <fficonfig.h>
|
|
30 #include <ffi.h>
|
|
31 #include <ffi_cfi.h>
|
|
32 #include "internal.h"
|
|
33
|
|
34 /* GCC 4.8 provides __ARM_ARCH; construct it otherwise. */
|
|
35 #ifndef __ARM_ARCH
|
|
36 # if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|
|
37 || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|
|
38 || defined(__ARM_ARCH_7EM__)
|
|
39 # define __ARM_ARCH 7
|
|
40 # elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
|
41 || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|
|
42 || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
|
|
43 || defined(__ARM_ARCH_6M__)
|
|
44 # define __ARM_ARCH 6
|
|
45 # elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
|
|
46 || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
|
|
47 || defined(__ARM_ARCH_5TEJ__)
|
|
48 # define __ARM_ARCH 5
|
|
49 # else
|
|
50 # define __ARM_ARCH 4
|
|
51 # endif
|
|
52 #endif
|
|
53
|
|
54 /* Conditionally compile unwinder directives. */
|
|
55 .macro UNWIND text:vararg
|
|
56 #ifdef __ARM_EABI__
|
|
57 \text
|
|
58 #endif
|
|
59 .endm
|
|
60 #if defined(HAVE_AS_CFI_PSEUDO_OP) && defined(__ARM_EABI__)
|
|
61 .cfi_sections .debug_frame
|
|
62 #endif
|
|
63
|
|
64 #define CONCAT(a, b) CONCAT2(a, b)
|
|
65 #define CONCAT2(a, b) a ## b
|
|
66
|
|
67 #ifdef __USER_LABEL_PREFIX__
|
|
68 # define CNAME(X) CONCAT (__USER_LABEL_PREFIX__, X)
|
|
69 #else
|
|
70 # define CNAME(X) X
|
|
71 #endif
|
|
72 #ifdef __ELF__
|
|
73 # define SIZE(X) .size CNAME(X), . - CNAME(X)
|
|
74 # define TYPE(X, Y) .type CNAME(X), Y
|
|
75 #else
|
|
76 # define SIZE(X)
|
|
77 # define TYPE(X, Y)
|
|
78 #endif
|
|
79
|
|
80 #define ARM_FUNC_START(name, gl) \
|
|
81 .align 3; \
|
|
82 .ifne gl; .globl CNAME(name); FFI_HIDDEN(CNAME(name)); .endif; \
|
|
83 TYPE(name, %function); \
|
|
84 CNAME(name):
|
|
85
|
|
86 #define ARM_FUNC_END(name) \
|
|
87 SIZE(name)
|
|
88
|
|
89 /* Aid in defining a jump table with 8 bytes between entries. */
|
|
90 .macro E index
|
|
91 .if . - 0b - 8*\index
|
|
92 .error "type table out of sync"
|
|
93 .endif
|
|
94 .endm
|
|
95
|
|
96 .text
|
|
97 .syntax unified
|
|
98 .arm
|
|
99
|
|
100 /* We require interworking on LDM, which implies ARMv5T,
|
|
101 which implies the existance of BLX. */
|
|
102 .arch armv5t
|
|
103
|
|
104 /* Note that we use STC and LDC to encode VFP instructions,
|
|
105 so that we do not need ".fpu vfp", nor get that added to
|
|
106 the object file attributes. These will not be executed
|
|
107 unless the FFI_VFP abi is used. */
|
|
108
|
|
109 @ r0: stack
|
|
110 @ r1: frame
|
|
111 @ r2: fn
|
|
112 @ r3: vfp_used
|
|
113
|
|
114 ARM_FUNC_START(ffi_call_VFP, 1)
|
|
115 UNWIND .fnstart
|
|
116 cfi_startproc
|
|
117
|
|
118 cmp r3, #3 @ load only d0 if possible
|
|
119 ldcle p11, cr0, [r0] @ vldrle d0, [sp]
|
|
120 ldcgt p11, cr0, [r0], {16} @ vldmgt sp, {d0-d7}
|
|
121 add r0, r0, #64 @ discard the vfp register args
|
|
122 /* FALLTHRU */
|
|
123 ARM_FUNC_END(ffi_call_VFP)
|
|
124
|
|
125 ARM_FUNC_START(ffi_call_SYSV, 1)
|
|
126 stm r1, {fp, lr}
|
|
127 mov fp, r1
|
|
128
|
|
129 @ This is a bit of a lie wrt the origin of the unwind info, but
|
|
130 @ now we've got the usual frame pointer and two saved registers.
|
|
131 UNWIND .save {fp,lr}
|
|
132 UNWIND .setfp fp, sp
|
|
133 cfi_def_cfa(fp, 8)
|
|
134 cfi_rel_offset(fp, 0)
|
|
135 cfi_rel_offset(lr, 4)
|
|
136
|
|
137 mov sp, r0 @ install the stack pointer
|
|
138 mov lr, r2 @ move the fn pointer out of the way
|
|
139 ldr ip, [fp, #16] @ install the static chain
|
|
140 ldmia sp!, {r0-r3} @ move first 4 parameters in registers.
|
|
141 blx lr @ call fn
|
|
142
|
|
143 @ Load r2 with the pointer to storage for the return value
|
|
144 @ Load r3 with the return type code
|
|
145 ldr r2, [fp, #8]
|
|
146 ldr r3, [fp, #12]
|
|
147
|
|
148 @ Deallocate the stack with the arguments.
|
|
149 mov sp, fp
|
|
150 cfi_def_cfa_register(sp)
|
|
151
|
|
152 @ Store values stored in registers.
|
|
153 .align 3
|
|
154 add pc, pc, r3, lsl #3
|
|
155 nop
|
|
156 0:
|
|
157 E ARM_TYPE_VFP_S
|
|
158 stc p10, cr0, [r2] @ vstr s0, [r2]
|
|
159 pop {fp,pc}
|
|
160 E ARM_TYPE_VFP_D
|
|
161 stc p11, cr0, [r2] @ vstr d0, [r2]
|
|
162 pop {fp,pc}
|
|
163 E ARM_TYPE_VFP_N
|
|
164 stc p11, cr0, [r2], {8} @ vstm r2, {d0-d3}
|
|
165 pop {fp,pc}
|
|
166 E ARM_TYPE_INT64
|
|
167 str r1, [r2, #4]
|
|
168 nop
|
|
169 E ARM_TYPE_INT
|
|
170 str r0, [r2]
|
|
171 pop {fp,pc}
|
|
172 E ARM_TYPE_VOID
|
|
173 pop {fp,pc}
|
|
174 nop
|
|
175 E ARM_TYPE_STRUCT
|
|
176 pop {fp,pc}
|
|
177
|
|
178 cfi_endproc
|
|
179 UNWIND .fnend
|
|
180 ARM_FUNC_END(ffi_call_SYSV)
|
|
181
|
|
182
|
|
183 /*
|
|
184 int ffi_closure_inner_* (cif, fun, user_data, frame)
|
|
185 */
|
|
186
|
|
187 ARM_FUNC_START(ffi_go_closure_SYSV, 1)
|
|
188 cfi_startproc
|
|
189 stmdb sp!, {r0-r3} @ save argument regs
|
|
190 cfi_adjust_cfa_offset(16)
|
|
191 ldr r0, [ip, #4] @ load cif
|
|
192 ldr r1, [ip, #8] @ load fun
|
|
193 mov r2, ip @ load user_data
|
|
194 b 0f
|
|
195 cfi_endproc
|
|
196 ARM_FUNC_END(ffi_go_closure_SYSV)
|
|
197
|
|
198 ARM_FUNC_START(ffi_closure_SYSV, 1)
|
|
199 UNWIND .fnstart
|
|
200 cfi_startproc
|
|
201 stmdb sp!, {r0-r3} @ save argument regs
|
|
202 cfi_adjust_cfa_offset(16)
|
|
203 ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif
|
|
204 ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun
|
|
205 ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data
|
|
206 0:
|
|
207 add ip, sp, #16 @ compute entry sp
|
|
208 sub sp, sp, #64+32 @ allocate frame
|
|
209 cfi_adjust_cfa_offset(64+32)
|
|
210 stmdb sp!, {ip,lr}
|
|
211
|
|
212 /* Remember that EABI unwind info only applies at call sites.
|
|
213 We need do nothing except note the save of the stack pointer
|
|
214 and the link registers. */
|
|
215 UNWIND .save {sp,lr}
|
|
216 cfi_adjust_cfa_offset(8)
|
|
217 cfi_rel_offset(lr, 4)
|
|
218
|
|
219 add r3, sp, #8 @ load frame
|
|
220 bl CNAME(ffi_closure_inner_SYSV)
|
|
221
|
|
222 @ Load values returned in registers.
|
|
223 add r2, sp, #8+64 @ load result
|
|
224 adr r3, CNAME(ffi_closure_ret)
|
|
225 add pc, r3, r0, lsl #3
|
|
226 cfi_endproc
|
|
227 UNWIND .fnend
|
|
228 ARM_FUNC_END(ffi_closure_SYSV)
|
|
229
|
|
230 ARM_FUNC_START(ffi_go_closure_VFP, 1)
|
|
231 cfi_startproc
|
|
232 stmdb sp!, {r0-r3} @ save argument regs
|
|
233 cfi_adjust_cfa_offset(16)
|
|
234 ldr r0, [ip, #4] @ load cif
|
|
235 ldr r1, [ip, #8] @ load fun
|
|
236 mov r2, ip @ load user_data
|
|
237 b 0f
|
|
238 cfi_endproc
|
|
239 ARM_FUNC_END(ffi_go_closure_VFP)
|
|
240
|
|
241 ARM_FUNC_START(ffi_closure_VFP, 1)
|
|
242 UNWIND .fnstart
|
|
243 cfi_startproc
|
|
244 stmdb sp!, {r0-r3} @ save argument regs
|
|
245 cfi_adjust_cfa_offset(16)
|
|
246 ldr r0, [ip, #FFI_TRAMPOLINE_SIZE] @ load cif
|
|
247 ldr r1, [ip, #FFI_TRAMPOLINE_SIZE+4] @ load fun
|
|
248 ldr r2, [ip, #FFI_TRAMPOLINE_SIZE+8] @ load user_data
|
|
249 0:
|
|
250 add ip, sp, #16
|
|
251 sub sp, sp, #64+32 @ allocate frame
|
|
252 cfi_adjust_cfa_offset(64+32)
|
|
253 stc p11, cr0, [sp], {16} @ vstm sp, {d0-d7}
|
|
254 stmdb sp!, {ip,lr}
|
|
255
|
|
256 /* See above. */
|
|
257 UNWIND .save {sp,lr}
|
|
258 cfi_adjust_cfa_offset(8)
|
|
259 cfi_rel_offset(lr, 4)
|
|
260
|
|
261 add r3, sp, #8 @ load frame
|
|
262 bl CNAME(ffi_closure_inner_VFP)
|
|
263
|
|
264 @ Load values returned in registers.
|
|
265 add r2, sp, #8+64 @ load result
|
|
266 adr r3, CNAME(ffi_closure_ret)
|
|
267 add pc, r3, r0, lsl #3
|
|
268 cfi_endproc
|
|
269 UNWIND .fnend
|
|
270 ARM_FUNC_END(ffi_closure_VFP)
|
|
271
|
|
272 /* Load values returned in registers for both closure entry points.
|
|
273 Note that we use LDM with SP in the register set. This is deprecated
|
|
274 by ARM, but not yet unpredictable. */
|
|
275
|
|
276 ARM_FUNC_START(ffi_closure_ret, 0)
|
|
277 cfi_startproc
|
|
278 cfi_rel_offset(sp, 0)
|
|
279 cfi_rel_offset(lr, 4)
|
|
280 0:
|
|
281 E ARM_TYPE_VFP_S
|
|
282 ldc p10, cr0, [r2] @ vldr s0, [r2]
|
|
283 ldm sp, {sp,pc}
|
|
284 E ARM_TYPE_VFP_D
|
|
285 ldc p11, cr0, [r2] @ vldr d0, [r2]
|
|
286 ldm sp, {sp,pc}
|
|
287 E ARM_TYPE_VFP_N
|
|
288 ldc p11, cr0, [r2], {8} @ vldm r2, {d0-d3}
|
|
289 ldm sp, {sp,pc}
|
|
290 E ARM_TYPE_INT64
|
|
291 ldr r1, [r2, #4]
|
|
292 nop
|
|
293 E ARM_TYPE_INT
|
|
294 ldr r0, [r2]
|
|
295 ldm sp, {sp,pc}
|
|
296 E ARM_TYPE_VOID
|
|
297 ldm sp, {sp,pc}
|
|
298 nop
|
|
299 E ARM_TYPE_STRUCT
|
|
300 ldm sp, {sp,pc}
|
|
301 cfi_endproc
|
|
302 ARM_FUNC_END(ffi_closure_ret)
|
|
303
|
|
304 #if FFI_EXEC_TRAMPOLINE_TABLE
|
|
305
|
|
306 /* ??? The iOS support should be updated. The first insn used to
|
|
307 be STMFD, but that's been moved into ffi_closure_SYSV. If the
|
|
308 writable page is put after this one we can make use of the
|
|
309 pc+8 feature of the architecture. We can also reduce the size
|
|
310 of the thunk to 8 and pack more of these into the page.
|
|
311
|
|
312 In the meantime, simply replace the STMFD with a NOP so as to
|
|
313 keep all the magic numbers the same within ffi.c. */
|
|
314
|
|
315 .align 12
|
|
316 ARM_FUNC_START(ffi_closure_trampoline_table_page)
|
|
317 .rept 4096 / 12
|
|
318 nop
|
|
319 ldr ip, [pc, #-4092]
|
|
320 ldr pc, [pc, #-4092]
|
|
321 .endr
|
|
322
|
|
323 #else
|
|
324
|
|
325 ARM_FUNC_START(ffi_arm_trampoline, 1)
|
|
326 0: adr ip, 0b
|
|
327 ldr pc, 1f
|
|
328 1: .long 0
|
|
329 ARM_FUNC_END(ffi_arm_trampoline)
|
|
330
|
|
331 #endif /* FFI_EXEC_TRAMPOLINE_TABLE */
|
|
332
|
|
333 #if defined __ELF__ && defined __linux__
|
|
334 .section .note.GNU-stack,"",%progbits
|
|
335 #endif
|