authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-09 17:31:28-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-09 17:31:28-07:00
log5d7ed6110391bc8f6ff7fb9fa225bfa03fd19191
tree86ee1b479156abe24ece112ffdcbbc02c6a1d2a4
parentc86a334d43c1818ed19eb403f88e61e38bbf20d6
parent33401ff3bb9359c656d21d2b1a0277c9fc5b85d1
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21644 from ziglang/macho-issue-21598

link.MachO: fix reporting undefined implicit symbols and fix a typo in InternalObject.addObjcMethnameSection method

4 files changed, 189 insertions(+), 89 deletions(-)

src/link/MachO.zig+118-86
......@@ -27,7 +27,7 @@ sections: std.MultiArrayList(Section) = .{},
2727resolver: SymbolResolver = .{},
2828/// This table will be populated after `scanRelocs` has run.
2929/// Key is symbol index.
30undefs: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .empty,
30undefs: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, UndefRefs) = .empty,
3131undefs_mutex: std.Thread.Mutex = .{},
3232dupes: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .empty,
3333dupes_mutex: std.Thread.Mutex = .{},
......@@ -1470,6 +1470,9 @@ fn scanRelocs(self: *MachO) !void {
14701470
14711471 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;
14721472
1473 if (self.getInternalObject()) |obj| {
1474 try obj.checkUndefs(self);
1475 }
14731476 try self.reportUndefs();
14741477
14751478 if (self.getZigObject()) |zo| {
......@@ -1530,29 +1533,43 @@ fn reportUndefs(self: *MachO) !void {
15301533 }
15311534 }.lessThan;
15321535
1533 for (self.undefs.values()) |*refs| {
1534 mem.sort(Ref, refs.items, {}, refLessThan);
1535 }
1536 for (self.undefs.values()) |*undefs| switch (undefs.*) {
1537 .refs => |refs| mem.sort(Ref, refs.items, {}, refLessThan),
1538 else => {},
1539 };
15361540
15371541 for (keys.items) |key| {
15381542 const undef_sym = self.resolver.keys.items[key - 1];
15391543 const notes = self.undefs.get(key).?;
1540 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
1544 const nnotes = nnotes: {
1545 const nnotes = switch (notes) {
1546 .refs => |refs| refs.items.len,
1547 else => 1,
1548 };
1549 break :nnotes @min(nnotes, max_notes) + @intFromBool(nnotes > max_notes);
1550 };
15411551
15421552 var err = try self.base.addErrorWithNotes(nnotes);
15431553 try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)});
15441554
1545 var inote: usize = 0;
1546 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
1547 const note = notes.items[inote];
1548 const file = self.getFile(note.file).?;
1549 const atom = note.getAtom(self).?;
1550 try err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });
1551 }
1555 switch (notes) {
1556 .force_undefined => try err.addNote("referenced with linker flag -u", .{}),
1557 .entry => try err.addNote("referenced with linker flag -e", .{}),
1558 .dyld_stub_binder, .objc_msgsend => try err.addNote("referenced implicitly", .{}),
1559 .refs => |refs| {
1560 var inote: usize = 0;
1561 while (inote < @min(refs.items.len, max_notes)) : (inote += 1) {
1562 const ref = refs.items[inote];
1563 const file = self.getFile(ref.file).?;
1564 const atom = ref.getAtom(self).?;
1565 try err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });
1566 }
15521567
1553 if (notes.items.len > max_notes) {
1554 const remaining = notes.items.len - max_notes;
1555 try err.addNote("referenced {d} more times", .{remaining});
1568 if (refs.items.len > max_notes) {
1569 const remaining = refs.items.len - max_notes;
1570 try err.addNote("referenced {d} more times", .{remaining});
1571 }
1572 },
15561573 }
15571574 }
15581575
......@@ -4584,78 +4601,20 @@ pub const String = struct {
45844601 len: u32 = 0,
45854602};
45864603
4587const MachO = @This();
4588
4589const std = @import("std");
4590const build_options = @import("build_options");
4591const builtin = @import("builtin");
4592const assert = std.debug.assert;
4593const fs = std.fs;
4594const log = std.log.scoped(.link);
4595const state_log = std.log.scoped(.link_state);
4596const macho = std.macho;
4597const math = std.math;
4598const mem = std.mem;
4599const meta = std.meta;
4600
4601const aarch64 = @import("../arch/aarch64/bits.zig");
4602const bind = @import("MachO/dyld_info/bind.zig");
4603const calcUuid = @import("MachO/uuid.zig").calcUuid;
4604const codegen = @import("../codegen.zig");
4605const dead_strip = @import("MachO/dead_strip.zig");
4606const eh_frame = @import("MachO/eh_frame.zig");
4607const fat = @import("MachO/fat.zig");
4608const link = @import("../link.zig");
4609const load_commands = @import("MachO/load_commands.zig");
4610const relocatable = @import("MachO/relocatable.zig");
4611const tapi = @import("tapi.zig");
4612const target_util = @import("../target.zig");
4613const trace = @import("../tracy.zig").trace;
4614const synthetic = @import("MachO/synthetic.zig");
4604pub const UndefRefs = union(enum) {
4605 force_undefined,
4606 entry,
4607 dyld_stub_binder,
4608 objc_msgsend,
4609 refs: std.ArrayListUnmanaged(Ref),
46154610
4616const Air = @import("../Air.zig");
4617const Alignment = Atom.Alignment;
4618const Allocator = mem.Allocator;
4619const Archive = @import("MachO/Archive.zig");
4620pub const Atom = @import("MachO/Atom.zig");
4621const AtomicBool = std.atomic.Value(bool);
4622const Bind = bind.Bind;
4623const Cache = std.Build.Cache;
4624const Path = Cache.Path;
4625const CodeSignature = @import("MachO/CodeSignature.zig");
4626const Compilation = @import("../Compilation.zig");
4627const DataInCode = synthetic.DataInCode;
4628pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
4629const Dylib = @import("MachO/Dylib.zig");
4630const ExportTrie = @import("MachO/dyld_info/Trie.zig");
4631const File = @import("MachO/file.zig").File;
4632const GotSection = synthetic.GotSection;
4633const Hash = std.hash.Wyhash;
4634const Indsymtab = synthetic.Indsymtab;
4635const InternalObject = @import("MachO/InternalObject.zig");
4636const ObjcStubsSection = synthetic.ObjcStubsSection;
4637const Object = @import("MachO/Object.zig");
4638const LazyBind = bind.LazyBind;
4639const LaSymbolPtrSection = synthetic.LaSymbolPtrSection;
4640const Liveness = @import("../Liveness.zig");
4641const LlvmObject = @import("../codegen/llvm.zig").Object;
4642const Md5 = std.crypto.hash.Md5;
4643const Zcu = @import("../Zcu.zig");
4644const InternPool = @import("../InternPool.zig");
4645const Rebase = @import("MachO/dyld_info/Rebase.zig");
4646pub const Relocation = @import("MachO/Relocation.zig");
4647const StringTable = @import("StringTable.zig");
4648const StubsSection = synthetic.StubsSection;
4649const StubsHelperSection = synthetic.StubsHelperSection;
4650const Symbol = @import("MachO/Symbol.zig");
4651const Thunk = @import("MachO/Thunk.zig");
4652const TlvPtrSection = synthetic.TlvPtrSection;
4653const Value = @import("../Value.zig");
4654const UnwindInfo = @import("MachO/UnwindInfo.zig");
4655const WaitGroup = std.Thread.WaitGroup;
4656const WeakBind = bind.WeakBind;
4657const ZigObject = @import("MachO/ZigObject.zig");
4658const dev = @import("../dev.zig");
4611 pub fn deinit(self: *UndefRefs, allocator: Allocator) void {
4612 switch (self.*) {
4613 .refs => |*refs| refs.deinit(allocator),
4614 else => {},
4615 }
4616 }
4617};
46594618
46604619pub const MachError = error{
46614620 /// Not enough permissions held to perform the requested kernel
......@@ -5392,3 +5351,76 @@ const max_distance = (1 << (jump_bits - 1));
53925351/// mold uses 5MiB margin, while ld64 uses 4MiB margin. We will follow mold
53935352/// and assume margin to be 5MiB.
53945353const max_allowed_distance = max_distance - 0x500_000;
5354
5355const MachO = @This();
5356
5357const std = @import("std");
5358const build_options = @import("build_options");
5359const builtin = @import("builtin");
5360const assert = std.debug.assert;
5361const fs = std.fs;
5362const log = std.log.scoped(.link);
5363const state_log = std.log.scoped(.link_state);
5364const macho = std.macho;
5365const math = std.math;
5366const mem = std.mem;
5367const meta = std.meta;
5368
5369const aarch64 = @import("../arch/aarch64/bits.zig");
5370const bind = @import("MachO/dyld_info/bind.zig");
5371const calcUuid = @import("MachO/uuid.zig").calcUuid;
5372const codegen = @import("../codegen.zig");
5373const dead_strip = @import("MachO/dead_strip.zig");
5374const eh_frame = @import("MachO/eh_frame.zig");
5375const fat = @import("MachO/fat.zig");
5376const link = @import("../link.zig");
5377const load_commands = @import("MachO/load_commands.zig");
5378const relocatable = @import("MachO/relocatable.zig");
5379const tapi = @import("tapi.zig");
5380const target_util = @import("../target.zig");
5381const trace = @import("../tracy.zig").trace;
5382const synthetic = @import("MachO/synthetic.zig");
5383
5384const Air = @import("../Air.zig");
5385const Alignment = Atom.Alignment;
5386const Allocator = mem.Allocator;
5387const Archive = @import("MachO/Archive.zig");
5388pub const Atom = @import("MachO/Atom.zig");
5389const AtomicBool = std.atomic.Value(bool);
5390const Bind = bind.Bind;
5391const Cache = std.Build.Cache;
5392const Path = Cache.Path;
5393const CodeSignature = @import("MachO/CodeSignature.zig");
5394const Compilation = @import("../Compilation.zig");
5395const DataInCode = synthetic.DataInCode;
5396pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
5397const Dylib = @import("MachO/Dylib.zig");
5398const ExportTrie = @import("MachO/dyld_info/Trie.zig");
5399const File = @import("MachO/file.zig").File;
5400const GotSection = synthetic.GotSection;
5401const Hash = std.hash.Wyhash;
5402const Indsymtab = synthetic.Indsymtab;
5403const InternalObject = @import("MachO/InternalObject.zig");
5404const ObjcStubsSection = synthetic.ObjcStubsSection;
5405const Object = @import("MachO/Object.zig");
5406const LazyBind = bind.LazyBind;
5407const LaSymbolPtrSection = synthetic.LaSymbolPtrSection;
5408const Liveness = @import("../Liveness.zig");
5409const LlvmObject = @import("../codegen/llvm.zig").Object;
5410const Md5 = std.crypto.hash.Md5;
5411const Zcu = @import("../Zcu.zig");
5412const InternPool = @import("../InternPool.zig");
5413const Rebase = @import("MachO/dyld_info/Rebase.zig");
5414pub const Relocation = @import("MachO/Relocation.zig");
5415const StringTable = @import("StringTable.zig");
5416const StubsSection = synthetic.StubsSection;
5417const StubsHelperSection = synthetic.StubsHelperSection;
5418const Symbol = @import("MachO/Symbol.zig");
5419const Thunk = @import("MachO/Thunk.zig");
5420const TlvPtrSection = synthetic.TlvPtrSection;
5421const Value = @import("../Value.zig");
5422const UnwindInfo = @import("MachO/UnwindInfo.zig");
5423const WaitGroup = std.Thread.WaitGroup;
5424const WeakBind = bind.WeakBind;
5425const ZigObject = @import("MachO/ZigObject.zig");
5426const dev = @import("../dev.zig");
src/link/MachO/Atom.zig+2-2
......@@ -560,9 +560,9 @@ fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool {
560560 const gpa = macho_file.base.comp.gpa;
561561 const gop = try macho_file.undefs.getOrPut(gpa, file.getGlobals()[rel.target]);
562562 if (!gop.found_existing) {
563 gop.value_ptr.* = .{};
563 gop.value_ptr.* = .{ .refs = .{} };
564564 }
565 try gop.value_ptr.append(gpa, .{ .index = self.atom_index, .file = self.file });
565 try gop.value_ptr.refs.append(gpa, .{ .index = self.atom_index, .file = self.file });
566566 return true;
567567 }
568568
src/link/MachO/InternalObject.zig+43-1
......@@ -281,7 +281,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
281281 sym.nlist_idx = nlist_idx;
282282 try self.globals.append(gpa, 0);
283283
284 return atom_index;
284 return sym_index;
285285}
286286
287287fn addObjcSelrefsSection(self: *InternalObject, methname_sym_index: Symbol.Index, macho_file: *MachO) !Symbol.Index {
......@@ -507,6 +507,41 @@ pub fn scanRelocs(self: *InternalObject, macho_file: *MachO) void {
507507 }
508508}
509509
510pub fn checkUndefs(self: InternalObject, macho_file: *MachO) !void {
511 const addUndef = struct {
512 fn addUndef(mf: *MachO, index: MachO.SymbolResolver.Index, tag: anytype) !void {
513 const gpa = mf.base.comp.gpa;
514 mf.undefs_mutex.lock();
515 defer mf.undefs_mutex.unlock();
516 const gop = try mf.undefs.getOrPut(gpa, index);
517 if (!gop.found_existing) {
518 gop.value_ptr.* = tag;
519 }
520 }
521 }.addUndef;
522 for (self.force_undefined.items) |index| {
523 const ref = self.getSymbolRef(index, macho_file);
524 if (ref.getFile(macho_file) == null) {
525 try addUndef(macho_file, self.globals.items[index], .force_undefined);
526 }
527 }
528 if (self.getEntryRef(macho_file)) |ref| {
529 if (ref.getFile(macho_file) == null) {
530 try addUndef(macho_file, self.globals.items[self.entry_index.?], .entry);
531 }
532 }
533 if (self.getDyldStubBinderRef(macho_file)) |ref| {
534 if (ref.getFile(macho_file) == null and macho_file.stubs.symbols.items.len > 0) {
535 try addUndef(macho_file, self.globals.items[self.dyld_stub_binder_index.?], .dyld_stub_binder);
536 }
537 }
538 if (self.getObjcMsgSendRef(macho_file)) |ref| {
539 if (ref.getFile(macho_file) == null and self.needsObjcMsgsendSymbol()) {
540 try addUndef(macho_file, self.globals.items[self.objc_msg_send_index.?], .objc_msgsend);
541 }
542 }
543}
544
510545pub fn allocateSyntheticSymbols(self: *InternalObject, macho_file: *MachO) void {
511546 const text_seg = macho_file.getTextSegment();
512547
......@@ -791,6 +826,13 @@ pub fn setSymbolExtra(self: *InternalObject, index: u32, extra: Symbol.Extra) vo
791826 }
792827}
793828
829fn needsObjcMsgsendSymbol(self: InternalObject) bool {
830 for (self.sections.items(.extra)) |extra| {
831 if (extra.is_objc_methname or extra.is_objc_selref) return true;
832 }
833 return false;
834}
835
794836const FormatContext = struct {
795837 self: *InternalObject,
796838 macho_file: *MachO,
test/link/macho.zig+26
......@@ -63,6 +63,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
6363 macho_step.dependOn(testTlsZig(b, .{ .target = default_target }));
6464 macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target }));
6565 macho_step.dependOn(testUnresolvedError(b, .{ .target = default_target }));
66 macho_step.dependOn(testUnresolvedError2(b, .{ .target = default_target }));
6667 macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target }));
6768 macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target }));
6869 macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target }));
......@@ -2610,6 +2611,31 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
26102611 return test_step;
26112612}
26122613
2614fn testUnresolvedError2(b: *Build, opts: Options) *Step {
2615 const test_step = addTestStep(b, "unresolved-error-2", opts);
2616
2617 const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes =
2618 \\pub fn main() !void {
2619 \\ const msg_send_fn = @extern(
2620 \\ *const fn () callconv(.C) usize,
2621 \\ .{ .name = "objc_msgSend$initWithContentRect:styleMask:backing:defer:screen:" },
2622 \\ );
2623 \\ _ = @call(
2624 \\ .auto,
2625 \\ msg_send_fn,
2626 \\ .{},
2627 \\ );
2628 \\}
2629 });
2630
2631 expectLinkErrors(exe, test_step, .{ .exact = &.{
2632 "error: undefined symbol: _objc_msgSend",
2633 "note: referenced implicitly",
2634 } });
2635
2636 return test_step;
2637}
2638
26132639fn testUnwindInfo(b: *Build, opts: Options) *Step {
26142640 const test_step = addTestStep(b, "unwind-info", opts);
26152641