| ... | @@ -468,6 +468,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol | ... | @@ -468,6 +468,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol |
| 468 | .flags = 0, | 468 | .flags = 0, |
| 469 | .tag = tag, | 469 | .tag = tag, |
| 470 | .index = undefined, | 470 | .index = undefined, |
| | 471 | .virtual_address = undefined, |
| 471 | }); | 472 | }); |
| 472 | try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, loc, {}); | 473 | try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, loc, {}); |
| 473 | try wasm.globals.put(wasm.base.allocator, name_offset, loc); | 474 | try wasm.globals.put(wasm.base.allocator, name_offset, loc); |
| ... | @@ -886,32 +887,12 @@ fn resolveLazySymbols(wasm: *Wasm) !void { | ... | @@ -886,32 +887,12 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 886 | const loc = try wasm.createSyntheticSymbol("__heap_base", .data); | 887 | const loc = try wasm.createSyntheticSymbol("__heap_base", .data); |
| 887 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | 888 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); |
| 888 | _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations. | 889 | _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations. |
| 889 | | | |
| 890 | // TODO: Can we use `createAtom` here while also re-using the symbol | | |
| 891 | // from `createSyntheticSymbol`. | | |
| 892 | const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len); | | |
| 893 | const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); | | |
| 894 | atom.* = Atom.empty; | | |
| 895 | atom.sym_index = loc.index; | | |
| 896 | atom.alignment = 1; | | |
| 897 | | | |
| 898 | try wasm.parseAtom(atom_index, .{ .data = .synthetic }); | | |
| 899 | try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); | | |
| 900 | } | 890 | } |
| 901 | | 891 | |
| 902 | if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| { | 892 | if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| { |
| 903 | const loc = try wasm.createSyntheticSymbol("__heap_end", .data); | 893 | const loc = try wasm.createSyntheticSymbol("__heap_end", .data); |
| 904 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | 894 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); |
| 905 | _ = wasm.resolved_symbols.swapRemove(loc); | 895 | _ = wasm.resolved_symbols.swapRemove(loc); |
| 906 | | | |
| 907 | const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len); | | |
| 908 | const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); | | |
| 909 | atom.* = Atom.empty; | | |
| 910 | atom.sym_index = loc.index; | | |
| 911 | atom.alignment = 1; | | |
| 912 | | | |
| 913 | try wasm.parseAtom(atom_index, .{ .data = .synthetic }); | | |
| 914 | try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); | | |
| 915 | } | 896 | } |
| 916 | } | 897 | } |
| 917 | | 898 | |
| ... | @@ -1011,6 +992,7 @@ pub fn allocateSymbol(wasm: *Wasm) !u32 { | ... | @@ -1011,6 +992,7 @@ pub fn allocateSymbol(wasm: *Wasm) !u32 { |
| 1011 | .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), | 992 | .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 1012 | .tag = undefined, // will be set after updateDecl | 993 | .tag = undefined, // will be set after updateDecl |
| 1013 | .index = undefined, // will be set after updateDecl | 994 | .index = undefined, // will be set after updateDecl |
| | 995 | .virtual_address = undefined, // will be set during atom allocation |
| 1014 | }; | 996 | }; |
| 1015 | if (wasm.symbols_free_list.popOrNull()) |index| { | 997 | if (wasm.symbols_free_list.popOrNull()) |index| { |
| 1016 | wasm.symbols.items[index] = symbol; | 998 | wasm.symbols.items[index] = symbol; |
| ... | @@ -1246,6 +1228,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1246,6 +1228,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1246 | .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), | 1228 | .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 1247 | .tag = .data, | 1229 | .tag = .data, |
| 1248 | .index = undefined, | 1230 | .index = undefined, |
| | 1231 | .virtual_address = undefined, |
| 1249 | }; | 1232 | }; |
| 1250 | try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {}); | 1233 | try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {}); |
| 1251 | | 1234 | |
| ... | @@ -1292,6 +1275,7 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8) !u32 { | ... | @@ -1292,6 +1275,7 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8) !u32 { |
| 1292 | .flags = 0, | 1275 | .flags = 0, |
| 1293 | .index = undefined, // index to type will be set after merging function symbols | 1276 | .index = undefined, // index to type will be set after merging function symbols |
| 1294 | .tag = .function, | 1277 | .tag = .function, |
| | 1278 | .virtual_address = undefined, |
| 1295 | }; | 1279 | }; |
| 1296 | symbol.setGlobal(true); | 1280 | symbol.setGlobal(true); |
| 1297 | symbol.setUndefined(true); | 1281 | symbol.setUndefined(true); |
| ... | @@ -1610,7 +1594,6 @@ const Kind = union(enum) { | ... | @@ -1610,7 +1594,6 @@ const Kind = union(enum) { |
| 1610 | read_only, | 1594 | read_only, |
| 1611 | uninitialized, | 1595 | uninitialized, |
| 1612 | initialized, | 1596 | initialized, |
| 1613 | synthetic, | | |
| 1614 | }, | 1597 | }, |
| 1615 | function: void, | 1598 | function: void, |
| 1616 | | 1599 | |
| ... | @@ -1621,7 +1604,6 @@ const Kind = union(enum) { | ... | @@ -1621,7 +1604,6 @@ const Kind = union(enum) { |
| 1621 | .read_only => return ".rodata.", | 1604 | .read_only => return ".rodata.", |
| 1622 | .uninitialized => return ".bss.", | 1605 | .uninitialized => return ".bss.", |
| 1623 | .initialized => return ".data.", | 1606 | .initialized => return ".data.", |
| 1624 | .synthetic => return ".synthetic", | | |
| 1625 | } | 1607 | } |
| 1626 | } | 1608 | } |
| 1627 | }; | 1609 | }; |
| ... | @@ -1788,6 +1770,30 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -1788,6 +1770,30 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 1788 | } | 1770 | } |
| 1789 | } | 1771 | } |
| 1790 | | 1772 | |
| | 1773 | /// For each data symbol, sets the virtual address. |
| | 1774 | fn allocateVirtualAddresses(wasm: *Wasm) void { |
| | 1775 | for (wasm.resolved_symbols.keys()) |loc| { |
| | 1776 | const symbol = loc.getSymbol(wasm); |
| | 1777 | if (symbol.tag != .data) { |
| | 1778 | continue; // only data symbols have virtual addresses |
| | 1779 | } |
| | 1780 | const atom_index = wasm.symbol_atom.get(loc) orelse { |
| | 1781 | // synthetic symbol that does not contain an atom |
| | 1782 | continue; |
| | 1783 | }; |
| | 1784 | |
| | 1785 | const atom = wasm.getAtom(atom_index); |
| | 1786 | const merge_segment = wasm.base.options.output_mode != .Obj; |
| | 1787 | const segment_info = if (atom.file) |object_index| blk: { |
| | 1788 | break :blk wasm.objects.items[object_index].segment_info; |
| | 1789 | } else wasm.segment_info.values(); |
| | 1790 | const segment_name = segment_info[symbol.index].outputName(merge_segment); |
| | 1791 | const segment_index = wasm.data_segments.get(segment_name).?; |
| | 1792 | const segment = wasm.segments.items[segment_index]; |
| | 1793 | symbol.virtual_address = atom.offset + segment.offset; |
| | 1794 | } |
| | 1795 | } |
| | 1796 | |
| 1791 | fn sortDataSegments(wasm: *Wasm) !void { | 1797 | fn sortDataSegments(wasm: *Wasm) !void { |
| 1792 | var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{}; | 1798 | var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{}; |
| 1793 | try new_mapping.ensureUnusedCapacity(wasm.base.allocator, wasm.data_segments.count()); | 1799 | try new_mapping.ensureUnusedCapacity(wasm.base.allocator, wasm.data_segments.count()); |
| ... | @@ -1805,7 +1811,6 @@ fn sortDataSegments(wasm: *Wasm) !void { | ... | @@ -1805,7 +1811,6 @@ fn sortDataSegments(wasm: *Wasm) !void { |
| 1805 | if (mem.startsWith(u8, name, ".rodata")) return 0; | 1811 | if (mem.startsWith(u8, name, ".rodata")) return 0; |
| 1806 | if (mem.startsWith(u8, name, ".data")) return 1; | 1812 | if (mem.startsWith(u8, name, ".data")) return 1; |
| 1807 | if (mem.startsWith(u8, name, ".text")) return 2; | 1813 | if (mem.startsWith(u8, name, ".text")) return 2; |
| 1808 | if (mem.startsWith(u8, name, ".synthetic")) return 100; // always at end | | |
| 1809 | return 3; | 1814 | return 3; |
| 1810 | } | 1815 | } |
| 1811 | }; | 1816 | }; |
| ... | @@ -2137,13 +2142,10 @@ fn setupExports(wasm: *Wasm) !void { | ... | @@ -2137,13 +2142,10 @@ fn setupExports(wasm: *Wasm) !void { |
| 2137 | break :blk try wasm.string_table.put(wasm.base.allocator, sym_name); | 2142 | break :blk try wasm.string_table.put(wasm.base.allocator, sym_name); |
| 2138 | }; | 2143 | }; |
| 2139 | const exp: types.Export = if (symbol.tag == .data) exp: { | 2144 | const exp: types.Export = if (symbol.tag == .data) exp: { |
| 2140 | const atom_index = wasm.symbol_atom.get(sym_loc).?; | | |
| 2141 | const atom = wasm.getAtom(atom_index); | | |
| 2142 | const va = atom.getVA(wasm, symbol); | | |
| 2143 | const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len); | 2145 | const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| 2144 | try wasm.wasm_globals.append(wasm.base.allocator, .{ | 2146 | try wasm.wasm_globals.append(wasm.base.allocator, .{ |
| 2145 | .global_type = .{ .valtype = .i32, .mutable = false }, | 2147 | .global_type = .{ .valtype = .i32, .mutable = false }, |
| 2146 | .init = .{ .i32_const = @intCast(i32, va) }, | 2148 | .init = .{ .i32_const = @intCast(i32, symbol.virtual_address) }, |
| 2147 | }); | 2149 | }); |
| 2148 | break :exp .{ | 2150 | break :exp .{ |
| 2149 | .name = export_name, | 2151 | .name = export_name, |
| ... | @@ -2220,10 +2222,6 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2220,10 +2222,6 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2220 | var offset: u32 = @intCast(u32, memory_ptr); | 2222 | var offset: u32 = @intCast(u32, memory_ptr); |
| 2221 | var data_seg_it = wasm.data_segments.iterator(); | 2223 | var data_seg_it = wasm.data_segments.iterator(); |
| 2222 | while (data_seg_it.next()) |entry| { | 2224 | while (data_seg_it.next()) |entry| { |
| 2223 | if (mem.eql(u8, entry.key_ptr.*, ".synthetic")) { | | |
| 2224 | // do not update synthetic segments as they are not part of the output | | |
| 2225 | continue; | | |
| 2226 | } | | |
| 2227 | const segment = &wasm.segments.items[entry.value_ptr.*]; | 2225 | const segment = &wasm.segments.items[entry.value_ptr.*]; |
| 2228 | memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment); | 2226 | memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment); |
| 2229 | memory_ptr += segment.size; | 2227 | memory_ptr += segment.size; |
| ... | @@ -2240,12 +2238,8 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2240,12 +2238,8 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2240 | // One of the linked object files has a reference to the __heap_base symbol. | 2238 | // One of the linked object files has a reference to the __heap_base symbol. |
| 2241 | // We must set its virtual address so it can be used in relocations. | 2239 | // We must set its virtual address so it can be used in relocations. |
| 2242 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { | 2240 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { |
| 2243 | const segment_index = wasm.data_segments.get(".synthetic").?; | 2241 | const symbol = loc.getSymbol(wasm); |
| 2244 | const segment = &wasm.segments.items[segment_index]; | 2242 | symbol.virtual_address = @intCast(u32, mem.alignForwardGeneric(u64, memory_ptr, heap_alignment)); |
| 2245 | segment.offset = 0; // for simplicity we store the entire VA into atom's offset. | | |
| 2246 | const atom_index = wasm.symbol_atom.get(loc).?; | | |
| 2247 | const atom = wasm.getAtomPtr(atom_index); | | |
| 2248 | atom.offset = @intCast(u32, mem.alignForwardGeneric(u64, memory_ptr, heap_alignment)); | | |
| 2249 | } | 2243 | } |
| 2250 | | 2244 | |
| 2251 | // Setup the max amount of pages | 2245 | // Setup the max amount of pages |
| ... | @@ -2274,12 +2268,8 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2274,12 +2268,8 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2274 | log.debug("Total memory pages: {d}", .{wasm.memories.limits.min}); | 2268 | log.debug("Total memory pages: {d}", .{wasm.memories.limits.min}); |
| 2275 | | 2269 | |
| 2276 | if (wasm.findGlobalSymbol("__heap_end")) |loc| { | 2270 | if (wasm.findGlobalSymbol("__heap_end")) |loc| { |
| 2277 | const segment_index = wasm.data_segments.get(".synthetic").?; | 2271 | const symbol = loc.getSymbol(wasm); |
| 2278 | const segment = &wasm.segments.items[segment_index]; | 2272 | symbol.virtual_address = @intCast(u32, memory_ptr); |
| 2279 | segment.offset = 0; | | |
| 2280 | const atom_index = wasm.symbol_atom.get(loc).?; | | |
| 2281 | const atom = wasm.getAtomPtr(atom_index); | | |
| 2282 | atom.offset = @intCast(u32, memory_ptr); | | |
| 2283 | } | 2273 | } |
| 2284 | | 2274 | |
| 2285 | if (wasm.base.options.max_memory) |max_memory| { | 2275 | if (wasm.base.options.max_memory) |max_memory| { |
| ... | @@ -2417,6 +2407,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { | ... | @@ -2417,6 +2407,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { |
| 2417 | .tag = .data, | 2407 | .tag = .data, |
| 2418 | .flags = 0, | 2408 | .flags = 0, |
| 2419 | .index = 0, | 2409 | .index = 0, |
| | 2410 | .virtual_address = undefined, |
| 2420 | }; | 2411 | }; |
| 2421 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 2412 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 2422 | | 2413 | |
| ... | @@ -2449,6 +2440,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { | ... | @@ -2449,6 +2440,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { |
| 2449 | .tag = .data, | 2440 | .tag = .data, |
| 2450 | .flags = 0, | 2441 | .flags = 0, |
| 2451 | .index = 0, | 2442 | .index = 0, |
| | 2443 | .virtual_address = undefined, |
| 2452 | }; | 2444 | }; |
| 2453 | names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 2445 | names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 2454 | | 2446 | |
| ... | @@ -2749,6 +2741,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -2749,6 +2741,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2749 | | 2741 | |
| 2750 | try wasm.allocateAtoms(); | 2742 | try wasm.allocateAtoms(); |
| 2751 | try wasm.setupMemory(); | 2743 | try wasm.setupMemory(); |
| | 2744 | wasm.allocateVirtualAddresses(); |
| 2752 | wasm.mapFunctionTable(); | 2745 | wasm.mapFunctionTable(); |
| 2753 | try wasm.mergeSections(); | 2746 | try wasm.mergeSections(); |
| 2754 | try wasm.mergeTypes(); | 2747 | try wasm.mergeTypes(); |
| ... | @@ -2867,6 +2860,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2867,6 +2860,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2867 | | 2860 | |
| 2868 | try wasm.allocateAtoms(); | 2861 | try wasm.allocateAtoms(); |
| 2869 | try wasm.setupMemory(); | 2862 | try wasm.setupMemory(); |
| | 2863 | wasm.allocateVirtualAddresses(); |
| 2870 | wasm.mapFunctionTable(); | 2864 | wasm.mapFunctionTable(); |
| 2871 | try wasm.mergeSections(); | 2865 | try wasm.mergeSections(); |
| 2872 | try wasm.mergeTypes(); | 2866 | try wasm.mergeTypes(); |
| ... | @@ -3460,8 +3454,6 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem | ... | @@ -3460,8 +3454,6 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem |
| 3460 | // bss section is not emitted when this condition holds true, so we also | 3454 | // bss section is not emitted when this condition holds true, so we also |
| 3461 | // do not output a name for it. | 3455 | // do not output a name for it. |
| 3462 | if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue; | 3456 | if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue; |
| 3463 | // Synthetic segments are not emitted | | |
| 3464 | if (std.mem.eql(u8, key, ".synthetic")) continue; | | |
| 3465 | segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key }); | 3457 | segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key }); |
| 3466 | data_segment_index += 1; | 3458 | data_segment_index += 1; |
| 3467 | } | 3459 | } |