Documentation ¶
Index ¶
- Constants
- func Dlclose(handle uintptr) error
- func Dlopen(path string, mode int) (uintptr, error)
- func Dlsym(handle uintptr, name string) (uintptr, error)
- func NewCallback(fn interface{}) uintptr
- func RegisterFunc(fptr interface{}, cfn uintptr)
- func RegisterLibFunc(fptr interface{}, handle uintptr, name string)
- func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr)
- type CDecl
- type Dlerror
Examples ¶
Constants ¶
const ( RTLD_DEFAULT = 0x00000 // Pseudo-handle for dlsym so search for any loaded symbol RTLD_LAZY = 0x00001 // Relocations are performed at an implementation-dependent time. RTLD_NOW = 0x00002 // Relocations are performed when the object is loaded. RTLD_LOCAL = 0x00000 // All symbols are not made available for relocation processing by other modules. RTLD_GLOBAL = 0x00100 // All symbols are available for relocation processing of other modules. )
Variables ¶
This section is empty.
Functions ¶
func Dlclose ¶
Dlclose decrements the reference count on the dynamic library handle. If the reference count drops to zero and no other loaded libraries use symbols in it, then the dynamic library is unloaded.
This function is not available on Windows. Use golang.org/x/sys/windows.FreeLibrary for Windows instead.
func Dlopen ¶
Dlopen examines the dynamic library or bundle file specified by path. If the file is compatible with the current process and has not already been loaded into the current process, it is loaded and linked. After being linked, if it contains any initializer functions, they are called, before Dlopen returns. It returns a handle that can be used with Dlsym and Dlclose. A second call to Dlopen with the same path will return the same handle, but the internal reference count for the handle will be incremented. Therefore, all Dlopen calls should be balanced with a Dlclose call.
This function is not available on Windows. Use golang.org/x/sys/windows.LoadLibrary, golang.org/x/sys/windows.LoadLibraryEx, golang.org/x/sys/windows.NewLazyDLL, or golang.org/x/sys/windows.NewLazySystemDLL for Windows instead.
func Dlsym ¶
Dlsym takes a "handle" of a dynamic library returned by Dlopen and the symbol name. It returns the address where that symbol is loaded into memory. If the symbol is not found, in the specified library or any of the libraries that were automatically loaded by Dlopen when that library was loaded, Dlsym returns zero.
This function is not available on Windows. Use golang.org/x/sys/windows.GetProcAddress for Windows instead.
func NewCallback ¶
func NewCallback(fn interface{}) uintptr
NewCallback converts a Go function to a function pointer conforming to the C calling convention. This is useful when interoperating with C code requiring callbacks. The argument is expected to be a function with zero or one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory allocated for these callbacks is never released. At least 2000 callbacks can always be created. Although this function provides similar functionality to windows.NewCallback it is distinct.
Example ¶
package main import ( "fmt" "github.com/ebitengine/purego" ) func main() { cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int { fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 }) var fn func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int purego.RegisterFunc(&fn, cb) ret := fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) fmt.Println(ret) }
Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 120
Example (Cdecl) ¶
package main import ( "fmt" "github.com/ebitengine/purego" ) func main() { fn := func(_ purego.CDecl, a int) { fmt.Println(a) } cb := purego.NewCallback(fn) purego.SyscallN(cb, 83) }
Output: 83
func RegisterFunc ¶
func RegisterFunc(fptr interface{}, cfn uintptr)
RegisterFunc takes a pointer to a Go function representing the calling convention of the C function. fptr will be set to a function that when called will call the C function given by cfn with the parameters passed in the correct registers and stack.
A panic is produced if the type is not a function pointer or if the function returns more than 1 value.
These conversions describe how a Go type in the fptr will be used to call the C function. It is important to note that there is no way to verify that fptr matches the C function. This also holds true for struct types where the padding needs to be ensured to match that of C; RegisterFunc does not verify this.
Type Conversions (Go <=> C) ¶
string <=> char* bool <=> _Bool uintptr <=> uintptr_t uint <=> uint32_t or uint64_t uint8 <=> uint8_t uint16 <=> uint16_t uint32 <=> uint32_t uint64 <=> uint64_t int <=> int32_t or int64_t int8 <=> int8_t int16 <=> int16_t int32 <=> int32_t int64 <=> int64_t float32 <=> float float64 <=> double struct <=> struct (WIP - darwin only) func <=> C function unsafe.Pointer, *T <=> void* []T => void*
There is a special case when the last argument of fptr is a variadic interface (or []interface} it will be expanded into a call to the C function as if it had the arguments in that slice. This means that using arg ...interface{} is like a cast to the function with the arguments inside arg. This is not the same as C variadic.
Memory ¶
In general it is not possible for purego to guarantee the lifetimes of objects returned or received from calling functions using RegisterFunc. For arguments to a C function it is important that the C function doesn't hold onto a reference to Go memory. This is the same as the Cgo rules.
However, there are some special cases. When passing a string as an argument if the string does not end in a null terminated byte (\x00) then the string will be copied into memory maintained by purego. The memory is only valid for that specific call. Therefore, if the C code keeps a reference to that string it may become invalid at some undefined time. However, if the string does already contain a null-terminated byte then no copy is done. It is then the responsibility of the caller to ensure the string stays alive as long as it's needed in C memory. This can be done using runtime.KeepAlive or allocating the string in C memory using malloc. When a C function returns a null-terminated pointer to char a Go string can be used. Purego will allocate a new string in Go memory and copy the data over. This string will be garbage collected whenever Go decides it's no longer referenced. This C created string will not be freed by purego. If the pointer to char is not null-terminated or must continue to point to C memory (because it's a buffer for example) then use a pointer to byte and then convert that to a slice using unsafe.Slice. Doing this means that it becomes the responsibility of the caller to care about the lifetime of the pointer
Structs ¶
Purego can handle the most common structs that have fields of builtin types like int8, uint16, float32, etc. However, it does not support aligning fields properly. It is therefore the responsibility of the caller to ensure that all padding is added to the Go struct to match the C one. See `BoolStructFn` in struct_test.go for an example.
Example ¶
All functions below call this C function:
char *foo(char *str); // Let purego convert types var foo func(s string) string goString := foo("copied") // Go will garbage collect this string // Manually, handle allocations var foo2 func(b string) *byte mustFree := foo2("not copied\x00") defer free(mustFree)
func RegisterLibFunc ¶
RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name). It panics if it can't find the name symbol.
func SyscallN ¶
SyscallN takes fn, a C function pointer and a list of arguments as uintptr. There is an internal maximum number of arguments that SyscallN can take. It panics when the maximum is exceeded. It returns the result and the libc error code if there is one.
NOTE: SyscallN does not properly call functions that have both integer and float parameters. See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607 for an explanation of why that is.
On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the stack.
The pragma go:nosplit is not needed at this function declaration because it uses go:uintptrescapes which forces all the objects that the uintptrs point to onto the heap where a stack split won't affect their memory location.
Types ¶
type CDecl ¶ added in v0.8.0
type CDecl struct{}
CDecl marks a function as being called using the __cdecl calling convention as defined in the MSDocs when passed to NewCallback. It must be the first argument to the function. This is only useful on 386 Windows, but it is safe to use on other platforms.