c/ffi: import libffi
This commit is contained in:
7
c/ffi/abi.go
Normal file
7
c/ffi/abi.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64))
|
||||||
|
|
||||||
|
package ffi
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultAbi Abi = 1
|
||||||
|
)
|
||||||
7
c/ffi/abi_amd64.go
Normal file
7
c/ffi/abi_amd64.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build freebsd || linux || darwin
|
||||||
|
|
||||||
|
package ffi
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultAbi Abi = 2
|
||||||
|
)
|
||||||
98
c/ffi/ffi.go
Normal file
98
c/ffi/ffi.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package ffi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
"github.com/goplus/llgo/c/ffi/ffi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Type = ffi.Type
|
||||||
|
|
||||||
|
type Signature = ffi.Cif
|
||||||
|
|
||||||
|
type Abi c.Uint
|
||||||
|
|
||||||
|
type Error c.Uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
OK Error = iota
|
||||||
|
BAD_TYPEDEF
|
||||||
|
BAD_ABI
|
||||||
|
BAD_ARGTYPE
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Error) Error() string {
|
||||||
|
switch s {
|
||||||
|
case OK:
|
||||||
|
return "ok"
|
||||||
|
case BAD_TYPEDEF:
|
||||||
|
return "bad type def"
|
||||||
|
case BAD_ABI:
|
||||||
|
return "bad ABI"
|
||||||
|
case BAD_ARGTYPE:
|
||||||
|
return "bad argument type"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("invalid status: %v", int(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSignature(ret *Type, args ...*Type) (*Signature, error) {
|
||||||
|
var cif ffi.Cif
|
||||||
|
var atype **Type
|
||||||
|
if len(args) > 0 {
|
||||||
|
atype = &args[0]
|
||||||
|
}
|
||||||
|
status := ffi.PrepCif(&cif, c.Uint(DefaultAbi), c.Uint(len(args)), ret, atype)
|
||||||
|
if status == 0 {
|
||||||
|
return &cif, nil
|
||||||
|
}
|
||||||
|
return nil, Error(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSignatureVar(ret *Type, fixed int, args ...*Type) (*Signature, error) {
|
||||||
|
var cif ffi.Cif
|
||||||
|
var atype **Type
|
||||||
|
if len(args) > 0 {
|
||||||
|
atype = &args[0]
|
||||||
|
}
|
||||||
|
status := ffi.PrepCifVar(&cif, c.Uint(DefaultAbi), c.Uint(fixed), c.Uint(len(args)), ret, atype)
|
||||||
|
if status == 0 {
|
||||||
|
return &cif, nil
|
||||||
|
}
|
||||||
|
return nil, Error(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Call(cif *Signature, fn unsafe.Pointer, ret unsafe.Pointer, args ...unsafe.Pointer) {
|
||||||
|
var avalues *unsafe.Pointer
|
||||||
|
if len(args) > 0 {
|
||||||
|
avalues = &args[0]
|
||||||
|
}
|
||||||
|
ffi.Call(cif, fn, ret, avalues)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Closure struct {
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
Fn unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClosure() *Closure {
|
||||||
|
c := &Closure{}
|
||||||
|
c.ptr = ffi.ClosureAlloc(&c.Fn)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Closure) Free() {
|
||||||
|
if c != nil && c.ptr != nil {
|
||||||
|
ffi.ClosureFree(c.ptr)
|
||||||
|
c.ptr = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Pointer) error {
|
||||||
|
status := ffi.PreClosureLoc(c.ptr, cif, fn, userdata, c.Fn)
|
||||||
|
if status == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return Error(status)
|
||||||
|
}
|
||||||
5
c/ffi/ffi/_wrap/libffi.c
Normal file
5
c/ffi/ffi/_wrap/libffi.c
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include <ffi.h>
|
||||||
|
|
||||||
|
void *llog_ffi_closure_alloc(void **code) {
|
||||||
|
return ffi_closure_alloc(sizeof(ffi_closure), code);
|
||||||
|
}
|
||||||
117
c/ffi/ffi/ffi.go
Normal file
117
c/ffi/ffi/ffi.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package ffi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LLGoPackage = "link: $(pkg-config --libs libffi); -lffi"
|
||||||
|
LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Void = iota
|
||||||
|
Int
|
||||||
|
Float
|
||||||
|
Double
|
||||||
|
LongDouble
|
||||||
|
Uint8
|
||||||
|
Sint8
|
||||||
|
Uint16
|
||||||
|
Sint16
|
||||||
|
Uint32
|
||||||
|
Sint32
|
||||||
|
Uint64
|
||||||
|
Sint64
|
||||||
|
Struct
|
||||||
|
Pointer
|
||||||
|
Complex
|
||||||
|
)
|
||||||
|
|
||||||
|
type Type struct {
|
||||||
|
Size uintptr
|
||||||
|
Alignment uint16
|
||||||
|
Type uint16
|
||||||
|
Elements **Type
|
||||||
|
}
|
||||||
|
|
||||||
|
/*typedef struct {
|
||||||
|
ffi_abi abi;
|
||||||
|
unsigned nargs;
|
||||||
|
ffi_type **arg_types;
|
||||||
|
ffi_type *rtype;
|
||||||
|
unsigned bytes;
|
||||||
|
unsigned flags;
|
||||||
|
#ifdef FFI_EXTRA_CIF_FIELDS
|
||||||
|
FFI_EXTRA_CIF_FIELDS;
|
||||||
|
#endif
|
||||||
|
} ffi_cif;
|
||||||
|
*/
|
||||||
|
|
||||||
|
type Cif struct {
|
||||||
|
Abi c.Uint
|
||||||
|
NArgs c.Uint
|
||||||
|
ArgTypes **Type
|
||||||
|
RType *Type
|
||||||
|
Bytes c.Uint
|
||||||
|
Flags c.Uint
|
||||||
|
//Extra c.Uint
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ffi_status
|
||||||
|
ffi_prep_cif(ffi_cif *cif,
|
||||||
|
ffi_abi abi,
|
||||||
|
unsigned int nargs,
|
||||||
|
ffi_type *rtype,
|
||||||
|
ffi_type **atypes);
|
||||||
|
*/
|
||||||
|
//go:linkname PrepCif C.ffi_prep_cif
|
||||||
|
func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||||
|
|
||||||
|
/*
|
||||||
|
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
||||||
|
ffi_abi abi,
|
||||||
|
unsigned int nfixedargs,
|
||||||
|
unsigned int ntotalargs,
|
||||||
|
ffi_type *rtype,
|
||||||
|
ffi_type **atypes);
|
||||||
|
*/
|
||||||
|
//go:linkname PrepCifVar C.ffi_prep_cif_var
|
||||||
|
func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||||
|
|
||||||
|
/*
|
||||||
|
void ffi_call(ffi_cif *cif,
|
||||||
|
void (*fn)(void),
|
||||||
|
void *rvalue,
|
||||||
|
void **avalue);
|
||||||
|
*/
|
||||||
|
//go:linkname Call C.ffi_call
|
||||||
|
func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer)
|
||||||
|
|
||||||
|
// void *ffi_closure_alloc (size_t size, void **code);
|
||||||
|
//
|
||||||
|
//go:linkname ClosureAlloc C.llog_ffi_closure_alloc
|
||||||
|
func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer
|
||||||
|
|
||||||
|
// void ffi_closure_free (void *);
|
||||||
|
//
|
||||||
|
//go:linkname ClosureFree C.ffi_closure_free
|
||||||
|
func ClosureFree(unsafe.Pointer)
|
||||||
|
|
||||||
|
/*
|
||||||
|
ffi_status
|
||||||
|
ffi_prep_closure_loc (ffi_closure*,
|
||||||
|
ffi_cif *,
|
||||||
|
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||||
|
void *user_data,
|
||||||
|
void *codeloc);
|
||||||
|
*/
|
||||||
|
|
||||||
|
//llgo:type C
|
||||||
|
type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer)
|
||||||
|
|
||||||
|
//go:linkname PreClosureLoc C.ffi_prep_closure_loc
|
||||||
|
func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint
|
||||||
124
c/ffi/type.go
Normal file
124
c/ffi/type.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package ffi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
"github.com/goplus/llgo/c/ffi/ffi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BasicKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Void BasicKind = iota // type is invalid
|
||||||
|
|
||||||
|
// predeclared types
|
||||||
|
Bool
|
||||||
|
Int
|
||||||
|
Int8
|
||||||
|
Int16
|
||||||
|
Int32
|
||||||
|
Int64
|
||||||
|
Uint
|
||||||
|
Uint8
|
||||||
|
Uint16
|
||||||
|
Uint32
|
||||||
|
Uint64
|
||||||
|
Uintptr
|
||||||
|
Float32
|
||||||
|
Float64
|
||||||
|
Complex64
|
||||||
|
Complex128
|
||||||
|
String
|
||||||
|
UnsafePointer
|
||||||
|
Interface
|
||||||
|
Slice
|
||||||
|
|
||||||
|
// aliases
|
||||||
|
Byte = Uint8
|
||||||
|
Rune = Int32
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_64bit = 1 << (^uintptr(0) >> 63) / 2
|
||||||
|
_Int = _64bit*ffi.Sint64 + (1-_64bit)*ffi.Sint32
|
||||||
|
_Uint = _64bit*ffi.Uint64 + (1-_64bit)*ffi.Uint32
|
||||||
|
_sizei = unsafe.Sizeof(0)
|
||||||
|
_aligni = uint16(unsafe.Alignof(0))
|
||||||
|
_sizeci = unsafe.Sizeof(c.Int(0))
|
||||||
|
_alignci = uint16(unsafe.Alignof(c.Int(0)))
|
||||||
|
_sizes = unsafe.Sizeof("")
|
||||||
|
_aligns = uint16(unsafe.Alignof(""))
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
TypeVoid = &Type{1, 1, ffi.Void, nil}
|
||||||
|
TypeBool = &Type{1, 1, ffi.Uint8, nil}
|
||||||
|
TypeInt8 = &Type{1, 1, ffi.Sint8, nil}
|
||||||
|
TypeInt16 = &Type{2, 2, ffi.Sint16, nil}
|
||||||
|
TypeInt32 = &Type{4, 4, ffi.Sint32, nil}
|
||||||
|
TypeInt64 = &Type{8, 8, ffi.Sint64, nil}
|
||||||
|
TypeUint8 = &Type{1, 1, ffi.Uint8, nil}
|
||||||
|
TypeUint16 = &Type{2, 2, ffi.Uint16, nil}
|
||||||
|
TypeUint32 = &Type{4, 4, ffi.Uint32, nil}
|
||||||
|
TypeUint64 = &Type{8, 8, ffi.Uint64, nil}
|
||||||
|
TypeFloat32 = &Type{4, 4, ffi.Float, nil}
|
||||||
|
TypeFloat64 = &Type{8, 8, ffi.Double, nil}
|
||||||
|
TypeComplex64 = &Type{8, 4, ffi.Complex, &[]*Type{TypeFloat32, nil}[0]}
|
||||||
|
TypeComplex128 = &Type{16, 8, ffi.Complex, &[]*Type{TypeFloat64, nil}[0]}
|
||||||
|
TypeInt = &Type{_sizei, _aligni, _Int, nil}
|
||||||
|
TypeUint = &Type{_sizei, _aligni, _Uint, nil}
|
||||||
|
TypeUintptr = &Type{_sizei, _aligni, _Uint, nil}
|
||||||
|
TypePointer = &Type{_sizei, _aligni, ffi.Pointer, nil}
|
||||||
|
TypeString = StructOf(TypePointer, TypeInt)
|
||||||
|
TypeInterface = StructOf(TypePointer, TypePointer)
|
||||||
|
TypeSlice = StructOf(TypePointer, TypeInt, TypeInt)
|
||||||
|
)
|
||||||
|
|
||||||
|
var Typ = []*Type{
|
||||||
|
Void: TypeVoid,
|
||||||
|
Bool: TypeBool,
|
||||||
|
Int: TypeInt,
|
||||||
|
Int8: TypeInt8,
|
||||||
|
Int16: TypeInt16,
|
||||||
|
Int32: TypeInt32,
|
||||||
|
Int64: TypeInt64,
|
||||||
|
Uint: TypeUint,
|
||||||
|
Uint8: TypeUint8,
|
||||||
|
Uint16: TypeUint16,
|
||||||
|
Uint32: TypeUint32,
|
||||||
|
Uint64: TypeUint64,
|
||||||
|
Uintptr: TypeUintptr,
|
||||||
|
Float32: TypeFloat32,
|
||||||
|
Float64: TypeFloat64,
|
||||||
|
Complex64: TypeComplex64,
|
||||||
|
Complex128: TypeComplex128,
|
||||||
|
String: TypeString,
|
||||||
|
UnsafePointer: TypePointer,
|
||||||
|
Interface: TypeInterface,
|
||||||
|
Slice: TypeSlice,
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArrayOf(elem *Type, N int) *Type {
|
||||||
|
fs := make([]*Type, N+1)
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
fs[i] = elem
|
||||||
|
}
|
||||||
|
return &Type{
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
ffi.Struct,
|
||||||
|
&fs[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StructOf(fields ...*Type) *Type {
|
||||||
|
fs := make([]*Type, len(fields)+1)
|
||||||
|
copy(fs, fields)
|
||||||
|
return &Type{
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
ffi.Struct,
|
||||||
|
&fs[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user