Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stage2: wasm-linker - Only export symbols notated as such #10517

Merged
merged 2 commits into from
Jan 11, 2022
Merged
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
2 changes: 2 additions & 0 deletions lib/std/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2659,6 +2659,8 @@ pub const LibExeObjStep = struct {
try zig_args.append(bin_name);
try zig_args.append("--test-cmd");
try zig_args.append("--dir=.");
try zig_args.append("--test-cmd");
try zig_args.append("--allow-unknown-exports"); // TODO: Remove when stage2 is default compiler
try zig_args.append("--test-cmd-bin");
} else {
try zig_args.append("--test-no-exec");
Expand Down
9 changes: 9 additions & 0 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ emit_docs: ?EmitLoc,
work_queue_wait_group: WaitGroup,
astgen_wait_group: WaitGroup,

/// Exported symbol names. This is only for when the target is wasm.
/// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information.
export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{},

pub const SemaError = Module.SemaError;

pub const CRTFile = struct {
Expand Down Expand Up @@ -1877,6 +1881,11 @@ pub fn destroy(self: *Compilation) void {
self.work_queue_wait_group.deinit();
self.astgen_wait_group.deinit();

for (self.export_symbol_names.items) |symbol_name| {
gpa.free(symbol_name);
}
self.export_symbol_names.deinit(gpa);

// This destroys `self`.
self.arena_state.promote(gpa).deinit();
}
Expand Down
45 changes: 32 additions & 13 deletions src/link/Wasm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
};
}

if (self.base.options.output_mode == .Obj) {
if (is_obj) {
// LLD's WASM driver does not support the equivalent of `-r` so we do a simple file copy
// here. TODO: think carefully about how we can avoid this redundant operation when doing
// build-obj. See also the corresponding TODO in linkAsArchive.
Expand Down Expand Up @@ -1233,14 +1233,45 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
try argv.append(arg);
}

var auto_export_symbols = true;
// Users are allowed to specify which symbols they want to export to the wasm host.
for (self.base.options.export_symbol_names) |symbol_name| {
const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});
try argv.append(arg);
auto_export_symbols = false;
}

if (self.base.options.rdynamic) {
try argv.append("--export-dynamic");
auto_export_symbols = false;
}

if (auto_export_symbols) {
if (self.base.options.module) |module| {
// when we use stage1, we use the exports that stage1 provided us.
// For stage2, we can directly retrieve them from the module.
const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
if (use_stage1) {
for (comp.export_symbol_names.items) |symbol_name| {
try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}));
}
} else {
const skip_export_non_fn = target.os.tag == .wasi and
self.base.options.wasi_exec_model == .command;
for (module.decl_exports.values()) |exports| {
for (exports) |exprt| {
if (skip_export_non_fn and exprt.exported_decl.ty.zigTypeTag() != .Fn) {
// skip exporting symbols when we're building a WASI command
// and the symbol is not a function
continue;
}
const symbol_name = exprt.exported_decl.name;
const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});
try argv.append(arg);
}
}
}
}
}

if (self.base.options.output_mode == .Exe) {
Expand All @@ -1258,25 +1289,13 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
if (self.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 (!self.base.options.rdynamic) {
try argv.append("--export-dynamic");
}
}
} else {
if (self.base.options.stack_size_override) |stack_size| {
try argv.append("-z");
const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
try argv.append(arg);
}

// Only when the user has not specified how they want to export the symbols, do we want
// to export all symbols.
if (self.base.options.export_symbol_names.len == 0 and !self.base.options.rdynamic) {
try argv.append("--export-all");
}
try argv.append("--no-entry"); // So lld doesn't look for _start.
}
try argv.appendSlice(&[_][]const u8{
Expand Down
7 changes: 7 additions & 0 deletions src/stage1.zig
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,10 @@ export fn stage2_fetch_file(
if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1);
return contents.ptr;
}

export fn stage2_append_symbol(stage1: *Module, name_ptr: [*c]const u8, name_len: usize) Error {
if (name_len == 0) return Error.None;
const comp = @intToPtr(*Compilation, stage1.userdata);
comp.export_symbol_names.append(comp.gpa, name_ptr[0..name_len]) catch return Error.OutOfMemory;
return Error.None;
}
12 changes: 12 additions & 0 deletions src/stage1/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9905,6 +9905,18 @@ void codegen_build_object(CodeGen *g) {

codegen_add_time_event(g, "Done");
codegen_switch_sub_prog_node(g, nullptr);

// append all export symbols to stage2 so we can provide them to the linker
if (target_is_wasm(g->zig_target)){
Error err;
auto export_it = g->exported_symbol_names.entry_iterator();
decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr;
while ((curr_entry = export_it.next()) != nullptr) {
if ((err = stage2_append_symbol(&g->stage1, buf_ptr(curr_entry->key), buf_len(curr_entry->key)))) {
fprintf(stderr, "Unable to export symbol '%s': %s\n", buf_ptr(curr_entry->key), err_str(err));
}
}
}
}

ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path,
Expand Down
3 changes: 3 additions & 0 deletions src/stage1/stage2.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,7 @@ ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1,
const char *lib_name_ptr, size_t lib_name_len,
const char *symbol_name_ptr, size_t symbol_name_len);

// ABI warning
ZIG_EXTERN_C enum Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len);

#endif
5 changes: 5 additions & 0 deletions src/stage1/zig0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,8 @@ const char *stage2_version_string(void) {
struct Stage2SemVer stage2_version(void) {
return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH};
}

Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len)
{
return ErrorNone;
}