1/* 2 * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * ``Software''), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included 13 * in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24/* 25 * vax Foreign Function Interface 26 * 27 * This file attempts to provide all the FFI entry points which can reliably 28 * be implemented in C. 29 */ 30 31#include <ffi.h> 32#include <ffi_common.h> 33 34#include <stdlib.h> 35#include <unistd.h> 36 37#define CIF_FLAGS_CHAR 1 /* for struct only */ 38#define CIF_FLAGS_SHORT 2 /* for struct only */ 39#define CIF_FLAGS_INT 4 40#define CIF_FLAGS_DINT 8 41 42/* 43 * Foreign Function Interface API 44 */ 45 46void ffi_call_elfbsd (extended_cif *, unsigned, unsigned, void *, 47 void (*) ()); 48void *ffi_prep_args (extended_cif *ecif, void *stack); 49 50void * 51ffi_prep_args (extended_cif *ecif, void *stack) 52{ 53 unsigned int i; 54 void **p_argv; 55 char *argp; 56 ffi_type **p_arg; 57 void *struct_value_ptr; 58 59 argp = stack; 60 61 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT 62 && !ecif->cif->flags) 63 struct_value_ptr = ecif->rvalue; 64 else 65 struct_value_ptr = NULL; 66 67 p_argv = ecif->avalue; 68 69 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; 70 i != 0; 71 i--, p_arg++) 72 { 73 size_t z; 74 75 z = (*p_arg)->size; 76 if (z < sizeof (int)) 77 { 78 switch ((*p_arg)->type) 79 { 80 case FFI_TYPE_SINT8: 81 *(signed int *) argp = (signed int) *(SINT8 *) *p_argv; 82 break; 83 84 case FFI_TYPE_UINT8: 85 *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv; 86 break; 87 88 case FFI_TYPE_SINT16: 89 *(signed int *) argp = (signed int) *(SINT16 *) *p_argv; 90 break; 91 92 case FFI_TYPE_UINT16: 93 *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv; 94 break; 95 96 case FFI_TYPE_STRUCT: 97 memcpy (argp, *p_argv, z); 98 break; 99 100 default: 101 FFI_ASSERT (0); 102 } 103 z = sizeof (int); 104 } 105 else 106 { 107 memcpy (argp, *p_argv, z); 108 109 /* Align if necessary. */ 110 if ((sizeof(int) - 1) & z) 111 z = ALIGN(z, sizeof(int)); 112 } 113 114 p_argv++; 115 argp += z; 116 } 117 118 return struct_value_ptr; 119} 120 121ffi_status 122ffi_prep_cif_machdep (ffi_cif *cif) 123{ 124 /* Set the return type flag */ 125 switch (cif->rtype->type) 126 { 127 case FFI_TYPE_VOID: 128 cif->flags = 0; 129 break; 130 131 case FFI_TYPE_STRUCT: 132 if (cif->rtype->elements[0]->type == FFI_TYPE_STRUCT && 133 cif->rtype->elements[1]) 134 { 135 cif->flags = 0; 136 break; 137 } 138 139 if (cif->rtype->size == sizeof (char)) 140 cif->flags = CIF_FLAGS_CHAR; 141 else if (cif->rtype->size == sizeof (short)) 142 cif->flags = CIF_FLAGS_SHORT; 143 else if (cif->rtype->size == sizeof (int)) 144 cif->flags = CIF_FLAGS_INT; 145 else if (cif->rtype->size == 2 * sizeof (int)) 146 cif->flags = CIF_FLAGS_DINT; 147 else 148 cif->flags = 0; 149 break; 150 151 default: 152 if (cif->rtype->size <= sizeof (int)) 153 cif->flags = CIF_FLAGS_INT; 154 else 155 cif->flags = CIF_FLAGS_DINT; 156 break; 157 } 158 159 return FFI_OK; 160} 161 162void 163ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) 164{ 165 extended_cif ecif; 166 167 ecif.cif = cif; 168 ecif.avalue = avalue; 169 170 /* If the return value is a struct and we don't have a return value 171 address then we need to make one. */ 172 173 if (rvalue == NULL 174 && cif->rtype->type == FFI_TYPE_STRUCT 175 && cif->flags == 0) 176 ecif.rvalue = alloca (cif->rtype->size); 177 else 178 ecif.rvalue = rvalue; 179 180 switch (cif->abi) 181 { 182 case FFI_ELFBSD: 183 ffi_call_elfbsd (&ecif, cif->bytes, cif->flags, ecif.rvalue, fn); 184 break; 185 186 default: 187 FFI_ASSERT (0); 188 break; 189 } 190} 191 192/* 193 * Closure API 194 */ 195 196void ffi_closure_elfbsd (void); 197void ffi_closure_struct_elfbsd (void); 198unsigned int ffi_closure_elfbsd_inner (ffi_closure *, void *, char *); 199 200static void 201ffi_prep_closure_elfbsd (ffi_cif *cif, void **avalue, char *stackp) 202{ 203 unsigned int i; 204 void **p_argv; 205 ffi_type **p_arg; 206 207 p_argv = avalue; 208 209 for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++) 210 { 211 size_t z; 212 213 z = (*p_arg)->size; 214 *p_argv = stackp; 215 216 /* Align if necessary */ 217 if ((sizeof (int) - 1) & z) 218 z = ALIGN(z, sizeof (int)); 219 220 p_argv++; 221 stackp += z; 222 } 223} 224 225unsigned int 226ffi_closure_elfbsd_inner (ffi_closure *closure, void *resp, char *stack) 227{ 228 ffi_cif *cif; 229 void **arg_area; 230 231 cif = closure->cif; 232 arg_area = (void **) alloca (cif->nargs * sizeof (void *)); 233 234 ffi_prep_closure_elfbsd (cif, arg_area, stack); 235 236 (closure->fun) (cif, resp, arg_area, closure->user_data); 237 238 return cif->flags; 239} 240 241ffi_status 242ffi_prep_closure_loc (ffi_closure *closure, ffi_cif *cif, 243 void (*fun)(ffi_cif *, void *, void **, void *), 244 void *user_data, void *codeloc) 245{ 246 char *tramp = (char *) codeloc; 247 void *fn; 248 249 FFI_ASSERT (cif->abi == FFI_ELFBSD); 250 251 /* entry mask */ 252 *(unsigned short *)(tramp + 0) = 0x0000; 253 /* movl #closure, r0 */ 254 tramp[2] = 0xd0; 255 tramp[3] = 0x8f; 256 *(unsigned int *)(tramp + 4) = (unsigned int) closure; 257 tramp[8] = 0x50; 258 259 if (cif->rtype->type == FFI_TYPE_STRUCT 260 && !cif->flags) 261 fn = &ffi_closure_struct_elfbsd; 262 else 263 fn = &ffi_closure_elfbsd; 264 265 /* jmpl #fn */ 266 tramp[9] = 0x17; 267 tramp[10] = 0xef; 268 *(unsigned int *)(tramp + 11) = (unsigned int)fn + 2 - 269 (unsigned int)tramp - 9 - 6; 270 271 closure->cif = cif; 272 closure->user_data = user_data; 273 closure->fun = fun; 274 275 return FFI_OK; 276} 277