authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-06 22:44:58+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-09 13:51:02-07:00
log8d488246da1665f147dcc00b5e6d253cfc3598eb
tree04bb4f743640caaeedf57f8117637c58eaf1811c
parent5f74bec076524612328d41ba362a8ff6c9c6a525

Merge pull request #13463 from ziglang/fix-13056

macho: parse weak imports in tbd descriptors

5 files changed, 83 insertions(+), 6 deletions(-)

src/link/MachO/Dylib.zig+36-6
...@@ -22,7 +22,14 @@ weak: bool = false,...@@ -22,7 +22,14 @@ weak: bool = false,
22/// Parsed symbol table represented as hash map of symbols'22/// Parsed symbol table represented as hash map of symbols'
23/// names. We can and should defer creating *Symbols until23/// names. We can and should defer creating *Symbols until
24/// a symbol is referenced by an object file.24/// a symbol is referenced by an object file.
25symbols: std.StringArrayHashMapUnmanaged(void) = .{},25///
26/// The value for each parsed symbol represents whether the
27/// symbol is defined as a weak symbol or strong.
28/// TODO when the referenced symbol is weak, ld64 marks it as
29/// N_REF_TO_WEAK but need to investigate if there's more to it
30/// such as weak binding entry or simply weak. For now, we generate
31/// standard bind or lazy bind.
32symbols: std.StringArrayHashMapUnmanaged(bool) = .{},
2633
27pub const Id = struct {34pub const Id = struct {
28 name: []const u8,35 name: []const u8,
...@@ -168,7 +175,7 @@ pub fn parseFromBinary(...@@ -168,7 +175,7 @@ pub fn parseFromBinary(
168 if (!add_to_symtab) continue;175 if (!add_to_symtab) continue;
169176
170 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);177 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);
171 try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, sym_name), {});178 try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, sym_name), false);
172 }179 }
173 },180 },
174 .ID_DYLIB => {181 .ID_DYLIB => {
...@@ -202,25 +209,30 @@ fn addObjCClassSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8)...@@ -202,25 +209,30 @@ fn addObjCClassSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8)
202209
203 for (expanded) |sym| {210 for (expanded) |sym| {
204 if (self.symbols.contains(sym)) continue;211 if (self.symbols.contains(sym)) continue;
205 try self.symbols.putNoClobber(allocator, sym, {});212 try self.symbols.putNoClobber(allocator, sym, false);
206 }213 }
207}214}
208215
209fn addObjCIVarSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {216fn addObjCIVarSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {
210 const expanded = try std.fmt.allocPrint(allocator, "_OBJC_IVAR_$_{s}", .{sym_name});217 const expanded = try std.fmt.allocPrint(allocator, "_OBJC_IVAR_$_{s}", .{sym_name});
211 if (self.symbols.contains(expanded)) return;218 if (self.symbols.contains(expanded)) return;
212 try self.symbols.putNoClobber(allocator, expanded, {});219 try self.symbols.putNoClobber(allocator, expanded, false);
213}220}
214221
215fn addObjCEhTypeSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {222fn addObjCEhTypeSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {
216 const expanded = try std.fmt.allocPrint(allocator, "_OBJC_EHTYPE_$_{s}", .{sym_name});223 const expanded = try std.fmt.allocPrint(allocator, "_OBJC_EHTYPE_$_{s}", .{sym_name});
217 if (self.symbols.contains(expanded)) return;224 if (self.symbols.contains(expanded)) return;
218 try self.symbols.putNoClobber(allocator, expanded, {});225 try self.symbols.putNoClobber(allocator, expanded, false);
219}226}
220227
221fn addSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {228fn addSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {
222 if (self.symbols.contains(sym_name)) return;229 if (self.symbols.contains(sym_name)) return;
223 try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, sym_name), {});230 try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, sym_name), false);
231}
232
233fn addWeakSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {
234 if (self.symbols.contains(sym_name)) return;
235 try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, sym_name), true);
224}236}
225237
226const TargetMatcher = struct {238const TargetMatcher = struct {
...@@ -359,6 +371,12 @@ pub fn parseFromStub(...@@ -359,6 +371,12 @@ pub fn parseFromStub(
359 }371 }
360 }372 }
361373
374 if (exp.weak_symbols) |symbols| {
375 for (symbols) |sym_name| {
376 try self.addWeakSymbol(allocator, sym_name);
377 }
378 }
379
362 if (exp.objc_classes) |objc_classes| {380 if (exp.objc_classes) |objc_classes| {
363 for (objc_classes) |class_name| {381 for (objc_classes) |class_name| {
364 try self.addObjCClassSymbol(allocator, class_name);382 try self.addObjCClassSymbol(allocator, class_name);
...@@ -402,6 +420,12 @@ pub fn parseFromStub(...@@ -402,6 +420,12 @@ pub fn parseFromStub(
402 }420 }
403 }421 }
404422
423 if (exp.weak_symbols) |symbols| {
424 for (symbols) |sym_name| {
425 try self.addWeakSymbol(allocator, sym_name);
426 }
427 }
428
405 if (exp.objc_classes) |classes| {429 if (exp.objc_classes) |classes| {
406 for (classes) |sym_name| {430 for (classes) |sym_name| {
407 try self.addObjCClassSymbol(allocator, sym_name);431 try self.addObjCClassSymbol(allocator, sym_name);
...@@ -432,6 +456,12 @@ pub fn parseFromStub(...@@ -432,6 +456,12 @@ pub fn parseFromStub(
432 }456 }
433 }457 }
434458
459 if (reexp.weak_symbols) |symbols| {
460 for (symbols) |sym_name| {
461 try self.addWeakSymbol(allocator, sym_name);
462 }
463 }
464
435 if (reexp.objc_classes) |classes| {465 if (reexp.objc_classes) |classes| {
436 for (classes) |sym_name| {466 for (classes) |sym_name| {
437 try self.addObjCClassSymbol(allocator, sym_name);467 try self.addObjCClassSymbol(allocator, sym_name);
src/link/tapi.zig+3
...@@ -26,6 +26,7 @@ pub const TbdV3 = struct {...@@ -26,6 +26,7 @@ pub const TbdV3 = struct {
26 allowable_clients: ?[]const []const u8,26 allowable_clients: ?[]const []const u8,
27 re_exports: ?[]const []const u8,27 re_exports: ?[]const []const u8,
28 symbols: ?[]const []const u8,28 symbols: ?[]const []const u8,
29 weak_symbols: ?[]const []const u8,
29 objc_classes: ?[]const []const u8,30 objc_classes: ?[]const []const u8,
30 objc_ivars: ?[]const []const u8,31 objc_ivars: ?[]const []const u8,
31 objc_eh_types: ?[]const []const u8,32 objc_eh_types: ?[]const []const u8,
...@@ -53,6 +54,7 @@ pub const TbdV4 = struct {...@@ -53,6 +54,7 @@ pub const TbdV4 = struct {
53 exports: ?[]const struct {54 exports: ?[]const struct {
54 targets: []const []const u8,55 targets: []const []const u8,
55 symbols: ?[]const []const u8,56 symbols: ?[]const []const u8,
57 weak_symbols: ?[]const []const u8,
56 objc_classes: ?[]const []const u8,58 objc_classes: ?[]const []const u8,
57 objc_ivars: ?[]const []const u8,59 objc_ivars: ?[]const []const u8,
58 objc_eh_types: ?[]const []const u8,60 objc_eh_types: ?[]const []const u8,
...@@ -60,6 +62,7 @@ pub const TbdV4 = struct {...@@ -60,6 +62,7 @@ pub const TbdV4 = struct {
60 reexports: ?[]const struct {62 reexports: ?[]const struct {
61 targets: []const []const u8,63 targets: []const []const u8,
62 symbols: ?[]const []const u8,64 symbols: ?[]const []const u8,
65 weak_symbols: ?[]const []const u8,
63 objc_classes: ?[]const []const u8,66 objc_classes: ?[]const []const u8,
64 objc_ivars: ?[]const []const u8,67 objc_ivars: ?[]const []const u8,
65 objc_eh_types: ?[]const []const u8,68 objc_eh_types: ?[]const []const u8,
test/link.zig+5
...@@ -79,6 +79,11 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {...@@ -79,6 +79,11 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {
79}79}
8080
81fn addMachOCases(cases: *tests.StandaloneContext) void {81fn addMachOCases(cases: *tests.StandaloneContext) void {
82 cases.addBuildFile("test/link/macho/bugs/13056/build.zig", .{
83 .build_modes = true,
84 .requires_macos_sdk = true,
85 });
86
82 cases.addBuildFile("test/link/macho/bugs/13457/build.zig", .{87 cases.addBuildFile("test/link/macho/bugs/13457/build.zig", .{
83 .build_modes = true,88 .build_modes = true,
84 });89 });
test/link/macho/bugs/13056/build.zig created+29
...@@ -0,0 +1,29 @@
1const std = @import("std");
2const Builder = std.build.Builder;
3
4pub fn build(b: *Builder) void {
5 const mode = b.standardReleaseOptions();
6
7 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
8 const target_info = std.zig.system.NativeTargetInfo.detect(target) catch unreachable;
9 const sdk = std.zig.system.darwin.getDarwinSDK(b.allocator, target_info.target) orelse
10 @panic("macOS SDK is required to run the test");
11
12 const test_step = b.step("test", "Test the program");
13
14 const exe = b.addExecutable("test", null);
15 b.default_step.dependOn(&exe.step);
16 exe.addIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include" }) catch unreachable);
17 exe.addIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include/c++/v1" }) catch unreachable);
18 exe.addCSourceFile("test.cpp", &.{
19 "-nostdlib++",
20 "-nostdinc++",
21 });
22 exe.addObjectFile(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/lib/libc++.tbd" }) catch unreachable);
23 exe.setBuildMode(mode);
24
25 const run_cmd = exe.run();
26 run_cmd.expectStdErrEqual("x: 5\n");
27
28 test_step.dependOn(&run_cmd.step);
29}
test/link/macho/bugs/13056/test.cpp created+10
...@@ -0,0 +1,10 @@
1// test.cpp
2#include <new>
3#include <cstdio>
4
5int main() {
6 int *x = new int;
7 *x = 5;
8 fprintf(stderr, "x: %d\n", *x);
9 delete x;
10}