authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-30 13:08:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-30 19:34:58-07:00
logba2d006634925850fab9d0a0e01d87bdaa368108
treea0bba99d508fe111cf967cbe5d27b55cf30cc972
parent17a87d734167b500761ef0d61493342dea0ae01d

link.File.Wasm: remove the "files" abstraction

Removes the `files` field from the Wasm linker, storing the ZigObject as its own field instead using a tagged union. This removes a layer of indirection when accessing the ZigObject, and untangles logic so that we can introduce a "pre-link" phase that prepares the linker state to handle only incremental updates to the ZigObject and then minimize logic inside flush(). Furthermore, don't make array elements store their own indexes, that's always a waste. Flattens some of the file system hierarchy and unifies variable names for easier refactoring. Introduces type safety for optional object indexes.

10 files changed, 1146 insertions(+), 1160 deletions(-)

CMakeLists.txt-3
...@@ -648,12 +648,9 @@ set(ZIG_STAGE2_SOURCES...@@ -648,12 +648,9 @@ set(ZIG_STAGE2_SOURCES
648 src/link/StringTable.zig648 src/link/StringTable.zig
649 src/link/Wasm.zig649 src/link/Wasm.zig
650 src/link/Wasm/Archive.zig650 src/link/Wasm/Archive.zig
651 src/link/Wasm/Atom.zig
652 src/link/Wasm/Object.zig651 src/link/Wasm/Object.zig
653 src/link/Wasm/Symbol.zig652 src/link/Wasm/Symbol.zig
654 src/link/Wasm/ZigObject.zig653 src/link/Wasm/ZigObject.zig
655 src/link/Wasm/file.zig
656 src/link/Wasm/types.zig
657 src/link/aarch64.zig654 src/link/aarch64.zig
658 src/link/riscv.zig655 src/link/riscv.zig
659 src/link/table_section.zig656 src/link/table_section.zig
src/arch/wasm/CodeGen.zig+5-5
...@@ -1291,7 +1291,7 @@ fn genFunc(func: *CodeGen) InnerError!void {...@@ -1291,7 +1291,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
1291 var prologue = std.ArrayList(Mir.Inst).init(func.gpa);1291 var prologue = std.ArrayList(Mir.Inst).init(func.gpa);
1292 defer prologue.deinit();1292 defer prologue.deinit();
12931293
1294 const sp = @intFromEnum(func.bin_file.zigObjectPtr().?.stack_pointer_sym);1294 const sp = @intFromEnum(func.bin_file.zig_object.?.stack_pointer_sym);
1295 // load stack pointer1295 // load stack pointer
1296 try prologue.append(.{ .tag = .global_get, .data = .{ .label = sp } });1296 try prologue.append(.{ .tag = .global_get, .data = .{ .label = sp } });
1297 // store stack pointer so we can restore it when we return from the function1297 // store stack pointer so we can restore it when we return from the function
...@@ -1511,7 +1511,7 @@ fn restoreStackPointer(func: *CodeGen) !void {...@@ -1511,7 +1511,7 @@ fn restoreStackPointer(func: *CodeGen) !void {
1511 try func.emitWValue(func.initial_stack_value);1511 try func.emitWValue(func.initial_stack_value);
15121512
1513 // save its value in the global stack pointer1513 // save its value in the global stack pointer
1514 try func.addLabel(.global_set, @intFromEnum(func.bin_file.zigObjectPtr().?.stack_pointer_sym));1514 try func.addLabel(.global_set, @intFromEnum(func.bin_file.zig_object.?.stack_pointer_sym));
1515}1515}
15161516
1517/// From a given type, will create space on the virtual stack to store the value of such type.1517/// From a given type, will create space on the virtual stack to store the value of such type.
...@@ -2262,7 +2262,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -2262,7 +2262,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2262 }2262 }
22632263
2264 if (callee) |direct| {2264 if (callee) |direct| {
2265 const atom_index = func.bin_file.zigObjectPtr().?.navs.get(direct).?.atom;2265 const atom_index = func.bin_file.zig_object.?.navs.get(direct).?.atom;
2266 try func.addLabel(.call, @intFromEnum(func.bin_file.getAtom(atom_index).sym_index));2266 try func.addLabel(.call, @intFromEnum(func.bin_file.getAtom(atom_index).sym_index));
2267 } else {2267 } else {
2268 // in this case we call a function pointer2268 // in this case we call a function pointer
...@@ -2274,7 +2274,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -2274,7 +2274,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2274 var fn_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), pt, func.target.*);2274 var fn_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), pt, func.target.*);
2275 defer fn_type.deinit(func.gpa);2275 defer fn_type.deinit(func.gpa);
22762276
2277 const fn_type_index = try func.bin_file.zigObjectPtr().?.putOrGetFuncType(func.gpa, fn_type);2277 const fn_type_index = try func.bin_file.zig_object.?.putOrGetFuncType(func.gpa, fn_type);
2278 try func.addLabel(.call_indirect, fn_type_index);2278 try func.addLabel(.call_indirect, fn_type_index);
2279 }2279 }
22802280
...@@ -7178,7 +7178,7 @@ fn callIntrinsic(...@@ -7178,7 +7178,7 @@ fn callIntrinsic(
7178 const zcu = pt.zcu;7178 const zcu = pt.zcu;
7179 var func_type = try genFunctype(func.gpa, .{ .wasm_watc = .{} }, param_types, return_type, pt, func.target.*);7179 var func_type = try genFunctype(func.gpa, .{ .wasm_watc = .{} }, param_types, return_type, pt, func.target.*);
7180 defer func_type.deinit(func.gpa);7180 defer func_type.deinit(func.gpa);
7181 const func_type_index = try func.bin_file.zigObjectPtr().?.putOrGetFuncType(func.gpa, func_type);7181 const func_type_index = try func.bin_file.zig_object.?.putOrGetFuncType(func.gpa, func_type);
7182 try func.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index);7182 try func.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index);
71837183
7184 const want_sret_param = firstParamSRet(.{ .wasm_watc = .{} }, return_type, pt, func.target.*);7184 const want_sret_param = firstParamSRet(.{ .wasm_watc = .{} }, return_type, pt, func.target.*);
src/arch/wasm/Emit.zig+5-5
...@@ -310,7 +310,7 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {...@@ -310,7 +310,7 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {
310 const global_offset = emit.offset();310 const global_offset = emit.offset();
311 try emit.code.appendSlice(&buf);311 try emit.code.appendSlice(&buf);
312312
313 const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;313 const atom_index = emit.bin_file.zig_object.?.navs.get(emit.owner_nav).?.atom;
314 const atom = emit.bin_file.getAtomPtr(atom_index);314 const atom = emit.bin_file.getAtomPtr(atom_index);
315 try atom.relocs.append(gpa, .{315 try atom.relocs.append(gpa, .{
316 .index = label,316 .index = label,
...@@ -370,7 +370,7 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -370,7 +370,7 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {
370 try emit.code.appendSlice(&buf);370 try emit.code.appendSlice(&buf);
371371
372 if (label != 0) {372 if (label != 0) {
373 const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;373 const atom_index = emit.bin_file.zig_object.?.navs.get(emit.owner_nav).?.atom;
374 const atom = emit.bin_file.getAtomPtr(atom_index);374 const atom = emit.bin_file.getAtomPtr(atom_index);
375 try atom.relocs.append(gpa, .{375 try atom.relocs.append(gpa, .{
376 .offset = call_offset,376 .offset = call_offset,
...@@ -390,7 +390,7 @@ fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -390,7 +390,7 @@ fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void {
390 leb128.writeUnsignedFixed(5, &buf, type_index);390 leb128.writeUnsignedFixed(5, &buf, type_index);
391 try emit.code.appendSlice(&buf);391 try emit.code.appendSlice(&buf);
392 if (type_index != 0) {392 if (type_index != 0) {
393 const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;393 const atom_index = emit.bin_file.zig_object.?.navs.get(emit.owner_nav).?.atom;
394 const atom = emit.bin_file.getAtomPtr(atom_index);394 const atom = emit.bin_file.getAtomPtr(atom_index);
395 try atom.relocs.append(emit.bin_file.base.comp.gpa, .{395 try atom.relocs.append(emit.bin_file.base.comp.gpa, .{
396 .offset = call_offset,396 .offset = call_offset,
...@@ -412,7 +412,7 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -412,7 +412,7 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
412 try emit.code.appendSlice(&buf);412 try emit.code.appendSlice(&buf);
413413
414 if (symbol_index != 0) {414 if (symbol_index != 0) {
415 const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;415 const atom_index = emit.bin_file.zig_object.?.navs.get(emit.owner_nav).?.atom;
416 const atom = emit.bin_file.getAtomPtr(atom_index);416 const atom = emit.bin_file.getAtomPtr(atom_index);
417 try atom.relocs.append(gpa, .{417 try atom.relocs.append(gpa, .{
418 .offset = index_offset,418 .offset = index_offset,
...@@ -443,7 +443,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -443,7 +443,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
443 }443 }
444444
445 if (mem.pointer != 0) {445 if (mem.pointer != 0) {
446 const atom_index = emit.bin_file.zigObjectPtr().?.navs.get(emit.owner_nav).?.atom;446 const atom_index = emit.bin_file.zig_object.?.navs.get(emit.owner_nav).?.atom;
447 const atom = emit.bin_file.getAtomPtr(atom_index);447 const atom = emit.bin_file.getAtomPtr(atom_index);
448 try atom.relocs.append(gpa, .{448 try atom.relocs.append(gpa, .{
449 .offset = mem_offset,449 .offset = mem_offset,
src/link/Wasm.zig+985-294
...@@ -15,7 +15,6 @@ const log = std.log.scoped(.link);...@@ -15,7 +15,6 @@ const log = std.log.scoped(.link);
15const gc_log = std.log.scoped(.gc);15const gc_log = std.log.scoped(.gc);
16const mem = std.mem;16const mem = std.mem;
17const trace = @import("../tracy.zig").trace;17const trace = @import("../tracy.zig").trace;
18const types = @import("Wasm/types.zig");
19const wasi_libc = @import("../wasi_libc.zig");18const wasi_libc = @import("../wasi_libc.zig");
2019
21const Air = @import("../Air.zig");20const Air = @import("../Air.zig");
...@@ -26,7 +25,6 @@ const Path = Cache.Path;...@@ -26,7 +25,6 @@ const Path = Cache.Path;
26const CodeGen = @import("../arch/wasm/CodeGen.zig");25const CodeGen = @import("../arch/wasm/CodeGen.zig");
27const Compilation = @import("../Compilation.zig");26const Compilation = @import("../Compilation.zig");
28const Dwarf = @import("Dwarf.zig");27const Dwarf = @import("Dwarf.zig");
29const File = @import("Wasm/file.zig").File;
30const InternPool = @import("../InternPool.zig");28const InternPool = @import("../InternPool.zig");
31const Liveness = @import("../Liveness.zig");29const Liveness = @import("../Liveness.zig");
32const LlvmObject = @import("../codegen/llvm.zig").Object;30const LlvmObject = @import("../codegen/llvm.zig").Object;
...@@ -37,9 +35,6 @@ const Type = @import("../Type.zig");...@@ -37,9 +35,6 @@ const Type = @import("../Type.zig");
37const Value = @import("../Value.zig");35const Value = @import("../Value.zig");
38const ZigObject = @import("Wasm/ZigObject.zig");36const ZigObject = @import("Wasm/ZigObject.zig");
3937
40pub const Atom = @import("Wasm/Atom.zig");
41pub const Relocation = types.Relocation;
42
43base: link.File,38base: link.File,
44/// Symbol name of the entry function to export39/// Symbol name of the entry function to export
45entry_name: ?[]const u8,40entry_name: ?[]const u8,
...@@ -61,11 +56,9 @@ export_table: bool,...@@ -61,11 +56,9 @@ export_table: bool,
61name: []const u8,56name: []const u8,
62/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.57/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
63llvm_object: ?LlvmObject.Ptr = null,58llvm_object: ?LlvmObject.Ptr = null,
64/// The file index of a `ZigObject`. This will only contain a valid index when a zcu exists,59zig_object: ?*ZigObject,
65/// and the chosen backend is the Wasm backend.
66zig_object_index: File.Index = .null,
67/// List of relocatable files to be linked into the final binary.60/// List of relocatable files to be linked into the final binary.
68files: std.MultiArrayList(File.Entry) = .{},61objects: std.ArrayListUnmanaged(Object) = .{},
69/// When importing objects from the host environment, a name must be supplied.62/// When importing objects from the host environment, a name must be supplied.
70/// LLVM uses "env" by default when none is given. This would be a good default for Zig63/// LLVM uses "env" by default when none is given. This would be a good default for Zig
71/// to support existing code.64/// to support existing code.
...@@ -105,17 +98,17 @@ imported_globals_count: u32 = 0,...@@ -105,17 +98,17 @@ imported_globals_count: u32 = 0,
105/// The count of imported tables. This number will be appended98/// The count of imported tables. This number will be appended
106/// to the table indexes when sections are merged.99/// to the table indexes when sections are merged.
107imported_tables_count: u32 = 0,100imported_tables_count: u32 = 0,
108/// Map of symbol locations, represented by its `types.Import`101/// Map of symbol locations, represented by its `Import`
109imports: std.AutoHashMapUnmanaged(SymbolLoc, types.Import) = .empty,102imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty,
110/// Represents non-synthetic section entries.103/// Represents non-synthetic section entries.
111/// Used for code, data and custom sections.104/// Used for code, data and custom sections.
112segments: std.ArrayListUnmanaged(Segment) = .empty,105segments: std.ArrayListUnmanaged(Segment) = .empty,
113/// Maps a data segment key (such as .rodata) to the index into `segments`.106/// Maps a data segment key (such as .rodata) to the index into `segments`.
114data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty,107data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty,
115/// A table of `types.Segment` which provide meta data108/// A table of `NamedSegment` which provide meta data
116/// about a data symbol such as its name where the key is109/// about a data symbol such as its name where the key is
117/// the segment index, which can be found from `data_segments`110/// the segment index, which can be found from `data_segments`
118segment_info: std.AutoArrayHashMapUnmanaged(u32, types.Segment) = .empty,111segment_info: std.AutoArrayHashMapUnmanaged(u32, NamedSegment) = .empty,
119/// Deduplicated string table for strings used by symbols, imports and exports.112/// Deduplicated string table for strings used by symbols, imports and exports.
120string_table: StringTable = .{},113string_table: StringTable = .{},
121114
...@@ -126,8 +119,15 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .empty,...@@ -126,8 +119,15 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .empty,
126/// function index and the value is function.119/// function index and the value is function.
127/// This allows us to map multiple symbols to the same function.120/// This allows us to map multiple symbols to the same function.
128functions: std.AutoArrayHashMapUnmanaged(121functions: std.AutoArrayHashMapUnmanaged(
129 struct { file: File.Index, index: u32 },122 struct {
130 struct { func: std.wasm.Func, sym_index: Symbol.Index },123 /// `none` in the case of synthetic sections.
124 file: OptionalObjectId,
125 index: u32,
126 },
127 struct {
128 func: std.wasm.Func,
129 sym_index: Symbol.Index,
130 },
131) = .{},131) = .{},
132/// Output global section132/// Output global section
133wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,133wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,
...@@ -140,7 +140,7 @@ memories: std.wasm.Memory = .{ .limits = .{...@@ -140,7 +140,7 @@ memories: std.wasm.Memory = .{ .limits = .{
140/// Output table section140/// Output table section
141tables: std.ArrayListUnmanaged(std.wasm.Table) = .empty,141tables: std.ArrayListUnmanaged(std.wasm.Table) = .empty,
142/// Output export section142/// Output export section
143exports: std.ArrayListUnmanaged(types.Export) = .empty,143exports: std.ArrayListUnmanaged(Export) = .empty,
144/// List of initialization functions. These must be called in order of priority144/// List of initialization functions. These must be called in order of priority
145/// by the (synthetic) __wasm_call_ctors function.145/// by the (synthetic) __wasm_call_ctors function.
146init_funcs: std.ArrayListUnmanaged(InitFuncLoc) = .empty,146init_funcs: std.ArrayListUnmanaged(InitFuncLoc) = .empty,
...@@ -154,8 +154,6 @@ entry: ?u32 = null,...@@ -154,8 +154,6 @@ entry: ?u32 = null,
154/// Note: Key is symbol location, value represents the index into the table154/// Note: Key is symbol location, value represents the index into the table
155function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty,155function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty,
156156
157/// All object files and their data which are linked into the final binary
158objects: std.ArrayListUnmanaged(File.Index) = .empty,
159/// All archive files that are lazy loaded.157/// All archive files that are lazy loaded.
160/// e.g. when an undefined symbol references a symbol from the archive.158/// e.g. when an undefined symbol references a symbol from the archive.
161archives: std.ArrayListUnmanaged(Archive) = .empty,159archives: std.ArrayListUnmanaged(Archive) = .empty,
...@@ -178,7 +176,29 @@ undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty,...@@ -178,7 +176,29 @@ undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty,
178/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.176/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.
179symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty,177symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty,
180178
181pub const Alignment = types.Alignment;179/// Index into objects array or the zig object.
180pub const ObjectId = enum(u16) {
181 zig_object = std.math.maxInt(u16) - 1,
182 _,
183
184 pub fn toOptional(i: ObjectId) OptionalObjectId {
185 const result: OptionalObjectId = @enumFromInt(@intFromEnum(i));
186 assert(result != .none);
187 return result;
188 }
189};
190
191/// Optional index into objects array or the zig object.
192pub const OptionalObjectId = enum(u16) {
193 zig_object = std.math.maxInt(u16) - 1,
194 none = std.math.maxInt(u16),
195 _,
196
197 pub fn unwrap(i: OptionalObjectId) ?ObjectId {
198 if (i == .none) return null;
199 return @enumFromInt(@intFromEnum(i));
200 }
201};
182202
183pub const Segment = struct {203pub const Segment = struct {
184 alignment: Alignment,204 alignment: Alignment,
...@@ -208,43 +228,55 @@ pub const SymbolLoc = struct {...@@ -208,43 +228,55 @@ pub const SymbolLoc = struct {
208 /// The index of the symbol within the specified file228 /// The index of the symbol within the specified file
209 index: Symbol.Index,229 index: Symbol.Index,
210 /// The index of the object file where the symbol resides.230 /// The index of the object file where the symbol resides.
211 file: File.Index,231 file: OptionalObjectId,
232};
212233
213 /// From a given location, returns the corresponding symbol in the wasm binary234/// From a given location, returns the corresponding symbol in the wasm binary
214 pub fn getSymbol(loc: SymbolLoc, wasm_file: *const Wasm) *Symbol {235pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol {
215 if (wasm_file.discarded.get(loc)) |new_loc| {236 if (wasm.discarded.get(loc)) |new_loc| {
216 return new_loc.getSymbol(wasm_file);237 return symbolLocSymbol(wasm, new_loc);
217 }
218 if (wasm_file.file(loc.file)) |obj_file| {
219 return obj_file.symbol(loc.index);
220 }
221 return &wasm_file.synthetic_symbols.items[@intFromEnum(loc.index)];
222 }238 }
239 return switch (loc.file) {
240 .none => &wasm.synthetic_symbols.items[@intFromEnum(loc.index)],
241 .zig_object => wasm.zig_object.?.symbol(loc.index),
242 _ => &wasm.objects.items[@intFromEnum(loc.file)].symtable[@intFromEnum(loc.index)],
243 };
244}
223245
224 /// From a given location, returns the name of the symbol.246/// From a given location, returns the name of the symbol.
225 pub fn getName(loc: SymbolLoc, wasm_file: *const Wasm) []const u8 {247pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) []const u8 {
226 if (wasm_file.discarded.get(loc)) |new_loc| {248 if (wasm.discarded.get(loc)) |new_loc| {
227 return new_loc.getName(wasm_file);249 return wasm.symbolLocName(new_loc);
228 }250 }
229 if (wasm_file.file(loc.file)) |obj_file| {251 switch (loc.file) {
230 return obj_file.symbolName(loc.index);252 .none => {
231 }253 const sym = wasm.synthetic_symbols.items[@intFromEnum(loc.index)];
232 const sym = wasm_file.synthetic_symbols.items[@intFromEnum(loc.index)];254 return wasm.string_table.get(sym.name);
233 return wasm_file.string_table.get(sym.name);255 },
256 .zig_object => {
257 const zo = wasm.zig_object.?;
258 const sym = zo.symbols.items[@intFromEnum(loc.index)];
259 return zo.string_table.get(sym.name).?;
260 },
261 _ => {
262 const obj = &wasm.objects.items[@intFromEnum(loc.file)];
263 const sym = obj.symtable[@intFromEnum(loc.index)];
264 return obj.string_table.get(sym.name);
265 },
234 }266 }
267}
235268
236 /// From a given symbol location, returns the final location.269/// From a given symbol location, returns the final location.
237 /// e.g. when a symbol was resolved and replaced by the symbol270/// e.g. when a symbol was resolved and replaced by the symbol
238 /// in a different file, this will return said location.271/// in a different file, this will return said location.
239 /// If the symbol wasn't replaced by another, this will return272/// If the symbol wasn't replaced by another, this will return
240 /// the given location itwasm.273/// the given location itwasm.
241 pub fn finalLoc(loc: SymbolLoc, wasm_file: *const Wasm) SymbolLoc {274pub fn symbolLocFinalLoc(wasm: *const Wasm, loc: SymbolLoc) SymbolLoc {
242 if (wasm_file.discarded.get(loc)) |new_loc| {275 if (wasm.discarded.get(loc)) |new_loc| {
243 return new_loc.finalLoc(wasm_file);276 return symbolLocFinalLoc(wasm, new_loc);
244 }
245 return loc;
246 }277 }
247};278 return loc;
279}
248280
249// Contains the location of the function symbol, as well as281// Contains the location of the function symbol, as well as
250/// the priority itself of the initialization function.282/// the priority itself of the initialization function.
...@@ -252,7 +284,7 @@ pub const InitFuncLoc = struct {...@@ -252,7 +284,7 @@ pub const InitFuncLoc = struct {
252 /// object file index in the list of objects.284 /// object file index in the list of objects.
253 /// Unlike `SymbolLoc` this cannot be `null` as we never define285 /// Unlike `SymbolLoc` this cannot be `null` as we never define
254 /// our own ctors.286 /// our own ctors.
255 file: File.Index,287 file: ObjectId,
256 /// Symbol index within the corresponding object file.288 /// Symbol index within the corresponding object file.
257 index: Symbol.Index,289 index: Symbol.Index,
258 /// The priority in which the constructor must be called.290 /// The priority in which the constructor must be called.
...@@ -260,12 +292,15 @@ pub const InitFuncLoc = struct {...@@ -260,12 +292,15 @@ pub const InitFuncLoc = struct {
260292
261 /// From a given `InitFuncLoc` returns the corresponding function symbol293 /// From a given `InitFuncLoc` returns the corresponding function symbol
262 fn getSymbol(loc: InitFuncLoc, wasm: *const Wasm) *Symbol {294 fn getSymbol(loc: InitFuncLoc, wasm: *const Wasm) *Symbol {
263 return getSymbolLoc(loc).getSymbol(wasm);295 return wasm.symbolLocSymbol(getSymbolLoc(loc));
264 }296 }
265297
266 /// Turns the given `InitFuncLoc` into a `SymbolLoc`298 /// Turns the given `InitFuncLoc` into a `SymbolLoc`
267 fn getSymbolLoc(loc: InitFuncLoc) SymbolLoc {299 fn getSymbolLoc(loc: InitFuncLoc) SymbolLoc {
268 return .{ .file = loc.file, .index = loc.index };300 return .{
301 .file = loc.file.toOptional(),
302 .index = loc.index,
303 };
269 }304 }
270305
271 /// Returns true when `lhs` has a higher priority (e.i. value closer to 0) than `rhs`.306 /// Returns true when `lhs` has a higher priority (e.i. value closer to 0) than `rhs`.
...@@ -307,7 +342,7 @@ pub const StringTable = struct {...@@ -307,7 +342,7 @@ pub const StringTable = struct {
307 }342 }
308343
309 try table.string_data.ensureUnusedCapacity(allocator, string.len + 1);344 try table.string_data.ensureUnusedCapacity(allocator, string.len + 1);
310 const offset = @as(u32, @intCast(table.string_data.items.len));345 const offset: u32 = @intCast(table.string_data.items.len);
311346
312 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });347 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });
313348
...@@ -414,6 +449,7 @@ pub fn createEmpty(...@@ -414,6 +449,7 @@ pub fn createEmpty(
414 .enabled => defaultEntrySymbolName(wasi_exec_model),449 .enabled => defaultEntrySymbolName(wasi_exec_model),
415 .named => |name| name,450 .named => |name| name,
416 },451 },
452 .zig_object = null,
417 };453 };
418 if (use_llvm and comp.config.have_zcu) {454 if (use_llvm and comp.config.have_zcu) {
419 wasm.llvm_object = try LlvmObject.create(arena, comp);455 wasm.llvm_object = try LlvmObject.create(arena, comp);
...@@ -446,7 +482,7 @@ pub fn createEmpty(...@@ -446,7 +482,7 @@ pub fn createEmpty(
446 // create stack pointer symbol482 // create stack pointer symbol
447 {483 {
448 const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global);484 const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global);
449 const symbol = loc.getSymbol(wasm);485 const symbol = wasm.symbolLocSymbol(loc);
450 // For object files we will import the stack pointer symbol486 // For object files we will import the stack pointer symbol
451 if (output_mode == .Obj) {487 if (output_mode == .Obj) {
452 symbol.setUndefined(true);488 symbol.setUndefined(true);
...@@ -478,7 +514,7 @@ pub fn createEmpty(...@@ -478,7 +514,7 @@ pub fn createEmpty(
478 // create indirect function pointer symbol514 // create indirect function pointer symbol
479 {515 {
480 const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table);516 const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table);
481 const symbol = loc.getSymbol(wasm);517 const symbol = wasm.symbolLocSymbol(loc);
482 const table: std.wasm.Table = .{518 const table: std.wasm.Table = .{
483 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`519 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
484 .reftype = .funcref,520 .reftype = .funcref,
...@@ -506,7 +542,7 @@ pub fn createEmpty(...@@ -506,7 +542,7 @@ pub fn createEmpty(
506 // create __wasm_call_ctors542 // create __wasm_call_ctors
507 {543 {
508 const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function);544 const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function);
509 const symbol = loc.getSymbol(wasm);545 const symbol = wasm.symbolLocSymbol(loc);
510 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);546 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
511 // we do not know the function index until after we merged all sections.547 // we do not know the function index until after we merged all sections.
512 // Therefore we set `symbol.index` and create its corresponding references548 // Therefore we set `symbol.index` and create its corresponding references
...@@ -517,7 +553,7 @@ pub fn createEmpty(...@@ -517,7 +553,7 @@ pub fn createEmpty(
517 if (shared_memory) {553 if (shared_memory) {
518 {554 {
519 const loc = try wasm.createSyntheticSymbol("__tls_base", .global);555 const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
520 const symbol = loc.getSymbol(wasm);556 const symbol = wasm.symbolLocSymbol(loc);
521 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);557 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
522 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);558 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
523 symbol.mark();559 symbol.mark();
...@@ -528,7 +564,7 @@ pub fn createEmpty(...@@ -528,7 +564,7 @@ pub fn createEmpty(
528 }564 }
529 {565 {
530 const loc = try wasm.createSyntheticSymbol("__tls_size", .global);566 const loc = try wasm.createSyntheticSymbol("__tls_size", .global);
531 const symbol = loc.getSymbol(wasm);567 const symbol = wasm.symbolLocSymbol(loc);
532 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);568 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
533 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);569 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
534 symbol.mark();570 symbol.mark();
...@@ -539,7 +575,7 @@ pub fn createEmpty(...@@ -539,7 +575,7 @@ pub fn createEmpty(
539 }575 }
540 {576 {
541 const loc = try wasm.createSyntheticSymbol("__tls_align", .global);577 const loc = try wasm.createSyntheticSymbol("__tls_align", .global);
542 const symbol = loc.getSymbol(wasm);578 const symbol = wasm.symbolLocSymbol(loc);
543 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);579 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
544 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);580 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
545 symbol.mark();581 symbol.mark();
...@@ -550,42 +586,26 @@ pub fn createEmpty(...@@ -550,42 +586,26 @@ pub fn createEmpty(
550 }586 }
551 {587 {
552 const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function);588 const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function);
553 const symbol = loc.getSymbol(wasm);589 const symbol = wasm.symbolLocSymbol(loc);
554 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);590 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
555 }591 }
556 }592 }
557593
558 if (comp.zcu) |zcu| {594 if (comp.zcu) |zcu| {
559 if (!use_llvm) {595 if (!use_llvm) {
560 const index: File.Index = @enumFromInt(wasm.files.len);596 const zig_object = try arena.create(ZigObject);
561 var zig_object: ZigObject = .{597 wasm.zig_object = zig_object;
562 .index = index,598 zig_object.* = .{
563 .path = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(zcu.main_mod.root_src_path)}),599 .path = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(zcu.main_mod.root_src_path)}),
564 .stack_pointer_sym = .null,600 .stack_pointer_sym = .null,
565 };601 };
566 try zig_object.init(wasm);602 try zig_object.init(wasm);
567 try wasm.files.append(gpa, .{ .zig_object = zig_object });
568 wasm.zig_object_index = index;
569 }603 }
570 }604 }
571605
572 return wasm;606 return wasm;
573}607}
574608
575pub fn file(wasm: *const Wasm, index: File.Index) ?File {
576 if (index == .null) return null;
577 const tag = wasm.files.items(.tags)[@intFromEnum(index)];
578 return switch (tag) {
579 .zig_object => .{ .zig_object = &wasm.files.items(.data)[@intFromEnum(index)].zig_object },
580 .object => .{ .object = &wasm.files.items(.data)[@intFromEnum(index)].object },
581 };
582}
583
584pub fn zigObjectPtr(wasm: *Wasm) ?*ZigObject {
585 if (wasm.zig_object_index == .null) return null;
586 return &wasm.files.items(.data)[@intFromEnum(wasm.zig_object_index)].zig_object;
587}
588
589pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 {609pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 {
590 var index: u32 = 0;610 var index: u32 = 0;
591 while (index < wasm.func_types.items.len) : (index += 1) {611 while (index < wasm.func_types.items.len) : (index += 1) {
...@@ -610,7 +630,7 @@ pub fn addOrUpdateImport(...@@ -610,7 +630,7 @@ pub fn addOrUpdateImport(
610 /// is asserted instead.630 /// is asserted instead.
611 type_index: ?u32,631 type_index: ?u32,
612) !void {632) !void {
613 return wasm.zigObjectPtr().?.addOrUpdateImport(wasm, name, symbol_index, lib_name, type_index);633 return wasm.zig_object.?.addOrUpdateImport(wasm, name, symbol_index, lib_name, type_index);
614}634}
615635
616/// For a given name, creates a new global synthetic symbol.636/// For a given name, creates a new global synthetic symbol.
...@@ -623,7 +643,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol...@@ -623,7 +643,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol
623643
624fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {644fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {
625 const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len);645 const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len);
626 const loc: SymbolLoc = .{ .index = sym_index, .file = .null };646 const loc: SymbolLoc = .{ .index = sym_index, .file = .none };
627 const gpa = wasm.base.comp.gpa;647 const gpa = wasm.base.comp.gpa;
628 try wasm.synthetic_symbols.append(gpa, .{648 try wasm.synthetic_symbols.append(gpa, .{
629 .name = name_offset,649 .name = name_offset,
...@@ -657,28 +677,29 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {...@@ -657,28 +677,29 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
657 },677 },
658 };678 };
659 errdefer object.deinit(gpa);679 errdefer object.deinit(gpa);
660 object.index = @enumFromInt(wasm.files.len);680 try wasm.objects.append(gpa, object);
661 try wasm.files.append(gpa, .{ .object = object });
662 try wasm.objects.append(gpa, object.index);
663 return true;681 return true;
664}682}
665683
666/// Creates a new empty `Atom` and returns its `Atom.Index`684/// Creates a new empty `Atom` and returns its `Atom.Index`
667pub fn createAtom(wasm: *Wasm, sym_index: Symbol.Index, file_index: File.Index) !Atom.Index {685pub fn createAtom(wasm: *Wasm, sym_index: Symbol.Index, object_index: OptionalObjectId) !Atom.Index {
668 const gpa = wasm.base.comp.gpa;686 const gpa = wasm.base.comp.gpa;
669 const index: Atom.Index = @enumFromInt(wasm.managed_atoms.items.len);687 const index: Atom.Index = @enumFromInt(wasm.managed_atoms.items.len);
670 const atom = try wasm.managed_atoms.addOne(gpa);688 const atom = try wasm.managed_atoms.addOne(gpa);
671 atom.* = .{ .file = file_index, .sym_index = sym_index };689 atom.* = .{
690 .file = object_index,
691 .sym_index = sym_index,
692 };
672 try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), index);693 try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), index);
673694
674 return index;695 return index;
675}696}
676697
677pub inline fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom {698pub fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom {
678 return wasm.managed_atoms.items[@intFromEnum(index)];699 return wasm.managed_atoms.items[@intFromEnum(index)];
679}700}
680701
681pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {702pub fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
682 return &wasm.managed_atoms.items[@intFromEnum(index)];703 return &wasm.managed_atoms.items[@intFromEnum(index)];
683}704}
684705
...@@ -733,15 +754,13 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -733,15 +754,13 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
733 }754 }
734755
735 for (offsets.keys()) |file_offset| {756 for (offsets.keys()) |file_offset| {
736 var object = archive.parseObject(wasm, file_offset) catch |e| {757 const object = archive.parseObject(wasm, file_offset) catch |e| {
737 var err_note = try diags.addErrorWithNotes(1);758 var err_note = try diags.addErrorWithNotes(1);
738 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});759 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});
739 try err_note.addNote("while parsing object in archive {s}", .{path});760 try err_note.addNote("while parsing object in archive {s}", .{path});
740 return error.FlushFailure;761 return error.FlushFailure;
741 };762 };
742 object.index = @enumFromInt(wasm.files.len);763 try wasm.objects.append(gpa, object);
743 try wasm.files.append(gpa, .{ .object = object });
744 try wasm.objects.append(gpa, object.index);
745 }764 }
746765
747 return true;766 return true;
...@@ -749,23 +768,102 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -749,23 +768,102 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
749768
750fn requiresTLSReloc(wasm: *const Wasm) bool {769fn requiresTLSReloc(wasm: *const Wasm) bool {
751 for (wasm.got_symbols.items) |loc| {770 for (wasm.got_symbols.items) |loc| {
752 if (loc.getSymbol(wasm).isTLS()) {771 if (wasm.symbolLocSymbol(loc).isTLS()) {
753 return true;772 return true;
754 }773 }
755 }774 }
756 return false;775 return false;
757}776}
758777
759fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {778fn objectPath(wasm: *const Wasm, object_id: ObjectId) []const u8 {
779 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.path;
780 return obj.path;
781}
782
783fn objectSymbols(wasm: *const Wasm, object_id: ObjectId) []const Symbol {
784 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.symbols.items;
785 return obj.symtable;
786}
787
788fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Symbol {
789 const obj = wasm.objectById(object_id) orelse return &wasm.zig_object.?.symbols.items[@intFromEnum(index)];
790 return &obj.symtable[@intFromEnum(index)];
791}
792
793fn objectSymbolName(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) []const u8 {
794 const obj = wasm.objectById(object_id) orelse {
795 const zo = wasm.zig_object.?;
796 const sym = zo.symbols.items[@intFromEnum(index)];
797 return zo.string_table.get(sym.name).?;
798 };
799 const sym = obj.symtable[@intFromEnum(index)];
800 return obj.string_table.get(sym.name);
801}
802
803fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func {
804 const obj = wasm.objectById(object_id) orelse {
805 const zo = wasm.zig_object.?;
806 const sym = zo.symbols.items[@intFromEnum(sym_index)];
807 return zo.functions.items[sym.index];
808 };
809 const sym = obj.symtable[@intFromEnum(sym_index)];
810 return obj.functions[sym.index - obj.imported_functions_count];
811}
812
813fn objectImportedFunctions(wasm: *const Wasm, object_id: ObjectId) u32 {
814 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.imported_functions_count;
815 return obj.imported_functions_count;
816}
817
818fn objectGlobals(wasm: *const Wasm, object_id: ObjectId) []const std.wasm.Global {
819 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.globals.items;
820 return obj.globals;
821}
822
823fn objectFuncTypes(wasm: *const Wasm, object_id: ObjectId) []const std.wasm.Type {
824 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.func_types.items;
825 return obj.func_types;
826}
827
828fn objectSegmentInfo(wasm: *const Wasm, object_id: ObjectId) []const NamedSegment {
829 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.segment_info.items;
830 return obj.segment_info;
831}
832
833/// For a given symbol index, find its corresponding import.
834/// Asserts import exists.
835fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Index) Import {
836 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.imports.get(symbol_index).?;
837 return obj.findImport(obj.symtable[@intFromEnum(symbol_index)]);
838}
839
840/// For a given offset, returns its string value.
841/// Asserts string exists in the object string table.
842fn objectString(wasm: *const Wasm, object_id: ObjectId, offset: u32) []const u8 {
843 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.string_table.get(offset).?;
844 return obj.string_table.get(offset);
845}
846
847/// Returns the object element pointer, or null if it is the ZigObject.
848fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object {
849 if (object_id == .zig_object) return null;
850 return &wasm.objects.items[@intFromEnum(object_id)];
851}
852
853fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
760 const gpa = wasm.base.comp.gpa;854 const gpa = wasm.base.comp.gpa;
761 const diags = &wasm.base.comp.link_diags;855 const diags = &wasm.base.comp.link_diags;
762 const obj_file = wasm.file(file_index).?;856 const obj_path = objectPath(wasm, object_id);
763 log.debug("Resolving symbols in object: '{s}'", .{obj_file.path()});857 log.debug("Resolving symbols in object: '{s}'", .{obj_path});
858 const symbols = objectSymbols(wasm, object_id);
764859
765 for (obj_file.symbols(), 0..) |symbol, i| {860 for (symbols, 0..) |symbol, i| {
766 const sym_index: Symbol.Index = @enumFromInt(i);861 const sym_index: Symbol.Index = @enumFromInt(i);
767 const location: SymbolLoc = .{ .file = file_index, .index = sym_index };862 const location: SymbolLoc = .{
768 const sym_name = obj_file.string(symbol.name);863 .file = object_id.toOptional(),
864 .index = sym_index,
865 };
866 const sym_name = objectString(wasm, object_id, symbol.name);
769 if (mem.eql(u8, sym_name, "__indirect_function_table")) {867 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
770 continue;868 continue;
771 }869 }
...@@ -775,7 +873,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -775,7 +873,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
775 if (symbol.isUndefined()) {873 if (symbol.isUndefined()) {
776 var err = try diags.addErrorWithNotes(1);874 var err = try diags.addErrorWithNotes(1);
777 try err.addMsg("Local symbols are not allowed to reference imports", .{});875 try err.addMsg("Local symbols are not allowed to reference imports", .{});
778 try err.addNote("symbol '{s}' defined in '{s}'", .{ sym_name, obj_file.path() });876 try err.addNote("symbol '{s}' defined in '{s}'", .{ sym_name, obj_path });
779 }877 }
780 try wasm.resolved_symbols.putNoClobber(gpa, location, {});878 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
781 continue;879 continue;
...@@ -793,13 +891,8 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -793,13 +891,8 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
793 }891 }
794892
795 const existing_loc = maybe_existing.value_ptr.*;893 const existing_loc = maybe_existing.value_ptr.*;
796 const existing_sym: *Symbol = existing_loc.getSymbol(wasm);894 const existing_sym: *Symbol = wasm.symbolLocSymbol(existing_loc);
797 const existing_file = wasm.file(existing_loc.file);895 const existing_file_path = if (existing_loc.file.unwrap()) |id| objectPath(wasm, id) else wasm.name;
798
799 const existing_file_path = if (existing_file) |existing_obj_file|
800 existing_obj_file.path()
801 else
802 wasm.name;
803896
804 if (!existing_sym.isUndefined()) outer: {897 if (!existing_sym.isUndefined()) outer: {
805 if (!symbol.isUndefined()) inner: {898 if (!symbol.isUndefined()) inner: {
...@@ -813,7 +906,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -813,7 +906,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
813 var err = try diags.addErrorWithNotes(2);906 var err = try diags.addErrorWithNotes(2);
814 try err.addMsg("symbol '{s}' defined multiple times", .{sym_name});907 try err.addMsg("symbol '{s}' defined multiple times", .{sym_name});
815 try err.addNote("first definition in '{s}'", .{existing_file_path});908 try err.addNote("first definition in '{s}'", .{existing_file_path});
816 try err.addNote("next definition in '{s}'", .{obj_file.path()});909 try err.addNote("next definition in '{s}'", .{obj_path});
817 }910 }
818911
819 try wasm.discarded.put(gpa, location, existing_loc);912 try wasm.discarded.put(gpa, location, existing_loc);
...@@ -824,22 +917,22 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -824,22 +917,22 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
824 var err = try diags.addErrorWithNotes(2);917 var err = try diags.addErrorWithNotes(2);
825 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) });918 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) });
826 try err.addNote("first definition in '{s}'", .{existing_file_path});919 try err.addNote("first definition in '{s}'", .{existing_file_path});
827 try err.addNote("next definition in '{s}'", .{obj_file.path()});920 try err.addNote("next definition in '{s}'", .{obj_path});
828 }921 }
829922
830 if (existing_sym.isUndefined() and symbol.isUndefined()) {923 if (existing_sym.isUndefined() and symbol.isUndefined()) {
831 // only verify module/import name for function symbols924 // only verify module/import name for function symbols
832 if (symbol.tag == .function) {925 if (symbol.tag == .function) {
833 const existing_name = if (existing_file) |existing_obj| blk: {926 const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| blk: {
834 const imp = existing_obj.import(existing_loc.index);927 const imp = objectImport(wasm, existing_obj_id, existing_loc.index);
835 break :blk existing_obj.string(imp.module_name);928 break :blk objectString(wasm, existing_obj_id, imp.module_name);
836 } else blk: {929 } else blk: {
837 const name_index = wasm.imports.get(existing_loc).?.module_name;930 const name_index = wasm.imports.get(existing_loc).?.module_name;
838 break :blk wasm.string_table.get(name_index);931 break :blk wasm.string_table.get(name_index);
839 };932 };
840933
841 const imp = obj_file.import(sym_index);934 const imp = objectImport(wasm, object_id, sym_index);
842 const module_name = obj_file.string(imp.module_name);935 const module_name = objectString(wasm, object_id, imp.module_name);
843 if (!mem.eql(u8, existing_name, module_name)) {936 if (!mem.eql(u8, existing_name, module_name)) {
844 var err = try diags.addErrorWithNotes(2);937 var err = try diags.addErrorWithNotes(2);
845 try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{938 try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{
...@@ -848,7 +941,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -848,7 +941,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
848 module_name,941 module_name,
849 });942 });
850 try err.addNote("first definition in '{s}'", .{existing_file_path});943 try err.addNote("first definition in '{s}'", .{existing_file_path});
851 try err.addNote("next definition in '{s}'", .{obj_file.path()});944 try err.addNote("next definition in '{s}'", .{obj_path});
852 }945 }
853 }946 }
854947
...@@ -864,7 +957,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -864,7 +957,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
864 var err = try diags.addErrorWithNotes(2);957 var err = try diags.addErrorWithNotes(2);
865 try err.addMsg("symbol '{s}' mismatching global types", .{sym_name});958 try err.addMsg("symbol '{s}' mismatching global types", .{sym_name});
866 try err.addNote("first definition in '{s}'", .{existing_file_path});959 try err.addNote("first definition in '{s}'", .{existing_file_path});
867 try err.addNote("next definition in '{s}'", .{obj_file.path()});960 try err.addNote("next definition in '{s}'", .{obj_path});
868 }961 }
869 }962 }
870963
...@@ -876,7 +969,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -876,7 +969,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
876 try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name});969 try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name});
877 try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });970 try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });
878 try err.addNote("first definition in '{s}'", .{existing_file_path});971 try err.addNote("first definition in '{s}'", .{existing_file_path});
879 try err.addNote("next definition in '{s}'", .{obj_file.path()});972 try err.addNote("next definition in '{s}'", .{obj_path});
880 }973 }
881 }974 }
882975
...@@ -891,7 +984,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {...@@ -891,7 +984,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
891 // simply overwrite with the new symbol984 // simply overwrite with the new symbol
892 log.debug("Overwriting symbol '{s}'", .{sym_name});985 log.debug("Overwriting symbol '{s}'", .{sym_name});
893 log.debug(" old definition in '{s}'", .{existing_file_path});986 log.debug(" old definition in '{s}'", .{existing_file_path});
894 log.debug(" new definition in '{s}'", .{obj_file.path()});987 log.debug(" new definition in '{s}'", .{obj_path});
895 try wasm.discarded.putNoClobber(gpa, existing_loc, location);988 try wasm.discarded.putNoClobber(gpa, existing_loc, location);
896 maybe_existing.value_ptr.* = location;989 maybe_existing.value_ptr.* = location;
897 try wasm.globals.put(gpa, sym_name_index, location);990 try wasm.globals.put(gpa, sym_name_index, location);
...@@ -924,16 +1017,14 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {...@@ -924,16 +1017,14 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
924 // Symbol is found in unparsed object file within current archive.1017 // Symbol is found in unparsed object file within current archive.
925 // Parse object and and resolve symbols again before we check remaining1018 // Parse object and and resolve symbols again before we check remaining
926 // undefined symbols.1019 // undefined symbols.
927 var object = archive.parseObject(wasm, offset.items[0]) catch |e| {1020 const object = archive.parseObject(wasm, offset.items[0]) catch |e| {
928 var err_note = try diags.addErrorWithNotes(1);1021 var err_note = try diags.addErrorWithNotes(1);
929 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});1022 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});
930 try err_note.addNote("while parsing object in archive {s}", .{archive.name});1023 try err_note.addNote("while parsing object in archive {s}", .{archive.name});
931 return error.FlushFailure;1024 return error.FlushFailure;
932 };1025 };
933 object.index = @enumFromInt(wasm.files.len);1026 try wasm.objects.append(gpa, object);
934 try wasm.files.append(gpa, .{ .object = object });1027 try wasm.resolveSymbolsInObject(@enumFromInt(wasm.objects.items.len - 1));
935 try wasm.objects.append(gpa, object.index);
936 try wasm.resolveSymbolsInObject(object.index);
9371028
938 // continue loop for any remaining undefined symbols that still exist1029 // continue loop for any remaining undefined symbols that still exist
939 // after resolving last object file1030 // after resolving last object file
...@@ -964,13 +1055,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {...@@ -964,13 +1055,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
964 return;1055 return;
965 }1056 }
966 const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function);1057 const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function);
967 sym_loc.getSymbol(wasm).mark();1058 wasm.symbolLocSymbol(sym_loc).mark();
9681059
969 const flag_address: u32 = if (shared_memory) address: {1060 const flag_address: u32 = if (shared_memory) address: {
970 // when we have passive initialization segments and shared memory1061 // when we have passive initialization segments and shared memory
971 // `setupMemory` will create this symbol and set its virtual address.1062 // `setupMemory` will create this symbol and set its virtual address.
972 const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?;1063 const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?;
973 break :address loc.getSymbol(wasm).virtual_address;1064 break :address wasm.symbolLocSymbol(loc).virtual_address;
974 } else 0;1065 } else 0;
9751066
976 var function_body = std.ArrayList(u8).init(gpa);1067 var function_body = std.ArrayList(u8).init(gpa);
...@@ -1028,7 +1119,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {...@@ -1028,7 +1119,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
1028 try writeI32Const(writer, segment.offset);1119 try writeI32Const(writer, segment.offset);
1029 try writer.writeByte(std.wasm.opcode(.global_set));1120 try writer.writeByte(std.wasm.opcode(.global_set));
1030 const loc = wasm.findGlobalSymbol("__tls_base").?;1121 const loc = wasm.findGlobalSymbol("__tls_base").?;
1031 try leb.writeUleb128(writer, loc.getSymbol(wasm).index);1122 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
1032 }1123 }
10331124
1034 try writeI32Const(writer, 0);1125 try writeI32Const(writer, 0);
...@@ -1128,7 +1219,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {...@@ -1128,7 +1219,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
1128 }1219 }
11291220
1130 const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function);1221 const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function);
1131 loc.getSymbol(wasm).mark();1222 wasm.symbolLocSymbol(loc).mark();
1132 var function_body = std.ArrayList(u8).init(gpa);1223 var function_body = std.ArrayList(u8).init(gpa);
1133 defer function_body.deinit();1224 defer function_body.deinit();
1134 const writer = function_body.writer();1225 const writer = function_body.writer();
...@@ -1136,12 +1227,12 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {...@@ -1136,12 +1227,12 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
1136 // locals (we have none)1227 // locals (we have none)
1137 try writer.writeByte(0);1228 try writer.writeByte(0);
1138 for (wasm.got_symbols.items, 0..) |got_loc, got_index| {1229 for (wasm.got_symbols.items, 0..) |got_loc, got_index| {
1139 const sym: *Symbol = got_loc.getSymbol(wasm);1230 const sym: *Symbol = wasm.symbolLocSymbol(got_loc);
1140 if (!sym.isTLS()) continue; // only relocate TLS symbols1231 if (!sym.isTLS()) continue; // only relocate TLS symbols
1141 if (sym.tag == .data and sym.isDefined()) {1232 if (sym.tag == .data and sym.isDefined()) {
1142 // get __tls_base1233 // get __tls_base
1143 try writer.writeByte(std.wasm.opcode(.global_get));1234 try writer.writeByte(std.wasm.opcode(.global_get));
1144 try leb.writeUleb128(writer, wasm.findGlobalSymbol("__tls_base").?.getSymbol(wasm).index);1235 try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.findGlobalSymbol("__tls_base").?).index);
11451236
1146 // add the virtual address of the symbol1237 // add the virtual address of the symbol
1147 try writer.writeByte(std.wasm.opcode(.i32_const));1238 try writer.writeByte(std.wasm.opcode(.i32_const));
...@@ -1165,7 +1256,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {...@@ -1165,7 +1256,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
11651256
1166fn validateFeatures(1257fn validateFeatures(
1167 wasm: *const Wasm,1258 wasm: *const Wasm,
1168 to_emit: *[@typeInfo(types.Feature.Tag).@"enum".fields.len]bool,1259 to_emit: *[@typeInfo(Feature.Tag).@"enum".fields.len]bool,
1169 emit_features_count: *u32,1260 emit_features_count: *u32,
1170) !void {1261) !void {
1171 const comp = wasm.base.comp;1262 const comp = wasm.base.comp;
...@@ -1174,7 +1265,7 @@ fn validateFeatures(...@@ -1174,7 +1265,7 @@ fn validateFeatures(
1174 const shared_memory = comp.config.shared_memory;1265 const shared_memory = comp.config.shared_memory;
1175 const cpu_features = target.cpu.features;1266 const cpu_features = target.cpu.features;
1176 const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects.1267 const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects.
1177 const known_features_count = @typeInfo(types.Feature.Tag).@"enum".fields.len;1268 const known_features_count = @typeInfo(Feature.Tag).@"enum".fields.len;
11781269
1179 var allowed = [_]bool{false} ** known_features_count;1270 var allowed = [_]bool{false} ** known_features_count;
1180 var used = [_]u17{0} ** known_features_count;1271 var used = [_]u17{0} ** known_features_count;
...@@ -1199,10 +1290,9 @@ fn validateFeatures(...@@ -1199,10 +1290,9 @@ fn validateFeatures(
11991290
1200 // extract all the used, disallowed and required features from each1291 // extract all the used, disallowed and required features from each
1201 // linked object file so we can test them.1292 // linked object file so we can test them.
1202 for (wasm.objects.items) |file_index| {1293 for (wasm.objects.items, 0..) |*object, file_index| {
1203 const object: Object = wasm.files.items(.data)[@intFromEnum(file_index)].object;
1204 for (object.features) |feature| {1294 for (object.features) |feature| {
1205 const value = @as(u16, @intFromEnum(file_index)) << 1 | @as(u1, 1);1295 const value = (@as(u16, @intCast(file_index)) << 1) | 1;
1206 switch (feature.prefix) {1296 switch (feature.prefix) {
1207 .used => {1297 .used => {
1208 used[@intFromEnum(feature.tag)] = value;1298 used[@intFromEnum(feature.tag)] = value;
...@@ -1234,8 +1324,8 @@ fn validateFeatures(...@@ -1234,8 +1324,8 @@ fn validateFeatures(
1234 emit_features_count.* += @intFromBool(is_enabled);1324 emit_features_count.* += @intFromBool(is_enabled);
1235 } else if (is_enabled and !allowed[used_index]) {1325 } else if (is_enabled and !allowed[used_index]) {
1236 var err = try diags.addErrorWithNotes(1);1326 var err = try diags.addErrorWithNotes(1);
1237 try err.addMsg("feature '{}' not allowed, but used by linked object", .{@as(types.Feature.Tag, @enumFromInt(used_index))});1327 try err.addMsg("feature '{}' not allowed, but used by linked object", .{@as(Feature.Tag, @enumFromInt(used_index))});
1238 try err.addNote("defined in '{s}'", .{wasm.files.items(.data)[used_set >> 1].object.path});1328 try err.addNote("defined in '{s}'", .{wasm.objects.items[used_set >> 1].path});
1239 valid_feature_set = false;1329 valid_feature_set = false;
1240 }1330 }
1241 }1331 }
...@@ -1245,17 +1335,17 @@ fn validateFeatures(...@@ -1245,17 +1335,17 @@ fn validateFeatures(
1245 }1335 }
12461336
1247 if (shared_memory) {1337 if (shared_memory) {
1248 const disallowed_feature = disallowed[@intFromEnum(types.Feature.Tag.shared_mem)];1338 const disallowed_feature = disallowed[@intFromEnum(Feature.Tag.shared_mem)];
1249 if (@as(u1, @truncate(disallowed_feature)) != 0) {1339 if (@as(u1, @truncate(disallowed_feature)) != 0) {
1250 var err = try diags.addErrorWithNotes(0);1340 var err = try diags.addErrorWithNotes(0);
1251 try err.addMsg(1341 try err.addMsg(
1252 "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled",1342 "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled",
1253 .{wasm.files.items(.data)[disallowed_feature >> 1].object.path},1343 .{wasm.objects.items[disallowed_feature >> 1].path},
1254 );1344 );
1255 valid_feature_set = false;1345 valid_feature_set = false;
1256 }1346 }
12571347
1258 for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {1348 for ([_]Feature.Tag{ .atomics, .bulk_memory }) |feature| {
1259 if (!allowed[@intFromEnum(feature)]) {1349 if (!allowed[@intFromEnum(feature)]) {
1260 var err = try diags.addErrorWithNotes(0);1350 var err = try diags.addErrorWithNotes(0);
1261 try err.addMsg("feature '{}' is not used but is required for shared-memory", .{feature});1351 try err.addMsg("feature '{}' is not used but is required for shared-memory", .{feature});
...@@ -1264,7 +1354,7 @@ fn validateFeatures(...@@ -1264,7 +1354,7 @@ fn validateFeatures(
1264 }1354 }
12651355
1266 if (has_tls) {1356 if (has_tls) {
1267 for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {1357 for ([_]Feature.Tag{ .atomics, .bulk_memory }) |feature| {
1268 if (!allowed[@intFromEnum(feature)]) {1358 if (!allowed[@intFromEnum(feature)]) {
1269 var err = try diags.addErrorWithNotes(0);1359 var err = try diags.addErrorWithNotes(0);
1270 try err.addMsg("feature '{}' is not used but is required for thread-local storage", .{feature});1360 try err.addMsg("feature '{}' is not used but is required for thread-local storage", .{feature});
...@@ -1272,9 +1362,8 @@ fn validateFeatures(...@@ -1272,9 +1362,8 @@ fn validateFeatures(
1272 }1362 }
1273 }1363 }
1274 // For each linked object, validate the required and disallowed features1364 // For each linked object, validate the required and disallowed features
1275 for (wasm.objects.items) |file_index| {1365 for (wasm.objects.items) |*object| {
1276 var object_used_features = [_]bool{false} ** known_features_count;1366 var object_used_features = [_]bool{false} ** known_features_count;
1277 const object = wasm.files.items(.data)[@intFromEnum(file_index)].object;
1278 for (object.features) |feature| {1367 for (object.features) |feature| {
1279 if (feature.prefix == .disallowed) continue; // already defined in 'disallowed' set.1368 if (feature.prefix == .disallowed) continue; // already defined in 'disallowed' set.
1280 // from here a feature is always used1369 // from here a feature is always used
...@@ -1282,7 +1371,7 @@ fn validateFeatures(...@@ -1282,7 +1371,7 @@ fn validateFeatures(
1282 if (@as(u1, @truncate(disallowed_feature)) != 0) {1371 if (@as(u1, @truncate(disallowed_feature)) != 0) {
1283 var err = try diags.addErrorWithNotes(2);1372 var err = try diags.addErrorWithNotes(2);
1284 try err.addMsg("feature '{}' is disallowed, but used by linked object", .{feature.tag});1373 try err.addMsg("feature '{}' is disallowed, but used by linked object", .{feature.tag});
1285 try err.addNote("disallowed by '{s}'", .{wasm.files.items(.data)[disallowed_feature >> 1].object.path});1374 try err.addNote("disallowed by '{s}'", .{wasm.objects.items[disallowed_feature >> 1].path});
1286 try err.addNote("used in '{s}'", .{object.path});1375 try err.addNote("used in '{s}'", .{object.path});
1287 valid_feature_set = false;1376 valid_feature_set = false;
1288 }1377 }
...@@ -1295,8 +1384,8 @@ fn validateFeatures(...@@ -1295,8 +1384,8 @@ fn validateFeatures(
1295 const is_required = @as(u1, @truncate(required_feature)) != 0;1384 const is_required = @as(u1, @truncate(required_feature)) != 0;
1296 if (is_required and !object_used_features[feature_index]) {1385 if (is_required and !object_used_features[feature_index]) {
1297 var err = try diags.addErrorWithNotes(2);1386 var err = try diags.addErrorWithNotes(2);
1298 try err.addMsg("feature '{}' is required but not used in linked object", .{@as(types.Feature.Tag, @enumFromInt(feature_index))});1387 try err.addMsg("feature '{}' is required but not used in linked object", .{@as(Feature.Tag, @enumFromInt(feature_index))});
1299 try err.addNote("required by '{s}'", .{wasm.files.items(.data)[required_feature >> 1].object.path});1388 try err.addNote("required by '{s}'", .{wasm.objects.items[required_feature >> 1].path});
1300 try err.addNote("missing in '{s}'", .{object.path});1389 try err.addNote("missing in '{s}'", .{object.path});
1301 valid_feature_set = false;1390 valid_feature_set = false;
1302 }1391 }
...@@ -1341,7 +1430,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1341,7 +1430,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1341 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);1430 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);
1342 try wasm.discarded.putNoClobber(gpa, kv.value, loc);1431 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
1343 _ = wasm.resolved_symbols.swapRemove(kv.value);1432 _ = wasm.resolved_symbols.swapRemove(kv.value);
1344 const symbol = loc.getSymbol(wasm);1433 const symbol = wasm.symbolLocSymbol(loc);
1345 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);1434 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
1346 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);1435 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
1347 try wasm.wasm_globals.append(gpa, .{1436 try wasm.wasm_globals.append(gpa, .{
...@@ -1368,14 +1457,15 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {...@@ -1368,14 +1457,15 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
13681457
1369 var found_undefined_symbols = false;1458 var found_undefined_symbols = false;
1370 for (wasm.undefs.values()) |undef| {1459 for (wasm.undefs.values()) |undef| {
1371 const symbol = undef.getSymbol(wasm);1460 const symbol = wasm.symbolLocSymbol(undef);
1372 if (symbol.tag == .data) {1461 if (symbol.tag == .data) {
1373 found_undefined_symbols = true;1462 found_undefined_symbols = true;
1374 const file_name = if (wasm.file(undef.file)) |obj_file|1463 const file_name = switch (undef.file) {
1375 obj_file.path()1464 .zig_object => wasm.zig_object.?.path,
1376 else1465 .none => wasm.name,
1377 wasm.name;1466 _ => wasm.objects.items[@intFromEnum(undef.file)].path,
1378 const symbol_name = undef.getName(wasm);1467 };
1468 const symbol_name = wasm.symbolLocName(undef);
1379 var err = try diags.addErrorWithNotes(1);1469 var err = try diags.addErrorWithNotes(1);
1380 try err.addMsg("could not resolve undefined symbol '{s}'", .{symbol_name});1470 try err.addMsg("could not resolve undefined symbol '{s}'", .{symbol_name});
1381 try err.addNote("defined in '{s}'", .{file_name});1471 try err.addNote("defined in '{s}'", .{file_name});
...@@ -1396,11 +1486,11 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1396,11 +1486,11 @@ pub fn deinit(wasm: *Wasm) void {
1396 for (wasm.segment_info.values()) |segment_info| {1486 for (wasm.segment_info.values()) |segment_info| {
1397 gpa.free(segment_info.name);1487 gpa.free(segment_info.name);
1398 }1488 }
1399 if (wasm.zigObjectPtr()) |zig_obj| {1489 if (wasm.zig_object) |zig_obj| {
1400 zig_obj.deinit(wasm);1490 zig_obj.deinit(wasm);
1401 }1491 }
1402 for (wasm.objects.items) |obj_index| {1492 for (wasm.objects.items) |*object| {
1403 wasm.file(obj_index).?.object.deinit(gpa);1493 object.deinit(gpa);
1404 }1494 }
14051495
1406 for (wasm.archives.items) |*archive| {1496 for (wasm.archives.items) |*archive| {
...@@ -1437,7 +1527,6 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1437,7 +1527,6 @@ pub fn deinit(wasm: *Wasm) void {
1437 wasm.exports.deinit(gpa);1527 wasm.exports.deinit(gpa);
14381528
1439 wasm.string_table.deinit(gpa);1529 wasm.string_table.deinit(gpa);
1440 wasm.files.deinit(gpa);
1441}1530}
14421531
1443pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {1532pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
...@@ -1445,7 +1534,7 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,...@@ -1445,7 +1534,7 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
1445 @panic("Attempted to compile for object format that was disabled by build configuration");1534 @panic("Attempted to compile for object format that was disabled by build configuration");
1446 }1535 }
1447 if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness);1536 if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness);
1448 try wasm.zigObjectPtr().?.updateFunc(wasm, pt, func_index, air, liveness);1537 try wasm.zig_object.?.updateFunc(wasm, pt, func_index, air, liveness);
1449}1538}
14501539
1451// Generate code for the "Nav", storing it in memory to be later written to1540// Generate code for the "Nav", storing it in memory to be later written to
...@@ -1455,51 +1544,84 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !voi...@@ -1455,51 +1544,84 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !voi
1455 @panic("Attempted to compile for object format that was disabled by build configuration");1544 @panic("Attempted to compile for object format that was disabled by build configuration");
1456 }1545 }
1457 if (wasm.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav);1546 if (wasm.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav);
1458 try wasm.zigObjectPtr().?.updateNav(wasm, pt, nav);1547 try wasm.zig_object.?.updateNav(wasm, pt, nav);
1459}1548}
14601549
1461pub fn updateNavLineNumber(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {1550pub fn updateNavLineNumber(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {
1462 if (wasm.llvm_object) |_| return;1551 if (wasm.llvm_object) |_| return;
1463 try wasm.zigObjectPtr().?.updateNavLineNumber(pt, nav);1552 try wasm.zig_object.?.updateNavLineNumber(pt, nav);
1464}1553}
14651554
1466/// From a given symbol location, returns its `wasm.GlobalType`.1555/// From a given symbol location, returns its `wasm.GlobalType`.
1467/// Asserts the Symbol represents a global.1556/// Asserts the Symbol represents a global.
1468fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType {1557fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType {
1469 const symbol = loc.getSymbol(wasm);1558 const symbol = wasm.symbolLocSymbol(loc);
1470 assert(symbol.tag == .global);1559 assert(symbol.tag == .global);
1471 const is_undefined = symbol.isUndefined();1560 const is_undefined = symbol.isUndefined();
1472 if (wasm.file(loc.file)) |obj_file| {1561 switch (loc.file) {
1473 if (is_undefined) {1562 .zig_object => {
1474 return obj_file.import(loc.index).kind.global;1563 const zo = wasm.zig_object.?;
1475 }1564 return if (is_undefined)
1476 return obj_file.globals()[symbol.index - obj_file.importedGlobals()].global_type;1565 zo.imports.get(loc.index).?.kind.global
1477 }1566 else
1478 if (is_undefined) {1567 zo.globals.items[symbol.index - zo.imported_globals_count].global_type;
1479 return wasm.imports.get(loc).?.kind.global;1568 },
1569 .none => {
1570 return if (is_undefined)
1571 wasm.imports.get(loc).?.kind.global
1572 else
1573 wasm.wasm_globals.items[symbol.index].global_type;
1574 },
1575 _ => {
1576 const obj = &wasm.objects.items[@intFromEnum(loc.file)];
1577 return if (is_undefined)
1578 obj.findImport(obj.symtable[@intFromEnum(loc.index)]).kind.global
1579 else
1580 obj.globals[symbol.index - obj.imported_globals_count].global_type;
1581 },
1480 }1582 }
1481 return wasm.wasm_globals.items[symbol.index].global_type;
1482}1583}
14831584
1484/// From a given symbol location, returns its `wasm.Type`.1585/// From a given symbol location, returns its `wasm.Type`.
1485/// Asserts the Symbol represents a function.1586/// Asserts the Symbol represents a function.
1486fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {1587fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
1487 const symbol = loc.getSymbol(wasm);1588 const symbol = wasm.symbolLocSymbol(loc);
1488 assert(symbol.tag == .function);1589 assert(symbol.tag == .function);
1489 const is_undefined = symbol.isUndefined();1590 const is_undefined = symbol.isUndefined();
1490 if (wasm.file(loc.file)) |obj_file| {1591 switch (loc.file) {
1491 if (is_undefined) {1592 .zig_object => {
1492 const ty_index = obj_file.import(loc.index).kind.function;1593 const zo = wasm.zig_object.?;
1493 return obj_file.funcTypes()[ty_index];1594 if (is_undefined) {
1494 }1595 const type_index = zo.imports.get(loc.index).?.kind.function;
1495 const type_index = obj_file.function(loc.index).type_index;1596 return zo.func_types.items[type_index];
1496 return obj_file.funcTypes()[type_index];1597 }
1497 }1598 const sym = zo.symbols.items[@intFromEnum(loc.index)];
1498 if (is_undefined) {1599 const type_index = zo.functions.items[sym.index].type_index;
1499 const ty_index = wasm.imports.get(loc).?.kind.function;1600 return zo.func_types.items[type_index];
1500 return wasm.func_types.items[ty_index];1601 },
1602 .none => {
1603 if (is_undefined) {
1604 const type_index = wasm.imports.get(loc).?.kind.function;
1605 return wasm.func_types.items[type_index];
1606 }
1607 return wasm.func_types.items[
1608 wasm.functions.get(.{
1609 .file = .none,
1610 .index = symbol.index,
1611 }).?.func.type_index
1612 ];
1613 },
1614 _ => {
1615 const obj = &wasm.objects.items[@intFromEnum(loc.file)];
1616 if (is_undefined) {
1617 const type_index = obj.findImport(obj.symtable[@intFromEnum(loc.index)]).kind.function;
1618 return obj.func_types[type_index];
1619 }
1620 const sym = obj.symtable[@intFromEnum(loc.index)];
1621 const type_index = obj.functions[sym.index - obj.imported_functions_count].type_index;
1622 return obj.func_types[type_index];
1623 },
1501 }1624 }
1502 return wasm.func_types.items[wasm.functions.get(.{ .file = loc.file, .index = symbol.index }).?.func.type_index];
1503}1625}
15041626
1505/// Returns the symbol index from a symbol of which its flag is set global,1627/// Returns the symbol index from a symbol of which its flag is set global,
...@@ -1508,7 +1630,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {...@@ -1508,7 +1630,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
1508/// and then returns the index to it.1630/// and then returns the index to it.
1509pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {1631pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {
1510 _ = lib_name;1632 _ = lib_name;
1511 return wasm.zigObjectPtr().?.getGlobalSymbol(wasm.base.comp.gpa, name);1633 return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name);
1512}1634}
15131635
1514/// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type.1636/// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type.
...@@ -1519,7 +1641,7 @@ pub fn getNavVAddr(...@@ -1519,7 +1641,7 @@ pub fn getNavVAddr(
1519 nav: InternPool.Nav.Index,1641 nav: InternPool.Nav.Index,
1520 reloc_info: link.File.RelocInfo,1642 reloc_info: link.File.RelocInfo,
1521) !u64 {1643) !u64 {
1522 return wasm.zigObjectPtr().?.getNavVAddr(wasm, pt, nav, reloc_info);1644 return wasm.zig_object.?.getNavVAddr(wasm, pt, nav, reloc_info);
1523}1645}
15241646
1525pub fn lowerUav(1647pub fn lowerUav(
...@@ -1529,11 +1651,11 @@ pub fn lowerUav(...@@ -1529,11 +1651,11 @@ pub fn lowerUav(
1529 explicit_alignment: Alignment,1651 explicit_alignment: Alignment,
1530 src_loc: Zcu.LazySrcLoc,1652 src_loc: Zcu.LazySrcLoc,
1531) !codegen.GenResult {1653) !codegen.GenResult {
1532 return wasm.zigObjectPtr().?.lowerUav(wasm, pt, uav, explicit_alignment, src_loc);1654 return wasm.zig_object.?.lowerUav(wasm, pt, uav, explicit_alignment, src_loc);
1533}1655}
15341656
1535pub fn getUavVAddr(wasm: *Wasm, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {1657pub fn getUavVAddr(wasm: *Wasm, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1536 return wasm.zigObjectPtr().?.getUavVAddr(wasm, uav, reloc_info);1658 return wasm.zig_object.?.getUavVAddr(wasm, uav, reloc_info);
1537}1659}
15381660
1539pub fn deleteExport(1661pub fn deleteExport(
...@@ -1542,7 +1664,7 @@ pub fn deleteExport(...@@ -1542,7 +1664,7 @@ pub fn deleteExport(
1542 name: InternPool.NullTerminatedString,1664 name: InternPool.NullTerminatedString,
1543) void {1665) void {
1544 if (wasm.llvm_object) |_| return;1666 if (wasm.llvm_object) |_| return;
1545 return wasm.zigObjectPtr().?.deleteExport(wasm, exported, name);1667 return wasm.zig_object.?.deleteExport(wasm, exported, name);
1546}1668}
15471669
1548pub fn updateExports(1670pub fn updateExports(
...@@ -1555,12 +1677,12 @@ pub fn updateExports(...@@ -1555,12 +1677,12 @@ pub fn updateExports(
1555 @panic("Attempted to compile for object format that was disabled by build configuration");1677 @panic("Attempted to compile for object format that was disabled by build configuration");
1556 }1678 }
1557 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices);1679 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices);
1558 return wasm.zigObjectPtr().?.updateExports(wasm, pt, exported, export_indices);1680 return wasm.zig_object.?.updateExports(wasm, pt, exported, export_indices);
1559}1681}
15601682
1561pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {1683pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
1562 if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);1684 if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
1563 return wasm.zigObjectPtr().?.freeDecl(wasm, decl_index);1685 return wasm.zig_object.?.freeDecl(wasm, decl_index);
1564}1686}
15651687
1566/// Assigns indexes to all indirect functions.1688/// Assigns indexes to all indirect functions.
...@@ -1570,7 +1692,7 @@ fn mapFunctionTable(wasm: *Wasm) void {...@@ -1570,7 +1692,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
1570 var it = wasm.function_table.iterator();1692 var it = wasm.function_table.iterator();
1571 var index: u32 = 1;1693 var index: u32 = 1;
1572 while (it.next()) |entry| {1694 while (it.next()) |entry| {
1573 const symbol = entry.key_ptr.*.getSymbol(wasm);1695 const symbol = wasm.symbolLocSymbol(entry.key_ptr.*);
1574 if (symbol.isAlive()) {1696 if (symbol.isAlive()) {
1575 entry.value_ptr.* = index;1697 entry.value_ptr.* = index;
1576 index += 1;1698 index += 1;
...@@ -1586,7 +1708,7 @@ fn mapFunctionTable(wasm: *Wasm) void {...@@ -1586,7 +1708,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
1586 } else if (index > 1) {1708 } else if (index > 1) {
1587 log.debug("Appending indirect function table", .{});1709 log.debug("Appending indirect function table", .{});
1588 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;1710 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
1589 const symbol = sym_loc.getSymbol(wasm);1711 const symbol = wasm.symbolLocSymbol(sym_loc);
1590 const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];1712 const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];
1591 table.limits = .{ .min = index, .max = index, .flags = 0x1 };1713 table.limits = .{ .min = index, .max = index, .flags = 0x1 };
1592 }1714 }
...@@ -1625,10 +1747,11 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -1625,10 +1747,11 @@ fn allocateAtoms(wasm: *Wasm) !void {
1625 // Ensure we get the original symbol, so we verify the correct symbol on whether1747 // Ensure we get the original symbol, so we verify the correct symbol on whether
1626 // it is dead or not and ensure an atom is removed when dead.1748 // it is dead or not and ensure an atom is removed when dead.
1627 // This is required as we may have parsed aliases into atoms.1749 // This is required as we may have parsed aliases into atoms.
1628 const sym = if (wasm.file(symbol_loc.file)) |obj_file|1750 const sym = switch (symbol_loc.file) {
1629 obj_file.symbol(symbol_loc.index).*1751 .zig_object => wasm.zig_object.?.symbols.items[@intFromEnum(symbol_loc.index)],
1630 else1752 .none => wasm.synthetic_symbols.items[@intFromEnum(symbol_loc.index)],
1631 wasm.synthetic_symbols.items[@intFromEnum(symbol_loc.index)];1753 _ => wasm.objects.items[@intFromEnum(symbol_loc.file)].symtable[@intFromEnum(symbol_loc.index)],
1754 };
16321755
1633 // Dead symbols must be unlinked from the linked-list to prevent them1756 // Dead symbols must be unlinked from the linked-list to prevent them
1634 // from being emit into the binary.1757 // from being emit into the binary.
...@@ -1647,7 +1770,7 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -1647,7 +1770,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
1647 offset = @intCast(atom.alignment.forward(offset));1770 offset = @intCast(atom.alignment.forward(offset));
1648 atom.offset = offset;1771 atom.offset = offset;
1649 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{1772 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{
1650 symbol_loc.getName(wasm),1773 wasm.symbolLocName(symbol_loc),
1651 offset,1774 offset,
1652 offset + atom.size,1775 offset + atom.size,
1653 atom.size,1776 atom.size,
...@@ -1663,7 +1786,7 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -1663,7 +1786,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
1663/// For each data symbol, sets the virtual address.1786/// For each data symbol, sets the virtual address.
1664fn allocateVirtualAddresses(wasm: *Wasm) void {1787fn allocateVirtualAddresses(wasm: *Wasm) void {
1665 for (wasm.resolved_symbols.keys()) |loc| {1788 for (wasm.resolved_symbols.keys()) |loc| {
1666 const symbol = loc.getSymbol(wasm);1789 const symbol = wasm.symbolLocSymbol(loc);
1667 if (symbol.tag != .data or symbol.isDead()) {1790 if (symbol.tag != .data or symbol.isDead()) {
1668 // Only data symbols have virtual addresses.1791 // Only data symbols have virtual addresses.
1669 // Dead symbols do not get allocated, so we don't need to set their virtual address either.1792 // Dead symbols do not get allocated, so we don't need to set their virtual address either.
...@@ -1676,10 +1799,11 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {...@@ -1676,10 +1799,11 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
16761799
1677 const atom = wasm.getAtom(atom_index);1800 const atom = wasm.getAtom(atom_index);
1678 const merge_segment = wasm.base.comp.config.output_mode != .Obj;1801 const merge_segment = wasm.base.comp.config.output_mode != .Obj;
1679 const segment_info = if (atom.file != .null)1802 const segment_info = switch (atom.file) {
1680 wasm.file(atom.file).?.segmentInfo()1803 .zig_object => wasm.zig_object.?.segment_info.items,
1681 else1804 .none => wasm.segment_info.values(),
1682 wasm.segment_info.values();1805 _ => wasm.objects.items[@intFromEnum(atom.file)].segment_info,
1806 };
1683 const segment_name = segment_info[symbol.index].outputName(merge_segment);1807 const segment_name = segment_info[symbol.index].outputName(merge_segment);
1684 const segment_index = wasm.data_segments.get(segment_name).?;1808 const segment_index = wasm.data_segments.get(segment_name).?;
1685 const segment = wasm.segments.items[segment_index];1809 const segment = wasm.segments.items[segment_index];
...@@ -1737,13 +1861,12 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -1737,13 +1861,12 @@ fn setupInitFunctions(wasm: *Wasm) !void {
1737 const gpa = wasm.base.comp.gpa;1861 const gpa = wasm.base.comp.gpa;
1738 const diags = &wasm.base.comp.link_diags;1862 const diags = &wasm.base.comp.link_diags;
1739 // There's no constructors for Zig so we can simply search through linked object files only.1863 // There's no constructors for Zig so we can simply search through linked object files only.
1740 for (wasm.objects.items) |file_index| {1864 for (wasm.objects.items, 0..) |*object, object_index| {
1741 const object: Object = wasm.files.items(.data)[@intFromEnum(file_index)].object;
1742 try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len);1865 try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len);
1743 for (object.init_funcs) |init_func| {1866 for (object.init_funcs) |init_func| {
1744 const symbol = object.symtable[init_func.symbol_index];1867 const symbol = object.symtable[init_func.symbol_index];
1745 const ty: std.wasm.Type = if (symbol.isUndefined()) ty: {1868 const ty: std.wasm.Type = if (symbol.isUndefined()) ty: {
1746 const imp: types.Import = object.findImport(symbol);1869 const imp: Import = object.findImport(symbol);
1747 break :ty object.func_types[imp.kind.function];1870 break :ty object.func_types[imp.kind.function];
1748 } else ty: {1871 } else ty: {
1749 const func_index = symbol.index - object.imported_functions_count;1872 const func_index = symbol.index - object.imported_functions_count;
...@@ -1757,10 +1880,13 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -1757,10 +1880,13 @@ fn setupInitFunctions(wasm: *Wasm) !void {
1757 log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)});1880 log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)});
1758 wasm.init_funcs.appendAssumeCapacity(.{1881 wasm.init_funcs.appendAssumeCapacity(.{
1759 .index = @enumFromInt(init_func.symbol_index),1882 .index = @enumFromInt(init_func.symbol_index),
1760 .file = file_index,1883 .file = @enumFromInt(object_index),
1761 .priority = init_func.priority,1884 .priority = init_func.priority,
1762 });1885 });
1763 try wasm.mark(.{ .index = @enumFromInt(init_func.symbol_index), .file = file_index });1886 try wasm.mark(.{
1887 .index = @enumFromInt(init_func.symbol_index),
1888 .file = @enumFromInt(object_index),
1889 });
1764 }1890 }
1765 }1891 }
17661892
...@@ -1834,7 +1960,7 @@ fn createSyntheticFunction(...@@ -1834,7 +1960,7 @@ fn createSyntheticFunction(
1834) !void {1960) !void {
1835 const gpa = wasm.base.comp.gpa;1961 const gpa = wasm.base.comp.gpa;
1836 const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol?1962 const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol?
1837 const symbol = loc.getSymbol(wasm);1963 const symbol = wasm.symbolLocSymbol(loc);
1838 if (symbol.isDead()) {1964 if (symbol.isDead()) {
1839 return;1965 return;
1840 }1966 }
...@@ -1843,13 +1969,13 @@ fn createSyntheticFunction(...@@ -1843,13 +1969,13 @@ fn createSyntheticFunction(
1843 const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count()));1969 const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count()));
1844 try wasm.functions.putNoClobber(1970 try wasm.functions.putNoClobber(
1845 gpa,1971 gpa,
1846 .{ .file = .null, .index = func_index },1972 .{ .file = .none, .index = func_index },
1847 .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index },1973 .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index },
1848 );1974 );
1849 symbol.index = func_index;1975 symbol.index = func_index;
18501976
1851 // create the atom that will be output into the final binary1977 // create the atom that will be output into the final binary
1852 const atom_index = try wasm.createAtom(loc.index, .null);1978 const atom_index = try wasm.createAtom(loc.index, .none);
1853 const atom = wasm.getAtomPtr(atom_index);1979 const atom = wasm.getAtomPtr(atom_index);
1854 atom.size = @intCast(function_body.items.len);1980 atom.size = @intCast(function_body.items.len);
1855 atom.code = function_body.moveToUnmanaged();1981 atom.code = function_body.moveToUnmanaged();
...@@ -1866,13 +1992,13 @@ pub fn createFunction(...@@ -1866,13 +1992,13 @@ pub fn createFunction(
1866 function_body: *std.ArrayList(u8),1992 function_body: *std.ArrayList(u8),
1867 relocations: *std.ArrayList(Relocation),1993 relocations: *std.ArrayList(Relocation),
1868) !Symbol.Index {1994) !Symbol.Index {
1869 return wasm.zigObjectPtr().?.createFunction(wasm, symbol_name, func_ty, function_body, relocations);1995 return wasm.zig_object.?.createFunction(wasm, symbol_name, func_ty, function_body, relocations);
1870}1996}
18711997
1872/// If required, sets the function index in the `start` section.1998/// If required, sets the function index in the `start` section.
1873fn setupStartSection(wasm: *Wasm) !void {1999fn setupStartSection(wasm: *Wasm) !void {
1874 if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| {2000 if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| {
1875 wasm.entry = loc.getSymbol(wasm).index;2001 wasm.entry = wasm.symbolLocSymbol(loc).index;
1876 }2002 }
1877}2003}
18782004
...@@ -1884,7 +2010,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {...@@ -1884,7 +2010,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
1884 if (!shared_memory) return;2010 if (!shared_memory) return;
18852011
1886 // ensure function is marked as we must emit it2012 // ensure function is marked as we must emit it
1887 wasm.findGlobalSymbol("__wasm_init_tls").?.getSymbol(wasm).mark();2013 wasm.symbolLocSymbol(wasm.findGlobalSymbol("__wasm_init_tls").?).mark();
18882014
1889 var function_body = std.ArrayList(u8).init(gpa);2015 var function_body = std.ArrayList(u8).init(gpa);
1890 defer function_body.deinit();2016 defer function_body.deinit();
...@@ -1905,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {...@@ -1905,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
19052031
1906 const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?;2032 const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?;
1907 try writer.writeByte(std.wasm.opcode(.global_set));2033 try writer.writeByte(std.wasm.opcode(.global_set));
1908 try leb.writeUleb128(writer, tls_base_loc.getSymbol(wasm).index);2034 try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index);
19092035
1910 // load stack values for the bulk-memory operation2036 // load stack values for the bulk-memory operation
1911 {2037 {
...@@ -1933,8 +2059,8 @@ fn initializeTLSFunction(wasm: *Wasm) !void {...@@ -1933,8 +2059,8 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
1933 // generated by the linker.2059 // generated by the linker.
1934 if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| {2060 if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| {
1935 try writer.writeByte(std.wasm.opcode(.call));2061 try writer.writeByte(std.wasm.opcode(.call));
1936 try leb.writeUleb128(writer, loc.getSymbol(wasm).index);2062 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
1937 loc.getSymbol(wasm).mark();2063 wasm.symbolLocSymbol(loc).mark();
1938 }2064 }
19392065
1940 try writer.writeByte(std.wasm.opcode(.end));2066 try writer.writeByte(std.wasm.opcode(.end));
...@@ -1950,27 +2076,27 @@ fn setupImports(wasm: *Wasm) !void {...@@ -1950,27 +2076,27 @@ fn setupImports(wasm: *Wasm) !void {
1950 const gpa = wasm.base.comp.gpa;2076 const gpa = wasm.base.comp.gpa;
1951 log.debug("Merging imports", .{});2077 log.debug("Merging imports", .{});
1952 for (wasm.resolved_symbols.keys()) |symbol_loc| {2078 for (wasm.resolved_symbols.keys()) |symbol_loc| {
1953 const obj_file = wasm.file(symbol_loc.file) orelse {2079 const object_id = symbol_loc.file.unwrap() orelse {
1954 // Synthetic symbols will already exist in the `import` section2080 // Synthetic symbols will already exist in the `import` section
1955 continue;2081 continue;
1956 };2082 };
19572083
1958 const symbol = symbol_loc.getSymbol(wasm);2084 const symbol = wasm.symbolLocSymbol(symbol_loc);
1959 if (symbol.isDead() or2085 if (symbol.isDead() or
1960 !symbol.requiresImport() or2086 !symbol.requiresImport() or
1961 std.mem.eql(u8, symbol_loc.getName(wasm), "__indirect_function_table"))2087 std.mem.eql(u8, wasm.symbolLocName(symbol_loc), "__indirect_function_table"))
1962 {2088 {
1963 continue;2089 continue;
1964 }2090 }
19652091
1966 log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)});2092 log.debug("Symbol '{s}' will be imported from the host", .{wasm.symbolLocName(symbol_loc)});
1967 const import = obj_file.import(symbol_loc.index);2093 const import = objectImport(wasm, object_id, symbol_loc.index);
19682094
1969 // We copy the import to a new import to ensure the names contain references2095 // We copy the import to a new import to ensure the names contain references
1970 // to the internal string table, rather than of the object file.2096 // to the internal string table, rather than of the object file.
1971 const new_imp: types.Import = .{2097 const new_imp: Import = .{
1972 .module_name = try wasm.string_table.put(gpa, obj_file.string(import.module_name)),2098 .module_name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.module_name)),
1973 .name = try wasm.string_table.put(gpa, obj_file.string(import.name)),2099 .name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.name)),
1974 .kind = import.kind,2100 .kind = import.kind,
1975 };2101 };
1976 // TODO: De-duplicate imports when they contain the same names and type2102 // TODO: De-duplicate imports when they contain the same names and type
...@@ -1983,8 +2109,8 @@ fn setupImports(wasm: *Wasm) !void {...@@ -1983,8 +2109,8 @@ fn setupImports(wasm: *Wasm) !void {
1983 var table_index: u32 = 0;2109 var table_index: u32 = 0;
1984 var it = wasm.imports.iterator();2110 var it = wasm.imports.iterator();
1985 while (it.next()) |entry| {2111 while (it.next()) |entry| {
1986 const symbol = entry.key_ptr.*.getSymbol(wasm);2112 const symbol = wasm.symbolLocSymbol(entry.key_ptr.*);
1987 const import: types.Import = entry.value_ptr.*;2113 const import: Import = entry.value_ptr.*;
1988 switch (import.kind) {2114 switch (import.kind) {
1989 .function => {2115 .function => {
1990 symbol.index = function_index;2116 symbol.index = function_index;
...@@ -2021,12 +2147,12 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2021,12 +2147,12 @@ fn mergeSections(wasm: *Wasm) !void {
2021 defer removed_duplicates.deinit();2147 defer removed_duplicates.deinit();
20222148
2023 for (wasm.resolved_symbols.keys()) |sym_loc| {2149 for (wasm.resolved_symbols.keys()) |sym_loc| {
2024 const obj_file = wasm.file(sym_loc.file) orelse {2150 const object_id = sym_loc.file.unwrap() orelse {
2025 // Synthetic symbols already live in the corresponding sections.2151 // Synthetic symbols already live in the corresponding sections.
2026 continue;2152 continue;
2027 };2153 };
20282154
2029 const symbol = obj_file.symbol(sym_loc.index);2155 const symbol = objectSymbol(wasm, object_id, sym_loc.index);
2030 if (symbol.isDead() or symbol.isUndefined()) {2156 if (symbol.isDead() or symbol.isUndefined()) {
2031 // Skip undefined symbols as they go in the `import` section2157 // Skip undefined symbols as they go in the `import` section
2032 continue;2158 continue;
...@@ -2044,7 +2170,7 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2044,7 +2170,7 @@ fn mergeSections(wasm: *Wasm) !void {
2044 // we only emit a single function, instead of duplicates.2170 // we only emit a single function, instead of duplicates.
2045 // we favor keeping the global over a local.2171 // we favor keeping the global over a local.
2046 const original_loc: SymbolLoc = .{ .file = gop.key_ptr.file, .index = gop.value_ptr.sym_index };2172 const original_loc: SymbolLoc = .{ .file = gop.key_ptr.file, .index = gop.value_ptr.sym_index };
2047 const original_sym = original_loc.getSymbol(wasm);2173 const original_sym = wasm.symbolLocSymbol(original_loc);
2048 if (original_sym.isLocal() and symbol.isGlobal()) {2174 if (original_sym.isLocal() and symbol.isGlobal()) {
2049 original_sym.unmark();2175 original_sym.unmark();
2050 try wasm.discarded.put(gpa, original_loc, sym_loc);2176 try wasm.discarded.put(gpa, original_loc, sym_loc);
...@@ -2056,20 +2182,23 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2056,20 +2182,23 @@ fn mergeSections(wasm: *Wasm) !void {
2056 continue;2182 continue;
2057 }2183 }
2058 }2184 }
2059 gop.value_ptr.* = .{ .func = obj_file.function(sym_loc.index), .sym_index = sym_loc.index };2185 gop.value_ptr.* = .{
2186 .func = objectFunction(wasm, object_id, sym_loc.index),
2187 .sym_index = sym_loc.index,
2188 };
2060 symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count;2189 symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count;
2061 },2190 },
2062 .global => {2191 .global => {
2063 const index = symbol.index - obj_file.importedFunctions();2192 const index = symbol.index - objectImportedFunctions(wasm, object_id);
2064 const original_global = obj_file.globals()[index];2193 const original_global = objectGlobals(wasm, object_id)[index];
2065 symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;2194 symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;
2066 try wasm.wasm_globals.append(gpa, original_global);2195 try wasm.wasm_globals.append(gpa, original_global);
2067 },2196 },
2068 .table => {2197 .table => {
2069 const index = symbol.index - obj_file.importedFunctions();2198 const index = symbol.index - objectImportedFunctions(wasm, object_id);
2070 // assert it's a regular relocatable object file as `ZigObject` will never2199 // assert it's a regular relocatable object file as `ZigObject` will never
2071 // contain a table.2200 // contain a table.
2072 const original_table = obj_file.object.tables[index];2201 const original_table = wasm.objectById(object_id).?.tables[index];
2073 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;2202 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;
2074 try wasm.tables.append(gpa, original_table);2203 try wasm.tables.append(gpa, original_table);
2075 },2204 },
...@@ -2081,7 +2210,7 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2081,7 +2210,7 @@ fn mergeSections(wasm: *Wasm) !void {
2081 // For any removed duplicates, remove them from the resolved symbols list2210 // For any removed duplicates, remove them from the resolved symbols list
2082 for (removed_duplicates.items) |sym_loc| {2211 for (removed_duplicates.items) |sym_loc| {
2083 assert(wasm.resolved_symbols.swapRemove(sym_loc));2212 assert(wasm.resolved_symbols.swapRemove(sym_loc));
2084 gc_log.debug("Removed duplicate for function '{s}'", .{sym_loc.getName(wasm)});2213 gc_log.debug("Removed duplicate for function '{s}'", .{wasm.symbolLocName(sym_loc)});
2085 }2214 }
20862215
2087 log.debug("Merged ({d}) functions", .{wasm.functions.count()});2216 log.debug("Merged ({d}) functions", .{wasm.functions.count()});
...@@ -2102,26 +2231,26 @@ fn mergeTypes(wasm: *Wasm) !void {...@@ -2102,26 +2231,26 @@ fn mergeTypes(wasm: *Wasm) !void {
2102 defer dirty.deinit();2231 defer dirty.deinit();
21032232
2104 for (wasm.resolved_symbols.keys()) |sym_loc| {2233 for (wasm.resolved_symbols.keys()) |sym_loc| {
2105 const obj_file = wasm.file(sym_loc.file) orelse {2234 const object_id = sym_loc.file.unwrap() orelse {
2106 // zig code-generated symbols are already present in final type section2235 // zig code-generated symbols are already present in final type section
2107 continue;2236 continue;
2108 };2237 };
21092238
2110 const symbol = obj_file.symbol(sym_loc.index);2239 const symbol = objectSymbol(wasm, object_id, sym_loc.index);
2111 if (symbol.tag != .function or symbol.isDead()) {2240 if (symbol.tag != .function or symbol.isDead()) {
2112 // Only functions have types. Only retrieve the type of referenced functions.2241 // Only functions have types. Only retrieve the type of referenced functions.
2113 continue;2242 continue;
2114 }2243 }
21152244
2116 if (symbol.isUndefined()) {2245 if (symbol.isUndefined()) {
2117 log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(wasm)});2246 log.debug("Adding type from extern function '{s}'", .{wasm.symbolLocName(sym_loc)});
2118 const import: *types.Import = wasm.imports.getPtr(sym_loc) orelse continue;2247 const import: *Import = wasm.imports.getPtr(sym_loc) orelse continue;
2119 const original_type = obj_file.funcTypes()[import.kind.function];2248 const original_type = objectFuncTypes(wasm, object_id)[import.kind.function];
2120 import.kind.function = try wasm.putOrGetFuncType(original_type);2249 import.kind.function = try wasm.putOrGetFuncType(original_type);
2121 } else if (!dirty.contains(symbol.index)) {2250 } else if (!dirty.contains(symbol.index)) {
2122 log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)});2251 log.debug("Adding type from function '{s}'", .{wasm.symbolLocName(sym_loc)});
2123 const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func;2252 const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func;
2124 func.type_index = try wasm.putOrGetFuncType(obj_file.funcTypes()[func.type_index]);2253 func.type_index = try wasm.putOrGetFuncType(objectFuncTypes(wasm, object_id)[func.type_index]);
2125 dirty.putAssumeCapacityNoClobber(symbol.index, {});2254 dirty.putAssumeCapacityNoClobber(symbol.index, {});
2126 }2255 }
2127 }2256 }
...@@ -2142,7 +2271,7 @@ fn checkExportNames(wasm: *Wasm) !void {...@@ -2142,7 +2271,7 @@ fn checkExportNames(wasm: *Wasm) !void {
2142 continue;2271 continue;
2143 };2272 };
21442273
2145 const symbol = loc.getSymbol(wasm);2274 const symbol = wasm.symbolLocSymbol(loc);
2146 symbol.setFlag(.WASM_SYM_EXPORTED);2275 symbol.setFlag(.WASM_SYM_EXPORTED);
2147 }2276 }
21482277
...@@ -2159,15 +2288,15 @@ fn setupExports(wasm: *Wasm) !void {...@@ -2159,15 +2288,15 @@ fn setupExports(wasm: *Wasm) !void {
2159 log.debug("Building exports from symbols", .{});2288 log.debug("Building exports from symbols", .{});
21602289
2161 for (wasm.resolved_symbols.keys()) |sym_loc| {2290 for (wasm.resolved_symbols.keys()) |sym_loc| {
2162 const symbol = sym_loc.getSymbol(wasm);2291 const symbol = wasm.symbolLocSymbol(sym_loc);
2163 if (!symbol.isExported(comp.config.rdynamic)) continue;2292 if (!symbol.isExported(comp.config.rdynamic)) continue;
21642293
2165 const sym_name = sym_loc.getName(wasm);2294 const sym_name = wasm.symbolLocName(sym_loc);
2166 const export_name = if (sym_loc.file == .null)2295 const export_name = if (sym_loc.file == .none)
2167 symbol.name2296 symbol.name
2168 else2297 else
2169 try wasm.string_table.put(gpa, sym_name);2298 try wasm.string_table.put(gpa, sym_name);
2170 const exp: types.Export = if (symbol.tag == .data) exp: {2299 const exp: Export = if (symbol.tag == .data) exp: {
2171 const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));2300 const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));
2172 try wasm.wasm_globals.append(gpa, .{2301 try wasm.wasm_globals.append(gpa, .{
2173 .global_type = .{ .valtype = .i32, .mutable = false },2302 .global_type = .{ .valtype = .i32, .mutable = false },
...@@ -2206,7 +2335,7 @@ fn setupStart(wasm: *Wasm) !void {...@@ -2206,7 +2335,7 @@ fn setupStart(wasm: *Wasm) !void {
2206 return error.FlushFailure;2335 return error.FlushFailure;
2207 };2336 };
22082337
2209 const symbol = symbol_loc.getSymbol(wasm);2338 const symbol = wasm.symbolLocSymbol(symbol_loc);
2210 if (symbol.tag != .function) {2339 if (symbol.tag != .function) {
2211 var err = try diags.addErrorWithNotes(0);2340 var err = try diags.addErrorWithNotes(0);
2212 try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name});2341 try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name});
...@@ -2240,7 +2369,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2240,7 +2369,7 @@ fn setupMemory(wasm: *Wasm) !void {
2240 const is_obj = comp.config.output_mode == .Obj;2369 const is_obj = comp.config.output_mode == .Obj;
22412370
2242 const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: {2371 const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: {
2243 const sym = loc.getSymbol(wasm);2372 const sym = wasm.symbolLocSymbol(loc);
2244 break :index sym.index - wasm.imported_globals_count;2373 break :index sym.index - wasm.imported_globals_count;
2245 } else null;2374 } else null;
22462375
...@@ -2262,15 +2391,15 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2262,15 +2391,15 @@ fn setupMemory(wasm: *Wasm) !void {
2262 // set TLS-related symbols2391 // set TLS-related symbols
2263 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {2392 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
2264 if (wasm.findGlobalSymbol("__tls_size")) |loc| {2393 if (wasm.findGlobalSymbol("__tls_size")) |loc| {
2265 const sym = loc.getSymbol(wasm);2394 const sym = wasm.symbolLocSymbol(loc);
2266 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size);2395 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size);
2267 }2396 }
2268 if (wasm.findGlobalSymbol("__tls_align")) |loc| {2397 if (wasm.findGlobalSymbol("__tls_align")) |loc| {
2269 const sym = loc.getSymbol(wasm);2398 const sym = wasm.symbolLocSymbol(loc);
2270 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);2399 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);
2271 }2400 }
2272 if (wasm.findGlobalSymbol("__tls_base")) |loc| {2401 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
2273 const sym = loc.getSymbol(wasm);2402 const sym = wasm.symbolLocSymbol(loc);
2274 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory)2403 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory)
2275 @as(i32, 0)2404 @as(i32, 0)
2276 else2405 else
...@@ -2288,7 +2417,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2288,7 +2417,7 @@ fn setupMemory(wasm: *Wasm) !void {
2288 // align to pointer size2417 // align to pointer size
2289 memory_ptr = mem.alignForward(u64, memory_ptr, 4);2418 memory_ptr = mem.alignForward(u64, memory_ptr, 4);
2290 const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data);2419 const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data);
2291 const sym = loc.getSymbol(wasm);2420 const sym = wasm.symbolLocSymbol(loc);
2292 sym.mark();2421 sym.mark();
2293 sym.virtual_address = @as(u32, @intCast(memory_ptr));2422 sym.virtual_address = @as(u32, @intCast(memory_ptr));
2294 memory_ptr += 4;2423 memory_ptr += 4;
...@@ -2305,7 +2434,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2305,7 +2434,7 @@ fn setupMemory(wasm: *Wasm) !void {
2305 // One of the linked object files has a reference to the __heap_base symbol.2434 // One of the linked object files has a reference to the __heap_base symbol.
2306 // We must set its virtual address so it can be used in relocations.2435 // We must set its virtual address so it can be used in relocations.
2307 if (wasm.findGlobalSymbol("__heap_base")) |loc| {2436 if (wasm.findGlobalSymbol("__heap_base")) |loc| {
2308 const symbol = loc.getSymbol(wasm);2437 const symbol = wasm.symbolLocSymbol(loc);
2309 symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr));2438 symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr));
2310 }2439 }
23112440
...@@ -2335,7 +2464,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2335,7 +2464,7 @@ fn setupMemory(wasm: *Wasm) !void {
2335 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});2464 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});
23362465
2337 if (wasm.findGlobalSymbol("__heap_end")) |loc| {2466 if (wasm.findGlobalSymbol("__heap_end")) |loc| {
2338 const symbol = loc.getSymbol(wasm);2467 const symbol = wasm.symbolLocSymbol(loc);
2339 symbol.virtual_address = @as(u32, @intCast(memory_ptr));2468 symbol.virtual_address = @as(u32, @intCast(memory_ptr));
2340 }2469 }
23412470
...@@ -2364,18 +2493,17 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2364,18 +2493,17 @@ fn setupMemory(wasm: *Wasm) !void {
2364/// From a given object's index and the index of the segment, returns the corresponding2493/// From a given object's index and the index of the segment, returns the corresponding
2365/// index of the segment within the final data section. When the segment does not yet2494/// index of the segment within the final data section. When the segment does not yet
2366/// exist, a new one will be initialized and appended. The new index will be returned in that case.2495/// exist, a new one will be initialized and appended. The new index will be returned in that case.
2367pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Symbol.Index) !u32 {2496pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !u32 {
2368 const comp = wasm.base.comp;2497 const comp = wasm.base.comp;
2369 const gpa = comp.gpa;2498 const gpa = comp.gpa;
2370 const diags = &wasm.base.comp.link_diags;2499 const diags = &wasm.base.comp.link_diags;
2371 const obj_file = wasm.file(file_index).?;2500 const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)];
2372 const symbol = obj_file.symbols()[@intFromEnum(symbol_index)];
2373 const index: u32 = @intCast(wasm.segments.items.len);2501 const index: u32 = @intCast(wasm.segments.items.len);
2374 const shared_memory = comp.config.shared_memory;2502 const shared_memory = comp.config.shared_memory;
23752503
2376 switch (symbol.tag) {2504 switch (symbol.tag) {
2377 .data => {2505 .data => {
2378 const segment_info = obj_file.segmentInfo()[symbol.index];2506 const segment_info = objectSegmentInfo(wasm, object_id)[symbol.index];
2379 const merge_segment = comp.config.output_mode != .Obj;2507 const merge_segment = comp.config.output_mode != .Obj;
2380 const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment));2508 const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment));
2381 if (!result.found_existing) {2509 if (!result.found_existing) {
...@@ -2404,7 +2532,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym...@@ -2404,7 +2532,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym
2404 break :blk index;2532 break :blk index;
2405 },2533 },
2406 .section => {2534 .section => {
2407 const section_name = obj_file.symbolName(symbol_index);2535 const section_name = objectSymbolName(wasm, object_id, symbol_index);
2408 if (mem.eql(u8, section_name, ".debug_info")) {2536 if (mem.eql(u8, section_name, ".debug_info")) {
2409 return wasm.debug_info_index orelse blk: {2537 return wasm.debug_info_index orelse blk: {
2410 wasm.debug_info_index = index;2538 wasm.debug_info_index = index;
...@@ -2456,7 +2584,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym...@@ -2456,7 +2584,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym
2456 } else {2584 } else {
2457 var err = try diags.addErrorWithNotes(1);2585 var err = try diags.addErrorWithNotes(1);
2458 try err.addMsg("found unknown section '{s}'", .{section_name});2586 try err.addMsg("found unknown section '{s}'", .{section_name});
2459 try err.addNote("defined in '{s}'", .{obj_file.path()});2587 try err.addNote("defined in '{s}'", .{objectPath(wasm, object_id)});
2460 return error.UnexpectedValue;2588 return error.UnexpectedValue;
2461 }2589 }
2462 },2590 },
...@@ -2523,7 +2651,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2523,7 +2651,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2523 const link_libcpp = comp.config.link_libcpp;2651 const link_libcpp = comp.config.link_libcpp;
2524 const wasi_exec_model = comp.config.wasi_exec_model;2652 const wasi_exec_model = comp.config.wasi_exec_model;
25252653
2526 if (wasm.zigObjectPtr()) |zig_object| {2654 if (wasm.zig_object) |zig_object| {
2527 try zig_object.flushModule(wasm, tid);2655 try zig_object.flushModule(wasm, tid);
2528 }2656 }
25292657
...@@ -2578,17 +2706,17 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2578,17 +2706,17 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2578 log.warn("Unexpected file format at path: '{s}'", .{path});2706 log.warn("Unexpected file format at path: '{s}'", .{path});
2579 }2707 }
25802708
2581 if (wasm.zig_object_index != .null) {2709 if (wasm.zig_object != null) {
2582 try wasm.resolveSymbolsInObject(wasm.zig_object_index);2710 try wasm.resolveSymbolsInObject(.zig_object);
2583 }2711 }
2584 if (diags.hasErrors()) return error.FlushFailure;2712 if (diags.hasErrors()) return error.FlushFailure;
2585 for (wasm.objects.items) |object_index| {2713 for (0..wasm.objects.items.len) |object_index| {
2586 try wasm.resolveSymbolsInObject(object_index);2714 try wasm.resolveSymbolsInObject(@enumFromInt(object_index));
2587 }2715 }
2588 if (diags.hasErrors()) return error.FlushFailure;2716 if (diags.hasErrors()) return error.FlushFailure;
25892717
2590 var emit_features_count: u32 = 0;2718 var emit_features_count: u32 = 0;
2591 var enabled_features: [@typeInfo(types.Feature.Tag).@"enum".fields.len]bool = undefined;2719 var enabled_features: [@typeInfo(Feature.Tag).@"enum".fields.len]bool = undefined;
2592 try wasm.validateFeatures(&enabled_features, &emit_features_count);2720 try wasm.validateFeatures(&enabled_features, &emit_features_count);
2593 try wasm.resolveSymbolsInArchives();2721 try wasm.resolveSymbolsInArchives();
2594 if (diags.hasErrors()) return error.FlushFailure;2722 if (diags.hasErrors()) return error.FlushFailure;
...@@ -2622,7 +2750,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2622,7 +2750,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2622/// Writes the WebAssembly in-memory module to the file2750/// Writes the WebAssembly in-memory module to the file
2623fn writeToFile(2751fn writeToFile(
2624 wasm: *Wasm,2752 wasm: *Wasm,
2625 enabled_features: [@typeInfo(types.Feature.Tag).@"enum".fields.len]bool,2753 enabled_features: [@typeInfo(Feature.Tag).@"enum".fields.len]bool,
2626 feature_count: u32,2754 feature_count: u32,
2627 arena: Allocator,2755 arena: Allocator,
2628) !void {2756) !void {
...@@ -2688,14 +2816,14 @@ fn writeToFile(...@@ -2688,14 +2816,14 @@ fn writeToFile(
26882816
2689 var it = wasm.imports.iterator();2817 var it = wasm.imports.iterator();
2690 while (it.next()) |entry| {2818 while (it.next()) |entry| {
2691 assert(entry.key_ptr.*.getSymbol(wasm).isUndefined());2819 assert(wasm.symbolLocSymbol(entry.key_ptr.*).isUndefined());
2692 const import = entry.value_ptr.*;2820 const import = entry.value_ptr.*;
2693 try wasm.emitImport(binary_writer, import);2821 try wasm.emitImport(binary_writer, import);
2694 }2822 }
26952823
2696 if (import_memory) {2824 if (import_memory) {
2697 const mem_name = if (is_obj) "__linear_memory" else "memory";2825 const mem_name = if (is_obj) "__linear_memory" else "memory";
2698 const mem_imp: types.Import = .{2826 const mem_imp: Import = .{
2699 .module_name = try wasm.string_table.put(gpa, wasm.host_name),2827 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
2700 .name = try wasm.string_table.put(gpa, mem_name),2828 .name = try wasm.string_table.put(gpa, mem_name),
2701 .kind = .{ .memory = wasm.memories.limits },2829 .kind = .{ .memory = wasm.memories.limits },
...@@ -2829,7 +2957,7 @@ fn writeToFile(...@@ -2829,7 +2957,7 @@ fn writeToFile(
2829 const header_offset = try reserveVecSectionHeader(&binary_bytes);2957 const header_offset = try reserveVecSectionHeader(&binary_bytes);
28302958
2831 const table_loc = wasm.findGlobalSymbol("__indirect_function_table").?;2959 const table_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
2832 const table_sym = table_loc.getSymbol(wasm);2960 const table_sym = wasm.symbolLocSymbol(table_loc);
28332961
2834 const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually2962 const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually
2835 try leb.writeUleb128(binary_writer, flags);2963 try leb.writeUleb128(binary_writer, flags);
...@@ -2843,7 +2971,7 @@ fn writeToFile(...@@ -2843,7 +2971,7 @@ fn writeToFile(
2843 try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.function_table.count())));2971 try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.function_table.count())));
2844 var symbol_it = wasm.function_table.keyIterator();2972 var symbol_it = wasm.function_table.keyIterator();
2845 while (symbol_it.next()) |symbol_loc_ptr| {2973 while (symbol_it.next()) |symbol_loc_ptr| {
2846 const sym = symbol_loc_ptr.getSymbol(wasm);2974 const sym = wasm.symbolLocSymbol(symbol_loc_ptr.*);
2847 std.debug.assert(sym.isAlive());2975 std.debug.assert(sym.isAlive());
2848 std.debug.assert(sym.index < wasm.functions.count() + wasm.imported_functions_count);2976 std.debug.assert(sym.index < wasm.functions.count() + wasm.imported_functions_count);
2849 try leb.writeUleb128(binary_writer, sym.index);2977 try leb.writeUleb128(binary_writer, sym.index);
...@@ -3183,7 +3311,7 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con...@@ -3183,7 +3311,7 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con
3183 try leb.writeUleb128(writer, features_count);3311 try leb.writeUleb128(writer, features_count);
3184 for (enabled_features, 0..) |enabled, feature_index| {3312 for (enabled_features, 0..) |enabled, feature_index| {
3185 if (enabled) {3313 if (enabled) {
3186 const feature: types.Feature = .{ .prefix = .used, .tag = @as(types.Feature.Tag, @enumFromInt(feature_index)) };3314 const feature: Feature = .{ .prefix = .used, .tag = @as(Feature.Tag, @enumFromInt(feature_index)) };
3187 try leb.writeUleb128(writer, @intFromEnum(feature.prefix));3315 try leb.writeUleb128(writer, @intFromEnum(feature.prefix));
3188 var buf: [100]u8 = undefined;3316 var buf: [100]u8 = undefined;
3189 const string = try std.fmt.bufPrint(&buf, "{}", .{feature.tag});3317 const string = try std.fmt.bufPrint(&buf, "{}", .{feature.tag});
...@@ -3219,11 +3347,11 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem...@@ -3219,11 +3347,11 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem
3219 var segments = try std.ArrayList(Name).initCapacity(arena, wasm.data_segments.count());3347 var segments = try std.ArrayList(Name).initCapacity(arena, wasm.data_segments.count());
32203348
3221 for (wasm.resolved_symbols.keys()) |sym_loc| {3349 for (wasm.resolved_symbols.keys()) |sym_loc| {
3222 const symbol = sym_loc.getSymbol(wasm).*;3350 const symbol = wasm.symbolLocSymbol(sym_loc).*;
3223 if (symbol.isDead()) {3351 if (symbol.isDead()) {
3224 continue;3352 continue;
3225 }3353 }
3226 const name = sym_loc.getName(wasm);3354 const name = wasm.symbolLocName(sym_loc);
3227 switch (symbol.tag) {3355 switch (symbol.tag) {
3228 .function => {3356 .function => {
3229 const gop = funcs.getOrPutAssumeCapacity(symbol.index);3357 const gop = funcs.getOrPutAssumeCapacity(symbol.index);
...@@ -3320,7 +3448,7 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {...@@ -3320,7 +3448,7 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
3320 try writer.writeByte(std.wasm.opcode(.end));3448 try writer.writeByte(std.wasm.opcode(.end));
3321}3449}
33223450
3323fn emitImport(wasm: *Wasm, writer: anytype, import: types.Import) !void {3451fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void {
3324 const module_name = wasm.string_table.get(import.module_name);3452 const module_name = wasm.string_table.get(import.module_name);
3325 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));3453 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));
3326 try writer.writeAll(module_name);3454 try writer.writeAll(module_name);
...@@ -3800,7 +3928,7 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:...@@ -3800,7 +3928,7 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
3800 // meta data version, which is currently '2'3928 // meta data version, which is currently '2'
3801 try leb.writeUleb128(writer, @as(u32, 2));3929 try leb.writeUleb128(writer, @as(u32, 2));
38023930
3803 // For each subsection type (found in types.Subsection) we can emit a section.3931 // For each subsection type (found in Subsection) we can emit a section.
3804 // Currently, we only support emitting segment info and the symbol table.3932 // Currently, we only support emitting segment info and the symbol table.
3805 try wasm.emitSymbolTable(binary_bytes, symbol_table);3933 try wasm.emitSymbolTable(binary_bytes, symbol_table);
3806 try wasm.emitSegmentInfo(binary_bytes);3934 try wasm.emitSegmentInfo(binary_bytes);
...@@ -3812,12 +3940,12 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:...@@ -3812,12 +3940,12 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
3812fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {3940fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {
3813 const writer = binary_bytes.writer();3941 const writer = binary_bytes.writer();
38143942
3815 try leb.writeUleb128(writer, @intFromEnum(types.SubsectionType.WASM_SYMBOL_TABLE));3943 try leb.writeUleb128(writer, @intFromEnum(SubsectionType.WASM_SYMBOL_TABLE));
3816 const table_offset = binary_bytes.items.len;3944 const table_offset = binary_bytes.items.len;
38173945
3818 var symbol_count: u32 = 0;3946 var symbol_count: u32 = 0;
3819 for (wasm.resolved_symbols.keys()) |sym_loc| {3947 for (wasm.resolved_symbols.keys()) |sym_loc| {
3820 const symbol = sym_loc.getSymbol(wasm).*;3948 const symbol = wasm.symbolLocSymbol(sym_loc).*;
3821 if (symbol.tag == .dead) continue; // Do not emit dead symbols3949 if (symbol.tag == .dead) continue; // Do not emit dead symbols
3822 try symbol_table.putNoClobber(sym_loc, symbol_count);3950 try symbol_table.putNoClobber(sym_loc, symbol_count);
3823 symbol_count += 1;3951 symbol_count += 1;
...@@ -3825,7 +3953,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:...@@ -3825,7 +3953,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
3825 try leb.writeUleb128(writer, @intFromEnum(symbol.tag));3953 try leb.writeUleb128(writer, @intFromEnum(symbol.tag));
3826 try leb.writeUleb128(writer, symbol.flags);3954 try leb.writeUleb128(writer, symbol.flags);
38273955
3828 const sym_name = sym_loc.getName(wasm);3956 const sym_name = wasm.symbolLocName(sym_loc);
3829 switch (symbol.tag) {3957 switch (symbol.tag) {
3830 .data => {3958 .data => {
3831 try leb.writeUleb128(writer, @as(u32, @intCast(sym_name.len)));3959 try leb.writeUleb128(writer, @as(u32, @intCast(sym_name.len)));
...@@ -3860,7 +3988,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:...@@ -3860,7 +3988,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
38603988
3861fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {3989fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
3862 const writer = binary_bytes.writer();3990 const writer = binary_bytes.writer();
3863 try leb.writeUleb128(writer, @intFromEnum(types.SubsectionType.WASM_SEGMENT_INFO));3991 try leb.writeUleb128(writer, @intFromEnum(SubsectionType.WASM_SEGMENT_INFO));
3864 const segment_offset = binary_bytes.items.len;3992 const segment_offset = binary_bytes.items.len;
38653993
3866 try leb.writeUleb128(writer, @as(u32, @intCast(wasm.segment_info.count())));3994 try leb.writeUleb128(writer, @as(u32, @intCast(wasm.segment_info.count())));
...@@ -4030,22 +4158,22 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {...@@ -4030,22 +4158,22 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {
4030/// Asserts declaration has an associated `Atom`.4158/// Asserts declaration has an associated `Atom`.
4031/// Returns the index into the list of types.4159/// Returns the index into the list of types.
4032pub fn storeNavType(wasm: *Wasm, nav: InternPool.Nav.Index, func_type: std.wasm.Type) !u32 {4160pub fn storeNavType(wasm: *Wasm, nav: InternPool.Nav.Index, func_type: std.wasm.Type) !u32 {
4033 return wasm.zigObjectPtr().?.storeDeclType(wasm.base.comp.gpa, nav, func_type);4161 return wasm.zig_object.?.storeDeclType(wasm.base.comp.gpa, nav, func_type);
4034}4162}
40354163
4036/// Returns the symbol index of the error name table.4164/// Returns the symbol index of the error name table.
4037///4165///
4038/// When the symbol does not yet exist, it will create a new one instead.4166/// When the symbol does not yet exist, it will create a new one instead.
4039pub fn getErrorTableSymbol(wasm_file: *Wasm, pt: Zcu.PerThread) !u32 {4167pub fn getErrorTableSymbol(wasm: *Wasm, pt: Zcu.PerThread) !u32 {
4040 const sym_index = try wasm_file.zigObjectPtr().?.getErrorTableSymbol(wasm_file, pt);4168 const sym_index = try wasm.zig_object.?.getErrorTableSymbol(wasm, pt);
4041 return @intFromEnum(sym_index);4169 return @intFromEnum(sym_index);
4042}4170}
40434171
4044/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.4172/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.
4045/// When the index was not found, a new `Atom` will be created, and its index will be returned.4173/// When the index was not found, a new `Atom` will be created, and its index will be returned.
4046/// The newly created Atom is empty with default fields as specified by `Atom.empty`.4174/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
4047pub fn getOrCreateAtomForNav(wasm_file: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !Atom.Index {4175pub fn getOrCreateAtomForNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !Atom.Index {
4048 return wasm_file.zigObjectPtr().?.getOrCreateAtomForNav(wasm_file, pt, nav);4176 return wasm.zig_object.?.getOrCreateAtomForNav(wasm, pt, nav);
4049}4177}
40504178
4051/// Verifies all resolved symbols and checks whether itself needs to be marked alive,4179/// Verifies all resolved symbols and checks whether itself needs to be marked alive,
...@@ -4058,7 +4186,7 @@ fn markReferences(wasm: *Wasm) !void {...@@ -4058,7 +4186,7 @@ fn markReferences(wasm: *Wasm) !void {
4058 const comp = wasm.base.comp;4186 const comp = wasm.base.comp;
40594187
4060 for (wasm.resolved_symbols.keys()) |sym_loc| {4188 for (wasm.resolved_symbols.keys()) |sym_loc| {
4061 const sym = sym_loc.getSymbol(wasm);4189 const sym = wasm.symbolLocSymbol(sym_loc);
4062 if (sym.isExported(comp.config.rdynamic) or sym.isNoStrip() or !do_garbage_collect) {4190 if (sym.isExported(comp.config.rdynamic) or sym.isNoStrip() or !do_garbage_collect) {
4063 try wasm.mark(sym_loc);4191 try wasm.mark(sym_loc);
4064 continue;4192 continue;
...@@ -4067,8 +4195,8 @@ fn markReferences(wasm: *Wasm) !void {...@@ -4067,8 +4195,8 @@ fn markReferences(wasm: *Wasm) !void {
4067 // Debug sections may require to be parsed and marked when it contains4195 // Debug sections may require to be parsed and marked when it contains
4068 // relocations to alive symbols.4196 // relocations to alive symbols.
4069 if (sym.tag == .section and comp.config.debug_format != .strip) {4197 if (sym.tag == .section and comp.config.debug_format != .strip) {
4070 const obj_file = wasm.file(sym_loc.file) orelse continue; // Incremental debug info is done independently4198 const object_id = sym_loc.file.unwrap() orelse continue; // Incremental debug info is done independently
4071 _ = try obj_file.parseSymbolIntoAtom(wasm, sym_loc.index);4199 _ = try wasm.parseSymbolIntoAtom(object_id, sym_loc.index);
4072 sym.mark();4200 sym.mark();
4073 }4201 }
4074 }4202 }
...@@ -4077,7 +4205,7 @@ fn markReferences(wasm: *Wasm) !void {...@@ -4077,7 +4205,7 @@ fn markReferences(wasm: *Wasm) !void {
4077/// Marks a symbol as 'alive' recursively so itself and any references it contains to4205/// Marks a symbol as 'alive' recursively so itself and any references it contains to
4078/// other symbols will not be omit from the binary.4206/// other symbols will not be omit from the binary.
4079fn mark(wasm: *Wasm, loc: SymbolLoc) !void {4207fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
4080 const symbol = loc.getSymbol(wasm);4208 const symbol = wasm.symbolLocSymbol(loc);
4081 if (symbol.isAlive()) {4209 if (symbol.isAlive()) {
4082 // Symbol is already marked alive, including its references.4210 // Symbol is already marked alive, including its references.
4083 // This means we can skip it so we don't end up marking the same symbols4211 // This means we can skip it so we don't end up marking the same symbols
...@@ -4085,22 +4213,22 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {...@@ -4085,22 +4213,22 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
4085 return;4213 return;
4086 }4214 }
4087 symbol.mark();4215 symbol.mark();
4088 gc_log.debug("Marked symbol '{s}'", .{loc.getName(wasm)});4216 gc_log.debug("Marked symbol '{s}'", .{wasm.symbolLocName(loc)});
4089 if (symbol.isUndefined()) {4217 if (symbol.isUndefined()) {
4090 // undefined symbols do not have an associated `Atom` and therefore also4218 // undefined symbols do not have an associated `Atom` and therefore also
4091 // do not contain relocations.4219 // do not contain relocations.
4092 return;4220 return;
4093 }4221 }
40944222
4095 const atom_index = if (wasm.file(loc.file)) |obj_file|4223 const atom_index = if (loc.file.unwrap()) |object_id|
4096 try obj_file.parseSymbolIntoAtom(wasm, loc.index)4224 try wasm.parseSymbolIntoAtom(object_id, loc.index)
4097 else4225 else
4098 wasm.symbol_atom.get(loc) orelse return;4226 wasm.symbol_atom.get(loc) orelse return;
40994227
4100 const atom = wasm.getAtom(atom_index);4228 const atom = wasm.getAtom(atom_index);
4101 for (atom.relocs.items) |reloc| {4229 for (atom.relocs.items) |reloc| {
4102 const target_loc: SymbolLoc = .{ .index = @enumFromInt(reloc.index), .file = loc.file };4230 const target_loc: SymbolLoc = .{ .index = @enumFromInt(reloc.index), .file = loc.file };
4103 try wasm.mark(target_loc.finalLoc(wasm));4231 try wasm.mark(wasm.symbolLocFinalLoc(target_loc));
4104 }4232 }
4105}4233}
41064234
...@@ -4110,3 +4238,566 @@ fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8...@@ -4110,3 +4238,566 @@ fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8
4110 .command => "_start",4238 .command => "_start",
4111 };4239 };
4112}4240}
4241
4242pub const Atom = struct {
4243 /// Represents the index of the file this atom was generated from.
4244 /// This is `none` when the atom was generated by a synthetic linker symbol.
4245 file: OptionalObjectId,
4246 /// symbol index of the symbol representing this atom
4247 sym_index: Symbol.Index,
4248 /// Size of the atom, used to calculate section sizes in the final binary
4249 size: u32 = 0,
4250 /// List of relocations belonging to this atom
4251 relocs: std.ArrayListUnmanaged(Relocation) = .empty,
4252 /// Contains the binary data of an atom, which can be non-relocated
4253 code: std.ArrayListUnmanaged(u8) = .empty,
4254 /// For code this is 1, for data this is set to the highest value of all segments
4255 alignment: Wasm.Alignment = .@"1",
4256 /// Offset into the section where the atom lives, this already accounts
4257 /// for alignment.
4258 offset: u32 = 0,
4259 /// The original offset within the object file. This value is subtracted from
4260 /// relocation offsets to determine where in the `data` to rewrite the value
4261 original_offset: u32 = 0,
4262 /// Previous atom in relation to this atom.
4263 /// is null when this atom is the first in its order
4264 prev: Atom.Index = .null,
4265 /// Contains atoms local to a decl, all managed by this `Atom`.
4266 /// When the parent atom is being freed, it will also do so for all local atoms.
4267 locals: std.ArrayListUnmanaged(Atom.Index) = .empty,
4268
4269 /// Represents the index of an Atom where `null` is considered
4270 /// an invalid atom.
4271 pub const Index = enum(u32) {
4272 null = std.math.maxInt(u32),
4273 _,
4274 };
4275
4276 /// Frees all resources owned by this `Atom`.
4277 pub fn deinit(atom: *Atom, gpa: std.mem.Allocator) void {
4278 atom.relocs.deinit(gpa);
4279 atom.code.deinit(gpa);
4280 atom.locals.deinit(gpa);
4281 atom.* = undefined;
4282 }
4283
4284 /// Sets the length of relocations and code to '0',
4285 /// effectively resetting them and allowing them to be re-populated.
4286 pub fn clear(atom: *Atom) void {
4287 atom.relocs.clearRetainingCapacity();
4288 atom.code.clearRetainingCapacity();
4289 }
4290
4291 pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
4292 _ = fmt;
4293 _ = options;
4294 try writer.print("Atom{{ .sym_index = {d}, .alignment = {d}, .size = {d}, .offset = 0x{x:0>8} }}", .{
4295 @intFromEnum(atom.sym_index),
4296 atom.alignment,
4297 atom.size,
4298 atom.offset,
4299 });
4300 }
4301
4302 /// Returns the location of the symbol that represents this `Atom`
4303 pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
4304 return .{
4305 .file = atom.file,
4306 .index = atom.sym_index,
4307 };
4308 }
4309
4310 /// Resolves the relocations within the atom, writing the new value
4311 /// at the calculated offset.
4312 pub fn resolveRelocs(atom: *Atom, wasm: *const Wasm) void {
4313 if (atom.relocs.items.len == 0) return;
4314 const symbol_name = wasm.symbolLocName(atom.symbolLoc());
4315 log.debug("Resolving relocs in atom '{s}' count({d})", .{
4316 symbol_name,
4317 atom.relocs.items.len,
4318 });
4319
4320 for (atom.relocs.items) |reloc| {
4321 const value = atom.relocationValue(reloc, wasm);
4322 log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
4323 wasm.symbolLocName(.{
4324 .file = atom.file,
4325 .index = @enumFromInt(reloc.index),
4326 }),
4327 symbol_name,
4328 reloc.offset,
4329 value,
4330 });
4331
4332 switch (reloc.relocation_type) {
4333 .R_WASM_TABLE_INDEX_I32,
4334 .R_WASM_FUNCTION_OFFSET_I32,
4335 .R_WASM_GLOBAL_INDEX_I32,
4336 .R_WASM_MEMORY_ADDR_I32,
4337 .R_WASM_SECTION_OFFSET_I32,
4338 => std.mem.writeInt(u32, atom.code.items[reloc.offset - atom.original_offset ..][0..4], @as(u32, @truncate(value)), .little),
4339 .R_WASM_TABLE_INDEX_I64,
4340 .R_WASM_MEMORY_ADDR_I64,
4341 => std.mem.writeInt(u64, atom.code.items[reloc.offset - atom.original_offset ..][0..8], value, .little),
4342 .R_WASM_GLOBAL_INDEX_LEB,
4343 .R_WASM_EVENT_INDEX_LEB,
4344 .R_WASM_FUNCTION_INDEX_LEB,
4345 .R_WASM_MEMORY_ADDR_LEB,
4346 .R_WASM_MEMORY_ADDR_SLEB,
4347 .R_WASM_TABLE_INDEX_SLEB,
4348 .R_WASM_TABLE_NUMBER_LEB,
4349 .R_WASM_TYPE_INDEX_LEB,
4350 .R_WASM_MEMORY_ADDR_TLS_SLEB,
4351 => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset - atom.original_offset ..][0..5], @as(u32, @truncate(value))),
4352 .R_WASM_MEMORY_ADDR_LEB64,
4353 .R_WASM_MEMORY_ADDR_SLEB64,
4354 .R_WASM_TABLE_INDEX_SLEB64,
4355 .R_WASM_MEMORY_ADDR_TLS_SLEB64,
4356 => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset - atom.original_offset ..][0..10], value),
4357 }
4358 }
4359 }
4360
4361 /// From a given `relocation` will return the new value to be written.
4362 /// All values will be represented as a `u64` as all values can fit within it.
4363 /// The final value must be casted to the correct size.
4364 fn relocationValue(atom: Atom, relocation: Relocation, wasm: *const Wasm) u64 {
4365 const target_loc = wasm.symbolLocFinalLoc(.{
4366 .file = atom.file,
4367 .index = @enumFromInt(relocation.index),
4368 });
4369 const symbol = wasm.symbolLocSymbol(target_loc);
4370 if (relocation.relocation_type != .R_WASM_TYPE_INDEX_LEB and
4371 symbol.tag != .section and
4372 symbol.isDead())
4373 {
4374 const val = atom.thombstone(wasm) orelse relocation.addend;
4375 return @bitCast(val);
4376 }
4377 switch (relocation.relocation_type) {
4378 .R_WASM_FUNCTION_INDEX_LEB => return symbol.index,
4379 .R_WASM_TABLE_NUMBER_LEB => return symbol.index,
4380 .R_WASM_TABLE_INDEX_I32,
4381 .R_WASM_TABLE_INDEX_I64,
4382 .R_WASM_TABLE_INDEX_SLEB,
4383 .R_WASM_TABLE_INDEX_SLEB64,
4384 => return wasm.function_table.get(.{ .file = atom.file, .index = @enumFromInt(relocation.index) }) orelse 0,
4385 .R_WASM_TYPE_INDEX_LEB => {
4386 const object_id = atom.file.unwrap() orelse return relocation.index;
4387 const original_type = objectFuncTypes(wasm, object_id)[relocation.index];
4388 return wasm.getTypeIndex(original_type).?;
4389 },
4390 .R_WASM_GLOBAL_INDEX_I32,
4391 .R_WASM_GLOBAL_INDEX_LEB,
4392 => return symbol.index,
4393 .R_WASM_MEMORY_ADDR_I32,
4394 .R_WASM_MEMORY_ADDR_I64,
4395 .R_WASM_MEMORY_ADDR_LEB,
4396 .R_WASM_MEMORY_ADDR_LEB64,
4397 .R_WASM_MEMORY_ADDR_SLEB,
4398 .R_WASM_MEMORY_ADDR_SLEB64,
4399 => {
4400 std.debug.assert(symbol.tag == .data);
4401 if (symbol.isUndefined()) {
4402 return 0;
4403 }
4404 const va: i33 = @intCast(symbol.virtual_address);
4405 return @intCast(va + relocation.addend);
4406 },
4407 .R_WASM_EVENT_INDEX_LEB => return symbol.index,
4408 .R_WASM_SECTION_OFFSET_I32 => {
4409 const target_atom_index = wasm.symbol_atom.get(target_loc).?;
4410 const target_atom = wasm.getAtom(target_atom_index);
4411 const rel_value: i33 = @intCast(target_atom.offset);
4412 return @intCast(rel_value + relocation.addend);
4413 },
4414 .R_WASM_FUNCTION_OFFSET_I32 => {
4415 if (symbol.isUndefined()) {
4416 const val = atom.thombstone(wasm) orelse relocation.addend;
4417 return @bitCast(val);
4418 }
4419 const target_atom_index = wasm.symbol_atom.get(target_loc).?;
4420 const target_atom = wasm.getAtom(target_atom_index);
4421 const rel_value: i33 = @intCast(target_atom.offset);
4422 return @intCast(rel_value + relocation.addend);
4423 },
4424 .R_WASM_MEMORY_ADDR_TLS_SLEB,
4425 .R_WASM_MEMORY_ADDR_TLS_SLEB64,
4426 => {
4427 const va: i33 = @intCast(symbol.virtual_address);
4428 return @intCast(va + relocation.addend);
4429 },
4430 }
4431 }
4432
4433 // For a given `Atom` returns whether it has a thombstone value or not.
4434 /// This defines whether we want a specific value when a section is dead.
4435 fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 {
4436 const atom_name = wasm.symbolLocName(atom.symbolLoc());
4437 if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) {
4438 return -2;
4439 } else if (std.mem.startsWith(u8, atom_name, ".debug_")) {
4440 return -1;
4441 }
4442 return null;
4443 }
4444};
4445
4446pub const Relocation = struct {
4447 /// Represents the type of the `Relocation`
4448 relocation_type: RelocationType,
4449 /// Offset of the value to rewrite relative to the relevant section's contents.
4450 /// When `offset` is zero, its position is immediately after the id and size of the section.
4451 offset: u32,
4452 /// The index of the symbol used.
4453 /// When the type is `R_WASM_TYPE_INDEX_LEB`, it represents the index of the type.
4454 index: u32,
4455 /// Addend to add to the address.
4456 /// This field is only non-zero for `R_WASM_MEMORY_ADDR_*`, `R_WASM_FUNCTION_OFFSET_I32` and `R_WASM_SECTION_OFFSET_I32`.
4457 addend: i32 = 0,
4458
4459 /// All possible relocation types currently existing.
4460 /// This enum is exhaustive as the spec is WIP and new types
4461 /// can be added which means that a generated binary will be invalid,
4462 /// so instead we will show an error in such cases.
4463 pub const RelocationType = enum(u8) {
4464 R_WASM_FUNCTION_INDEX_LEB = 0,
4465 R_WASM_TABLE_INDEX_SLEB = 1,
4466 R_WASM_TABLE_INDEX_I32 = 2,
4467 R_WASM_MEMORY_ADDR_LEB = 3,
4468 R_WASM_MEMORY_ADDR_SLEB = 4,
4469 R_WASM_MEMORY_ADDR_I32 = 5,
4470 R_WASM_TYPE_INDEX_LEB = 6,
4471 R_WASM_GLOBAL_INDEX_LEB = 7,
4472 R_WASM_FUNCTION_OFFSET_I32 = 8,
4473 R_WASM_SECTION_OFFSET_I32 = 9,
4474 R_WASM_EVENT_INDEX_LEB = 10,
4475 R_WASM_GLOBAL_INDEX_I32 = 13,
4476 R_WASM_MEMORY_ADDR_LEB64 = 14,
4477 R_WASM_MEMORY_ADDR_SLEB64 = 15,
4478 R_WASM_MEMORY_ADDR_I64 = 16,
4479 R_WASM_TABLE_INDEX_SLEB64 = 18,
4480 R_WASM_TABLE_INDEX_I64 = 19,
4481 R_WASM_TABLE_NUMBER_LEB = 20,
4482 R_WASM_MEMORY_ADDR_TLS_SLEB = 21,
4483 R_WASM_MEMORY_ADDR_TLS_SLEB64 = 25,
4484
4485 /// Returns true for relocation types where the `addend` field is present.
4486 pub fn addendIsPresent(self: RelocationType) bool {
4487 return switch (self) {
4488 .R_WASM_MEMORY_ADDR_LEB,
4489 .R_WASM_MEMORY_ADDR_SLEB,
4490 .R_WASM_MEMORY_ADDR_I32,
4491 .R_WASM_MEMORY_ADDR_LEB64,
4492 .R_WASM_MEMORY_ADDR_SLEB64,
4493 .R_WASM_MEMORY_ADDR_I64,
4494 .R_WASM_MEMORY_ADDR_TLS_SLEB,
4495 .R_WASM_MEMORY_ADDR_TLS_SLEB64,
4496 .R_WASM_FUNCTION_OFFSET_I32,
4497 .R_WASM_SECTION_OFFSET_I32,
4498 => true,
4499 else => false,
4500 };
4501 }
4502 };
4503
4504 /// Verifies the relocation type of a given `Relocation` and returns
4505 /// true when the relocation references a function call or address to a function.
4506 pub fn isFunction(self: Relocation) bool {
4507 return switch (self.relocation_type) {
4508 .R_WASM_FUNCTION_INDEX_LEB,
4509 .R_WASM_TABLE_INDEX_SLEB,
4510 => true,
4511 else => false,
4512 };
4513 }
4514
4515 pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
4516 _ = fmt;
4517 _ = options;
4518 try writer.print("{s} offset=0x{x:0>6} symbol={d}", .{
4519 @tagName(self.relocation_type),
4520 self.offset,
4521 self.index,
4522 });
4523 }
4524};
4525
4526/// Unlike the `Import` object defined by the wasm spec, and existing
4527/// in the std.wasm namespace, this construct saves the 'module name' and 'name'
4528/// of the import using offsets into a string table, rather than the slices itself.
4529/// This saves us (potentially) 24 bytes per import on 64bit machines.
4530pub const Import = struct {
4531 module_name: u32,
4532 name: u32,
4533 kind: std.wasm.Import.Kind,
4534};
4535
4536/// Unlike the `Export` object defined by the wasm spec, and existing
4537/// in the std.wasm namespace, this construct saves the 'name'
4538/// of the export using offsets into a string table, rather than the slice itself.
4539/// This saves us (potentially) 12 bytes per export on 64bit machines.
4540pub const Export = struct {
4541 name: u32,
4542 index: u32,
4543 kind: std.wasm.ExternalKind,
4544};
4545
4546pub const SubsectionType = enum(u8) {
4547 WASM_SEGMENT_INFO = 5,
4548 WASM_INIT_FUNCS = 6,
4549 WASM_COMDAT_INFO = 7,
4550 WASM_SYMBOL_TABLE = 8,
4551};
4552
4553pub const Alignment = @import("../InternPool.zig").Alignment;
4554
4555pub const NamedSegment = struct {
4556 /// Segment's name, encoded as UTF-8 bytes.
4557 name: []const u8,
4558 /// The required alignment of the segment, encoded as a power of 2
4559 alignment: Alignment,
4560 /// Bitfield containing flags for a segment
4561 flags: u32,
4562
4563 pub fn isTLS(segment: NamedSegment) bool {
4564 return segment.flags & @intFromEnum(Flags.WASM_SEG_FLAG_TLS) != 0;
4565 }
4566
4567 /// Returns the name as how it will be output into the final object
4568 /// file or binary. When `merge_segments` is true, this will return the
4569 /// short name. i.e. ".rodata". When false, it returns the entire name instead.
4570 pub fn outputName(segment: NamedSegment, merge_segments: bool) []const u8 {
4571 if (segment.isTLS()) {
4572 return ".tdata";
4573 } else if (!merge_segments) {
4574 return segment.name;
4575 } else if (std.mem.startsWith(u8, segment.name, ".rodata.")) {
4576 return ".rodata";
4577 } else if (std.mem.startsWith(u8, segment.name, ".text.")) {
4578 return ".text";
4579 } else if (std.mem.startsWith(u8, segment.name, ".data.")) {
4580 return ".data";
4581 } else if (std.mem.startsWith(u8, segment.name, ".bss.")) {
4582 return ".bss";
4583 }
4584 return segment.name;
4585 }
4586
4587 pub const Flags = enum(u32) {
4588 WASM_SEG_FLAG_STRINGS = 0x1,
4589 WASM_SEG_FLAG_TLS = 0x2,
4590 };
4591};
4592
4593pub const InitFunc = struct {
4594 /// Priority of the init function
4595 priority: u32,
4596 /// The symbol index of init function (not the function index).
4597 symbol_index: u32,
4598};
4599
4600pub const Comdat = struct {
4601 name: []const u8,
4602 /// Must be zero, no flags are currently defined by the tool-convention.
4603 flags: u32,
4604 symbols: []const ComdatSym,
4605};
4606
4607pub const ComdatSym = struct {
4608 kind: @This().Type,
4609 /// Index of the data segment/function/global/event/table within a WASM module.
4610 /// The object must not be an import.
4611 index: u32,
4612
4613 pub const Type = enum(u8) {
4614 WASM_COMDAT_DATA = 0,
4615 WASM_COMDAT_FUNCTION = 1,
4616 WASM_COMDAT_GLOBAL = 2,
4617 WASM_COMDAT_EVENT = 3,
4618 WASM_COMDAT_TABLE = 4,
4619 WASM_COMDAT_SECTION = 5,
4620 };
4621};
4622
4623pub const Feature = struct {
4624 /// Provides information about the usage of the feature.
4625 /// - '0x2b' (+): Object uses this feature, and the link fails if feature is not in the allowed set.
4626 /// - '0x2d' (-): Object does not use this feature, and the link fails if this feature is in the allowed set.
4627 /// - '0x3d' (=): Object uses this feature, and the link fails if this feature is not in the allowed set,
4628 /// or if any object does not use this feature.
4629 prefix: Prefix,
4630 /// Type of the feature, must be unique in the sequence of features.
4631 tag: Tag,
4632
4633 /// Unlike `std.Target.wasm.Feature` this also contains linker-features such as shared-mem
4634 pub const Tag = enum {
4635 atomics,
4636 bulk_memory,
4637 exception_handling,
4638 extended_const,
4639 half_precision,
4640 multimemory,
4641 multivalue,
4642 mutable_globals,
4643 nontrapping_fptoint,
4644 reference_types,
4645 relaxed_simd,
4646 sign_ext,
4647 simd128,
4648 tail_call,
4649 shared_mem,
4650
4651 /// From a given cpu feature, returns its linker feature
4652 pub fn fromCpuFeature(feature: std.Target.wasm.Feature) Tag {
4653 return @as(Tag, @enumFromInt(@intFromEnum(feature)));
4654 }
4655
4656 pub fn format(tag: Tag, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
4657 _ = fmt;
4658 _ = opt;
4659 try writer.writeAll(switch (tag) {
4660 .atomics => "atomics",
4661 .bulk_memory => "bulk-memory",
4662 .exception_handling => "exception-handling",
4663 .extended_const => "extended-const",
4664 .half_precision => "half-precision",
4665 .multimemory => "multimemory",
4666 .multivalue => "multivalue",
4667 .mutable_globals => "mutable-globals",
4668 .nontrapping_fptoint => "nontrapping-fptoint",
4669 .reference_types => "reference-types",
4670 .relaxed_simd => "relaxed-simd",
4671 .sign_ext => "sign-ext",
4672 .simd128 => "simd128",
4673 .tail_call => "tail-call",
4674 .shared_mem => "shared-mem",
4675 });
4676 }
4677 };
4678
4679 pub const Prefix = enum(u8) {
4680 used = '+',
4681 disallowed = '-',
4682 required = '=',
4683 };
4684
4685 pub fn format(feature: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
4686 _ = opt;
4687 _ = fmt;
4688 try writer.print("{c} {}", .{ feature.prefix, feature.tag });
4689 }
4690};
4691
4692pub const known_features = std.StaticStringMap(Feature.Tag).initComptime(.{
4693 .{ "atomics", .atomics },
4694 .{ "bulk-memory", .bulk_memory },
4695 .{ "exception-handling", .exception_handling },
4696 .{ "extended-const", .extended_const },
4697 .{ "half-precision", .half_precision },
4698 .{ "multimemory", .multimemory },
4699 .{ "multivalue", .multivalue },
4700 .{ "mutable-globals", .mutable_globals },
4701 .{ "nontrapping-fptoint", .nontrapping_fptoint },
4702 .{ "reference-types", .reference_types },
4703 .{ "relaxed-simd", .relaxed_simd },
4704 .{ "sign-ext", .sign_ext },
4705 .{ "simd128", .simd128 },
4706 .{ "tail-call", .tail_call },
4707 .{ "shared-mem", .shared_mem },
4708});
4709
4710/// Parses an object file into atoms, for code and data sections
4711fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !Atom.Index {
4712 const object = wasm.objectById(object_id) orelse
4713 return wasm.zig_object.?.parseSymbolIntoAtom(wasm, symbol_index);
4714 const comp = wasm.base.comp;
4715 const gpa = comp.gpa;
4716 const symbol = &object.symtable[@intFromEnum(symbol_index)];
4717 const relocatable_data: Object.RelocatableData = switch (symbol.tag) {
4718 .function => object.relocatable_data.get(.code).?[symbol.index - object.imported_functions_count],
4719 .data => object.relocatable_data.get(.data).?[symbol.index],
4720 .section => blk: {
4721 const data = object.relocatable_data.get(.custom).?;
4722 for (data) |dat| {
4723 if (dat.section_index == symbol.index) {
4724 break :blk dat;
4725 }
4726 }
4727 unreachable;
4728 },
4729 else => unreachable,
4730 };
4731 const final_index = try wasm.getMatchingSegment(object_id, symbol_index);
4732 const atom_index = try wasm.createAtom(symbol_index, object_id.toOptional());
4733 try wasm.appendAtomAtIndex(final_index, atom_index);
4734
4735 const atom = wasm.getAtomPtr(atom_index);
4736 atom.size = relocatable_data.size;
4737 atom.alignment = relocatable_data.getAlignment(object);
4738 atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
4739 atom.original_offset = relocatable_data.offset;
4740
4741 const segment: *Wasm.Segment = &wasm.segments.items[final_index];
4742 if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
4743 segment.alignment = segment.alignment.max(atom.alignment);
4744 }
4745
4746 if (object.relocations.get(relocatable_data.section_index)) |relocations| {
4747 const start = searchRelocStart(relocations, relocatable_data.offset);
4748 const len = searchRelocEnd(relocations[start..], relocatable_data.offset + atom.size);
4749 atom.relocs = std.ArrayListUnmanaged(Wasm.Relocation).fromOwnedSlice(relocations[start..][0..len]);
4750 for (atom.relocs.items) |reloc| {
4751 switch (reloc.relocation_type) {
4752 .R_WASM_TABLE_INDEX_I32,
4753 .R_WASM_TABLE_INDEX_I64,
4754 .R_WASM_TABLE_INDEX_SLEB,
4755 .R_WASM_TABLE_INDEX_SLEB64,
4756 => {
4757 try wasm.function_table.put(gpa, .{
4758 .file = object_id.toOptional(),
4759 .index = @enumFromInt(reloc.index),
4760 }, 0);
4761 },
4762 .R_WASM_GLOBAL_INDEX_I32,
4763 .R_WASM_GLOBAL_INDEX_LEB,
4764 => {
4765 const sym = object.symtable[reloc.index];
4766 if (sym.tag != .global) {
4767 try wasm.got_symbols.append(gpa, .{
4768 .file = object_id.toOptional(),
4769 .index = @enumFromInt(reloc.index),
4770 });
4771 }
4772 },
4773 else => {},
4774 }
4775 }
4776 }
4777
4778 return atom_index;
4779}
4780
4781fn searchRelocStart(relocs: []const Wasm.Relocation, address: u32) usize {
4782 var min: usize = 0;
4783 var max: usize = relocs.len;
4784 while (min < max) {
4785 const index = (min + max) / 2;
4786 const curr = relocs[index];
4787 if (curr.offset < address) {
4788 min = index + 1;
4789 } else {
4790 max = index;
4791 }
4792 }
4793 return min;
4794}
4795
4796fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize {
4797 for (relocs, 0..relocs.len) |reloc, index| {
4798 if (reloc.offset > address) {
4799 return index;
4800 }
4801 }
4802 return relocs.len;
4803}
src/link/Wasm/Atom.zig deleted-204
...@@ -1,204 +0,0 @@
1/// Represents the index of the file this atom was generated from.
2/// This is 'null' when the atom was generated by a synthetic linker symbol.
3file: FileIndex,
4/// symbol index of the symbol representing this atom
5sym_index: Symbol.Index,
6/// Size of the atom, used to calculate section sizes in the final binary
7size: u32 = 0,
8/// List of relocations belonging to this atom
9relocs: std.ArrayListUnmanaged(types.Relocation) = .empty,
10/// Contains the binary data of an atom, which can be non-relocated
11code: std.ArrayListUnmanaged(u8) = .empty,
12/// For code this is 1, for data this is set to the highest value of all segments
13alignment: Wasm.Alignment = .@"1",
14/// Offset into the section where the atom lives, this already accounts
15/// for alignment.
16offset: u32 = 0,
17/// The original offset within the object file. This value is subtracted from
18/// relocation offsets to determine where in the `data` to rewrite the value
19original_offset: u32 = 0,
20/// Previous atom in relation to this atom.
21/// is null when this atom is the first in its order
22prev: Atom.Index = .null,
23/// Contains atoms local to a decl, all managed by this `Atom`.
24/// When the parent atom is being freed, it will also do so for all local atoms.
25locals: std.ArrayListUnmanaged(Atom.Index) = .empty,
26
27/// Represents the index of an Atom where `null` is considered
28/// an invalid atom.
29pub const Index = enum(u32) {
30 null = std.math.maxInt(u32),
31 _,
32};
33
34/// Frees all resources owned by this `Atom`.
35pub fn deinit(atom: *Atom, gpa: std.mem.Allocator) void {
36 atom.relocs.deinit(gpa);
37 atom.code.deinit(gpa);
38 atom.locals.deinit(gpa);
39 atom.* = undefined;
40}
41
42/// Sets the length of relocations and code to '0',
43/// effectively resetting them and allowing them to be re-populated.
44pub fn clear(atom: *Atom) void {
45 atom.relocs.clearRetainingCapacity();
46 atom.code.clearRetainingCapacity();
47}
48
49pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
50 _ = fmt;
51 _ = options;
52 try writer.print("Atom{{ .sym_index = {d}, .alignment = {d}, .size = {d}, .offset = 0x{x:0>8} }}", .{
53 @intFromEnum(atom.sym_index),
54 atom.alignment,
55 atom.size,
56 atom.offset,
57 });
58}
59
60/// Returns the location of the symbol that represents this `Atom`
61pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
62 return .{ .file = atom.file, .index = atom.sym_index };
63}
64
65/// Resolves the relocations within the atom, writing the new value
66/// at the calculated offset.
67pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
68 if (atom.relocs.items.len == 0) return;
69 const symbol_name = atom.symbolLoc().getName(wasm_bin);
70 log.debug("Resolving relocs in atom '{s}' count({d})", .{
71 symbol_name,
72 atom.relocs.items.len,
73 });
74
75 for (atom.relocs.items) |reloc| {
76 const value = atom.relocationValue(reloc, wasm_bin);
77 log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
78 (Wasm.SymbolLoc{ .file = atom.file, .index = @enumFromInt(reloc.index) }).getName(wasm_bin),
79 symbol_name,
80 reloc.offset,
81 value,
82 });
83
84 switch (reloc.relocation_type) {
85 .R_WASM_TABLE_INDEX_I32,
86 .R_WASM_FUNCTION_OFFSET_I32,
87 .R_WASM_GLOBAL_INDEX_I32,
88 .R_WASM_MEMORY_ADDR_I32,
89 .R_WASM_SECTION_OFFSET_I32,
90 => std.mem.writeInt(u32, atom.code.items[reloc.offset - atom.original_offset ..][0..4], @as(u32, @truncate(value)), .little),
91 .R_WASM_TABLE_INDEX_I64,
92 .R_WASM_MEMORY_ADDR_I64,
93 => std.mem.writeInt(u64, atom.code.items[reloc.offset - atom.original_offset ..][0..8], value, .little),
94 .R_WASM_GLOBAL_INDEX_LEB,
95 .R_WASM_EVENT_INDEX_LEB,
96 .R_WASM_FUNCTION_INDEX_LEB,
97 .R_WASM_MEMORY_ADDR_LEB,
98 .R_WASM_MEMORY_ADDR_SLEB,
99 .R_WASM_TABLE_INDEX_SLEB,
100 .R_WASM_TABLE_NUMBER_LEB,
101 .R_WASM_TYPE_INDEX_LEB,
102 .R_WASM_MEMORY_ADDR_TLS_SLEB,
103 => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset - atom.original_offset ..][0..5], @as(u32, @truncate(value))),
104 .R_WASM_MEMORY_ADDR_LEB64,
105 .R_WASM_MEMORY_ADDR_SLEB64,
106 .R_WASM_TABLE_INDEX_SLEB64,
107 .R_WASM_MEMORY_ADDR_TLS_SLEB64,
108 => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset - atom.original_offset ..][0..10], value),
109 }
110 }
111}
112
113/// From a given `relocation` will return the new value to be written.
114/// All values will be represented as a `u64` as all values can fit within it.
115/// The final value must be casted to the correct size.
116fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 {
117 const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = @enumFromInt(relocation.index) }).finalLoc(wasm_bin);
118 const symbol = target_loc.getSymbol(wasm_bin);
119 if (relocation.relocation_type != .R_WASM_TYPE_INDEX_LEB and
120 symbol.tag != .section and
121 symbol.isDead())
122 {
123 const val = atom.thombstone(wasm_bin) orelse relocation.addend;
124 return @bitCast(val);
125 }
126 switch (relocation.relocation_type) {
127 .R_WASM_FUNCTION_INDEX_LEB => return symbol.index,
128 .R_WASM_TABLE_NUMBER_LEB => return symbol.index,
129 .R_WASM_TABLE_INDEX_I32,
130 .R_WASM_TABLE_INDEX_I64,
131 .R_WASM_TABLE_INDEX_SLEB,
132 .R_WASM_TABLE_INDEX_SLEB64,
133 => return wasm_bin.function_table.get(.{ .file = atom.file, .index = @enumFromInt(relocation.index) }) orelse 0,
134 .R_WASM_TYPE_INDEX_LEB => {
135 const obj_file = wasm_bin.file(atom.file) orelse return relocation.index;
136 const original_type = obj_file.funcTypes()[relocation.index];
137 return wasm_bin.getTypeIndex(original_type).?;
138 },
139 .R_WASM_GLOBAL_INDEX_I32,
140 .R_WASM_GLOBAL_INDEX_LEB,
141 => return symbol.index,
142 .R_WASM_MEMORY_ADDR_I32,
143 .R_WASM_MEMORY_ADDR_I64,
144 .R_WASM_MEMORY_ADDR_LEB,
145 .R_WASM_MEMORY_ADDR_LEB64,
146 .R_WASM_MEMORY_ADDR_SLEB,
147 .R_WASM_MEMORY_ADDR_SLEB64,
148 => {
149 std.debug.assert(symbol.tag == .data);
150 if (symbol.isUndefined()) {
151 return 0;
152 }
153 const va: i33 = @intCast(symbol.virtual_address);
154 return @intCast(va + relocation.addend);
155 },
156 .R_WASM_EVENT_INDEX_LEB => return symbol.index,
157 .R_WASM_SECTION_OFFSET_I32 => {
158 const target_atom_index = wasm_bin.symbol_atom.get(target_loc).?;
159 const target_atom = wasm_bin.getAtom(target_atom_index);
160 const rel_value: i33 = @intCast(target_atom.offset);
161 return @intCast(rel_value + relocation.addend);
162 },
163 .R_WASM_FUNCTION_OFFSET_I32 => {
164 if (symbol.isUndefined()) {
165 const val = atom.thombstone(wasm_bin) orelse relocation.addend;
166 return @bitCast(val);
167 }
168 const target_atom_index = wasm_bin.symbol_atom.get(target_loc).?;
169 const target_atom = wasm_bin.getAtom(target_atom_index);
170 const rel_value: i33 = @intCast(target_atom.offset);
171 return @intCast(rel_value + relocation.addend);
172 },
173 .R_WASM_MEMORY_ADDR_TLS_SLEB,
174 .R_WASM_MEMORY_ADDR_TLS_SLEB64,
175 => {
176 const va: i33 = @intCast(symbol.virtual_address);
177 return @intCast(va + relocation.addend);
178 },
179 }
180}
181
182// For a given `Atom` returns whether it has a thombstone value or not.
183/// This defines whether we want a specific value when a section is dead.
184fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 {
185 const atom_name = atom.symbolLoc().getName(wasm);
186 if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) {
187 return -2;
188 } else if (std.mem.startsWith(u8, atom_name, ".debug_")) {
189 return -1;
190 }
191 return null;
192}
193
194const leb = std.leb;
195const log = std.log.scoped(.link);
196const mem = std.mem;
197const std = @import("std");
198const types = @import("types.zig");
199
200const Allocator = mem.Allocator;
201const Atom = @This();
202const FileIndex = @import("file.zig").File.Index;
203const Symbol = @import("Symbol.zig");
204const Wasm = @import("../Wasm.zig");
src/link/Wasm/Object.zig+25-119
...@@ -3,22 +3,18 @@...@@ -3,22 +3,18 @@
3//! the data on correctness. The result can then be used by the linker.3//! the data on correctness. The result can then be used by the linker.
4const Object = @This();4const Object = @This();
55
6const Atom = @import("Atom.zig");
7const types = @import("types.zig");
8const std = @import("std");
9const Wasm = @import("../Wasm.zig");6const Wasm = @import("../Wasm.zig");
7const Atom = Wasm.Atom;
8const Alignment = Wasm.Alignment;
10const Symbol = @import("Symbol.zig");9const Symbol = @import("Symbol.zig");
11const Alignment = types.Alignment;
12const File = @import("file.zig").File;
1310
11const std = @import("std");
14const Allocator = std.mem.Allocator;12const Allocator = std.mem.Allocator;
15const leb = std.leb;13const leb = std.leb;
16const meta = std.meta;14const meta = std.meta;
1715
18const log = std.log.scoped(.object);16const log = std.log.scoped(.object);
1917
20/// Index into the list of relocatable object files within the linker driver.
21index: File.Index = .null,
22/// Wasm spec version used for this `Object`18/// Wasm spec version used for this `Object`
23version: u32 = 0,19version: u32 = 0,
24/// The file descriptor that represents the wasm object file.20/// The file descriptor that represents the wasm object file.
...@@ -28,7 +24,7 @@ path: []const u8,...@@ -28,7 +24,7 @@ path: []const u8,
28/// Parsed type section24/// Parsed type section
29func_types: []const std.wasm.Type = &.{},25func_types: []const std.wasm.Type = &.{},
30/// A list of all imports for this module26/// A list of all imports for this module
31imports: []const types.Import = &.{},27imports: []const Wasm.Import = &.{},
32/// Parsed function section28/// Parsed function section
33functions: []const std.wasm.Func = &.{},29functions: []const std.wasm.Func = &.{},
34/// Parsed table section30/// Parsed table section
...@@ -38,7 +34,7 @@ memories: []const std.wasm.Memory = &.{},...@@ -38,7 +34,7 @@ memories: []const std.wasm.Memory = &.{},
38/// Parsed global section34/// Parsed global section
39globals: []const std.wasm.Global = &.{},35globals: []const std.wasm.Global = &.{},
40/// Parsed export section36/// Parsed export section
41exports: []const types.Export = &.{},37exports: []const Wasm.Export = &.{},
42/// Parsed element section38/// Parsed element section
43elements: []const std.wasm.Element = &.{},39elements: []const std.wasm.Element = &.{},
44/// Represents the function ID that must be called on startup.40/// Represents the function ID that must be called on startup.
...@@ -48,18 +44,18 @@ start: ?u32 = null,...@@ -48,18 +44,18 @@ start: ?u32 = null,
48/// A slice of features that tell the linker what features are mandatory,44/// A slice of features that tell the linker what features are mandatory,
49/// used (or therefore missing) and must generate an error when another45/// used (or therefore missing) and must generate an error when another
50/// object uses features that are not supported by the other.46/// object uses features that are not supported by the other.
51features: []const types.Feature = &.{},47features: []const Wasm.Feature = &.{},
52/// A table that maps the relocations we must perform where the key represents48/// A table that maps the relocations we must perform where the key represents
53/// the section that the list of relocations applies to.49/// the section that the list of relocations applies to.
54relocations: std.AutoArrayHashMapUnmanaged(u32, []types.Relocation) = .empty,50relocations: std.AutoArrayHashMapUnmanaged(u32, []Wasm.Relocation) = .empty,
55/// Table of symbols belonging to this Object file51/// Table of symbols belonging to this Object file
56symtable: []Symbol = &.{},52symtable: []Symbol = &.{},
57/// Extra metadata about the linking section, such as alignment of segments and their name53/// Extra metadata about the linking section, such as alignment of segments and their name
58segment_info: []const types.Segment = &.{},54segment_info: []const Wasm.NamedSegment = &.{},
59/// A sequence of function initializers that must be called on startup55/// A sequence of function initializers that must be called on startup
60init_funcs: []const types.InitFunc = &.{},56init_funcs: []const Wasm.InitFunc = &.{},
61/// Comdat information57/// Comdat information
62comdat_info: []const types.Comdat = &.{},58comdat_info: []const Wasm.Comdat = &.{},
63/// Represents non-synthetic sections that can essentially be mem-cpy'd into place59/// Represents non-synthetic sections that can essentially be mem-cpy'd into place
64/// after performing relocations.60/// after performing relocations.
65relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .empty,61relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .empty,
...@@ -75,7 +71,7 @@ imported_globals_count: u32 = 0,...@@ -75,7 +71,7 @@ imported_globals_count: u32 = 0,
75imported_tables_count: u32 = 0,71imported_tables_count: u32 = 0,
7672
77/// Represents a single item within a section (depending on its `type`)73/// Represents a single item within a section (depending on its `type`)
78const RelocatableData = struct {74pub const RelocatableData = struct {
79 /// The type of the relocatable data75 /// The type of the relocatable data
80 type: Tag,76 type: Tag,
81 /// Pointer to the data of the segment, where its length is written to `size`77 /// Pointer to the data of the segment, where its length is written to `size`
...@@ -209,7 +205,7 @@ pub fn deinit(object: *Object, gpa: Allocator) void {...@@ -209,7 +205,7 @@ pub fn deinit(object: *Object, gpa: Allocator) void {
209205
210/// Finds the import within the list of imports from a given kind and index of that kind.206/// Finds the import within the list of imports from a given kind and index of that kind.
211/// Asserts the import exists207/// Asserts the import exists
212pub fn findImport(object: *const Object, sym: Symbol) types.Import {208pub fn findImport(object: *const Object, sym: Symbol) Wasm.Import {
213 var i: u32 = 0;209 var i: u32 = 0;
214 return for (object.imports) |import| {210 return for (object.imports) |import| {
215 if (std.meta.activeTag(import.kind) == sym.tag.externalType()) {211 if (std.meta.activeTag(import.kind) == sym.tag.externalType()) {
...@@ -261,7 +257,7 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S...@@ -261,7 +257,7 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S
261 return error.MissingTableSymbols;257 return error.MissingTableSymbols;
262 }258 }
263259
264 const table_import: types.Import = for (object.imports) |imp| {260 const table_import: Wasm.Import = for (object.imports) |imp| {
265 if (imp.kind == .table) {261 if (imp.kind == .table) {
266 break imp;262 break imp;
267 }263 }
...@@ -592,13 +588,13 @@ fn Parser(comptime ReaderType: type) type {...@@ -592,13 +588,13 @@ fn Parser(comptime ReaderType: type) type {
592 const diags = &parser.wasm_file.base.comp.link_diags;588 const diags = &parser.wasm_file.base.comp.link_diags;
593 const reader = parser.reader.reader();589 const reader = parser.reader.reader();
594 for (try readVec(&parser.object.features, reader, gpa)) |*feature| {590 for (try readVec(&parser.object.features, reader, gpa)) |*feature| {
595 const prefix = try readEnum(types.Feature.Prefix, reader);591 const prefix = try readEnum(Wasm.Feature.Prefix, reader);
596 const name_len = try leb.readUleb128(u32, reader);592 const name_len = try leb.readUleb128(u32, reader);
597 const name = try gpa.alloc(u8, name_len);593 const name = try gpa.alloc(u8, name_len);
598 defer gpa.free(name);594 defer gpa.free(name);
599 try reader.readNoEof(name);595 try reader.readNoEof(name);
600596
601 const tag = types.known_features.get(name) orelse {597 const tag = Wasm.known_features.get(name) orelse {
602 var err = try diags.addErrorWithNotes(1);598 var err = try diags.addErrorWithNotes(1);
603 try err.addMsg("Object file contains unknown feature: {s}", .{name});599 try err.addMsg("Object file contains unknown feature: {s}", .{name});
604 try err.addNote("defined in '{s}'", .{parser.object.path});600 try err.addNote("defined in '{s}'", .{parser.object.path});
...@@ -618,7 +614,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -618,7 +614,7 @@ fn Parser(comptime ReaderType: type) type {
618 const reader = parser.reader.reader();614 const reader = parser.reader.reader();
619 const section = try leb.readUleb128(u32, reader);615 const section = try leb.readUleb128(u32, reader);
620 const count = try leb.readUleb128(u32, reader);616 const count = try leb.readUleb128(u32, reader);
621 const relocations = try gpa.alloc(types.Relocation, count);617 const relocations = try gpa.alloc(Wasm.Relocation, count);
622 errdefer gpa.free(relocations);618 errdefer gpa.free(relocations);
623619
624 log.debug("Found {d} relocations for section ({d})", .{620 log.debug("Found {d} relocations for section ({d})", .{
...@@ -628,7 +624,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -628,7 +624,7 @@ fn Parser(comptime ReaderType: type) type {
628624
629 for (relocations) |*relocation| {625 for (relocations) |*relocation| {
630 const rel_type = try reader.readByte();626 const rel_type = try reader.readByte();
631 const rel_type_enum = std.meta.intToEnum(types.Relocation.RelocationType, rel_type) catch return error.MalformedSection;627 const rel_type_enum = std.meta.intToEnum(Wasm.Relocation.RelocationType, rel_type) catch return error.MalformedSection;
632 relocation.* = .{628 relocation.* = .{
633 .relocation_type = rel_type_enum,629 .relocation_type = rel_type_enum,
634 .offset = try leb.readUleb128(u32, reader),630 .offset = try leb.readUleb128(u32, reader),
...@@ -671,7 +667,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -671,7 +667,7 @@ fn Parser(comptime ReaderType: type) type {
671 /// such as access to the `import` section to find the name of a symbol.667 /// such as access to the `import` section to find the name of a symbol.
672 fn parseSubsection(parser: *ObjectParser, gpa: Allocator, reader: anytype) !void {668 fn parseSubsection(parser: *ObjectParser, gpa: Allocator, reader: anytype) !void {
673 const sub_type = try leb.readUleb128(u8, reader);669 const sub_type = try leb.readUleb128(u8, reader);
674 log.debug("Found subsection: {s}", .{@tagName(@as(types.SubsectionType, @enumFromInt(sub_type)))});670 log.debug("Found subsection: {s}", .{@tagName(@as(Wasm.SubsectionType, @enumFromInt(sub_type)))});
675 const payload_len = try leb.readUleb128(u32, reader);671 const payload_len = try leb.readUleb128(u32, reader);
676 if (payload_len == 0) return;672 if (payload_len == 0) return;
677673
...@@ -681,9 +677,9 @@ fn Parser(comptime ReaderType: type) type {...@@ -681,9 +677,9 @@ fn Parser(comptime ReaderType: type) type {
681 // every subsection contains a 'count' field677 // every subsection contains a 'count' field
682 const count = try leb.readUleb128(u32, limited_reader);678 const count = try leb.readUleb128(u32, limited_reader);
683679
684 switch (@as(types.SubsectionType, @enumFromInt(sub_type))) {680 switch (@as(Wasm.SubsectionType, @enumFromInt(sub_type))) {
685 .WASM_SEGMENT_INFO => {681 .WASM_SEGMENT_INFO => {
686 const segments = try gpa.alloc(types.Segment, count);682 const segments = try gpa.alloc(Wasm.NamedSegment, count);
687 errdefer gpa.free(segments);683 errdefer gpa.free(segments);
688 for (segments) |*segment| {684 for (segments) |*segment| {
689 const name_len = try leb.readUleb128(u32, reader);685 const name_len = try leb.readUleb128(u32, reader);
...@@ -704,13 +700,13 @@ fn Parser(comptime ReaderType: type) type {...@@ -704,13 +700,13 @@ fn Parser(comptime ReaderType: type) type {
704 // support legacy object files that specified being TLS by the name instead of the TLS flag.700 // support legacy object files that specified being TLS by the name instead of the TLS flag.
705 if (!segment.isTLS() and (std.mem.startsWith(u8, segment.name, ".tdata") or std.mem.startsWith(u8, segment.name, ".tbss"))) {701 if (!segment.isTLS() and (std.mem.startsWith(u8, segment.name, ".tdata") or std.mem.startsWith(u8, segment.name, ".tbss"))) {
706 // set the flag so we can simply check for the flag in the rest of the linker.702 // set the flag so we can simply check for the flag in the rest of the linker.
707 segment.flags |= @intFromEnum(types.Segment.Flags.WASM_SEG_FLAG_TLS);703 segment.flags |= @intFromEnum(Wasm.NamedSegment.Flags.WASM_SEG_FLAG_TLS);
708 }704 }
709 }705 }
710 parser.object.segment_info = segments;706 parser.object.segment_info = segments;
711 },707 },
712 .WASM_INIT_FUNCS => {708 .WASM_INIT_FUNCS => {
713 const funcs = try gpa.alloc(types.InitFunc, count);709 const funcs = try gpa.alloc(Wasm.InitFunc, count);
714 errdefer gpa.free(funcs);710 errdefer gpa.free(funcs);
715 for (funcs) |*func| {711 for (funcs) |*func| {
716 func.* = .{712 func.* = .{
...@@ -722,7 +718,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -722,7 +718,7 @@ fn Parser(comptime ReaderType: type) type {
722 parser.object.init_funcs = funcs;718 parser.object.init_funcs = funcs;
723 },719 },
724 .WASM_COMDAT_INFO => {720 .WASM_COMDAT_INFO => {
725 const comdats = try gpa.alloc(types.Comdat, count);721 const comdats = try gpa.alloc(Wasm.Comdat, count);
726 errdefer gpa.free(comdats);722 errdefer gpa.free(comdats);
727 for (comdats) |*comdat| {723 for (comdats) |*comdat| {
728 const name_len = try leb.readUleb128(u32, reader);724 const name_len = try leb.readUleb128(u32, reader);
...@@ -736,11 +732,11 @@ fn Parser(comptime ReaderType: type) type {...@@ -736,11 +732,11 @@ fn Parser(comptime ReaderType: type) type {
736 }732 }
737733
738 const symbol_count = try leb.readUleb128(u32, reader);734 const symbol_count = try leb.readUleb128(u32, reader);
739 const symbols = try gpa.alloc(types.ComdatSym, symbol_count);735 const symbols = try gpa.alloc(Wasm.ComdatSym, symbol_count);
740 errdefer gpa.free(symbols);736 errdefer gpa.free(symbols);
741 for (symbols) |*symbol| {737 for (symbols) |*symbol| {
742 symbol.* = .{738 symbol.* = .{
743 .kind = @as(types.ComdatSym.Type, @enumFromInt(try leb.readUleb128(u8, reader))),739 .kind = @as(Wasm.ComdatSym.Type, @enumFromInt(try leb.readUleb128(u8, reader))),
744 .index = try leb.readUleb128(u32, reader),740 .index = try leb.readUleb128(u32, reader),
745 };741 };
746 }742 }
...@@ -921,93 +917,3 @@ fn assertEnd(reader: anytype) !void {...@@ -921,93 +917,3 @@ fn assertEnd(reader: anytype) !void {
921 if (len != 0) return error.MalformedSection;917 if (len != 0) return error.MalformedSection;
922 if (reader.context.bytes_left != 0) return error.MalformedSection;918 if (reader.context.bytes_left != 0) return error.MalformedSection;
923}919}
924
925/// Parses an object file into atoms, for code and data sections
926pub fn parseSymbolIntoAtom(object: *Object, wasm: *Wasm, symbol_index: Symbol.Index) !Atom.Index {
927 const comp = wasm.base.comp;
928 const gpa = comp.gpa;
929 const symbol = &object.symtable[@intFromEnum(symbol_index)];
930 const relocatable_data: RelocatableData = switch (symbol.tag) {
931 .function => object.relocatable_data.get(.code).?[symbol.index - object.imported_functions_count],
932 .data => object.relocatable_data.get(.data).?[symbol.index],
933 .section => blk: {
934 const data = object.relocatable_data.get(.custom).?;
935 for (data) |dat| {
936 if (dat.section_index == symbol.index) {
937 break :blk dat;
938 }
939 }
940 unreachable;
941 },
942 else => unreachable,
943 };
944 const final_index = try wasm.getMatchingSegment(object.index, symbol_index);
945 const atom_index = try wasm.createAtom(symbol_index, object.index);
946 try wasm.appendAtomAtIndex(final_index, atom_index);
947
948 const atom = wasm.getAtomPtr(atom_index);
949 atom.size = relocatable_data.size;
950 atom.alignment = relocatable_data.getAlignment(object);
951 atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
952 atom.original_offset = relocatable_data.offset;
953
954 const segment: *Wasm.Segment = &wasm.segments.items[final_index];
955 if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
956 segment.alignment = segment.alignment.max(atom.alignment);
957 }
958
959 if (object.relocations.get(relocatable_data.section_index)) |relocations| {
960 const start = searchRelocStart(relocations, relocatable_data.offset);
961 const len = searchRelocEnd(relocations[start..], relocatable_data.offset + atom.size);
962 atom.relocs = std.ArrayListUnmanaged(types.Relocation).fromOwnedSlice(relocations[start..][0..len]);
963 for (atom.relocs.items) |reloc| {
964 switch (reloc.relocation_type) {
965 .R_WASM_TABLE_INDEX_I32,
966 .R_WASM_TABLE_INDEX_I64,
967 .R_WASM_TABLE_INDEX_SLEB,
968 .R_WASM_TABLE_INDEX_SLEB64,
969 => {
970 try wasm.function_table.put(gpa, .{
971 .file = object.index,
972 .index = @enumFromInt(reloc.index),
973 }, 0);
974 },
975 .R_WASM_GLOBAL_INDEX_I32,
976 .R_WASM_GLOBAL_INDEX_LEB,
977 => {
978 const sym = object.symtable[reloc.index];
979 if (sym.tag != .global) {
980 try wasm.got_symbols.append(gpa, .{ .file = object.index, .index = @enumFromInt(reloc.index) });
981 }
982 },
983 else => {},
984 }
985 }
986 }
987
988 return atom_index;
989}
990
991fn searchRelocStart(relocs: []const types.Relocation, address: u32) usize {
992 var min: usize = 0;
993 var max: usize = relocs.len;
994 while (min < max) {
995 const index = (min + max) / 2;
996 const curr = relocs[index];
997 if (curr.offset < address) {
998 min = index + 1;
999 } else {
1000 max = index;
1001 }
1002 }
1003 return min;
1004}
1005
1006fn searchRelocEnd(relocs: []const types.Relocation, address: u32) usize {
1007 for (relocs, 0..relocs.len) |reloc, index| {
1008 if (reloc.offset > address) {
1009 return index;
1010 }
1011 }
1012 return relocs.len;
1013}
src/link/Wasm/Symbol.zig-1
...@@ -206,5 +206,4 @@ pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatO...@@ -206,5 +206,4 @@ pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatO
206}206}
207207
208const std = @import("std");208const std = @import("std");
209const types = @import("types.zig");
210const Symbol = @This();209const Symbol = @This();
src/link/Wasm/ZigObject.zig+126-130
...@@ -4,8 +4,6 @@...@@ -4,8 +4,6 @@
4//! Think about this as fake in-memory Object file for the Zig module.4//! Think about this as fake in-memory Object file for the Zig module.
55
6path: []const u8,6path: []const u8,
7/// Index within the list of relocatable objects of the linker driver.
8index: File.Index,
9/// Map of all `Nav` that are currently alive.7/// Map of all `Nav` that are currently alive.
10/// Each index maps to the corresponding `NavInfo`.8/// Each index maps to the corresponding `NavInfo`.
11navs: std.AutoHashMapUnmanaged(InternPool.Nav.Index, NavInfo) = .empty,9navs: std.AutoHashMapUnmanaged(InternPool.Nav.Index, NavInfo) = .empty,
...@@ -16,8 +14,8 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .empty,...@@ -16,8 +14,8 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .empty,
16functions: std.ArrayListUnmanaged(std.wasm.Func) = .empty,14functions: std.ArrayListUnmanaged(std.wasm.Func) = .empty,
17/// List of indexes pointing to an entry within the `functions` list which has been removed.15/// List of indexes pointing to an entry within the `functions` list which has been removed.
18functions_free_list: std.ArrayListUnmanaged(u32) = .empty,16functions_free_list: std.ArrayListUnmanaged(u32) = .empty,
19/// Map of symbol locations, represented by its `types.Import`.17/// Map of symbol locations, represented by its `Wasm.Import`.
20imports: std.AutoHashMapUnmanaged(Symbol.Index, types.Import) = .empty,18imports: std.AutoHashMapUnmanaged(Symbol.Index, Wasm.Import) = .empty,
21/// List of WebAssembly globals.19/// List of WebAssembly globals.
22globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,20globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,
23/// Mapping between an `Atom` and its type index representing the Wasm21/// Mapping between an `Atom` and its type index representing the Wasm
...@@ -30,7 +28,7 @@ global_syms: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .empty,...@@ -30,7 +28,7 @@ global_syms: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .empty,
30/// List of symbol indexes which are free to be used.28/// List of symbol indexes which are free to be used.
31symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .empty,29symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .empty,
32/// Extra metadata about the linking section, such as alignment of segments and their name.30/// Extra metadata about the linking section, such as alignment of segments and their name.
33segment_info: std.ArrayListUnmanaged(types.Segment) = .empty,31segment_info: std.ArrayListUnmanaged(Wasm.NamedSegment) = .empty,
34/// List of indexes which contain a free slot in the `segment_info` list.32/// List of indexes which contain a free slot in the `segment_info` list.
35segment_free_list: std.ArrayListUnmanaged(u32) = .empty,33segment_free_list: std.ArrayListUnmanaged(u32) = .empty,
36/// File encapsulated string table, used to deduplicate strings within the generated file.34/// File encapsulated string table, used to deduplicate strings within the generated file.
...@@ -117,39 +115,39 @@ const NavInfo = struct {...@@ -117,39 +115,39 @@ const NavInfo = struct {
117};115};
118116
119/// Initializes the `ZigObject` with initial symbols.117/// Initializes the `ZigObject` with initial symbols.
120pub fn init(zig_object: *ZigObject, wasm_file: *Wasm) !void {118pub fn init(zig_object: *ZigObject, wasm: *Wasm) !void {
121 // Initialize an undefined global with the name __stack_pointer. Codegen will use119 // Initialize an undefined global with the name __stack_pointer. Codegen will use
122 // this to generate relocations when moving the stack pointer. This symbol will be120 // this to generate relocations when moving the stack pointer. This symbol will be
123 // resolved automatically by the final linking stage.121 // resolved automatically by the final linking stage.
124 try zig_object.createStackPointer(wasm_file);122 try zig_object.createStackPointer(wasm);
125123
126 // TODO: Initialize debug information when we reimplement Dwarf support.124 // TODO: Initialize debug information when we reimplement Dwarf support.
127}125}
128126
129fn createStackPointer(zig_object: *ZigObject, wasm_file: *Wasm) !void {127fn createStackPointer(zig_object: *ZigObject, wasm: *Wasm) !void {
130 const gpa = wasm_file.base.comp.gpa;128 const gpa = wasm.base.comp.gpa;
131 const sym_index = try zig_object.getGlobalSymbol(gpa, "__stack_pointer");129 const sym_index = try zig_object.getGlobalSymbol(gpa, "__stack_pointer");
132 const sym = zig_object.symbol(sym_index);130 const sym = zig_object.symbol(sym_index);
133 sym.index = zig_object.imported_globals_count;131 sym.index = zig_object.imported_globals_count;
134 sym.tag = .global;132 sym.tag = .global;
135 const is_wasm32 = wasm_file.base.comp.root_mod.resolved_target.result.cpu.arch == .wasm32;133 const is_wasm32 = wasm.base.comp.root_mod.resolved_target.result.cpu.arch == .wasm32;
136 try zig_object.imports.putNoClobber(gpa, sym_index, .{134 try zig_object.imports.putNoClobber(gpa, sym_index, .{
137 .name = sym.name,135 .name = sym.name,
138 .module_name = try zig_object.string_table.insert(gpa, wasm_file.host_name),136 .module_name = try zig_object.string_table.insert(gpa, wasm.host_name),
139 .kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } },137 .kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } },
140 });138 });
141 zig_object.imported_globals_count += 1;139 zig_object.imported_globals_count += 1;
142 zig_object.stack_pointer_sym = sym_index;140 zig_object.stack_pointer_sym = sym_index;
143}141}
144142
145fn symbol(zig_object: *const ZigObject, index: Symbol.Index) *Symbol {143pub fn symbol(zig_object: *const ZigObject, index: Symbol.Index) *Symbol {
146 return &zig_object.symbols.items[@intFromEnum(index)];144 return &zig_object.symbols.items[@intFromEnum(index)];
147}145}
148146
149/// Frees and invalidates all memory of the incrementally compiled Zig module.147/// Frees and invalidates all memory of the incrementally compiled Zig module.
150/// It is illegal behavior to access the `ZigObject` after calling `deinit`.148/// It is illegal behavior to access the `ZigObject` after calling `deinit`.
151pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {149pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
152 const gpa = wasm_file.base.comp.gpa;150 const gpa = wasm.base.comp.gpa;
153 for (zig_object.segment_info.items) |segment_info| {151 for (zig_object.segment_info.items) |segment_info| {
154 gpa.free(segment_info.name);152 gpa.free(segment_info.name);
155 }153 }
...@@ -157,9 +155,9 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {...@@ -157,9 +155,9 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
157 {155 {
158 var it = zig_object.navs.valueIterator();156 var it = zig_object.navs.valueIterator();
159 while (it.next()) |nav_info| {157 while (it.next()) |nav_info| {
160 const atom = wasm_file.getAtomPtr(nav_info.atom);158 const atom = wasm.getAtomPtr(nav_info.atom);
161 for (atom.locals.items) |local_index| {159 for (atom.locals.items) |local_index| {
162 const local_atom = wasm_file.getAtomPtr(local_index);160 const local_atom = wasm.getAtomPtr(local_index);
163 local_atom.deinit(gpa);161 local_atom.deinit(gpa);
164 }162 }
165 atom.deinit(gpa);163 atom.deinit(gpa);
...@@ -168,24 +166,24 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {...@@ -168,24 +166,24 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
168 }166 }
169 {167 {
170 for (zig_object.uavs.values()) |atom_index| {168 for (zig_object.uavs.values()) |atom_index| {
171 const atom = wasm_file.getAtomPtr(atom_index);169 const atom = wasm.getAtomPtr(atom_index);
172 for (atom.locals.items) |local_index| {170 for (atom.locals.items) |local_index| {
173 const local_atom = wasm_file.getAtomPtr(local_index);171 const local_atom = wasm.getAtomPtr(local_index);
174 local_atom.deinit(gpa);172 local_atom.deinit(gpa);
175 }173 }
176 atom.deinit(gpa);174 atom.deinit(gpa);
177 }175 }
178 }176 }
179 if (zig_object.findGlobalSymbol("__zig_errors_len")) |sym_index| {177 if (zig_object.findGlobalSymbol("__zig_errors_len")) |sym_index| {
180 const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = sym_index }).?;178 const atom_index = wasm.symbol_atom.get(.{ .file = .zig_object, .index = sym_index }).?;
181 wasm_file.getAtomPtr(atom_index).deinit(gpa);179 wasm.getAtomPtr(atom_index).deinit(gpa);
182 }180 }
183 if (wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = zig_object.error_table_symbol })) |atom_index| {181 if (wasm.symbol_atom.get(.{ .file = .zig_object, .index = zig_object.error_table_symbol })) |atom_index| {
184 const atom = wasm_file.getAtomPtr(atom_index);182 const atom = wasm.getAtomPtr(atom_index);
185 atom.deinit(gpa);183 atom.deinit(gpa);
186 }184 }
187 for (zig_object.synthetic_functions.items) |atom_index| {185 for (zig_object.synthetic_functions.items) |atom_index| {
188 const atom = wasm_file.getAtomPtr(atom_index);186 const atom = wasm.getAtomPtr(atom_index);
189 atom.deinit(gpa);187 atom.deinit(gpa);
190 }188 }
191 zig_object.synthetic_functions.deinit(gpa);189 zig_object.synthetic_functions.deinit(gpa);
...@@ -193,7 +191,7 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {...@@ -193,7 +191,7 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
193 ty.deinit(gpa);191 ty.deinit(gpa);
194 }192 }
195 if (zig_object.error_names_atom != .null) {193 if (zig_object.error_names_atom != .null) {
196 const atom = wasm_file.getAtomPtr(zig_object.error_names_atom);194 const atom = wasm.getAtomPtr(zig_object.error_names_atom);
197 atom.deinit(gpa);195 atom.deinit(gpa);
198 }196 }
199 zig_object.global_syms.deinit(gpa);197 zig_object.global_syms.deinit(gpa);
...@@ -240,7 +238,7 @@ pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.In...@@ -240,7 +238,7 @@ pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.In
240// the file on flush().238// the file on flush().
241pub fn updateNav(239pub fn updateNav(
242 zig_object: *ZigObject,240 zig_object: *ZigObject,
243 wasm_file: *Wasm,241 wasm: *Wasm,
244 pt: Zcu.PerThread,242 pt: Zcu.PerThread,
245 nav_index: InternPool.Nav.Index,243 nav_index: InternPool.Nav.Index,
246) !void {244) !void {
...@@ -260,19 +258,19 @@ pub fn updateNav(...@@ -260,19 +258,19 @@ pub fn updateNav(
260 };258 };
261259
262 if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {260 if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
263 const gpa = wasm_file.base.comp.gpa;261 const gpa = wasm.base.comp.gpa;
264 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);262 const atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);
265 const atom = wasm_file.getAtomPtr(atom_index);263 const atom = wasm.getAtomPtr(atom_index);
266 atom.clear();264 atom.clear();
267265
268 if (is_extern)266 if (is_extern)
269 return zig_object.addOrUpdateImport(wasm_file, nav.name.toSlice(ip), atom.sym_index, lib_name.toSlice(ip), null);267 return zig_object.addOrUpdateImport(wasm, nav.name.toSlice(ip), atom.sym_index, lib_name.toSlice(ip), null);
270268
271 var code_writer = std.ArrayList(u8).init(gpa);269 var code_writer = std.ArrayList(u8).init(gpa);
272 defer code_writer.deinit();270 defer code_writer.deinit();
273271
274 const res = try codegen.generateSymbol(272 const res = try codegen.generateSymbol(
275 &wasm_file.base,273 &wasm.base,
276 pt,274 pt,
277 zcu.navSrcLoc(nav_index),275 zcu.navSrcLoc(nav_index),
278 nav_init,276 nav_init,
...@@ -288,13 +286,13 @@ pub fn updateNav(...@@ -288,13 +286,13 @@ pub fn updateNav(
288 },286 },
289 };287 };
290288
291 try zig_object.finishUpdateNav(wasm_file, pt, nav_index, code);289 try zig_object.finishUpdateNav(wasm, pt, nav_index, code);
292 }290 }
293}291}
294292
295pub fn updateFunc(293pub fn updateFunc(
296 zig_object: *ZigObject,294 zig_object: *ZigObject,
297 wasm_file: *Wasm,295 wasm: *Wasm,
298 pt: Zcu.PerThread,296 pt: Zcu.PerThread,
299 func_index: InternPool.Index,297 func_index: InternPool.Index,
300 air: Air,298 air: Air,
...@@ -303,14 +301,14 @@ pub fn updateFunc(...@@ -303,14 +301,14 @@ pub fn updateFunc(
303 const zcu = pt.zcu;301 const zcu = pt.zcu;
304 const gpa = zcu.gpa;302 const gpa = zcu.gpa;
305 const func = pt.zcu.funcInfo(func_index);303 const func = pt.zcu.funcInfo(func_index);
306 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, func.owner_nav);304 const atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, func.owner_nav);
307 const atom = wasm_file.getAtomPtr(atom_index);305 const atom = wasm.getAtomPtr(atom_index);
308 atom.clear();306 atom.clear();
309307
310 var code_writer = std.ArrayList(u8).init(gpa);308 var code_writer = std.ArrayList(u8).init(gpa);
311 defer code_writer.deinit();309 defer code_writer.deinit();
312 const result = try codegen.generateFunction(310 const result = try codegen.generateFunction(
313 &wasm_file.base,311 &wasm.base,
314 pt,312 pt,
315 zcu.navSrcLoc(func.owner_nav),313 zcu.navSrcLoc(func.owner_nav),
316 func_index,314 func_index,
...@@ -328,12 +326,12 @@ pub fn updateFunc(...@@ -328,12 +326,12 @@ pub fn updateFunc(
328 },326 },
329 };327 };
330328
331 return zig_object.finishUpdateNav(wasm_file, pt, func.owner_nav, code);329 return zig_object.finishUpdateNav(wasm, pt, func.owner_nav, code);
332}330}
333331
334fn finishUpdateNav(332fn finishUpdateNav(
335 zig_object: *ZigObject,333 zig_object: *ZigObject,
336 wasm_file: *Wasm,334 wasm: *Wasm,
337 pt: Zcu.PerThread,335 pt: Zcu.PerThread,
338 nav_index: InternPool.Nav.Index,336 nav_index: InternPool.Nav.Index,
339 code: []const u8,337 code: []const u8,
...@@ -345,7 +343,7 @@ fn finishUpdateNav(...@@ -345,7 +343,7 @@ fn finishUpdateNav(
345 const nav_val = zcu.navValue(nav_index);343 const nav_val = zcu.navValue(nav_index);
346 const nav_info = zig_object.navs.get(nav_index).?;344 const nav_info = zig_object.navs.get(nav_index).?;
347 const atom_index = nav_info.atom;345 const atom_index = nav_info.atom;
348 const atom = wasm_file.getAtomPtr(atom_index);346 const atom = wasm.getAtomPtr(atom_index);
349 const sym = zig_object.symbol(atom.sym_index);347 const sym = zig_object.symbol(atom.sym_index);
350 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));348 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
351 try atom.code.appendSlice(gpa, code);349 try atom.code.appendSlice(gpa, code);
...@@ -376,7 +374,7 @@ fn finishUpdateNav(...@@ -376,7 +374,7 @@ fn finishUpdateNav(
376 }374 }
377 break :name ".bss.";375 break :name ".bss.";
378 };376 };
379 if ((wasm_file.base.isObject() or wasm_file.base.comp.config.import_memory) and377 if ((wasm.base.isObject() or wasm.base.comp.config.import_memory) and
380 std.mem.startsWith(u8, segment_name, ".bss"))378 std.mem.startsWith(u8, segment_name, ".bss"))
381 {379 {
382 @memset(atom.code.items, 0);380 @memset(atom.code.items, 0);
...@@ -422,7 +420,7 @@ fn createDataSegment(...@@ -422,7 +420,7 @@ fn createDataSegment(
422/// The newly created Atom is empty with default fields as specified by `Atom.empty`.420/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
423pub fn getOrCreateAtomForNav(421pub fn getOrCreateAtomForNav(
424 zig_object: *ZigObject,422 zig_object: *ZigObject,
425 wasm_file: *Wasm,423 wasm: *Wasm,
426 pt: Zcu.PerThread,424 pt: Zcu.PerThread,
427 nav_index: InternPool.Nav.Index,425 nav_index: InternPool.Nav.Index,
428) !Atom.Index {426) !Atom.Index {
...@@ -431,7 +429,7 @@ pub fn getOrCreateAtomForNav(...@@ -431,7 +429,7 @@ pub fn getOrCreateAtomForNav(
431 const gop = try zig_object.navs.getOrPut(gpa, nav_index);429 const gop = try zig_object.navs.getOrPut(gpa, nav_index);
432 if (!gop.found_existing) {430 if (!gop.found_existing) {
433 const sym_index = try zig_object.allocateSymbol(gpa);431 const sym_index = try zig_object.allocateSymbol(gpa);
434 gop.value_ptr.* = .{ .atom = try wasm_file.createAtom(sym_index, zig_object.index) };432 gop.value_ptr.* = .{ .atom = try wasm.createAtom(sym_index, .zig_object) };
435 const nav = ip.getNav(nav_index);433 const nav = ip.getNav(nav_index);
436 const sym = zig_object.symbol(sym_index);434 const sym = zig_object.symbol(sym_index);
437 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));435 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
...@@ -441,13 +439,13 @@ pub fn getOrCreateAtomForNav(...@@ -441,13 +439,13 @@ pub fn getOrCreateAtomForNav(
441439
442pub fn lowerUav(440pub fn lowerUav(
443 zig_object: *ZigObject,441 zig_object: *ZigObject,
444 wasm_file: *Wasm,442 wasm: *Wasm,
445 pt: Zcu.PerThread,443 pt: Zcu.PerThread,
446 uav: InternPool.Index,444 uav: InternPool.Index,
447 explicit_alignment: InternPool.Alignment,445 explicit_alignment: InternPool.Alignment,
448 src_loc: Zcu.LazySrcLoc,446 src_loc: Zcu.LazySrcLoc,
449) !codegen.GenResult {447) !codegen.GenResult {
450 const gpa = wasm_file.base.comp.gpa;448 const gpa = wasm.base.comp.gpa;
451 const gop = try zig_object.uavs.getOrPut(gpa, uav);449 const gop = try zig_object.uavs.getOrPut(gpa, uav);
452 if (!gop.found_existing) {450 if (!gop.found_existing) {
453 var name_buf: [32]u8 = undefined;451 var name_buf: [32]u8 = undefined;
...@@ -455,13 +453,13 @@ pub fn lowerUav(...@@ -455,13 +453,13 @@ pub fn lowerUav(
455 @intFromEnum(uav),453 @intFromEnum(uav),
456 }) catch unreachable;454 }) catch unreachable;
457455
458 switch (try zig_object.lowerConst(wasm_file, pt, name, Value.fromInterned(uav), src_loc)) {456 switch (try zig_object.lowerConst(wasm, pt, name, Value.fromInterned(uav), src_loc)) {
459 .ok => |atom_index| zig_object.uavs.values()[gop.index] = atom_index,457 .ok => |atom_index| zig_object.uavs.values()[gop.index] = atom_index,
460 .fail => |em| return .{ .fail = em },458 .fail => |em| return .{ .fail = em },
461 }459 }
462 }460 }
463461
464 const atom = wasm_file.getAtomPtr(zig_object.uavs.values()[gop.index]);462 const atom = wasm.getAtomPtr(zig_object.uavs.values()[gop.index]);
465 atom.alignment = switch (atom.alignment) {463 atom.alignment = switch (atom.alignment) {
466 .none => explicit_alignment,464 .none => explicit_alignment,
467 else => switch (explicit_alignment) {465 else => switch (explicit_alignment) {
...@@ -479,25 +477,25 @@ const LowerConstResult = union(enum) {...@@ -479,25 +477,25 @@ const LowerConstResult = union(enum) {
479477
480fn lowerConst(478fn lowerConst(
481 zig_object: *ZigObject,479 zig_object: *ZigObject,
482 wasm_file: *Wasm,480 wasm: *Wasm,
483 pt: Zcu.PerThread,481 pt: Zcu.PerThread,
484 name: []const u8,482 name: []const u8,
485 val: Value,483 val: Value,
486 src_loc: Zcu.LazySrcLoc,484 src_loc: Zcu.LazySrcLoc,
487) !LowerConstResult {485) !LowerConstResult {
488 const gpa = wasm_file.base.comp.gpa;486 const gpa = wasm.base.comp.gpa;
489 const zcu = wasm_file.base.comp.zcu.?;487 const zcu = wasm.base.comp.zcu.?;
490488
491 const ty = val.typeOf(zcu);489 const ty = val.typeOf(zcu);
492490
493 // Create and initialize a new local symbol and atom491 // Create and initialize a new local symbol and atom
494 const sym_index = try zig_object.allocateSymbol(gpa);492 const sym_index = try zig_object.allocateSymbol(gpa);
495 const atom_index = try wasm_file.createAtom(sym_index, zig_object.index);493 const atom_index = try wasm.createAtom(sym_index, .zig_object);
496 var value_bytes = std.ArrayList(u8).init(gpa);494 var value_bytes = std.ArrayList(u8).init(gpa);
497 defer value_bytes.deinit();495 defer value_bytes.deinit();
498496
499 const code = code: {497 const code = code: {
500 const atom = wasm_file.getAtomPtr(atom_index);498 const atom = wasm.getAtomPtr(atom_index);
501 atom.alignment = ty.abiAlignment(zcu);499 atom.alignment = ty.abiAlignment(zcu);
502 const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name });500 const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name });
503 errdefer gpa.free(segment_name);501 errdefer gpa.free(segment_name);
...@@ -514,7 +512,7 @@ fn lowerConst(...@@ -514,7 +512,7 @@ fn lowerConst(
514 };512 };
515513
516 const result = try codegen.generateSymbol(514 const result = try codegen.generateSymbol(
517 &wasm_file.base,515 &wasm.base,
518 pt,516 pt,
519 src_loc,517 src_loc,
520 val,518 val,
...@@ -529,7 +527,7 @@ fn lowerConst(...@@ -529,7 +527,7 @@ fn lowerConst(
529 };527 };
530 };528 };
531529
532 const atom = wasm_file.getAtomPtr(atom_index);530 const atom = wasm.getAtomPtr(atom_index);
533 atom.size = @intCast(code.len);531 atom.size = @intCast(code.len);
534 try atom.code.appendSlice(gpa, code);532 try atom.code.appendSlice(gpa, code);
535 return .{ .ok = atom_index };533 return .{ .ok = atom_index };
...@@ -538,7 +536,7 @@ fn lowerConst(...@@ -538,7 +536,7 @@ fn lowerConst(
538/// Returns the symbol index of the error name table.536/// Returns the symbol index of the error name table.
539///537///
540/// When the symbol does not yet exist, it will create a new one instead.538/// When the symbol does not yet exist, it will create a new one instead.
541pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm, pt: Zcu.PerThread) !Symbol.Index {539pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm: *Wasm, pt: Zcu.PerThread) !Symbol.Index {
542 if (zig_object.error_table_symbol != .null) {540 if (zig_object.error_table_symbol != .null) {
543 return zig_object.error_table_symbol;541 return zig_object.error_table_symbol;
544 }542 }
...@@ -546,10 +544,10 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm, pt: Zcu.Per...@@ -546,10 +544,10 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm, pt: Zcu.Per
546 // no error was referenced yet, so create a new symbol and atom for it544 // no error was referenced yet, so create a new symbol and atom for it
547 // and then return said symbol's index. The final table will be populated545 // and then return said symbol's index. The final table will be populated
548 // during `flush` when we know all possible error names.546 // during `flush` when we know all possible error names.
549 const gpa = wasm_file.base.comp.gpa;547 const gpa = wasm.base.comp.gpa;
550 const sym_index = try zig_object.allocateSymbol(gpa);548 const sym_index = try zig_object.allocateSymbol(gpa);
551 const atom_index = try wasm_file.createAtom(sym_index, zig_object.index);549 const atom_index = try wasm.createAtom(sym_index, .zig_object);
552 const atom = wasm_file.getAtomPtr(atom_index);550 const atom = wasm.getAtomPtr(atom_index);
553 const slice_ty = Type.slice_const_u8_sentinel_0;551 const slice_ty = Type.slice_const_u8_sentinel_0;
554 atom.alignment = slice_ty.abiAlignment(pt.zcu);552 atom.alignment = slice_ty.abiAlignment(pt.zcu);
555553
...@@ -573,17 +571,17 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm, pt: Zcu.Per...@@ -573,17 +571,17 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm, pt: Zcu.Per
573///571///
574/// This creates a table that consists of pointers and length to each error name.572/// This creates a table that consists of pointers and length to each error name.
575/// The table is what is being pointed to within the runtime bodies that are generated.573/// The table is what is being pointed to within the runtime bodies that are generated.
576fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm, tid: Zcu.PerThread.Id) !void {574fn populateErrorNameTable(zig_object: *ZigObject, wasm: *Wasm, tid: Zcu.PerThread.Id) !void {
577 if (zig_object.error_table_symbol == .null) return;575 if (zig_object.error_table_symbol == .null) return;
578 const gpa = wasm_file.base.comp.gpa;576 const gpa = wasm.base.comp.gpa;
579 const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = zig_object.error_table_symbol }).?;577 const atom_index = wasm.symbol_atom.get(.{ .file = .zig_object, .index = zig_object.error_table_symbol }).?;
580578
581 // Rather than creating a symbol for each individual error name,579 // Rather than creating a symbol for each individual error name,
582 // we create a symbol for the entire region of error names. We then calculate580 // we create a symbol for the entire region of error names. We then calculate
583 // the pointers into the list using addends which are appended to the relocation.581 // the pointers into the list using addends which are appended to the relocation.
584 const names_sym_index = try zig_object.allocateSymbol(gpa);582 const names_sym_index = try zig_object.allocateSymbol(gpa);
585 const names_atom_index = try wasm_file.createAtom(names_sym_index, zig_object.index);583 const names_atom_index = try wasm.createAtom(names_sym_index, .zig_object);
586 const names_atom = wasm_file.getAtomPtr(names_atom_index);584 const names_atom = wasm.getAtomPtr(names_atom_index);
587 names_atom.alignment = .@"1";585 names_atom.alignment = .@"1";
588 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names");586 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names");
589 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_names");587 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_names");
...@@ -600,9 +598,9 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm, tid: Zcu.Per...@@ -600,9 +598,9 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm, tid: Zcu.Per
600598
601 // Addend for each relocation to the table599 // Addend for each relocation to the table
602 var addend: u32 = 0;600 var addend: u32 = 0;
603 const pt: Zcu.PerThread = .{ .zcu = wasm_file.base.comp.zcu.?, .tid = tid };601 const pt: Zcu.PerThread = .{ .zcu = wasm.base.comp.zcu.?, .tid = tid };
604 const slice_ty = Type.slice_const_u8_sentinel_0;602 const slice_ty = Type.slice_const_u8_sentinel_0;
605 const atom = wasm_file.getAtomPtr(atom_index);603 const atom = wasm.getAtomPtr(atom_index);
606 {604 {
607 // TODO: remove this unreachable entry605 // TODO: remove this unreachable entry
608 try atom.code.appendNTimes(gpa, 0, 4);606 try atom.code.appendNTimes(gpa, 0, 4);
...@@ -646,7 +644,7 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm, tid: Zcu.Per...@@ -646,7 +644,7 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm, tid: Zcu.Per
646/// In all other cases, a data-symbol will be created instead.644/// In all other cases, a data-symbol will be created instead.
647pub fn addOrUpdateImport(645pub fn addOrUpdateImport(
648 zig_object: *ZigObject,646 zig_object: *ZigObject,
649 wasm_file: *Wasm,647 wasm: *Wasm,
650 /// Name of the import648 /// Name of the import
651 name: []const u8,649 name: []const u8,
652 /// Symbol index that is external650 /// Symbol index that is external
...@@ -658,7 +656,7 @@ pub fn addOrUpdateImport(...@@ -658,7 +656,7 @@ pub fn addOrUpdateImport(
658 /// is asserted instead.656 /// is asserted instead.
659 type_index: ?u32,657 type_index: ?u32,
660) !void {658) !void {
661 const gpa = wasm_file.base.comp.gpa;659 const gpa = wasm.base.comp.gpa;
662 std.debug.assert(symbol_index != .null);660 std.debug.assert(symbol_index != .null);
663 // For the import name, we use the decl's name, rather than the fully qualified name661 // For the import name, we use the decl's name, rather than the fully qualified name
664 // Also mangle the name when the lib name is set and not equal to "C" so imports with the same662 // Also mangle the name when the lib name is set and not equal to "C" so imports with the same
...@@ -682,7 +680,7 @@ pub fn addOrUpdateImport(...@@ -682,7 +680,7 @@ pub fn addOrUpdateImport(
682680
683 if (type_index) |ty_index| {681 if (type_index) |ty_index| {
684 const gop = try zig_object.imports.getOrPut(gpa, symbol_index);682 const gop = try zig_object.imports.getOrPut(gpa, symbol_index);
685 const module_name = if (lib_name) |l_name| l_name else wasm_file.host_name;683 const module_name = if (lib_name) |l_name| l_name else wasm.host_name;
686 if (!gop.found_existing) {684 if (!gop.found_existing) {
687 zig_object.imported_functions_count += 1;685 zig_object.imported_functions_count += 1;
688 }686 }
...@@ -733,7 +731,7 @@ pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []c...@@ -733,7 +731,7 @@ pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []c
733/// Returns the given pointer address731/// Returns the given pointer address
734pub fn getNavVAddr(732pub fn getNavVAddr(
735 zig_object: *ZigObject,733 zig_object: *ZigObject,
736 wasm_file: *Wasm,734 wasm: *Wasm,
737 pt: Zcu.PerThread,735 pt: Zcu.PerThread,
738 nav_index: InternPool.Nav.Index,736 nav_index: InternPool.Nav.Index,
739 reloc_info: link.File.RelocInfo,737 reloc_info: link.File.RelocInfo,
...@@ -744,12 +742,12 @@ pub fn getNavVAddr(...@@ -744,12 +742,12 @@ pub fn getNavVAddr(
744 const nav = ip.getNav(nav_index);742 const nav = ip.getNav(nav_index);
745 const target = &zcu.navFileScope(nav_index).mod.resolved_target.result;743 const target = &zcu.navFileScope(nav_index).mod.resolved_target.result;
746744
747 const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);745 const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);
748 const target_atom = wasm_file.getAtom(target_atom_index);746 const target_atom = wasm.getAtom(target_atom_index);
749 const target_symbol_index = @intFromEnum(target_atom.sym_index);747 const target_symbol_index = @intFromEnum(target_atom.sym_index);
750 switch (ip.indexToKey(nav.status.resolved.val)) {748 switch (ip.indexToKey(nav.status.resolved.val)) {
751 .@"extern" => |@"extern"| try zig_object.addOrUpdateImport(749 .@"extern" => |@"extern"| try zig_object.addOrUpdateImport(
752 wasm_file,750 wasm,
753 nav.name.toSlice(ip),751 nav.name.toSlice(ip),
754 target_atom.sym_index,752 target_atom.sym_index,
755 @"extern".lib_name.toSlice(ip),753 @"extern".lib_name.toSlice(ip),
...@@ -759,11 +757,11 @@ pub fn getNavVAddr(...@@ -759,11 +757,11 @@ pub fn getNavVAddr(
759 }757 }
760758
761 std.debug.assert(reloc_info.parent.atom_index != 0);759 std.debug.assert(reloc_info.parent.atom_index != 0);
762 const atom_index = wasm_file.symbol_atom.get(.{760 const atom_index = wasm.symbol_atom.get(.{
763 .file = zig_object.index,761 .file = .zig_object,
764 .index = @enumFromInt(reloc_info.parent.atom_index),762 .index = @enumFromInt(reloc_info.parent.atom_index),
765 }).?;763 }).?;
766 const atom = wasm_file.getAtomPtr(atom_index);764 const atom = wasm.getAtomPtr(atom_index);
767 const is_wasm32 = target.cpu.arch == .wasm32;765 const is_wasm32 = target.cpu.arch == .wasm32;
768 if (ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) {766 if (ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) {
769 std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations767 std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations
...@@ -790,22 +788,22 @@ pub fn getNavVAddr(...@@ -790,22 +788,22 @@ pub fn getNavVAddr(
790788
791pub fn getUavVAddr(789pub fn getUavVAddr(
792 zig_object: *ZigObject,790 zig_object: *ZigObject,
793 wasm_file: *Wasm,791 wasm: *Wasm,
794 uav: InternPool.Index,792 uav: InternPool.Index,
795 reloc_info: link.File.RelocInfo,793 reloc_info: link.File.RelocInfo,
796) !u64 {794) !u64 {
797 const gpa = wasm_file.base.comp.gpa;795 const gpa = wasm.base.comp.gpa;
798 const target = wasm_file.base.comp.root_mod.resolved_target.result;796 const target = wasm.base.comp.root_mod.resolved_target.result;
799 const atom_index = zig_object.uavs.get(uav).?;797 const atom_index = zig_object.uavs.get(uav).?;
800 const target_symbol_index = @intFromEnum(wasm_file.getAtom(atom_index).sym_index);798 const target_symbol_index = @intFromEnum(wasm.getAtom(atom_index).sym_index);
801799
802 const parent_atom_index = wasm_file.symbol_atom.get(.{800 const parent_atom_index = wasm.symbol_atom.get(.{
803 .file = zig_object.index,801 .file = .zig_object,
804 .index = @enumFromInt(reloc_info.parent.atom_index),802 .index = @enumFromInt(reloc_info.parent.atom_index),
805 }).?;803 }).?;
806 const parent_atom = wasm_file.getAtomPtr(parent_atom_index);804 const parent_atom = wasm.getAtomPtr(parent_atom_index);
807 const is_wasm32 = target.cpu.arch == .wasm32;805 const is_wasm32 = target.cpu.arch == .wasm32;
808 const zcu = wasm_file.base.comp.zcu.?;806 const zcu = wasm.base.comp.zcu.?;
809 const ty = Type.fromInterned(zcu.intern_pool.typeOf(uav));807 const ty = Type.fromInterned(zcu.intern_pool.typeOf(uav));
810 if (ty.zigTypeTag(zcu) == .@"fn") {808 if (ty.zigTypeTag(zcu) == .@"fn") {
811 std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations809 std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations
...@@ -832,11 +830,11 @@ pub fn getUavVAddr(...@@ -832,11 +830,11 @@ pub fn getUavVAddr(
832830
833pub fn deleteExport(831pub fn deleteExport(
834 zig_object: *ZigObject,832 zig_object: *ZigObject,
835 wasm_file: *Wasm,833 wasm: *Wasm,
836 exported: Zcu.Exported,834 exported: Zcu.Exported,
837 name: InternPool.NullTerminatedString,835 name: InternPool.NullTerminatedString,
838) void {836) void {
839 const zcu = wasm_file.base.comp.zcu.?;837 const zcu = wasm.base.comp.zcu.?;
840 const nav_index = switch (exported) {838 const nav_index = switch (exported) {
841 .nav => |nav_index| nav_index,839 .nav => |nav_index| nav_index,
842 .uav => @panic("TODO: implement Wasm linker code for exporting a constant value"),840 .uav => @panic("TODO: implement Wasm linker code for exporting a constant value"),
...@@ -846,15 +844,15 @@ pub fn deleteExport(...@@ -846,15 +844,15 @@ pub fn deleteExport(
846 const sym = zig_object.symbol(sym_index);844 const sym = zig_object.symbol(sym_index);
847 nav_info.deleteExport(sym_index);845 nav_info.deleteExport(sym_index);
848 std.debug.assert(zig_object.global_syms.remove(sym.name));846 std.debug.assert(zig_object.global_syms.remove(sym.name));
849 std.debug.assert(wasm_file.symbol_atom.remove(.{ .file = zig_object.index, .index = sym_index }));847 std.debug.assert(wasm.symbol_atom.remove(.{ .file = .zig_object, .index = sym_index }));
850 zig_object.symbols_free_list.append(wasm_file.base.comp.gpa, sym_index) catch {};848 zig_object.symbols_free_list.append(wasm.base.comp.gpa, sym_index) catch {};
851 sym.tag = .dead;849 sym.tag = .dead;
852 }850 }
853}851}
854852
855pub fn updateExports(853pub fn updateExports(
856 zig_object: *ZigObject,854 zig_object: *ZigObject,
857 wasm_file: *Wasm,855 wasm: *Wasm,
858 pt: Zcu.PerThread,856 pt: Zcu.PerThread,
859 exported: Zcu.Exported,857 exported: Zcu.Exported,
860 export_indices: []const u32,858 export_indices: []const u32,
...@@ -869,10 +867,10 @@ pub fn updateExports(...@@ -869,10 +867,10 @@ pub fn updateExports(
869 },867 },
870 };868 };
871 const nav = ip.getNav(nav_index);869 const nav = ip.getNav(nav_index);
872 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);870 const atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);
873 const nav_info = zig_object.navs.getPtr(nav_index).?;871 const nav_info = zig_object.navs.getPtr(nav_index).?;
874 const atom = wasm_file.getAtom(atom_index);872 const atom = wasm.getAtom(atom_index);
875 const atom_sym = atom.symbolLoc().getSymbol(wasm_file).*;873 const atom_sym = wasm.symbolLocSymbol(atom.symbolLoc()).*;
876 const gpa = zcu.gpa;874 const gpa = zcu.gpa;
877 log.debug("Updating exports for decl '{}'", .{nav.name.fmt(ip)});875 log.debug("Updating exports for decl '{}'", .{nav.name.fmt(ip)});
878876
...@@ -926,17 +924,17 @@ pub fn updateExports(...@@ -926,17 +924,17 @@ pub fn updateExports(
926 }924 }
927 log.debug(" with name '{s}' - {}", .{ export_string, sym });925 log.debug(" with name '{s}' - {}", .{ export_string, sym });
928 try zig_object.global_syms.put(gpa, export_name, sym_index);926 try zig_object.global_syms.put(gpa, export_name, sym_index);
929 try wasm_file.symbol_atom.put(gpa, .{ .file = zig_object.index, .index = sym_index }, atom_index);927 try wasm.symbol_atom.put(gpa, .{ .file = .zig_object, .index = sym_index }, atom_index);
930 }928 }
931}929}
932930
933pub fn freeNav(zig_object: *ZigObject, wasm_file: *Wasm, nav_index: InternPool.Nav.Index) void {931pub fn freeNav(zig_object: *ZigObject, wasm: *Wasm, nav_index: InternPool.Nav.Index) void {
934 const gpa = wasm_file.base.comp.gpa;932 const gpa = wasm.base.comp.gpa;
935 const zcu = wasm_file.base.comp.zcu.?;933 const zcu = wasm.base.comp.zcu.?;
936 const ip = &zcu.intern_pool;934 const ip = &zcu.intern_pool;
937 const nav_info = zig_object.navs.getPtr(nav_index).?;935 const nav_info = zig_object.navs.getPtr(nav_index).?;
938 const atom_index = nav_info.atom;936 const atom_index = nav_info.atom;
939 const atom = wasm_file.getAtomPtr(atom_index);937 const atom = wasm.getAtomPtr(atom_index);
940 zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {};938 zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {};
941 for (nav_info.exports.items) |exp_sym_index| {939 for (nav_info.exports.items) |exp_sym_index| {
942 const exp_sym = zig_object.symbol(exp_sym_index);940 const exp_sym = zig_object.symbol(exp_sym_index);
...@@ -947,11 +945,11 @@ pub fn freeNav(zig_object: *ZigObject, wasm_file: *Wasm, nav_index: InternPool.N...@@ -947,11 +945,11 @@ pub fn freeNav(zig_object: *ZigObject, wasm_file: *Wasm, nav_index: InternPool.N
947 std.debug.assert(zig_object.navs.remove(nav_index));945 std.debug.assert(zig_object.navs.remove(nav_index));
948 const sym = &zig_object.symbols.items[atom.sym_index];946 const sym = &zig_object.symbols.items[atom.sym_index];
949 for (atom.locals.items) |local_atom_index| {947 for (atom.locals.items) |local_atom_index| {
950 const local_atom = wasm_file.getAtom(local_atom_index);948 const local_atom = wasm.getAtom(local_atom_index);
951 const local_symbol = &zig_object.symbols.items[local_atom.sym_index];949 const local_symbol = &zig_object.symbols.items[local_atom.sym_index];
952 std.debug.assert(local_symbol.tag == .data);950 std.debug.assert(local_symbol.tag == .data);
953 zig_object.symbols_free_list.append(gpa, local_atom.sym_index) catch {};951 zig_object.symbols_free_list.append(gpa, local_atom.sym_index) catch {};
954 std.debug.assert(wasm_file.symbol_atom.remove(local_atom.symbolLoc()));952 std.debug.assert(wasm.symbol_atom.remove(local_atom.symbolLoc()));
955 local_symbol.tag = .dead; // also for any local symbol953 local_symbol.tag = .dead; // also for any local symbol
956 const segment = &zig_object.segment_info.items[local_atom.sym_index];954 const segment = &zig_object.segment_info.items[local_atom.sym_index];
957 gpa.free(segment.name);955 gpa.free(segment.name);
...@@ -962,7 +960,7 @@ pub fn freeNav(zig_object: *ZigObject, wasm_file: *Wasm, nav_index: InternPool.N...@@ -962,7 +960,7 @@ pub fn freeNav(zig_object: *ZigObject, wasm_file: *Wasm, nav_index: InternPool.N
962 if (ip.indexToKey(nav_val) == .@"extern") {960 if (ip.indexToKey(nav_val) == .@"extern") {
963 std.debug.assert(zig_object.imports.remove(atom.sym_index));961 std.debug.assert(zig_object.imports.remove(atom.sym_index));
964 }962 }
965 std.debug.assert(wasm_file.symbol_atom.remove(atom.symbolLoc()));963 std.debug.assert(wasm.symbol_atom.remove(atom.symbolLoc()));
966964
967 // if (wasm.dwarf) |*dwarf| {965 // if (wasm.dwarf) |*dwarf| {
968 // dwarf.freeDecl(decl_index);966 // dwarf.freeDecl(decl_index);
...@@ -1014,15 +1012,15 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ...@@ -1014,15 +1012,15 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ
10141012
1015/// Generates an atom containing the global error set' size.1013/// Generates an atom containing the global error set' size.
1016/// This will only be generated if the symbol exists.1014/// This will only be generated if the symbol exists.
1017fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {1015fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {
1018 const gpa = wasm_file.base.comp.gpa;1016 const gpa = wasm.base.comp.gpa;
1019 const sym_index = zig_object.findGlobalSymbol("__zig_errors_len") orelse return;1017 const sym_index = zig_object.findGlobalSymbol("__zig_errors_len") orelse return;
10201018
1021 const errors_len = 1 + wasm_file.base.comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len;1019 const errors_len = 1 + wasm.base.comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len;
1022 // overwrite existing atom if it already exists (maybe the error set has increased)1020 // overwrite existing atom if it already exists (maybe the error set has increased)
1023 // if not, allocate a new atom.1021 // if not, allocate a new atom.
1024 const atom_index = if (wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = sym_index })) |index| blk: {1022 const atom_index = if (wasm.symbol_atom.get(.{ .file = .zig_object, .index = sym_index })) |index| blk: {
1025 const atom = wasm_file.getAtomPtr(index);1023 const atom = wasm.getAtomPtr(index);
1026 atom.prev = .null;1024 atom.prev = .null;
1027 atom.deinit(gpa);1025 atom.deinit(gpa);
1028 break :blk index;1026 break :blk index;
...@@ -1036,10 +1034,10 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {...@@ -1036,10 +1034,10 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {
1036 sym.tag = .data;1034 sym.tag = .data;
1037 const segment_name = try gpa.dupe(u8, ".rodata.__zig_errors_len");1035 const segment_name = try gpa.dupe(u8, ".rodata.__zig_errors_len");
1038 sym.index = try zig_object.createDataSegment(gpa, segment_name, .@"2");1036 sym.index = try zig_object.createDataSegment(gpa, segment_name, .@"2");
1039 break :idx try wasm_file.createAtom(sym_index, zig_object.index);1037 break :idx try wasm.createAtom(sym_index, .zig_object);
1040 };1038 };
10411039
1042 const atom = wasm_file.getAtomPtr(atom_index);1040 const atom = wasm.getAtomPtr(atom_index);
1043 atom.code.clearRetainingCapacity();1041 atom.code.clearRetainingCapacity();
1044 atom.sym_index = sym_index;1042 atom.sym_index = sym_index;
1045 atom.size = 2;1043 atom.size = 2;
...@@ -1073,15 +1071,15 @@ pub fn initDebugSections(zig_object: *ZigObject) !void {...@@ -1073,15 +1071,15 @@ pub fn initDebugSections(zig_object: *ZigObject) !void {
1073/// From a given index variable, creates a new debug section.1071/// From a given index variable, creates a new debug section.
1074/// This initializes the index, appends a new segment,1072/// This initializes the index, appends a new segment,
1075/// and finally, creates a managed `Atom`.1073/// and finally, creates a managed `Atom`.
1076pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm_file: *Wasm, index: *?u32, name: []const u8) !Atom.Index {1074pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index {
1077 const gpa = wasm_file.base.comp.gpa;1075 const gpa = wasm.base.comp.gpa;
1078 const new_index: u32 = @intCast(zig_object.segments.items.len);1076 const new_index: u32 = @intCast(zig_object.segments.items.len);
1079 index.* = new_index;1077 index.* = new_index;
1080 try zig_object.appendDummySegment();1078 try zig_object.appendDummySegment();
10811079
1082 const sym_index = try zig_object.allocateSymbol(gpa);1080 const sym_index = try zig_object.allocateSymbol(gpa);
1083 const atom_index = try wasm_file.createAtom(sym_index, zig_object.index);1081 const atom_index = try wasm.createAtom(sym_index, .zig_object);
1084 const atom = wasm_file.getAtomPtr(atom_index);1082 const atom = wasm.getAtomPtr(atom_index);
1085 zig_object.symbols.items[sym_index] = .{1083 zig_object.symbols.items[sym_index] = .{
1086 .tag = .section,1084 .tag = .section,
1087 .name = try zig_object.string_table.put(gpa, name),1085 .name = try zig_object.string_table.put(gpa, name),
...@@ -1148,13 +1146,13 @@ pub fn storeDeclType(zig_object: *ZigObject, gpa: std.mem.Allocator, nav_index:...@@ -1148,13 +1146,13 @@ pub fn storeDeclType(zig_object: *ZigObject, gpa: std.mem.Allocator, nav_index:
1148/// The symbols in ZigObject are already represented by an atom as we need to store its data.1146/// The symbols in ZigObject are already represented by an atom as we need to store its data.
1149/// So rather than creating a new Atom and returning its index, we use this opportunity to scan1147/// So rather than creating a new Atom and returning its index, we use this opportunity to scan
1150/// its relocations and create any GOT symbols or function table indexes it may require.1148/// its relocations and create any GOT symbols or function table indexes it may require.
1151pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symbol.Index) !Atom.Index {1149pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm: *Wasm, index: Symbol.Index) !Atom.Index {
1152 const gpa = wasm_file.base.comp.gpa;1150 const gpa = wasm.base.comp.gpa;
1153 const loc: Wasm.SymbolLoc = .{ .file = zig_object.index, .index = index };1151 const loc: Wasm.SymbolLoc = .{ .file = .zig_object, .index = index };
1154 const atom_index = wasm_file.symbol_atom.get(loc).?;1152 const atom_index = wasm.symbol_atom.get(loc).?;
1155 const final_index = try wasm_file.getMatchingSegment(zig_object.index, index);1153 const final_index = try wasm.getMatchingSegment(.zig_object, index);
1156 try wasm_file.appendAtomAtIndex(final_index, atom_index);1154 try wasm.appendAtomAtIndex(final_index, atom_index);
1157 const atom = wasm_file.getAtom(atom_index);1155 const atom = wasm.getAtom(atom_index);
1158 for (atom.relocs.items) |reloc| {1156 for (atom.relocs.items) |reloc| {
1159 const reloc_index: Symbol.Index = @enumFromInt(reloc.index);1157 const reloc_index: Symbol.Index = @enumFromInt(reloc.index);
1160 switch (reloc.relocation_type) {1158 switch (reloc.relocation_type) {
...@@ -1163,8 +1161,8 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb...@@ -1163,8 +1161,8 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb
1163 .R_WASM_TABLE_INDEX_SLEB,1161 .R_WASM_TABLE_INDEX_SLEB,
1164 .R_WASM_TABLE_INDEX_SLEB64,1162 .R_WASM_TABLE_INDEX_SLEB64,
1165 => {1163 => {
1166 try wasm_file.function_table.put(gpa, .{1164 try wasm.function_table.put(gpa, .{
1167 .file = zig_object.index,1165 .file = .zig_object,
1168 .index = reloc_index,1166 .index = reloc_index,
1169 }, 0);1167 }, 0);
1170 },1168 },
...@@ -1173,8 +1171,8 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb...@@ -1173,8 +1171,8 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb
1173 => {1171 => {
1174 const sym = zig_object.symbol(reloc_index);1172 const sym = zig_object.symbol(reloc_index);
1175 if (sym.tag != .global) {1173 if (sym.tag != .global) {
1176 try wasm_file.got_symbols.append(gpa, .{1174 try wasm.got_symbols.append(gpa, .{
1177 .file = zig_object.index,1175 .file = .zig_object,
1178 .index = reloc_index,1176 .index = reloc_index,
1179 });1177 });
1180 }1178 }
...@@ -1189,13 +1187,13 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb...@@ -1189,13 +1187,13 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb
1189/// Returns the symbol index of the new function.1187/// Returns the symbol index of the new function.
1190pub fn createFunction(1188pub fn createFunction(
1191 zig_object: *ZigObject,1189 zig_object: *ZigObject,
1192 wasm_file: *Wasm,1190 wasm: *Wasm,
1193 symbol_name: []const u8,1191 symbol_name: []const u8,
1194 func_ty: std.wasm.Type,1192 func_ty: std.wasm.Type,
1195 function_body: *std.ArrayList(u8),1193 function_body: *std.ArrayList(u8),
1196 relocations: *std.ArrayList(types.Relocation),1194 relocations: *std.ArrayList(Wasm.Relocation),
1197) !Symbol.Index {1195) !Symbol.Index {
1198 const gpa = wasm_file.base.comp.gpa;1196 const gpa = wasm.base.comp.gpa;
1199 const sym_index = try zig_object.allocateSymbol(gpa);1197 const sym_index = try zig_object.allocateSymbol(gpa);
1200 const sym = zig_object.symbol(sym_index);1198 const sym = zig_object.symbol(sym_index);
1201 sym.tag = .function;1199 sym.tag = .function;
...@@ -1203,8 +1201,8 @@ pub fn createFunction(...@@ -1203,8 +1201,8 @@ pub fn createFunction(
1203 const type_index = try zig_object.putOrGetFuncType(gpa, func_ty);1201 const type_index = try zig_object.putOrGetFuncType(gpa, func_ty);
1204 sym.index = try zig_object.appendFunction(gpa, .{ .type_index = type_index });1202 sym.index = try zig_object.appendFunction(gpa, .{ .type_index = type_index });
12051203
1206 const atom_index = try wasm_file.createAtom(sym_index, zig_object.index);1204 const atom_index = try wasm.createAtom(sym_index, .zig_object);
1207 const atom = wasm_file.getAtomPtr(atom_index);1205 const atom = wasm.getAtomPtr(atom_index);
1208 atom.size = @intCast(function_body.items.len);1206 atom.size = @intCast(function_body.items.len);
1209 atom.code = function_body.moveToUnmanaged();1207 atom.code = function_body.moveToUnmanaged();
1210 atom.relocs = relocations.moveToUnmanaged();1208 atom.relocs = relocations.moveToUnmanaged();
...@@ -1227,9 +1225,9 @@ fn appendFunction(zig_object: *ZigObject, gpa: std.mem.Allocator, func: std.wasm...@@ -1227,9 +1225,9 @@ fn appendFunction(zig_object: *ZigObject, gpa: std.mem.Allocator, func: std.wasm
1227 return index;1225 return index;
1228}1226}
12291227
1230pub fn flushModule(zig_object: *ZigObject, wasm_file: *Wasm, tid: Zcu.PerThread.Id) !void {1228pub fn flushModule(zig_object: *ZigObject, wasm: *Wasm, tid: Zcu.PerThread.Id) !void {
1231 try zig_object.populateErrorNameTable(wasm_file, tid);1229 try zig_object.populateErrorNameTable(wasm, tid);
1232 try zig_object.setupErrorsLen(wasm_file);1230 try zig_object.setupErrorsLen(wasm);
1233}1231}
12341232
1235const build_options = @import("build_options");1233const build_options = @import("build_options");
...@@ -1238,12 +1236,10 @@ const codegen = @import("../../codegen.zig");...@@ -1238,12 +1236,10 @@ const codegen = @import("../../codegen.zig");
1238const link = @import("../../link.zig");1236const link = @import("../../link.zig");
1239const log = std.log.scoped(.zig_object);1237const log = std.log.scoped(.zig_object);
1240const std = @import("std");1238const std = @import("std");
1241const types = @import("types.zig");
12421239
1243const Air = @import("../../Air.zig");1240const Air = @import("../../Air.zig");
1244const Atom = @import("Atom.zig");1241const Atom = Wasm.Atom;
1245const Dwarf = @import("../Dwarf.zig");1242const Dwarf = @import("../Dwarf.zig");
1246const File = @import("file.zig").File;
1247const InternPool = @import("../../InternPool.zig");1243const InternPool = @import("../../InternPool.zig");
1248const Liveness = @import("../../Liveness.zig");1244const Liveness = @import("../../Liveness.zig");
1249const Zcu = @import("../../Zcu.zig");1245const Zcu = @import("../../Zcu.zig");
src/link/Wasm/file.zig deleted-132
...@@ -1,132 +0,0 @@
1pub const File = union(enum) {
2 zig_object: *ZigObject,
3 object: *Object,
4
5 pub const Index = enum(u16) {
6 null = std.math.maxInt(u16),
7 _,
8 };
9
10 pub fn path(file: File) []const u8 {
11 return switch (file) {
12 inline else => |obj| obj.path,
13 };
14 }
15
16 pub fn segmentInfo(file: File) []const types.Segment {
17 return switch (file) {
18 .zig_object => |obj| obj.segment_info.items,
19 .object => |obj| obj.segment_info,
20 };
21 }
22
23 pub fn symbol(file: File, index: Symbol.Index) *Symbol {
24 return switch (file) {
25 .zig_object => |obj| &obj.symbols.items[@intFromEnum(index)],
26 .object => |obj| &obj.symtable[@intFromEnum(index)],
27 };
28 }
29
30 pub fn symbols(file: File) []const Symbol {
31 return switch (file) {
32 .zig_object => |obj| obj.symbols.items,
33 .object => |obj| obj.symtable,
34 };
35 }
36
37 pub fn symbolName(file: File, index: Symbol.Index) []const u8 {
38 switch (file) {
39 .zig_object => |obj| {
40 const sym = obj.symbols.items[@intFromEnum(index)];
41 return obj.string_table.get(sym.name).?;
42 },
43 .object => |obj| {
44 const sym = obj.symtable[@intFromEnum(index)];
45 return obj.string_table.get(sym.name);
46 },
47 }
48 }
49
50 pub fn parseSymbolIntoAtom(file: File, wasm_file: *Wasm, index: Symbol.Index) !AtomIndex {
51 return switch (file) {
52 inline else => |obj| obj.parseSymbolIntoAtom(wasm_file, index),
53 };
54 }
55
56 /// For a given symbol index, find its corresponding import.
57 /// Asserts import exists.
58 pub fn import(file: File, symbol_index: Symbol.Index) types.Import {
59 return switch (file) {
60 .zig_object => |obj| obj.imports.get(symbol_index).?,
61 .object => |obj| obj.findImport(obj.symtable[@intFromEnum(symbol_index)]),
62 };
63 }
64
65 /// For a given offset, returns its string value.
66 /// Asserts string exists in the object string table.
67 pub fn string(file: File, offset: u32) []const u8 {
68 return switch (file) {
69 .zig_object => |obj| obj.string_table.get(offset).?,
70 .object => |obj| obj.string_table.get(offset),
71 };
72 }
73
74 pub fn importedGlobals(file: File) u32 {
75 return switch (file) {
76 inline else => |obj| obj.imported_globals_count,
77 };
78 }
79
80 pub fn importedFunctions(file: File) u32 {
81 return switch (file) {
82 inline else => |obj| obj.imported_functions_count,
83 };
84 }
85
86 pub fn importedTables(file: File) u32 {
87 return switch (file) {
88 inline else => |obj| obj.imported_tables_count,
89 };
90 }
91
92 pub fn function(file: File, sym_index: Symbol.Index) std.wasm.Func {
93 switch (file) {
94 .zig_object => |obj| {
95 const sym = obj.symbols.items[@intFromEnum(sym_index)];
96 return obj.functions.items[sym.index];
97 },
98 .object => |obj| {
99 const sym = obj.symtable[@intFromEnum(sym_index)];
100 return obj.functions[sym.index - obj.imported_functions_count];
101 },
102 }
103 }
104
105 pub fn globals(file: File) []const std.wasm.Global {
106 return switch (file) {
107 .zig_object => |obj| obj.globals.items,
108 .object => |obj| obj.globals,
109 };
110 }
111
112 pub fn funcTypes(file: File) []const std.wasm.Type {
113 return switch (file) {
114 .zig_object => |obj| obj.func_types.items,
115 .object => |obj| obj.func_types,
116 };
117 }
118
119 pub const Entry = union(enum) {
120 zig_object: ZigObject,
121 object: Object,
122 };
123};
124
125const std = @import("std");
126const types = @import("types.zig");
127
128const AtomIndex = @import("Atom.zig").Index;
129const Object = @import("Object.zig");
130const Symbol = @import("Symbol.zig");
131const Wasm = @import("../Wasm.zig");
132const ZigObject = @import("ZigObject.zig");
src/link/Wasm/types.zig deleted-267
...@@ -1,267 +0,0 @@
1//! This file contains all constants and related to wasm's object format.
2
3const std = @import("std");
4
5pub const Relocation = struct {
6 /// Represents the type of the `Relocation`
7 relocation_type: RelocationType,
8 /// Offset of the value to rewrite relative to the relevant section's contents.
9 /// When `offset` is zero, its position is immediately after the id and size of the section.
10 offset: u32,
11 /// The index of the symbol used.
12 /// When the type is `R_WASM_TYPE_INDEX_LEB`, it represents the index of the type.
13 index: u32,
14 /// Addend to add to the address.
15 /// This field is only non-zero for `R_WASM_MEMORY_ADDR_*`, `R_WASM_FUNCTION_OFFSET_I32` and `R_WASM_SECTION_OFFSET_I32`.
16 addend: i32 = 0,
17
18 /// All possible relocation types currently existing.
19 /// This enum is exhaustive as the spec is WIP and new types
20 /// can be added which means that a generated binary will be invalid,
21 /// so instead we will show an error in such cases.
22 pub const RelocationType = enum(u8) {
23 R_WASM_FUNCTION_INDEX_LEB = 0,
24 R_WASM_TABLE_INDEX_SLEB = 1,
25 R_WASM_TABLE_INDEX_I32 = 2,
26 R_WASM_MEMORY_ADDR_LEB = 3,
27 R_WASM_MEMORY_ADDR_SLEB = 4,
28 R_WASM_MEMORY_ADDR_I32 = 5,
29 R_WASM_TYPE_INDEX_LEB = 6,
30 R_WASM_GLOBAL_INDEX_LEB = 7,
31 R_WASM_FUNCTION_OFFSET_I32 = 8,
32 R_WASM_SECTION_OFFSET_I32 = 9,
33 R_WASM_EVENT_INDEX_LEB = 10,
34 R_WASM_GLOBAL_INDEX_I32 = 13,
35 R_WASM_MEMORY_ADDR_LEB64 = 14,
36 R_WASM_MEMORY_ADDR_SLEB64 = 15,
37 R_WASM_MEMORY_ADDR_I64 = 16,
38 R_WASM_TABLE_INDEX_SLEB64 = 18,
39 R_WASM_TABLE_INDEX_I64 = 19,
40 R_WASM_TABLE_NUMBER_LEB = 20,
41 R_WASM_MEMORY_ADDR_TLS_SLEB = 21,
42 R_WASM_MEMORY_ADDR_TLS_SLEB64 = 25,
43
44 /// Returns true for relocation types where the `addend` field is present.
45 pub fn addendIsPresent(self: RelocationType) bool {
46 return switch (self) {
47 .R_WASM_MEMORY_ADDR_LEB,
48 .R_WASM_MEMORY_ADDR_SLEB,
49 .R_WASM_MEMORY_ADDR_I32,
50 .R_WASM_MEMORY_ADDR_LEB64,
51 .R_WASM_MEMORY_ADDR_SLEB64,
52 .R_WASM_MEMORY_ADDR_I64,
53 .R_WASM_MEMORY_ADDR_TLS_SLEB,
54 .R_WASM_MEMORY_ADDR_TLS_SLEB64,
55 .R_WASM_FUNCTION_OFFSET_I32,
56 .R_WASM_SECTION_OFFSET_I32,
57 => true,
58 else => false,
59 };
60 }
61 };
62
63 /// Verifies the relocation type of a given `Relocation` and returns
64 /// true when the relocation references a function call or address to a function.
65 pub fn isFunction(self: Relocation) bool {
66 return switch (self.relocation_type) {
67 .R_WASM_FUNCTION_INDEX_LEB,
68 .R_WASM_TABLE_INDEX_SLEB,
69 => true,
70 else => false,
71 };
72 }
73
74 pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
75 _ = fmt;
76 _ = options;
77 try writer.print("{s} offset=0x{x:0>6} symbol={d}", .{
78 @tagName(self.relocation_type),
79 self.offset,
80 self.index,
81 });
82 }
83};
84
85/// Unlike the `Import` object defined by the wasm spec, and existing
86/// in the std.wasm namespace, this construct saves the 'module name' and 'name'
87/// of the import using offsets into a string table, rather than the slices itself.
88/// This saves us (potentially) 24 bytes per import on 64bit machines.
89pub const Import = struct {
90 module_name: u32,
91 name: u32,
92 kind: std.wasm.Import.Kind,
93};
94
95/// Unlike the `Export` object defined by the wasm spec, and existing
96/// in the std.wasm namespace, this construct saves the 'name'
97/// of the export using offsets into a string table, rather than the slice itself.
98/// This saves us (potentially) 12 bytes per export on 64bit machines.
99pub const Export = struct {
100 name: u32,
101 index: u32,
102 kind: std.wasm.ExternalKind,
103};
104
105pub const SubsectionType = enum(u8) {
106 WASM_SEGMENT_INFO = 5,
107 WASM_INIT_FUNCS = 6,
108 WASM_COMDAT_INFO = 7,
109 WASM_SYMBOL_TABLE = 8,
110};
111
112pub const Alignment = @import("../../InternPool.zig").Alignment;
113
114pub const Segment = struct {
115 /// Segment's name, encoded as UTF-8 bytes.
116 name: []const u8,
117 /// The required alignment of the segment, encoded as a power of 2
118 alignment: Alignment,
119 /// Bitfield containing flags for a segment
120 flags: u32,
121
122 pub fn isTLS(segment: Segment) bool {
123 return segment.flags & @intFromEnum(Flags.WASM_SEG_FLAG_TLS) != 0;
124 }
125
126 /// Returns the name as how it will be output into the final object
127 /// file or binary. When `merge_segments` is true, this will return the
128 /// short name. i.e. ".rodata". When false, it returns the entire name instead.
129 pub fn outputName(segment: Segment, merge_segments: bool) []const u8 {
130 if (segment.isTLS()) {
131 return ".tdata";
132 } else if (!merge_segments) {
133 return segment.name;
134 } else if (std.mem.startsWith(u8, segment.name, ".rodata.")) {
135 return ".rodata";
136 } else if (std.mem.startsWith(u8, segment.name, ".text.")) {
137 return ".text";
138 } else if (std.mem.startsWith(u8, segment.name, ".data.")) {
139 return ".data";
140 } else if (std.mem.startsWith(u8, segment.name, ".bss.")) {
141 return ".bss";
142 }
143 return segment.name;
144 }
145
146 pub const Flags = enum(u32) {
147 WASM_SEG_FLAG_STRINGS = 0x1,
148 WASM_SEG_FLAG_TLS = 0x2,
149 };
150};
151
152pub const InitFunc = struct {
153 /// Priority of the init function
154 priority: u32,
155 /// The symbol index of init function (not the function index).
156 symbol_index: u32,
157};
158
159pub const Comdat = struct {
160 name: []const u8,
161 /// Must be zero, no flags are currently defined by the tool-convention.
162 flags: u32,
163 symbols: []const ComdatSym,
164};
165
166pub const ComdatSym = struct {
167 kind: Type,
168 /// Index of the data segment/function/global/event/table within a WASM module.
169 /// The object must not be an import.
170 index: u32,
171
172 pub const Type = enum(u8) {
173 WASM_COMDAT_DATA = 0,
174 WASM_COMDAT_FUNCTION = 1,
175 WASM_COMDAT_GLOBAL = 2,
176 WASM_COMDAT_EVENT = 3,
177 WASM_COMDAT_TABLE = 4,
178 WASM_COMDAT_SECTION = 5,
179 };
180};
181
182pub const Feature = struct {
183 /// Provides information about the usage of the feature.
184 /// - '0x2b' (+): Object uses this feature, and the link fails if feature is not in the allowed set.
185 /// - '0x2d' (-): Object does not use this feature, and the link fails if this feature is in the allowed set.
186 /// - '0x3d' (=): Object uses this feature, and the link fails if this feature is not in the allowed set,
187 /// or if any object does not use this feature.
188 prefix: Prefix,
189 /// Type of the feature, must be unique in the sequence of features.
190 tag: Tag,
191
192 /// Unlike `std.Target.wasm.Feature` this also contains linker-features such as shared-mem
193 pub const Tag = enum {
194 atomics,
195 bulk_memory,
196 exception_handling,
197 extended_const,
198 half_precision,
199 multimemory,
200 multivalue,
201 mutable_globals,
202 nontrapping_fptoint,
203 reference_types,
204 relaxed_simd,
205 sign_ext,
206 simd128,
207 tail_call,
208 shared_mem,
209
210 /// From a given cpu feature, returns its linker feature
211 pub fn fromCpuFeature(feature: std.Target.wasm.Feature) Tag {
212 return @as(Tag, @enumFromInt(@intFromEnum(feature)));
213 }
214
215 pub fn format(tag: Tag, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
216 _ = fmt;
217 _ = opt;
218 try writer.writeAll(switch (tag) {
219 .atomics => "atomics",
220 .bulk_memory => "bulk-memory",
221 .exception_handling => "exception-handling",
222 .extended_const => "extended-const",
223 .half_precision => "half-precision",
224 .multimemory => "multimemory",
225 .multivalue => "multivalue",
226 .mutable_globals => "mutable-globals",
227 .nontrapping_fptoint => "nontrapping-fptoint",
228 .reference_types => "reference-types",
229 .relaxed_simd => "relaxed-simd",
230 .sign_ext => "sign-ext",
231 .simd128 => "simd128",
232 .tail_call => "tail-call",
233 .shared_mem => "shared-mem",
234 });
235 }
236 };
237
238 pub const Prefix = enum(u8) {
239 used = '+',
240 disallowed = '-',
241 required = '=',
242 };
243
244 pub fn format(feature: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
245 _ = opt;
246 _ = fmt;
247 try writer.print("{c} {}", .{ feature.prefix, feature.tag });
248 }
249};
250
251pub const known_features = std.StaticStringMap(Feature.Tag).initComptime(.{
252 .{ "atomics", .atomics },
253 .{ "bulk-memory", .bulk_memory },
254 .{ "exception-handling", .exception_handling },
255 .{ "extended-const", .extended_const },
256 .{ "half-precision", .half_precision },
257 .{ "multimemory", .multimemory },
258 .{ "multivalue", .multivalue },
259 .{ "mutable-globals", .mutable_globals },
260 .{ "nontrapping-fptoint", .nontrapping_fptoint },
261 .{ "reference-types", .reference_types },
262 .{ "relaxed-simd", .relaxed_simd },
263 .{ "sign-ext", .sign_ext },
264 .{ "simd128", .simd128 },
265 .{ "tail-call", .tail_call },
266 .{ "shared-mem", .shared_mem },
267});