Commit 3ca3fe94f4
Changed files (1)
src
link
src/link/Wasm.zig
@@ -335,41 +335,64 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
wasm_bin.base.file = file;
wasm_bin.name = sub_path;
- // As sym_index '0' is reserved, we use it for our stack pointer symbol
- const sym_name = try wasm_bin.string_table.put(allocator, "__stack_pointer");
- const symbol = try wasm_bin.symbols.addOne(allocator);
- symbol.* = .{
- .name = sym_name,
- .tag = .global,
- .flags = 0,
- .index = 0,
- };
- const loc: SymbolLoc = .{ .file = null, .index = 0 };
- try wasm_bin.resolved_symbols.putNoClobber(allocator, loc, {});
- try wasm_bin.globals.putNoClobber(allocator, sym_name, loc);
-
- // For object files we will import the stack pointer symbol
- if (options.output_mode == .Obj) {
- symbol.setUndefined(true);
- try wasm_bin.imports.putNoClobber(
- allocator,
- .{ .file = null, .index = 0 },
- .{
- .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name),
- .name = sym_name,
- .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
- },
- );
- } else {
- symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
- const global = try wasm_bin.wasm_globals.addOne(allocator);
- global.* = .{
- .global_type = .{
- .valtype = .i32,
- .mutable = true,
- },
- .init = .{ .i32_const = 0 },
+ // create stack pointer symbol
+ {
+ const loc = try wasm_bin.createSyntheticSymbol("__stack_pointer", .global);
+ const symbol = loc.getSymbol(wasm_bin);
+ // For object files we will import the stack pointer symbol
+ if (options.output_mode == .Obj) {
+ symbol.setUndefined(true);
+ symbol.index = @intCast(u32, wasm_bin.imported_globals_count);
+ wasm_bin.imported_globals_count += 1;
+ try wasm_bin.imports.putNoClobber(
+ allocator,
+ loc,
+ .{
+ .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name),
+ .name = symbol.name,
+ .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
+ },
+ );
+ } else {
+ symbol.index = @intCast(u32, wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
+ symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
+ const global = try wasm_bin.wasm_globals.addOne(allocator);
+ global.* = .{
+ .global_type = .{
+ .valtype = .i32,
+ .mutable = true,
+ },
+ .init = .{ .i32_const = 0 },
+ };
+ }
+ }
+
+ // create indirect function pointer symbol
+ {
+ const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table);
+ const symbol = loc.getSymbol(wasm_bin);
+ const table: std.wasm.Table = .{
+ .limits = .{ .min = 0, .max = null }, // will be overwritten during `mapFunctionTable`
+ .reftype = .funcref,
};
+ if (options.output_mode == .Obj or options.import_table) {
+ symbol.setUndefined(true);
+ symbol.index = @intCast(u32, wasm_bin.imported_tables_count);
+ wasm_bin.imported_tables_count += 1;
+ try wasm_bin.imports.put(allocator, loc, .{
+ .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name),
+ .name = symbol.name,
+ .kind = .{ .table = table },
+ });
+ } else {
+ symbol.index = @intCast(u32, wasm_bin.imported_tables_count + wasm_bin.tables.items.len);
+ try wasm_bin.tables.append(allocator, table);
+ if (options.export_table) {
+ symbol.setFlag(.WASM_SYM_EXPORTED);
+ } else {
+ symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
+ }
+ }
}
if (!options.strip and options.module != null) {
@@ -400,6 +423,22 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
return wasm;
}
+/// For a given name, creates a new global synthetic symbol.
+/// Leaves index undefined and the default flags (0).
+fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc {
+ const name_offset = try wasm.string_table.put(wasm.base.allocator, name);
+ const sym_index = @intCast(u32, wasm.symbols.items.len);
+ const loc: SymbolLoc = .{ .index = sym_index, .file = null };
+ try wasm.symbols.append(wasm.base.allocator, .{
+ .name = name_offset,
+ .flags = 0,
+ .tag = tag,
+ .index = undefined,
+ });
+ try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, loc, {});
+ try wasm.globals.putNoClobber(wasm.base.allocator, name_offset, loc);
+ return loc;
+}
/// Initializes symbols and atoms for the debug sections
/// Initialization is only done when compiling Zig code.
/// When Zig is invoked as a linker instead, the atoms
@@ -1249,7 +1288,7 @@ pub fn updateDeclExports(
const existing_sym: Symbol = existing_loc.getSymbol(wasm).*;
const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak;
- // When both the to-bo-exported symbol and the already existing symbol
+ // When both the to-be-exported symbol and the already existing symbol
// are strong symbols, we have a linker error.
// In the other case we replace one with the other.
if (!exp_is_weak and !existing_sym.isWeak()) {
@@ -1361,6 +1400,19 @@ fn mapFunctionTable(wasm: *Wasm) void {
while (it.next()) |value_ptr| : (index += 1) {
value_ptr.* = index;
}
+
+ if (wasm.base.options.import_table or wasm.base.options.output_mode == .Obj) {
+ const sym_loc = wasm.globals.get(wasm.string_table.getOffset("__indirect_function_table").?).?;
+ const import = wasm.imports.getPtr(sym_loc).?;
+ import.kind.table.limits.min = index - 1; // we start at index 1.
+ } else if (index > 1) {
+ log.debug("Appending indirect function table", .{});
+ const offset = wasm.string_table.getOffset("__indirect_function_table").?;
+ const sym_with_loc = wasm.globals.get(offset).?;
+ const symbol = sym_with_loc.getSymbol(wasm);
+ const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];
+ table.limits = .{ .min = index, .max = index };
+ }
}
/// Either creates a new import, or updates one if existing.
@@ -1700,17 +1752,6 @@ fn setupImports(wasm: *Wasm) !void {
/// Takes the global, function and table section from each linked object file
/// and merges it into a single section for each.
fn mergeSections(wasm: *Wasm) !void {
- // append the indirect function table if initialized
- if (wasm.string_table.getOffset("__indirect_function_table")) |offset| {
- const sym_loc = wasm.globals.get(offset).?;
- const table: std.wasm.Table = .{
- .limits = .{ .min = @intCast(u32, wasm.function_table.count()), .max = null },
- .reftype = .funcref,
- };
- sym_loc.getSymbol(wasm).index = @intCast(u32, wasm.tables.items.len) + wasm.imported_tables_count;
- try wasm.tables.append(wasm.base.allocator, table);
- }
-
for (wasm.resolved_symbols.keys()) |sym_loc| {
if (sym_loc.file == null) {
// Zig code-generated symbols are already within the sections and do not
@@ -2613,28 +2654,9 @@ fn writeToFile(
// Import section
const import_memory = wasm.base.options.import_memory or is_obj;
- const import_table = wasm.base.options.import_table or is_obj;
- if (wasm.imports.count() != 0 or import_memory or import_table) {
+ if (wasm.imports.count() != 0 or import_memory) {
const header_offset = try reserveVecSectionHeader(&binary_bytes);
- // import table is always first table so emit that first
- if (import_table) {
- const table_imp: types.Import = .{
- .module_name = try wasm.string_table.put(wasm.base.allocator, wasm.host_name),
- .name = try wasm.string_table.put(wasm.base.allocator, "__indirect_function_table"),
- .kind = .{
- .table = .{
- .limits = .{
- .min = @intCast(u32, wasm.function_table.count()),
- .max = null,
- },
- .reftype = .funcref,
- },
- },
- };
- try wasm.emitImport(binary_writer, table_imp);
- }
-
var it = wasm.imports.iterator();
while (it.next()) |entry| {
assert(entry.key_ptr.*.getSymbol(wasm).isUndefined());
@@ -2657,7 +2679,7 @@ fn writeToFile(
header_offset,
.import,
@intCast(u32, binary_bytes.items.len - header_offset - header_size),
- @intCast(u32, wasm.imports.count() + @boolToInt(import_memory) + @boolToInt(import_table)),
+ @intCast(u32, wasm.imports.count() + @boolToInt(import_memory)),
);
section_count += 1;
}
@@ -2680,22 +2702,20 @@ fn writeToFile(
}
// Table section
- const export_table = wasm.base.options.export_table;
- if (!import_table and wasm.function_table.count() != 0) {
+ if (wasm.tables.items.len > 0) {
const header_offset = try reserveVecSectionHeader(&binary_bytes);
- try leb.writeULEB128(binary_writer, std.wasm.reftype(.funcref));
- try emitLimits(binary_writer, .{
- .min = @intCast(u32, wasm.function_table.count()) + 1,
- .max = null,
- });
+ for (wasm.tables.items) |table| {
+ try leb.writeULEB128(binary_writer, std.wasm.reftype(table.reftype));
+ try emitLimits(binary_writer, table.limits);
+ }
try writeVecSectionHeader(
binary_bytes.items,
header_offset,
.table,
@intCast(u32, binary_bytes.items.len - header_offset - header_size),
- @as(u32, 1),
+ @intCast(u32, wasm.tables.items.len),
);
section_count += 1;
}
@@ -2748,7 +2768,7 @@ fn writeToFile(
}
// Export section
- if (wasm.exports.items.len != 0 or export_table or !import_memory) {
+ if (wasm.exports.items.len != 0 or !import_memory) {
const header_offset = try reserveVecSectionHeader(&binary_bytes);
for (wasm.exports.items) |exp| {
@@ -2759,13 +2779,6 @@ fn writeToFile(
try leb.writeULEB128(binary_writer, exp.index);
}
- if (export_table) {
- try leb.writeULEB128(binary_writer, @intCast(u32, "__indirect_function_table".len));
- try binary_writer.writeAll("__indirect_function_table");
- try binary_writer.writeByte(std.wasm.externalKind(.table));
- try leb.writeULEB128(binary_writer, @as(u32, 0)); // function table is always the first table
- }
-
if (!import_memory) {
try leb.writeULEB128(binary_writer, @intCast(u32, "memory".len));
try binary_writer.writeAll("memory");
@@ -2778,7 +2791,7 @@ fn writeToFile(
header_offset,
.@"export",
@intCast(u32, binary_bytes.items.len - header_offset - header_size),
- @intCast(u32, wasm.exports.items.len) + @boolToInt(export_table) + @boolToInt(!import_memory),
+ @intCast(u32, wasm.exports.items.len) + @boolToInt(!import_memory),
);
section_count += 1;
}
@@ -2787,11 +2800,18 @@ fn writeToFile(
if (wasm.function_table.count() > 0) {
const header_offset = try reserveVecSectionHeader(&binary_bytes);
- var flags: u32 = 0x2; // Yes we have a table
+ const table_loc = wasm.globals.get(wasm.string_table.getOffset("__indirect_function_table").?).?;
+ const table_sym = table_loc.getSymbol(wasm);
+
+ var flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually
try leb.writeULEB128(binary_writer, flags);
- try leb.writeULEB128(binary_writer, @as(u32, 0)); // index of that table. TODO: Store synthetic symbols
+ if (flags == 0x02) {
+ try leb.writeULEB128(binary_writer, table_sym.index);
+ }
try emitInit(binary_writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid
- try leb.writeULEB128(binary_writer, @as(u8, 0));
+ if (flags == 0x02) {
+ try leb.writeULEB128(binary_writer, @as(u8, 0)); // represents funcref
+ }
try leb.writeULEB128(binary_writer, @intCast(u32, wasm.function_table.count()));
var symbol_it = wasm.function_table.keyIterator();
while (symbol_it.next()) |symbol_loc_ptr| {