diff options
| author | Luuk de Gram <luuk@degram.dev> | 2023-03-15 19:27:55 +0100 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2023-03-18 20:13:30 +0100 |
| commit | 9d13c2257dcae11d9bc69035e55c33a7dda14a2b (patch) | |
| tree | 32e99150347fc950bb16e23b587d07e7f975fa20 /src | |
| parent | ff28c8b60080b24ae7d5e9d485b6aa47e8c8de9c (diff) | |
| download | zig-9d13c2257dcae11d9bc69035e55c33a7dda14a2b.tar.gz zig-9d13c2257dcae11d9bc69035e55c33a7dda14a2b.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Wasm.zig | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index d66facb912..5d4ab2961b 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1990,10 +1990,23 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { try writer.writeByte(std.wasm.opcode(.end)); } - const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?; + try wasm.createSyntheticFunction( + "__wasm_call_ctors", + std.wasm.Type{ .params = &.{}, .returns = &.{} }, + &function_body, + ); +} + +fn createSyntheticFunction( + wasm: *Wasm, + symbol_name: []const u8, + func_ty: std.wasm.Type, + function_body: *std.ArrayList(u8), +) !void { + const loc = wasm.findGlobalSymbol(symbol_name) orelse + try wasm.createSyntheticSymbol(symbol_name, .function); const symbol = loc.getSymbol(wasm); - // create type (() -> nil) as we do not have any parameters or return value. - const ty_index = try wasm.putOrGetFuncType(.{ .params = &[_]std.wasm.Valtype{}, .returns = &[_]std.wasm.Valtype{} }); + const ty_index = try wasm.putOrGetFuncType(func_ty); // create function with above type const func_index = wasm.imported_functions_count + @intCast(u32, wasm.functions.count()); try wasm.functions.putNoClobber( @@ -2025,6 +2038,60 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { atom.offset = prev_atom.offset + prev_atom.size; } +fn initializeTLSFunction(wasm: *Wasm) !void { + if (!wasm.base.options.shared_memory) return; + + var function_body = std.ArrayList(u8).init(wasm.base.allocator); + defer function_body.deinit(); + const writer = function_body.writer(); + + // locals + try writer.writeByte(0); + + // If there's a TLS segment, initialize it during runtime using the bulk-memory feature + if (wasm.data_segments.getIndex(".tdata")) |data_index| { + const segment_index = wasm.data_segments.entries.items(.value)[data_index]; + const segment = wasm.segments.items[segment_index]; + + const param_local: u32 = 0; + + try writer.writeByte(std.wasm.opcode(.local_get)); + try leb.writeULEB128(writer, param_local); + + const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?; + try writer.writeByte(std.wasm.opcode(.global_get)); + try leb.writeULEB128(writer, tls_base_loc.getSymbol(wasm).index); + + // load stack values for the bulk-memory operation + { + try writer.writeByte(std.wasm.opcode(.local_get)); + try leb.writeULEB128(writer, param_local); + + try writer.writeByte(std.wasm.opcode(.i32_const)); + try leb.writeULEB128(writer, @as(u32, 0)); //segment offset + + try writer.writeByte(std.wasm.opcode(.i32_const)); + try leb.writeULEB128(writer, @as(u32, segment.size)); //segment offset + } + + // perform the bulk-memory operation to initialize the data segment + try writer.writeByte(std.wasm.opcode(.prefixed)); + try leb.writeULEB128(writer, @enumToInt(std.wasm.PrefixedOpcode.memory_init)); + // segment immediate + try leb.writeULEB128(writer, @intCast(u32, data_index)); + // memory index immediate (always 0) + try leb.writeULEB128(writer, @as(u32, 0)); + } + + try writer.writeByte(std.wasm.opcode(.end)); + + try wasm.createSyntheticFunction( + "__wasm_init_tls", + std.wasm.Type{ .params = &.{.i32}, .returns = &.{} }, + &function_body, + ); +} + fn setupImports(wasm: *Wasm) !void { log.debug("Merging imports", .{}); var discarded_it = wasm.discarded.keyIterator(); @@ -2872,6 +2939,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l try wasm.mergeSections(); try wasm.mergeTypes(); try wasm.initializeCallCtorsFunction(); + try wasm.initializeTLSFunction(); try wasm.setupExports(); try wasm.writeToFile(enabled_features, emit_features_count, arena); @@ -2991,6 +3059,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod try wasm.mergeSections(); try wasm.mergeTypes(); try wasm.initializeCallCtorsFunction(); + try wasm.initializeTLSFunction(); try wasm.setupExports(); try wasm.writeToFile(enabled_features, emit_features_count, arena); } |
