From 65e4725aba5947a86c12c775b05a31cc1c08cfab Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 13 Apr 2021 13:32:59 +0200 Subject: [PATCH 1/2] Add standalone test for interdep C archives Tests a scenario where the linker line has the following: ``` main.o libA.a libB.a ``` where `main.o` pulls a symbol from `libB.a`, which in turn is dependent on a symbol from `libA.a`. --- test/standalone.zig | 1 + .../link_interdependent_static_c_libs/a.c | 4 ++++ .../link_interdependent_static_c_libs/a.h | 2 ++ .../link_interdependent_static_c_libs/b.c | 6 +++++ .../link_interdependent_static_c_libs/b.h | 2 ++ .../build.zig | 24 +++++++++++++++++++ .../main.zig | 8 +++++++ 7 files changed, 47 insertions(+) create mode 100644 test/standalone/link_interdependent_static_c_libs/a.c create mode 100644 test/standalone/link_interdependent_static_c_libs/a.h create mode 100644 test/standalone/link_interdependent_static_c_libs/b.c create mode 100644 test/standalone/link_interdependent_static_c_libs/b.h create mode 100644 test/standalone/link_interdependent_static_c_libs/build.zig create mode 100644 test/standalone/link_interdependent_static_c_libs/main.zig diff --git a/test/standalone.zig b/test/standalone.zig index d8c08a6b9c..04b8af869c 100644 --- a/test/standalone.zig +++ b/test/standalone.zig @@ -16,6 +16,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { cases.addBuildFile("test/standalone/mix_o_files/build.zig"); cases.addBuildFile("test/standalone/global_linkage/build.zig"); cases.addBuildFile("test/standalone/static_c_lib/build.zig"); + cases.addBuildFile("test/standalone/link_interdependent_static_c_libs/build.zig"); cases.addBuildFile("test/standalone/issue_339/build.zig"); cases.addBuildFile("test/standalone/issue_794/build.zig"); cases.addBuildFile("test/standalone/issue_5825/build.zig"); diff --git a/test/standalone/link_interdependent_static_c_libs/a.c b/test/standalone/link_interdependent_static_c_libs/a.c new file mode 100644 index 0000000000..ee9da97a3a --- /dev/null +++ b/test/standalone/link_interdependent_static_c_libs/a.c @@ -0,0 +1,4 @@ +#include "a.h" +int32_t add(int32_t a, int32_t b) { + return a + b; +} diff --git a/test/standalone/link_interdependent_static_c_libs/a.h b/test/standalone/link_interdependent_static_c_libs/a.h new file mode 100644 index 0000000000..7b45d54d56 --- /dev/null +++ b/test/standalone/link_interdependent_static_c_libs/a.h @@ -0,0 +1,2 @@ +#include +int32_t add(int32_t a, int32_t b); diff --git a/test/standalone/link_interdependent_static_c_libs/b.c b/test/standalone/link_interdependent_static_c_libs/b.c new file mode 100644 index 0000000000..ac2cc4f937 --- /dev/null +++ b/test/standalone/link_interdependent_static_c_libs/b.c @@ -0,0 +1,6 @@ +#include "a.h" +#include "b.h" + +int32_t sub(int32_t a, int32_t b) { + return add(a, -1 * b); +} diff --git a/test/standalone/link_interdependent_static_c_libs/b.h b/test/standalone/link_interdependent_static_c_libs/b.h new file mode 100644 index 0000000000..6047163145 --- /dev/null +++ b/test/standalone/link_interdependent_static_c_libs/b.h @@ -0,0 +1,2 @@ +#include +int32_t sub(int32_t a, int32_t b); diff --git a/test/standalone/link_interdependent_static_c_libs/build.zig b/test/standalone/link_interdependent_static_c_libs/build.zig new file mode 100644 index 0000000000..1c361b2dc6 --- /dev/null +++ b/test/standalone/link_interdependent_static_c_libs/build.zig @@ -0,0 +1,24 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + const mode = b.standardReleaseOptions(); + + const lib_a = b.addStaticLibrary("a", null); + lib_a.addCSourceFile("a.c", &[_][]const u8{}); + lib_a.setBuildMode(mode); + lib_a.addIncludeDir("."); + + const lib_b = b.addStaticLibrary("b", null); + lib_b.addCSourceFile("b.c", &[_][]const u8{}); + lib_b.setBuildMode(mode); + lib_b.addIncludeDir("."); + + const test_exe = b.addTest("main.zig"); + test_exe.setBuildMode(mode); + test_exe.linkLibrary(lib_a); + test_exe.linkLibrary(lib_b); + test_exe.addIncludeDir("."); + + const test_step = b.step("test", "Test it"); + test_step.dependOn(&test_exe.step); +} diff --git a/test/standalone/link_interdependent_static_c_libs/main.zig b/test/standalone/link_interdependent_static_c_libs/main.zig new file mode 100644 index 0000000000..1d8f854125 --- /dev/null +++ b/test/standalone/link_interdependent_static_c_libs/main.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const expect = std.testing.expect; +const c = @cImport(@cInclude("b.h")); + +test "import C sub" { + const result = c.sub(2, 1); + expect(result == 1); +} From 461543a5fd27415710f027d034b83ef196bc8a44 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 13 Apr 2021 13:36:08 +0200 Subject: [PATCH 2/2] zld: fix symbol resolution from interdep archives Fixes symbol resolution if an archive occurring later in the linker line depends on a object embedded within the archive that occurred before. --- src/link/MachO/Zld.zig | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 56a35a3bca..ae475ab30d 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -1284,17 +1284,14 @@ fn resolveSymbols(self: *Zld) !void { } // Second pass, resolve symbols in static libraries. - var next: usize = 0; - var hit: bool = undefined; - while (true) { - var archive = &self.archives.items[next]; - hit = false; - - for (self.symtab.items()) |entry| { - if (entry.value.tag != .undef) continue; - - const sym_name = entry.value.name; + var next_sym: usize = 0; + var nsyms: usize = self.symtab.items().len; + while (next_sym < nsyms) : (next_sym += 1) { + const sym = self.symtab.items()[next_sym]; + if (sym.value.tag != .undef) continue; + const sym_name = sym.value.name; + for (self.archives.items) |archive| { // Check if the entry exists in a static archive. const offsets = archive.toc.get(sym_name) orelse { // No hit. @@ -1307,18 +1304,9 @@ fn resolveSymbols(self: *Zld) !void { try self.objects.append(self.allocator, object); try self.resolveSymbolsInObject(object_id); - hit = true; + nsyms = self.symtab.items().len; break; } - - if (!hit) { - // Next archive. - next += 1; - if (next == self.archives.items.len) { - break; - } - archive = &self.archives.items[next]; - } } // Third pass, resolve symbols in dynamic libraries.