authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-03-15 19:27:55+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-03-18 20:13:30+01:00
log9d13c2257dcae11d9bc69035e55c33a7dda14a2b
tree32e99150347fc950bb16e23b587d07e7f975fa20
parentff28c8b60080b24ae7d5e9d485b6aa47e8c8de9c
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: implement TLS initialization function

Implements the TLS initialization function. This is a synthetic function created by the linker. This will only be created when shared-memory is enabled. This function will be called during thread creation, if there's any TLS symbols, which will initialize the TLS segment using the bulk-memory feature.

1 files changed, 72 insertions(+), 3 deletions(-)

src/link/Wasm.zig+72-3
...@@ -1990,10 +1990,23 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {...@@ -1990,10 +1990,23 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
1990 try writer.writeByte(std.wasm.opcode(.end));1990 try writer.writeByte(std.wasm.opcode(.end));
1991 }1991 }
19921992
1993 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;1993 try wasm.createSyntheticFunction(
1994 "__wasm_call_ctors",
1995 std.wasm.Type{ .params = &.{}, .returns = &.{} },
1996 &function_body,
1997 );
1998}
1999
2000fn createSyntheticFunction(
2001 wasm: *Wasm,
2002 symbol_name: []const u8,
2003 func_ty: std.wasm.Type,
2004 function_body: *std.ArrayList(u8),
2005) !void {
2006 const loc = wasm.findGlobalSymbol(symbol_name) orelse
2007 try wasm.createSyntheticSymbol(symbol_name, .function);
1994 const symbol = loc.getSymbol(wasm);2008 const symbol = loc.getSymbol(wasm);
1995 // create type (() -> nil) as we do not have any parameters or return value.2009 const ty_index = try wasm.putOrGetFuncType(func_ty);
1996 const ty_index = try wasm.putOrGetFuncType(.{ .params = &[_]std.wasm.Valtype{}, .returns = &[_]std.wasm.Valtype{} });
1997 // create function with above type2010 // create function with above type
1998 const func_index = wasm.imported_functions_count + @intCast(u32, wasm.functions.count());2011 const func_index = wasm.imported_functions_count + @intCast(u32, wasm.functions.count());
1999 try wasm.functions.putNoClobber(2012 try wasm.functions.putNoClobber(
...@@ -2025,6 +2038,60 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {...@@ -2025,6 +2038,60 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
2025 atom.offset = prev_atom.offset + prev_atom.size;2038 atom.offset = prev_atom.offset + prev_atom.size;
2026}2039}
20272040
2041fn initializeTLSFunction(wasm: *Wasm) !void {
2042 if (!wasm.base.options.shared_memory) return;
2043
2044 var function_body = std.ArrayList(u8).init(wasm.base.allocator);
2045 defer function_body.deinit();
2046 const writer = function_body.writer();
2047
2048 // locals
2049 try writer.writeByte(0);
2050
2051 // If there's a TLS segment, initialize it during runtime using the bulk-memory feature
2052 if (wasm.data_segments.getIndex(".tdata")) |data_index| {
2053 const segment_index = wasm.data_segments.entries.items(.value)[data_index];
2054 const segment = wasm.segments.items[segment_index];
2055
2056 const param_local: u32 = 0;
2057
2058 try writer.writeByte(std.wasm.opcode(.local_get));
2059 try leb.writeULEB128(writer, param_local);
2060
2061 const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?;
2062 try writer.writeByte(std.wasm.opcode(.global_get));
2063 try leb.writeULEB128(writer, tls_base_loc.getSymbol(wasm).index);
2064
2065 // load stack values for the bulk-memory operation
2066 {
2067 try writer.writeByte(std.wasm.opcode(.local_get));
2068 try leb.writeULEB128(writer, param_local);
2069
2070 try writer.writeByte(std.wasm.opcode(.i32_const));
2071 try leb.writeULEB128(writer, @as(u32, 0)); //segment offset
2072
2073 try writer.writeByte(std.wasm.opcode(.i32_const));
2074 try leb.writeULEB128(writer, @as(u32, segment.size)); //segment offset
2075 }
2076
2077 // perform the bulk-memory operation to initialize the data segment
2078 try writer.writeByte(std.wasm.opcode(.prefixed));
2079 try leb.writeULEB128(writer, @enumToInt(std.wasm.PrefixedOpcode.memory_init));
2080 // segment immediate
2081 try leb.writeULEB128(writer, @intCast(u32, data_index));
2082 // memory index immediate (always 0)
2083 try leb.writeULEB128(writer, @as(u32, 0));
2084 }
2085
2086 try writer.writeByte(std.wasm.opcode(.end));
2087
2088 try wasm.createSyntheticFunction(
2089 "__wasm_init_tls",
2090 std.wasm.Type{ .params = &.{.i32}, .returns = &.{} },
2091 &function_body,
2092 );
2093}
2094
2028fn setupImports(wasm: *Wasm) !void {2095fn setupImports(wasm: *Wasm) !void {
2029 log.debug("Merging imports", .{});2096 log.debug("Merging imports", .{});
2030 var discarded_it = wasm.discarded.keyIterator();2097 var discarded_it = wasm.discarded.keyIterator();
...@@ -2872,6 +2939,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -2872,6 +2939,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
2872 try wasm.mergeSections();2939 try wasm.mergeSections();
2873 try wasm.mergeTypes();2940 try wasm.mergeTypes();
2874 try wasm.initializeCallCtorsFunction();2941 try wasm.initializeCallCtorsFunction();
2942 try wasm.initializeTLSFunction();
2875 try wasm.setupExports();2943 try wasm.setupExports();
2876 try wasm.writeToFile(enabled_features, emit_features_count, arena);2944 try wasm.writeToFile(enabled_features, emit_features_count, arena);
28772945
...@@ -2991,6 +3059,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2991,6 +3059,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2991 try wasm.mergeSections();3059 try wasm.mergeSections();
2992 try wasm.mergeTypes();3060 try wasm.mergeTypes();
2993 try wasm.initializeCallCtorsFunction();3061 try wasm.initializeCallCtorsFunction();
3062 try wasm.initializeTLSFunction();
2994 try wasm.setupExports();3063 try wasm.setupExports();
2995 try wasm.writeToFile(enabled_features, emit_features_count, arena);3064 try wasm.writeToFile(enabled_features, emit_features_count, arena);
2996}3065}