dlfcn.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // SPDX-License-Identifier: Apache-2.0
  2. // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
  3. //go:build (darwin || freebsd || linux) && !android && !faketime
  4. package purego
  5. import (
  6. "unsafe"
  7. )
  8. // Unix Specification for dlfcn.h: https://pubs.opengroup.org/onlinepubs/7908799/xsh/dlfcn.h.html
  9. var (
  10. fnDlopen func(path string, mode int) uintptr
  11. fnDlsym func(handle uintptr, name string) uintptr
  12. fnDlerror func() string
  13. fnDlclose func(handle uintptr) bool
  14. )
  15. func init() {
  16. RegisterFunc(&fnDlopen, dlopenABI0)
  17. RegisterFunc(&fnDlsym, dlsymABI0)
  18. RegisterFunc(&fnDlerror, dlerrorABI0)
  19. RegisterFunc(&fnDlclose, dlcloseABI0)
  20. }
  21. // Dlopen examines the dynamic library or bundle file specified by path. If the file is compatible
  22. // with the current process and has not already been loaded into the
  23. // current process, it is loaded and linked. After being linked, if it contains
  24. // any initializer functions, they are called, before Dlopen
  25. // returns. It returns a handle that can be used with Dlsym and Dlclose.
  26. // A second call to Dlopen with the same path will return the same handle, but the internal
  27. // reference count for the handle will be incremented. Therefore, all
  28. // Dlopen calls should be balanced with a Dlclose call.
  29. //
  30. // This function is not available on Windows.
  31. // Use [golang.org/x/sys/windows.LoadLibrary], [golang.org/x/sys/windows.LoadLibraryEx],
  32. // [golang.org/x/sys/windows.NewLazyDLL], or [golang.org/x/sys/windows.NewLazySystemDLL] for Windows instead.
  33. func Dlopen(path string, mode int) (uintptr, error) {
  34. u := fnDlopen(path, mode)
  35. if u == 0 {
  36. return 0, Dlerror{fnDlerror()}
  37. }
  38. return u, nil
  39. }
  40. // Dlsym takes a "handle" of a dynamic library returned by Dlopen and the symbol name.
  41. // It returns the address where that symbol is loaded into memory. If the symbol is not found,
  42. // in the specified library or any of the libraries that were automatically loaded by Dlopen
  43. // when that library was loaded, Dlsym returns zero.
  44. //
  45. // This function is not available on Windows.
  46. // Use [golang.org/x/sys/windows.GetProcAddress] for Windows instead.
  47. func Dlsym(handle uintptr, name string) (uintptr, error) {
  48. u := fnDlsym(handle, name)
  49. if u == 0 {
  50. return 0, Dlerror{fnDlerror()}
  51. }
  52. return u, nil
  53. }
  54. // Dlclose decrements the reference count on the dynamic library handle.
  55. // If the reference count drops to zero and no other loaded libraries
  56. // use symbols in it, then the dynamic library is unloaded.
  57. //
  58. // This function is not available on Windows.
  59. // Use [golang.org/x/sys/windows.FreeLibrary] for Windows instead.
  60. func Dlclose(handle uintptr) error {
  61. if fnDlclose(handle) {
  62. return Dlerror{fnDlerror()}
  63. }
  64. return nil
  65. }
  66. func loadSymbol(handle uintptr, name string) (uintptr, error) {
  67. return Dlsym(handle, name)
  68. }
  69. // these functions exist in dlfcn_stubs.s and are calling C functions linked to in dlfcn_GOOS.go
  70. // the indirection is necessary because a function is actually a pointer to the pointer to the code.
  71. // sadly, I do not know of anyway to remove the assembly stubs entirely because //go:linkname doesn't
  72. // appear to work if you link directly to the C function on darwin arm64.
  73. //go:linkname dlopen dlopen
  74. var dlopen uint8
  75. var dlopenABI0 = uintptr(unsafe.Pointer(&dlopen))
  76. //go:linkname dlsym dlsym
  77. var dlsym uint8
  78. var dlsymABI0 = uintptr(unsafe.Pointer(&dlsym))
  79. //go:linkname dlclose dlclose
  80. var dlclose uint8
  81. var dlcloseABI0 = uintptr(unsafe.Pointer(&dlclose))
  82. //go:linkname dlerror dlerror
  83. var dlerror uint8
  84. var dlerrorABI0 = uintptr(unsafe.Pointer(&dlerror))