Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 1 | /* ----------------------------------------------------------------------- |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 2 | sysv.S - Copyright (c) 1998, 2008 Red Hat, Inc. |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 3 | |
| 4 | ARM Foreign Function Interface |
| 5 | |
| 6 | Permission is hereby granted, free of charge, to any person obtaining |
| 7 | a copy of this software and associated documentation files (the |
| 8 | ``Software''), to deal in the Software without restriction, including |
| 9 | without limitation the rights to use, copy, modify, merge, publish, |
| 10 | distribute, sublicense, and/or sell copies of the Software, and to |
| 11 | permit persons to whom the Software is furnished to do so, subject to |
| 12 | the following conditions: |
| 13 | |
| 14 | The above copyright notice and this permission notice shall be included |
| 15 | in all copies or substantial portions of the Software. |
| 16 | |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 17 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
| 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 24 | DEALINGS IN THE SOFTWARE. |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 25 | ----------------------------------------------------------------------- */ |
| 26 | |
| 27 | #define LIBFFI_ASM |
| 28 | #include <fficonfig.h> |
| 29 | #include <ffi.h> |
| 30 | #ifdef HAVE_MACHINE_ASM_H |
| 31 | #include <machine/asm.h> |
| 32 | #else |
| 33 | #ifdef __USER_LABEL_PREFIX__ |
| 34 | #define CONCAT1(a, b) CONCAT2(a, b) |
| 35 | #define CONCAT2(a, b) a ## b |
| 36 | |
| 37 | /* Use the right prefix for global labels. */ |
| 38 | #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) |
| 39 | #else |
| 40 | #define CNAME(x) x |
| 41 | #endif |
| 42 | #define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): |
| 43 | #endif |
| 44 | |
| 45 | #ifdef __ELF__ |
| 46 | #define LSYM(x) .x |
| 47 | #else |
| 48 | #define LSYM(x) x |
| 49 | #endif |
| 50 | |
| 51 | /* We need a better way of testing for this, but for now, this is all |
| 52 | we can do. */ |
| 53 | @ This selects the minimum architecture level required. |
| 54 | #define __ARM_ARCH__ 3 |
| 55 | |
| 56 | #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) |
| 57 | # undef __ARM_ARCH__ |
| 58 | # define __ARM_ARCH__ 4 |
| 59 | #endif |
| 60 | |
| 61 | #if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ |
| 62 | || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ |
| 63 | || defined(__ARM_ARCH_5TEJ__) |
| 64 | # undef __ARM_ARCH__ |
| 65 | # define __ARM_ARCH__ 5 |
| 66 | #endif |
| 67 | |
| 68 | #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ |
| 69 | || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 70 | || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \ |
| 71 | || defined(__ARM_ARCH_6M__) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 72 | # undef __ARM_ARCH__ |
| 73 | # define __ARM_ARCH__ 6 |
| 74 | #endif |
| 75 | |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 76 | #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ |
| 77 | || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ |
| 78 | || defined(__ARM_ARCH_7EM__) |
| 79 | # undef __ARM_ARCH__ |
| 80 | # define __ARM_ARCH__ 7 |
| 81 | #endif |
| 82 | |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 83 | #if __ARM_ARCH__ >= 5 |
| 84 | # define call_reg(x) blx x |
| 85 | #elif defined (__ARM_ARCH_4T__) |
| 86 | # define call_reg(x) mov lr, pc ; bx x |
| 87 | # if defined(__thumb__) || defined(__THUMB_INTERWORK__) |
| 88 | # define __INTERWORKING__ |
| 89 | # endif |
| 90 | #else |
| 91 | # define call_reg(x) mov lr, pc ; mov pc, x |
| 92 | #endif |
| 93 | |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 94 | /* Conditionally compile unwinder directives. */ |
| 95 | #ifdef __ARM_EABI__ |
| 96 | #define UNWIND |
| 97 | #else |
| 98 | #define UNWIND @ |
| 99 | #endif |
| 100 | |
| 101 | |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 102 | #if defined(__thumb__) && !defined(__THUMB_INTERWORK__) |
| 103 | .macro ARM_FUNC_START name |
| 104 | .text |
| 105 | .align 0 |
| 106 | .thumb |
| 107 | .thumb_func |
| 108 | ENTRY(\name) |
| 109 | bx pc |
| 110 | nop |
| 111 | .arm |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 112 | UNWIND .fnstart |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 113 | /* A hook to tell gdb that we've switched to ARM mode. Also used to call |
| 114 | directly from other local arm routines. */ |
| 115 | _L__\name: |
| 116 | .endm |
| 117 | #else |
| 118 | .macro ARM_FUNC_START name |
| 119 | .text |
| 120 | .align 0 |
| 121 | .arm |
| 122 | ENTRY(\name) |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 123 | UNWIND .fnstart |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 124 | .endm |
| 125 | #endif |
| 126 | |
| 127 | .macro RETLDM regs=, cond=, dirn=ia |
| 128 | #if defined (__INTERWORKING__) |
| 129 | .ifc "\regs","" |
| 130 | ldr\cond lr, [sp], #4 |
| 131 | .else |
| 132 | ldm\cond\dirn sp!, {\regs, lr} |
| 133 | .endif |
| 134 | bx\cond lr |
| 135 | #else |
| 136 | .ifc "\regs","" |
| 137 | ldr\cond pc, [sp], #4 |
| 138 | .else |
| 139 | ldm\cond\dirn sp!, {\regs, pc} |
| 140 | .endif |
| 141 | #endif |
| 142 | .endm |
| 143 | |
| 144 | |
| 145 | @ r0: ffi_prep_args |
| 146 | @ r1: &ecif |
| 147 | @ r2: cif->bytes |
| 148 | @ r3: fig->flags |
| 149 | @ sp+0: ecif.rvalue |
| 150 | @ sp+4: fn |
| 151 | |
| 152 | @ This assumes we are using gas. |
| 153 | ARM_FUNC_START ffi_call_SYSV |
| 154 | @ Save registers |
| 155 | stmfd sp!, {r0-r3, fp, lr} |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 156 | UNWIND .save {r0-r3, fp, lr} |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 157 | mov fp, sp |
| 158 | |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 159 | UNWIND .setfp fp, sp |
| 160 | |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 161 | @ Make room for all of the new args. |
| 162 | sub sp, fp, r2 |
| 163 | |
| 164 | @ Place all of the ffi_prep_args in position |
| 165 | mov ip, r0 |
| 166 | mov r0, sp |
| 167 | @ r1 already set |
| 168 | |
| 169 | @ Call ffi_prep_args(stack, &ecif) |
| 170 | call_reg(ip) |
| 171 | |
| 172 | @ move first 4 parameters in registers |
| 173 | ldmia sp, {r0-r3} |
| 174 | |
| 175 | @ and adjust stack |
| 176 | ldr ip, [fp, #8] |
| 177 | cmp ip, #16 |
| 178 | movhs ip, #16 |
| 179 | add sp, sp, ip |
| 180 | |
| 181 | @ call (fn) (...) |
| 182 | ldr ip, [fp, #28] |
| 183 | call_reg(ip) |
| 184 | |
| 185 | @ Remove the space we pushed for the args |
| 186 | mov sp, fp |
| 187 | |
| 188 | @ Load r2 with the pointer to storage for the return value |
| 189 | ldr r2, [sp, #24] |
| 190 | |
| 191 | @ Load r3 with the return type code |
| 192 | ldr r3, [sp, #12] |
| 193 | |
| 194 | @ If the return value pointer is NULL, assume no return value. |
| 195 | cmp r2, #0 |
| 196 | beq LSYM(Lepilogue) |
| 197 | |
| 198 | @ return INT |
| 199 | cmp r3, #FFI_TYPE_INT |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 200 | #if defined(__SOFTFP__) || defined(__ARM_EABI__) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 201 | cmpne r3, #FFI_TYPE_FLOAT |
| 202 | #endif |
| 203 | streq r0, [r2] |
| 204 | beq LSYM(Lepilogue) |
| 205 | |
| 206 | @ return INT64 |
| 207 | cmp r3, #FFI_TYPE_SINT64 |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 208 | #if defined(__SOFTFP__) || defined(__ARM_EABI__) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 209 | cmpne r3, #FFI_TYPE_DOUBLE |
| 210 | #endif |
| 211 | stmeqia r2, {r0, r1} |
| 212 | |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 213 | #if !defined(__SOFTFP__) && !defined(__ARM_EABI__) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 214 | beq LSYM(Lepilogue) |
| 215 | |
| 216 | @ return FLOAT |
| 217 | cmp r3, #FFI_TYPE_FLOAT |
| 218 | stfeqs f0, [r2] |
| 219 | beq LSYM(Lepilogue) |
| 220 | |
| 221 | @ return DOUBLE or LONGDOUBLE |
| 222 | cmp r3, #FFI_TYPE_DOUBLE |
| 223 | stfeqd f0, [r2] |
| 224 | #endif |
| 225 | |
| 226 | LSYM(Lepilogue): |
| 227 | RETLDM "r0-r3,fp" |
| 228 | |
| 229 | .ffi_call_SYSV_end: |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 230 | UNWIND .fnend |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 231 | .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) |
| 232 | |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 233 | /* |
| 234 | unsigned int FFI_HIDDEN |
| 235 | ffi_closure_SYSV_inner (closure, respp, args) |
| 236 | ffi_closure *closure; |
| 237 | void **respp; |
| 238 | void *args; |
| 239 | */ |
| 240 | |
| 241 | ARM_FUNC_START ffi_closure_SYSV |
| 242 | UNWIND .pad #16 |
| 243 | add ip, sp, #16 |
| 244 | stmfd sp!, {ip, lr} |
| 245 | UNWIND .save {r0, lr} |
| 246 | add r2, sp, #8 |
| 247 | .pad #16 |
| 248 | sub sp, sp, #16 |
| 249 | str sp, [sp, #8] |
| 250 | add r1, sp, #8 |
| 251 | bl ffi_closure_SYSV_inner |
| 252 | cmp r0, #FFI_TYPE_INT |
| 253 | beq .Lretint |
| 254 | |
| 255 | cmp r0, #FFI_TYPE_FLOAT |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 256 | #if defined(__SOFTFP__) || defined(__ARM_EABI__) |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 257 | beq .Lretint |
| 258 | #else |
| 259 | beq .Lretfloat |
| 260 | #endif |
| 261 | |
| 262 | cmp r0, #FFI_TYPE_DOUBLE |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 263 | #if defined(__SOFTFP__) || defined(__ARM_EABI__) |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 264 | beq .Lretlonglong |
| 265 | #else |
| 266 | beq .Lretdouble |
| 267 | #endif |
| 268 | |
| 269 | cmp r0, #FFI_TYPE_LONGDOUBLE |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 270 | #if defined(__SOFTFP__) || defined(__ARM_EABI__) |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 271 | beq .Lretlonglong |
| 272 | #else |
| 273 | beq .Lretlongdouble |
| 274 | #endif |
| 275 | |
| 276 | cmp r0, #FFI_TYPE_SINT64 |
| 277 | beq .Lretlonglong |
| 278 | .Lclosure_epilogue: |
| 279 | add sp, sp, #16 |
| 280 | ldmfd sp, {sp, pc} |
| 281 | .Lretint: |
| 282 | ldr r0, [sp] |
| 283 | b .Lclosure_epilogue |
| 284 | .Lretlonglong: |
| 285 | ldr r0, [sp] |
| 286 | ldr r1, [sp, #4] |
| 287 | b .Lclosure_epilogue |
| 288 | |
Matthias Klose | a834975 | 2010-03-15 13:25:28 +0000 | [diff] [blame^] | 289 | #if !defined(__SOFTFP__) && !defined(__ARM_EABI__) |
Christian Heimes | 7864476 | 2008-03-04 23:39:23 +0000 | [diff] [blame] | 290 | .Lretfloat: |
| 291 | ldfs f0, [sp] |
| 292 | b .Lclosure_epilogue |
| 293 | .Lretdouble: |
| 294 | ldfd f0, [sp] |
| 295 | b .Lclosure_epilogue |
| 296 | .Lretlongdouble: |
| 297 | ldfd f0, [sp] |
| 298 | b .Lclosure_epilogue |
| 299 | #endif |
| 300 | |
| 301 | .ffi_closure_SYSV_end: |
| 302 | UNWIND .fnend |
| 303 | .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) |
| 304 | |
| 305 | #if defined __ELF__ && defined __linux__ |
| 306 | .section .note.GNU-stack,"",%progbits |
| 307 | #endif |