| ... | @@ -139,6 +139,8 @@ archives: std.ArrayListUnmanaged(Archive) = .{}, | ... | @@ -139,6 +139,8 @@ archives: std.ArrayListUnmanaged(Archive) = .{}, |
| 139 | | 139 | |
| 140 | /// A map of global names (read: offset into string table) to their symbol location | 140 | /// A map of global names (read: offset into string table) to their symbol location |
| 141 | globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .{}, | 141 | globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .{}, |
| | 142 | /// The list of GOT symbols and their location |
| | 143 | got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .{}, |
| 142 | /// Maps discarded symbols and their positions to the location of the symbol | 144 | /// Maps discarded symbols and their positions to the location of the symbol |
| 143 | /// it was resolved to | 145 | /// it was resolved to |
| 144 | discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, | 146 | discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, |
| ... | @@ -635,6 +637,15 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { | ... | @@ -635,6 +637,15 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { |
| 635 | return true; | 637 | return true; |
| 636 | } | 638 | } |
| 637 | | 639 | |
| | 640 | fn requiresTLSReloc(wasm: *const Wasm) bool { |
| | 641 | for (wasm.got_symbols.items) |loc| { |
| | 642 | if (loc.getSymbol(wasm).isTLS()) { |
| | 643 | return true; |
| | 644 | } |
| | 645 | } |
| | 646 | return false; |
| | 647 | } |
| | 648 | |
| 638 | fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { | 649 | fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { |
| 639 | const object: Object = wasm.objects.items[object_index]; | 650 | const object: Object = wasm.objects.items[object_index]; |
| 640 | log.debug("Resolving symbols in object: '{s}'", .{object.name}); | 651 | log.debug("Resolving symbols in object: '{s}'", .{object.name}); |
| ... | @@ -813,6 +824,48 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { | ... | @@ -813,6 +824,48 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { |
| 813 | } | 824 | } |
| 814 | } | 825 | } |
| 815 | | 826 | |
| | 827 | fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| | 828 | // When we have TLS GOT entries and shared memory is enabled, |
| | 829 | // we must perform runtime relocations or else we don't create the function. |
| | 830 | if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) { |
| | 831 | return; |
| | 832 | } |
| | 833 | |
| | 834 | // const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs"); |
| | 835 | var function_body = std.ArrayList(u8).init(wasm.base.allocator); |
| | 836 | defer function_body.deinit(); |
| | 837 | const writer = function_body.writer(); |
| | 838 | |
| | 839 | // locals (we have none) |
| | 840 | try writer.writeByte(0); |
| | 841 | for (wasm.got_symbols.items, 0..) |got_loc, got_index| { |
| | 842 | const sym: *Symbol = got_loc.getSymbol(wasm); |
| | 843 | if (!sym.isTLS()) continue; // only relocate TLS symbols |
| | 844 | if (sym.tag == .data and sym.isDefined()) { |
| | 845 | // get __tls_base |
| | 846 | try writer.writeByte(std.wasm.opcode(.global_get)); |
| | 847 | try leb.writeULEB128(writer, wasm.findGlobalSymbol("__tls_base").?.getSymbol(wasm).index); |
| | 848 | |
| | 849 | // add the virtual address of the symbol |
| | 850 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| | 851 | try leb.writeULEB128(writer, sym.virtual_address); |
| | 852 | } else if (sym.tag == .function) { |
| | 853 | @panic("TODO: relocate GOT entry of function"); |
| | 854 | } else continue; |
| | 855 | |
| | 856 | try writer.writeByte(std.wasm.opcode(.i32_add)); |
| | 857 | try writer.writeByte(std.wasm.opcode(.global_set)); |
| | 858 | try leb.writeULEB128(writer, wasm.imported_globals_count + @intCast(u32, wasm.wasm_globals.items.len + got_index)); |
| | 859 | } |
| | 860 | try writer.writeByte(std.wasm.opcode(.end)); |
| | 861 | |
| | 862 | try wasm.createSyntheticFunction( |
| | 863 | "__wasm_apply_global_tls_relocs", |
| | 864 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, |
| | 865 | &function_body, |
| | 866 | ); |
| | 867 | } |
| | 868 | |
| 816 | fn validateFeatures( | 869 | fn validateFeatures( |
| 817 | wasm: *const Wasm, | 870 | wasm: *const Wasm, |
| 818 | to_emit: *[@typeInfo(types.Feature.Tag).Enum.fields.len]bool, | 871 | to_emit: *[@typeInfo(types.Feature.Tag).Enum.fields.len]bool, |
| ... | @@ -2083,6 +2136,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void { | ... | @@ -2083,6 +2136,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2083 | try leb.writeULEB128(writer, @as(u32, 0)); | 2136 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 2084 | } | 2137 | } |
| 2085 | | 2138 | |
| | 2139 | // If we have to perform any TLS relocations, call the corresponding function |
| | 2140 | // which performs all runtime TLS relocations. This is a synthetic function, |
| | 2141 | // generated by the linker. |
| | 2142 | if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| { |
| | 2143 | try writer.writeByte(std.wasm.opcode(.call)); |
| | 2144 | try leb.writeULEB128(writer, loc.getSymbol(wasm).index); |
| | 2145 | } |
| | 2146 | |
| 2086 | try writer.writeByte(std.wasm.opcode(.end)); | 2147 | try writer.writeByte(std.wasm.opcode(.end)); |
| 2087 | | 2148 | |
| 2088 | try wasm.createSyntheticFunction( | 2149 | try wasm.createSyntheticFunction( |
| ... | @@ -2939,6 +3000,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -2939,6 +3000,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2939 | try wasm.mergeSections(); | 3000 | try wasm.mergeSections(); |
| 2940 | try wasm.mergeTypes(); | 3001 | try wasm.mergeTypes(); |
| 2941 | try wasm.initializeCallCtorsFunction(); | 3002 | try wasm.initializeCallCtorsFunction(); |
| | 3003 | try wasm.setupTLSRelocationsFunction(); |
| 2942 | try wasm.initializeTLSFunction(); | 3004 | try wasm.initializeTLSFunction(); |
| 2943 | try wasm.setupExports(); | 3005 | try wasm.setupExports(); |
| 2944 | try wasm.writeToFile(enabled_features, emit_features_count, arena); | 3006 | try wasm.writeToFile(enabled_features, emit_features_count, arena); |
| ... | @@ -3059,6 +3121,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -3059,6 +3121,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3059 | try wasm.mergeSections(); | 3121 | try wasm.mergeSections(); |
| 3060 | try wasm.mergeTypes(); | 3122 | try wasm.mergeTypes(); |
| 3061 | try wasm.initializeCallCtorsFunction(); | 3123 | try wasm.initializeCallCtorsFunction(); |
| | 3124 | try wasm.setupTLSRelocationsFunction(); |
| 3062 | try wasm.initializeTLSFunction(); | 3125 | try wasm.initializeTLSFunction(); |
| 3063 | try wasm.setupExports(); | 3126 | try wasm.setupExports(); |
| 3064 | try wasm.writeToFile(enabled_features, emit_features_count, arena); | 3127 | try wasm.writeToFile(enabled_features, emit_features_count, arena); |