aboutsummaryrefslogtreecommitdiff
path: root/src/link/Wasm.zig
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2024-01-17 17:21:59 +0100
committerLuuk de Gram <luuk@degram.dev>2024-02-29 15:23:03 +0100
commit143e9599d64e7ac7991f360679a5611ee0d59376 (patch)
tree495335f70d3fb3783a133f128bbc6a86280b40cb /src/link/Wasm.zig
parent12505c6d3d4ccfc859b67e4b43c5b3844bebb475 (diff)
downloadzig-143e9599d64e7ac7991f360679a5611ee0d59376.tar.gz
zig-143e9599d64e7ac7991f360679a5611ee0d59376.zip
wasm: use `File` abstraction instead of object
When merging sections we now make use of the `File` abstraction so all objects such as globals, functions, imports, etc are also merged from the `ZigObject` module. This allows us to use a singular way to perform each link action without having to check the kind of the file. The logic is mostly handled in the abstract file module, unless its complexity warrants the handling within the corresponding module itself.
Diffstat (limited to 'src/link/Wasm.zig')
-rw-r--r--src/link/Wasm.zig209
1 files changed, 117 insertions, 92 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 55e08babd2..142365ecb3 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -152,7 +152,7 @@ entry: ?u32 = null,
function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},
/// All object files and their data which are linked into the final binary
-objects: std.ArrayListUnmanaged(Object) = .{},
+objects: std.ArrayListUnmanaged(File.Index) = .{},
/// All archive files that are lazy loaded.
/// e.g. when an undefined symbol references a symbol from the archive.
archives: std.ArrayListUnmanaged(Archive) = .{},
@@ -442,7 +442,7 @@ pub fn createEmpty(
// can be passed to LLD.
const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
- const file = try emit.directory.handle.createFile(sub_path, .{
+ wasm.base.file = try emit.directory.handle.createFile(sub_path, .{
.truncate = true,
.read = true,
.mode = if (fs.has_executable_bit)
@@ -453,7 +453,6 @@ pub fn createEmpty(
else
0,
});
- wasm.base.file = file;
wasm.name = sub_path;
// create stack pointer symbol
@@ -582,6 +581,15 @@ pub fn createEmpty(
return wasm;
}
+pub fn file(wasm: *Wasm, index: File.Index) ?File {
+ const tag = wasm.files.items(.tags)[index];
+ return switch (tag) {
+ .null => null,
+ .zig_object => .{ .zig_object = &wasm.files.items(.data)[index].zig_object },
+ .object => .{ .object = &wasm.files.items(.data)[index].object },
+ };
+}
+
pub fn zigObjectPtr(wasm: *Wasm) ?*ZigObject {
if (wasm.zig_object_index == .null) return null;
return &wasm.files.items(.data)[@intFromEnum(wasm.zig_object_index)].zig_object;
@@ -650,16 +658,18 @@ fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void {
/// file and parsed successfully. Returns false when file is not an object file.
/// May return an error instead when parsing failed.
fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
- const file = try fs.cwd().openFile(path, .{});
- errdefer file.close();
+ const obj_file = try fs.cwd().openFile(path, .{});
+ errdefer obj_file.close();
const gpa = wasm.base.comp.gpa;
- var object = Object.create(gpa, file, path, null) catch |err| switch (err) {
+ var object = Object.create(gpa, obj_file, path, null) catch |err| switch (err) {
error.InvalidMagicByte, error.NotObjectFile => return false,
else => |e| return e,
};
errdefer object.deinit(gpa);
- try wasm.objects.append(gpa, object);
+ object.index = @enumFromInt(wasm.files.len);
+ try wasm.files.append(gpa, .{ .object = object });
+ try wasm.objects.append(gpa, object.index);
return true;
}
@@ -693,11 +703,11 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
const gpa = wasm.base.comp.gpa;
- const file = try fs.cwd().openFile(path, .{});
- errdefer file.close();
+ const archive_file = try fs.cwd().openFile(path, .{});
+ errdefer archive_file.close();
var archive: Archive = .{
- .file = file,
+ .file = archive_file,
.name = path,
};
archive.parse(gpa) catch |err| switch (err) {
@@ -727,8 +737,10 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
}
for (offsets.keys()) |file_offset| {
- const object = try wasm.objects.addOne(gpa);
- object.* = try archive.parseObject(gpa, file_offset);
+ var object = try archive.parseObject(gpa, file_offset);
+ object.index = @enumFromInt(wasm.files.len);
+ try wasm.files.append(gpa, .{ .object = object });
+ try wasm.objects.append(gpa, object.index);
}
return true;
@@ -784,8 +796,8 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
const existing_loc = maybe_existing.value_ptr.*;
const existing_sym: *Symbol = existing_loc.getSymbol(wasm);
- const existing_file_path = if (existing_loc.file) |file| blk: {
- break :blk wasm.objects.items[file].name;
+ const existing_file_path = if (existing_loc.file) |file_index| blk: {
+ break :blk wasm.objects.items[file_index].name;
} else wasm.name;
if (!existing_sym.isUndefined()) outer: {
@@ -911,10 +923,11 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
// Symbol is found in unparsed object file within current archive.
// Parse object and and resolve symbols again before we check remaining
// undefined symbols.
- const object_file_index: u16 = @intCast(wasm.objects.items.len);
- const object = try archive.parseObject(gpa, offset.items[0]);
- try wasm.objects.append(gpa, object);
- try wasm.resolveSymbolsInObject(object_file_index);
+ var object = try archive.parseObject(gpa, offset.items[0]);
+ object.index = @enumFromInt(wasm.files.len);
+ try wasm.files.append(gpa, .{ .object = object });
+ try wasm.objects.append(gpa, object.index);
+ try wasm.resolveSymbolsInObject(object.index);
// continue loop for any remaining undefined symbols that still exist
// after resolving last object file
@@ -1176,9 +1189,10 @@ fn validateFeatures(
// extract all the used, disallowed and required features from each
// linked object file so we can test them.
- for (wasm.objects.items, 0..) |object, object_index| {
+ for (wasm.objects.items) |file_index| {
+ const object: Object = wasm.files.items(.data)[file_index].object;
for (object.features) |feature| {
- const value = @as(u16, @intCast(object_index)) << 1 | @as(u1, 1);
+ const value = @as(u16, @intFromEnum(file_index)) << 1 | @as(u1, 1);
switch (feature.prefix) {
.used => {
used[@intFromEnum(feature.tag)] = value;
@@ -1210,7 +1224,7 @@ fn validateFeatures(
emit_features_count.* += @intFromBool(is_enabled);
} else if (is_enabled and !allowed[used_index]) {
log.err("feature '{}' not allowed, but used by linked object", .{@as(types.Feature.Tag, @enumFromInt(used_index))});
- log.err(" defined in '{s}'", .{wasm.objects.items[used_set >> 1].name});
+ log.err(" defined in '{s}'", .{wasm.files.items(.data)[used_set >> 1].object.path});
valid_feature_set = false;
}
}
@@ -1224,7 +1238,7 @@ fn validateFeatures(
if (@as(u1, @truncate(disallowed_feature)) != 0) {
log.err(
"shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled",
- .{wasm.objects.items[disallowed_feature >> 1].name},
+ .{wasm.files.items(.data)[disallowed_feature >> 1].object.path},
);
valid_feature_set = false;
}
@@ -1244,16 +1258,17 @@ fn validateFeatures(
}
}
// For each linked object, validate the required and disallowed features
- for (wasm.objects.items) |object| {
+ for (wasm.objects.items) |file_index| {
var object_used_features = [_]bool{false} ** known_features_count;
+ const object = wasm.files.items(.data)[file_index].object;
for (object.features) |feature| {
if (feature.prefix == .disallowed) continue; // already defined in 'disallowed' set.
// from here a feature is always used
const disallowed_feature = disallowed[@intFromEnum(feature.tag)];
if (@as(u1, @truncate(disallowed_feature)) != 0) {
log.err("feature '{}' is disallowed, but used by linked object", .{feature.tag});
- log.err(" disallowed by '{s}'", .{wasm.objects.items[disallowed_feature >> 1].name});
- log.err(" used in '{s}'", .{object.name});
+ log.err(" disallowed by '{s}'", .{wasm.files.items(.data)[disallowed_feature >> 1].object.path});
+ log.err(" used in '{s}'", .{object.path});
valid_feature_set = false;
}
@@ -1265,8 +1280,8 @@ fn validateFeatures(
const is_required = @as(u1, @truncate(required_feature)) != 0;
if (is_required and !object_used_features[feature_index]) {
log.err("feature '{}' is required but not used in linked object", .{@as(types.Feature.Tag, @enumFromInt(feature_index))});
- log.err(" required by '{s}'", .{wasm.objects.items[required_feature >> 1].name});
- log.err(" missing in '{s}'", .{object.name});
+ log.err(" required by '{s}'", .{wasm.files.items(.data)[required_feature >> 1].object.path});
+ log.err(" missing in '{s}'", .{object.path});
valid_feature_set = false;
}
}
@@ -1346,9 +1361,10 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
const symbol = undef.getSymbol(wasm);
if (symbol.tag == .data) {
found_undefined_symbols = true;
- const file_name = if (undef.file) |file_index| name: {
- break :name wasm.objects.items[file_index].name;
- } else wasm.name;
+ const file_name = if (undef.file) |file_index|
+ wasm.file(file_index).?.path()
+ else
+ wasm.name;
const symbol_name = undef.getName(wasm);
log.err("could not resolve undefined symbol '{s}'", .{symbol_name});
log.err(" defined in '{s}'", .{file_name});
@@ -1369,8 +1385,11 @@ pub fn deinit(wasm: *Wasm) void {
for (wasm.segment_info.values()) |segment_info| {
gpa.free(segment_info.name);
}
- for (wasm.objects.items) |*object| {
- object.deinit(gpa);
+ if (wasm.zigObjectPtr()) |zig_obj| {
+ zig_obj.deinit(gpa);
+ }
+ for (wasm.objects.items) |obj_index| {
+ wasm.file(obj_index).?.object.deinit(gpa);
}
for (wasm.archives.items) |*archive| {
@@ -1441,12 +1460,11 @@ fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType {
assert(symbol.tag == .global);
const is_undefined = symbol.isUndefined();
if (loc.file) |file_index| {
- const obj: Object = wasm.objects.items[file_index];
+ const obj_file = wasm.file(@enumFromInt(file_index)).?;
if (is_undefined) {
- return obj.findImport(.global, symbol.index).kind.global;
+ return obj_file.import(loc.index).kind.global;
}
- const import_global_count = obj.importedCountByKind(.global);
- return obj.globals[symbol.index - import_global_count].global_type;
+ return obj_file.globals()[symbol.index - obj_file.importedGlobals()].global_type;
}
if (is_undefined) {
return wasm.imports.get(loc).?.kind.global;
@@ -1461,14 +1479,13 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
assert(symbol.tag == .function);
const is_undefined = symbol.isUndefined();
if (loc.file) |file_index| {
- const obj: Object = wasm.objects.items[file_index];
+ const obj_file = wasm.file(@enumFromInt(file_index)).?;
if (is_undefined) {
- const ty_index = obj.findImport(.function, symbol.index).kind.function;
- return obj.func_types[ty_index];
+ const ty_index = obj_file.import(loc.index).kind.function;
+ return obj_file.funcTypes()[ty_index];
}
- const import_function_count = obj.importedCountByKind(.function);
- const type_index = obj.functions[symbol.index - import_function_count].type_index;
- return obj.func_types[type_index];
+ const type_index = obj_file.functions()[symbol.index - obj_file.importedFunctions()].type_index;
+ return obj_file.funcTypes()[type_index];
}
if (is_undefined) {
const ty_index = wasm.imports.get(loc).?.kind.function;
@@ -1606,10 +1623,10 @@ fn allocateAtoms(wasm: *Wasm) !void {
// Ensure we get the original symbol, so we verify the correct symbol on whether
// it is dead or not and ensure an atom is removed when dead.
// This is required as we may have parsed aliases into atoms.
- const sym = if (symbol_loc.file) |object_index| sym: {
- const object = wasm.objects.items[object_index];
- break :sym object.symtable[symbol_loc.index];
- } else wasm.synthetic_symbols.items[symbol_loc.index];
+ const sym = if (symbol_loc.file) |object_index|
+ wasm.file(object_index).?.symbol(symbol_loc.index).*
+ else
+ wasm.synthetic_symbols.items[symbol_loc.index];
// Dead symbols must be unlinked from the linked-list to prevent them
// from being emit into the binary.
@@ -1655,9 +1672,10 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
const atom = wasm.getAtom(atom_index);
const merge_segment = wasm.base.comp.config.output_mode != .Obj;
- const segment_info = if (atom.file) |object_index| blk: {
- break :blk wasm.objects.items[object_index].segment_info;
- } else wasm.segment_info.values();
+ const segment_info = if (atom.file) |object_index|
+ wasm.file(object_index).?.segmentInfo()
+ else
+ wasm.segment_info.values();
const segment_name = segment_info[symbol.index].outputName(merge_segment);
const segment_index = wasm.data_segments.get(segment_name).?;
const segment = wasm.segments.items[segment_index];
@@ -1713,7 +1731,8 @@ fn sortDataSegments(wasm: *Wasm) !void {
/// contain any parameters.
fn setupInitFunctions(wasm: *Wasm) !void {
const gpa = wasm.base.comp.gpa;
- for (wasm.objects.items, 0..) |object, file_index| {
+ for (wasm.objects.items) |file_index| {
+ const object = wasm.files.items(.data)[file_index].object;
try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len);
for (object.init_funcs) |init_func| {
const symbol = object.symtable[init_func.symbol_index];
@@ -1961,7 +1980,7 @@ fn setupImports(wasm: *Wasm) !void {
for (wasm.resolved_symbols.keys()) |symbol_loc| {
const file_index = symbol_loc.file orelse {
- // imports generated by Zig code are already in the `import` section
+ // Synthetic symbols will already exist in the `import` section
continue;
};
@@ -1974,14 +1993,14 @@ fn setupImports(wasm: *Wasm) !void {
}
log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)});
- const object = wasm.objects.items[file_index];
- const import = object.findImport(symbol.tag.externalType(), symbol.index);
+ const obj_file = wasm.file(file_index).?;
+ const import = obj_file.import(symbol_loc.index);
// We copy the import to a new import to ensure the names contain references
// to the internal string table, rather than of the object file.
const new_imp: types.Import = .{
- .module_name = try wasm.string_table.put(gpa, object.string_table.get(import.module_name)),
- .name = try wasm.string_table.put(gpa, object.string_table.get(import.name)),
+ .module_name = try wasm.string_table.put(gpa, obj_file.string(import.module_name)),
+ .name = try wasm.string_table.put(gpa, obj_file.string(import.name)),
.kind = import.kind,
};
// TODO: De-duplicate imports when they contain the same names and type
@@ -2032,28 +2051,23 @@ fn mergeSections(wasm: *Wasm) !void {
defer removed_duplicates.deinit();
for (wasm.resolved_symbols.keys()) |sym_loc| {
- if (sym_loc.file == null) {
+ const file_index = sym_loc.file orelse {
// Zig code-generated symbols are already within the sections and do not
// require to be merged
continue;
- }
+ };
- const object = &wasm.objects.items[sym_loc.file.?];
- const symbol = &object.symtable[sym_loc.index];
+ const obj_file = wasm.file(@enumFromInt(file_index)).?;
+ const symbol = obj_file.symbol[sym_loc.index];
- if (symbol.isDead() or
- symbol.isUndefined() or
- (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table))
- {
+ if (symbol.isDead() or symbol.isUndefined()) {
// Skip undefined symbols as they go in the `import` section
- // Also skip symbols that do not need to have a section merged.
continue;
}
- const offset = object.importedCountByKind(symbol.tag.externalType());
- const index = symbol.index - offset;
switch (symbol.tag) {
.function => {
+ const index = symbol.index - obj_file.importedFunctions();
const gop = try wasm.functions.getOrPut(
gpa,
.{ .file = sym_loc.file, .index = symbol.index },
@@ -2071,20 +2085,24 @@ fn mergeSections(wasm: *Wasm) !void {
try removed_duplicates.append(sym_loc);
continue;
}
- gop.value_ptr.* = .{ .func = object.functions[index], .sym_index = sym_loc.index };
+ gop.value_ptr.* = .{ .func = obj_file.functions()[index], .sym_index = sym_loc.index };
symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count;
},
.global => {
- const original_global = object.globals[index];
+ const index = symbol.index - obj_file.importedFunctions();
+ const original_global = obj_file.globals()[index];
symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;
try wasm.wasm_globals.append(gpa, original_global);
},
.table => {
- const original_table = object.tables[index];
+ const index = symbol.index - obj_file.importedFunctions();
+ // assert it's a regular relocatable object file as `ZigObject` will never
+ // contain a table.
+ const original_table = obj_file.object.tables[index];
symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;
try wasm.tables.append(gpa, original_table);
},
- else => unreachable,
+ else => continue,
}
}
@@ -2111,12 +2129,13 @@ fn mergeTypes(wasm: *Wasm) !void {
defer dirty.deinit();
for (wasm.resolved_symbols.keys()) |sym_loc| {
- if (sym_loc.file == null) {
+ const file_index = sym_loc.file orelse {
// zig code-generated symbols are already present in final type section
continue;
- }
- const object = wasm.objects.items[sym_loc.file.?];
- const symbol = object.symtable[sym_loc.index];
+ };
+
+ const obj_file = wasm.file(@enumFromInt(file_index)).?;
+ const symbol = obj_file.symbol(sym_loc.index);
if (symbol.tag != .function or symbol.isDead()) {
// Only functions have types. Only retrieve the type of referenced functions.
continue;
@@ -2125,12 +2144,12 @@ fn mergeTypes(wasm: *Wasm) !void {
if (symbol.isUndefined()) {
log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(wasm)});
const import: *types.Import = wasm.imports.getPtr(sym_loc) orelse continue;
- const original_type = object.func_types[import.kind.function];
+ const original_type = obj_file.funcTypes()[import.kind.function];
import.kind.function = try wasm.putOrGetFuncType(original_type);
} else if (!dirty.contains(symbol.index)) {
log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)});
const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func;
- func.type_index = try wasm.putOrGetFuncType(object.func_types[func.type_index]);
+ func.type_index = try wasm.putOrGetFuncType(obj_file.funcTypes()[func.type_index]);
dirty.putAssumeCapacityNoClobber(symbol.index, {});
}
}
@@ -2240,11 +2259,18 @@ fn setupMemory(wasm: *Wasm) !void {
const is_obj = comp.config.output_mode == .Obj;
+ const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: {
+ const sym = loc.getSymbol(wasm);
+ break :index sym.index - wasm.imported_globals_count;
+ } else null;
+
if (place_stack_first and !is_obj) {
memory_ptr = stack_alignment.forward(memory_ptr);
memory_ptr += wasm.base.stack_size;
// We always put the stack pointer global at index 0
- wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
+ if (stack_ptr) |index| {
+ wasm.wasm_globals.items[index].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
+ }
}
var offset: u32 = @as(u32, @intCast(memory_ptr));
@@ -2290,7 +2316,9 @@ fn setupMemory(wasm: *Wasm) !void {
if (!place_stack_first and !is_obj) {
memory_ptr = stack_alignment.forward(memory_ptr);
memory_ptr += wasm.base.stack_size;
- wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
+ if (stack_ptr) |index| {
+ wasm.wasm_globals.items[index].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
+ }
}
// One of the linked object files has a reference to the __heap_base symbol.
@@ -2355,17 +2383,17 @@ fn setupMemory(wasm: *Wasm) !void {
/// From a given object's index and the index of the segment, returns the corresponding
/// index of the segment within the final data section. When the segment does not yet
/// exist, a new one will be initialized and appended. The new index will be returned in that case.
-pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 {
+pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: u32) !u32 {
const comp = wasm.base.comp;
const gpa = comp.gpa;
- const object: Object = wasm.objects.items[object_index];
- const symbol = object.symtable[symbol_index];
+ const obj_file = wasm.file(file_index).?;
+ const symbol = obj_file.symbols()[symbol_index];
const index: u32 = @intCast(wasm.segments.items.len);
const shared_memory = comp.config.shared_memory;
switch (symbol.tag) {
.data => {
- const segment_info = object.segment_info[symbol.index];
+ const segment_info = obj_file.segmentInfo()[symbol.index];
const merge_segment = comp.config.output_mode != .Obj;
const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment));
if (!result.found_existing) {
@@ -2394,7 +2422,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u3
break :blk index;
},
.section => {
- const section_name = object.string_table.get(symbol.name);
+ const section_name = file.symbolName(symbol.index);
if (mem.eql(u8, section_name, ".debug_info")) {
return wasm.debug_info_index orelse blk: {
wasm.debug_info_index = index;
@@ -4291,12 +4319,10 @@ fn markReferences(wasm: *Wasm) !void {
// Debug sections may require to be parsed and marked when it contains
// relocations to alive symbols.
if (sym.tag == .section and comp.config.debug_format != .strip) {
- const file = sym_loc.file orelse continue; // Incremental debug info is done independently
- const object = &wasm.objects.items[file];
- const atom_index = try Object.parseSymbolIntoAtom(object, file, sym_loc.index, wasm);
- const atom = wasm.getAtom(atom_index);
- const atom_sym = atom.symbolLoc().getSymbol(wasm);
- atom_sym.mark();
+ const file_index = sym_loc.file orelse continue; // Incremental debug info is done independently
+ const obj_file = wasm.file(@enumFromInt(file_index)).?;
+ _ = try obj_file.parseSymbolIntoAtom(wasm, sym_loc.index);
+ sym.mark();
}
}
}
@@ -4319,9 +4345,8 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
}
const atom_index = if (loc.file) |file_index| idx: {
- const object = &wasm.objects.items[file_index];
- const atom_index = try object.parseSymbolIntoAtom(file_index, loc.index, wasm);
- break :idx atom_index;
+ const obj_file = wasm.file(@enumFromInt(file_index)).?;
+ break :idx try obj_file.parseSymbolIntoAtom(wasm, loc.index);
} else wasm.symbol_atom.get(loc) orelse return;
const atom = wasm.getAtom(atom_index);