1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#+build darwin, linux, freebsd, openbsd, netbsd
package posix
import "core:c"
when ODIN_OS == .Darwin {
foreign import lib "system:System"
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
foreign import lib "system:dl"
} else {
foreign import lib {
"system:c",
"system:dl",
}
}
// dlfcn.h - dynamic linking
foreign lib {
/*
inform the system that the object referenced by a handle returned from a previous dlopen()
invocation is no longer needed by the application.
Returns: 0 on success, non-zero on failure (use dlerror() for more information)
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlclose.html ]]
*/
dlclose :: proc(handle: Symbol_Table) -> c.int ---
/*
return a null-terminated character string (with no trailing <newline>) that describes
the last error that occurred during dynamic linking processing.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlerror.html ]]
*/
dlerror :: proc() -> cstring ---
/*
Make the symbols (function identifiers and data object identifiers) in the executable object
file specified by file available to the calling program.
Returns: a reference to the symbol table on success, nil on failure (use dlerror() for more information)
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html ]]
*/
dlopen :: proc(file: cstring, mode: RTLD_Flags) -> Symbol_Table ---
/*
Obtain the address of a symbol (a function identifier or a data object identifier)
defined in the symbol table identified by the handle argument.
Returns: the address of the matched symbol on success, nil on failure (use dlerror() for more information)
Example:
handle := posix.dlopen("/usr/home/me/libfoo.so", posix.RTLD_LOCAL + { .RTLD_LAZY })
defer posix.dlclose(handle)
if handle == nil {
panic(string(posix.dlerror()))
}
foo: proc(a, b: int) -> int
foo = auto_cast posix.dlsym(handle, "foo")
if foo == nil {
panic(string(posix.dlerror()))
}
fmt.printfln("foo(%v, %v) == %v", 1, 2, foo(1, 2))
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html ]]
*/
dlsym :: proc(handle: Symbol_Table, name: cstring) -> rawptr ---
}
RTLD_Flag_Bits :: enum c.int {
LAZY = log2(RTLD_LAZY),
NOW = log2(RTLD_NOW),
GLOBAL = log2(RTLD_GLOBAL),
// NOTE: use with `posix.RTLD_LOCAL + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
// this bit set enum because it is 0 on some platforms and a value on others.
// LOCAL = RTLD_LOCAL
_MAX = 31,
}
RTLD_Flags :: bit_set[RTLD_Flag_Bits; c.int]
Symbol_Table :: distinct rawptr
when ODIN_OS == .Darwin {
RTLD_LAZY :: 0x1
RTLD_NOW :: 0x2
_RTLD_LOCAL :: 0x4
RTLD_GLOBAL :: 0x8
RTLD_LOCAL :: RTLD_Flags{RTLD_Flag_Bits(log2(_RTLD_LOCAL))}
} else when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
RTLD_LAZY :: 1
RTLD_NOW :: 2
_RTLD_LOCAL :: 0
RTLD_GLOBAL :: 0x100
RTLD_LOCAL :: RTLD_Flags{}
} else when ODIN_OS == .NetBSD {
RTLD_LAZY :: 0x1
RTLD_NOW :: 0x2
_RTLD_LOCAL :: 0x200
RTLD_GLOBAL :: 0x100
RTLD_LOCAL :: RTLD_Flags{RTLD_Flag_Bits(log2(_RTLD_LOCAL))}
} else when ODIN_OS == .Linux {
RTLD_LAZY :: 0x001
RTLD_NOW :: 0x002
RTLD_GLOBAL :: 0x100
_RTLD_LOCAL :: 0
RTLD_LOCAL :: RTLD_Flags{}
}
|