1/* ----------------------------------------------------------------------- 2 sysv.S - Copyright (c) 1998, 2008, 2011 Red Hat, Inc. 3 Copyright (c) 2011 Plausible Labs Cooperative, Inc. 4 Copyright (c) 2019 Microsoft Corporation. 5 6 ARM Foreign Function Interface 7 8 Permission is hereby granted, free of charge, to any person obtaining 9 a copy of this software and associated documentation files (the 10 ``Software''), to deal in the Software without restriction, including 11 without limitation the rights to use, copy, modify, merge, publish, 12 distribute, sublicense, and/or sell copies of the Software, and to 13 permit persons to whom the Software is furnished to do so, subject to 14 the following conditions: 15 16 The above copyright notice and this permission notice shall be included 17 in all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 ----------------------------------------------------------------------- */ 28 29#define LIBFFI_ASM 30#include <fficonfig.h> 31#include <ffi.h> 32#include <ffi_cfi.h> 33#include "internal.h" 34#include "ksarm.h" 35 36 37 ; 8 byte aligned AREA to support 8 byte aligned jump tables 38 MACRO 39 NESTED_ENTRY_FFI $FuncName, $AreaName, $ExceptHandler 40 41 ; compute the function's labels 42 __DeriveFunctionLabels $FuncName 43 44 ; determine the area we will put the function into 45__FuncArea SETS "|.text|" 46 IF "$AreaName" != "" 47__FuncArea SETS "$AreaName" 48 ENDIF 49 50 ; set up the exception handler itself 51__FuncExceptionHandler SETS "" 52 IF "$ExceptHandler" != "" 53__FuncExceptionHandler SETS "|$ExceptHandler|" 54 ENDIF 55 56 ; switch to the specified area, jump tables require 8 byte alignment 57 AREA $__FuncArea,CODE,CODEALIGN,ALIGN=3,READONLY 58 59 ; export the function name 60 __ExportProc $FuncName 61 62 ; flush any pending literal pool stuff 63 ROUT 64 65 ; reset the state of the unwind code tracking 66 __ResetUnwindState 67 68 MEND 69 70; MACRO 71; TABLE_ENTRY $Type, $Table 72;$Type_$Table 73; MEND 74 75#define E(index,table) return_##index##_##table 76 77 ; r0: stack 78 ; r1: frame 79 ; r2: fn 80 ; r3: vfp_used 81 82 ; fake entry point exists only to generate exists only to 83 ; generate .pdata for exception unwinding 84 NESTED_ENTRY_FFI ffi_call_VFP_fake 85 PROLOG_PUSH {r11, lr} ; save fp and lr for unwind 86 87 ALTERNATE_ENTRY ffi_call_VFP 88 cmp r3, #3 ; load only d0 if possible 89 vldrle d0, [r0] 90 vldmgt r0, {d0-d7} 91 add r0, r0, #64 ; discard the vfp register args 92 b ffi_call_SYSV 93 NESTED_END ffi_call_VFP_fake 94 95 ; fake entry point exists only to generate exists only to 96 ; generate .pdata for exception unwinding 97 NESTED_ENTRY_FFI ffi_call_SYSV_fake 98 PROLOG_PUSH {r11, lr} ; save fp and lr for unwind 99 100 ALTERNATE_ENTRY ffi_call_SYSV 101 stm r1, {fp, lr} 102 mov fp, r1 103 104 mov sp, r0 ; install the stack pointer 105 mov lr, r2 ; move the fn pointer out of the way 106 ldr ip, [fp, #16] ; install the static chain 107 ldmia sp!, {r0-r3} ; move first 4 parameters in registers. 108 blx lr ; call fn 109 110 ; Load r2 with the pointer to storage for the return value 111 ; Load r3 with the return type code 112 ldr r2, [fp, #8] 113 ldr r3, [fp, #12] 114 115 ; Deallocate the stack with the arguments. 116 mov sp, fp 117 118 ; Store values stored in registers. 119 ALIGN 8 120 lsl r3, #3 121 add r3, r3, pc 122 add r3, #8 123 mov pc, r3 124 125 126E(ARM_TYPE_VFP_S, ffi_call) 127 ALIGN 8 128 vstr s0, [r2] 129 pop {fp,pc} 130E(ARM_TYPE_VFP_D, ffi_call) 131 ALIGN 8 132 vstr d0, [r2] 133 pop {fp,pc} 134E(ARM_TYPE_VFP_N, ffi_call) 135 ALIGN 8 136 vstm r2, {d0-d3} 137 pop {fp,pc} 138E(ARM_TYPE_INT64, ffi_call) 139 ALIGN 8 140 str r1, [r2, #4] 141 nop 142E(ARM_TYPE_INT, ffi_call) 143 ALIGN 8 144 str r0, [r2] 145 pop {fp,pc} 146E(ARM_TYPE_VOID, ffi_call) 147 ALIGN 8 148 pop {fp,pc} 149 nop 150E(ARM_TYPE_STRUCT, ffi_call) 151 ALIGN 8 152 cmp r3, #ARM_TYPE_STRUCT 153 pop {fp,pc} 154 NESTED_END ffi_call_SYSV_fake 155 156 IMPORT |ffi_closure_inner_SYSV| 157 /* 158 int ffi_closure_inner_SYSV 159 ( 160 cif, ; r0 161 fun, ; r1 162 user_data, ; r2 163 frame ; r3 164 ) 165 */ 166 167 NESTED_ENTRY_FFI ffi_go_closure_SYSV 168 stmdb sp!, {r0-r3} ; save argument regs 169 ldr r0, [ip, #4] ; load cif 170 ldr r1, [ip, #8] ; load fun 171 mov r2, ip ; load user_data 172 b ffi_go_closure_SYSV_0 173 NESTED_END ffi_go_closure_SYSV 174 175 ; r3: ffi_closure 176 177 ; fake entry point exists only to generate exists only to 178 ; generate .pdata for exception unwinding 179 NESTED_ENTRY_FFI ffi_closure_SYSV_fake 180 PROLOG_PUSH {r11, lr} ; save fp and lr for unwind 181 ALTERNATE_ENTRY ffi_closure_SYSV 182 ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment) 183 stmdb sp!, {r0-r3} ; save argument regs 184 185 ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] ; ffi_closure->cif 186 ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] ; ffi_closure->fun 187 ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] ; ffi_closure->user_data 188 189 ALTERNATE_ENTRY ffi_go_closure_SYSV_0 190 add ip, sp, #16 ; compute entry sp 191 192 sub sp, sp, #64+32 ; allocate frame parameter (sizeof(vfp_space) = 64, sizeof(result) = 32) 193 mov r3, sp ; set frame parameter 194 stmdb sp!, {ip,lr} 195 196 bl ffi_closure_inner_SYSV ; call the Python closure 197 198 ; Load values returned in registers. 199 add r2, sp, #64+8 ; address of closure_frame->result 200 bl ffi_closure_ret ; move result to correct register or memory for type 201 202 ldmfd sp!, {ip,lr} 203 mov sp, ip ; restore stack pointer 204 mov pc, lr 205 NESTED_END ffi_closure_SYSV_fake 206 207 IMPORT |ffi_closure_inner_VFP| 208 /* 209 int ffi_closure_inner_VFP 210 ( 211 cif, ; r0 212 fun, ; r1 213 user_data, ; r2 214 frame ; r3 215 ) 216 */ 217 218 NESTED_ENTRY_FFI ffi_go_closure_VFP 219 stmdb sp!, {r0-r3} ; save argument regs 220 ldr r0, [ip, #4] ; load cif 221 ldr r1, [ip, #8] ; load fun 222 mov r2, ip ; load user_data 223 b ffi_go_closure_VFP_0 224 NESTED_END ffi_go_closure_VFP 225 226 ; fake entry point exists only to generate exists only to 227 ; generate .pdata for exception unwinding 228 ; r3: closure 229 NESTED_ENTRY_FFI ffi_closure_VFP_fake 230 PROLOG_PUSH {r11, lr} ; save fp and lr for unwind 231 232 ALTERNATE_ENTRY ffi_closure_VFP 233 ldmfd sp!, {ip,r0} ; restore fp (r0 is used for stack alignment) 234 stmdb sp!, {r0-r3} ; save argument regs 235 236 ldr r0, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET] ; load cif 237 ldr r1, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+4] ; load fun 238 ldr r2, [ip, #FFI_TRAMPOLINE_CLOSURE_OFFSET+8] ; load user_data 239 240 ALTERNATE_ENTRY ffi_go_closure_VFP_0 241 add ip, sp, #16 ; compute entry sp 242 sub sp, sp, #32 ; save space for closure_frame->result 243 vstmdb sp!, {d0-d7} ; push closure_frame->vfp_space 244 245 mov r3, sp ; save closure_frame 246 stmdb sp!, {ip,lr} 247 248 bl ffi_closure_inner_VFP 249 250 ; Load values returned in registers. 251 add r2, sp, #64+8 ; load result 252 bl ffi_closure_ret 253 ldmfd sp!, {ip,lr} 254 mov sp, ip ; restore stack pointer 255 mov pc, lr 256 NESTED_END ffi_closure_VFP_fake 257 258/* Load values returned in registers for both closure entry points. 259 Note that we use LDM with SP in the register set. This is deprecated 260 by ARM, but not yet unpredictable. */ 261 262 NESTED_ENTRY_FFI ffi_closure_ret 263 stmdb sp!, {fp,lr} 264 265 ALIGN 8 266 lsl r0, #3 267 add r0, r0, pc 268 add r0, #8 269 mov pc, r0 270 271E(ARM_TYPE_VFP_S, ffi_closure) 272 ALIGN 8 273 vldr s0, [r2] 274 b call_epilogue 275E(ARM_TYPE_VFP_D, ffi_closure) 276 ALIGN 8 277 vldr d0, [r2] 278 b call_epilogue 279E(ARM_TYPE_VFP_N, ffi_closure) 280 ALIGN 8 281 vldm r2, {d0-d3} 282 b call_epilogue 283E(ARM_TYPE_INT64, ffi_closure) 284 ALIGN 8 285 ldr r1, [r2, #4] 286 nop 287E(ARM_TYPE_INT, ffi_closure) 288 ALIGN 8 289 ldr r0, [r2] 290 b call_epilogue 291E(ARM_TYPE_VOID, ffi_closure) 292 ALIGN 8 293 b call_epilogue 294 nop 295E(ARM_TYPE_STRUCT, ffi_closure) 296 ALIGN 8 297 b call_epilogue 298call_epilogue 299 ldmfd sp!, {fp,pc} 300 NESTED_END ffi_closure_ret 301 302 AREA |.trampoline|, DATA, THUMB, READONLY 303 EXPORT |ffi_arm_trampoline| 304|ffi_arm_trampoline| DATA 305thisproc adr ip, thisproc 306 stmdb sp!, {ip, r0} 307 ldr pc, [pc, #0] 308 DCD 0 309 ;ENDP 310 311 END