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) = .{},...@@ -101,8 +101,8 @@ exports: std.ArrayListUnmanaged(types.Export) = .{},
101/// When this is non-zero, we must emit a table entry,101/// When this is non-zero, we must emit a table entry,
102/// as well as an 'elements' section.102/// as well as an 'elements' section.
103///103///
104/// Note: Key is symbol index, value represents the index into the table104/// Note: Key is symbol location, value represents the index into the table
105function_table: std.AutoHashMapUnmanaged(u32, u32) = .{},105function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},
106106
107/// All object files and their data which are linked into the final binary107/// All object files and their data which are linked into the final binary
108objects: std.ArrayListUnmanaged(Object) = .{},108objects: std.ArrayListUnmanaged(Object) = .{},
...@@ -363,6 +363,9 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -363,6 +363,9 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
363 .index = sym_index,363 .index = sym_index,
364 };364 };
365 const sym_name = object.string_table.get(symbol.name);365 const sym_name = object.string_table.get(symbol.name);
366 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
367 continue;
368 }
366 const sym_name_index = try self.string_table.put(self.base.allocator, sym_name);369 const sym_name_index = try self.string_table.put(self.base.allocator, sym_name);
367370
368 if (symbol.isLocal()) {371 if (symbol.isLocal()) {
...@@ -837,7 +840,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {...@@ -837,7 +840,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
837/// Appends a new entry to the indirect function table840/// Appends a new entry to the indirect function table
838pub fn addTableFunction(self: *Wasm, symbol_index: u32) !void {841pub fn addTableFunction(self: *Wasm, symbol_index: u32) !void {
839 const index = @intCast(u32, self.function_table.count());842 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);
841}844}
842845
843/// Assigns indexes to all indirect functions.846/// Assigns indexes to all indirect functions.
...@@ -1017,6 +1020,9 @@ fn setupImports(self: *Wasm) !void {...@@ -1017,6 +1020,9 @@ fn setupImports(self: *Wasm) !void {
1017 }1020 }
10181021
1019 const symbol = symbol_loc.getSymbol(self);1022 const symbol = symbol_loc.getSymbol(self);
1023 if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) {
1024 continue;
1025 }
1020 if (symbol.tag == .data or !symbol.requiresImport()) {1026 if (symbol.tag == .data or !symbol.requiresImport()) {
1021 continue;1027 continue;
1022 }1028 }
...@@ -1166,13 +1172,20 @@ fn setupExports(self: *Wasm) !void {...@@ -1166,13 +1172,20 @@ fn setupExports(self: *Wasm) !void {
1166 if (!symbol.isExported()) continue;1172 if (!symbol.isExported()) continue;
11671173
1168 const sym_name = sym_loc.getName(self);1174 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 };
1170 const exp: types.Export = .{1179 const exp: types.Export = .{
1171 .name = export_name,1180 .name = export_name,
1172 .kind = symbol.tag.externalType(),1181 .kind = symbol.tag.externalType(),
1173 .index = symbol.index,1182 .index = symbol.index,
1174 };1183 };
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 });
1176 try self.exports.append(self.base.allocator, exp);1189 try self.exports.append(self.base.allocator, exp);
1177 }1190 }
11781191
...@@ -1767,8 +1780,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -1767,8 +1780,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
1767 try leb.writeULEB128(writer, @as(u8, 0));1780 try leb.writeULEB128(writer, @as(u8, 0));
1768 try leb.writeULEB128(writer, @intCast(u32, self.function_table.count()));1781 try leb.writeULEB128(writer, @intCast(u32, self.function_table.count()));
1769 var symbol_it = self.function_table.keyIterator();1782 var symbol_it = self.function_table.keyIterator();
1770 while (symbol_it.next()) |symbol_index_ptr| {1783 while (symbol_it.next()) |symbol_loc_ptr| {
1771 try leb.writeULEB128(writer, self.symbols.items[symbol_index_ptr.*].index);1784 try leb.writeULEB128(writer, symbol_loc_ptr.*.getSymbol(self).index);
1772 }1785 }
17731786
1774 try writeVecSectionHeader(1787 try writeVecSectionHeader(
src/link/Wasm/Atom.zig+1-1
...@@ -158,7 +158,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa...@@ -158,7 +158,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
158 .R_WASM_TABLE_INDEX_I64,158 .R_WASM_TABLE_INDEX_I64,
159 .R_WASM_TABLE_INDEX_SLEB,159 .R_WASM_TABLE_INDEX_SLEB,
160 .R_WASM_TABLE_INDEX_SLEB64,160 .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,
162 .R_WASM_TYPE_INDEX_LEB => return wasm_bin.functions.items[symbol.index].type_index,162 .R_WASM_TYPE_INDEX_LEB => return wasm_bin.functions.items[symbol.index].type_index,
163 .R_WASM_GLOBAL_INDEX_I32,163 .R_WASM_GLOBAL_INDEX_I32,
164 .R_WASM_GLOBAL_INDEX_LEB,164 .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...@@ -851,15 +851,12 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
851 reloc.offset -= relocatable_data.offset;851 reloc.offset -= relocatable_data.offset;
852 try atom.relocs.append(gpa, reloc);852 try atom.relocs.append(gpa, reloc);
853853
854 // TODO: Automatically append the target symbol to the indirect854 if (relocation.isTableIndex()) {
855 // function table when the relocation is a table index.855 try wasm_bin.function_table.putNoClobber(gpa, .{
856 //856 .file = object_index,
857 // if (relocation.isTableIndex()) {857 .index = relocation.index,
858 // try wasm_bin.elements.appendSymbol(gpa, .{858 }, 0);
859 // .file = object_index,859 }
860 // .sym_index = relocation.index,
861 // });
862 // }
863 }860 }
864 }861 }
865862
src/link/Wasm/types.zig+12
...@@ -67,6 +67,18 @@ pub const Relocation = struct {...@@ -67,6 +67,18 @@ pub const Relocation = struct {
67 };67 };
68 }68 }
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
70 pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {82 pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
71 _ = fmt;83 _ = fmt;
72 _ = options;84 _ = options;