authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-18 07:02:10-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-18 14:02:10+03:00
logbd0dd225e843801b4b6162cbd2709c7325ab87b7
tree6bbaa9f240311c52f7f24fc294c8c838710989e2
parent71f876295981ecf5dfb8daadc05e7e9c1c7e1cbe
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Sema: implement linksection on functions

* Sema: implement linksection on functions * Implement function linksection in Sema. * Don't clobber function linksection/align/addrspace in Sema. * Fix copy-paste typo in tests. * Add a bunch of missing test_step.dependOn. * Fix checkInSymtab match. Closes #12546

14 files changed, 97 insertions(+), 56 deletions(-)

lib/std/build/CheckObjectStep.zig+1
...@@ -436,6 +436,7 @@ const MachODumper = struct {...@@ -436,6 +436,7 @@ const MachODumper = struct {
436 }436 }
437437
438 if (opts.dump_symtab) {438 if (opts.dump_symtab) {
439 try writer.print("{s}\n", .{symtab_label});
439 for (symtab) |sym| {440 for (symtab) |sym| {
440 if (sym.stab()) continue;441 if (sym.stab()) continue;
441 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);442 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);
src/Module.zig+35-40
...@@ -4592,40 +4592,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4592,40 +4592,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4592 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };4592 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
4593 const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };4593 const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
4594 const decl_tv = try sema.resolveInstValue(&block_scope, init_src, result_ref, undefined);4594 const decl_tv = try sema.resolveInstValue(&block_scope, init_src, result_ref, undefined);
4595 const decl_align: u32 = blk: {
4596 const align_ref = decl.zirAlignRef();
4597 if (align_ref == .none) break :blk 0;
4598 break :blk try sema.resolveAlign(&block_scope, align_src, align_ref);
4599 };
4600 const decl_linksection: ?[*:0]const u8 = blk: {
4601 const linksection_ref = decl.zirLinksectionRef();
4602 if (linksection_ref == .none) break :blk null;
4603 const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known");
4604 if (mem.indexOfScalar(u8, bytes, 0) != null) {
4605 return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{});
4606 } else if (bytes.len == 0) {
4607 return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{});
4608 }
4609 break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr;
4610 };
4611 const target = sema.mod.getTarget();
4612 const address_space = blk: {
4613 const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) {
4614 .function, .extern_fn => .function,
4615 .variable => .variable,
4616 else => .constant,
4617 };
4618
4619 break :blk switch (decl.zirAddrspaceRef()) {
4620 .none => switch (addrspace_ctx) {
4621 .function => target_util.defaultAddressSpace(target, .function),
4622 .variable => target_util.defaultAddressSpace(target, .global_mutable),
4623 .constant => target_util.defaultAddressSpace(target, .global_constant),
4624 else => unreachable,
4625 },
4626 else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),
4627 };
4628 };
46294595
4630 // Note this resolves the type of the Decl, not the value; if this Decl4596 // Note this resolves the type of the Decl, not the value; if this Decl
4631 // is a struct, for example, this resolves `type` (which needs no resolution),4597 // 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 {...@@ -4679,9 +4645,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
46794645
4680 decl.ty = try decl_tv.ty.copy(decl_arena_allocator);4646 decl.ty = try decl_tv.ty.copy(decl_arena_allocator);
4681 decl.val = try decl_tv.val.copy(decl_arena_allocator);4647 decl.val = try decl_tv.val.copy(decl_arena_allocator);
4682 decl.@"align" = decl_align;4648 // linksection, align, and addrspace were already set by Sema
4683 decl.@"linksection" = decl_linksection;
4684 decl.@"addrspace" = address_space;
4685 decl.has_tv = true;4649 decl.has_tv = true;
4686 decl.owns_tv = owns_tv;4650 decl.owns_tv = owns_tv;
4687 decl_arena_state.* = decl_arena.state;4651 decl_arena_state.* = decl_arena.state;
...@@ -4759,9 +4723,40 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4759,9 +4723,40 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
47594723
4760 decl.ty = try decl_tv.ty.copy(decl_arena_allocator);4724 decl.ty = try decl_tv.ty.copy(decl_arena_allocator);
4761 decl.val = try decl_tv.val.copy(decl_arena_allocator);4725 decl.val = try decl_tv.val.copy(decl_arena_allocator);
4762 decl.@"align" = decl_align;4726 decl.@"align" = blk: {
4763 decl.@"linksection" = decl_linksection;4727 const align_ref = decl.zirAlignRef();
4764 decl.@"addrspace" = address_space;4728 if (align_ref == .none) break :blk 0;
4729 break :blk try sema.resolveAlign(&block_scope, align_src, align_ref);
4730 };
4731 decl.@"linksection" = blk: {
4732 const linksection_ref = decl.zirLinksectionRef();
4733 if (linksection_ref == .none) break :blk null;
4734 const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known");
4735 if (mem.indexOfScalar(u8, bytes, 0) != null) {
4736 return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{});
4737 } else if (bytes.len == 0) {
4738 return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{});
4739 }
4740 break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr;
4741 };
4742 decl.@"addrspace" = blk: {
4743 const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) {
4744 .function, .extern_fn => .function,
4745 .variable => .variable,
4746 else => .constant,
4747 };
4748
4749 const target = sema.mod.getTarget();
4750 break :blk switch (decl.zirAddrspaceRef()) {
4751 .none => switch (addrspace_ctx) {
4752 .function => target_util.defaultAddressSpace(target, .function),
4753 .variable => target_util.defaultAddressSpace(target, .global_mutable),
4754 .constant => target_util.defaultAddressSpace(target, .global_constant),
4755 else => unreachable,
4756 },
4757 else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),
4758 };
4759 };
4765 decl.has_tv = true;4760 decl.has_tv = true;
4766 decl_arena_state.* = decl_arena.state;4761 decl_arena_state.* = decl_arena.state;
4767 decl.value_arena = decl_arena_state;4762 decl.value_arena = decl_arena_state;
src/Sema.zig+13-15
...@@ -7899,7 +7899,7 @@ fn handleExternLibName(...@@ -7899,7 +7899,7 @@ fn handleExternLibName(
7899const FuncLinkSection = union(enum) {7899const FuncLinkSection = union(enum) {
7900 generic,7900 generic,
7901 default,7901 default,
7902 explicit: [*:0]const u8,7902 explicit: []const u8,
7903};7903};
79047904
7905fn funcCommon(7905fn funcCommon(
...@@ -8185,15 +8185,13 @@ fn funcCommon(...@@ -8185,15 +8185,13 @@ fn funcCommon(
8185 });8185 });
8186 };8186 };
81878187
8188 if (sema.owner_decl.owns_tv) {8188 sema.owner_decl.@"linksection" = switch (section) {
8189 switch (section) {8189 .generic => undefined,
8190 .generic => sema.owner_decl.@"linksection" = undefined,8190 .default => null,
8191 .default => sema.owner_decl.@"linksection" = null,8191 .explicit => |section_name| try sema.perm_arena.dupeZ(u8, section_name),
8192 .explicit => |s| sema.owner_decl.@"linksection" = s,8192 };
8193 }8193 sema.owner_decl.@"align" = alignment orelse 0;
8194 if (alignment) |a| sema.owner_decl.@"align" = a;8194 sema.owner_decl.@"addrspace" = address_space orelse .generic;
8195 if (address_space) |a| sema.owner_decl.@"addrspace" = a;
8196 }
81978195
8198 if (is_extern) {8196 if (is_extern) {
8199 const new_extern_fn = try sema.gpa.create(Module.ExternFn);8197 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...@@ -20717,22 +20715,22 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
20717 const body = sema.code.extra[extra_index..][0..body_len];20715 const body = sema.code.extra[extra_index..][0..body_len];
20718 extra_index += body.len;20716 extra_index += body.len;
2071920717
20720 const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8), "linksection must be comptime-known");20718 const ty = Type.initTag(.const_slice_u8);
20719 const val = try sema.resolveGenericBody(block, section_src, body, inst, ty, "linksection must be comptime-known");
20721 if (val.tag() == .generic_poison) {20720 if (val.tag() == .generic_poison) {
20722 break :blk FuncLinkSection{ .generic = {} };20721 break :blk FuncLinkSection{ .generic = {} };
20723 }20722 }
20724 return sema.fail(block, section_src, "TODO implement linksection on functions", .{});20723 break :blk FuncLinkSection{ .explicit = try val.toAllocatedBytes(ty, sema.arena, sema.mod) };
20725 } else if (extra.data.bits.has_section_ref) blk: {20724 } else if (extra.data.bits.has_section_ref) blk: {
20726 const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);20725 const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
20727 extra_index += 1;20726 extra_index += 1;
20728 const section_tv = sema.resolveInstConst(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) {20727 const section_name = sema.resolveConstString(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) {
20729 error.GenericPoison => {20728 error.GenericPoison => {
20730 break :blk FuncLinkSection{ .generic = {} };20729 break :blk FuncLinkSection{ .generic = {} };
20731 },20730 },
20732 else => |e| return e,20731 else => |e| return e,
20733 };20732 };
20734 _ = section_tv;20733 break :blk FuncLinkSection{ .explicit = section_name };
20735 return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
20736 } else FuncLinkSection{ .default = {} };20734 } else FuncLinkSection{ .default = {} };
2073720735
20738 const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {20736 const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {
test/link.zig+4
...@@ -92,6 +92,10 @@ fn addMachOCases(cases: *tests.StandaloneContext) void {...@@ -92,6 +92,10 @@ fn addMachOCases(cases: *tests.StandaloneContext) void {
92 .requires_macos_sdk = true,92 .requires_macos_sdk = true,
93 });93 });
9494
95 cases.addBuildFile("test/link/macho/linksection/build.zig", .{
96 .build_modes = true,
97 });
98
95 cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{99 cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{
96 .build_modes = true,100 .build_modes = true,
97 .requires_macos_sdk = true,101 .requires_macos_sdk = true,
test/link/macho/dead_strip/build.zig+2
...@@ -16,6 +16,7 @@ pub fn build(b: *Builder) void {...@@ -16,6 +16,7 @@ pub fn build(b: *Builder) void {
16 const check = exe.checkObject(.macho);16 const check = exe.checkObject(.macho);
17 check.checkInSymtab();17 check.checkInSymtab();
18 check.checkNext("{*} (__TEXT,__text) external _iAmUnused");18 check.checkNext("{*} (__TEXT,__text) external _iAmUnused");
19 test_step.dependOn(&check.step);
1920
20 const run_cmd = check.runAndCompare();21 const run_cmd = check.runAndCompare();
21 run_cmd.expectStdOutEqual("Hello!\n");22 run_cmd.expectStdOutEqual("Hello!\n");
...@@ -30,6 +31,7 @@ pub fn build(b: *Builder) void {...@@ -30,6 +31,7 @@ pub fn build(b: *Builder) void {
30 const check = exe.checkObject(.macho);31 const check = exe.checkObject(.macho);
31 check.checkInSymtab();32 check.checkInSymtab();
32 check.checkNotPresent("{*} (__TEXT,__text) external _iAmUnused");33 check.checkNotPresent("{*} (__TEXT,__text) external _iAmUnused");
34 test_step.dependOn(&check.step);
3335
34 const run_cmd = check.runAndCompare();36 const run_cmd = check.runAndCompare();
35 run_cmd.expectStdOutEqual("Hello!\n");37 run_cmd.expectStdOutEqual("Hello!\n");
test/link/macho/dylib/build.zig+2
...@@ -40,6 +40,8 @@ pub fn build(b: *Builder) void {...@@ -40,6 +40,8 @@ pub fn build(b: *Builder) void {
40 check_exe.checkNext("current version 10000");40 check_exe.checkNext("current version 10000");
41 check_exe.checkNext("compatibility version 10000");41 check_exe.checkNext("compatibility version 10000");
4242
43 test_step.dependOn(&check_exe.step);
44
43 check_exe.checkStart("cmd RPATH");45 check_exe.checkStart("cmd RPATH");
44 check_exe.checkNext(std.fmt.allocPrint(b.allocator, "path {s}", .{b.pathFromRoot("zig-out/lib")}) catch unreachable);46 check_exe.checkNext(std.fmt.allocPrint(b.allocator, "path {s}", .{b.pathFromRoot("zig-out/lib")}) catch unreachable);
4547
test/link/macho/entry/build.zig+1
...@@ -26,6 +26,7 @@ pub fn build(b: *Builder) void {...@@ -26,6 +26,7 @@ pub fn build(b: *Builder) void {
26 check_exe.checkNext("{n_value} (__TEXT,__text) external _non_main");26 check_exe.checkNext("{n_value} (__TEXT,__text) external _non_main");
2727
28 check_exe.checkComputeCompare("vmaddr entryoff +", .{ .op = .eq, .value = .{ .variable = "n_value" } });28 check_exe.checkComputeCompare("vmaddr entryoff +", .{ .op = .eq, .value = .{ .variable = "n_value" } });
29 test_step.dependOn(&check_exe.step);
2930
30 const run = check_exe.runAndCompare();31 const run = check_exe.runAndCompare();
31 run.expectStdOutEqual("42");32 run.expectStdOutEqual("42");
test/link/macho/linksection/build.zig created+28
...@@ -0,0 +1,28 @@
1const std = @import("std");
2
3pub fn build(b: *std.build.Builder) void {
4 const mode = b.standardReleaseOptions();
5 const target = std.zig.CrossTarget{ .os_tag = .macos };
6
7 const test_step = b.step("test", "Test");
8 test_step.dependOn(b.getInstallStep());
9
10 const obj = b.addObject("test", "main.zig");
11 obj.setBuildMode(mode);
12 obj.setTarget(target);
13
14 const check = obj.checkObject(.macho);
15
16 check.checkInSymtab();
17 check.checkNext("{*} (__DATA,__TestGlobal) external _test_global");
18
19 check.checkInSymtab();
20 check.checkNext("{*} (__TEXT,__TestFn) external _testFn");
21
22 if (mode == .Debug) {
23 check.checkInSymtab();
24 check.checkNext("{*} (__TEXT,__TestGenFnA) _main.testGenericFn__anon_{*}");
25 }
26
27 test_step.dependOn(&check.step);
28}
test/link/macho/linksection/main.zig created+5
...@@ -0,0 +1,5 @@
1export var test_global: u32 linksection("__DATA,__TestGlobal") = undefined;
2export fn testFn() linksection("__TEXT,__TestFn") callconv(.C) void {
3 testGenericFn("A");
4}
5fn testGenericFn(comptime suffix: []const u8) linksection("__TEXT,__TestGenFn" ++ suffix) void {}
test/link/macho/needed_library/build.zig+1
...@@ -31,6 +31,7 @@ pub fn build(b: *Builder) void {...@@ -31,6 +31,7 @@ pub fn build(b: *Builder) void {
31 const check = exe.checkObject(.macho);31 const check = exe.checkObject(.macho);
32 check.checkStart("cmd LOAD_DYLIB");32 check.checkStart("cmd LOAD_DYLIB");
33 check.checkNext("name @rpath/liba.dylib");33 check.checkNext("name @rpath/liba.dylib");
34 test_step.dependOn(&check.step);
3435
35 const run_cmd = check.runAndCompare();36 const run_cmd = check.runAndCompare();
36 test_step.dependOn(&run_cmd.step);37 test_step.dependOn(&run_cmd.step);
test/link/macho/search_strategy/build.zig+1
...@@ -17,6 +17,7 @@ pub fn build(b: *Builder) void {...@@ -17,6 +17,7 @@ pub fn build(b: *Builder) void {
17 const check = exe.checkObject(.macho);17 const check = exe.checkObject(.macho);
18 check.checkStart("cmd LOAD_DYLIB");18 check.checkStart("cmd LOAD_DYLIB");
19 check.checkNext("name @rpath/liba.dylib");19 check.checkNext("name @rpath/liba.dylib");
20 test_step.dependOn(&check.step);
2021
21 const run = check.runAndCompare();22 const run = check.runAndCompare();
22 run.cwd = b.pathFromRoot(".");23 run.cwd = b.pathFromRoot(".");
test/link/macho/stack_size/build.zig+1
...@@ -18,6 +18,7 @@ pub fn build(b: *Builder) void {...@@ -18,6 +18,7 @@ pub fn build(b: *Builder) void {
18 const check_exe = exe.checkObject(.macho);18 const check_exe = exe.checkObject(.macho);
19 check_exe.checkStart("cmd MAIN");19 check_exe.checkStart("cmd MAIN");
20 check_exe.checkNext("stacksize 100000000");20 check_exe.checkNext("stacksize 100000000");
21 test_step.dependOn(&check_exe.step);
2122
22 const run = check_exe.runAndCompare();23 const run = check_exe.runAndCompare();
23 test_step.dependOn(&run.step);24 test_step.dependOn(&run.step);
test/link/macho/weak_library/build.zig+2
...@@ -33,6 +33,8 @@ pub fn build(b: *Builder) void {...@@ -33,6 +33,8 @@ pub fn build(b: *Builder) void {
33 check.checkNext("(undefined) weak external _a (from liba)");33 check.checkNext("(undefined) weak external _a (from liba)");
34 check.checkNext("(undefined) weak external _asStr (from liba)");34 check.checkNext("(undefined) weak external _asStr (from liba)");
3535
36 test_step.dependOn(&check.step);
37
36 const run_cmd = check.runAndCompare();38 const run_cmd = check.runAndCompare();
37 run_cmd.expectStdOutEqual("42 42");39 run_cmd.expectStdOutEqual("42 42");
38 test_step.dependOn(&run_cmd.step);40 test_step.dependOn(&run_cmd.step);
test/tests.zig+1-1
...@@ -83,7 +83,7 @@ const test_targets = blk: {...@@ -83,7 +83,7 @@ const test_targets = blk: {
83 .cpu_arch = .arm,83 .cpu_arch = .arm,
84 .os_tag = .linux,84 .os_tag = .linux,
85 },85 },
86 .backend = .stage2_wasm,86 .backend = .stage2_arm,
87 },87 },
88 .{88 .{
89 .target = CrossTarget.parse(.{89 .target = CrossTarget.parse(.{