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
648648 src/link/StringTable.zig
649649 src/link/Wasm.zig
650650 src/link/Wasm/Archive.zig
651 src/link/Wasm/Atom.zig
652651 src/link/Wasm/Object.zig
653652 src/link/Wasm/Symbol.zig
654653 src/link/Wasm/ZigObject.zig
655 src/link/Wasm/file.zig
656 src/link/Wasm/types.zig
657654 src/link/aarch64.zig
658655 src/link/riscv.zig
659656 src/link/table_section.zig
src/arch/wasm/CodeGen.zig+5-5
......@@ -1291,7 +1291,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
12911291 var prologue = std.ArrayList(Mir.Inst).init(func.gpa);
12921292 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);
12951295 // load stack pointer
12961296 try prologue.append(.{ .tag = .global_get, .data = .{ .label = sp } });
12971297 // store stack pointer so we can restore it when we return from the function
......@@ -1511,7 +1511,7 @@ fn restoreStackPointer(func: *CodeGen) !void {
15111511 try func.emitWValue(func.initial_stack_value);
15121512
15131513 // 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));
15151515}
15161516
15171517/// 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
22622262 }
22632263
22642264 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;
22662266 try func.addLabel(.call, @intFromEnum(func.bin_file.getAtom(atom_index).sym_index));
22672267 } else {
22682268 // in this case we call a function pointer
......@@ -2274,7 +2274,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
22742274 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.*);
22752275 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);
22782278 try func.addLabel(.call_indirect, fn_type_index);
22792279 }
22802280
......@@ -7178,7 +7178,7 @@ fn callIntrinsic(
71787178 const zcu = pt.zcu;
71797179 var func_type = try genFunctype(func.gpa, .{ .wasm_watc = .{} }, param_types, return_type, pt, func.target.*);
71807180 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);
71827182 try func.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index);
71837183
71847184 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 {
310310 const global_offset = emit.offset();
311311 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;
314314 const atom = emit.bin_file.getAtomPtr(atom_index);
315315 try atom.relocs.append(gpa, .{
316316 .index = label,
......@@ -370,7 +370,7 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {
370370 try emit.code.appendSlice(&buf);
371371
372372 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;
374374 const atom = emit.bin_file.getAtomPtr(atom_index);
375375 try atom.relocs.append(gpa, .{
376376 .offset = call_offset,
......@@ -390,7 +390,7 @@ fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void {
390390 leb128.writeUnsignedFixed(5, &buf, type_index);
391391 try emit.code.appendSlice(&buf);
392392 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;
394394 const atom = emit.bin_file.getAtomPtr(atom_index);
395395 try atom.relocs.append(emit.bin_file.base.comp.gpa, .{
396396 .offset = call_offset,
......@@ -412,7 +412,7 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
412412 try emit.code.appendSlice(&buf);
413413
414414 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;
416416 const atom = emit.bin_file.getAtomPtr(atom_index);
417417 try atom.relocs.append(gpa, .{
418418 .offset = index_offset,
......@@ -443,7 +443,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
443443 }
444444
445445 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;
447447 const atom = emit.bin_file.getAtomPtr(atom_index);
448448 try atom.relocs.append(gpa, .{
449449 .offset = mem_offset,
src/link/Wasm.zig+985-294
......@@ -15,7 +15,6 @@ const log = std.log.scoped(.link);
1515const gc_log = std.log.scoped(.gc);
1616const mem = std.mem;
1717const trace = @import("../tracy.zig").trace;
18const types = @import("Wasm/types.zig");
1918const wasi_libc = @import("../wasi_libc.zig");
2019
2120const Air = @import("../Air.zig");
......@@ -26,7 +25,6 @@ const Path = Cache.Path;
2625const CodeGen = @import("../arch/wasm/CodeGen.zig");
2726const Compilation = @import("../Compilation.zig");
2827const Dwarf = @import("Dwarf.zig");
29const File = @import("Wasm/file.zig").File;
3028const InternPool = @import("../InternPool.zig");
3129const Liveness = @import("../Liveness.zig");
3230const LlvmObject = @import("../codegen/llvm.zig").Object;
......@@ -37,9 +35,6 @@ const Type = @import("../Type.zig");
3735const Value = @import("../Value.zig");
3836const ZigObject = @import("Wasm/ZigObject.zig");
3937
40pub const Atom = @import("Wasm/Atom.zig");
41pub const Relocation = types.Relocation;
42
4338base: link.File,
4439/// Symbol name of the entry function to export
4540entry_name: ?[]const u8,
......@@ -61,11 +56,9 @@ export_table: bool,
6156name: []const u8,
6257/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
6358llvm_object: ?LlvmObject.Ptr = null,
64/// The file index of a `ZigObject`. This will only contain a valid index when a zcu exists,
65/// and the chosen backend is the Wasm backend.
66zig_object_index: File.Index = .null,
59zig_object: ?*ZigObject,
6760/// List of relocatable files to be linked into the final binary.
68files: std.MultiArrayList(File.Entry) = .{},
61objects: std.ArrayListUnmanaged(Object) = .{},
6962/// When importing objects from the host environment, a name must be supplied.
7063/// LLVM uses "env" by default when none is given. This would be a good default for Zig
7164/// to support existing code.
......@@ -105,17 +98,17 @@ imported_globals_count: u32 = 0,
10598/// The count of imported tables. This number will be appended
10699/// to the table indexes when sections are merged.
107100imported_tables_count: u32 = 0,
108/// Map of symbol locations, represented by its `types.Import`
109imports: std.AutoHashMapUnmanaged(SymbolLoc, types.Import) = .empty,
101/// Map of symbol locations, represented by its `Import`
102imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty,
110103/// Represents non-synthetic section entries.
111104/// Used for code, data and custom sections.
112105segments: std.ArrayListUnmanaged(Segment) = .empty,
113106/// Maps a data segment key (such as .rodata) to the index into `segments`.
114107data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty,
115/// A table of `types.Segment` which provide meta data
108/// A table of `NamedSegment` which provide meta data
116109/// about a data symbol such as its name where the key is
117110/// 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,
119112/// Deduplicated string table for strings used by symbols, imports and exports.
120113string_table: StringTable = .{},
121114
......@@ -126,8 +119,15 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .empty,
126119/// function index and the value is function.
127120/// This allows us to map multiple symbols to the same function.
128121functions: std.AutoArrayHashMapUnmanaged(
129 struct { file: File.Index, index: u32 },
130 struct { func: std.wasm.Func, sym_index: Symbol.Index },
122 struct {
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 },
131131) = .{},
132132/// Output global section
133133wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,
......@@ -140,7 +140,7 @@ memories: std.wasm.Memory = .{ .limits = .{
140140/// Output table section
141141tables: std.ArrayListUnmanaged(std.wasm.Table) = .empty,
142142/// Output export section
143exports: std.ArrayListUnmanaged(types.Export) = .empty,
143exports: std.ArrayListUnmanaged(Export) = .empty,
144144/// List of initialization functions. These must be called in order of priority
145145/// by the (synthetic) __wasm_call_ctors function.
146146init_funcs: std.ArrayListUnmanaged(InitFuncLoc) = .empty,
......@@ -154,8 +154,6 @@ entry: ?u32 = null,
154154/// Note: Key is symbol location, value represents the index into the table
155155function_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,
159157/// All archive files that are lazy loaded.
160158/// e.g. when an undefined symbol references a symbol from the archive.
161159archives: std.ArrayListUnmanaged(Archive) = .empty,
......@@ -178,7 +176,29 @@ undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty,
178176/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.
179177symbol_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
183203pub const Segment = struct {
184204 alignment: Alignment,
......@@ -208,43 +228,55 @@ pub const SymbolLoc = struct {
208228 /// The index of the symbol within the specified file
209229 index: Symbol.Index,
210230 /// 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 binary
214 pub fn getSymbol(loc: SymbolLoc, wasm_file: *const Wasm) *Symbol {
215 if (wasm_file.discarded.get(loc)) |new_loc| {
216 return new_loc.getSymbol(wasm_file);
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)];
234/// From a given location, returns the corresponding symbol in the wasm binary
235pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol {
236 if (wasm.discarded.get(loc)) |new_loc| {
237 return symbolLocSymbol(wasm, new_loc);
222238 }
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.
225 pub fn getName(loc: SymbolLoc, wasm_file: *const Wasm) []const u8 {
226 if (wasm_file.discarded.get(loc)) |new_loc| {
227 return new_loc.getName(wasm_file);
228 }
229 if (wasm_file.file(loc.file)) |obj_file| {
230 return obj_file.symbolName(loc.index);
231 }
232 const sym = wasm_file.synthetic_symbols.items[@intFromEnum(loc.index)];
233 return wasm_file.string_table.get(sym.name);
246/// From a given location, returns the name of the symbol.
247pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) []const u8 {
248 if (wasm.discarded.get(loc)) |new_loc| {
249 return wasm.symbolLocName(new_loc);
250 }
251 switch (loc.file) {
252 .none => {
253 const sym = wasm.synthetic_symbols.items[@intFromEnum(loc.index)];
254 return wasm.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 },
234266 }
267}
235268
236 /// From a given symbol location, returns the final location.
237 /// e.g. when a symbol was resolved and replaced by the symbol
238 /// in a different file, this will return said location.
239 /// If the symbol wasn't replaced by another, this will return
240 /// the given location itwasm.
241 pub fn finalLoc(loc: SymbolLoc, wasm_file: *const Wasm) SymbolLoc {
242 if (wasm_file.discarded.get(loc)) |new_loc| {
243 return new_loc.finalLoc(wasm_file);
244 }
245 return loc;
269/// From a given symbol location, returns the final location.
270/// e.g. when a symbol was resolved and replaced by the symbol
271/// in a different file, this will return said location.
272/// If the symbol wasn't replaced by another, this will return
273/// the given location itwasm.
274pub fn symbolLocFinalLoc(wasm: *const Wasm, loc: SymbolLoc) SymbolLoc {
275 if (wasm.discarded.get(loc)) |new_loc| {
276 return symbolLocFinalLoc(wasm, new_loc);
246277 }
247};
278 return loc;
279}
248280
249281// Contains the location of the function symbol, as well as
250282/// the priority itself of the initialization function.
......@@ -252,7 +284,7 @@ pub const InitFuncLoc = struct {
252284 /// object file index in the list of objects.
253285 /// Unlike `SymbolLoc` this cannot be `null` as we never define
254286 /// our own ctors.
255 file: File.Index,
287 file: ObjectId,
256288 /// Symbol index within the corresponding object file.
257289 index: Symbol.Index,
258290 /// The priority in which the constructor must be called.
......@@ -260,12 +292,15 @@ pub const InitFuncLoc = struct {
260292
261293 /// From a given `InitFuncLoc` returns the corresponding function symbol
262294 fn getSymbol(loc: InitFuncLoc, wasm: *const Wasm) *Symbol {
263 return getSymbolLoc(loc).getSymbol(wasm);
295 return wasm.symbolLocSymbol(getSymbolLoc(loc));
264296 }
265297
266298 /// Turns the given `InitFuncLoc` into a `SymbolLoc`
267299 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 };
269304 }
270305
271306 /// Returns true when `lhs` has a higher priority (e.i. value closer to 0) than `rhs`.
......@@ -307,7 +342,7 @@ pub const StringTable = struct {
307342 }
308343
309344 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
312347 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });
313348
......@@ -414,6 +449,7 @@ pub fn createEmpty(
414449 .enabled => defaultEntrySymbolName(wasi_exec_model),
415450 .named => |name| name,
416451 },
452 .zig_object = null,
417453 };
418454 if (use_llvm and comp.config.have_zcu) {
419455 wasm.llvm_object = try LlvmObject.create(arena, comp);
......@@ -446,7 +482,7 @@ pub fn createEmpty(
446482 // create stack pointer symbol
447483 {
448484 const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global);
449 const symbol = loc.getSymbol(wasm);
485 const symbol = wasm.symbolLocSymbol(loc);
450486 // For object files we will import the stack pointer symbol
451487 if (output_mode == .Obj) {
452488 symbol.setUndefined(true);
......@@ -478,7 +514,7 @@ pub fn createEmpty(
478514 // create indirect function pointer symbol
479515 {
480516 const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table);
481 const symbol = loc.getSymbol(wasm);
517 const symbol = wasm.symbolLocSymbol(loc);
482518 const table: std.wasm.Table = .{
483519 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
484520 .reftype = .funcref,
......@@ -506,7 +542,7 @@ pub fn createEmpty(
506542 // create __wasm_call_ctors
507543 {
508544 const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function);
509 const symbol = loc.getSymbol(wasm);
545 const symbol = wasm.symbolLocSymbol(loc);
510546 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
511547 // we do not know the function index until after we merged all sections.
512548 // Therefore we set `symbol.index` and create its corresponding references
......@@ -517,7 +553,7 @@ pub fn createEmpty(
517553 if (shared_memory) {
518554 {
519555 const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
520 const symbol = loc.getSymbol(wasm);
556 const symbol = wasm.symbolLocSymbol(loc);
521557 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
522558 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
523559 symbol.mark();
......@@ -528,7 +564,7 @@ pub fn createEmpty(
528564 }
529565 {
530566 const loc = try wasm.createSyntheticSymbol("__tls_size", .global);
531 const symbol = loc.getSymbol(wasm);
567 const symbol = wasm.symbolLocSymbol(loc);
532568 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
533569 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
534570 symbol.mark();
......@@ -539,7 +575,7 @@ pub fn createEmpty(
539575 }
540576 {
541577 const loc = try wasm.createSyntheticSymbol("__tls_align", .global);
542 const symbol = loc.getSymbol(wasm);
578 const symbol = wasm.symbolLocSymbol(loc);
543579 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
544580 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
545581 symbol.mark();
......@@ -550,42 +586,26 @@ pub fn createEmpty(
550586 }
551587 {
552588 const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function);
553 const symbol = loc.getSymbol(wasm);
589 const symbol = wasm.symbolLocSymbol(loc);
554590 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
555591 }
556592 }
557593
558594 if (comp.zcu) |zcu| {
559595 if (!use_llvm) {
560 const index: File.Index = @enumFromInt(wasm.files.len);
561 var zig_object: ZigObject = .{
562 .index = index,
596 const zig_object = try arena.create(ZigObject);
597 wasm.zig_object = zig_object;
598 zig_object.* = .{
563599 .path = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(zcu.main_mod.root_src_path)}),
564600 .stack_pointer_sym = .null,
565601 };
566602 try zig_object.init(wasm);
567 try wasm.files.append(gpa, .{ .zig_object = zig_object });
568 wasm.zig_object_index = index;
569603 }
570604 }
571605
572606 return wasm;
573607}
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
589609pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 {
590610 var index: u32 = 0;
591611 while (index < wasm.func_types.items.len) : (index += 1) {
......@@ -610,7 +630,7 @@ pub fn addOrUpdateImport(
610630 /// is asserted instead.
611631 type_index: ?u32,
612632) !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);
614634}
615635
616636/// 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
623643
624644fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {
625645 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 };
627647 const gpa = wasm.base.comp.gpa;
628648 try wasm.synthetic_symbols.append(gpa, .{
629649 .name = name_offset,
......@@ -657,28 +677,29 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
657677 },
658678 };
659679 errdefer object.deinit(gpa);
660 object.index = @enumFromInt(wasm.files.len);
661 try wasm.files.append(gpa, .{ .object = object });
662 try wasm.objects.append(gpa, object.index);
680 try wasm.objects.append(gpa, object);
663681 return true;
664682}
665683
666684/// 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 {
668686 const gpa = wasm.base.comp.gpa;
669687 const index: Atom.Index = @enumFromInt(wasm.managed_atoms.items.len);
670688 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 };
672693 try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), index);
673694
674695 return index;
675696}
676697
677pub inline fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom {
698pub fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom {
678699 return wasm.managed_atoms.items[@intFromEnum(index)];
679700}
680701
681pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
702pub fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
682703 return &wasm.managed_atoms.items[@intFromEnum(index)];
683704}
684705
......@@ -733,15 +754,13 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
733754 }
734755
735756 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| {
737758 var err_note = try diags.addErrorWithNotes(1);
738759 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});
739760 try err_note.addNote("while parsing object in archive {s}", .{path});
740761 return error.FlushFailure;
741762 };
742 object.index = @enumFromInt(wasm.files.len);
743 try wasm.files.append(gpa, .{ .object = object });
744 try wasm.objects.append(gpa, object.index);
763 try wasm.objects.append(gpa, object);
745764 }
746765
747766 return true;
......@@ -749,23 +768,102 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
749768
750769fn requiresTLSReloc(wasm: *const Wasm) bool {
751770 for (wasm.got_symbols.items) |loc| {
752 if (loc.getSymbol(wasm).isTLS()) {
771 if (wasm.symbolLocSymbol(loc).isTLS()) {
753772 return true;
754773 }
755774 }
756775 return false;
757776}
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 {
760854 const gpa = wasm.base.comp.gpa;
761855 const diags = &wasm.base.comp.link_diags;
762 const obj_file = wasm.file(file_index).?;
763 log.debug("Resolving symbols in object: '{s}'", .{obj_file.path()});
856 const obj_path = objectPath(wasm, object_id);
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| {
766861 const sym_index: Symbol.Index = @enumFromInt(i);
767 const location: SymbolLoc = .{ .file = file_index, .index = sym_index };
768 const sym_name = obj_file.string(symbol.name);
862 const location: SymbolLoc = .{
863 .file = object_id.toOptional(),
864 .index = sym_index,
865 };
866 const sym_name = objectString(wasm, object_id, symbol.name);
769867 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
770868 continue;
771869 }
......@@ -775,7 +873,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
775873 if (symbol.isUndefined()) {
776874 var err = try diags.addErrorWithNotes(1);
777875 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 });
779877 }
780878 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
781879 continue;
......@@ -793,13 +891,8 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
793891 }
794892
795893 const existing_loc = maybe_existing.value_ptr.*;
796 const existing_sym: *Symbol = existing_loc.getSymbol(wasm);
797 const existing_file = wasm.file(existing_loc.file);
798
799 const existing_file_path = if (existing_file) |existing_obj_file|
800 existing_obj_file.path()
801 else
802 wasm.name;
894 const existing_sym: *Symbol = wasm.symbolLocSymbol(existing_loc);
895 const existing_file_path = if (existing_loc.file.unwrap()) |id| objectPath(wasm, id) else wasm.name;
803896
804897 if (!existing_sym.isUndefined()) outer: {
805898 if (!symbol.isUndefined()) inner: {
......@@ -813,7 +906,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
813906 var err = try diags.addErrorWithNotes(2);
814907 try err.addMsg("symbol '{s}' defined multiple times", .{sym_name});
815908 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});
817910 }
818911
819912 try wasm.discarded.put(gpa, location, existing_loc);
......@@ -824,22 +917,22 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
824917 var err = try diags.addErrorWithNotes(2);
825918 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) });
826919 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});
828921 }
829922
830923 if (existing_sym.isUndefined() and symbol.isUndefined()) {
831924 // only verify module/import name for function symbols
832925 if (symbol.tag == .function) {
833 const existing_name = if (existing_file) |existing_obj| blk: {
834 const imp = existing_obj.import(existing_loc.index);
835 break :blk existing_obj.string(imp.module_name);
926 const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| blk: {
927 const imp = objectImport(wasm, existing_obj_id, existing_loc.index);
928 break :blk objectString(wasm, existing_obj_id, imp.module_name);
836929 } else blk: {
837930 const name_index = wasm.imports.get(existing_loc).?.module_name;
838931 break :blk wasm.string_table.get(name_index);
839932 };
840933
841 const imp = obj_file.import(sym_index);
842 const module_name = obj_file.string(imp.module_name);
934 const imp = objectImport(wasm, object_id, sym_index);
935 const module_name = objectString(wasm, object_id, imp.module_name);
843936 if (!mem.eql(u8, existing_name, module_name)) {
844937 var err = try diags.addErrorWithNotes(2);
845938 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 {
848941 module_name,
849942 });
850943 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});
852945 }
853946 }
854947
......@@ -864,7 +957,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
864957 var err = try diags.addErrorWithNotes(2);
865958 try err.addMsg("symbol '{s}' mismatching global types", .{sym_name});
866959 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});
868961 }
869962 }
870963
......@@ -876,7 +969,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
876969 try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name});
877970 try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });
878971 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});
880973 }
881974 }
882975
......@@ -891,7 +984,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void {
891984 // simply overwrite with the new symbol
892985 log.debug("Overwriting symbol '{s}'", .{sym_name});
893986 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});
895988 try wasm.discarded.putNoClobber(gpa, existing_loc, location);
896989 maybe_existing.value_ptr.* = location;
897990 try wasm.globals.put(gpa, sym_name_index, location);
......@@ -924,16 +1017,14 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
9241017 // Symbol is found in unparsed object file within current archive.
9251018 // Parse object and and resolve symbols again before we check remaining
9261019 // undefined symbols.
927 var object = archive.parseObject(wasm, offset.items[0]) catch |e| {
1020 const object = archive.parseObject(wasm, offset.items[0]) catch |e| {
9281021 var err_note = try diags.addErrorWithNotes(1);
9291022 try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)});
9301023 try err_note.addNote("while parsing object in archive {s}", .{archive.name});
9311024 return error.FlushFailure;
9321025 };
933 object.index = @enumFromInt(wasm.files.len);
934 try wasm.files.append(gpa, .{ .object = object });
935 try wasm.objects.append(gpa, object.index);
936 try wasm.resolveSymbolsInObject(object.index);
1026 try wasm.objects.append(gpa, object);
1027 try wasm.resolveSymbolsInObject(@enumFromInt(wasm.objects.items.len - 1));
9371028
9381029 // continue loop for any remaining undefined symbols that still exist
9391030 // after resolving last object file
......@@ -964,13 +1055,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
9641055 return;
9651056 }
9661057 const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function);
967 sym_loc.getSymbol(wasm).mark();
1058 wasm.symbolLocSymbol(sym_loc).mark();
9681059
9691060 const flag_address: u32 = if (shared_memory) address: {
9701061 // when we have passive initialization segments and shared memory
9711062 // `setupMemory` will create this symbol and set its virtual address.
9721063 const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?;
973 break :address loc.getSymbol(wasm).virtual_address;
1064 break :address wasm.symbolLocSymbol(loc).virtual_address;
9741065 } else 0;
9751066
9761067 var function_body = std.ArrayList(u8).init(gpa);
......@@ -1028,7 +1119,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
10281119 try writeI32Const(writer, segment.offset);
10291120 try writer.writeByte(std.wasm.opcode(.global_set));
10301121 const loc = wasm.findGlobalSymbol("__tls_base").?;
1031 try leb.writeUleb128(writer, loc.getSymbol(wasm).index);
1122 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
10321123 }
10331124
10341125 try writeI32Const(writer, 0);
......@@ -1128,7 +1219,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
11281219 }
11291220
11301221 const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function);
1131 loc.getSymbol(wasm).mark();
1222 wasm.symbolLocSymbol(loc).mark();
11321223 var function_body = std.ArrayList(u8).init(gpa);
11331224 defer function_body.deinit();
11341225 const writer = function_body.writer();
......@@ -1136,12 +1227,12 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
11361227 // locals (we have none)
11371228 try writer.writeByte(0);
11381229 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);
11401231 if (!sym.isTLS()) continue; // only relocate TLS symbols
11411232 if (sym.tag == .data and sym.isDefined()) {
11421233 // get __tls_base
11431234 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
11461237 // add the virtual address of the symbol
11471238 try writer.writeByte(std.wasm.opcode(.i32_const));
......@@ -1165,7 +1256,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
11651256
11661257fn validateFeatures(
11671258 wasm: *const Wasm,
1168 to_emit: *[@typeInfo(types.Feature.Tag).@"enum".fields.len]bool,
1259 to_emit: *[@typeInfo(Feature.Tag).@"enum".fields.len]bool,
11691260 emit_features_count: *u32,
11701261) !void {
11711262 const comp = wasm.base.comp;
......@@ -1174,7 +1265,7 @@ fn validateFeatures(
11741265 const shared_memory = comp.config.shared_memory;
11751266 const cpu_features = target.cpu.features;
11761267 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
11791270 var allowed = [_]bool{false} ** known_features_count;
11801271 var used = [_]u17{0} ** known_features_count;
......@@ -1199,10 +1290,9 @@ fn validateFeatures(
11991290
12001291 // extract all the used, disallowed and required features from each
12011292 // linked object file so we can test them.
1202 for (wasm.objects.items) |file_index| {
1203 const object: Object = wasm.files.items(.data)[@intFromEnum(file_index)].object;
1293 for (wasm.objects.items, 0..) |*object, file_index| {
12041294 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;
12061296 switch (feature.prefix) {
12071297 .used => {
12081298 used[@intFromEnum(feature.tag)] = value;
......@@ -1234,8 +1324,8 @@ fn validateFeatures(
12341324 emit_features_count.* += @intFromBool(is_enabled);
12351325 } else if (is_enabled and !allowed[used_index]) {
12361326 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))});
1238 try err.addNote("defined in '{s}'", .{wasm.files.items(.data)[used_set >> 1].object.path});
1327 try err.addMsg("feature '{}' not allowed, but used by linked object", .{@as(Feature.Tag, @enumFromInt(used_index))});
1328 try err.addNote("defined in '{s}'", .{wasm.objects.items[used_set >> 1].path});
12391329 valid_feature_set = false;
12401330 }
12411331 }
......@@ -1245,17 +1335,17 @@ fn validateFeatures(
12451335 }
12461336
12471337 if (shared_memory) {
1248 const disallowed_feature = disallowed[@intFromEnum(types.Feature.Tag.shared_mem)];
1338 const disallowed_feature = disallowed[@intFromEnum(Feature.Tag.shared_mem)];
12491339 if (@as(u1, @truncate(disallowed_feature)) != 0) {
12501340 var err = try diags.addErrorWithNotes(0);
12511341 try err.addMsg(
12521342 "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},
12541344 );
12551345 valid_feature_set = false;
12561346 }
12571347
1258 for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {
1348 for ([_]Feature.Tag{ .atomics, .bulk_memory }) |feature| {
12591349 if (!allowed[@intFromEnum(feature)]) {
12601350 var err = try diags.addErrorWithNotes(0);
12611351 try err.addMsg("feature '{}' is not used but is required for shared-memory", .{feature});
......@@ -1264,7 +1354,7 @@ fn validateFeatures(
12641354 }
12651355
12661356 if (has_tls) {
1267 for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {
1357 for ([_]Feature.Tag{ .atomics, .bulk_memory }) |feature| {
12681358 if (!allowed[@intFromEnum(feature)]) {
12691359 var err = try diags.addErrorWithNotes(0);
12701360 try err.addMsg("feature '{}' is not used but is required for thread-local storage", .{feature});
......@@ -1272,9 +1362,8 @@ fn validateFeatures(
12721362 }
12731363 }
12741364 // For each linked object, validate the required and disallowed features
1275 for (wasm.objects.items) |file_index| {
1365 for (wasm.objects.items) |*object| {
12761366 var object_used_features = [_]bool{false} ** known_features_count;
1277 const object = wasm.files.items(.data)[@intFromEnum(file_index)].object;
12781367 for (object.features) |feature| {
12791368 if (feature.prefix == .disallowed) continue; // already defined in 'disallowed' set.
12801369 // from here a feature is always used
......@@ -1282,7 +1371,7 @@ fn validateFeatures(
12821371 if (@as(u1, @truncate(disallowed_feature)) != 0) {
12831372 var err = try diags.addErrorWithNotes(2);
12841373 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});
12861375 try err.addNote("used in '{s}'", .{object.path});
12871376 valid_feature_set = false;
12881377 }
......@@ -1295,8 +1384,8 @@ fn validateFeatures(
12951384 const is_required = @as(u1, @truncate(required_feature)) != 0;
12961385 if (is_required and !object_used_features[feature_index]) {
12971386 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))});
1299 try err.addNote("required by '{s}'", .{wasm.files.items(.data)[required_feature >> 1].object.path});
1387 try err.addMsg("feature '{}' is required but not used in linked object", .{@as(Feature.Tag, @enumFromInt(feature_index))});
1388 try err.addNote("required by '{s}'", .{wasm.objects.items[required_feature >> 1].path});
13001389 try err.addNote("missing in '{s}'", .{object.path});
13011390 valid_feature_set = false;
13021391 }
......@@ -1341,7 +1430,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
13411430 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);
13421431 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
13431432 _ = wasm.resolved_symbols.swapRemove(kv.value);
1344 const symbol = loc.getSymbol(wasm);
1433 const symbol = wasm.symbolLocSymbol(loc);
13451434 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
13461435 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
13471436 try wasm.wasm_globals.append(gpa, .{
......@@ -1368,14 +1457,15 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
13681457
13691458 var found_undefined_symbols = false;
13701459 for (wasm.undefs.values()) |undef| {
1371 const symbol = undef.getSymbol(wasm);
1460 const symbol = wasm.symbolLocSymbol(undef);
13721461 if (symbol.tag == .data) {
13731462 found_undefined_symbols = true;
1374 const file_name = if (wasm.file(undef.file)) |obj_file|
1375 obj_file.path()
1376 else
1377 wasm.name;
1378 const symbol_name = undef.getName(wasm);
1463 const file_name = switch (undef.file) {
1464 .zig_object => wasm.zig_object.?.path,
1465 .none => wasm.name,
1466 _ => wasm.objects.items[@intFromEnum(undef.file)].path,
1467 };
1468 const symbol_name = wasm.symbolLocName(undef);
13791469 var err = try diags.addErrorWithNotes(1);
13801470 try err.addMsg("could not resolve undefined symbol '{s}'", .{symbol_name});
13811471 try err.addNote("defined in '{s}'", .{file_name});
......@@ -1396,11 +1486,11 @@ pub fn deinit(wasm: *Wasm) void {
13961486 for (wasm.segment_info.values()) |segment_info| {
13971487 gpa.free(segment_info.name);
13981488 }
1399 if (wasm.zigObjectPtr()) |zig_obj| {
1489 if (wasm.zig_object) |zig_obj| {
14001490 zig_obj.deinit(wasm);
14011491 }
1402 for (wasm.objects.items) |obj_index| {
1403 wasm.file(obj_index).?.object.deinit(gpa);
1492 for (wasm.objects.items) |*object| {
1493 object.deinit(gpa);
14041494 }
14051495
14061496 for (wasm.archives.items) |*archive| {
......@@ -1437,7 +1527,6 @@ pub fn deinit(wasm: *Wasm) void {
14371527 wasm.exports.deinit(gpa);
14381528
14391529 wasm.string_table.deinit(gpa);
1440 wasm.files.deinit(gpa);
14411530}
14421531
14431532pub 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,
14451534 @panic("Attempted to compile for object format that was disabled by build configuration");
14461535 }
14471536 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);
14491538}
14501539
14511540// 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
14551544 @panic("Attempted to compile for object format that was disabled by build configuration");
14561545 }
14571546 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);
14591548}
14601549
14611550pub fn updateNavLineNumber(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {
14621551 if (wasm.llvm_object) |_| return;
1463 try wasm.zigObjectPtr().?.updateNavLineNumber(pt, nav);
1552 try wasm.zig_object.?.updateNavLineNumber(pt, nav);
14641553}
14651554
14661555/// From a given symbol location, returns its `wasm.GlobalType`.
14671556/// Asserts the Symbol represents a global.
14681557fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType {
1469 const symbol = loc.getSymbol(wasm);
1558 const symbol = wasm.symbolLocSymbol(loc);
14701559 assert(symbol.tag == .global);
14711560 const is_undefined = symbol.isUndefined();
1472 if (wasm.file(loc.file)) |obj_file| {
1473 if (is_undefined) {
1474 return obj_file.import(loc.index).kind.global;
1475 }
1476 return obj_file.globals()[symbol.index - obj_file.importedGlobals()].global_type;
1477 }
1478 if (is_undefined) {
1479 return wasm.imports.get(loc).?.kind.global;
1561 switch (loc.file) {
1562 .zig_object => {
1563 const zo = wasm.zig_object.?;
1564 return if (is_undefined)
1565 zo.imports.get(loc.index).?.kind.global
1566 else
1567 zo.globals.items[symbol.index - zo.imported_globals_count].global_type;
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 },
14801582 }
1481 return wasm.wasm_globals.items[symbol.index].global_type;
14821583}
14831584
14841585/// From a given symbol location, returns its `wasm.Type`.
14851586/// Asserts the Symbol represents a function.
14861587fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
1487 const symbol = loc.getSymbol(wasm);
1588 const symbol = wasm.symbolLocSymbol(loc);
14881589 assert(symbol.tag == .function);
14891590 const is_undefined = symbol.isUndefined();
1490 if (wasm.file(loc.file)) |obj_file| {
1491 if (is_undefined) {
1492 const ty_index = obj_file.import(loc.index).kind.function;
1493 return obj_file.funcTypes()[ty_index];
1494 }
1495 const type_index = obj_file.function(loc.index).type_index;
1496 return obj_file.funcTypes()[type_index];
1497 }
1498 if (is_undefined) {
1499 const ty_index = wasm.imports.get(loc).?.kind.function;
1500 return wasm.func_types.items[ty_index];
1591 switch (loc.file) {
1592 .zig_object => {
1593 const zo = wasm.zig_object.?;
1594 if (is_undefined) {
1595 const type_index = zo.imports.get(loc.index).?.kind.function;
1596 return zo.func_types.items[type_index];
1597 }
1598 const sym = zo.symbols.items[@intFromEnum(loc.index)];
1599 const type_index = zo.functions.items[sym.index].type_index;
1600 return zo.func_types.items[type_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 },
15011624 }
1502 return wasm.func_types.items[wasm.functions.get(.{ .file = loc.file, .index = symbol.index }).?.func.type_index];
15031625}
15041626
15051627/// 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 {
15081630/// and then returns the index to it.
15091631pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {
15101632 _ = lib_name;
1511 return wasm.zigObjectPtr().?.getGlobalSymbol(wasm.base.comp.gpa, name);
1633 return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name);
15121634}
15131635
15141636/// 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(
15191641 nav: InternPool.Nav.Index,
15201642 reloc_info: link.File.RelocInfo,
15211643) !u64 {
1522 return wasm.zigObjectPtr().?.getNavVAddr(wasm, pt, nav, reloc_info);
1644 return wasm.zig_object.?.getNavVAddr(wasm, pt, nav, reloc_info);
15231645}
15241646
15251647pub fn lowerUav(
......@@ -1529,11 +1651,11 @@ pub fn lowerUav(
15291651 explicit_alignment: Alignment,
15301652 src_loc: Zcu.LazySrcLoc,
15311653) !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);
15331655}
15341656
15351657pub 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);
15371659}
15381660
15391661pub fn deleteExport(
......@@ -1542,7 +1664,7 @@ pub fn deleteExport(
15421664 name: InternPool.NullTerminatedString,
15431665) void {
15441666 if (wasm.llvm_object) |_| return;
1545 return wasm.zigObjectPtr().?.deleteExport(wasm, exported, name);
1667 return wasm.zig_object.?.deleteExport(wasm, exported, name);
15461668}
15471669
15481670pub fn updateExports(
......@@ -1555,12 +1677,12 @@ pub fn updateExports(
15551677 @panic("Attempted to compile for object format that was disabled by build configuration");
15561678 }
15571679 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);
15591681}
15601682
15611683pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
15621684 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);
15641686}
15651687
15661688/// Assigns indexes to all indirect functions.
......@@ -1570,7 +1692,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
15701692 var it = wasm.function_table.iterator();
15711693 var index: u32 = 1;
15721694 while (it.next()) |entry| {
1573 const symbol = entry.key_ptr.*.getSymbol(wasm);
1695 const symbol = wasm.symbolLocSymbol(entry.key_ptr.*);
15741696 if (symbol.isAlive()) {
15751697 entry.value_ptr.* = index;
15761698 index += 1;
......@@ -1586,7 +1708,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
15861708 } else if (index > 1) {
15871709 log.debug("Appending indirect function table", .{});
15881710 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
1589 const symbol = sym_loc.getSymbol(wasm);
1711 const symbol = wasm.symbolLocSymbol(sym_loc);
15901712 const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];
15911713 table.limits = .{ .min = index, .max = index, .flags = 0x1 };
15921714 }
......@@ -1625,10 +1747,11 @@ fn allocateAtoms(wasm: *Wasm) !void {
16251747 // Ensure we get the original symbol, so we verify the correct symbol on whether
16261748 // it is dead or not and ensure an atom is removed when dead.
16271749 // This is required as we may have parsed aliases into atoms.
1628 const sym = if (wasm.file(symbol_loc.file)) |obj_file|
1629 obj_file.symbol(symbol_loc.index).*
1630 else
1631 wasm.synthetic_symbols.items[@intFromEnum(symbol_loc.index)];
1750 const sym = switch (symbol_loc.file) {
1751 .zig_object => wasm.zig_object.?.symbols.items[@intFromEnum(symbol_loc.index)],
1752 .none => wasm.synthetic_symbols.items[@intFromEnum(symbol_loc.index)],
1753 _ => wasm.objects.items[@intFromEnum(symbol_loc.file)].symtable[@intFromEnum(symbol_loc.index)],
1754 };
16321755
16331756 // Dead symbols must be unlinked from the linked-list to prevent them
16341757 // from being emit into the binary.
......@@ -1647,7 +1770,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
16471770 offset = @intCast(atom.alignment.forward(offset));
16481771 atom.offset = offset;
16491772 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),
16511774 offset,
16521775 offset + atom.size,
16531776 atom.size,
......@@ -1663,7 +1786,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
16631786/// For each data symbol, sets the virtual address.
16641787fn allocateVirtualAddresses(wasm: *Wasm) void {
16651788 for (wasm.resolved_symbols.keys()) |loc| {
1666 const symbol = loc.getSymbol(wasm);
1789 const symbol = wasm.symbolLocSymbol(loc);
16671790 if (symbol.tag != .data or symbol.isDead()) {
16681791 // Only data symbols have virtual addresses.
16691792 // 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 {
16761799
16771800 const atom = wasm.getAtom(atom_index);
16781801 const merge_segment = wasm.base.comp.config.output_mode != .Obj;
1679 const segment_info = if (atom.file != .null)
1680 wasm.file(atom.file).?.segmentInfo()
1681 else
1682 wasm.segment_info.values();
1802 const segment_info = switch (atom.file) {
1803 .zig_object => wasm.zig_object.?.segment_info.items,
1804 .none => wasm.segment_info.values(),
1805 _ => wasm.objects.items[@intFromEnum(atom.file)].segment_info,
1806 };
16831807 const segment_name = segment_info[symbol.index].outputName(merge_segment);
16841808 const segment_index = wasm.data_segments.get(segment_name).?;
16851809 const segment = wasm.segments.items[segment_index];
......@@ -1737,13 +1861,12 @@ fn setupInitFunctions(wasm: *Wasm) !void {
17371861 const gpa = wasm.base.comp.gpa;
17381862 const diags = &wasm.base.comp.link_diags;
17391863 // There's no constructors for Zig so we can simply search through linked object files only.
1740 for (wasm.objects.items) |file_index| {
1741 const object: Object = wasm.files.items(.data)[@intFromEnum(file_index)].object;
1864 for (wasm.objects.items, 0..) |*object, object_index| {
17421865 try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len);
17431866 for (object.init_funcs) |init_func| {
17441867 const symbol = object.symtable[init_func.symbol_index];
17451868 const ty: std.wasm.Type = if (symbol.isUndefined()) ty: {
1746 const imp: types.Import = object.findImport(symbol);
1869 const imp: Import = object.findImport(symbol);
17471870 break :ty object.func_types[imp.kind.function];
17481871 } else ty: {
17491872 const func_index = symbol.index - object.imported_functions_count;
......@@ -1757,10 +1880,13 @@ fn setupInitFunctions(wasm: *Wasm) !void {
17571880 log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)});
17581881 wasm.init_funcs.appendAssumeCapacity(.{
17591882 .index = @enumFromInt(init_func.symbol_index),
1760 .file = file_index,
1883 .file = @enumFromInt(object_index),
17611884 .priority = init_func.priority,
17621885 });
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 });
17641890 }
17651891 }
17661892
......@@ -1834,7 +1960,7 @@ fn createSyntheticFunction(
18341960) !void {
18351961 const gpa = wasm.base.comp.gpa;
18361962 const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol?
1837 const symbol = loc.getSymbol(wasm);
1963 const symbol = wasm.symbolLocSymbol(loc);
18381964 if (symbol.isDead()) {
18391965 return;
18401966 }
......@@ -1843,13 +1969,13 @@ fn createSyntheticFunction(
18431969 const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count()));
18441970 try wasm.functions.putNoClobber(
18451971 gpa,
1846 .{ .file = .null, .index = func_index },
1972 .{ .file = .none, .index = func_index },
18471973 .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index },
18481974 );
18491975 symbol.index = func_index;
18501976
18511977 // 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);
18531979 const atom = wasm.getAtomPtr(atom_index);
18541980 atom.size = @intCast(function_body.items.len);
18551981 atom.code = function_body.moveToUnmanaged();
......@@ -1866,13 +1992,13 @@ pub fn createFunction(
18661992 function_body: *std.ArrayList(u8),
18671993 relocations: *std.ArrayList(Relocation),
18681994) !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);
18701996}
18711997
18721998/// If required, sets the function index in the `start` section.
18731999fn setupStartSection(wasm: *Wasm) !void {
18742000 if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| {
1875 wasm.entry = loc.getSymbol(wasm).index;
2001 wasm.entry = wasm.symbolLocSymbol(loc).index;
18762002 }
18772003}
18782004
......@@ -1884,7 +2010,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
18842010 if (!shared_memory) return;
18852011
18862012 // 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
18892015 var function_body = std.ArrayList(u8).init(gpa);
18902016 defer function_body.deinit();
......@@ -1905,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
19052031
19062032 const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?;
19072033 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
19102036 // load stack values for the bulk-memory operation
19112037 {
......@@ -1933,8 +2059,8 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
19332059 // generated by the linker.
19342060 if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| {
19352061 try writer.writeByte(std.wasm.opcode(.call));
1936 try leb.writeUleb128(writer, loc.getSymbol(wasm).index);
1937 loc.getSymbol(wasm).mark();
2062 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
2063 wasm.symbolLocSymbol(loc).mark();
19382064 }
19392065
19402066 try writer.writeByte(std.wasm.opcode(.end));
......@@ -1950,27 +2076,27 @@ fn setupImports(wasm: *Wasm) !void {
19502076 const gpa = wasm.base.comp.gpa;
19512077 log.debug("Merging imports", .{});
19522078 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 {
19542080 // Synthetic symbols will already exist in the `import` section
19552081 continue;
19562082 };
19572083
1958 const symbol = symbol_loc.getSymbol(wasm);
2084 const symbol = wasm.symbolLocSymbol(symbol_loc);
19592085 if (symbol.isDead() or
19602086 !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"))
19622088 {
19632089 continue;
19642090 }
19652091
1966 log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)});
1967 const import = obj_file.import(symbol_loc.index);
2092 log.debug("Symbol '{s}' will be imported from the host", .{wasm.symbolLocName(symbol_loc)});
2093 const import = objectImport(wasm, object_id, symbol_loc.index);
19682094
19692095 // We copy the import to a new import to ensure the names contain references
19702096 // to the internal string table, rather than of the object file.
1971 const new_imp: types.Import = .{
1972 .module_name = try wasm.string_table.put(gpa, obj_file.string(import.module_name)),
1973 .name = try wasm.string_table.put(gpa, obj_file.string(import.name)),
2097 const new_imp: Import = .{
2098 .module_name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.module_name)),
2099 .name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.name)),
19742100 .kind = import.kind,
19752101 };
19762102 // TODO: De-duplicate imports when they contain the same names and type
......@@ -1983,8 +2109,8 @@ fn setupImports(wasm: *Wasm) !void {
19832109 var table_index: u32 = 0;
19842110 var it = wasm.imports.iterator();
19852111 while (it.next()) |entry| {
1986 const symbol = entry.key_ptr.*.getSymbol(wasm);
1987 const import: types.Import = entry.value_ptr.*;
2112 const symbol = wasm.symbolLocSymbol(entry.key_ptr.*);
2113 const import: Import = entry.value_ptr.*;
19882114 switch (import.kind) {
19892115 .function => {
19902116 symbol.index = function_index;
......@@ -2021,12 +2147,12 @@ fn mergeSections(wasm: *Wasm) !void {
20212147 defer removed_duplicates.deinit();
20222148
20232149 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 {
20252151 // Synthetic symbols already live in the corresponding sections.
20262152 continue;
20272153 };
20282154
2029 const symbol = obj_file.symbol(sym_loc.index);
2155 const symbol = objectSymbol(wasm, object_id, sym_loc.index);
20302156 if (symbol.isDead() or symbol.isUndefined()) {
20312157 // Skip undefined symbols as they go in the `import` section
20322158 continue;
......@@ -2044,7 +2170,7 @@ fn mergeSections(wasm: *Wasm) !void {
20442170 // we only emit a single function, instead of duplicates.
20452171 // we favor keeping the global over a local.
20462172 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);
20482174 if (original_sym.isLocal() and symbol.isGlobal()) {
20492175 original_sym.unmark();
20502176 try wasm.discarded.put(gpa, original_loc, sym_loc);
......@@ -2056,20 +2182,23 @@ fn mergeSections(wasm: *Wasm) !void {
20562182 continue;
20572183 }
20582184 }
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 };
20602189 symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count;
20612190 },
20622191 .global => {
2063 const index = symbol.index - obj_file.importedFunctions();
2064 const original_global = obj_file.globals()[index];
2192 const index = symbol.index - objectImportedFunctions(wasm, object_id);
2193 const original_global = objectGlobals(wasm, object_id)[index];
20652194 symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;
20662195 try wasm.wasm_globals.append(gpa, original_global);
20672196 },
20682197 .table => {
2069 const index = symbol.index - obj_file.importedFunctions();
2198 const index = symbol.index - objectImportedFunctions(wasm, object_id);
20702199 // assert it's a regular relocatable object file as `ZigObject` will never
20712200 // contain a table.
2072 const original_table = obj_file.object.tables[index];
2201 const original_table = wasm.objectById(object_id).?.tables[index];
20732202 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;
20742203 try wasm.tables.append(gpa, original_table);
20752204 },
......@@ -2081,7 +2210,7 @@ fn mergeSections(wasm: *Wasm) !void {
20812210 // For any removed duplicates, remove them from the resolved symbols list
20822211 for (removed_duplicates.items) |sym_loc| {
20832212 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)});
20852214 }
20862215
20872216 log.debug("Merged ({d}) functions", .{wasm.functions.count()});
......@@ -2102,26 +2231,26 @@ fn mergeTypes(wasm: *Wasm) !void {
21022231 defer dirty.deinit();
21032232
21042233 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 {
21062235 // zig code-generated symbols are already present in final type section
21072236 continue;
21082237 };
21092238
2110 const symbol = obj_file.symbol(sym_loc.index);
2239 const symbol = objectSymbol(wasm, object_id, sym_loc.index);
21112240 if (symbol.tag != .function or symbol.isDead()) {
21122241 // Only functions have types. Only retrieve the type of referenced functions.
21132242 continue;
21142243 }
21152244
21162245 if (symbol.isUndefined()) {
2117 log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(wasm)});
2118 const import: *types.Import = wasm.imports.getPtr(sym_loc) orelse continue;
2119 const original_type = obj_file.funcTypes()[import.kind.function];
2246 log.debug("Adding type from extern function '{s}'", .{wasm.symbolLocName(sym_loc)});
2247 const import: *Import = wasm.imports.getPtr(sym_loc) orelse continue;
2248 const original_type = objectFuncTypes(wasm, object_id)[import.kind.function];
21202249 import.kind.function = try wasm.putOrGetFuncType(original_type);
21212250 } 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)});
21232252 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]);
21252254 dirty.putAssumeCapacityNoClobber(symbol.index, {});
21262255 }
21272256 }
......@@ -2142,7 +2271,7 @@ fn checkExportNames(wasm: *Wasm) !void {
21422271 continue;
21432272 };
21442273
2145 const symbol = loc.getSymbol(wasm);
2274 const symbol = wasm.symbolLocSymbol(loc);
21462275 symbol.setFlag(.WASM_SYM_EXPORTED);
21472276 }
21482277
......@@ -2159,15 +2288,15 @@ fn setupExports(wasm: *Wasm) !void {
21592288 log.debug("Building exports from symbols", .{});
21602289
21612290 for (wasm.resolved_symbols.keys()) |sym_loc| {
2162 const symbol = sym_loc.getSymbol(wasm);
2291 const symbol = wasm.symbolLocSymbol(sym_loc);
21632292 if (!symbol.isExported(comp.config.rdynamic)) continue;
21642293
2165 const sym_name = sym_loc.getName(wasm);
2166 const export_name = if (sym_loc.file == .null)
2294 const sym_name = wasm.symbolLocName(sym_loc);
2295 const export_name = if (sym_loc.file == .none)
21672296 symbol.name
21682297 else
21692298 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: {
21712300 const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));
21722301 try wasm.wasm_globals.append(gpa, .{
21732302 .global_type = .{ .valtype = .i32, .mutable = false },
......@@ -2206,7 +2335,7 @@ fn setupStart(wasm: *Wasm) !void {
22062335 return error.FlushFailure;
22072336 };
22082337
2209 const symbol = symbol_loc.getSymbol(wasm);
2338 const symbol = wasm.symbolLocSymbol(symbol_loc);
22102339 if (symbol.tag != .function) {
22112340 var err = try diags.addErrorWithNotes(0);
22122341 try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name});
......@@ -2240,7 +2369,7 @@ fn setupMemory(wasm: *Wasm) !void {
22402369 const is_obj = comp.config.output_mode == .Obj;
22412370
22422371 const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: {
2243 const sym = loc.getSymbol(wasm);
2372 const sym = wasm.symbolLocSymbol(loc);
22442373 break :index sym.index - wasm.imported_globals_count;
22452374 } else null;
22462375
......@@ -2262,15 +2391,15 @@ fn setupMemory(wasm: *Wasm) !void {
22622391 // set TLS-related symbols
22632392 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
22642393 if (wasm.findGlobalSymbol("__tls_size")) |loc| {
2265 const sym = loc.getSymbol(wasm);
2394 const sym = wasm.symbolLocSymbol(loc);
22662395 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size);
22672396 }
22682397 if (wasm.findGlobalSymbol("__tls_align")) |loc| {
2269 const sym = loc.getSymbol(wasm);
2398 const sym = wasm.symbolLocSymbol(loc);
22702399 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);
22712400 }
22722401 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
2273 const sym = loc.getSymbol(wasm);
2402 const sym = wasm.symbolLocSymbol(loc);
22742403 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory)
22752404 @as(i32, 0)
22762405 else
......@@ -2288,7 +2417,7 @@ fn setupMemory(wasm: *Wasm) !void {
22882417 // align to pointer size
22892418 memory_ptr = mem.alignForward(u64, memory_ptr, 4);
22902419 const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data);
2291 const sym = loc.getSymbol(wasm);
2420 const sym = wasm.symbolLocSymbol(loc);
22922421 sym.mark();
22932422 sym.virtual_address = @as(u32, @intCast(memory_ptr));
22942423 memory_ptr += 4;
......@@ -2305,7 +2434,7 @@ fn setupMemory(wasm: *Wasm) !void {
23052434 // One of the linked object files has a reference to the __heap_base symbol.
23062435 // We must set its virtual address so it can be used in relocations.
23072436 if (wasm.findGlobalSymbol("__heap_base")) |loc| {
2308 const symbol = loc.getSymbol(wasm);
2437 const symbol = wasm.symbolLocSymbol(loc);
23092438 symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr));
23102439 }
23112440
......@@ -2335,7 +2464,7 @@ fn setupMemory(wasm: *Wasm) !void {
23352464 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});
23362465
23372466 if (wasm.findGlobalSymbol("__heap_end")) |loc| {
2338 const symbol = loc.getSymbol(wasm);
2467 const symbol = wasm.symbolLocSymbol(loc);
23392468 symbol.virtual_address = @as(u32, @intCast(memory_ptr));
23402469 }
23412470
......@@ -2364,18 +2493,17 @@ fn setupMemory(wasm: *Wasm) !void {
23642493/// From a given object's index and the index of the segment, returns the corresponding
23652494/// index of the segment within the final data section. When the segment does not yet
23662495/// 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 {
23682497 const comp = wasm.base.comp;
23692498 const gpa = comp.gpa;
23702499 const diags = &wasm.base.comp.link_diags;
2371 const obj_file = wasm.file(file_index).?;
2372 const symbol = obj_file.symbols()[@intFromEnum(symbol_index)];
2500 const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)];
23732501 const index: u32 = @intCast(wasm.segments.items.len);
23742502 const shared_memory = comp.config.shared_memory;
23752503
23762504 switch (symbol.tag) {
23772505 .data => {
2378 const segment_info = obj_file.segmentInfo()[symbol.index];
2506 const segment_info = objectSegmentInfo(wasm, object_id)[symbol.index];
23792507 const merge_segment = comp.config.output_mode != .Obj;
23802508 const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment));
23812509 if (!result.found_existing) {
......@@ -2404,7 +2532,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym
24042532 break :blk index;
24052533 },
24062534 .section => {
2407 const section_name = obj_file.symbolName(symbol_index);
2535 const section_name = objectSymbolName(wasm, object_id, symbol_index);
24082536 if (mem.eql(u8, section_name, ".debug_info")) {
24092537 return wasm.debug_info_index orelse blk: {
24102538 wasm.debug_info_index = index;
......@@ -2456,7 +2584,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym
24562584 } else {
24572585 var err = try diags.addErrorWithNotes(1);
24582586 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)});
24602588 return error.UnexpectedValue;
24612589 }
24622590 },
......@@ -2523,7 +2651,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
25232651 const link_libcpp = comp.config.link_libcpp;
25242652 const wasi_exec_model = comp.config.wasi_exec_model;
25252653
2526 if (wasm.zigObjectPtr()) |zig_object| {
2654 if (wasm.zig_object) |zig_object| {
25272655 try zig_object.flushModule(wasm, tid);
25282656 }
25292657
......@@ -2578,17 +2706,17 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
25782706 log.warn("Unexpected file format at path: '{s}'", .{path});
25792707 }
25802708
2581 if (wasm.zig_object_index != .null) {
2582 try wasm.resolveSymbolsInObject(wasm.zig_object_index);
2709 if (wasm.zig_object != null) {
2710 try wasm.resolveSymbolsInObject(.zig_object);
25832711 }
25842712 if (diags.hasErrors()) return error.FlushFailure;
2585 for (wasm.objects.items) |object_index| {
2586 try wasm.resolveSymbolsInObject(object_index);
2713 for (0..wasm.objects.items.len) |object_index| {
2714 try wasm.resolveSymbolsInObject(@enumFromInt(object_index));
25872715 }
25882716 if (diags.hasErrors()) return error.FlushFailure;
25892717
25902718 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;
25922720 try wasm.validateFeatures(&enabled_features, &emit_features_count);
25932721 try wasm.resolveSymbolsInArchives();
25942722 if (diags.hasErrors()) return error.FlushFailure;
......@@ -2622,7 +2750,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
26222750/// Writes the WebAssembly in-memory module to the file
26232751fn writeToFile(
26242752 wasm: *Wasm,
2625 enabled_features: [@typeInfo(types.Feature.Tag).@"enum".fields.len]bool,
2753 enabled_features: [@typeInfo(Feature.Tag).@"enum".fields.len]bool,
26262754 feature_count: u32,
26272755 arena: Allocator,
26282756) !void {
......@@ -2688,14 +2816,14 @@ fn writeToFile(
26882816
26892817 var it = wasm.imports.iterator();
26902818 while (it.next()) |entry| {
2691 assert(entry.key_ptr.*.getSymbol(wasm).isUndefined());
2819 assert(wasm.symbolLocSymbol(entry.key_ptr.*).isUndefined());
26922820 const import = entry.value_ptr.*;
26932821 try wasm.emitImport(binary_writer, import);
26942822 }
26952823
26962824 if (import_memory) {
26972825 const mem_name = if (is_obj) "__linear_memory" else "memory";
2698 const mem_imp: types.Import = .{
2826 const mem_imp: Import = .{
26992827 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
27002828 .name = try wasm.string_table.put(gpa, mem_name),
27012829 .kind = .{ .memory = wasm.memories.limits },
......@@ -2829,7 +2957,7 @@ fn writeToFile(
28292957 const header_offset = try reserveVecSectionHeader(&binary_bytes);
28302958
28312959 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
28342962 const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually
28352963 try leb.writeUleb128(binary_writer, flags);
......@@ -2843,7 +2971,7 @@ fn writeToFile(
28432971 try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.function_table.count())));
28442972 var symbol_it = wasm.function_table.keyIterator();
28452973 while (symbol_it.next()) |symbol_loc_ptr| {
2846 const sym = symbol_loc_ptr.getSymbol(wasm);
2974 const sym = wasm.symbolLocSymbol(symbol_loc_ptr.*);
28472975 std.debug.assert(sym.isAlive());
28482976 std.debug.assert(sym.index < wasm.functions.count() + wasm.imported_functions_count);
28492977 try leb.writeUleb128(binary_writer, sym.index);
......@@ -3183,7 +3311,7 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con
31833311 try leb.writeUleb128(writer, features_count);
31843312 for (enabled_features, 0..) |enabled, feature_index| {
31853313 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)) };
31873315 try leb.writeUleb128(writer, @intFromEnum(feature.prefix));
31883316 var buf: [100]u8 = undefined;
31893317 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
32193347 var segments = try std.ArrayList(Name).initCapacity(arena, wasm.data_segments.count());
32203348
32213349 for (wasm.resolved_symbols.keys()) |sym_loc| {
3222 const symbol = sym_loc.getSymbol(wasm).*;
3350 const symbol = wasm.symbolLocSymbol(sym_loc).*;
32233351 if (symbol.isDead()) {
32243352 continue;
32253353 }
3226 const name = sym_loc.getName(wasm);
3354 const name = wasm.symbolLocName(sym_loc);
32273355 switch (symbol.tag) {
32283356 .function => {
32293357 const gop = funcs.getOrPutAssumeCapacity(symbol.index);
......@@ -3320,7 +3448,7 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
33203448 try writer.writeByte(std.wasm.opcode(.end));
33213449}
33223450
3323fn emitImport(wasm: *Wasm, writer: anytype, import: types.Import) !void {
3451fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void {
33243452 const module_name = wasm.string_table.get(import.module_name);
33253453 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));
33263454 try writer.writeAll(module_name);
......@@ -3800,7 +3928,7 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
38003928 // meta data version, which is currently '2'
38013929 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.
38043932 // Currently, we only support emitting segment info and the symbol table.
38053933 try wasm.emitSymbolTable(binary_bytes, symbol_table);
38063934 try wasm.emitSegmentInfo(binary_bytes);
......@@ -3812,12 +3940,12 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
38123940fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {
38133941 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));
38163944 const table_offset = binary_bytes.items.len;
38173945
38183946 var symbol_count: u32 = 0;
38193947 for (wasm.resolved_symbols.keys()) |sym_loc| {
3820 const symbol = sym_loc.getSymbol(wasm).*;
3948 const symbol = wasm.symbolLocSymbol(sym_loc).*;
38213949 if (symbol.tag == .dead) continue; // Do not emit dead symbols
38223950 try symbol_table.putNoClobber(sym_loc, symbol_count);
38233951 symbol_count += 1;
......@@ -3825,7 +3953,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
38253953 try leb.writeUleb128(writer, @intFromEnum(symbol.tag));
38263954 try leb.writeUleb128(writer, symbol.flags);
38273955
3828 const sym_name = sym_loc.getName(wasm);
3956 const sym_name = wasm.symbolLocName(sym_loc);
38293957 switch (symbol.tag) {
38303958 .data => {
38313959 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:
38603988
38613989fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
38623990 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));
38643992 const segment_offset = binary_bytes.items.len;
38653993
38663994 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 {
40304158/// Asserts declaration has an associated `Atom`.
40314159/// Returns the index into the list of types.
40324160pub 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);
40344162}
40354163
40364164/// Returns the symbol index of the error name table.
40374165///
40384166/// When the symbol does not yet exist, it will create a new one instead.
4039pub fn getErrorTableSymbol(wasm_file: *Wasm, pt: Zcu.PerThread) !u32 {
4040 const sym_index = try wasm_file.zigObjectPtr().?.getErrorTableSymbol(wasm_file, pt);
4167pub fn getErrorTableSymbol(wasm: *Wasm, pt: Zcu.PerThread) !u32 {
4168 const sym_index = try wasm.zig_object.?.getErrorTableSymbol(wasm, pt);
40414169 return @intFromEnum(sym_index);
40424170}
40434171
40444172/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.
40454173/// When the index was not found, a new `Atom` will be created, and its index will be returned.
40464174/// 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 {
4048 return wasm_file.zigObjectPtr().?.getOrCreateAtomForNav(wasm_file, pt, nav);
4175pub fn getOrCreateAtomForNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !Atom.Index {
4176 return wasm.zig_object.?.getOrCreateAtomForNav(wasm, pt, nav);
40494177}
40504178
40514179/// Verifies all resolved symbols and checks whether itself needs to be marked alive,
......@@ -4058,7 +4186,7 @@ fn markReferences(wasm: *Wasm) !void {
40584186 const comp = wasm.base.comp;
40594187
40604188 for (wasm.resolved_symbols.keys()) |sym_loc| {
4061 const sym = sym_loc.getSymbol(wasm);
4189 const sym = wasm.symbolLocSymbol(sym_loc);
40624190 if (sym.isExported(comp.config.rdynamic) or sym.isNoStrip() or !do_garbage_collect) {
40634191 try wasm.mark(sym_loc);
40644192 continue;
......@@ -4067,8 +4195,8 @@ fn markReferences(wasm: *Wasm) !void {
40674195 // Debug sections may require to be parsed and marked when it contains
40684196 // relocations to alive symbols.
40694197 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 independently
4071 _ = try obj_file.parseSymbolIntoAtom(wasm, sym_loc.index);
4198 const object_id = sym_loc.file.unwrap() orelse continue; // Incremental debug info is done independently
4199 _ = try wasm.parseSymbolIntoAtom(object_id, sym_loc.index);
40724200 sym.mark();
40734201 }
40744202 }
......@@ -4077,7 +4205,7 @@ fn markReferences(wasm: *Wasm) !void {
40774205/// Marks a symbol as 'alive' recursively so itself and any references it contains to
40784206/// other symbols will not be omit from the binary.
40794207fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
4080 const symbol = loc.getSymbol(wasm);
4208 const symbol = wasm.symbolLocSymbol(loc);
40814209 if (symbol.isAlive()) {
40824210 // Symbol is already marked alive, including its references.
40834211 // 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 {
40854213 return;
40864214 }
40874215 symbol.mark();
4088 gc_log.debug("Marked symbol '{s}'", .{loc.getName(wasm)});
4216 gc_log.debug("Marked symbol '{s}'", .{wasm.symbolLocName(loc)});
40894217 if (symbol.isUndefined()) {
40904218 // undefined symbols do not have an associated `Atom` and therefore also
40914219 // do not contain relocations.
40924220 return;
40934221 }
40944222
4095 const atom_index = if (wasm.file(loc.file)) |obj_file|
4096 try obj_file.parseSymbolIntoAtom(wasm, loc.index)
4223 const atom_index = if (loc.file.unwrap()) |object_id|
4224 try wasm.parseSymbolIntoAtom(object_id, loc.index)
40974225 else
40984226 wasm.symbol_atom.get(loc) orelse return;
40994227
41004228 const atom = wasm.getAtom(atom_index);
41014229 for (atom.relocs.items) |reloc| {
41024230 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));
41044232 }
41054233}
41064234
......@@ -4110,3 +4238,566 @@ fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8
41104238 .command => "_start",
41114239 };
41124240}
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 @@
33//! the data on correctness. The result can then be used by the linker.
44const Object = @This();
55
6const Atom = @import("Atom.zig");
7const types = @import("types.zig");
8const std = @import("std");
96const Wasm = @import("../Wasm.zig");
7const Atom = Wasm.Atom;
8const Alignment = Wasm.Alignment;
109const Symbol = @import("Symbol.zig");
11const Alignment = types.Alignment;
12const File = @import("file.zig").File;
1310
11const std = @import("std");
1412const Allocator = std.mem.Allocator;
1513const leb = std.leb;
1614const meta = std.meta;
1715
1816const log = std.log.scoped(.object);
1917
20/// Index into the list of relocatable object files within the linker driver.
21index: File.Index = .null,
2218/// Wasm spec version used for this `Object`
2319version: u32 = 0,
2420/// The file descriptor that represents the wasm object file.
......@@ -28,7 +24,7 @@ path: []const u8,
2824/// Parsed type section
2925func_types: []const std.wasm.Type = &.{},
3026/// A list of all imports for this module
31imports: []const types.Import = &.{},
27imports: []const Wasm.Import = &.{},
3228/// Parsed function section
3329functions: []const std.wasm.Func = &.{},
3430/// Parsed table section
......@@ -38,7 +34,7 @@ memories: []const std.wasm.Memory = &.{},
3834/// Parsed global section
3935globals: []const std.wasm.Global = &.{},
4036/// Parsed export section
41exports: []const types.Export = &.{},
37exports: []const Wasm.Export = &.{},
4238/// Parsed element section
4339elements: []const std.wasm.Element = &.{},
4440/// Represents the function ID that must be called on startup.
......@@ -48,18 +44,18 @@ start: ?u32 = null,
4844/// A slice of features that tell the linker what features are mandatory,
4945/// used (or therefore missing) and must generate an error when another
5046/// object uses features that are not supported by the other.
51features: []const types.Feature = &.{},
47features: []const Wasm.Feature = &.{},
5248/// A table that maps the relocations we must perform where the key represents
5349/// the section that the list of relocations applies to.
54relocations: std.AutoArrayHashMapUnmanaged(u32, []types.Relocation) = .empty,
50relocations: std.AutoArrayHashMapUnmanaged(u32, []Wasm.Relocation) = .empty,
5551/// Table of symbols belonging to this Object file
5652symtable: []Symbol = &.{},
5753/// Extra metadata about the linking section, such as alignment of segments and their name
58segment_info: []const types.Segment = &.{},
54segment_info: []const Wasm.NamedSegment = &.{},
5955/// A sequence of function initializers that must be called on startup
60init_funcs: []const types.InitFunc = &.{},
56init_funcs: []const Wasm.InitFunc = &.{},
6157/// Comdat information
62comdat_info: []const types.Comdat = &.{},
58comdat_info: []const Wasm.Comdat = &.{},
6359/// Represents non-synthetic sections that can essentially be mem-cpy'd into place
6460/// after performing relocations.
6561relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .empty,
......@@ -75,7 +71,7 @@ imported_globals_count: u32 = 0,
7571imported_tables_count: u32 = 0,
7672
7773/// Represents a single item within a section (depending on its `type`)
78const RelocatableData = struct {
74pub const RelocatableData = struct {
7975 /// The type of the relocatable data
8076 type: Tag,
8177 /// 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 {
209205
210206/// Finds the import within the list of imports from a given kind and index of that kind.
211207/// Asserts the import exists
212pub fn findImport(object: *const Object, sym: Symbol) types.Import {
208pub fn findImport(object: *const Object, sym: Symbol) Wasm.Import {
213209 var i: u32 = 0;
214210 return for (object.imports) |import| {
215211 if (std.meta.activeTag(import.kind) == sym.tag.externalType()) {
......@@ -261,7 +257,7 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm_file: *const Wasm) !?S
261257 return error.MissingTableSymbols;
262258 }
263259
264 const table_import: types.Import = for (object.imports) |imp| {
260 const table_import: Wasm.Import = for (object.imports) |imp| {
265261 if (imp.kind == .table) {
266262 break imp;
267263 }
......@@ -592,13 +588,13 @@ fn Parser(comptime ReaderType: type) type {
592588 const diags = &parser.wasm_file.base.comp.link_diags;
593589 const reader = parser.reader.reader();
594590 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);
596592 const name_len = try leb.readUleb128(u32, reader);
597593 const name = try gpa.alloc(u8, name_len);
598594 defer gpa.free(name);
599595 try reader.readNoEof(name);
600596
601 const tag = types.known_features.get(name) orelse {
597 const tag = Wasm.known_features.get(name) orelse {
602598 var err = try diags.addErrorWithNotes(1);
603599 try err.addMsg("Object file contains unknown feature: {s}", .{name});
604600 try err.addNote("defined in '{s}'", .{parser.object.path});
......@@ -618,7 +614,7 @@ fn Parser(comptime ReaderType: type) type {
618614 const reader = parser.reader.reader();
619615 const section = try leb.readUleb128(u32, reader);
620616 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);
622618 errdefer gpa.free(relocations);
623619
624620 log.debug("Found {d} relocations for section ({d})", .{
......@@ -628,7 +624,7 @@ fn Parser(comptime ReaderType: type) type {
628624
629625 for (relocations) |*relocation| {
630626 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;
632628 relocation.* = .{
633629 .relocation_type = rel_type_enum,
634630 .offset = try leb.readUleb128(u32, reader),
......@@ -671,7 +667,7 @@ fn Parser(comptime ReaderType: type) type {
671667 /// such as access to the `import` section to find the name of a symbol.
672668 fn parseSubsection(parser: *ObjectParser, gpa: Allocator, reader: anytype) !void {
673669 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)))});
675671 const payload_len = try leb.readUleb128(u32, reader);
676672 if (payload_len == 0) return;
677673
......@@ -681,9 +677,9 @@ fn Parser(comptime ReaderType: type) type {
681677 // every subsection contains a 'count' field
682678 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))) {
685681 .WASM_SEGMENT_INFO => {
686 const segments = try gpa.alloc(types.Segment, count);
682 const segments = try gpa.alloc(Wasm.NamedSegment, count);
687683 errdefer gpa.free(segments);
688684 for (segments) |*segment| {
689685 const name_len = try leb.readUleb128(u32, reader);
......@@ -704,13 +700,13 @@ fn Parser(comptime ReaderType: type) type {
704700 // support legacy object files that specified being TLS by the name instead of the TLS flag.
705701 if (!segment.isTLS() and (std.mem.startsWith(u8, segment.name, ".tdata") or std.mem.startsWith(u8, segment.name, ".tbss"))) {
706702 // 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);
708704 }
709705 }
710706 parser.object.segment_info = segments;
711707 },
712708 .WASM_INIT_FUNCS => {
713 const funcs = try gpa.alloc(types.InitFunc, count);
709 const funcs = try gpa.alloc(Wasm.InitFunc, count);
714710 errdefer gpa.free(funcs);
715711 for (funcs) |*func| {
716712 func.* = .{
......@@ -722,7 +718,7 @@ fn Parser(comptime ReaderType: type) type {
722718 parser.object.init_funcs = funcs;
723719 },
724720 .WASM_COMDAT_INFO => {
725 const comdats = try gpa.alloc(types.Comdat, count);
721 const comdats = try gpa.alloc(Wasm.Comdat, count);
726722 errdefer gpa.free(comdats);
727723 for (comdats) |*comdat| {
728724 const name_len = try leb.readUleb128(u32, reader);
......@@ -736,11 +732,11 @@ fn Parser(comptime ReaderType: type) type {
736732 }
737733
738734 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);
740736 errdefer gpa.free(symbols);
741737 for (symbols) |*symbol| {
742738 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))),
744740 .index = try leb.readUleb128(u32, reader),
745741 };
746742 }
......@@ -921,93 +917,3 @@ fn assertEnd(reader: anytype) !void {
921917 if (len != 0) return error.MalformedSection;
922918 if (reader.context.bytes_left != 0) return error.MalformedSection;
923919}
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
206206}
207207
208208const std = @import("std");
209const types = @import("types.zig");
210209const Symbol = @This();
src/link/Wasm/ZigObject.zig+126-130
......@@ -4,8 +4,6 @@
44//! Think about this as fake in-memory Object file for the Zig module.
55
66path: []const u8,
7/// Index within the list of relocatable objects of the linker driver.
8index: File.Index,
97/// Map of all `Nav` that are currently alive.
108/// Each index maps to the corresponding `NavInfo`.
119navs: std.AutoHashMapUnmanaged(InternPool.Nav.Index, NavInfo) = .empty,
......@@ -16,8 +14,8 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .empty,
1614functions: std.ArrayListUnmanaged(std.wasm.Func) = .empty,
1715/// List of indexes pointing to an entry within the `functions` list which has been removed.
1816functions_free_list: std.ArrayListUnmanaged(u32) = .empty,
19/// Map of symbol locations, represented by its `types.Import`.
20imports: std.AutoHashMapUnmanaged(Symbol.Index, types.Import) = .empty,
17/// Map of symbol locations, represented by its `Wasm.Import`.
18imports: std.AutoHashMapUnmanaged(Symbol.Index, Wasm.Import) = .empty,
2119/// List of WebAssembly globals.
2220globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,
2321/// Mapping between an `Atom` and its type index representing the Wasm
......@@ -30,7 +28,7 @@ global_syms: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .empty,
3028/// List of symbol indexes which are free to be used.
3129symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .empty,
3230/// 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,
3432/// List of indexes which contain a free slot in the `segment_info` list.
3533segment_free_list: std.ArrayListUnmanaged(u32) = .empty,
3634/// File encapsulated string table, used to deduplicate strings within the generated file.
......@@ -117,39 +115,39 @@ const NavInfo = struct {
117115};
118116
119117/// 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 {
121119 // Initialize an undefined global with the name __stack_pointer. Codegen will use
122120 // this to generate relocations when moving the stack pointer. This symbol will be
123121 // resolved automatically by the final linking stage.
124 try zig_object.createStackPointer(wasm_file);
122 try zig_object.createStackPointer(wasm);
125123
126124 // TODO: Initialize debug information when we reimplement Dwarf support.
127125}
128126
129fn createStackPointer(zig_object: *ZigObject, wasm_file: *Wasm) !void {
130 const gpa = wasm_file.base.comp.gpa;
127fn createStackPointer(zig_object: *ZigObject, wasm: *Wasm) !void {
128 const gpa = wasm.base.comp.gpa;
131129 const sym_index = try zig_object.getGlobalSymbol(gpa, "__stack_pointer");
132130 const sym = zig_object.symbol(sym_index);
133131 sym.index = zig_object.imported_globals_count;
134132 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;
136134 try zig_object.imports.putNoClobber(gpa, sym_index, .{
137135 .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),
139137 .kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } },
140138 });
141139 zig_object.imported_globals_count += 1;
142140 zig_object.stack_pointer_sym = sym_index;
143141}
144142
145fn symbol(zig_object: *const ZigObject, index: Symbol.Index) *Symbol {
143pub fn symbol(zig_object: *const ZigObject, index: Symbol.Index) *Symbol {
146144 return &zig_object.symbols.items[@intFromEnum(index)];
147145}
148146
149147/// Frees and invalidates all memory of the incrementally compiled Zig module.
150148/// It is illegal behavior to access the `ZigObject` after calling `deinit`.
151pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
152 const gpa = wasm_file.base.comp.gpa;
149pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
150 const gpa = wasm.base.comp.gpa;
153151 for (zig_object.segment_info.items) |segment_info| {
154152 gpa.free(segment_info.name);
155153 }
......@@ -157,9 +155,9 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
157155 {
158156 var it = zig_object.navs.valueIterator();
159157 while (it.next()) |nav_info| {
160 const atom = wasm_file.getAtomPtr(nav_info.atom);
158 const atom = wasm.getAtomPtr(nav_info.atom);
161159 for (atom.locals.items) |local_index| {
162 const local_atom = wasm_file.getAtomPtr(local_index);
160 const local_atom = wasm.getAtomPtr(local_index);
163161 local_atom.deinit(gpa);
164162 }
165163 atom.deinit(gpa);
......@@ -168,24 +166,24 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
168166 }
169167 {
170168 for (zig_object.uavs.values()) |atom_index| {
171 const atom = wasm_file.getAtomPtr(atom_index);
169 const atom = wasm.getAtomPtr(atom_index);
172170 for (atom.locals.items) |local_index| {
173 const local_atom = wasm_file.getAtomPtr(local_index);
171 const local_atom = wasm.getAtomPtr(local_index);
174172 local_atom.deinit(gpa);
175173 }
176174 atom.deinit(gpa);
177175 }
178176 }
179177 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 }).?;
181 wasm_file.getAtomPtr(atom_index).deinit(gpa);
178 const atom_index = wasm.symbol_atom.get(.{ .file = .zig_object, .index = sym_index }).?;
179 wasm.getAtomPtr(atom_index).deinit(gpa);
182180 }
183 if (wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = zig_object.error_table_symbol })) |atom_index| {
184 const atom = wasm_file.getAtomPtr(atom_index);
181 if (wasm.symbol_atom.get(.{ .file = .zig_object, .index = zig_object.error_table_symbol })) |atom_index| {
182 const atom = wasm.getAtomPtr(atom_index);
185183 atom.deinit(gpa);
186184 }
187185 for (zig_object.synthetic_functions.items) |atom_index| {
188 const atom = wasm_file.getAtomPtr(atom_index);
186 const atom = wasm.getAtomPtr(atom_index);
189187 atom.deinit(gpa);
190188 }
191189 zig_object.synthetic_functions.deinit(gpa);
......@@ -193,7 +191,7 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
193191 ty.deinit(gpa);
194192 }
195193 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);
197195 atom.deinit(gpa);
198196 }
199197 zig_object.global_syms.deinit(gpa);
......@@ -240,7 +238,7 @@ pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.In
240238// the file on flush().
241239pub fn updateNav(
242240 zig_object: *ZigObject,
243 wasm_file: *Wasm,
241 wasm: *Wasm,
244242 pt: Zcu.PerThread,
245243 nav_index: InternPool.Nav.Index,
246244) !void {
......@@ -260,19 +258,19 @@ pub fn updateNav(
260258 };
261259
262260 if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
263 const gpa = wasm_file.base.comp.gpa;
264 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index);
265 const atom = wasm_file.getAtomPtr(atom_index);
261 const gpa = wasm.base.comp.gpa;
262 const atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);
263 const atom = wasm.getAtomPtr(atom_index);
266264 atom.clear();
267265
268266 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
271269 var code_writer = std.ArrayList(u8).init(gpa);
272270 defer code_writer.deinit();
273271
274272 const res = try codegen.generateSymbol(
275 &wasm_file.base,
273 &wasm.base,
276274 pt,
277275 zcu.navSrcLoc(nav_index),
278276 nav_init,
......@@ -288,13 +286,13 @@ pub fn updateNav(
288286 },
289287 };
290288
291 try zig_object.finishUpdateNav(wasm_file, pt, nav_index, code);
289 try zig_object.finishUpdateNav(wasm, pt, nav_index, code);
292290 }
293291}
294292
295293pub fn updateFunc(
296294 zig_object: *ZigObject,
297 wasm_file: *Wasm,
295 wasm: *Wasm,
298296 pt: Zcu.PerThread,
299297 func_index: InternPool.Index,
300298 air: Air,
......@@ -303,14 +301,14 @@ pub fn updateFunc(
303301 const zcu = pt.zcu;
304302 const gpa = zcu.gpa;
305303 const func = pt.zcu.funcInfo(func_index);
306 const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, func.owner_nav);
307 const atom = wasm_file.getAtomPtr(atom_index);
304 const atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, func.owner_nav);
305 const atom = wasm.getAtomPtr(atom_index);
308306 atom.clear();
309307
310308 var code_writer = std.ArrayList(u8).init(gpa);
311309 defer code_writer.deinit();
312310 const result = try codegen.generateFunction(
313 &wasm_file.base,
311 &wasm.base,
314312 pt,
315313 zcu.navSrcLoc(func.owner_nav),
316314 func_index,
......@@ -328,12 +326,12 @@ pub fn updateFunc(
328326 },
329327 };
330328
331 return zig_object.finishUpdateNav(wasm_file, pt, func.owner_nav, code);
329 return zig_object.finishUpdateNav(wasm, pt, func.owner_nav, code);
332330}
333331
334332fn finishUpdateNav(
335333 zig_object: *ZigObject,
336 wasm_file: *Wasm,
334 wasm: *Wasm,
337335 pt: Zcu.PerThread,
338336 nav_index: InternPool.Nav.Index,
339337 code: []const u8,
......@@ -345,7 +343,7 @@ fn finishUpdateNav(
345343 const nav_val = zcu.navValue(nav_index);
346344 const nav_info = zig_object.navs.get(nav_index).?;
347345 const atom_index = nav_info.atom;
348 const atom = wasm_file.getAtomPtr(atom_index);
346 const atom = wasm.getAtomPtr(atom_index);
349347 const sym = zig_object.symbol(atom.sym_index);
350348 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
351349 try atom.code.appendSlice(gpa, code);
......@@ -376,7 +374,7 @@ fn finishUpdateNav(
376374 }
377375 break :name ".bss.";
378376 };
379 if ((wasm_file.base.isObject() or wasm_file.base.comp.config.import_memory) and
377 if ((wasm.base.isObject() or wasm.base.comp.config.import_memory) and
380378 std.mem.startsWith(u8, segment_name, ".bss"))
381379 {
382380 @memset(atom.code.items, 0);
......@@ -422,7 +420,7 @@ fn createDataSegment(
422420/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
423421pub fn getOrCreateAtomForNav(
424422 zig_object: *ZigObject,
425 wasm_file: *Wasm,
423 wasm: *Wasm,
426424 pt: Zcu.PerThread,
427425 nav_index: InternPool.Nav.Index,
428426) !Atom.Index {
......@@ -431,7 +429,7 @@ pub fn getOrCreateAtomForNav(
431429 const gop = try zig_object.navs.getOrPut(gpa, nav_index);
432430 if (!gop.found_existing) {
433431 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) };
435433 const nav = ip.getNav(nav_index);
436434 const sym = zig_object.symbol(sym_index);
437435 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
......@@ -441,13 +439,13 @@ pub fn getOrCreateAtomForNav(
441439
442440pub fn lowerUav(
443441 zig_object: *ZigObject,
444 wasm_file: *Wasm,
442 wasm: *Wasm,
445443 pt: Zcu.PerThread,
446444 uav: InternPool.Index,
447445 explicit_alignment: InternPool.Alignment,
448446 src_loc: Zcu.LazySrcLoc,
449447) !codegen.GenResult {
450 const gpa = wasm_file.base.comp.gpa;
448 const gpa = wasm.base.comp.gpa;
451449 const gop = try zig_object.uavs.getOrPut(gpa, uav);
452450 if (!gop.found_existing) {
453451 var name_buf: [32]u8 = undefined;
......@@ -455,13 +453,13 @@ pub fn lowerUav(
455453 @intFromEnum(uav),
456454 }) 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)) {
459457 .ok => |atom_index| zig_object.uavs.values()[gop.index] = atom_index,
460458 .fail => |em| return .{ .fail = em },
461459 }
462460 }
463461
464 const atom = wasm_file.getAtomPtr(zig_object.uavs.values()[gop.index]);
462 const atom = wasm.getAtomPtr(zig_object.uavs.values()[gop.index]);
465463 atom.alignment = switch (atom.alignment) {
466464 .none => explicit_alignment,
467465 else => switch (explicit_alignment) {
......@@ -479,25 +477,25 @@ const LowerConstResult = union(enum) {
479477
480478fn lowerConst(
481479 zig_object: *ZigObject,
482 wasm_file: *Wasm,
480 wasm: *Wasm,
483481 pt: Zcu.PerThread,
484482 name: []const u8,
485483 val: Value,
486484 src_loc: Zcu.LazySrcLoc,
487485) !LowerConstResult {
488 const gpa = wasm_file.base.comp.gpa;
489 const zcu = wasm_file.base.comp.zcu.?;
486 const gpa = wasm.base.comp.gpa;
487 const zcu = wasm.base.comp.zcu.?;
490488
491489 const ty = val.typeOf(zcu);
492490
493491 // Create and initialize a new local symbol and atom
494492 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);
496494 var value_bytes = std.ArrayList(u8).init(gpa);
497495 defer value_bytes.deinit();
498496
499497 const code = code: {
500 const atom = wasm_file.getAtomPtr(atom_index);
498 const atom = wasm.getAtomPtr(atom_index);
501499 atom.alignment = ty.abiAlignment(zcu);
502500 const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name });
503501 errdefer gpa.free(segment_name);
......@@ -514,7 +512,7 @@ fn lowerConst(
514512 };
515513
516514 const result = try codegen.generateSymbol(
517 &wasm_file.base,
515 &wasm.base,
518516 pt,
519517 src_loc,
520518 val,
......@@ -529,7 +527,7 @@ fn lowerConst(
529527 };
530528 };
531529
532 const atom = wasm_file.getAtomPtr(atom_index);
530 const atom = wasm.getAtomPtr(atom_index);
533531 atom.size = @intCast(code.len);
534532 try atom.code.appendSlice(gpa, code);
535533 return .{ .ok = atom_index };
......@@ -538,7 +536,7 @@ fn lowerConst(
538536/// Returns the symbol index of the error name table.
539537///
540538/// 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 {
542540 if (zig_object.error_table_symbol != .null) {
543541 return zig_object.error_table_symbol;
544542 }
......@@ -546,10 +544,10 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm, pt: Zcu.Per
546544 // no error was referenced yet, so create a new symbol and atom for it
547545 // and then return said symbol's index. The final table will be populated
548546 // during `flush` when we know all possible error names.
549 const gpa = wasm_file.base.comp.gpa;
547 const gpa = wasm.base.comp.gpa;
550548 const sym_index = try zig_object.allocateSymbol(gpa);
551 const atom_index = try wasm_file.createAtom(sym_index, zig_object.index);
552 const atom = wasm_file.getAtomPtr(atom_index);
549 const atom_index = try wasm.createAtom(sym_index, .zig_object);
550 const atom = wasm.getAtomPtr(atom_index);
553551 const slice_ty = Type.slice_const_u8_sentinel_0;
554552 atom.alignment = slice_ty.abiAlignment(pt.zcu);
555553
......@@ -573,17 +571,17 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm, pt: Zcu.Per
573571///
574572/// This creates a table that consists of pointers and length to each error name.
575573/// 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 {
577575 if (zig_object.error_table_symbol == .null) return;
578 const gpa = wasm_file.base.comp.gpa;
579 const atom_index = wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = zig_object.error_table_symbol }).?;
576 const gpa = wasm.base.comp.gpa;
577 const atom_index = wasm.symbol_atom.get(.{ .file = .zig_object, .index = zig_object.error_table_symbol }).?;
580578
581579 // Rather than creating a symbol for each individual error name,
582580 // we create a symbol for the entire region of error names. We then calculate
583581 // the pointers into the list using addends which are appended to the relocation.
584582 const names_sym_index = try zig_object.allocateSymbol(gpa);
585 const names_atom_index = try wasm_file.createAtom(names_sym_index, zig_object.index);
586 const names_atom = wasm_file.getAtomPtr(names_atom_index);
583 const names_atom_index = try wasm.createAtom(names_sym_index, .zig_object);
584 const names_atom = wasm.getAtomPtr(names_atom_index);
587585 names_atom.alignment = .@"1";
588586 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names");
589587 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
600598
601599 // Addend for each relocation to the table
602600 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 };
604602 const slice_ty = Type.slice_const_u8_sentinel_0;
605 const atom = wasm_file.getAtomPtr(atom_index);
603 const atom = wasm.getAtomPtr(atom_index);
606604 {
607605 // TODO: remove this unreachable entry
608606 try atom.code.appendNTimes(gpa, 0, 4);
......@@ -646,7 +644,7 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm, tid: Zcu.Per
646644/// In all other cases, a data-symbol will be created instead.
647645pub fn addOrUpdateImport(
648646 zig_object: *ZigObject,
649 wasm_file: *Wasm,
647 wasm: *Wasm,
650648 /// Name of the import
651649 name: []const u8,
652650 /// Symbol index that is external
......@@ -658,7 +656,7 @@ pub fn addOrUpdateImport(
658656 /// is asserted instead.
659657 type_index: ?u32,
660658) !void {
661 const gpa = wasm_file.base.comp.gpa;
659 const gpa = wasm.base.comp.gpa;
662660 std.debug.assert(symbol_index != .null);
663661 // For the import name, we use the decl's name, rather than the fully qualified name
664662 // 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(
682680
683681 if (type_index) |ty_index| {
684682 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;
686684 if (!gop.found_existing) {
687685 zig_object.imported_functions_count += 1;
688686 }
......@@ -733,7 +731,7 @@ pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []c
733731/// Returns the given pointer address
734732pub fn getNavVAddr(
735733 zig_object: *ZigObject,
736 wasm_file: *Wasm,
734 wasm: *Wasm,
737735 pt: Zcu.PerThread,
738736 nav_index: InternPool.Nav.Index,
739737 reloc_info: link.File.RelocInfo,
......@@ -744,12 +742,12 @@ pub fn getNavVAddr(
744742 const nav = ip.getNav(nav_index);
745743 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);
748 const target_atom = wasm_file.getAtom(target_atom_index);
745 const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);
746 const target_atom = wasm.getAtom(target_atom_index);
749747 const target_symbol_index = @intFromEnum(target_atom.sym_index);
750748 switch (ip.indexToKey(nav.status.resolved.val)) {
751749 .@"extern" => |@"extern"| try zig_object.addOrUpdateImport(
752 wasm_file,
750 wasm,
753751 nav.name.toSlice(ip),
754752 target_atom.sym_index,
755753 @"extern".lib_name.toSlice(ip),
......@@ -759,11 +757,11 @@ pub fn getNavVAddr(
759757 }
760758
761759 std.debug.assert(reloc_info.parent.atom_index != 0);
762 const atom_index = wasm_file.symbol_atom.get(.{
763 .file = zig_object.index,
760 const atom_index = wasm.symbol_atom.get(.{
761 .file = .zig_object,
764762 .index = @enumFromInt(reloc_info.parent.atom_index),
765763 }).?;
766 const atom = wasm_file.getAtomPtr(atom_index);
764 const atom = wasm.getAtomPtr(atom_index);
767765 const is_wasm32 = target.cpu.arch == .wasm32;
768766 if (ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) {
769767 std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations
......@@ -790,22 +788,22 @@ pub fn getNavVAddr(
790788
791789pub fn getUavVAddr(
792790 zig_object: *ZigObject,
793 wasm_file: *Wasm,
791 wasm: *Wasm,
794792 uav: InternPool.Index,
795793 reloc_info: link.File.RelocInfo,
796794) !u64 {
797 const gpa = wasm_file.base.comp.gpa;
798 const target = wasm_file.base.comp.root_mod.resolved_target.result;
795 const gpa = wasm.base.comp.gpa;
796 const target = wasm.base.comp.root_mod.resolved_target.result;
799797 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(.{
803 .file = zig_object.index,
800 const parent_atom_index = wasm.symbol_atom.get(.{
801 .file = .zig_object,
804802 .index = @enumFromInt(reloc_info.parent.atom_index),
805803 }).?;
806 const parent_atom = wasm_file.getAtomPtr(parent_atom_index);
804 const parent_atom = wasm.getAtomPtr(parent_atom_index);
807805 const is_wasm32 = target.cpu.arch == .wasm32;
808 const zcu = wasm_file.base.comp.zcu.?;
806 const zcu = wasm.base.comp.zcu.?;
809807 const ty = Type.fromInterned(zcu.intern_pool.typeOf(uav));
810808 if (ty.zigTypeTag(zcu) == .@"fn") {
811809 std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations
......@@ -832,11 +830,11 @@ pub fn getUavVAddr(
832830
833831pub fn deleteExport(
834832 zig_object: *ZigObject,
835 wasm_file: *Wasm,
833 wasm: *Wasm,
836834 exported: Zcu.Exported,
837835 name: InternPool.NullTerminatedString,
838836) void {
839 const zcu = wasm_file.base.comp.zcu.?;
837 const zcu = wasm.base.comp.zcu.?;
840838 const nav_index = switch (exported) {
841839 .nav => |nav_index| nav_index,
842840 .uav => @panic("TODO: implement Wasm linker code for exporting a constant value"),
......@@ -846,15 +844,15 @@ pub fn deleteExport(
846844 const sym = zig_object.symbol(sym_index);
847845 nav_info.deleteExport(sym_index);
848846 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 }));
850 zig_object.symbols_free_list.append(wasm_file.base.comp.gpa, sym_index) catch {};
847 std.debug.assert(wasm.symbol_atom.remove(.{ .file = .zig_object, .index = sym_index }));
848 zig_object.symbols_free_list.append(wasm.base.comp.gpa, sym_index) catch {};
851849 sym.tag = .dead;
852850 }
853851}
854852
855853pub fn updateExports(
856854 zig_object: *ZigObject,
857 wasm_file: *Wasm,
855 wasm: *Wasm,
858856 pt: Zcu.PerThread,
859857 exported: Zcu.Exported,
860858 export_indices: []const u32,
......@@ -869,10 +867,10 @@ pub fn updateExports(
869867 },
870868 };
871869 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);
873871 const nav_info = zig_object.navs.getPtr(nav_index).?;
874 const atom = wasm_file.getAtom(atom_index);
875 const atom_sym = atom.symbolLoc().getSymbol(wasm_file).*;
872 const atom = wasm.getAtom(atom_index);
873 const atom_sym = wasm.symbolLocSymbol(atom.symbolLoc()).*;
876874 const gpa = zcu.gpa;
877875 log.debug("Updating exports for decl '{}'", .{nav.name.fmt(ip)});
878876
......@@ -926,17 +924,17 @@ pub fn updateExports(
926924 }
927925 log.debug(" with name '{s}' - {}", .{ export_string, sym });
928926 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);
930928 }
931929}
932930
933pub fn freeNav(zig_object: *ZigObject, wasm_file: *Wasm, nav_index: InternPool.Nav.Index) void {
934 const gpa = wasm_file.base.comp.gpa;
935 const zcu = wasm_file.base.comp.zcu.?;
931pub fn freeNav(zig_object: *ZigObject, wasm: *Wasm, nav_index: InternPool.Nav.Index) void {
932 const gpa = wasm.base.comp.gpa;
933 const zcu = wasm.base.comp.zcu.?;
936934 const ip = &zcu.intern_pool;
937935 const nav_info = zig_object.navs.getPtr(nav_index).?;
938936 const atom_index = nav_info.atom;
939 const atom = wasm_file.getAtomPtr(atom_index);
937 const atom = wasm.getAtomPtr(atom_index);
940938 zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {};
941939 for (nav_info.exports.items) |exp_sym_index| {
942940 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
947945 std.debug.assert(zig_object.navs.remove(nav_index));
948946 const sym = &zig_object.symbols.items[atom.sym_index];
949947 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);
951949 const local_symbol = &zig_object.symbols.items[local_atom.sym_index];
952950 std.debug.assert(local_symbol.tag == .data);
953951 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()));
955953 local_symbol.tag = .dead; // also for any local symbol
956954 const segment = &zig_object.segment_info.items[local_atom.sym_index];
957955 gpa.free(segment.name);
......@@ -962,7 +960,7 @@ pub fn freeNav(zig_object: *ZigObject, wasm_file: *Wasm, nav_index: InternPool.N
962960 if (ip.indexToKey(nav_val) == .@"extern") {
963961 std.debug.assert(zig_object.imports.remove(atom.sym_index));
964962 }
965 std.debug.assert(wasm_file.symbol_atom.remove(atom.symbolLoc()));
963 std.debug.assert(wasm.symbol_atom.remove(atom.symbolLoc()));
966964
967965 // if (wasm.dwarf) |*dwarf| {
968966 // dwarf.freeDecl(decl_index);
......@@ -1014,15 +1012,15 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ
10141012
10151013/// Generates an atom containing the global error set' size.
10161014/// This will only be generated if the symbol exists.
1017fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {
1018 const gpa = wasm_file.base.comp.gpa;
1015fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {
1016 const gpa = wasm.base.comp.gpa;
10191017 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;
10221020 // overwrite existing atom if it already exists (maybe the error set has increased)
10231021 // 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: {
1025 const atom = wasm_file.getAtomPtr(index);
1022 const atom_index = if (wasm.symbol_atom.get(.{ .file = .zig_object, .index = sym_index })) |index| blk: {
1023 const atom = wasm.getAtomPtr(index);
10261024 atom.prev = .null;
10271025 atom.deinit(gpa);
10281026 break :blk index;
......@@ -1036,10 +1034,10 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {
10361034 sym.tag = .data;
10371035 const segment_name = try gpa.dupe(u8, ".rodata.__zig_errors_len");
10381036 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);
10401038 };
10411039
1042 const atom = wasm_file.getAtomPtr(atom_index);
1040 const atom = wasm.getAtomPtr(atom_index);
10431041 atom.code.clearRetainingCapacity();
10441042 atom.sym_index = sym_index;
10451043 atom.size = 2;
......@@ -1073,15 +1071,15 @@ pub fn initDebugSections(zig_object: *ZigObject) !void {
10731071/// From a given index variable, creates a new debug section.
10741072/// This initializes the index, appends a new segment,
10751073/// and finally, creates a managed `Atom`.
1076pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm_file: *Wasm, index: *?u32, name: []const u8) !Atom.Index {
1077 const gpa = wasm_file.base.comp.gpa;
1074pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index {
1075 const gpa = wasm.base.comp.gpa;
10781076 const new_index: u32 = @intCast(zig_object.segments.items.len);
10791077 index.* = new_index;
10801078 try zig_object.appendDummySegment();
10811079
10821080 const sym_index = try zig_object.allocateSymbol(gpa);
1083 const atom_index = try wasm_file.createAtom(sym_index, zig_object.index);
1084 const atom = wasm_file.getAtomPtr(atom_index);
1081 const atom_index = try wasm.createAtom(sym_index, .zig_object);
1082 const atom = wasm.getAtomPtr(atom_index);
10851083 zig_object.symbols.items[sym_index] = .{
10861084 .tag = .section,
10871085 .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:
11481146/// The symbols in ZigObject are already represented by an atom as we need to store its data.
11491147/// So rather than creating a new Atom and returning its index, we use this opportunity to scan
11501148/// 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 {
1152 const gpa = wasm_file.base.comp.gpa;
1153 const loc: Wasm.SymbolLoc = .{ .file = zig_object.index, .index = index };
1154 const atom_index = wasm_file.symbol_atom.get(loc).?;
1155 const final_index = try wasm_file.getMatchingSegment(zig_object.index, index);
1156 try wasm_file.appendAtomAtIndex(final_index, atom_index);
1157 const atom = wasm_file.getAtom(atom_index);
1149pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm: *Wasm, index: Symbol.Index) !Atom.Index {
1150 const gpa = wasm.base.comp.gpa;
1151 const loc: Wasm.SymbolLoc = .{ .file = .zig_object, .index = index };
1152 const atom_index = wasm.symbol_atom.get(loc).?;
1153 const final_index = try wasm.getMatchingSegment(.zig_object, index);
1154 try wasm.appendAtomAtIndex(final_index, atom_index);
1155 const atom = wasm.getAtom(atom_index);
11581156 for (atom.relocs.items) |reloc| {
11591157 const reloc_index: Symbol.Index = @enumFromInt(reloc.index);
11601158 switch (reloc.relocation_type) {
......@@ -1163,8 +1161,8 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb
11631161 .R_WASM_TABLE_INDEX_SLEB,
11641162 .R_WASM_TABLE_INDEX_SLEB64,
11651163 => {
1166 try wasm_file.function_table.put(gpa, .{
1167 .file = zig_object.index,
1164 try wasm.function_table.put(gpa, .{
1165 .file = .zig_object,
11681166 .index = reloc_index,
11691167 }, 0);
11701168 },
......@@ -1173,8 +1171,8 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb
11731171 => {
11741172 const sym = zig_object.symbol(reloc_index);
11751173 if (sym.tag != .global) {
1176 try wasm_file.got_symbols.append(gpa, .{
1177 .file = zig_object.index,
1174 try wasm.got_symbols.append(gpa, .{
1175 .file = .zig_object,
11781176 .index = reloc_index,
11791177 });
11801178 }
......@@ -1189,13 +1187,13 @@ pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: Symb
11891187/// Returns the symbol index of the new function.
11901188pub fn createFunction(
11911189 zig_object: *ZigObject,
1192 wasm_file: *Wasm,
1190 wasm: *Wasm,
11931191 symbol_name: []const u8,
11941192 func_ty: std.wasm.Type,
11951193 function_body: *std.ArrayList(u8),
1196 relocations: *std.ArrayList(types.Relocation),
1194 relocations: *std.ArrayList(Wasm.Relocation),
11971195) !Symbol.Index {
1198 const gpa = wasm_file.base.comp.gpa;
1196 const gpa = wasm.base.comp.gpa;
11991197 const sym_index = try zig_object.allocateSymbol(gpa);
12001198 const sym = zig_object.symbol(sym_index);
12011199 sym.tag = .function;
......@@ -1203,8 +1201,8 @@ pub fn createFunction(
12031201 const type_index = try zig_object.putOrGetFuncType(gpa, func_ty);
12041202 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);
1207 const atom = wasm_file.getAtomPtr(atom_index);
1204 const atom_index = try wasm.createAtom(sym_index, .zig_object);
1205 const atom = wasm.getAtomPtr(atom_index);
12081206 atom.size = @intCast(function_body.items.len);
12091207 atom.code = function_body.moveToUnmanaged();
12101208 atom.relocs = relocations.moveToUnmanaged();
......@@ -1227,9 +1225,9 @@ fn appendFunction(zig_object: *ZigObject, gpa: std.mem.Allocator, func: std.wasm
12271225 return index;
12281226}
12291227
1230pub fn flushModule(zig_object: *ZigObject, wasm_file: *Wasm, tid: Zcu.PerThread.Id) !void {
1231 try zig_object.populateErrorNameTable(wasm_file, tid);
1232 try zig_object.setupErrorsLen(wasm_file);
1228pub fn flushModule(zig_object: *ZigObject, wasm: *Wasm, tid: Zcu.PerThread.Id) !void {
1229 try zig_object.populateErrorNameTable(wasm, tid);
1230 try zig_object.setupErrorsLen(wasm);
12331231}
12341232
12351233const build_options = @import("build_options");
......@@ -1238,12 +1236,10 @@ const codegen = @import("../../codegen.zig");
12381236const link = @import("../../link.zig");
12391237const log = std.log.scoped(.zig_object);
12401238const std = @import("std");
1241const types = @import("types.zig");
12421239
12431240const Air = @import("../../Air.zig");
1244const Atom = @import("Atom.zig");
1241const Atom = Wasm.Atom;
12451242const Dwarf = @import("../Dwarf.zig");
1246const File = @import("file.zig").File;
12471243const InternPool = @import("../../InternPool.zig");
12481244const Liveness = @import("../../Liveness.zig");
12491245const 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});