Created
May 29, 2024 12:53
-
-
Save amlwwalker/028a15cce5bd2375d25b9feb2c59c85c to your computer and use it in GitHub Desktop.
attempt at c-shared go plugins
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
/* | |
#cgo LDFLAGS: -ldl | |
#include <dlfcn.h> | |
#include <stdlib.h> | |
typedef void (*initializeFunc)(); | |
typedef void (*handleMessageFunc)(const char* message, char** response); | |
void* loadSO(const char* path) { | |
return dlopen(path, RTLD_LAZY); | |
} | |
initializeFunc getInitializeFunc(void* handle) { | |
return (initializeFunc)dlsym(handle, "Initialize"); | |
} | |
handleMessageFunc getHandleMessageFunc(void* handle) { | |
return (handleMessageFunc)dlsym(handle, "HandleMessage"); | |
} | |
void handle_message(handleMessageFunc fn, const char* message, char** response) { | |
fn(message, response); | |
} | |
*/ | |
import "C" | |
import ( | |
"fmt" | |
"unsafe" | |
) | |
type Plugin struct { | |
handle unsafe.Pointer | |
initializeFn unsafe.Pointer | |
handleMessageFn unsafe.Pointer | |
} | |
func LoadPlugin(path string) (*Plugin, error) { | |
cpath := C.CString(path) | |
defer C.free(unsafe.Pointer(cpath)) | |
handle := C.loadSO(cpath) | |
if handle == nil { | |
return nil, fmt.Errorf("failed to load plugin: %s", path) | |
} | |
initializeFn := unsafe.Pointer(C.getInitializeFunc(handle)) | |
if initializeFn == nil { | |
return nil, fmt.Errorf("failed to find Initialize function in plugin: %s", path) | |
} | |
handleMessageFn := unsafe.Pointer(C.getHandleMessageFunc(handle)) | |
if handleMessageFn == nil { | |
return nil, fmt.Errorf("failed to find HandleMessage function in plugin: %s", path) | |
} | |
return &Plugin{handle: handle, initializeFn: initializeFn, handleMessageFn: handleMessageFn}, nil | |
} | |
func (p *Plugin) Initialize() { | |
initializeFn := *(*func())(unsafe.Pointer(&p.initializeFn)) | |
initializeFn() | |
} | |
func (p *Plugin) SendMessage(message []byte) ([]byte, error) { | |
cmessage := C.CString(string(message)) | |
defer C.free(unsafe.Pointer(cmessage)) | |
var cresponse *C.char | |
handleMessageFn := *(*func(*C.char, **C.char))(unsafe.Pointer(&p.handleMessageFn)) | |
handleMessageFn(cmessage, &cresponse) | |
defer C.free(unsafe.Pointer(cresponse)) | |
response := C.GoString(cresponse) | |
return []byte(response), nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
) | |
func main() { | |
plugin, err := LoadPlugin("./examples/example/plugin.so") | |
if err != nil { | |
panic(err) | |
} | |
plugin.Initialize() | |
message := []byte("Hello Plugin") | |
response, err := plugin.SendMessage(message) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Printf("Received response: %s\n", string(response)) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "C" | |
import "fmt" | |
//export Initialize | |
func Initialize() { | |
fmt.Println("Plugin initialized") | |
} | |
//export HandleMessage | |
func HandleMessage(message *C.char, response **C.char) { | |
receivedMessage := C.GoString(message) | |
fmt.Printf("Received message: %s\n", receivedMessage) | |
responseMessage := "Response to: " + receivedMessage | |
*response = C.CString(responseMessage) | |
} | |
func main() {} |
The crash error
unexpected fault address 0xa9014ff4d100c3ff
fatal error: fault
[signal SIGBUS: bus error code=0x1 addr=0xa9014ff4d100c3ff pc=0xa9014ff4d100c3ff]
goroutine 1 gp=0x140000021c0 m=0 mp=0x1024323c0 [running]:
runtime.throw({0x1023784ed?, 0x0?})
/usr/local/go/src/runtime/panic.go:1023 +0x40 fp=0x14000060e70 sp=0x14000060e40 pc=0x1023190e0
runtime.sigpanic()
/usr/local/go/src/runtime/signal_unix.go:878 +0x178 fp=0x14000060ed0 sp=0x14000060e70 pc=0x102330e48
main.main()
/Users/alexwalker/go/src/github.com/amlwwalker/cgo-plugin/main.go:16 +0x48 fp=0x14000060f40 sp=0x14000060ee0 pc=0x102376da8
runtime.main()
/usr/local/go/src/runtime/proc.go:271 +0x28c fp=0x14000060fd0 sp=0x14000060f40 pc=0x10231badc
runtime.goexit({})
/usr/local/go/src/runtime/asm_arm64.s:1222 +0x4 fp=0x14000060fd0 sp=0x14000060fd0 pc=0x10234aa44
goroutine 18 gp=0x14000084380 m=nil [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/usr/local/go/src/runtime/proc.go:402 +0xc8 fp=0x1400004a790 sp=0x1400004a770 pc=0x10231bf08
runtime.goparkunlock(...)
/usr/local/go/src/runtime/proc.go:408
runtime.forcegchelper()
/usr/local/go/src/runtime/proc.go:326 +0xb8 fp=0x1400004a7d0 sp=0x1400004a790 pc=0x10231bd98
runtime.goexit({})
/usr/local/go/src/runtime/asm_arm64.s:1222 +0x4 fp=0x1400004a7d0 sp=0x1400004a7d0 pc=0x10234aa44
created by runtime.init.6 in goroutine 1
/usr/local/go/src/runtime/proc.go:314 +0x24
goroutine 19 gp=0x14000084540 m=nil [GC sweep wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/usr/local/go/src/runtime/proc.go:402 +0xc8 fp=0x1400004af60 sp=0x1400004af40 pc=0x10231bf08
runtime.goparkunlock(...)
/usr/local/go/src/runtime/proc.go:408
runtime.bgsweep(0x14000092000)
/usr/local/go/src/runtime/mgcsweep.go:278 +0xa0 fp=0x1400004afb0 sp=0x1400004af60 pc=0x102308970
runtime.gcenable.gowrap1()
/usr/local/go/src/runtime/mgc.go:203 +0x28 fp=0x1400004afd0 sp=0x1400004afb0 pc=0x1022fcde8
runtime.goexit({})
/usr/local/go/src/runtime/asm_arm64.s:1222 +0x4 fp=0x1400004afd0 sp=0x1400004afd0 pc=0x10234aa44
created by runtime.gcenable in goroutine 1
/usr/local/go/src/runtime/mgc.go:203 +0x6c
goroutine 20 gp=0x14000084700 m=nil [GC scavenge wait]:
runtime.gopark(0x14000092000?, 0x10239a2c0?, 0x1?, 0x0?, 0x14000084700?)
/usr/local/go/src/runtime/proc.go:402 +0xc8 fp=0x1400004b760 sp=0x1400004b740 pc=0x10231bf08
runtime.goparkunlock(...)
/usr/local/go/src/runtime/proc.go:408
runtime.(*scavengerState).park(0x102431ce0)
/usr/local/go/src/runtime/mgcscavenge.go:425 +0x5c fp=0x1400004b790 sp=0x1400004b760 pc=0x10230635c
runtime.bgscavenge(0x14000092000)
/usr/local/go/src/runtime/mgcscavenge.go:653 +0x44 fp=0x1400004b7b0 sp=0x1400004b790 pc=0x1023068b4
runtime.gcenable.gowrap2()
/usr/local/go/src/runtime/mgc.go:204 +0x28 fp=0x1400004b7d0 sp=0x1400004b7b0 pc=0x1022fcd88
runtime.goexit({})
/usr/local/go/src/runtime/asm_arm64.s:1222 +0x4 fp=0x1400004b7d0 sp=0x1400004b7d0 pc=0x10234aa44
created by runtime.gcenable in goroutine 1
/usr/local/go/src/runtime/mgc.go:204 +0xac
goroutine 34 gp=0x14000104700 m=nil [finalizer wait]:
runtime.gopark(0x0?, 0x0?, 0x2f?, 0x0?, 0x10232c568?)
/usr/local/go/src/runtime/proc.go:402 +0xc8 fp=0x1400004e580 sp=0x1400004e560 pc=0x10231bf08
runtime.runfinq()
/usr/local/go/src/runtime/mfinal.go:194 +0x108 fp=0x1400004e7d0 sp=0x1400004e580 pc=0x1022fbeb8
runtime.goexit({})
/usr/local/go/src/runtime/asm_arm64.s:1222 +0x4 fp=0x1400004e7d0 sp=0x1400004e7d0 pc=0x10234aa44
created by runtime.createfing in goroutine 1
/usr/local/go/src/runtime/mfinal.go:164 +0x80
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am compiling the plugin with
go build -o plugin.so -buildmode=c-shared plugin.go
and the main application with
go build -o main main.go loader.go