0
|
1 /*
|
|
2
|
|
3 godc.go
|
|
4 Copyright (c) 2014 Tassilo Philipp <tphilipp@potion-studios.com>
|
|
5
|
|
6 Permission to use, copy, modify, and distribute this software for any
|
|
7 purpose with or without fee is hereby granted, provided that the above
|
|
8 copyright notice and this permission notice appear in all copies.
|
|
9
|
|
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
17
|
|
18 */
|
|
19
|
|
20
|
|
21 // Go/dyncall extension implementation.
|
|
22 package godc
|
|
23
|
|
24 // #cgo LDFLAGS: -L../../../dyncall/ -ldyncall_s
|
|
25 // #cgo LDFLAGS: -L../../../dynload/ -ldynload_s
|
|
26 // #cgo LDFLAGS: -L../../../dyncallback/ -ldyncallback_s
|
|
27 // #include <stdlib.h>
|
|
28 // #include "../../../dyncall/dyncall/dyncall.h"
|
|
29 // #include "../../../dyncall/dynload/dynload.h"
|
|
30 // #include "../../../dyncall/dyncall/dyncall_signature.h"
|
|
31 import "C"
|
|
32 import (
|
|
33 "unsafe"
|
|
34 "fmt"
|
|
35 "reflect"
|
|
36 )
|
|
37
|
|
38 type ExtLib struct {
|
|
39 lib *C.DLLib
|
|
40 syms *C.DLSyms
|
|
41 }
|
|
42
|
|
43 type CallVM struct {
|
|
44 cvm *C.DCCallVM
|
|
45 }
|
|
46
|
|
47
|
|
48 // dynload
|
|
49 func (p *ExtLib) Load(path string) error {
|
|
50 s := C.CString(path)
|
|
51 defer C.free(unsafe.Pointer(s))
|
|
52 p.lib = C.dlLoadLibrary(s)
|
|
53 if p.lib != nil { return nil }
|
|
54 return fmt.Errorf("Can't load %s", path)
|
|
55 }
|
|
56
|
|
57 func (p *ExtLib) Free() {
|
|
58 C.dlFreeLibrary(p.lib)
|
|
59 }
|
|
60
|
|
61 func (p *ExtLib) FindSymbol(name string) unsafe.Pointer {
|
|
62 s := C.CString(name)
|
|
63 defer C.free(unsafe.Pointer(s))
|
|
64 return unsafe.Pointer(C.dlFindSymbol(p.lib, s))
|
|
65 }
|
|
66
|
|
67
|
|
68 // dynload Syms
|
|
69 func (p *ExtLib) SymsInit(path string) error {
|
|
70 s := C.CString(path)
|
|
71 defer C.free(unsafe.Pointer(s))
|
|
72 p.syms = C.dlSymsInit(s)
|
|
73 if p.syms != nil { return nil }
|
|
74 return fmt.Errorf("Can't load %s", path)
|
|
75 }
|
|
76
|
|
77 func (p *ExtLib) SymsCleanup() {
|
|
78 C.dlSymsCleanup(p.syms)
|
|
79 }
|
|
80
|
|
81 func (p *ExtLib) SymsCount() int {
|
|
82 return int(C.dlSymsCount(p.syms))
|
|
83 }
|
|
84
|
|
85 func (p *ExtLib) SymsName(i int) string {
|
|
86 return C.GoString(C.dlSymsName(p.syms, C.int(i)))
|
|
87 }
|
|
88
|
|
89 func (p *ExtLib) SymsNameFromValue(v unsafe.Pointer) string {
|
|
90 return C.GoString(C.dlSymsNameFromValue(p.syms, v))
|
|
91 }
|
|
92
|
|
93
|
|
94 // dyncall
|
|
95 func (p *CallVM) InitCallVM() error {
|
|
96 return p.InitCallVMWithStackSize(4096)
|
|
97 }
|
|
98
|
|
99 func (p *CallVM) InitCallVMWithStackSize(stackSize int) error {
|
|
100 p.cvm = C.dcNewCallVM(C.DCsize(stackSize))
|
|
101 if p.cvm != nil { return nil }
|
|
102 return fmt.Errorf("Can't create CallVM")
|
|
103 }
|
|
104
|
|
105 func (p *CallVM) Free() {
|
|
106 C.dcFree(p.cvm)
|
|
107 }
|
|
108
|
|
109 func (p *CallVM) Reset() {
|
|
110 C.dcReset(p.cvm)
|
|
111 }
|
|
112
|
|
113
|
|
114
|
|
115 // Modes
|
|
116 const (
|
|
117 DC_CALL_C_DEFAULT = C.DC_CALL_C_DEFAULT
|
|
118 DC_CALL_C_ELLIPSIS = C.DC_CALL_C_ELLIPSIS
|
|
119 DC_CALL_C_ELLIPSIS_VARARGS = C.DC_CALL_C_ELLIPSIS_VARARGS
|
|
120 DC_CALL_C_X86_CDECL = C.DC_CALL_C_X86_CDECL
|
|
121 DC_CALL_C_X86_WIN32_STD = C.DC_CALL_C_X86_WIN32_STD
|
|
122 DC_CALL_C_X86_WIN32_FAST_MS = C.DC_CALL_C_X86_WIN32_FAST_MS
|
|
123 DC_CALL_C_X86_WIN32_FAST_GNU = C.DC_CALL_C_X86_WIN32_FAST_GNU
|
|
124 DC_CALL_C_X86_WIN32_THIS_MS = C.DC_CALL_C_X86_WIN32_THIS_MS
|
|
125 DC_CALL_C_X86_WIN32_THIS_GNU = C.DC_CALL_C_X86_WIN32_THIS_GNU
|
|
126 DC_CALL_C_X64_WIN64 = C.DC_CALL_C_X64_WIN64
|
|
127 DC_CALL_C_X64_SYSV = C.DC_CALL_C_X64_SYSV
|
|
128 DC_CALL_C_PPC32_DARWIN = C.DC_CALL_C_PPC32_DARWIN
|
|
129 DC_CALL_C_PPC32_OSX = C.DC_CALL_C_PPC32_OSX
|
|
130 DC_CALL_C_ARM_ARM_EABI = C.DC_CALL_C_ARM_ARM_EABI
|
|
131 DC_CALL_C_ARM_THUMB_EABI = C.DC_CALL_C_ARM_THUMB_EABI
|
|
132 DC_CALL_C_ARM_ARMHF = C.DC_CALL_C_ARM_ARMHF
|
|
133 DC_CALL_C_MIPS32_EABI = C.DC_CALL_C_MIPS32_EABI
|
|
134 DC_CALL_C_MIPS32_PSPSDK = C.DC_CALL_C_MIPS32_PSPSDK
|
|
135 DC_CALL_C_PPC32_SYSV = C.DC_CALL_C_PPC32_SYSV
|
|
136 DC_CALL_C_PPC32_LINUX = C.DC_CALL_C_PPC32_LINUX
|
|
137 DC_CALL_C_ARM_ARM = C.DC_CALL_C_ARM_ARM
|
|
138 DC_CALL_C_ARM_THUMB = C.DC_CALL_C_ARM_THUMB
|
|
139 DC_CALL_C_MIPS32_O32 = C.DC_CALL_C_MIPS32_O32
|
|
140 DC_CALL_C_MIPS64_N32 = C.DC_CALL_C_MIPS64_N32
|
|
141 DC_CALL_C_MIPS64_N64 = C.DC_CALL_C_MIPS64_N64
|
|
142 DC_CALL_C_X86_PLAN9 = C.DC_CALL_C_X86_PLAN9
|
|
143 DC_CALL_C_SPARC32 = C.DC_CALL_C_SPARC32
|
|
144 DC_CALL_C_SPARC64 = C.DC_CALL_C_SPARC64
|
|
145 DC_CALL_SYS_DEFAULT = C.DC_CALL_SYS_DEFAULT
|
|
146 DC_CALL_SYS_X86_INT80H_LINUX = C.DC_CALL_SYS_X86_INT80H_LINUX
|
|
147 DC_CALL_SYS_X86_INT80H_BSD = C.DC_CALL_SYS_X86_INT80H_BSD
|
|
148 )
|
|
149
|
|
150
|
|
151 func (p *CallVM) Mode(mode int) {
|
|
152 C.dcMode(p.cvm, C.DCint(mode))
|
|
153 }
|
|
154
|
|
155 // Error codes
|
|
156 const (
|
|
157 DC_ERROR_NONE = C.DC_ERROR_NONE
|
|
158 DC_ERROR_UNSUPPORTED_MODE = C.DC_ERROR_UNSUPPORTED_MODE
|
|
159 )
|
|
160
|
|
161
|
|
162 func (p *CallVM) GetError() int {
|
|
163 return int(C.dcGetError(p.cvm))
|
|
164 }
|
|
165
|
|
166
|
|
167 // Helper for string/pointer conversion, needed as low-level string alloc needs to be freed in different scope
|
|
168 func (p *CallVM) AllocCString(value string) unsafe.Pointer { s := C.CString(value); return unsafe.Pointer(s) }
|
|
169 func (p *CallVM) FreeCString (value unsafe.Pointer) { C.free(value) }
|
|
170
|
|
171 // Args
|
|
172 func (p *CallVM) ArgBool (value bool) { if value==true { C.dcArgBool(p.cvm, C.DC_TRUE) } else { C.dcArgBool(p.cvm, C.DC_FALSE) } }
|
|
173 func (p *CallVM) ArgChar (value int8) { C.dcArgChar (p.cvm, C.DCchar (value)) }
|
|
174 func (p *CallVM) ArgShort (value int16) { C.dcArgShort (p.cvm, C.DCshort (value)) }
|
|
175 func (p *CallVM) ArgInt (value int) { C.dcArgInt (p.cvm, C.DCint (value)) }
|
|
176 func (p *CallVM) ArgLong (value int32) { C.dcArgLong (p.cvm, C.DClong (value)) }
|
|
177 func (p *CallVM) ArgLongLong (value int64) { C.dcArgLongLong(p.cvm, C.DClonglong(value)) }
|
|
178 func (p *CallVM) ArgFloat (value float32) { C.dcArgFloat (p.cvm, C.DCfloat (value)) }
|
|
179 func (p *CallVM) ArgDouble (value float64) { C.dcArgDouble (p.cvm, C.DCdouble (value)) }
|
|
180 func (p *CallVM) ArgPointer (value unsafe.Pointer) { C.dcArgPointer (p.cvm, C.DCpointer (value)) }
|
|
181 //@@@func (p *CallVM) ArgStruct (s C.DCstruct*, value unsafe.Pointer)
|
|
182
|
|
183 // "Formatted" args
|
|
184 // - first takes Go's types (as they cover all C types dyncall supports) and pushes values accordingly
|
|
185 // - second uses a dyncall signature for implicit type conversion/casting, however it uses reflect package and is slower
|
|
186 // Note that first version doesn't feature calling convention mode switching.
|
|
187 func (p *CallVM) ArgF_Go(args ...interface{}) error {
|
|
188
|
|
189 for i, n := 0, len(args); i<n; i++ {
|
|
190 switch args[i].(type) {
|
|
191 case bool: p.ArgBool ( (args[i].(bool )))
|
|
192 case int8: p.ArgChar ( (args[i].(int8 )))
|
|
193 case uint8/*byte*/: p.ArgChar (int8 (args[i].(uint8 )))
|
|
194 case int16: p.ArgShort ( (args[i].(int16 )))
|
|
195 case uint16: p.ArgShort (int16 (args[i].(uint16 )))
|
|
196 case int: p.ArgInt ( (args[i].(int )))
|
|
197 case uint: p.ArgInt (int (args[i].(uint )))
|
|
198 case int32/*rune*/: p.ArgLong ( (args[i].(int32 )))
|
|
199 case uint32: p.ArgLong (int32 (args[i].(uint32 )))
|
|
200 case int64: p.ArgLongLong( (args[i].(int64 )))
|
|
201 case uint64: p.ArgLongLong(int64 (args[i].(uint64 )))
|
|
202 case float32: p.ArgFloat ( (args[i].(float32 )))
|
|
203 case float64: p.ArgDouble ( (args[i].(float64 )))
|
|
204 case uintptr: p.ArgPointer (unsafe.Pointer(args[i].(unsafe.Pointer)))
|
|
205 case unsafe.Pointer: p.ArgPointer ( (args[i].(unsafe.Pointer)))
|
|
206 default: return fmt.Errorf("Unknown type passed to ArgF_Go")
|
|
207 }
|
|
208 }
|
|
209 return nil
|
|
210 }
|
|
211
|
|
212 func (p *CallVM) ArgF(signature string, args ...interface{}) {
|
|
213
|
|
214 tb := reflect.TypeOf((*bool )(nil)).Elem()
|
|
215 ti := reflect.TypeOf((*int64 )(nil)).Elem()
|
|
216 tf := reflect.TypeOf((*float64)(nil)).Elem()
|
|
217 tp := reflect.TypeOf((*uintptr)(nil)).Elem()
|
|
218
|
|
219 for i, n := 0, len(signature); i<n; i++ {
|
|
220 //@@@ add support for calling convention mode(s)
|
|
221 switch s := signature[i]; s {
|
|
222 case C.DC_SIGCHAR_BOOL: p.ArgBool (bool (reflect.ValueOf(args[i]).Convert(tb).Bool ()))
|
|
223 case C.DC_SIGCHAR_CHAR, C.DC_SIGCHAR_UCHAR: p.ArgChar (int8 (reflect.ValueOf(args[i]).Convert(ti).Int ()))
|
|
224 case C.DC_SIGCHAR_INT, C.DC_SIGCHAR_UINT: p.ArgInt (int (reflect.ValueOf(args[i]).Convert(ti).Int ()))
|
|
225 case C.DC_SIGCHAR_LONG, C.DC_SIGCHAR_ULONG: p.ArgLong (int32 (reflect.ValueOf(args[i]).Convert(ti).Int ()))
|
|
226 case C.DC_SIGCHAR_LONGLONG, C.DC_SIGCHAR_ULONGLONG: p.ArgLongLong(int64 (reflect.ValueOf(args[i]).Convert(ti).Int ()))
|
|
227 case C.DC_SIGCHAR_FLOAT: p.ArgFloat (float32 (reflect.ValueOf(args[i]).Convert(tf).Float ()))
|
|
228 case C.DC_SIGCHAR_DOUBLE: p.ArgDouble (float64 (reflect.ValueOf(args[i]).Convert(tf).Float ()))
|
|
229 case C.DC_SIGCHAR_POINTER, C.DC_SIGCHAR_STRING: p.ArgPointer (unsafe.Pointer(reflect.ValueOf(args[i]).Convert(tp).Pointer()))
|
|
230 case C.DC_SIGCHAR_ENDARG: return
|
|
231 }
|
|
232 // Faster, but doesn't do cross-type conversions.
|
|
233 //switch s := signature[i]; s {
|
|
234 // case C.DC_SIGCHAR_BOOL: p.ArgBool (args[i].(bool ))
|
|
235 // case C.DC_SIGCHAR_CHAR, C.DC_SIGCHAR_UCHAR: p.ArgChar (args[i].(int8 ))
|
|
236 // case C.DC_SIGCHAR_SHORT, C.DC_SIGCHAR_USHORT: p.ArgShort (args[i].(int16 ))
|
|
237 // case C.DC_SIGCHAR_INT, C.DC_SIGCHAR_UINT: p.ArgInt (args[i].(int ))
|
|
238 // case C.DC_SIGCHAR_LONG, C.DC_SIGCHAR_ULONG: p.ArgLong (args[i].(int32 ))
|
|
239 // case C.DC_SIGCHAR_LONGLONG, C.DC_SIGCHAR_ULONGLONG: p.ArgLongLong(args[i].(int64 ))
|
|
240 // case C.DC_SIGCHAR_FLOAT: p.ArgFloat (args[i].(float32 ))
|
|
241 // case C.DC_SIGCHAR_DOUBLE: p.ArgDouble (args[i].(float64 ))
|
|
242 // case C.DC_SIGCHAR_POINTER, C.DC_SIGCHAR_STRING: p.ArgPointer (args[i].(unsafe.Pointer))
|
|
243 // case C.DC_SIGCHAR_ENDARG: return
|
|
244 //}
|
|
245 }
|
|
246 }
|
|
247
|
|
248
|
|
249 // Calls
|
|
250 func (p *CallVM) CallVoid (funcptr unsafe.Pointer) { C.dcCallVoid (p.cvm, C.DCpointer(funcptr)) }
|
|
251 func (p *CallVM) CallBool (funcptr unsafe.Pointer) bool { b := (C.dcCallBool(p.cvm, C.DCpointer(funcptr))); if b==C.DC_TRUE { return true } else { return false } }
|
|
252 func (p *CallVM) CallChar (funcptr unsafe.Pointer) int8 { return int8 (C.dcCallChar (p.cvm, C.DCpointer(funcptr))) }
|
|
253 func (p *CallVM) CallShort (funcptr unsafe.Pointer) int16 { return int16 (C.dcCallShort (p.cvm, C.DCpointer(funcptr))) }
|
|
254 func (p *CallVM) CallInt (funcptr unsafe.Pointer) int { return int (C.dcCallInt (p.cvm, C.DCpointer(funcptr))) }
|
|
255 func (p *CallVM) CallLong (funcptr unsafe.Pointer) int32 { return int32 (C.dcCallLong (p.cvm, C.DCpointer(funcptr))) }
|
|
256 func (p *CallVM) CallLongLong (funcptr unsafe.Pointer) int64 { return int64 (C.dcCallLongLong(p.cvm, C.DCpointer(funcptr))) }
|
|
257 func (p *CallVM) CallFloat (funcptr unsafe.Pointer) float32 { return float32 (C.dcCallFloat (p.cvm, C.DCpointer(funcptr))) }
|
|
258 func (p *CallVM) CallDouble (funcptr unsafe.Pointer) float64 { return float64 (C.dcCallDouble (p.cvm, C.DCpointer(funcptr))) }
|
|
259 func (p *CallVM) CallPointer (funcptr unsafe.Pointer) unsafe.Pointer { return unsafe.Pointer(C.dcCallPointer (p.cvm, C.DCpointer(funcptr))) }
|
|
260 func (p *CallVM) CallPointerToStr(funcptr unsafe.Pointer) string { return C.GoString((*C.char)(C.dcCallPointer (p.cvm, C.DCpointer(funcptr)))) } // For convenience
|
|
261 //@@@func (p *CallVM) CallStruct (funcptr unsafe.Pointer, s C.DCstruct* s, returnValue unsafe.Pointer)
|
|
262
|
|
263 // "Formatted" calls
|
|
264 //@@@func (p *CallVM) Call(result, funcptr unsafe.Pointer, signature string, args ...interface{}) {
|
|
265 //@@@...
|
|
266 //@@@}
|
|
267
|
|
268
|
|
269 //void dcCallF (DCCallVM* vm, DCValue* result, DCpointer funcptr, const DCsigchar* signature, ...);
|
|
270
|
|
271 /*
|
|
272 DC_API DCstruct* dcNewStruct (DCsize fieldCount, DCint alignment);
|
|
273 DC_API void dcStructField (DCstruct* s, DCint type, DCint alignment, DCsize arrayLength);
|
|
274 DC_API void dcSubStruct (DCstruct* s, DCsize fieldCount, DCint alignment, DCsize arrayLength);
|
|
275 DC_API void dcCloseStruct (DCstruct* s);
|
|
276 DC_API DCsize dcStructSize (DCstruct* s);
|
|
277 DC_API DCsize dcStructAlignment(DCstruct* s);
|
|
278 DC_API void dcFreeStruct (DCstruct* s);
|
|
279
|
|
280 DC_API DCstruct* dcDefineStruct (const char* signature);
|
|
281 */
|
|
282
|