authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-12-21 20:10:36+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-21 12:38:50-08:00
log4cb2f11693b1bf13770b8ad6a8b8a1e37101a516
tree5c874f02332d2cefabc66fd5d5d6d6e505ea6599
parente15a267668bae168f2bba06cc3706c54bc062522

wasm-linker: Implement the --export-table and --import-table flags.

This implements the flags for both the linker frontend as well as the self-hosted linker. Closes #5790

5 files changed, 76 insertions(+), 6 deletions(-)

lib/std/build.zig+8
...@@ -1479,6 +1479,8 @@ pub const LibExeObjStep = struct {...@@ -1479,6 +1479,8 @@ pub const LibExeObjStep = struct {
1479 sanitize_thread: bool,1479 sanitize_thread: bool,
1480 rdynamic: bool,1480 rdynamic: bool,
1481 import_memory: bool = false,1481 import_memory: bool = false,
1482 import_table: bool = false,
1483 export_table: bool = false,
1482 initial_memory: ?u64 = null,1484 initial_memory: ?u64 = null,
1483 max_memory: ?u64 = null,1485 max_memory: ?u64 = null,
1484 global_base: ?u64 = null,1486 global_base: ?u64 = null,
...@@ -2509,6 +2511,12 @@ pub const LibExeObjStep = struct {...@@ -2509,6 +2511,12 @@ pub const LibExeObjStep = struct {
2509 if (self.import_memory) {2511 if (self.import_memory) {
2510 try zig_args.append("--import-memory");2512 try zig_args.append("--import-memory");
2511 }2513 }
2514 if (self.import_table) {
2515 try zig_args.append("--import-table");
2516 }
2517 if (self.export_table) {
2518 try zig_args.append("--export-table");
2519 }
2512 if (self.initial_memory) |initial_memory| {2520 if (self.initial_memory) |initial_memory| {
2513 try zig_args.append(builder.fmt("--initial-memory={d}", .{initial_memory}));2521 try zig_args.append(builder.fmt("--initial-memory={d}", .{initial_memory}));
2514 }2522 }
src/Compilation.zig+4
...@@ -724,6 +724,8 @@ pub const InitOptions = struct {...@@ -724,6 +724,8 @@ pub const InitOptions = struct {
724 linker_allow_shlib_undefined: ?bool = null,724 linker_allow_shlib_undefined: ?bool = null,
725 linker_bind_global_refs_locally: ?bool = null,725 linker_bind_global_refs_locally: ?bool = null,
726 linker_import_memory: ?bool = null,726 linker_import_memory: ?bool = null,
727 linker_import_table: bool = false,
728 linker_export_table: bool = false,
727 linker_initial_memory: ?u64 = null,729 linker_initial_memory: ?u64 = null,
728 linker_max_memory: ?u64 = null,730 linker_max_memory: ?u64 = null,
729 linker_global_base: ?u64 = null,731 linker_global_base: ?u64 = null,
...@@ -1457,6 +1459,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1457,6 +1459,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1457 .allow_shlib_undefined = options.linker_allow_shlib_undefined,1459 .allow_shlib_undefined = options.linker_allow_shlib_undefined,
1458 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,1460 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
1459 .import_memory = options.linker_import_memory orelse false,1461 .import_memory = options.linker_import_memory orelse false,
1462 .import_table = options.linker_import_table,
1463 .export_table = options.linker_export_table,
1460 .initial_memory = options.linker_initial_memory,1464 .initial_memory = options.linker_initial_memory,
1461 .max_memory = options.linker_max_memory,1465 .max_memory = options.linker_max_memory,
1462 .global_base = options.linker_global_base,1466 .global_base = options.linker_global_base,
src/link.zig+2
...@@ -102,6 +102,8 @@ pub const Options = struct {...@@ -102,6 +102,8 @@ pub const Options = struct {
102 linker_optimization: u8,102 linker_optimization: u8,
103 bind_global_refs_locally: bool,103 bind_global_refs_locally: bool,
104 import_memory: bool,104 import_memory: bool,
105 import_table: bool,
106 export_table: bool,
105 initial_memory: ?u64,107 initial_memory: ?u64,
106 max_memory: ?u64,108 max_memory: ?u64,
107 export_symbol_names: []const []const u8,109 export_symbol_names: []const []const u8,
src/link/Wasm.zig+48-6
...@@ -635,11 +635,30 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -635,11 +635,30 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
635 }635 }
636636
637 // Import section637 // Import section
638 const import_mem = self.base.options.import_memory;638 const import_memory = self.base.options.import_memory;
639 if (self.imports.count() != 0 or import_mem) {639 const import_table = self.base.options.import_table;
640 if (self.imports.count() != 0 or import_memory or import_table) {
640 const header_offset = try reserveVecSectionHeader(file);641 const header_offset = try reserveVecSectionHeader(file);
641 const writer = file.writer();642 const writer = file.writer();
642643
644 // import table is always first table so emit that first
645 if (import_table) {
646 const table_imp: wasm.Import = .{
647 .module_name = self.host_name,
648 .name = "__indirect_function_table",
649 .kind = .{
650 .table = .{
651 .limits = .{
652 .min = @intCast(u32, self.imports.count()),
653 .max = null,
654 },
655 .reftype = .funcref,
656 },
657 },
658 };
659 try emitImport(writer, table_imp);
660 }
661
643 var it = self.imports.iterator();662 var it = self.imports.iterator();
644 while (it.next()) |entry| {663 while (it.next()) |entry| {
645 const import_symbol = self.symbols.items[entry.key_ptr.*];664 const import_symbol = self.symbols.items[entry.key_ptr.*];
...@@ -648,7 +667,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -648,7 +667,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
648 try emitImport(writer, import);667 try emitImport(writer, import);
649 }668 }
650669
651 if (import_mem) {670 if (import_memory) {
652 const mem_imp: wasm.Import = .{671 const mem_imp: wasm.Import = .{
653 .module_name = self.host_name,672 .module_name = self.host_name,
654 .name = "memory",673 .name = "memory",
...@@ -662,7 +681,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -662,7 +681,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
662 header_offset,681 header_offset,
663 .import,682 .import,
664 @intCast(u32, (try file.getPos()) - header_offset - header_size),683 @intCast(u32, (try file.getPos()) - header_offset - header_size),
665 @intCast(u32, self.imports.count() + @boolToInt(import_mem)),684 @intCast(u32, self.imports.count() + @boolToInt(import_memory)),
666 );685 );
667 }686 }
668687
...@@ -684,7 +703,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -684,7 +703,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
684 }703 }
685704
686 // Table section705 // Table section
687 if (self.function_table.count() > 0) {706 const export_table = self.base.options.export_table;
707 if (!import_table and (self.function_table.count() > 0 or export_table)) {
688 const header_offset = try reserveVecSectionHeader(file);708 const header_offset = try reserveVecSectionHeader(file);
689 const writer = file.writer();709 const writer = file.writer();
690710
...@@ -767,7 +787,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -767,7 +787,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
767 }787 }
768788
769 // export memory if size is not 0789 // export memory if size is not 0
770 if (!self.base.options.import_memory) {790 if (!import_memory) {
771 try leb.writeULEB128(writer, @intCast(u32, "memory".len));791 try leb.writeULEB128(writer, @intCast(u32, "memory".len));
772 try writer.writeAll("memory");792 try writer.writeAll("memory");
773 try writer.writeByte(wasm.externalKind(.memory));793 try writer.writeByte(wasm.externalKind(.memory));
...@@ -775,6 +795,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -775,6 +795,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
775 count += 1;795 count += 1;
776 }796 }
777797
798 if (export_table) {
799 try leb.writeULEB128(writer, @intCast(u32, "__indirect_function_table".len));
800 try writer.writeAll("__indirect_function_table");
801 try writer.writeByte(wasm.externalKind(.table));
802 try leb.writeULEB128(writer, @as(u32, 0)); // function table is always the first table
803 count += 1;
804 }
805
778 try writeVecSectionHeader(806 try writeVecSectionHeader(
779 file,807 file,
780 header_offset,808 header_offset,
...@@ -1008,6 +1036,8 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1008,6 +1036,8 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1008 try man.addOptionalFile(compiler_rt_path);1036 try man.addOptionalFile(compiler_rt_path);
1009 man.hash.addOptional(self.base.options.stack_size_override);1037 man.hash.addOptional(self.base.options.stack_size_override);
1010 man.hash.add(self.base.options.import_memory);1038 man.hash.add(self.base.options.import_memory);
1039 man.hash.add(self.base.options.import_table);
1040 man.hash.add(self.base.options.export_table);
1011 man.hash.addOptional(self.base.options.initial_memory);1041 man.hash.addOptional(self.base.options.initial_memory);
1012 man.hash.addOptional(self.base.options.max_memory);1042 man.hash.addOptional(self.base.options.max_memory);
1013 man.hash.addOptional(self.base.options.global_base);1043 man.hash.addOptional(self.base.options.global_base);
...@@ -1092,6 +1122,18 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1092,6 +1122,18 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1092 try argv.append("--import-memory");1122 try argv.append("--import-memory");
1093 }1123 }
10941124
1125 if (self.base.options.import_table) {
1126 if (self.base.options.export_table) {
1127 log.err("--import-table and --export-table may not be used together", .{});
1128 return error.InvalidArgs;
1129 }
1130 try argv.append("--import-table");
1131 }
1132
1133 if (self.base.options.export_table) {
1134 try argv.append("--export-table");
1135 }
1136
1095 if (self.base.options.initial_memory) |initial_memory| {1137 if (self.base.options.initial_memory) |initial_memory| {
1096 const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory});1138 const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory});
1097 try argv.append(arg);1139 try argv.append(arg);
src/main.zig+14
...@@ -432,6 +432,8 @@ const usage_build_generic =...@@ -432,6 +432,8 @@ const usage_build_generic =
432 \\ -F[dir] (Darwin) add search path for frameworks432 \\ -F[dir] (Darwin) add search path for frameworks
433 \\ -install_name=[value] (Darwin) add dylib's install name433 \\ -install_name=[value] (Darwin) add dylib's install name
434 \\ --import-memory (WebAssembly) import memory from the environment434 \\ --import-memory (WebAssembly) import memory from the environment
435 \\ --import-table (WebAssembly) import function table from the host environment
436 \\ --export-table (WebAssembly) export function table to the host environment
435 \\ --initial-memory=[bytes] (WebAssembly) initial size of the linear memory437 \\ --initial-memory=[bytes] (WebAssembly) initial size of the linear memory
436 \\ --max-memory=[bytes] (WebAssembly) maximum size of the linear memory438 \\ --max-memory=[bytes] (WebAssembly) maximum size of the linear memory
437 \\ --global-base=[addr] (WebAssembly) where to start to place global data439 \\ --global-base=[addr] (WebAssembly) where to start to place global data
...@@ -627,6 +629,8 @@ fn buildOutputType(...@@ -627,6 +629,8 @@ fn buildOutputType(
627 var linker_allow_shlib_undefined: ?bool = null;629 var linker_allow_shlib_undefined: ?bool = null;
628 var linker_bind_global_refs_locally: ?bool = null;630 var linker_bind_global_refs_locally: ?bool = null;
629 var linker_import_memory: ?bool = null;631 var linker_import_memory: ?bool = null;
632 var linker_import_table: bool = false;
633 var linker_export_table: bool = false;
630 var linker_initial_memory: ?u64 = null;634 var linker_initial_memory: ?u64 = null;
631 var linker_max_memory: ?u64 = null;635 var linker_max_memory: ?u64 = null;
632 var linker_global_base: ?u64 = null;636 var linker_global_base: ?u64 = null;
...@@ -1179,6 +1183,10 @@ fn buildOutputType(...@@ -1179,6 +1183,10 @@ fn buildOutputType(
1179 }1183 }
1180 } else if (mem.eql(u8, arg, "--import-memory")) {1184 } else if (mem.eql(u8, arg, "--import-memory")) {
1181 linker_import_memory = true;1185 linker_import_memory = true;
1186 } else if (mem.eql(u8, arg, "--import-table")) {
1187 linker_import_table = true;
1188 } else if (mem.eql(u8, arg, "--export-table")) {
1189 linker_export_table = true;
1182 } else if (mem.startsWith(u8, arg, "--initial-memory=")) {1190 } else if (mem.startsWith(u8, arg, "--initial-memory=")) {
1183 linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);1191 linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);
1184 } else if (mem.startsWith(u8, arg, "--max-memory=")) {1192 } else if (mem.startsWith(u8, arg, "--max-memory=")) {
...@@ -1560,6 +1568,10 @@ fn buildOutputType(...@@ -1560,6 +1568,10 @@ fn buildOutputType(
1560 linker_bind_global_refs_locally = true;1568 linker_bind_global_refs_locally = true;
1561 } else if (mem.eql(u8, arg, "--import-memory")) {1569 } else if (mem.eql(u8, arg, "--import-memory")) {
1562 linker_import_memory = true;1570 linker_import_memory = true;
1571 } else if (mem.eql(u8, arg, "--import-table")) {
1572 linker_import_table = true;
1573 } else if (mem.eql(u8, arg, "--export-table")) {
1574 linker_export_table = true;
1563 } else if (mem.startsWith(u8, arg, "--initial-memory=")) {1575 } else if (mem.startsWith(u8, arg, "--initial-memory=")) {
1564 linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);1576 linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);
1565 } else if (mem.startsWith(u8, arg, "--max-memory=")) {1577 } else if (mem.startsWith(u8, arg, "--max-memory=")) {
...@@ -2455,6 +2467,8 @@ fn buildOutputType(...@@ -2455,6 +2467,8 @@ fn buildOutputType(
2455 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,2467 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
2456 .linker_bind_global_refs_locally = linker_bind_global_refs_locally,2468 .linker_bind_global_refs_locally = linker_bind_global_refs_locally,
2457 .linker_import_memory = linker_import_memory,2469 .linker_import_memory = linker_import_memory,
2470 .linker_import_table = linker_import_table,
2471 .linker_export_table = linker_export_table,
2458 .linker_initial_memory = linker_initial_memory,2472 .linker_initial_memory = linker_initial_memory,
2459 .linker_max_memory = linker_max_memory,2473 .linker_max_memory = linker_max_memory,
2460 .linker_global_base = linker_global_base,2474 .linker_global_base = linker_global_base,