@@ -7,11 +7,13 @@ const assert = std.debug.assert;
7
7
const testing = std .testing ;
8
8
const elf = std .elf ;
9
9
const windows = std .os .windows ;
10
+ const system = std .os .system ;
10
11
const maxInt = std .math .maxInt ;
11
12
12
13
pub const DynLib = switch (builtin .os ) {
13
- .linux = > LinuxDynLib ,
14
+ .linux = > if ( builtin . link_libc ) DlDynlib else LinuxDynLib ,
14
15
.windows = > WindowsDynLib ,
16
+ .macosx , .tvos , .watchos , .ios = > DlDynlib ,
15
17
else = > void ,
16
18
};
17
19
@@ -99,12 +101,14 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
99
101
}
100
102
101
103
pub const LinuxDynLib = struct {
104
+ pub const Error = ElfLib .Error ;
105
+
102
106
elf_lib : ElfLib ,
103
107
fd : i32 ,
104
108
memory : []align (mem .page_size ) u8 ,
105
109
106
110
/// Trusts the file
107
- pub fn open (path : []const u8 ) ! DynLib {
111
+ pub fn open (path : []const u8 ) ! LinuxDynLib {
108
112
const fd = try os .open (path , 0 , os .O_RDONLY | os .O_CLOEXEC );
109
113
errdefer os .close (fd );
110
114
@@ -121,25 +125,43 @@ pub const LinuxDynLib = struct {
121
125
);
122
126
errdefer os .munmap (bytes );
123
127
124
- return DynLib {
128
+ return LinuxDynLib {
125
129
.elf_lib = try ElfLib .init (bytes ),
126
130
.fd = fd ,
127
131
.memory = bytes ,
128
132
};
129
133
}
130
134
131
- pub fn close (self : * DynLib ) void {
135
+ pub fn openC (path_c : [* :0 ]const u8 ) ! LinuxDynLib {
136
+ return open (mem .toSlice (u8 , path_c ));
137
+ }
138
+
139
+ pub fn close (self : * LinuxDynLib ) void {
132
140
os .munmap (self .memory );
133
141
os .close (self .fd );
134
142
self .* = undefined ;
135
143
}
136
144
137
- pub fn lookup (self : * DynLib , name : []const u8 ) ? usize {
138
- return self .elf_lib .lookup ("" , name );
145
+ pub fn lookup (self : * LinuxDynLib , comptime T : type , name : [:0 ]const u8 ) ? T {
146
+ if (self .elf_lib .lookup ("" , name )) | symbol | {
147
+ return @intToPtr (T , symbol );
148
+ } else {
149
+ return null ;
150
+ }
139
151
}
140
152
};
141
153
142
154
pub const ElfLib = struct {
155
+ pub const Error = error {
156
+ NotElfFile ,
157
+ NotDynamicLibrary ,
158
+ MissingDynamicLinkingInformation ,
159
+ BaseNotFound ,
160
+ ElfStringSectionNotFound ,
161
+ ElfSymSectionNotFound ,
162
+ ElfHashTableNotFound ,
163
+ };
164
+
143
165
strings : [* :0 ]u8 ,
144
166
syms : [* ]elf.Sym ,
145
167
hashtab : [* ]os.Elf_Symndx ,
@@ -245,13 +267,24 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [
245
267
}
246
268
247
269
pub const WindowsDynLib = struct {
270
+ pub const Error = error {FileNotFound };
271
+
248
272
dll : windows.HMODULE ,
249
273
250
274
pub fn open (path : []const u8 ) ! WindowsDynLib {
251
- const wpath = try windows .sliceToPrefixedFileW (path );
275
+ const path_w = try windows .sliceToPrefixedFileW (path );
276
+ return openW (& path_w );
277
+ }
278
+
279
+ pub fn openC (path_c : [* :0 ]const u8 ) ! WindowsDynLib {
280
+ const path_w = try windows .cStrToPrefixedFileW (path );
281
+ return openW (& path_w );
282
+ }
252
283
284
+ pub fn openW (path_w : [* :0 ]const u16 ) ! WindowsDynLib {
253
285
return WindowsDynLib {
254
- .dll = try windows .LoadLibraryW (& wpath ),
286
+ // + 4 to skip over the \??\
287
+ .dll = try windows .LoadLibraryW (path_w + 4 ),
255
288
};
256
289
}
257
290
@@ -260,21 +293,59 @@ pub const WindowsDynLib = struct {
260
293
self .* = undefined ;
261
294
}
262
295
263
- pub fn lookup (self : * WindowsDynLib , name : []const u8 ) ? usize {
264
- return @ptrToInt (windows .kernel32 .GetProcAddress (self .dll , name .ptr ));
296
+ pub fn lookup (self : * WindowsDynLib , comptime T : type , name : [:0 ]const u8 ) ? T {
297
+ if (windows .kernel32 .GetProcAddress (self .dll , name .ptr )) | addr | {
298
+ return @ptrCast (T , addr );
299
+ } else {
300
+ return null ;
301
+ }
302
+ }
303
+ };
304
+
305
+ pub const DlDynlib = struct {
306
+ pub const Error = error {FileNotFound };
307
+
308
+ handle : * c_void ,
309
+
310
+ pub fn open (path : []const u8 ) ! DlDynlib {
311
+ const path_c = try os .toPosixPath (path );
312
+ return openC (& path_c );
313
+ }
314
+
315
+ pub fn openC (path_c : [* :0 ]const u8 ) ! DlDynlib {
316
+ return DlDynlib {
317
+ .handle = system .dlopen (path_c , system .RTLD_LAZY ) orelse {
318
+ return error .FileNotFound ;
319
+ },
320
+ };
321
+ }
322
+
323
+ pub fn close (self : * DlDynlib ) void {
324
+ _ = system .dlclose (self .handle );
325
+ self .* = undefined ;
326
+ }
327
+
328
+ pub fn lookup (self : * DlDynlib , comptime T : type , name : [:0 ]const u8 ) ? T {
329
+ // dlsym (and other dl-functions) secretly take shadow parameter - return address on stack
330
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66826
331
+ if (@call (.{ .modifier = .never_tail }, system .dlsym , .{ self .handle , name .ptr })) | symbol | {
332
+ return @ptrCast (T , symbol );
333
+ } else {
334
+ return null ;
335
+ }
265
336
}
266
337
};
267
338
268
339
test "dynamic_library" {
269
340
const libname = switch (builtin .os ) {
270
341
.linux = > "invalid_so.so" ,
271
342
.windows = > "invalid_dll.dll" ,
272
- else = > return ,
343
+ .macosx , .tvos , .watchos , .ios = > "invalid_dylib.dylib" ,
344
+ else = > return error .SkipZigTest ,
273
345
};
274
346
275
347
const dynlib = DynLib .open (libname ) catch | err | {
276
348
testing .expect (err == error .FileNotFound );
277
349
return ;
278
350
};
279
- @panic ("Expected error from function" );
280
351
}
0 commit comments