diff --git a/lib/std/build/CheckObjectStep.zig b/lib/std/build/CheckObjectStep.zig index 09a8d3c148..eaa3a1c1b7 100644 --- a/lib/std/build/CheckObjectStep.zig +++ b/lib/std/build/CheckObjectStep.zig @@ -436,6 +436,7 @@ const MachODumper = struct { } if (opts.dump_symtab) { + try writer.print("{s}\n", .{symtab_label}); for (symtab) |sym| { if (sym.stab()) continue; const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0); diff --git a/src/Module.zig b/src/Module.zig index 4edba007e9..d117c3af33 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4592,40 +4592,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; const decl_tv = try sema.resolveInstValue(&block_scope, init_src, result_ref, undefined); - const decl_align: u32 = blk: { - const align_ref = decl.zirAlignRef(); - if (align_ref == .none) break :blk 0; - break :blk try sema.resolveAlign(&block_scope, align_src, align_ref); - }; - const decl_linksection: ?[*:0]const u8 = blk: { - const linksection_ref = decl.zirLinksectionRef(); - if (linksection_ref == .none) break :blk null; - const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known"); - if (mem.indexOfScalar(u8, bytes, 0) != null) { - return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); - } else if (bytes.len == 0) { - return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); - } - break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr; - }; - const target = sema.mod.getTarget(); - const address_space = blk: { - const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) { - .function, .extern_fn => .function, - .variable => .variable, - else => .constant, - }; - - break :blk switch (decl.zirAddrspaceRef()) { - .none => switch (addrspace_ctx) { - .function => target_util.defaultAddressSpace(target, .function), - .variable => target_util.defaultAddressSpace(target, .global_mutable), - .constant => target_util.defaultAddressSpace(target, .global_constant), - else => unreachable, - }, - else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx), - }; - }; // Note this resolves the type of the Decl, not the value; if this Decl // is a struct, for example, this resolves `type` (which needs no resolution), @@ -4679,9 +4645,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { decl.ty = try decl_tv.ty.copy(decl_arena_allocator); decl.val = try decl_tv.val.copy(decl_arena_allocator); - decl.@"align" = decl_align; - decl.@"linksection" = decl_linksection; - decl.@"addrspace" = address_space; + // linksection, align, and addrspace were already set by Sema decl.has_tv = true; decl.owns_tv = owns_tv; decl_arena_state.* = decl_arena.state; @@ -4759,9 +4723,40 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { decl.ty = try decl_tv.ty.copy(decl_arena_allocator); decl.val = try decl_tv.val.copy(decl_arena_allocator); - decl.@"align" = decl_align; - decl.@"linksection" = decl_linksection; - decl.@"addrspace" = address_space; + decl.@"align" = blk: { + const align_ref = decl.zirAlignRef(); + if (align_ref == .none) break :blk 0; + break :blk try sema.resolveAlign(&block_scope, align_src, align_ref); + }; + decl.@"linksection" = blk: { + const linksection_ref = decl.zirLinksectionRef(); + if (linksection_ref == .none) break :blk null; + const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known"); + if (mem.indexOfScalar(u8, bytes, 0) != null) { + return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); + } else if (bytes.len == 0) { + return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); + } + break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr; + }; + decl.@"addrspace" = blk: { + const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) { + .function, .extern_fn => .function, + .variable => .variable, + else => .constant, + }; + + const target = sema.mod.getTarget(); + break :blk switch (decl.zirAddrspaceRef()) { + .none => switch (addrspace_ctx) { + .function => target_util.defaultAddressSpace(target, .function), + .variable => target_util.defaultAddressSpace(target, .global_mutable), + .constant => target_util.defaultAddressSpace(target, .global_constant), + else => unreachable, + }, + else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx), + }; + }; decl.has_tv = true; decl_arena_state.* = decl_arena.state; decl.value_arena = decl_arena_state; diff --git a/src/Sema.zig b/src/Sema.zig index 4807e68f48..f0b6a8c9f8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7899,7 +7899,7 @@ fn handleExternLibName( const FuncLinkSection = union(enum) { generic, default, - explicit: [*:0]const u8, + explicit: []const u8, }; fn funcCommon( @@ -8185,15 +8185,13 @@ fn funcCommon( }); }; - if (sema.owner_decl.owns_tv) { - switch (section) { - .generic => sema.owner_decl.@"linksection" = undefined, - .default => sema.owner_decl.@"linksection" = null, - .explicit => |s| sema.owner_decl.@"linksection" = s, - } - if (alignment) |a| sema.owner_decl.@"align" = a; - if (address_space) |a| sema.owner_decl.@"addrspace" = a; - } + sema.owner_decl.@"linksection" = switch (section) { + .generic => undefined, + .default => null, + .explicit => |section_name| try sema.perm_arena.dupeZ(u8, section_name), + }; + sema.owner_decl.@"align" = alignment orelse 0; + sema.owner_decl.@"addrspace" = address_space orelse .generic; if (is_extern) { const new_extern_fn = try sema.gpa.create(Module.ExternFn); @@ -20717,22 +20715,22 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const body = sema.code.extra[extra_index..][0..body_len]; extra_index += body.len; - const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8), "linksection must be comptime-known"); + const ty = Type.initTag(.const_slice_u8); + const val = try sema.resolveGenericBody(block, section_src, body, inst, ty, "linksection must be comptime-known"); if (val.tag() == .generic_poison) { break :blk FuncLinkSection{ .generic = {} }; } - return sema.fail(block, section_src, "TODO implement linksection on functions", .{}); + break :blk FuncLinkSection{ .explicit = try val.toAllocatedBytes(ty, sema.arena, sema.mod) }; } else if (extra.data.bits.has_section_ref) blk: { const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); extra_index += 1; - const section_tv = sema.resolveInstConst(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) { + const section_name = sema.resolveConstString(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) { error.GenericPoison => { break :blk FuncLinkSection{ .generic = {} }; }, else => |e| return e, }; - _ = section_tv; - return sema.fail(block, section_src, "TODO implement linksection on functions", .{}); + break :blk FuncLinkSection{ .explicit = section_name }; } else FuncLinkSection{ .default = {} }; const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: { diff --git a/test/link.zig b/test/link.zig index 4bde09df38..df397cd5d2 100644 --- a/test/link.zig +++ b/test/link.zig @@ -92,6 +92,10 @@ fn addMachOCases(cases: *tests.StandaloneContext) void { .requires_macos_sdk = true, }); + cases.addBuildFile("test/link/macho/linksection/build.zig", .{ + .build_modes = true, + }); + cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{ .build_modes = true, .requires_macos_sdk = true, diff --git a/test/link/macho/dead_strip/build.zig b/test/link/macho/dead_strip/build.zig index 25759f5619..1f245fc245 100644 --- a/test/link/macho/dead_strip/build.zig +++ b/test/link/macho/dead_strip/build.zig @@ -16,6 +16,7 @@ pub fn build(b: *Builder) void { const check = exe.checkObject(.macho); check.checkInSymtab(); check.checkNext("{*} (__TEXT,__text) external _iAmUnused"); + test_step.dependOn(&check.step); const run_cmd = check.runAndCompare(); run_cmd.expectStdOutEqual("Hello!\n"); @@ -30,6 +31,7 @@ pub fn build(b: *Builder) void { const check = exe.checkObject(.macho); check.checkInSymtab(); check.checkNotPresent("{*} (__TEXT,__text) external _iAmUnused"); + test_step.dependOn(&check.step); const run_cmd = check.runAndCompare(); run_cmd.expectStdOutEqual("Hello!\n"); diff --git a/test/link/macho/dylib/build.zig b/test/link/macho/dylib/build.zig index a5baf255c6..a4b10eb807 100644 --- a/test/link/macho/dylib/build.zig +++ b/test/link/macho/dylib/build.zig @@ -40,6 +40,8 @@ pub fn build(b: *Builder) void { check_exe.checkNext("current version 10000"); check_exe.checkNext("compatibility version 10000"); + test_step.dependOn(&check_exe.step); + check_exe.checkStart("cmd RPATH"); check_exe.checkNext(std.fmt.allocPrint(b.allocator, "path {s}", .{b.pathFromRoot("zig-out/lib")}) catch unreachable); diff --git a/test/link/macho/entry/build.zig b/test/link/macho/entry/build.zig index 0ecca14aa2..6f63576e0b 100644 --- a/test/link/macho/entry/build.zig +++ b/test/link/macho/entry/build.zig @@ -26,6 +26,7 @@ pub fn build(b: *Builder) void { check_exe.checkNext("{n_value} (__TEXT,__text) external _non_main"); check_exe.checkComputeCompare("vmaddr entryoff +", .{ .op = .eq, .value = .{ .variable = "n_value" } }); + test_step.dependOn(&check_exe.step); const run = check_exe.runAndCompare(); run.expectStdOutEqual("42"); diff --git a/test/link/macho/linksection/build.zig b/test/link/macho/linksection/build.zig new file mode 100644 index 0000000000..9204499803 --- /dev/null +++ b/test/link/macho/linksection/build.zig @@ -0,0 +1,28 @@ +const std = @import("std"); + +pub fn build(b: *std.build.Builder) void { + const mode = b.standardReleaseOptions(); + const target = std.zig.CrossTarget{ .os_tag = .macos }; + + const test_step = b.step("test", "Test"); + test_step.dependOn(b.getInstallStep()); + + const obj = b.addObject("test", "main.zig"); + obj.setBuildMode(mode); + obj.setTarget(target); + + const check = obj.checkObject(.macho); + + check.checkInSymtab(); + check.checkNext("{*} (__DATA,__TestGlobal) external _test_global"); + + check.checkInSymtab(); + check.checkNext("{*} (__TEXT,__TestFn) external _testFn"); + + if (mode == .Debug) { + check.checkInSymtab(); + check.checkNext("{*} (__TEXT,__TestGenFnA) _main.testGenericFn__anon_{*}"); + } + + test_step.dependOn(&check.step); +} diff --git a/test/link/macho/linksection/main.zig b/test/link/macho/linksection/main.zig new file mode 100644 index 0000000000..2105c35ed3 --- /dev/null +++ b/test/link/macho/linksection/main.zig @@ -0,0 +1,5 @@ +export var test_global: u32 linksection("__DATA,__TestGlobal") = undefined; +export fn testFn() linksection("__TEXT,__TestFn") callconv(.C) void { + testGenericFn("A"); +} +fn testGenericFn(comptime suffix: []const u8) linksection("__TEXT,__TestGenFn" ++ suffix) void {} diff --git a/test/link/macho/needed_library/build.zig b/test/link/macho/needed_library/build.zig index a314fd2201..a1218560e8 100644 --- a/test/link/macho/needed_library/build.zig +++ b/test/link/macho/needed_library/build.zig @@ -31,6 +31,7 @@ pub fn build(b: *Builder) void { const check = exe.checkObject(.macho); check.checkStart("cmd LOAD_DYLIB"); check.checkNext("name @rpath/liba.dylib"); + test_step.dependOn(&check.step); const run_cmd = check.runAndCompare(); test_step.dependOn(&run_cmd.step); diff --git a/test/link/macho/search_strategy/build.zig b/test/link/macho/search_strategy/build.zig index e556b5bb23..d497a6499b 100644 --- a/test/link/macho/search_strategy/build.zig +++ b/test/link/macho/search_strategy/build.zig @@ -17,6 +17,7 @@ pub fn build(b: *Builder) void { const check = exe.checkObject(.macho); check.checkStart("cmd LOAD_DYLIB"); check.checkNext("name @rpath/liba.dylib"); + test_step.dependOn(&check.step); const run = check.runAndCompare(); run.cwd = b.pathFromRoot("."); diff --git a/test/link/macho/stack_size/build.zig b/test/link/macho/stack_size/build.zig index 91c44baf52..c32261b533 100644 --- a/test/link/macho/stack_size/build.zig +++ b/test/link/macho/stack_size/build.zig @@ -18,6 +18,7 @@ pub fn build(b: *Builder) void { const check_exe = exe.checkObject(.macho); check_exe.checkStart("cmd MAIN"); check_exe.checkNext("stacksize 100000000"); + test_step.dependOn(&check_exe.step); const run = check_exe.runAndCompare(); test_step.dependOn(&run.step); diff --git a/test/link/macho/weak_library/build.zig b/test/link/macho/weak_library/build.zig index 8c41e0dfd1..beecddb91d 100644 --- a/test/link/macho/weak_library/build.zig +++ b/test/link/macho/weak_library/build.zig @@ -33,6 +33,8 @@ pub fn build(b: *Builder) void { check.checkNext("(undefined) weak external _a (from liba)"); check.checkNext("(undefined) weak external _asStr (from liba)"); + test_step.dependOn(&check.step); + const run_cmd = check.runAndCompare(); run_cmd.expectStdOutEqual("42 42"); test_step.dependOn(&run_cmd.step); diff --git a/test/tests.zig b/test/tests.zig index aef549d4f9..4dec71bc52 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -83,7 +83,7 @@ const test_targets = blk: { .cpu_arch = .arm, .os_tag = .linux, }, - .backend = .stage2_wasm, + .backend = .stage2_arm, }, .{ .target = CrossTarget.parse(.{