purego: implement dlerror & dlclose (#14)
- commit
- 0f3e4f83313426b50eecae8b43d626551631be62
- author
- TotallyGamerJet · · 2022-08-09 00:23 UTC
- committer
- GitHub · · 2022-08-09 00:23 UTC
- parent
- 78cdc29
- signature
- GPG Unverified
4AEE18F83AFDEB23The key is unknown
3 files · +46 -2
M dlfcn.go +31 -2
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | package purego | |
| 8 | 8 | ||
| 9 | 9 | import ( | |
| 10 | + | "reflect" | |
| 10 | 11 | "runtime" | |
| 11 | 12 | "unsafe" | |
| 12 | 13 | ||
| @@ -17,8 +18,8 @@ const RTLD_GLOBAL = 0x8 | |||
| 17 | 18 | ||
| 18 | 19 | const RTLD_DEFAULT = ^uintptr(1) | |
| 19 | 20 | ||
| 20 | - | func Dlopen(name string, mode int) uintptr { | |
| 21 | - | bs := strings.CString(name) | |
| 21 | + | func Dlopen(path string, mode int) uintptr { | |
| 22 | + | bs := strings.CString(path) | |
| 22 | 23 | ret, _, _ := SyscallN(dlopenABI0, uintptr(unsafe.Pointer(bs)), uintptr(mode), 0) | |
| 23 | 24 | runtime.KeepAlive(bs) | |
| 24 | 25 | return ret | |
| @@ -31,6 +32,34 @@ func Dlsym(handle uintptr, name string) uintptr { | |||
| 31 | 32 | return ret | |
| 32 | 33 | } | |
| 33 | 34 | ||
| 35 | + | func Dlerror() string { | |
| 36 | + | // msg is only valid until the next call to Dlerror | |
| 37 | + | // which is why it gets copied into a Go string | |
| 38 | + | msg, _, _ := SyscallN(dlerrorABI0) | |
| 39 | + | if msg == 0 { | |
| 40 | + | return "" | |
| 41 | + | } | |
| 42 | + | var length int | |
| 43 | + | for { | |
| 44 | + | // use unsafe.Add once we reach 1.17 | |
| 45 | + | if *(*byte)(unsafe.Pointer(msg + uintptr(length))) == '\x00' { | |
| 46 | + | break | |
| 47 | + | } | |
| 48 | + | length++ | |
| 49 | + | } | |
| 50 | + | // use unsafe.Slice once we reach 1.17 | |
| 51 | + | s := make([]byte, length) | |
| 52 | + | copy(s, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{Data: msg, Len: length, Cap: length}))) | |
| 53 | + | return string(s) | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | func Dlclose(handle uintptr) bool { | |
| 57 | + | ret, _, _ := SyscallN(dlcloseABI0, handle) | |
| 58 | + | return ret != 0 | |
| 59 | + | } | |
| 60 | + | ||
| 34 | 61 | // these functions exist in dlfcn_stubs.s and are calling C functions linked to in dlfcn_GOOS.go | |
| 35 | 62 | var dlopenABI0 uintptr | |
| 36 | 63 | var dlsymABI0 uintptr | |
| 64 | + | var dlcloseABI0 uintptr | |
| 65 | + | var dlerrorABI0 uintptr | |
| @@ -7,6 +7,7 @@ | |||||
| 7 | package purego | 7 | package purego | ||
| 8 | 8 | ||||
| 9 | import ( | 9 | import ( | ||
| 10 | + | "reflect" | |||
| 10 | "runtime" | 11 | "runtime" | ||
| 11 | "unsafe" | 12 | "unsafe" | ||
| 12 | 13 | ||||
| @@ -17,8 +18,8 @@ const RTLD_GLOBAL = 0x8 | |||||
| 17 | 18 | ||||
| 18 | const RTLD_DEFAULT = ^uintptr(1) | 19 | const RTLD_DEFAULT = ^uintptr(1) | ||
| 19 | 20 | ||||
| 20 | - | func Dlopen(name string, mode int) uintptr { | 21 | + | func Dlopen(path string, mode int) uintptr { |
| 21 | - | bs := strings.CString(name) | 22 | + | bs := strings.CString(path) |
| 22 | ret, _, _ := SyscallN(dlopenABI0, uintptr(unsafe.Pointer(bs)), uintptr(mode), 0) | 23 | ret, _, _ := SyscallN(dlopenABI0, uintptr(unsafe.Pointer(bs)), uintptr(mode), 0) | ||
| 23 | runtime.KeepAlive(bs) | 24 | runtime.KeepAlive(bs) | ||
| 24 | return ret | 25 | return ret | ||
| @@ -31,6 +32,34 @@ func Dlsym(handle uintptr, name string) uintptr { | |||||
| 31 | return ret | 32 | return ret | ||
| 32 | } | 33 | } | ||
| 33 | 34 | ||||
| 35 | + | func Dlerror() string { | |||
| 36 | + | // msg is only valid until the next call to Dlerror | |||
| 37 | + | // which is why it gets copied into a Go string | |||
| 38 | + | msg, _, _ := SyscallN(dlerrorABI0) | |||
| 39 | + | if msg == 0 { | |||
| 40 | + | return "" | |||
| 41 | + | } | |||
| 42 | + | var length int | |||
| 43 | + | for { | |||
| 44 | + | // use unsafe.Add once we reach 1.17 | |||
| 45 | + | if *(*byte)(unsafe.Pointer(msg + uintptr(length))) == '\x00' { | |||
| 46 | + | break | |||
| 47 | + | } | |||
| 48 | + | length++ | |||
| 49 | + | } | |||
| 50 | + | // use unsafe.Slice once we reach 1.17 | |||
| 51 | + | s := make([]byte, length) | |||
| 52 | + | copy(s, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{Data: msg, Len: length, Cap: length}))) | |||
| 53 | + | return string(s) | |||
| 54 | + | } | |||
| 55 | + | ||||
| 56 | + | func Dlclose(handle uintptr) bool { | |||
| 57 | + | ret, _, _ := SyscallN(dlcloseABI0, handle) | |||
| 58 | + | return ret != 0 | |||
| 59 | + | } | |||
| 60 | + | ||||
| 34 | // these functions exist in dlfcn_stubs.s and are calling C functions linked to in dlfcn_GOOS.go | 61 | // these functions exist in dlfcn_stubs.s and are calling C functions linked to in dlfcn_GOOS.go | ||
| 35 | var dlopenABI0 uintptr | 62 | var dlopenABI0 uintptr | ||
| 36 | var dlsymABI0 uintptr | 63 | var dlsymABI0 uintptr | ||
| 64 | + | var dlcloseABI0 uintptr | |||
| 65 | + | var dlerrorABI0 uintptr | |||
M dlfcn_darwin.go +2 -0
| @@ -5,3 +5,5 @@ package purego | |||
| 5 | 5 | ||
| 6 | 6 | //go:cgo_import_dynamic _dlopen dlopen "/usr/lib/libSystem.B.dylib" | |
| 7 | 7 | //go:cgo_import_dynamic _dlsym dlsym "/usr/lib/libSystem.B.dylib" | |
| 8 | + | //go:cgo_import_dynamic _dlerror dlerror "/usr/lib/libSystem.B.dylib" | |
| 9 | + | //go:cgo_import_dynamic _dlclose dlclose "/usr/lib/libSystem.B.dylib" | |
| @@ -5,3 +5,5 @@ package purego | |||||
| 5 | 5 | ||||
| 6 | //go:cgo_import_dynamic _dlopen dlopen "/usr/lib/libSystem.B.dylib" | 6 | //go:cgo_import_dynamic _dlopen dlopen "/usr/lib/libSystem.B.dylib" | ||
| 7 | //go:cgo_import_dynamic _dlsym dlsym "/usr/lib/libSystem.B.dylib" | 7 | //go:cgo_import_dynamic _dlsym dlsym "/usr/lib/libSystem.B.dylib" | ||
| 8 | + | //go:cgo_import_dynamic _dlerror dlerror "/usr/lib/libSystem.B.dylib" | |||
| 9 | + | //go:cgo_import_dynamic _dlclose dlclose "/usr/lib/libSystem.B.dylib" | |||
M dlfcn_stubs.s +13 -0
| @@ -20,3 +20,16 @@ TEXT dlsym(SB), NOSPLIT, $0-0 | |||
| 20 | 20 | JMP _dlsym(SB) | |
| 21 | 21 | RET | |
| 22 | 22 | ||
| 23 | + | // func dlerror() (ret *byte) | |
| 24 | + | GLOBL ·dlerrorABI0(SB), NOPTR|RODATA, $8 | |
| 25 | + | DATA ·dlerrorABI0(SB)/8, $dlerror(SB) | |
| 26 | + | TEXT dlerror(SB), NOSPLIT, $0-0 | |
| 27 | + | JMP _dlerror(SB) | |
| 28 | + | RET | |
| 29 | + | ||
| 30 | + | // func dlclose(handle uintptr) (ret int) | |
| 31 | + | GLOBL ·dlcloseABI0(SB), NOPTR|RODATA, $8 | |
| 32 | + | DATA ·dlcloseABI0(SB)/8, $dlclose(SB) | |
| 33 | + | TEXT dlclose(SB), NOSPLIT, $0-0 | |
| 34 | + | JMP _dlclose(SB) | |
| 35 | + | RET | |
| @@ -20,3 +20,16 @@ TEXT dlsym(SB), NOSPLIT, $0-0 | |||||
| 20 | JMP _dlsym(SB) | 20 | JMP _dlsym(SB) | ||
| 21 | RET | 21 | RET | ||
| 22 | 22 | ||||
| 23 | + | // func dlerror() (ret *byte) | |||
| 24 | + | GLOBL ·dlerrorABI0(SB), NOPTR|RODATA, $8 | |||
| 25 | + | DATA ·dlerrorABI0(SB)/8, $dlerror(SB) | |||
| 26 | + | TEXT dlerror(SB), NOSPLIT, $0-0 | |||
| 27 | + | JMP _dlerror(SB) | |||
| 28 | + | RET | |||
| 29 | + | ||||
| 30 | + | // func dlclose(handle uintptr) (ret int) | |||
| 31 | + | GLOBL ·dlcloseABI0(SB), NOPTR|RODATA, $8 | |||
| 32 | + | DATA ·dlcloseABI0(SB)/8, $dlclose(SB) | |||
| 33 | + | TEXT dlclose(SB), NOSPLIT, $0-0 | |||
| 34 | + | JMP _dlclose(SB) | |||
| 35 | + | RET | |||