github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/arm/sysv.S (about) 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