authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-11 13:34:43+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-12 12:01:32-07:00
logdafbc6eb2524d1e8276ceec2cf26cb1d4982e2ad
tree00e562e85f176fca441581ea1e7f7b98b46b6363
parent6f49233ac6a6569b909b689f22fc260dc8c19234

Merge branch 'Luukdegram-linker-eport-symbols'


7 files changed, 71 insertions(+), 14 deletions(-)

lib/std/build.zig+2
...@@ -2651,6 +2651,8 @@ pub const LibExeObjStep = struct {...@@ -2651,6 +2651,8 @@ pub const LibExeObjStep = struct {
2651 try zig_args.append(bin_name);2651 try zig_args.append(bin_name);
2652 try zig_args.append("--test-cmd");2652 try zig_args.append("--test-cmd");
2653 try zig_args.append("--dir=.");2653 try zig_args.append("--dir=.");
2654 try zig_args.append("--test-cmd");
2655 try zig_args.append("--allow-unknown-exports"); // TODO: Remove when stage2 is default compiler
2654 try zig_args.append("--test-cmd-bin");2656 try zig_args.append("--test-cmd-bin");
2655 } else {2657 } else {
2656 try zig_args.append("--test-no-exec");2658 try zig_args.append("--test-no-exec");
src/Compilation.zig+9
...@@ -158,6 +158,10 @@ emit_docs: ?EmitLoc,...@@ -158,6 +158,10 @@ emit_docs: ?EmitLoc,
158work_queue_wait_group: WaitGroup,158work_queue_wait_group: WaitGroup,
159astgen_wait_group: WaitGroup,159astgen_wait_group: WaitGroup,
160160
161/// Exported symbol names. This is only for when the target is wasm.
162/// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information.
163export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{},
164
161pub const SemaError = Module.SemaError;165pub const SemaError = Module.SemaError;
162166
163pub const CRTFile = struct {167pub const CRTFile = struct {
...@@ -1791,6 +1795,11 @@ pub fn destroy(self: *Compilation) void {...@@ -1791,6 +1795,11 @@ pub fn destroy(self: *Compilation) void {
1791 self.work_queue_wait_group.deinit();1795 self.work_queue_wait_group.deinit();
1792 self.astgen_wait_group.deinit();1796 self.astgen_wait_group.deinit();
17931797
1798 for (self.export_symbol_names.items) |symbol_name| {
1799 gpa.free(symbol_name);
1800 }
1801 self.export_symbol_names.deinit(gpa);
1802
1794 // This destroys `self`.1803 // This destroys `self`.
1795 self.arena_state.promote(gpa).deinit();1804 self.arena_state.promote(gpa).deinit();
1796}1805}
src/link/Wasm.zig+32-14
...@@ -1058,8 +1058,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1058,8 +1058,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1058 }1058 }
10591059
1060 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});1060 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
10611061 if (is_obj) {
1062 if (self.base.options.output_mode == .Obj) {
1063 // LLD's WASM driver does not support the equivalent of `-r` so we do a simple file copy1062 // LLD's WASM driver does not support the equivalent of `-r` so we do a simple file copy
1064 // here. TODO: think carefully about how we can avoid this redundant operation when doing1063 // here. TODO: think carefully about how we can avoid this redundant operation when doing
1065 // build-obj. See also the corresponding TODO in linkAsArchive.1064 // build-obj. See also the corresponding TODO in linkAsArchive.
...@@ -1125,14 +1124,45 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1125,14 +1124,45 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1125 try argv.append("--stack-first");1124 try argv.append("--stack-first");
1126 }1125 }
11271126
1127 var auto_export_symbols = true;
1128 // Users are allowed to specify which symbols they want to export to the wasm host.1128 // Users are allowed to specify which symbols they want to export to the wasm host.
1129 for (self.base.options.export_symbol_names) |symbol_name| {1129 for (self.base.options.export_symbol_names) |symbol_name| {
1130 const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});1130 const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});
1131 try argv.append(arg);1131 try argv.append(arg);
1132 auto_export_symbols = false;
1132 }1133 }
11331134
1134 if (self.base.options.rdynamic) {1135 if (self.base.options.rdynamic) {
1135 try argv.append("--export-dynamic");1136 try argv.append("--export-dynamic");
1137 auto_export_symbols = false;
1138 }
1139
1140 if (auto_export_symbols) {
1141 if (self.base.options.module) |module| {
1142 // when we use stage1, we use the exports that stage1 provided us.
1143 // For stage2, we can directly retrieve them from the module.
1144 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
1145 if (use_stage1) {
1146 for (comp.export_symbol_names.items) |symbol_name| {
1147 try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}));
1148 }
1149 } else {
1150 const skip_export_non_fn = target.os.tag == .wasi and
1151 self.base.options.wasi_exec_model == .command;
1152 for (module.decl_exports.values()) |exports| {
1153 for (exports) |exprt| {
1154 if (skip_export_non_fn and exprt.exported_decl.ty.zigTypeTag() != .Fn) {
1155 // skip exporting symbols when we're building a WASI command
1156 // and the symbol is not a function
1157 continue;
1158 }
1159 const symbol_name = exprt.exported_decl.name;
1160 const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});
1161 try argv.append(arg);
1162 }
1163 }
1164 }
1165 }
1136 }1166 }
11371167
1138 if (self.base.options.output_mode == .Exe) {1168 if (self.base.options.output_mode == .Exe) {
...@@ -1146,12 +1176,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1146,12 +1176,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1146 if (self.base.options.wasi_exec_model == .reactor) {1176 if (self.base.options.wasi_exec_model == .reactor) {
1147 // Reactor execution model does not have _start so lld doesn't look for it.1177 // Reactor execution model does not have _start so lld doesn't look for it.
1148 try argv.append("--no-entry");1178 try argv.append("--no-entry");
1149 // Make sure "_initialize" and other used-defined functions are exported if this is WASI reactor.
1150 // If rdynamic is true, it will already be appended, so only verify if the user did not specify
1151 // the flag in which case, we ensure `--export-dynamic` is called.
1152 if (!self.base.options.rdynamic) {
1153 try argv.append("--export-dynamic");
1154 }
1155 }1179 }
1156 } else {1180 } else {
1157 if (self.base.options.stack_size_override) |stack_size| {1181 if (self.base.options.stack_size_override) |stack_size| {
...@@ -1159,12 +1183,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1159,12 +1183,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1159 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});1183 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
1160 try argv.append(arg);1184 try argv.append(arg);
1161 }1185 }
1162
1163 // Only when the user has not specified how they want to export the symbols, do we want
1164 // to export all symbols.
1165 if (self.base.options.export_symbol_names.len == 0 and !self.base.options.rdynamic) {
1166 try argv.append("--export-all");
1167 }
1168 try argv.append("--no-entry"); // So lld doesn't look for _start.1186 try argv.append("--no-entry"); // So lld doesn't look for _start.
1169 }1187 }
1170 try argv.appendSlice(&[_][]const u8{1188 try argv.appendSlice(&[_][]const u8{
src/stage1.zig+8
...@@ -464,3 +464,11 @@ export fn stage2_fetch_file(...@@ -464,3 +464,11 @@ export fn stage2_fetch_file(
464 if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1);464 if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1);
465 return contents.ptr;465 return contents.ptr;
466}466}
467
468export fn stage2_append_symbol(stage1: *Module, name_ptr: [*c]const u8, name_len: usize) Error {
469 if (name_len == 0) return Error.None;
470 const comp = @intToPtr(*Compilation, stage1.userdata);
471 const sym_name = comp.gpa.dupe(u8, name_ptr[0..name_len]) catch return Error.OutOfMemory;
472 comp.export_symbol_names.append(comp.gpa, sym_name) catch return Error.OutOfMemory;
473 return Error.None;
474}
src/stage1/codegen.cpp+12
...@@ -9905,6 +9905,18 @@ void codegen_build_object(CodeGen *g) {...@@ -9905,6 +9905,18 @@ void codegen_build_object(CodeGen *g) {
99059905
9906 codegen_add_time_event(g, "Done");9906 codegen_add_time_event(g, "Done");
9907 codegen_switch_sub_prog_node(g, nullptr);9907 codegen_switch_sub_prog_node(g, nullptr);
9908
9909 // append all export symbols to stage2 so we can provide them to the linker
9910 if (target_is_wasm(g->zig_target)){
9911 Error err;
9912 auto export_it = g->exported_symbol_names.entry_iterator();
9913 decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr;
9914 while ((curr_entry = export_it.next()) != nullptr) {
9915 if ((err = stage2_append_symbol(&g->stage1, buf_ptr(curr_entry->key), buf_len(curr_entry->key)))) {
9916 fprintf(stderr, "Unable to export symbol '%s': %s\n", buf_ptr(curr_entry->key), err_str(err));
9917 }
9918 }
9919 }
9908}9920}
99099921
9910ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path,9922ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path,
src/stage1/stage2.h+3
...@@ -182,4 +182,7 @@ ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1,...@@ -182,4 +182,7 @@ ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1,
182 const char *lib_name_ptr, size_t lib_name_len,182 const char *lib_name_ptr, size_t lib_name_len,
183 const char *symbol_name_ptr, size_t symbol_name_len);183 const char *symbol_name_ptr, size_t symbol_name_len);
184184
185// ABI warning
186ZIG_EXTERN_C enum Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len);
187
185#endif188#endif
src/stage1/zig0.cpp+5
...@@ -554,3 +554,8 @@ const char *stage2_version_string(void) {...@@ -554,3 +554,8 @@ const char *stage2_version_string(void) {
554struct Stage2SemVer stage2_version(void) {554struct Stage2SemVer stage2_version(void) {
555 return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH};555 return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH};
556}556}
557
558Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len)
559{
560 return ErrorNone;
561}