authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-04-13 22:10:02+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-04-14 22:53:13+02:00
logcf37101108e56412e958a8b597bae84649893b6f
tree29979e1e3e82acba2b6da1893b834a8636993ede
parent321a1642693b74481e12cae8d7be089c6ef45cc1

wasm-linker: Add function table indexes

When linking with an object file, verify if a relocation is a table index relocation. If that's the case, add the relocation target to the function table.

4 files changed, 39 insertions(+), 17 deletions(-)

src/link/Wasm.zig+20-7
......@@ -101,8 +101,8 @@ exports: std.ArrayListUnmanaged(types.Export) = .{},
101101/// When this is non-zero, we must emit a table entry,
102102/// as well as an 'elements' section.
103103///
104/// Note: Key is symbol index, value represents the index into the table
105function_table: std.AutoHashMapUnmanaged(u32, u32) = .{},
104/// Note: Key is symbol location, value represents the index into the table
105function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},
106106
107107/// All object files and their data which are linked into the final binary
108108objects: std.ArrayListUnmanaged(Object) = .{},
......@@ -363,6 +363,9 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
363363 .index = sym_index,
364364 };
365365 const sym_name = object.string_table.get(symbol.name);
366 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
367 continue;
368 }
366369 const sym_name_index = try self.string_table.put(self.base.allocator, sym_name);
367370
368371 if (symbol.isLocal()) {
......@@ -837,7 +840,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
837840/// Appends a new entry to the indirect function table
838841pub fn addTableFunction(self: *Wasm, symbol_index: u32) !void {
839842 const index = @intCast(u32, self.function_table.count());
840 try self.function_table.put(self.base.allocator, symbol_index, index);
843 try self.function_table.put(self.base.allocator, .{ .file = null, .index = symbol_index }, index);
841844}
842845
843846/// Assigns indexes to all indirect functions.
......@@ -1017,6 +1020,9 @@ fn setupImports(self: *Wasm) !void {
10171020 }
10181021
10191022 const symbol = symbol_loc.getSymbol(self);
1023 if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) {
1024 continue;
1025 }
10201026 if (symbol.tag == .data or !symbol.requiresImport()) {
10211027 continue;
10221028 }
......@@ -1166,13 +1172,20 @@ fn setupExports(self: *Wasm) !void {
11661172 if (!symbol.isExported()) continue;
11671173
11681174 const sym_name = sym_loc.getName(self);
1169 const export_name = if (self.export_names.get(sym_loc)) |name| name else symbol.name;
1175 const export_name = if (self.export_names.get(sym_loc)) |name| name else blk: {
1176 if (sym_loc.file == null) break :blk symbol.name;
1177 break :blk try self.string_table.put(self.base.allocator, sym_name);
1178 };
11701179 const exp: types.Export = .{
11711180 .name = export_name,
11721181 .kind = symbol.tag.externalType(),
11731182 .index = symbol.index,
11741183 };
1175 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ sym_name, self.string_table.get(exp.name), exp.index });
1184 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{
1185 sym_name,
1186 self.string_table.get(exp.name),
1187 exp.index,
1188 });
11761189 try self.exports.append(self.base.allocator, exp);
11771190 }
11781191
......@@ -1767,8 +1780,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
17671780 try leb.writeULEB128(writer, @as(u8, 0));
17681781 try leb.writeULEB128(writer, @intCast(u32, self.function_table.count()));
17691782 var symbol_it = self.function_table.keyIterator();
1770 while (symbol_it.next()) |symbol_index_ptr| {
1771 try leb.writeULEB128(writer, self.symbols.items[symbol_index_ptr.*].index);
1783 while (symbol_it.next()) |symbol_loc_ptr| {
1784 try leb.writeULEB128(writer, symbol_loc_ptr.*.getSymbol(self).index);
17721785 }
17731786
17741787 try writeVecSectionHeader(
src/link/Wasm/Atom.zig+1-1
......@@ -158,7 +158,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
158158 .R_WASM_TABLE_INDEX_I64,
159159 .R_WASM_TABLE_INDEX_SLEB,
160160 .R_WASM_TABLE_INDEX_SLEB64,
161 => return wasm_bin.function_table.get(relocation.index) orelse 0,
161 => return wasm_bin.function_table.get(target_loc) orelse 0,
162162 .R_WASM_TYPE_INDEX_LEB => return wasm_bin.functions.items[symbol.index].type_index,
163163 .R_WASM_GLOBAL_INDEX_I32,
164164 .R_WASM_GLOBAL_INDEX_LEB,
src/link/Wasm/Object.zig+6-9
......@@ -851,15 +851,12 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
851851 reloc.offset -= relocatable_data.offset;
852852 try atom.relocs.append(gpa, reloc);
853853
854 // TODO: Automatically append the target symbol to the indirect
855 // function table when the relocation is a table index.
856 //
857 // if (relocation.isTableIndex()) {
858 // try wasm_bin.elements.appendSymbol(gpa, .{
859 // .file = object_index,
860 // .sym_index = relocation.index,
861 // });
862 // }
854 if (relocation.isTableIndex()) {
855 try wasm_bin.function_table.putNoClobber(gpa, .{
856 .file = object_index,
857 .index = relocation.index,
858 }, 0);
859 }
863860 }
864861 }
865862
src/link/Wasm/types.zig+12
......@@ -67,6 +67,18 @@ pub const Relocation = struct {
6767 };
6868 }
6969
70 /// Returns true when the relocation represents a table index relocatable
71 pub fn isTableIndex(self: Relocation) bool {
72 return switch (self.relocation_type) {
73 .R_WASM_TABLE_INDEX_I32,
74 .R_WASM_TABLE_INDEX_I64,
75 .R_WASM_TABLE_INDEX_SLEB,
76 .R_WASM_TABLE_INDEX_SLEB64,
77 => true,
78 else => false,
79 };
80 }
81
7082 pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
7183 _ = fmt;
7284 _ = options;