1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Only build this file if libffi is supported. 6 7// +build libffi 8 9package runtime 10 11import "unsafe" 12 13// This file contains the code that converts a Go type to an FFI type. 14// This has to be written in Go because it allocates memory in the Go heap. 15 16// C functions to return pointers to libffi variables. 17 18func ffi_type_pointer() *__ffi_type 19func ffi_type_sint8() *__ffi_type 20func ffi_type_sint16() *__ffi_type 21func ffi_type_sint32() *__ffi_type 22func ffi_type_sint64() *__ffi_type 23func ffi_type_uint8() *__ffi_type 24func ffi_type_uint16() *__ffi_type 25func ffi_type_uint32() *__ffi_type 26func ffi_type_uint64() *__ffi_type 27func ffi_type_float() *__ffi_type 28func ffi_type_double() *__ffi_type 29func ffi_supports_complex() bool 30func ffi_type_complex_float() *__ffi_type 31func ffi_type_complex_double() *__ffi_type 32func ffi_type_void() *__ffi_type 33 34// C functions defined in libffi. 35 36//extern ffi_prep_cif 37func ffi_prep_cif(*_ffi_cif, _ffi_abi, uint32, *__ffi_type, **__ffi_type) _ffi_status 38 39// ffiFuncToCIF is called from C code. 40//go:linkname ffiFuncToCIF 41 42// ffiFuncToCIF builds an _ffi_cif struct for function described by ft. 43func ffiFuncToCIF(ft *functype, isInterface bool, isMethod bool, cif *_ffi_cif) { 44 nparams := len(ft.in) 45 nargs := nparams 46 if isInterface { 47 nargs++ 48 } 49 args := make([]*__ffi_type, nargs) 50 i := 0 51 off := 0 52 if isInterface { 53 args[0] = ffi_type_pointer() 54 off = 1 55 } else if isMethod { 56 args[0] = ffi_type_pointer() 57 i = 1 58 } 59 for ; i < nparams; i++ { 60 args[i+off] = typeToFFI(ft.in[i]) 61 } 62 63 rettype := funcReturnFFI(ft) 64 65 var pargs **__ffi_type 66 if len(args) > 0 { 67 pargs = &args[0] 68 } 69 status := ffi_prep_cif(cif, _FFI_DEFAULT_ABI, uint32(nargs), rettype, pargs) 70 if status != _FFI_OK { 71 throw("ffi_prep_cif failed") 72 } 73} 74 75// funcReturnFFI returns the FFI definition of the return type of ft. 76func funcReturnFFI(ft *functype) *__ffi_type { 77 c := len(ft.out) 78 if c == 0 { 79 return ffi_type_void() 80 } 81 82 // Compile a function that returns a zero-sized value as 83 // though it returns void. This works around a problem in 84 // libffi: it can't represent a zero-sized value. 85 var size uintptr 86 for _, v := range ft.out { 87 size += v.size 88 } 89 if size == 0 { 90 return ffi_type_void() 91 } 92 93 if c == 1 { 94 return typeToFFI(ft.out[0]) 95 } 96 97 elements := make([]*__ffi_type, c+1) 98 for i, v := range ft.out { 99 elements[i] = typeToFFI(v) 100 } 101 elements[c] = nil 102 103 return &__ffi_type{ 104 _type: _FFI_TYPE_STRUCT, 105 elements: &elements[0], 106 } 107} 108 109// typeToFFI returns the __ffi_type for a Go type. 110func typeToFFI(typ *_type) *__ffi_type { 111 switch typ.kind & kindMask { 112 case kindBool: 113 switch unsafe.Sizeof(false) { 114 case 1: 115 return ffi_type_uint8() 116 case 4: 117 return ffi_type_uint32() 118 default: 119 throw("bad bool size") 120 return nil 121 } 122 case kindInt: 123 return intToFFI() 124 case kindInt8: 125 return ffi_type_sint8() 126 case kindInt16: 127 return ffi_type_sint16() 128 case kindInt32: 129 return ffi_type_sint32() 130 case kindInt64: 131 return ffi_type_sint64() 132 case kindUint: 133 switch unsafe.Sizeof(uint(0)) { 134 case 4: 135 return ffi_type_uint32() 136 case 8: 137 return ffi_type_uint64() 138 default: 139 throw("bad uint size") 140 return nil 141 } 142 case kindUint8: 143 return ffi_type_uint8() 144 case kindUint16: 145 return ffi_type_uint16() 146 case kindUint32: 147 return ffi_type_uint32() 148 case kindUint64: 149 return ffi_type_uint64() 150 case kindUintptr: 151 switch unsafe.Sizeof(uintptr(0)) { 152 case 4: 153 return ffi_type_uint32() 154 case 8: 155 return ffi_type_uint64() 156 default: 157 throw("bad uinptr size") 158 return nil 159 } 160 case kindFloat32: 161 return ffi_type_float() 162 case kindFloat64: 163 return ffi_type_double() 164 case kindComplex64: 165 if ffi_supports_complex() { 166 return ffi_type_complex_float() 167 } else { 168 return complexToFFI(ffi_type_float()) 169 } 170 case kindComplex128: 171 if ffi_supports_complex() { 172 return ffi_type_complex_double() 173 } else { 174 return complexToFFI(ffi_type_double()) 175 } 176 case kindArray: 177 return arrayToFFI((*arraytype)(unsafe.Pointer(typ))) 178 case kindChan, kindFunc, kindMap, kindPtr, kindUnsafePointer: 179 // These types are always simple pointers, and for FFI 180 // purposes nothing else matters. 181 return ffi_type_pointer() 182 case kindInterface: 183 return interfaceToFFI() 184 case kindSlice: 185 return sliceToFFI((*slicetype)(unsafe.Pointer(typ))) 186 case kindString: 187 return stringToFFI() 188 case kindStruct: 189 return structToFFI((*structtype)(unsafe.Pointer(typ))) 190 default: 191 throw("unknown type kind") 192 return nil 193 } 194} 195 196// interfaceToFFI returns an ffi_type for a Go interface type. 197// This is used for both empty and non-empty interface types. 198func interfaceToFFI() *__ffi_type { 199 elements := make([]*__ffi_type, 3) 200 elements[0] = ffi_type_pointer() 201 elements[1] = elements[0] 202 elements[2] = nil 203 return &__ffi_type{ 204 _type: _FFI_TYPE_STRUCT, 205 elements: &elements[0], 206 } 207} 208 209// stringToFFI returns an ffi_type for a Go string type. 210func stringToFFI() *__ffi_type { 211 elements := make([]*__ffi_type, 3) 212 elements[0] = ffi_type_pointer() 213 elements[1] = intToFFI() 214 elements[2] = nil 215 return &__ffi_type{ 216 _type: _FFI_TYPE_STRUCT, 217 elements: &elements[0], 218 } 219} 220 221// structToFFI returns an ffi_type for a Go struct type. 222func structToFFI(typ *structtype) *__ffi_type { 223 c := len(typ.fields) 224 if c == 0 { 225 return emptyStructToFFI() 226 } 227 if typ.typ.kind&kindDirectIface != 0 { 228 return ffi_type_pointer() 229 } 230 231 fields := make([]*__ffi_type, 0, c+1) 232 checkPad := false 233 lastzero := false 234 for i, v := range typ.fields { 235 // Skip zero-sized fields; they confuse libffi, 236 // and there is no value to pass in any case. 237 // We do have to check whether the alignment of the 238 // zero-sized field introduces any padding for the 239 // next field. 240 if v.typ.size == 0 { 241 checkPad = true 242 lastzero = true 243 continue 244 } 245 lastzero = false 246 247 if checkPad { 248 off := uintptr(0) 249 for j := i - 1; j >= 0; j-- { 250 if typ.fields[j].typ.size > 0 { 251 off = typ.fields[j].offset() + typ.fields[j].typ.size 252 break 253 } 254 } 255 off += uintptr(v.typ.align) - 1 256 off &^= uintptr(v.typ.align) - 1 257 if off != v.offset() { 258 fields = append(fields, padFFI(v.offset()-off)) 259 } 260 checkPad = false 261 } 262 263 fields = append(fields, typeToFFI(v.typ)) 264 } 265 266 if lastzero { 267 // The compiler adds one byte padding to non-empty struct ending 268 // with a zero-sized field (types.cc:get_backend_struct_fields). 269 // Add this padding to the FFI type. 270 fields = append(fields, ffi_type_uint8()) 271 } 272 273 fields = append(fields, nil) 274 275 return &__ffi_type{ 276 _type: _FFI_TYPE_STRUCT, 277 elements: &fields[0], 278 } 279} 280 281// sliceToFFI returns an ffi_type for a Go slice type. 282func sliceToFFI(typ *slicetype) *__ffi_type { 283 elements := make([]*__ffi_type, 4) 284 elements[0] = ffi_type_pointer() 285 elements[1] = intToFFI() 286 elements[2] = elements[1] 287 elements[3] = nil 288 return &__ffi_type{ 289 _type: _FFI_TYPE_STRUCT, 290 elements: &elements[0], 291 } 292} 293 294// complexToFFI returns an ffi_type for a Go complex type. 295// This is only used if libffi does not support complex types internally 296// for this target. 297func complexToFFI(ffiFloatType *__ffi_type) *__ffi_type { 298 elements := make([]*__ffi_type, 3) 299 elements[0] = ffiFloatType 300 elements[1] = ffiFloatType 301 elements[2] = nil 302 return &__ffi_type{ 303 _type: _FFI_TYPE_STRUCT, 304 elements: &elements[0], 305 } 306} 307 308// arrayToFFI returns an ffi_type for a Go array type. 309func arrayToFFI(typ *arraytype) *__ffi_type { 310 if typ.len == 0 { 311 return emptyStructToFFI() 312 } 313 if typ.typ.kind&kindDirectIface != 0 { 314 return ffi_type_pointer() 315 } 316 elements := make([]*__ffi_type, typ.len+1) 317 et := typeToFFI(typ.elem) 318 for i := uintptr(0); i < typ.len; i++ { 319 elements[i] = et 320 } 321 elements[typ.len] = nil 322 return &__ffi_type{ 323 _type: _FFI_TYPE_STRUCT, 324 elements: &elements[0], 325 } 326} 327 328// intToFFI returns an ffi_type for the Go int type. 329func intToFFI() *__ffi_type { 330 switch unsafe.Sizeof(0) { 331 case 4: 332 return ffi_type_sint32() 333 case 8: 334 return ffi_type_sint64() 335 default: 336 throw("bad int size") 337 return nil 338 } 339} 340 341// emptyStructToFFI returns an ffi_type for an empty struct. 342// The libffi library won't accept a struct with no fields. 343func emptyStructToFFI() *__ffi_type { 344 elements := make([]*__ffi_type, 2) 345 elements[0] = ffi_type_void() 346 elements[1] = nil 347 return &__ffi_type{ 348 _type: _FFI_TYPE_STRUCT, 349 elements: &elements[0], 350 } 351} 352 353// padFFI returns a padding field of the given size 354func padFFI(size uintptr) *__ffi_type { 355 elements := make([]*__ffi_type, size+1) 356 for i := uintptr(0); i < size; i++ { 357 elements[i] = ffi_type_uint8() 358 } 359 elements[size] = nil 360 return &__ffi_type{ 361 _type: _FFI_TYPE_STRUCT, 362 elements: &elements[0], 363 } 364} 365 366//go:linkname makeCIF reflect.makeCIF 367 368// makeCIF is used by the reflect package to allocate a CIF. 369func makeCIF(ft *functype) *_ffi_cif { 370 cif := new(_ffi_cif) 371 ffiFuncToCIF(ft, false, false, cif) 372 return cif 373} 374