aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2023-03-15 19:27:55 +0100
committerLuuk de Gram <luuk@degram.dev>2023-03-18 20:13:30 +0100
commit9d13c2257dcae11d9bc69035e55c33a7dda14a2b (patch)
tree32e99150347fc950bb16e23b587d07e7f975fa20 /src
parentff28c8b60080b24ae7d5e9d485b6aa47e8c8de9c (diff)
downloadzig-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.zig75
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);
}