1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3
4//go:build darwin
5// +build darwin
6
7package purego
8
9import (
10 "reflect"
11 "runtime"
12 "unsafe"
13
14 "github.com/ebitengine/purego/internal/strings"
15)
16
17const RTLD_GLOBAL = 0x8
18
19const RTLD_DEFAULT = ^uintptr(1)
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.
29func Dlopen(path string, mode int) uintptr {
30 bs := strings.CString(path)
31 ret, _, _ := SyscallN(dlopenABI0, uintptr(unsafe.Pointer(bs)), uintptr(mode), 0)
32 runtime.KeepAlive(bs)
33 return ret
34}
35
36// Dlsym takes a "handle" of a dynamic library returned by Dlopen and the symbol name.
37// It returns the address where that symbol is loaded into memory. If the symbol is not found,
38// in the specified library or any of the libraries that were automatically loaded by Dlopen
39// when that library was loaded, Dlsym returns zero.
40func Dlsym(handle uintptr, name string) uintptr {
41 bs := strings.CString(name)
42 ret, _, _ := SyscallN(dlsymABI0, handle, uintptr(unsafe.Pointer(bs)), 0)
43 runtime.KeepAlive(bs)
44 return ret
45}
46
47// Dlerror returns a human-readable string describing the most recent error that
48// occurred from Dlopen, Dlsym or Dlclose since the last call to Dlerror. It
49// returns an empty string if no errors have occurred since initialization or
50// since it was last called.
51func Dlerror() string {
52 // msg is only valid until the next call to Dlerror
53 // which is why it gets copied into a Go string
54 msg, _, _ := SyscallN(dlerrorABI0)
55 if msg == 0 {
56 return ""
57 }
58 var length int
59 for {
60 // use unsafe.Add once we reach 1.17
61 if *(*byte)(unsafe.Pointer(msg + uintptr(length))) == '\x00' {
62 break
63 }
64 length++
65 }
66 // use unsafe.Slice once we reach 1.17
67 s := make([]byte, length)
68 var src []byte
69 h := (*reflect.SliceHeader)(unsafe.Pointer(&src))
70 h.Data = msg
71 h.Len = length
72 h.Cap = length
73 copy(s, src)
74 return string(s)
75}
76
77// Dlclose decrements the reference count on the dynamic library handle.
78// If the reference count drops to zero and no other loaded libraries
79// use symbols in it, then the dynamic library is unloaded.
80// Dlclose returns false on success, and true on error.
81func Dlclose(handle uintptr) bool {
82 ret, _, _ := SyscallN(dlcloseABI0, handle)
83 return ret != 0
84}
85
86// these functions exist in dlfcn_stubs.s and are calling C functions linked to in dlfcn_GOOS.go
87var dlopenABI0 uintptr
88var dlsymABI0 uintptr
89var dlcloseABI0 uintptr
90var dlerrorABI0 uintptr