Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/link/MachO.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2937,7 +2937,13 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {

fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
var header: macho.mach_header_64 = .{};
header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK;
header.flags = macho.MH_DYLDLINK;

// Only set MH_NOUNDEFS if we're not allowing undefined symbols via dynamic lookup.
// When dynamic_lookup is enabled, undefined symbols are resolved at runtime by dyld.
if (self.undefined_treatment != .dynamic_lookup) {
header.flags |= macho.MH_NOUNDEFS;
}

// TODO: if (self.options.namespace == .two_level) {
header.flags |= macho.MH_TWOLEVEL;
Expand Down
24 changes: 24 additions & 0 deletions test/link/macho.zig
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target }));
macho_step.dependOn(testTlsZig(b, .{ .target = default_target }));
macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target }));
macho_step.dependOn(testUndefinedDynamicLookup(b, .{ .target = default_target }));
macho_step.dependOn(testDiscardLocalSymbols(b, .{ .target = default_target }));
macho_step.dependOn(testUnresolvedError(b, .{ .target = default_target }));
macho_step.dependOn(testUnresolvedError2(b, .{ .target = default_target }));
Expand Down Expand Up @@ -2632,6 +2633,29 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
return test_step;
}

fn testUndefinedDynamicLookup(b: *Build, opts: Options) *Step {
const test_step = addTestStep(b, "undefined-dynamic-lookup", opts);

// Create a dylib with an undefined external symbol reference
const dylib = addSharedLibrary(b, opts, .{ .name = "a" });
addCSourceBytes(dylib,
\\extern int undefined_symbol(void);
\\int call_undefined(void) {
\\ return undefined_symbol();
\\}
, &.{});
dylib.linker_allow_shlib_undefined = true;

// Verify the Mach-O header does NOT contain NOUNDEFS flag
const check = dylib.checkObject();
check.checkInHeaders();
check.checkExact("header");
check.checkNotPresent("NOUNDEFS");
test_step.dependOn(&check.step);

return test_step;
}

fn testUnresolvedError(b: *Build, opts: Options) *Step {
const test_step = addTestStep(b, "unresolved-error", opts);

Expand Down