Commit 1cb7a01b25
Changed files (6)
lib
std
Build
Step
lib/std/Build/Step/Compile.zig
@@ -64,6 +64,8 @@ initial_memory: ?u64 = null,
max_memory: ?u64 = null,
shared_memory: bool = false,
global_base: ?u64 = null,
+/// For WebAssembly only. Tells the linker to not output an entry point.
+no_entry: ?bool = null,
c_std: std.Build.CStd,
/// Set via options; intended to be read-only after that.
zig_lib_dir: ?LazyPath,
@@ -1851,6 +1853,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
if (self.global_base) |global_base| {
try zig_args.append(b.fmt("--global-base={d}", .{global_base}));
}
+ try addFlag(&zig_args, "entry", self.no_entry);
if (self.code_model != .default) {
try zig_args.append("-mcmodel");
lib/std/start.zig
@@ -82,11 +82,15 @@ comptime {
.reactor => "_initialize",
.command => "_start",
};
- if (!@hasDecl(root, wasm_start_sym)) {
+ if (!@hasDecl(root, wasm_start_sym) and @hasDecl(root, "main")) {
+ // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
+ // case it's not required to provide an entrypoint such as main.
@export(wasi_start, .{ .name = wasm_start_sym });
}
} else if (native_arch.isWasm() and native_os == .freestanding) {
- if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
+ // Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
+ // case it's not required to provide an entrypoint such as main.
+ if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main")) @export(wasm_freestanding_start, .{ .name = start_sym_name });
} else if (native_os != .other and native_os != .freestanding) {
if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
}
src/link/Wasm.zig
@@ -2817,14 +2817,10 @@ fn setupExports(wasm: *Wasm) !void {
}
fn setupStart(wasm: *Wasm) !void {
+ if (wasm.base.options.no_entry) return;
const entry_name = wasm.base.options.entry orelse "_start";
const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
- if (wasm.base.options.output_mode == .Exe) {
- if (wasm.base.options.wasi_exec_model == .reactor) return; // Not required for reactors
- } else {
- return; // No entry point needed for non-executable wasm files
- }
log.err("Entry symbol '{s}' missing", .{entry_name});
return error.MissingSymbol;
};
@@ -4544,24 +4540,14 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
try argv.append(arg);
- if (wasm.base.options.output_mode == .Exe) {
- if (wasm.base.options.wasi_exec_model == .reactor) {
- // Reactor execution model does not have _start so lld doesn't look for it.
- try argv.append("--no-entry");
- // Make sure "_initialize" and other used-defined functions are exported if this is WASI reactor.
- // If rdynamic is true, it will already be appended, so only verify if the user did not specify
- // the flag in which case, we ensure `--export-dynamic` is called.
- if (!wasm.base.options.rdynamic) {
- try argv.append("--export-dynamic");
- }
- }
- } else if (wasm.base.options.entry == null) {
- try argv.append("--no-entry"); // So lld doesn't look for _start.
- }
if (wasm.base.options.import_symbols) {
try argv.append("--allow-undefined");
}
+ if (wasm.base.options.no_entry) {
+ try argv.append("--no-entry");
+ }
+
// XXX - TODO: add when wasm-ld supports --build-id.
// if (wasm.base.options.build_id) {
// try argv.append("--build-id=tree");
src/Compilation.zig
@@ -643,6 +643,7 @@ pub const InitOptions = struct {
linker_import_symbols: bool = false,
linker_import_table: bool = false,
linker_export_table: bool = false,
+ linker_no_entry: bool = false,
linker_initial_memory: ?u64 = null,
linker_max_memory: ?u64 = null,
linker_shared_memory: bool = false,
@@ -1614,6 +1615,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.import_symbols = options.linker_import_symbols,
.import_table = options.linker_import_table,
.export_table = options.linker_export_table,
+ .no_entry = options.linker_no_entry,
.initial_memory = options.linker_initial_memory,
.max_memory = options.linker_max_memory,
.shared_memory = options.linker_shared_memory,
@@ -2577,6 +2579,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
man.hash.addOptional(comp.bin_file.options.max_memory);
man.hash.add(comp.bin_file.options.shared_memory);
man.hash.addOptional(comp.bin_file.options.global_base);
+ man.hash.add(comp.bin_file.options.no_entry);
// Mach-O specific stuff
man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);
src/link.zig
@@ -166,6 +166,7 @@ pub const Options = struct {
export_table: bool,
initial_memory: ?u64,
max_memory: ?u64,
+ no_entry: bool,
shared_memory: bool,
export_symbol_names: []const []const u8,
global_base: ?u64,
src/main.zig
@@ -577,6 +577,8 @@ const usage_build_generic =
\\ --shared-memory (WebAssembly) use shared linear memory
\\ --global-base=[addr] (WebAssembly) where to start to place global data
\\ --export=[value] (WebAssembly) Force a symbol to be exported
+ \\ -fentry (WebAssembly) Force output an entry point
+ \\ -fno-entry (WebAssembly) Do not output any entry point
\\
\\Test Options:
\\ --test-filter [text] Skip tests that do not match filter
@@ -835,6 +837,7 @@ fn buildOutputType(
var linker_import_symbols: bool = false;
var linker_import_table: bool = false;
var linker_export_table: bool = false;
+ var linker_no_entry: ?bool = null;
var linker_initial_memory: ?u64 = null;
var linker_max_memory: ?u64 = null;
var linker_shared_memory: bool = false;
@@ -1503,6 +1506,10 @@ fn buildOutputType(
}
} else if (mem.eql(u8, arg, "--import-memory")) {
linker_import_memory = true;
+ } else if (mem.eql(u8, arg, "-fentry")) {
+ linker_no_entry = false;
+ } else if (mem.eql(u8, arg, "-fno-entry")) {
+ linker_no_entry = true;
} else if (mem.eql(u8, arg, "--export-memory")) {
linker_export_memory = true;
} else if (mem.eql(u8, arg, "--import-symbols")) {
@@ -2134,6 +2141,8 @@ fn buildOutputType(
linker_import_table = true;
} else if (mem.eql(u8, arg, "--export-table")) {
linker_export_table = true;
+ } else if (mem.eql(u8, arg, "--no-entry")) {
+ linker_no_entry = true;
} else if (mem.eql(u8, arg, "--initial-memory")) {
const next_arg = linker_args_it.nextOrFatal();
linker_initial_memory = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
@@ -2618,6 +2627,25 @@ fn buildOutputType(
if (single_threaded == null) {
single_threaded = true;
}
+ if (wasi_exec_model) |model| {
+ if (model == .reactor) {
+ if (linker_no_entry != null and !linker_no_entry.?) {
+ fatal("WASI exucution model 'reactor' incompatible with flag '-fentry'. Reactor execution model has no entry point", .{});
+ }
+ if (entry) |entry_name| {
+ if (!mem.eql(u8, "_initialize", entry_name)) {
+ fatal("the entry symbol of the reactor model must be '_initialize', but found '{s}'", .{entry_name});
+ }
+ } else {
+ entry = "_initialize";
+ }
+ }
+ }
+ if (linker_no_entry) |no_entry| {
+ if (no_entry and entry != null) {
+ fatal("combination of '--entry' and `-fno-entry` are incompatible", .{});
+ }
+ }
if (linker_shared_memory) {
if (output_mode == .Obj) {
fatal("shared memory is not allowed in object files", .{});
@@ -3465,6 +3493,7 @@ fn buildOutputType(
.linker_import_symbols = linker_import_symbols,
.linker_import_table = linker_import_table,
.linker_export_table = linker_export_table,
+ .linker_no_entry = linker_no_entry orelse false,
.linker_initial_memory = linker_initial_memory,
.linker_max_memory = linker_max_memory,
.linker_shared_memory = linker_shared_memory,