| author | |
| committer | |
| log | b0024c48841b78a962918cd4ab20459ba6451050 |
| tree | 55a213e4ee740d77306ae1c4ac769bb6f1a586c9 |
| parent | 49d37e2d179948f526f500043c6ea9ae324e9476 |
| signature |
Linker now parses segments with regards to TLS segments. If the name
represents a TLS segment but does not contain the TLS flag, we set it
manually as the object file is created using an older compiler (LLVM).
For now we panic when we find a TLS relocation and implement those
later.5 files changed, 57 insertions(+), 8 deletions(-)
src/link/Wasm.zig+19| ... | @@ -894,6 +894,13 @@ fn resolveLazySymbols(wasm: *Wasm) !void { | ... | @@ -894,6 +894,13 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 894 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | 894 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); |
| 895 | _ = wasm.resolved_symbols.swapRemove(loc); | 895 | _ = wasm.resolved_symbols.swapRemove(loc); |
| 896 | } | 896 | } |
| 897 | |||
| 898 | if (!wasm.base.options.shared_memory) { | ||
| 899 | if (wasm.undefs.fetchSwapRemove("__tls_base")) |kv| { | ||
| 900 | const loc = try wasm.createSyntheticSymbol("__tls_base", .global); | ||
| 901 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | ||
| 902 | } | ||
| 903 | } | ||
| 897 | } | 904 | } |
| 898 | 905 | ||
| 899 | // Tries to find a global symbol by its name. Returns null when not found, | 906 | // Tries to find a global symbol by its name. Returns null when not found, |
| ... | @@ -2224,6 +2231,18 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2224,6 +2231,18 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2224 | while (data_seg_it.next()) |entry| { | 2231 | while (data_seg_it.next()) |entry| { |
| 2225 | const segment = &wasm.segments.items[entry.value_ptr.*]; | 2232 | const segment = &wasm.segments.items[entry.value_ptr.*]; |
| 2226 | memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment); | 2233 | memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment); |
| 2234 | |||
| 2235 | // set TLS-related symbols | ||
| 2236 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { | ||
| 2237 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { | ||
| 2238 | const sym = loc.getSymbol(wasm); | ||
| 2239 | sym.index = try wasm.globals.append(wasm.base.allocator, wasm.imports.globalCount, .{ | ||
| 2240 | .global_type = .{ .valtype = .i32_const, .mutable = false }, | ||
| 2241 | .init = .{ .i32_const = @intCast(i32, memory_ptr) }, | ||
| 2242 | }); | ||
| 2243 | } | ||
| 2244 | } | ||
| 2245 | |||
| 2227 | memory_ptr += segment.size; | 2246 | memory_ptr += segment.size; |
| 2228 | segment.offset = offset; | 2247 | segment.offset = offset; |
| 2229 | offset += segment.size; | 2248 | offset += segment.size; |
src/link/Wasm/Atom.zig+7| ... | @@ -126,10 +126,12 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void { | ... | @@ -126,10 +126,12 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void { |
| 126 | .R_WASM_TABLE_INDEX_SLEB, | 126 | .R_WASM_TABLE_INDEX_SLEB, |
| 127 | .R_WASM_TABLE_NUMBER_LEB, | 127 | .R_WASM_TABLE_NUMBER_LEB, |
| 128 | .R_WASM_TYPE_INDEX_LEB, | 128 | .R_WASM_TYPE_INDEX_LEB, |
| 129 | .R_WASM_MEMORY_ADDR_TLS_SLEB, | ||
| 129 | => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset..][0..5], @intCast(u32, value)), | 130 | => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset..][0..5], @intCast(u32, value)), |
| 130 | .R_WASM_MEMORY_ADDR_LEB64, | 131 | .R_WASM_MEMORY_ADDR_LEB64, |
| 131 | .R_WASM_MEMORY_ADDR_SLEB64, | 132 | .R_WASM_MEMORY_ADDR_SLEB64, |
| 132 | .R_WASM_TABLE_INDEX_SLEB64, | 133 | .R_WASM_TABLE_INDEX_SLEB64, |
| 134 | .R_WASM_MEMORY_ADDR_TLS_SLEB64, | ||
| 133 | => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset..][0..10], value), | 135 | => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset..][0..10], value), |
| 134 | } | 136 | } |
| 135 | } | 137 | } |
| ... | @@ -190,5 +192,10 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa | ... | @@ -190,5 +192,10 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa |
| 190 | const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend; | 192 | const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend; |
| 191 | return @intCast(u32, rel_value); | 193 | return @intCast(u32, rel_value); |
| 192 | }, | 194 | }, |
| 195 | .R_WASM_MEMORY_ADDR_TLS_SLEB, | ||
| 196 | .R_WASM_MEMORY_ADDR_TLS_SLEB64, | ||
| 197 | => { | ||
| 198 | @panic("TODO: Implement TLS relocations"); | ||
| 199 | }, | ||
| 193 | } | 200 | } |
| 194 | } | 201 | } |
src/link/Wasm/Object.zig+6| ... | @@ -674,6 +674,12 @@ fn Parser(comptime ReaderType: type) type { | ... | @@ -674,6 +674,12 @@ fn Parser(comptime ReaderType: type) type { |
| 674 | segment.alignment, | 674 | segment.alignment, |
| 675 | segment.flags, | 675 | segment.flags, |
| 676 | }); | 676 | }); |
| 677 | |||
| 678 | // support legacy object files that specified being TLS by the name instead of the TLS flag. | ||
| 679 | if (!segment.isTLS() and (std.mem.startsWith(u8, segment.name, ".tdata") or std.mem.startsWith(u8, segment.name, ".tbss"))) { | ||
| 680 | // set the flag so we can simply check for the flag in the rest of the linker. | ||
| 681 | segment.flags |= @enumToInt(types.Segment.Flags.WASM_SEG_FLAG_TLS); | ||
| 682 | } | ||
| 677 | } | 683 | } |
| 678 | parser.object.segment_info = segments; | 684 | parser.object.segment_info = segments; |
| 679 | }, | 685 | }, |
src/link/Wasm/Symbol.zig+4| ... | @@ -90,6 +90,10 @@ pub fn requiresImport(symbol: Symbol) bool { | ... | @@ -90,6 +90,10 @@ pub fn requiresImport(symbol: Symbol) bool { |
| 90 | return true; | 90 | return true; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | pub fn isTLS(symbol: Symbol) bool { | ||
| 94 | return symbol.flags & @enumToInt(Flag.WASM_SYM_TLS) != 0; | ||
| 95 | } | ||
| 96 | |||
| 93 | pub fn hasFlag(symbol: Symbol, flag: Flag) bool { | 97 | pub fn hasFlag(symbol: Symbol, flag: Flag) bool { |
| 94 | return symbol.flags & @enumToInt(flag) != 0; | 98 | return symbol.flags & @enumToInt(flag) != 0; |
| 95 | } | 99 | } |
src/link/Wasm/types.zig+21-8| ... | @@ -38,6 +38,8 @@ pub const Relocation = struct { | ... | @@ -38,6 +38,8 @@ pub const Relocation = struct { |
| 38 | R_WASM_TABLE_INDEX_SLEB64 = 18, | 38 | R_WASM_TABLE_INDEX_SLEB64 = 18, |
| 39 | R_WASM_TABLE_INDEX_I64 = 19, | 39 | R_WASM_TABLE_INDEX_I64 = 19, |
| 40 | R_WASM_TABLE_NUMBER_LEB = 20, | 40 | R_WASM_TABLE_NUMBER_LEB = 20, |
| 41 | R_WASM_MEMORY_ADDR_TLS_SLEB = 21, | ||
| 42 | R_WASM_MEMORY_ADDR_TLS_SLEB64 = 25, | ||
| 41 | 43 | ||
| 42 | /// Returns true for relocation types where the `addend` field is present. | 44 | /// Returns true for relocation types where the `addend` field is present. |
| 43 | pub fn addendIsPresent(self: RelocationType) bool { | 45 | pub fn addendIsPresent(self: RelocationType) bool { |
| ... | @@ -125,23 +127,34 @@ pub const Segment = struct { | ... | @@ -125,23 +127,34 @@ pub const Segment = struct { |
| 125 | /// Bitfield containing flags for a segment | 127 | /// Bitfield containing flags for a segment |
| 126 | flags: u32, | 128 | flags: u32, |
| 127 | 129 | ||
| 130 | pub fn isTLS(segment: Segment) bool { | ||
| 131 | return segment.flags & @enumToInt(Flags.WASM_SEG_FLAG_TLS) != 0; | ||
| 132 | } | ||
| 133 | |||
| 128 | /// Returns the name as how it will be output into the final object | 134 | /// Returns the name as how it will be output into the final object |
| 129 | /// file or binary. When `merge_segments` is true, this will return the | 135 | /// file or binary. When `merge_segments` is true, this will return the |
| 130 | /// short name. i.e. ".rodata". When false, it returns the entire name instead. | 136 | /// short name. i.e. ".rodata". When false, it returns the entire name instead. |
| 131 | pub fn outputName(self: Segment, merge_segments: bool) []const u8 { | 137 | pub fn outputName(segment: Segment, merge_segments: bool) []const u8 { |
| 132 | if (std.mem.startsWith(u8, self.name, ".synthetic")) return ".synthetic"; // always merge | 138 | if (segment.isTLS()) { |
| 133 | if (!merge_segments) return self.name; | 139 | return ".tdata"; |
| 134 | if (std.mem.startsWith(u8, self.name, ".rodata.")) { | 140 | } else if (!merge_segments) { |
| 141 | return segment.name; | ||
| 142 | } else if (std.mem.startsWith(u8, segment.name, ".rodata.")) { | ||
| 135 | return ".rodata"; | 143 | return ".rodata"; |
| 136 | } else if (std.mem.startsWith(u8, self.name, ".text.")) { | 144 | } else if (std.mem.startsWith(u8, segment.name, ".text.")) { |
| 137 | return ".text"; | 145 | return ".text"; |
| 138 | } else if (std.mem.startsWith(u8, self.name, ".data.")) { | 146 | } else if (std.mem.startsWith(u8, segment.name, ".data.")) { |
| 139 | return ".data"; | 147 | return ".data"; |
| 140 | } else if (std.mem.startsWith(u8, self.name, ".bss.")) { | 148 | } else if (std.mem.startsWith(u8, segment.name, ".bss.")) { |
| 141 | return ".bss"; | 149 | return ".bss"; |
| 142 | } | 150 | } |
| 143 | return self.name; | 151 | return segment.name; |
| 144 | } | 152 | } |
| 153 | |||
| 154 | pub const Flags = enum(u32) { | ||
| 155 | WASM_SEG_FLAG_STRINGS = 0x1, | ||
| 156 | WASM_SEG_FLAG_TLS = 0x2, | ||
| 157 | }; | ||
| 145 | }; | 158 | }; |
| 146 | 159 | ||
| 147 | pub const InitFunc = struct { | 160 | pub const InitFunc = struct { |