Commit b0024c4884
Changed files (5)
src
src/link/Wasm/Atom.zig
@@ -126,10 +126,12 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
.R_WASM_TABLE_INDEX_SLEB,
.R_WASM_TABLE_NUMBER_LEB,
.R_WASM_TYPE_INDEX_LEB,
+ .R_WASM_MEMORY_ADDR_TLS_SLEB,
=> leb.writeUnsignedFixed(5, atom.code.items[reloc.offset..][0..5], @intCast(u32, value)),
.R_WASM_MEMORY_ADDR_LEB64,
.R_WASM_MEMORY_ADDR_SLEB64,
.R_WASM_TABLE_INDEX_SLEB64,
+ .R_WASM_MEMORY_ADDR_TLS_SLEB64,
=> leb.writeUnsignedFixed(10, atom.code.items[reloc.offset..][0..10], value),
}
}
@@ -190,5 +192,10 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend;
return @intCast(u32, rel_value);
},
+ .R_WASM_MEMORY_ADDR_TLS_SLEB,
+ .R_WASM_MEMORY_ADDR_TLS_SLEB64,
+ => {
+ @panic("TODO: Implement TLS relocations");
+ },
}
}
src/link/Wasm/Object.zig
@@ -674,6 +674,12 @@ fn Parser(comptime ReaderType: type) type {
segment.alignment,
segment.flags,
});
+
+ // support legacy object files that specified being TLS by the name instead of the TLS flag.
+ if (!segment.isTLS() and (std.mem.startsWith(u8, segment.name, ".tdata") or std.mem.startsWith(u8, segment.name, ".tbss"))) {
+ // set the flag so we can simply check for the flag in the rest of the linker.
+ segment.flags |= @enumToInt(types.Segment.Flags.WASM_SEG_FLAG_TLS);
+ }
}
parser.object.segment_info = segments;
},
src/link/Wasm/Symbol.zig
@@ -90,6 +90,10 @@ pub fn requiresImport(symbol: Symbol) bool {
return true;
}
+pub fn isTLS(symbol: Symbol) bool {
+ return symbol.flags & @enumToInt(Flag.WASM_SYM_TLS) != 0;
+}
+
pub fn hasFlag(symbol: Symbol, flag: Flag) bool {
return symbol.flags & @enumToInt(flag) != 0;
}
src/link/Wasm/types.zig
@@ -38,6 +38,8 @@ pub const Relocation = struct {
R_WASM_TABLE_INDEX_SLEB64 = 18,
R_WASM_TABLE_INDEX_I64 = 19,
R_WASM_TABLE_NUMBER_LEB = 20,
+ R_WASM_MEMORY_ADDR_TLS_SLEB = 21,
+ R_WASM_MEMORY_ADDR_TLS_SLEB64 = 25,
/// Returns true for relocation types where the `addend` field is present.
pub fn addendIsPresent(self: RelocationType) bool {
@@ -125,23 +127,34 @@ pub const Segment = struct {
/// Bitfield containing flags for a segment
flags: u32,
+ pub fn isTLS(segment: Segment) bool {
+ return segment.flags & @enumToInt(Flags.WASM_SEG_FLAG_TLS) != 0;
+ }
+
/// Returns the name as how it will be output into the final object
/// file or binary. When `merge_segments` is true, this will return the
/// short name. i.e. ".rodata". When false, it returns the entire name instead.
- pub fn outputName(self: Segment, merge_segments: bool) []const u8 {
- if (std.mem.startsWith(u8, self.name, ".synthetic")) return ".synthetic"; // always merge
- if (!merge_segments) return self.name;
- if (std.mem.startsWith(u8, self.name, ".rodata.")) {
+ pub fn outputName(segment: Segment, merge_segments: bool) []const u8 {
+ if (segment.isTLS()) {
+ return ".tdata";
+ } else if (!merge_segments) {
+ return segment.name;
+ } else if (std.mem.startsWith(u8, segment.name, ".rodata.")) {
return ".rodata";
- } else if (std.mem.startsWith(u8, self.name, ".text.")) {
+ } else if (std.mem.startsWith(u8, segment.name, ".text.")) {
return ".text";
- } else if (std.mem.startsWith(u8, self.name, ".data.")) {
+ } else if (std.mem.startsWith(u8, segment.name, ".data.")) {
return ".data";
- } else if (std.mem.startsWith(u8, self.name, ".bss.")) {
+ } else if (std.mem.startsWith(u8, segment.name, ".bss.")) {
return ".bss";
}
- return self.name;
+ return segment.name;
}
+
+ pub const Flags = enum(u32) {
+ WASM_SEG_FLAG_STRINGS = 0x1,
+ WASM_SEG_FLAG_TLS = 0x2,
+ };
};
pub const InitFunc = struct {
src/link/Wasm.zig
@@ -894,6 +894,13 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
_ = wasm.resolved_symbols.swapRemove(loc);
}
+
+ if (!wasm.base.options.shared_memory) {
+ if (wasm.undefs.fetchSwapRemove("__tls_base")) |kv| {
+ const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
+ try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
+ }
+ }
}
// Tries to find a global symbol by its name. Returns null when not found,
@@ -2224,6 +2231,18 @@ fn setupMemory(wasm: *Wasm) !void {
while (data_seg_it.next()) |entry| {
const segment = &wasm.segments.items[entry.value_ptr.*];
memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment);
+
+ // set TLS-related symbols
+ if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
+ if (wasm.findGlobalSymbol("__tls_base")) |loc| {
+ const sym = loc.getSymbol(wasm);
+ sym.index = try wasm.globals.append(wasm.base.allocator, wasm.imports.globalCount, .{
+ .global_type = .{ .valtype = .i32_const, .mutable = false },
+ .init = .{ .i32_const = @intCast(i32, memory_ptr) },
+ });
+ }
+ }
+
memory_ptr += segment.size;
segment.offset = offset;
offset += segment.size;