From df36ae4b90974ed5b48817f79977541319986711 Mon Sep 17 00:00:00 2001 From: emekoi Date: Thu, 30 May 2019 20:03:56 -0500 Subject: [PATCH 1/5] fixed windows dynamic library loading and added loading for darwin --- std/c/darwin.zig | 5 +++++ std/dynamic_library.zig | 45 ++++++++++++++++++++++++++++++++++++++--- std/os/bits/darwin.zig | 22 ++++++++++++++++++++ test/standalone.zig | 9 +++++---- 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/std/c/darwin.zig b/std/c/darwin.zig index f2e8120a0e87..f348192d5c73 100644 --- a/std/c/darwin.zig +++ b/std/c/darwin.zig @@ -56,3 +56,8 @@ pub fn sigaddset(set: *sigset_t, signo: u5) void { } pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; + +pub extern "c" fn dlopen_preflight(path: [*]const u8) c_int; +pub extern "c" fn dlopen(path: [*]const u8, mode: c_int) ?*c_void; +pub extern "c" fn dlclose(handle: *c_void) c_int; +pub extern "c" fn dlsym(handle: ?*c_void, symbol: [*]const u8) ?*c_void; diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 341378801970..b689607da49a 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -7,11 +7,13 @@ const assert = std.debug.assert; const testing = std.testing; const elf = std.elf; const windows = std.os.windows; +const darwin = std.os.darwin; const maxInt = std.math.maxInt; pub const DynLib = switch (builtin.os) { .linux => LinuxDynLib, .windows => WindowsDynLib, + .macosx, .tvos, .watchos, .ios => DarwinDynLib, else => void, }; @@ -249,7 +251,6 @@ pub const WindowsDynLib = struct { pub fn open(path: []const u8) !WindowsDynLib { const wpath = try windows.sliceToPrefixedFileW(path); - return WindowsDynLib{ .dll = try windows.LoadLibraryW(&wpath), }; @@ -261,7 +262,45 @@ pub const WindowsDynLib = struct { } pub fn lookup(self: *WindowsDynLib, name: []const u8) ?usize { - return @ptrToInt(windows.kernel32.GetProcAddress(self.dll, name.ptr)); + if (windows.kernel32.GetProcAddress(self.dll, name.ptr)) |addr| { + return @ptrToInt(addr); + } else { + return null; + } + } +}; + +pub const DarwinDynLib = struct { + handle: *c_void, + + pub fn open(path: []const u8) !DarwinDynLib { + // should we perform this check? + if (false) { + // check if dynamic library being loaded is compatible + if (darwin.dlopen_preflight(path) == 0) { + return error.InvalidDynLib; + } + } + + // see https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlopen.3.html + return DarwinDynLib{ + .handle = darwin.dlopen(path, darwin.RTLD_LAZY) orelse { + return error.FileNotFound; + }, + }; + } + + pub fn close(self: *DarwinDynLib) void { + _ = darwin.dlclose(self.handle); + self.* = undefined; + } + + pub fn lookup(self: *DarwinDynLib, name: []const u8) ?usize { + if (darwin.dlsym(self.handle, name.ptr)) |sym| { + return @ptrToInt(sym); + } else { + return null; + } } }; @@ -269,6 +308,7 @@ test "dynamic_library" { const libname = switch (builtin.os) { .linux => "invalid_so.so", .windows => "invalid_dll.dll", + .macosx, .tvos, .watchos, .ios => "invalid_dylib.dylib", else => return, }; @@ -276,5 +316,4 @@ test "dynamic_library" { testing.expect(err == error.FileNotFound); return; }; - @panic("Expected error from function"); } diff --git a/std/os/bits/darwin.zig b/std/os/bits/darwin.zig index 483d4cda908f..b69d959fdb99 100644 --- a/std/os/bits/darwin.zig +++ b/std/os/bits/darwin.zig @@ -1175,3 +1175,25 @@ pub fn S_ISSOCK(m: u32) bool { pub fn S_IWHT(m: u32) bool { return m & S_IFMT == S_IFWHT; } + +pub const RTLD_LAZY = 0x1; + +pub const RTLD_NOW = 0x2; + +pub const RTLD_LOCAL = 0x4; + +pub const RTLD_GLOBAL = 0x8; + +pub const RTLD_NOLOAD = 0x10; + +pub const RTLD_NODELETE = 0x80; + +pub const RTLD_FIRST = 0x100; + +pub const RTLD_NEXT = @intToPtr(*c_void, ~maxInt(usize)); + +pub const RTLD_DEFAULT = @intToPtr(*c_void, ~maxInt(usize) - 1); + +pub const RTLD_SELF = @intToPtr(*c_void, ~maxInt(usize) - 2); + +pub const RTLD_MAIN_ONLY = @intToPtr(*c_void, ~maxInt(usize) - 4); \ No newline at end of file diff --git a/test/standalone.zig b/test/standalone.zig index f3a1f735daad..7abe8fa229fb 100644 --- a/test/standalone.zig +++ b/test/standalone.zig @@ -19,10 +19,11 @@ pub fn addCases(cases: *tests.StandaloneContext) void { cases.addBuildFile("test/standalone/use_alias/build.zig"); cases.addBuildFile("test/standalone/brace_expansion/build.zig"); cases.addBuildFile("test/standalone/empty_env/build.zig"); - if (builtin.os == builtin.Os.linux) { - // TODO hook up the DynLib API for windows using LoadLibraryA - // TODO figure out how to make this work on darwin - probably libSystem has dlopen/dlsym in it - cases.addBuildFile("test/standalone/load_dynamic_library/build.zig"); + switch (builtin.os) { + .linux, .windows, .macosx, .tvos, .watchos, .ios => { + cases.addBuildFile("test/standalone/load_dynamic_library/build.zig"); + }, + else => {}, } if (builtin.arch == builtin.Arch.x86_64) { // TODO add C ABI support for other architectures From 9215beaded9e82bf580e11f158f9f37404dec434 Mon Sep 17 00:00:00 2001 From: emekoi Date: Fri, 31 May 2019 14:03:09 -0500 Subject: [PATCH 2/5] forgot to perform .ptr on slice --- std/dynamic_library.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index b689607da49a..c6fbc3735788 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -284,7 +284,7 @@ pub const DarwinDynLib = struct { // see https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlopen.3.html return DarwinDynLib{ - .handle = darwin.dlopen(path, darwin.RTLD_LAZY) orelse { + .handle = darwin.dlopen(path.ptr, darwin.RTLD_LAZY) orelse { return error.FileNotFound; }, }; From 815ed14a3f279f1b75a6870d6b70bf91218ca577 Mon Sep 17 00:00:00 2001 From: emekoi Date: Fri, 6 Sep 2019 17:18:13 -0500 Subject: [PATCH 3/5] renamed DarwinDynlib to DlDynlib --- std/c/darwin.zig | 1 - std/dynamic_library.zig | 87 +++++++++++++++++++++++++++++------------ std/os/bits/darwin.zig | 11 +----- std/os/bits/linux.zig | 2 +- 4 files changed, 63 insertions(+), 38 deletions(-) diff --git a/std/c/darwin.zig b/std/c/darwin.zig index f348192d5c73..c21134ff64cf 100644 --- a/std/c/darwin.zig +++ b/std/c/darwin.zig @@ -57,7 +57,6 @@ pub fn sigaddset(set: *sigset_t, signo: u5) void { pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; -pub extern "c" fn dlopen_preflight(path: [*]const u8) c_int; pub extern "c" fn dlopen(path: [*]const u8, mode: c_int) ?*c_void; pub extern "c" fn dlclose(handle: *c_void) c_int; pub extern "c" fn dlsym(handle: ?*c_void, symbol: [*]const u8) ?*c_void; diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index c6fbc3735788..1f23a104727e 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -7,13 +7,13 @@ const assert = std.debug.assert; const testing = std.testing; const elf = std.elf; const windows = std.os.windows; -const darwin = std.os.darwin; +const system = std.os.system; const maxInt = std.math.maxInt; pub const DynLib = switch (builtin.os) { .linux => LinuxDynLib, .windows => WindowsDynLib, - .macosx, .tvos, .watchos, .ios => DarwinDynLib, + .macosx, .tvos, .watchos, .ios => DlDynlib, else => void, }; @@ -101,12 +101,14 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator { } pub const LinuxDynLib = struct { + pub const Error = ElfLib.Error; + elf_lib: ElfLib, fd: i32, memory: []align(mem.page_size) u8, /// Trusts the file - pub fn open(path: []const u8) !DynLib { + pub fn open(path: []const u8) !LinuxDynLib { const fd = try os.open(path, 0, os.O_RDONLY | os.O_CLOEXEC); errdefer os.close(fd); @@ -123,25 +125,39 @@ pub const LinuxDynLib = struct { ); errdefer os.munmap(bytes); - return DynLib{ + return LinuxDynLib{ .elf_lib = try ElfLib.init(bytes), .fd = fd, .memory = bytes, }; } - pub fn close(self: *DynLib) void { + pub fn close(self: *LinuxDynLib) void { os.munmap(self.memory); os.close(self.fd); self.* = undefined; } - pub fn lookup(self: *DynLib, name: []const u8) ?usize { - return self.elf_lib.lookup("", name); + pub fn lookup(self: *LinuxDynLib, comptime T: type, name: []const u8) ?T { + if (self.elf_lib.lookup("", name)) |symbol| { + return @ptrCast(T, symbol); + } else { + return null; + } } }; pub const ElfLib = struct { + pub const Error = error{ + NotElfFile, + NotDynamicLibrary, + MissingDynamicLinkingInformation, + BaseNotFound, + ElfStringSectionNotFound, + ElfSymSectionNotFound, + ElfHashTableNotFound, + }; + strings: [*]u8, syms: [*]elf.Sym, hashtab: [*]os.Elf_Symndx, @@ -247,6 +263,11 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [ } pub const WindowsDynLib = struct { + pub const Error = error{ + FileNotFound, + SymbolTooLong, + }; + dll: windows.HMODULE, pub fn open(path: []const u8) !WindowsDynLib { @@ -261,43 +282,57 @@ pub const WindowsDynLib = struct { self.* = undefined; } - pub fn lookup(self: *WindowsDynLib, name: []const u8) ?usize { - if (windows.kernel32.GetProcAddress(self.dll, name.ptr)) |addr| { - return @ptrToInt(addr); + pub fn lookup(self: *WindowsDynLib, comptime T: type, name: []const u8) !?T { + const c_name: [512]u8 = []u8{0} ** 512; + if (name.len > 512) { + return error.SymbolTooLong; + } + + mem.copy(&c_name, name); + + if (windows.kernel32.GetProcAddress(self.dll, (&c_name).ptr)) |addr| { + return @ptrCast(T, addr); } else { return null; } } }; -pub const DarwinDynLib = struct { +pub const DlDynlib = struct { + pub const Error = error{ + FileNotFound, + SymbolTooLong, + }; + handle: *c_void, - pub fn open(path: []const u8) !DarwinDynLib { - // should we perform this check? - if (false) { - // check if dynamic library being loaded is compatible - if (darwin.dlopen_preflight(path) == 0) { - return error.InvalidDynLib; - } + pub fn open(path: []const u8) !DlDynlib { + if (!builtin.link_libc and !os.darwin.is_the_target) { + @compileError("DlDynlib requires libc"); } - // see https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlopen.3.html - return DarwinDynLib{ - .handle = darwin.dlopen(path.ptr, darwin.RTLD_LAZY) orelse { + return DlDynlib{ + .handle = system.dlopen(path.ptr, system.RTLD_LAZY) orelse { return error.FileNotFound; }, }; } - pub fn close(self: *DarwinDynLib) void { - _ = darwin.dlclose(self.handle); + pub fn close(self: *DlDynlib) void { + _ = system.dlclose(self.handle); self.* = undefined; } - pub fn lookup(self: *DarwinDynLib, name: []const u8) ?usize { - if (darwin.dlsym(self.handle, name.ptr)) |sym| { - return @ptrToInt(sym); + pub fn lookup(self: *DlDynlib, comptime T: type, name: []const u8) !?T { + const c_name: [512]u8 = []u8{0} ** 512; + if (name.len > 512) { + return error.SymbolTooLong; + } + + mem.copy(&c_name, name); + + if (system.dlsym(self.handle, (&c_name).ptr)) |symbol| { + return @ptrCast(T, symbol); } else { return null; } diff --git a/std/os/bits/darwin.zig b/std/os/bits/darwin.zig index b69d959fdb99..4640d9ce2c18 100644 --- a/std/os/bits/darwin.zig +++ b/std/os/bits/darwin.zig @@ -1177,23 +1177,14 @@ pub fn S_IWHT(m: u32) bool { } pub const RTLD_LAZY = 0x1; - pub const RTLD_NOW = 0x2; - pub const RTLD_LOCAL = 0x4; - pub const RTLD_GLOBAL = 0x8; - pub const RTLD_NOLOAD = 0x10; - pub const RTLD_NODELETE = 0x80; - pub const RTLD_FIRST = 0x100; pub const RTLD_NEXT = @intToPtr(*c_void, ~maxInt(usize)); - pub const RTLD_DEFAULT = @intToPtr(*c_void, ~maxInt(usize) - 1); - pub const RTLD_SELF = @intToPtr(*c_void, ~maxInt(usize) - 2); - -pub const RTLD_MAIN_ONLY = @intToPtr(*c_void, ~maxInt(usize) - 4); \ No newline at end of file +pub const RTLD_MAIN_ONLY = @intToPtr(*c_void, ~maxInt(usize) - 4); diff --git a/std/os/bits/linux.zig b/std/os/bits/linux.zig index 0617378da9f5..dcb79c55ca78 100644 --- a/std/os/bits/linux.zig +++ b/std/os/bits/linux.zig @@ -1,4 +1,4 @@ -const builtin = @import("builtin"); + const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; usingnamespace @import("../bits.zig"); From 58d526ec0934788db783b982e0b2616b9c9ae59b Mon Sep 17 00:00:00 2001 From: emekoi Date: Fri, 6 Sep 2019 18:12:23 -0500 Subject: [PATCH 4/5] removed error case from Dynlib.lookup --- std/dynamic_library.zig | 46 ++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 1f23a104727e..653c8242f789 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -263,10 +263,7 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [ } pub const WindowsDynLib = struct { - pub const Error = error{ - FileNotFound, - SymbolTooLong, - }; + pub const Error = error{FileNotFound}; dll: windows.HMODULE, @@ -282,27 +279,24 @@ pub const WindowsDynLib = struct { self.* = undefined; } - pub fn lookup(self: *WindowsDynLib, comptime T: type, name: []const u8) !?T { - const c_name: [512]u8 = []u8{0} ** 512; - if (name.len > 512) { - return error.SymbolTooLong; - } - - mem.copy(&c_name, name); - - if (windows.kernel32.GetProcAddress(self.dll, (&c_name).ptr)) |addr| { + pub fn lookupC(self: *WindowsDynLib, comptime T: type, name: [*]const u8) ?T { + if (windows.kernel32.GetProcAddress(self.dll, name)) |addr| { return @ptrCast(T, addr); } else { return null; } } + + pub fn lookup(self: *DlDynlib, comptime T: type, comptime max_name_len: usize, name: []const u8) ?T { + const c_name: [max_name_len]u8 = undefined; + mem.copy(&c_name, name); + c_name[name.len] = 0; + return self.lookupC(T, &c_name); + } }; pub const DlDynlib = struct { - pub const Error = error{ - FileNotFound, - SymbolTooLong, - }; + pub const Error = error{FileNotFound}; handle: *c_void, @@ -323,20 +317,20 @@ pub const DlDynlib = struct { self.* = undefined; } - pub fn lookup(self: *DlDynlib, comptime T: type, name: []const u8) !?T { - const c_name: [512]u8 = []u8{0} ** 512; - if (name.len > 512) { - return error.SymbolTooLong; - } - - mem.copy(&c_name, name); - - if (system.dlsym(self.handle, (&c_name).ptr)) |symbol| { + pub fn lookupC(self: *DlDynlib, comptime T: type, name: [*]const u8) ?T { + if (system.dlsym(self.handle, name)) |symbol| { return @ptrCast(T, symbol); } else { return null; } } + + pub fn lookup(self: *DlDynlib, comptime T: type, comptime max_name_len: usize, name: []const u8) ?T { + const c_name: [max_name_len]u8 = undefined; + mem.copy(&c_name, name); + c_name[name.len] = 0; + return self.lookupC(T, &c_name); + } }; test "dynamic_library" { From 908cfcd94e408da745a14435076b0215062b4a21 Mon Sep 17 00:00:00 2001 From: emekoi Date: Fri, 6 Sep 2019 18:30:19 -0500 Subject: [PATCH 5/5] use DlDynlib when linked to libc on linux --- std/dynamic_library.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 653c8242f789..5ca276bb43e7 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -11,7 +11,7 @@ const system = std.os.system; const maxInt = std.math.maxInt; pub const DynLib = switch (builtin.os) { - .linux => LinuxDynLib, + .linux => if (builtin.link_libc) DlDynlib else LinuxDynLib, .windows => WindowsDynLib, .macosx, .tvos, .watchos, .ios => DlDynlib, else => void,