mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 15:42:49 +00:00
wasm-linker: create TLS Wasm globals correctly
Previously, they were only created when we had any TLS segment. This meant that while the symbol existed, the global itself wouldn't. The result of this was a crash during symbol names writing as it would attempt to write the symbol name of a global that didn't exist. Now we always create them, and instead update its `init` value during `setupMemory`. In the future, the entire symbol (and global) will be removed by the garbage collector.
This commit is contained in:
parent
1a3304ed23
commit
142dbc7b82
@ -410,7 +410,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
|
||||
},
|
||||
);
|
||||
} else {
|
||||
symbol.index = @as(u32, @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len));
|
||||
symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
const global = try wasm_bin.wasm_globals.addOne(allocator);
|
||||
global.* = .{
|
||||
@ -433,7 +433,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
|
||||
};
|
||||
if (options.output_mode == .Obj or options.import_table) {
|
||||
symbol.setUndefined(true);
|
||||
symbol.index = @as(u32, @intCast(wasm_bin.imported_tables_count));
|
||||
symbol.index = @intCast(wasm_bin.imported_tables_count);
|
||||
wasm_bin.imported_tables_count += 1;
|
||||
try wasm_bin.imports.put(allocator, loc, .{
|
||||
.module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name),
|
||||
@ -467,16 +467,31 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
|
||||
const loc = try wasm_bin.createSyntheticSymbol("__tls_base", .global);
|
||||
const symbol = loc.getSymbol(wasm_bin);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
|
||||
try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{
|
||||
.global_type = .{ .valtype = .i32, .mutable = true },
|
||||
.init = .{ .i32_const = undefined },
|
||||
});
|
||||
}
|
||||
{
|
||||
const loc = try wasm_bin.createSyntheticSymbol("__tls_size", .global);
|
||||
const symbol = loc.getSymbol(wasm_bin);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
|
||||
try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{
|
||||
.global_type = .{ .valtype = .i32, .mutable = false },
|
||||
.init = .{ .i32_const = undefined },
|
||||
});
|
||||
}
|
||||
{
|
||||
const loc = try wasm_bin.createSyntheticSymbol("__tls_align", .global);
|
||||
const symbol = loc.getSymbol(wasm_bin);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
|
||||
try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{
|
||||
.global_type = .{ .valtype = .i32, .mutable = false },
|
||||
.init = .{ .i32_const = undefined },
|
||||
});
|
||||
}
|
||||
{
|
||||
const loc = try wasm_bin.createSyntheticSymbol("__wasm_init_tls", .function);
|
||||
@ -2757,27 +2772,18 @@ fn setupMemory(wasm: *Wasm) !void {
|
||||
if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
|
||||
if (wasm.findGlobalSymbol("__tls_size")) |loc| {
|
||||
const sym = loc.getSymbol(wasm);
|
||||
sym.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;
|
||||
try wasm.wasm_globals.append(wasm.base.allocator, .{
|
||||
.global_type = .{ .valtype = .i32, .mutable = false },
|
||||
.init = .{ .i32_const = @as(i32, @intCast(segment.size)) },
|
||||
});
|
||||
wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size);
|
||||
}
|
||||
if (wasm.findGlobalSymbol("__tls_align")) |loc| {
|
||||
const sym = loc.getSymbol(wasm);
|
||||
sym.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;
|
||||
try wasm.wasm_globals.append(wasm.base.allocator, .{
|
||||
.global_type = .{ .valtype = .i32, .mutable = false },
|
||||
.init = .{ .i32_const = @as(i32, @intCast(segment.alignment)) },
|
||||
});
|
||||
wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment);
|
||||
}
|
||||
if (wasm.findGlobalSymbol("__tls_base")) |loc| {
|
||||
const sym = loc.getSymbol(wasm);
|
||||
sym.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;
|
||||
try wasm.wasm_globals.append(wasm.base.allocator, .{
|
||||
.global_type = .{ .valtype = .i32, .mutable = wasm.base.options.shared_memory },
|
||||
.init = .{ .i32_const = if (wasm.base.options.shared_memory) @as(u32, 0) else @as(i32, @intCast(memory_ptr)) },
|
||||
});
|
||||
wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (wasm.base.options.shared_memory)
|
||||
@as(i32, 0)
|
||||
else
|
||||
@as(i32, @intCast(memory_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,9 @@ pub fn build(b: *std.Build) void {
|
||||
b.default_step = test_step;
|
||||
|
||||
add(b, test_step, .Debug);
|
||||
|
||||
// Enable the following build modes once garbage-collection is implemented properly.
|
||||
// add(b, test_step, .ReleaseFast);
|
||||
// add(b, test_step, .ReleaseSmall);
|
||||
// add(b, test_step, .ReleaseSafe);
|
||||
add(b, test_step, .ReleaseFast);
|
||||
add(b, test_step, .ReleaseSmall);
|
||||
add(b, test_step, .ReleaseSafe);
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode) void {
|
||||
@ -47,30 +45,53 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
|
||||
|
||||
// This section *must* be emit as the start function is set to the index
|
||||
// of __wasm_init_memory
|
||||
check_lib.checkStart("Section start");
|
||||
// release modes will have the TLS segment optimized out in our test-case.
|
||||
// This means we won't have __wasm_init_memory in such case, and therefore
|
||||
// should also not have a section "start"
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkStart("Section start");
|
||||
}
|
||||
|
||||
// This section is only and *must* be emit when shared-memory is enabled
|
||||
check_lib.checkStart("Section data_count");
|
||||
check_lib.checkNext("count 3");
|
||||
// release modes will have the TLS segment optimized out in our test-case.
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkStart("Section data_count");
|
||||
check_lib.checkNext("count 3");
|
||||
}
|
||||
|
||||
check_lib.checkStart("Section custom");
|
||||
check_lib.checkNext("name name");
|
||||
check_lib.checkNext("type function");
|
||||
check_lib.checkNext("name __wasm_init_memory");
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("name __wasm_init_memory");
|
||||
}
|
||||
check_lib.checkNext("name __wasm_init_tls");
|
||||
check_lib.checkNext("type global");
|
||||
check_lib.checkNext("name __tls_size");
|
||||
check_lib.checkNext("name __tls_align");
|
||||
check_lib.checkNext("name __tls_base");
|
||||
|
||||
// In debug mode the symbol __tls_base is resolved to an undefined symbol
|
||||
// from the object file, hence its placement differs than in release modes
|
||||
// where the entire tls segment is optimized away, and tls_base will have
|
||||
// its original position.
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("name __tls_size");
|
||||
check_lib.checkNext("name __tls_align");
|
||||
check_lib.checkNext("name __tls_base");
|
||||
} else {
|
||||
check_lib.checkNext("name __tls_base");
|
||||
check_lib.checkNext("name __tls_size");
|
||||
check_lib.checkNext("name __tls_align");
|
||||
}
|
||||
|
||||
check_lib.checkNext("type data_segment");
|
||||
check_lib.checkNext("names 3");
|
||||
check_lib.checkNext("index 0");
|
||||
check_lib.checkNext("name .rodata");
|
||||
check_lib.checkNext("index 1");
|
||||
check_lib.checkNext("name .bss");
|
||||
check_lib.checkNext("index 2");
|
||||
check_lib.checkNext("name .tdata");
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("names 3");
|
||||
check_lib.checkNext("index 0");
|
||||
check_lib.checkNext("name .rodata");
|
||||
check_lib.checkNext("index 1");
|
||||
check_lib.checkNext("name .bss");
|
||||
check_lib.checkNext("index 2");
|
||||
check_lib.checkNext("name .tdata");
|
||||
}
|
||||
|
||||
test_step.dependOn(&check_lib.step);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user