srctree

jacobly0 parent 71f87629 bd0dd225
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

inlinesplit
lib/std/build/CheckObjectStep.zig added: 111, removed: 70, total 41
@@ -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);
 
src/Module.zig added: 111, removed: 70, total 41
@@ -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;
 
src/Sema.zig added: 111, removed: 70, total 41
@@ -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: {
 
test/link.zig added: 111, removed: 70, total 41
@@ -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,
 
test/link/macho/dead_strip/build.zig added: 111, removed: 70, total 41
@@ -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");
 
test/link/macho/dylib/build.zig added: 111, removed: 70, total 41
@@ -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);
 
 
test/link/macho/entry/build.zig added: 111, removed: 70, total 41
@@ -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");
 
filename was Deleted added: 111, removed: 70, total 41
@@ -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);
}
 
filename was Deleted added: 111, removed: 70, total 41
@@ -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 {}
 
test/link/macho/needed_library/build.zig added: 111, removed: 70, total 41
@@ -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);
 
test/link/macho/search_strategy/build.zig added: 111, removed: 70, total 41
@@ -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(".");
 
test/link/macho/stack_size/build.zig added: 111, removed: 70, total 41
@@ -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);
 
test/link/macho/weak_library/build.zig added: 111, removed: 70, total 41
@@ -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);
 
test/tests.zig added: 111, removed: 70, total 41
@@ -83,7 +83,7 @@ const test_targets = blk: {
.cpu_arch = .arm,
.os_tag = .linux,
},
.backend = .stage2_wasm,
.backend = .stage2_arm,
},
.{
.target = CrossTarget.parse(.{