-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lld-link: duplicate symbol: ___chkstk_ms with addSharedLibrary #15107
Comments
Does it also happen when building an executable rather than a DLL? If so, we are probably re-exporting the offending symbols one too many times in our |
If I build the DLL as a separate executable, no. In the current build script, I am linking the library to an executable. And that is what causes the issue. |
I think I've gotten to the bottom of this. It comes down to behavior added here https://reviews.llvm.org/D38760 to LLD, which causes all symbols to be exported if none are explicitly marked for export. This is a mingw thing, link.exe doesn't do this. This is the function that does this in
So, on If using It seems there are a couple ways we could solve this issue:
I can work on a PR for this, but it would be great to get your feedback on which direction to go @kubkon Building the DLL with MSVC:
Building the DLL with zig build, using __declspec(dllexport) in the C code
Building the DLL with zig, not using __declspec(dllexport) in the c code
|
I haven't looked in detail into this but here's my main observation with a suggestion of exploring the problem space a little more. The collision happens when trying to link an executable with a shared library. When linking executable, regardless if linking with a shared object or not, we always provide a static lib of compiler-rt symbols each marked as weak so that they can easily be overwritten by user's definition if available. Here, for some reason, we get a collision. When creating a shared object all compiler-rt symbols were re-exported (and their binding promoted to strong as is customary I believe tho not sure if required, we could investigate that in our self-hosted linkers). So we have a situation like this:
Symbols in None of this is satisfactory as I don't want the shared object to re-export compiler-rt symbols ever. @kcbanner would you be up for some more investigation here? The next step would be to figure out why the collision is actually happening in the linker. I would also like to learn how the linker handles symbol binding promotion, in particular upgrading weak to strong. I realise it would have been so much simpler to reason about and fix if we had a working traditional COFF linker but sadly we are not there yet, and I currently don't have the cycles to spare - too deep in ELF currently. Also, I am happy to push this issue back to 0.12 milestone - I'd rather we solved it properly the first time round than put a bandaid on it and let it burst again in the near future. Also, does this problem also repro when build a shared object from Zig sources and not C? |
For comparison, it doesn't look like this problem happens with ELF:
|
@marler8997 and I hit this while working on a build script for Orca (https://github.com/allyourcodebase/orca) |
Doesn't seem to be limited to shared libraries, I also hit this while trying to link a Rust-built static library:
|
And once more, this time due to
|
Also met this when I try to build djvulibre using wget http://downloads.sourceforge.net/djvu/djvulibre-3.5.28.tar.gz
tar xzf djvulibre-3.5.28.tar.gz && cd djvulibre-3.5.28
./configure CC="zig cc" CXX="zig c++ -std=c++11" AR="zig ar" RANLIB="zig ranlib"
make Log:
|
Also encountering this when linking wasmtime on windows:
|
Like @linusg and @dcov, hitting this when using Zig as the cross-compiler and linker for Rust. Temporary workaround for the crt symbols is to manually filter out the rust-provided crt object files from the link command. But I don't have a workaround for the |
I attempted to create a shared library, but encountered an error when running
//build.zig
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const lib = b.addSharedLibrary(.{
.name = "zlo",
.root_source_file = .{ .path = "src/root.zig" },
.target = target,
.optimize = optimize,
});
const ziglua = b.dependency("ziglua", .{
.target = target,
.optimize = optimize,
.lang = .lua53,
.shared = true,
});
lib.root_module.addImport("ziglua", ziglua.module("ziglua"));
b.installArtifact(lib);
} //src/root.zig
const ziglua = @import("ziglua");
fn zlo(lua: *ziglua.Lua) i32 {
lua.newLib(&.{
.{ .name = "add", .func = ziglua.wrap(add) },
});
return 1;
}
fn add(lua: *ziglua.Lua) i32 {
const a = lua.toInteger(1) catch 0;
const b = lua.toInteger(2) catch 0;
lua.pushInteger(a + b);
return 1;
}
comptime {
_ = ziglua.exportFn("zlo", zlo);
} |
So I thought I should be able to work around this by simply asking zig cc to skip including Bug or intended? Also, @kubkon, you mentioned that the zig/lib/compiler_rt/stack_probe.zig Line 20 in 341857e
Bug or intended? |
Hacky workaround for the rust case is to unpack the rust rlib ( |
I encountered the ___chkstk_ms duplicate symbol when trying to build zlib for windows. |
@kubkon mentioned that `compiler_rt` symbols should have weak linkage, but that wasn't the case for `__chkstk_ms` which was causing conflicts during linking in some circumstances (specifically with linking object files from Rust sources). This PR switches `__chkstk_ms` to have weak linkage. ziglang#15107
@kubkon mentioned that `compiler_rt` symbols should have weak linkage, but that wasn't the case for `__chkstk_ms` which was causing conflicts during linking in some circumstances (specifically with linking object files from Rust sources). This PR switches `__chkstk_ms` to have weak linkage. ziglang#15107
* Update `__chkstk_ms` to have weak linkage `__chkstk_ms` was causing conflicts during linking in some circumstances (specifically with linking object files from Rust sources). This PR switches `__chkstk_ms` to have weak linkage. #15107 * Update stack_probe.zig to weak linkage for all symbols
I can confirm this is fixed for me by #20138 🎉 |
* Update `__chkstk_ms` to have weak linkage `__chkstk_ms` was causing conflicts during linking in some circumstances (specifically with linking object files from Rust sources). This PR switches `__chkstk_ms` to have weak linkage. ziglang#15107 * Update stack_probe.zig to weak linkage for all symbols
* Update `__chkstk_ms` to have weak linkage `__chkstk_ms` was causing conflicts during linking in some circumstances (specifically with linking object files from Rust sources). This PR switches `__chkstk_ms` to have weak linkage. ziglang#15107 * Update stack_probe.zig to weak linkage for all symbols
* Update `__chkstk_ms` to have weak linkage `__chkstk_ms` was causing conflicts during linking in some circumstances (specifically with linking object files from Rust sources). This PR switches `__chkstk_ms` to have weak linkage. ziglang#15107 * Update stack_probe.zig to weak linkage for all symbols
Hello, zig build -Dtarget=x86_64-windows I get the following output:
Build.zig.zon: .{
.name = "lua",
.version = "5.4.7",
.dependencies = .{
.lua = .{
.url = "https://www.lua.org/ftp/lua-5.4.7.tar.gz",
.hash = "12206df90729936e110f5d2574437be370fc4367b5f44afcc77749ac421547bc8ff0",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"LICENSE",
"README.md",
},
} Build.zig const std = @import("std");
const Build = std.Build;
const StringList = std.ArrayList([]const u8);
const ResolvedTarget = Build.ResolvedTarget;
const OptimizeMode = std.builtin.OptimizeMode;
const version = std.SemanticVersion{
.major = 5,
.minor = 4,
.patch = 7,
};
const lib_name = "lua";
const exe_name = lib_name;
const compiler_name = "luac";
pub fn build(b: *Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseFast });
const build_shared = b.option(bool, "shared", "build as shared library") orelse target.result.isMinGW();
const use_readline =
if (target.result.os.tag == .linux)
b.option(bool, "use_readline", "readline support for linux") orelse false
else
null;
const lua_src = b.dependency("lua", .{});
const lib =
b.addStaticLibrary(artifactOptions(
.{ .shared = false },
.{ .target = target, .optimize = optimize },
));
const shared = if (build_shared)
b.addSharedLibrary(artifactOptions(
.{ .shared = true },
.{ .target = target, .optimize = optimize },
))
else
null;
const exe = b.addExecutable(artifactOptions(.exe, .{
.target = target,
.optimize = optimize,
}));
const exec = b.addExecutable(artifactOptions(.exec, .{
.target = target,
.optimize = optimize,
}));
if (!target.result.isMinGW()) {
lib.linkSystemLibrary("m");
exe.linkSystemLibrary("m");
exec.linkSystemLibrary("m");
}
const build_targets = [_]?*Build.Step.Compile{
lib,
exe,
exec,
shared,
};
// Common compile flags
for (&build_targets) |tr| {
if (tr == null)
continue;
const t = tr.?;
t.linkLibC();
t.addIncludePath(lua_src.path("src"));
switch (target.result.os.tag) {
.aix => {
t.defineCMacro("LUA_USE_POSIX", null);
t.defineCMacro("LUA_USE_DLOPEN", null);
t.linkSystemLibrary("dl");
},
.freebsd, .netbsd, .openbsd => {
t.defineCMacro("LUA_USE_LINUX", null);
t.defineCMacro("LUA_USE_READLINE", null);
t.addIncludePath(.{ .cwd_relative = "/usr/include/edit" });
t.linkSystemLibrary("edit");
},
.ios => {
t.defineCMacro("LUA_USE_IOS", null);
},
.linux => {
t.defineCMacro("LUA_USE_LINUX", null);
t.linkSystemLibrary("dl");
if (use_readline.?) {
t.defineCMacro("LUA_USE_READLINE", null);
t.linkSystemLibrary("readline");
}
},
.macos => {
t.defineCMacro("LUA_USE_MACOSX", null);
t.defineCMacro("LUA_USE_READLINE", null);
t.linkSystemLibrary("readline");
},
.solaris => {
t.defineCMacro("LUA_USE_POSIX", null);
t.defineCMacro("LUA_USE_DLOPEN", null);
t.defineCMacro("_REENTRANT", null);
t.linkSystemLibrary("dl");
},
else => {},
}
}
if (target.result.isMinGW()) {
lib.defineCMacro("LUA_BUILD_AS_DLL", null);
exe.defineCMacro("LUA_BUILD_AS_DLL", null);
}
if (shared) |s| {
s.addCSourceFiles(.{
.root = lua_src.path("src"),
.files = &base_src,
.flags = &cflags,
});
s.installHeadersDirectory(
lua_src.path("src"),
"",
.{ .include_extensions = &lua_inc },
);
}
lib.addCSourceFiles(.{
.root = lua_src.path("src"),
.files = &base_src,
.flags = &cflags,
});
lib.installHeadersDirectory(
lua_src.path("src"),
"",
.{ .include_extensions = &lua_inc },
);
exe.addCSourceFile(.{
.file = lua_src.path("src/lua.c"),
.flags = &cflags,
});
exec.addCSourceFile(.{
.file = lua_src.path("src/luac.c"),
.flags = &cflags,
});
if (shared) |s| {
exe.linkLibrary(s);
b.installArtifact(s);
} else {
exe.linkLibrary(lib);
b.installArtifact(lib);
}
exec.linkLibrary(lib);
b.installArtifact(exe);
b.installArtifact(exec);
b.installDirectory(.{
.source_dir = lua_src.path("doc"),
.include_extensions = &.{".1"},
.install_dir = .{ .custom = "man" },
.install_subdir = "man1",
});
const run_step = b.step("run", "run lua interpreter");
const run_cmd = b.addRunArtifact(exe);
run_step.dependOn(&run_cmd.step);
const unpack_step = b.step("unpack", "unpack source");
const unpack_cmd = b.addInstallDirectory(.{
.source_dir = lua_src.path(""),
.install_dir = .prefix,
.install_subdir = "",
});
unpack_step.dependOn(&unpack_cmd.step);
}
const ArtifactTarget = union(enum) {
// True if shared options
shared: bool,
exe,
exec,
};
const ArtifactTargetOptions = struct {
target: ResolvedTarget,
optimize: OptimizeMode,
};
fn artifactOptions(comptime options: ArtifactTarget, opts: ArtifactTargetOptions) switch (options) {
.exe, .exec => Build.ExecutableOptions,
.shared => |shared| if (shared)
Build.SharedLibraryOptions
else
Build.StaticLibraryOptions,
} {
const t = opts.target.result.os.tag;
return switch (options) {
.shared => |shared| if (shared) blk: {
switch (t) {
else => break :blk .{
.name = lib_name,
.target = opts.target,
.optimize = opts.optimize,
.strip = true,
},
}
} else blk: {
switch (t) {
else => break :blk .{
.name = lib_name,
.target = opts.target,
.optimize = opts.optimize,
},
}
},
.exe => switch (t) {
else => .{
.name = exe_name,
.target = opts.target,
.optimize = opts.optimize,
},
},
.exec => switch (t) {
else => .{
.name = compiler_name,
.target = opts.target,
.optimize = opts.optimize,
},
},
};
}
const cflags = [_][]const u8{
"-std=gnu99",
"-Wall",
"-Wextra",
};
const core_src = [_][]const u8{
"lapi.c",
"lcode.c",
"lctype.c",
"ldebug.c",
"ldo.c",
"ldump.c",
"lfunc.c",
"lgc.c",
"llex.c",
"lmem.c",
"lobject.c",
"lopcodes.c",
"lparser.c",
"lstate.c",
"lstring.c",
"ltable.c",
"ltm.c",
"lundump.c",
"lvm.c",
"lzio.c",
};
const lib_src = [_][]const u8{
"lauxlib.c",
"lbaselib.c",
"lcorolib.c",
"ldblib.c",
"liolib.c",
"lmathlib.c",
"loadlib.c",
"loslib.c",
"lstrlib.c",
"ltablib.c",
"lutf8lib.c",
"linit.c",
};
const base_src = core_src ++ lib_src;
const lua_inc = [_][]const u8{
"lua.h",
"luaconf.h",
"lualib.h",
"lauxlib.h",
"lua.hpp",
}; zig version:
|
0.13.0 was released on June 7, the fix got merged on July 11. Use zig master. |
Zig Version
0.11.0-dev.2298+5d63d1115
Steps to Reproduce and Observed Behavior
Operating System: Windows 10 Home 19045.2728
zig build
If you replace
addSharedLibrary
withaddStaticLibrary
, there are no errors.Expected Behavior
Compile with no warnings and errors.
The text was updated successfully, but these errors were encountered: