authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-01-17 17:21:59+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-02-29 15:23:03+01:00
log143e9599d64e7ac7991f360679a5611ee0d59376
tree495335f70d3fb3783a133f128bbc6a86280b40cb
parent12505c6d3d4ccfc859b67e4b43c5b3844bebb475
signaturelock-open Commit is signed but in an unrecognized format.

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.

3 files changed, 192 insertions(+), 128 deletions(-)

src/link/Wasm.zig+117-92
...@@ -152,7 +152,7 @@ entry: ?u32 = null,...@@ -152,7 +152,7 @@ entry: ?u32 = null,
152function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},152function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},
153153
154/// All object files and their data which are linked into the final binary154/// All object files and their data which are linked into the final binary
155objects: std.ArrayListUnmanaged(Object) = .{},155objects: std.ArrayListUnmanaged(File.Index) = .{},
156/// All archive files that are lazy loaded.156/// All archive files that are lazy loaded.
157/// e.g. when an undefined symbol references a symbol from the archive.157/// e.g. when an undefined symbol references a symbol from the archive.
158archives: std.ArrayListUnmanaged(Archive) = .{},158archives: std.ArrayListUnmanaged(Archive) = .{},
...@@ -442,7 +442,7 @@ pub fn createEmpty(...@@ -442,7 +442,7 @@ pub fn createEmpty(
442 // can be passed to LLD.442 // can be passed to LLD.
443 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;443 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
444444
445 const file = try emit.directory.handle.createFile(sub_path, .{445 wasm.base.file = try emit.directory.handle.createFile(sub_path, .{
446 .truncate = true,446 .truncate = true,
447 .read = true,447 .read = true,
448 .mode = if (fs.has_executable_bit)448 .mode = if (fs.has_executable_bit)
...@@ -453,7 +453,6 @@ pub fn createEmpty(...@@ -453,7 +453,6 @@ pub fn createEmpty(
453 else453 else
454 0,454 0,
455 });455 });
456 wasm.base.file = file;
457 wasm.name = sub_path;456 wasm.name = sub_path;
458457
459 // create stack pointer symbol458 // create stack pointer symbol
...@@ -582,6 +581,15 @@ pub fn createEmpty(...@@ -582,6 +581,15 @@ pub fn createEmpty(
582 return wasm;581 return wasm;
583}582}
584583
584pub fn file(wasm: *Wasm, index: File.Index) ?File {
585 const tag = wasm.files.items(.tags)[index];
586 return switch (tag) {
587 .null => null,
588 .zig_object => .{ .zig_object = &wasm.files.items(.data)[index].zig_object },
589 .object => .{ .object = &wasm.files.items(.data)[index].object },
590 };
591}
592
585pub fn zigObjectPtr(wasm: *Wasm) ?*ZigObject {593pub fn zigObjectPtr(wasm: *Wasm) ?*ZigObject {
586 if (wasm.zig_object_index == .null) return null;594 if (wasm.zig_object_index == .null) return null;
587 return &wasm.files.items(.data)[@intFromEnum(wasm.zig_object_index)].zig_object;595 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 {...@@ -650,16 +658,18 @@ fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void {
650/// file and parsed successfully. Returns false when file is not an object file.658/// file and parsed successfully. Returns false when file is not an object file.
651/// May return an error instead when parsing failed.659/// May return an error instead when parsing failed.
652fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {660fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
653 const file = try fs.cwd().openFile(path, .{});661 const obj_file = try fs.cwd().openFile(path, .{});
654 errdefer file.close();662 errdefer obj_file.close();
655663
656 const gpa = wasm.base.comp.gpa;664 const gpa = wasm.base.comp.gpa;
657 var object = Object.create(gpa, file, path, null) catch |err| switch (err) {665 var object = Object.create(gpa, obj_file, path, null) catch |err| switch (err) {
658 error.InvalidMagicByte, error.NotObjectFile => return false,666 error.InvalidMagicByte, error.NotObjectFile => return false,
659 else => |e| return e,667 else => |e| return e,
660 };668 };
661 errdefer object.deinit(gpa);669 errdefer object.deinit(gpa);
662 try wasm.objects.append(gpa, object);670 object.index = @enumFromInt(wasm.files.len);
671 try wasm.files.append(gpa, .{ .object = object });
672 try wasm.objects.append(gpa, object.index);
663 return true;673 return true;
664}674}
665675
...@@ -693,11 +703,11 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {...@@ -693,11 +703,11 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
693fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {703fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
694 const gpa = wasm.base.comp.gpa;704 const gpa = wasm.base.comp.gpa;
695705
696 const file = try fs.cwd().openFile(path, .{});706 const archive_file = try fs.cwd().openFile(path, .{});
697 errdefer file.close();707 errdefer archive_file.close();
698708
699 var archive: Archive = .{709 var archive: Archive = .{
700 .file = file,710 .file = archive_file,
701 .name = path,711 .name = path,
702 };712 };
703 archive.parse(gpa) catch |err| switch (err) {713 archive.parse(gpa) catch |err| switch (err) {
...@@ -727,8 +737,10 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -727,8 +737,10 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
727 }737 }
728738
729 for (offsets.keys()) |file_offset| {739 for (offsets.keys()) |file_offset| {
730 const object = try wasm.objects.addOne(gpa);740 var object = try archive.parseObject(gpa, file_offset);
731 object.* = try archive.parseObject(gpa, file_offset);741 object.index = @enumFromInt(wasm.files.len);
742 try wasm.files.append(gpa, .{ .object = object });
743 try wasm.objects.append(gpa, object.index);
732 }744 }
733745
734 return true;746 return true;
...@@ -784,8 +796,8 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {...@@ -784,8 +796,8 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
784 const existing_loc = maybe_existing.value_ptr.*;796 const existing_loc = maybe_existing.value_ptr.*;
785 const existing_sym: *Symbol = existing_loc.getSymbol(wasm);797 const existing_sym: *Symbol = existing_loc.getSymbol(wasm);
786798
787 const existing_file_path = if (existing_loc.file) |file| blk: {799 const existing_file_path = if (existing_loc.file) |file_index| blk: {
788 break :blk wasm.objects.items[file].name;800 break :blk wasm.objects.items[file_index].name;
789 } else wasm.name;801 } else wasm.name;
790802
791 if (!existing_sym.isUndefined()) outer: {803 if (!existing_sym.isUndefined()) outer: {
...@@ -911,10 +923,11 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {...@@ -911,10 +923,11 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
911 // Symbol is found in unparsed object file within current archive.923 // Symbol is found in unparsed object file within current archive.
912 // Parse object and and resolve symbols again before we check remaining924 // Parse object and and resolve symbols again before we check remaining
913 // undefined symbols.925 // undefined symbols.
914 const object_file_index: u16 = @intCast(wasm.objects.items.len);926 var object = try archive.parseObject(gpa, offset.items[0]);
915 const object = try archive.parseObject(gpa, offset.items[0]);927 object.index = @enumFromInt(wasm.files.len);
916 try wasm.objects.append(gpa, object);928 try wasm.files.append(gpa, .{ .object = object });
917 try wasm.resolveSymbolsInObject(object_file_index);929 try wasm.objects.append(gpa, object.index);
930 try wasm.resolveSymbolsInObject(object.index);
918931
919 // continue loop for any remaining undefined symbols that still exist932 // continue loop for any remaining undefined symbols that still exist
920 // after resolving last object file933 // after resolving last object file
...@@ -1176,9 +1189,10 @@ fn validateFeatures(...@@ -1176,9 +1189,10 @@ fn validateFeatures(
11761189
1177 // extract all the used, disallowed and required features from each1190 // extract all the used, disallowed and required features from each
1178 // linked object file so we can test them.1191 // linked object file so we can test them.
1179 for (wasm.objects.items, 0..) |object, object_index| {1192 for (wasm.objects.items) |file_index| {
1193 const object: Object = wasm.files.items(.data)[file_index].object;
1180 for (object.features) |feature| {1194 for (object.features) |feature| {
1181 const value = @as(u16, @intCast(object_index)) << 1 | @as(u1, 1);1195 const value = @as(u16, @intFromEnum(file_index)) << 1 | @as(u1, 1);
1182 switch (feature.prefix) {1196 switch (feature.prefix) {
1183 .used => {1197 .used => {
1184 used[@intFromEnum(feature.tag)] = value;1198 used[@intFromEnum(feature.tag)] = value;
...@@ -1210,7 +1224,7 @@ fn validateFeatures(...@@ -1210,7 +1224,7 @@ fn validateFeatures(
1210 emit_features_count.* += @intFromBool(is_enabled);1224 emit_features_count.* += @intFromBool(is_enabled);
1211 } else if (is_enabled and !allowed[used_index]) {1225 } else if (is_enabled and !allowed[used_index]) {
1212 log.err("feature '{}' not allowed, but used by linked object", .{@as(types.Feature.Tag, @enumFromInt(used_index))});1226 log.err("feature '{}' not allowed, but used by linked object", .{@as(types.Feature.Tag, @enumFromInt(used_index))});
1213 log.err(" defined in '{s}'", .{wasm.objects.items[used_set >> 1].name});1227 log.err(" defined in '{s}'", .{wasm.files.items(.data)[used_set >> 1].object.path});
1214 valid_feature_set = false;1228 valid_feature_set = false;
1215 }1229 }
1216 }1230 }
...@@ -1224,7 +1238,7 @@ fn validateFeatures(...@@ -1224,7 +1238,7 @@ fn validateFeatures(
1224 if (@as(u1, @truncate(disallowed_feature)) != 0) {1238 if (@as(u1, @truncate(disallowed_feature)) != 0) {
1225 log.err(1239 log.err(
1226 "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled",1240 "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled",
1227 .{wasm.objects.items[disallowed_feature >> 1].name},1241 .{wasm.files.items(.data)[disallowed_feature >> 1].object.path},
1228 );1242 );
1229 valid_feature_set = false;1243 valid_feature_set = false;
1230 }1244 }
...@@ -1244,16 +1258,17 @@ fn validateFeatures(...@@ -1244,16 +1258,17 @@ fn validateFeatures(
1244 }1258 }
1245 }1259 }
1246 // For each linked object, validate the required and disallowed features1260 // For each linked object, validate the required and disallowed features
1247 for (wasm.objects.items) |object| {1261 for (wasm.objects.items) |file_index| {
1248 var object_used_features = [_]bool{false} ** known_features_count;1262 var object_used_features = [_]bool{false} ** known_features_count;
1263 const object = wasm.files.items(.data)[file_index].object;
1249 for (object.features) |feature| {1264 for (object.features) |feature| {
1250 if (feature.prefix == .disallowed) continue; // already defined in 'disallowed' set.1265 if (feature.prefix == .disallowed) continue; // already defined in 'disallowed' set.
1251 // from here a feature is always used1266 // from here a feature is always used
1252 const disallowed_feature = disallowed[@intFromEnum(feature.tag)];1267 const disallowed_feature = disallowed[@intFromEnum(feature.tag)];
1253 if (@as(u1, @truncate(disallowed_feature)) != 0) {1268 if (@as(u1, @truncate(disallowed_feature)) != 0) {
1254 log.err("feature '{}' is disallowed, but used by linked object", .{feature.tag});1269 log.err("feature '{}' is disallowed, but used by linked object", .{feature.tag});
1255 log.err(" disallowed by '{s}'", .{wasm.objects.items[disallowed_feature >> 1].name});1270 log.err(" disallowed by '{s}'", .{wasm.files.items(.data)[disallowed_feature >> 1].object.path});
1256 log.err(" used in '{s}'", .{object.name});1271 log.err(" used in '{s}'", .{object.path});
1257 valid_feature_set = false;1272 valid_feature_set = false;
1258 }1273 }
12591274
...@@ -1265,8 +1280,8 @@ fn validateFeatures(...@@ -1265,8 +1280,8 @@ fn validateFeatures(
1265 const is_required = @as(u1, @truncate(required_feature)) != 0;1280 const is_required = @as(u1, @truncate(required_feature)) != 0;
1266 if (is_required and !object_used_features[feature_index]) {1281 if (is_required and !object_used_features[feature_index]) {
1267 log.err("feature '{}' is required but not used in linked object", .{@as(types.Feature.Tag, @enumFromInt(feature_index))});1282 log.err("feature '{}' is required but not used in linked object", .{@as(types.Feature.Tag, @enumFromInt(feature_index))});
1268 log.err(" required by '{s}'", .{wasm.objects.items[required_feature >> 1].name});1283 log.err(" required by '{s}'", .{wasm.files.items(.data)[required_feature >> 1].object.path});
1269 log.err(" missing in '{s}'", .{object.name});1284 log.err(" missing in '{s}'", .{object.path});
1270 valid_feature_set = false;1285 valid_feature_set = false;
1271 }1286 }
1272 }1287 }
...@@ -1346,9 +1361,10 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {...@@ -1346,9 +1361,10 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
1346 const symbol = undef.getSymbol(wasm);1361 const symbol = undef.getSymbol(wasm);
1347 if (symbol.tag == .data) {1362 if (symbol.tag == .data) {
1348 found_undefined_symbols = true;1363 found_undefined_symbols = true;
1349 const file_name = if (undef.file) |file_index| name: {1364 const file_name = if (undef.file) |file_index|
1350 break :name wasm.objects.items[file_index].name;1365 wasm.file(file_index).?.path()
1351 } else wasm.name;1366 else
1367 wasm.name;
1352 const symbol_name = undef.getName(wasm);1368 const symbol_name = undef.getName(wasm);
1353 log.err("could not resolve undefined symbol '{s}'", .{symbol_name});1369 log.err("could not resolve undefined symbol '{s}'", .{symbol_name});
1354 log.err(" defined in '{s}'", .{file_name});1370 log.err(" defined in '{s}'", .{file_name});
...@@ -1369,8 +1385,11 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1369,8 +1385,11 @@ pub fn deinit(wasm: *Wasm) void {
1369 for (wasm.segment_info.values()) |segment_info| {1385 for (wasm.segment_info.values()) |segment_info| {
1370 gpa.free(segment_info.name);1386 gpa.free(segment_info.name);
1371 }1387 }
1372 for (wasm.objects.items) |*object| {1388 if (wasm.zigObjectPtr()) |zig_obj| {
1373 object.deinit(gpa);1389 zig_obj.deinit(gpa);
1390 }
1391 for (wasm.objects.items) |obj_index| {
1392 wasm.file(obj_index).?.object.deinit(gpa);
1374 }1393 }
13751394
1376 for (wasm.archives.items) |*archive| {1395 for (wasm.archives.items) |*archive| {
...@@ -1441,12 +1460,11 @@ fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType {...@@ -1441,12 +1460,11 @@ fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType {
1441 assert(symbol.tag == .global);1460 assert(symbol.tag == .global);
1442 const is_undefined = symbol.isUndefined();1461 const is_undefined = symbol.isUndefined();
1443 if (loc.file) |file_index| {1462 if (loc.file) |file_index| {
1444 const obj: Object = wasm.objects.items[file_index];1463 const obj_file = wasm.file(@enumFromInt(file_index)).?;
1445 if (is_undefined) {1464 if (is_undefined) {
1446 return obj.findImport(.global, symbol.index).kind.global;1465 return obj_file.import(loc.index).kind.global;
1447 }1466 }
1448 const import_global_count = obj.importedCountByKind(.global);1467 return obj_file.globals()[symbol.index - obj_file.importedGlobals()].global_type;
1449 return obj.globals[symbol.index - import_global_count].global_type;
1450 }1468 }
1451 if (is_undefined) {1469 if (is_undefined) {
1452 return wasm.imports.get(loc).?.kind.global;1470 return wasm.imports.get(loc).?.kind.global;
...@@ -1461,14 +1479,13 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {...@@ -1461,14 +1479,13 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
1461 assert(symbol.tag == .function);1479 assert(symbol.tag == .function);
1462 const is_undefined = symbol.isUndefined();1480 const is_undefined = symbol.isUndefined();
1463 if (loc.file) |file_index| {1481 if (loc.file) |file_index| {
1464 const obj: Object = wasm.objects.items[file_index];1482 const obj_file = wasm.file(@enumFromInt(file_index)).?;
1465 if (is_undefined) {1483 if (is_undefined) {
1466 const ty_index = obj.findImport(.function, symbol.index).kind.function;1484 const ty_index = obj_file.import(loc.index).kind.function;
1467 return obj.func_types[ty_index];1485 return obj_file.funcTypes()[ty_index];
1468 }1486 }
1469 const import_function_count = obj.importedCountByKind(.function);1487 const type_index = obj_file.functions()[symbol.index - obj_file.importedFunctions()].type_index;
1470 const type_index = obj.functions[symbol.index - import_function_count].type_index;1488 return obj_file.funcTypes()[type_index];
1471 return obj.func_types[type_index];
1472 }1489 }
1473 if (is_undefined) {1490 if (is_undefined) {
1474 const ty_index = wasm.imports.get(loc).?.kind.function;1491 const ty_index = wasm.imports.get(loc).?.kind.function;
...@@ -1606,10 +1623,10 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -1606,10 +1623,10 @@ fn allocateAtoms(wasm: *Wasm) !void {
1606 // Ensure we get the original symbol, so we verify the correct symbol on whether1623 // Ensure we get the original symbol, so we verify the correct symbol on whether
1607 // it is dead or not and ensure an atom is removed when dead.1624 // it is dead or not and ensure an atom is removed when dead.
1608 // This is required as we may have parsed aliases into atoms.1625 // This is required as we may have parsed aliases into atoms.
1609 const sym = if (symbol_loc.file) |object_index| sym: {1626 const sym = if (symbol_loc.file) |object_index|
1610 const object = wasm.objects.items[object_index];1627 wasm.file(object_index).?.symbol(symbol_loc.index).*
1611 break :sym object.symtable[symbol_loc.index];1628 else
1612 } else wasm.synthetic_symbols.items[symbol_loc.index];1629 wasm.synthetic_symbols.items[symbol_loc.index];
16131630
1614 // Dead symbols must be unlinked from the linked-list to prevent them1631 // Dead symbols must be unlinked from the linked-list to prevent them
1615 // from being emit into the binary.1632 // from being emit into the binary.
...@@ -1655,9 +1672,10 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {...@@ -1655,9 +1672,10 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
16551672
1656 const atom = wasm.getAtom(atom_index);1673 const atom = wasm.getAtom(atom_index);
1657 const merge_segment = wasm.base.comp.config.output_mode != .Obj;1674 const merge_segment = wasm.base.comp.config.output_mode != .Obj;
1658 const segment_info = if (atom.file) |object_index| blk: {1675 const segment_info = if (atom.file) |object_index|
1659 break :blk wasm.objects.items[object_index].segment_info;1676 wasm.file(object_index).?.segmentInfo()
1660 } else wasm.segment_info.values();1677 else
1678 wasm.segment_info.values();
1661 const segment_name = segment_info[symbol.index].outputName(merge_segment);1679 const segment_name = segment_info[symbol.index].outputName(merge_segment);
1662 const segment_index = wasm.data_segments.get(segment_name).?;1680 const segment_index = wasm.data_segments.get(segment_name).?;
1663 const segment = wasm.segments.items[segment_index];1681 const segment = wasm.segments.items[segment_index];
...@@ -1713,7 +1731,8 @@ fn sortDataSegments(wasm: *Wasm) !void {...@@ -1713,7 +1731,8 @@ fn sortDataSegments(wasm: *Wasm) !void {
1713/// contain any parameters.1731/// contain any parameters.
1714fn setupInitFunctions(wasm: *Wasm) !void {1732fn setupInitFunctions(wasm: *Wasm) !void {
1715 const gpa = wasm.base.comp.gpa;1733 const gpa = wasm.base.comp.gpa;
1716 for (wasm.objects.items, 0..) |object, file_index| {1734 for (wasm.objects.items) |file_index| {
1735 const object = wasm.files.items(.data)[file_index].object;
1717 try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len);1736 try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len);
1718 for (object.init_funcs) |init_func| {1737 for (object.init_funcs) |init_func| {
1719 const symbol = object.symtable[init_func.symbol_index];1738 const symbol = object.symtable[init_func.symbol_index];
...@@ -1961,7 +1980,7 @@ fn setupImports(wasm: *Wasm) !void {...@@ -1961,7 +1980,7 @@ fn setupImports(wasm: *Wasm) !void {
19611980
1962 for (wasm.resolved_symbols.keys()) |symbol_loc| {1981 for (wasm.resolved_symbols.keys()) |symbol_loc| {
1963 const file_index = symbol_loc.file orelse {1982 const file_index = symbol_loc.file orelse {
1964 // imports generated by Zig code are already in the `import` section1983 // Synthetic symbols will already exist in the `import` section
1965 continue;1984 continue;
1966 };1985 };
19671986
...@@ -1974,14 +1993,14 @@ fn setupImports(wasm: *Wasm) !void {...@@ -1974,14 +1993,14 @@ fn setupImports(wasm: *Wasm) !void {
1974 }1993 }
19751994
1976 log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)});1995 log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)});
1977 const object = wasm.objects.items[file_index];1996 const obj_file = wasm.file(file_index).?;
1978 const import = object.findImport(symbol.tag.externalType(), symbol.index);1997 const import = obj_file.import(symbol_loc.index);
19791998
1980 // We copy the import to a new import to ensure the names contain references1999 // We copy the import to a new import to ensure the names contain references
1981 // to the internal string table, rather than of the object file.2000 // to the internal string table, rather than of the object file.
1982 const new_imp: types.Import = .{2001 const new_imp: types.Import = .{
1983 .module_name = try wasm.string_table.put(gpa, object.string_table.get(import.module_name)),2002 .module_name = try wasm.string_table.put(gpa, obj_file.string(import.module_name)),
1984 .name = try wasm.string_table.put(gpa, object.string_table.get(import.name)),2003 .name = try wasm.string_table.put(gpa, obj_file.string(import.name)),
1985 .kind = import.kind,2004 .kind = import.kind,
1986 };2005 };
1987 // TODO: De-duplicate imports when they contain the same names and type2006 // TODO: De-duplicate imports when they contain the same names and type
...@@ -2032,28 +2051,23 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2032,28 +2051,23 @@ fn mergeSections(wasm: *Wasm) !void {
2032 defer removed_duplicates.deinit();2051 defer removed_duplicates.deinit();
20332052
2034 for (wasm.resolved_symbols.keys()) |sym_loc| {2053 for (wasm.resolved_symbols.keys()) |sym_loc| {
2035 if (sym_loc.file == null) {2054 const file_index = sym_loc.file orelse {
2036 // Zig code-generated symbols are already within the sections and do not2055 // Zig code-generated symbols are already within the sections and do not
2037 // require to be merged2056 // require to be merged
2038 continue;2057 continue;
2039 }2058 };
20402059
2041 const object = &wasm.objects.items[sym_loc.file.?];2060 const obj_file = wasm.file(@enumFromInt(file_index)).?;
2042 const symbol = &object.symtable[sym_loc.index];2061 const symbol = obj_file.symbol[sym_loc.index];
20432062
2044 if (symbol.isDead() or2063 if (symbol.isDead() or symbol.isUndefined()) {
2045 symbol.isUndefined() or
2046 (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table))
2047 {
2048 // Skip undefined symbols as they go in the `import` section2064 // Skip undefined symbols as they go in the `import` section
2049 // Also skip symbols that do not need to have a section merged.
2050 continue;2065 continue;
2051 }2066 }
20522067
2053 const offset = object.importedCountByKind(symbol.tag.externalType());
2054 const index = symbol.index - offset;
2055 switch (symbol.tag) {2068 switch (symbol.tag) {
2056 .function => {2069 .function => {
2070 const index = symbol.index - obj_file.importedFunctions();
2057 const gop = try wasm.functions.getOrPut(2071 const gop = try wasm.functions.getOrPut(
2058 gpa,2072 gpa,
2059 .{ .file = sym_loc.file, .index = symbol.index },2073 .{ .file = sym_loc.file, .index = symbol.index },
...@@ -2071,20 +2085,24 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2071,20 +2085,24 @@ fn mergeSections(wasm: *Wasm) !void {
2071 try removed_duplicates.append(sym_loc);2085 try removed_duplicates.append(sym_loc);
2072 continue;2086 continue;
2073 }2087 }
2074 gop.value_ptr.* = .{ .func = object.functions[index], .sym_index = sym_loc.index };2088 gop.value_ptr.* = .{ .func = obj_file.functions()[index], .sym_index = sym_loc.index };
2075 symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count;2089 symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count;
2076 },2090 },
2077 .global => {2091 .global => {
2078 const original_global = object.globals[index];2092 const index = symbol.index - obj_file.importedFunctions();
2093 const original_global = obj_file.globals()[index];
2079 symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;2094 symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;
2080 try wasm.wasm_globals.append(gpa, original_global);2095 try wasm.wasm_globals.append(gpa, original_global);
2081 },2096 },
2082 .table => {2097 .table => {
2083 const original_table = object.tables[index];2098 const index = symbol.index - obj_file.importedFunctions();
2099 // assert it's a regular relocatable object file as `ZigObject` will never
2100 // contain a table.
2101 const original_table = obj_file.object.tables[index];
2084 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;2102 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;
2085 try wasm.tables.append(gpa, original_table);2103 try wasm.tables.append(gpa, original_table);
2086 },2104 },
2087 else => unreachable,2105 else => continue,
2088 }2106 }
2089 }2107 }
20902108
...@@ -2111,12 +2129,13 @@ fn mergeTypes(wasm: *Wasm) !void {...@@ -2111,12 +2129,13 @@ fn mergeTypes(wasm: *Wasm) !void {
2111 defer dirty.deinit();2129 defer dirty.deinit();
21122130
2113 for (wasm.resolved_symbols.keys()) |sym_loc| {2131 for (wasm.resolved_symbols.keys()) |sym_loc| {
2114 if (sym_loc.file == null) {2132 const file_index = sym_loc.file orelse {
2115 // zig code-generated symbols are already present in final type section2133 // zig code-generated symbols are already present in final type section
2116 continue;2134 continue;
2117 }2135 };
2118 const object = wasm.objects.items[sym_loc.file.?];2136
2119 const symbol = object.symtable[sym_loc.index];2137 const obj_file = wasm.file(@enumFromInt(file_index)).?;
2138 const symbol = obj_file.symbol(sym_loc.index);
2120 if (symbol.tag != .function or symbol.isDead()) {2139 if (symbol.tag != .function or symbol.isDead()) {
2121 // Only functions have types. Only retrieve the type of referenced functions.2140 // Only functions have types. Only retrieve the type of referenced functions.
2122 continue;2141 continue;
...@@ -2125,12 +2144,12 @@ fn mergeTypes(wasm: *Wasm) !void {...@@ -2125,12 +2144,12 @@ fn mergeTypes(wasm: *Wasm) !void {
2125 if (symbol.isUndefined()) {2144 if (symbol.isUndefined()) {
2126 log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(wasm)});2145 log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(wasm)});
2127 const import: *types.Import = wasm.imports.getPtr(sym_loc) orelse continue;2146 const import: *types.Import = wasm.imports.getPtr(sym_loc) orelse continue;
2128 const original_type = object.func_types[import.kind.function];2147 const original_type = obj_file.funcTypes()[import.kind.function];
2129 import.kind.function = try wasm.putOrGetFuncType(original_type);2148 import.kind.function = try wasm.putOrGetFuncType(original_type);
2130 } else if (!dirty.contains(symbol.index)) {2149 } else if (!dirty.contains(symbol.index)) {
2131 log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)});2150 log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)});
2132 const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func;2151 const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func;
2133 func.type_index = try wasm.putOrGetFuncType(object.func_types[func.type_index]);2152 func.type_index = try wasm.putOrGetFuncType(obj_file.funcTypes()[func.type_index]);
2134 dirty.putAssumeCapacityNoClobber(symbol.index, {});2153 dirty.putAssumeCapacityNoClobber(symbol.index, {});
2135 }2154 }
2136 }2155 }
...@@ -2240,11 +2259,18 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2240,11 +2259,18 @@ fn setupMemory(wasm: *Wasm) !void {
22402259
2241 const is_obj = comp.config.output_mode == .Obj;2260 const is_obj = comp.config.output_mode == .Obj;
22422261
2262 const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: {
2263 const sym = loc.getSymbol(wasm);
2264 break :index sym.index - wasm.imported_globals_count;
2265 } else null;
2266
2243 if (place_stack_first and !is_obj) {2267 if (place_stack_first and !is_obj) {
2244 memory_ptr = stack_alignment.forward(memory_ptr);2268 memory_ptr = stack_alignment.forward(memory_ptr);
2245 memory_ptr += wasm.base.stack_size;2269 memory_ptr += wasm.base.stack_size;
2246 // We always put the stack pointer global at index 02270 // We always put the stack pointer global at index 0
2247 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));2271 if (stack_ptr) |index| {
2272 wasm.wasm_globals.items[index].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
2273 }
2248 }2274 }
22492275
2250 var offset: u32 = @as(u32, @intCast(memory_ptr));2276 var offset: u32 = @as(u32, @intCast(memory_ptr));
...@@ -2290,7 +2316,9 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2290,7 +2316,9 @@ fn setupMemory(wasm: *Wasm) !void {
2290 if (!place_stack_first and !is_obj) {2316 if (!place_stack_first and !is_obj) {
2291 memory_ptr = stack_alignment.forward(memory_ptr);2317 memory_ptr = stack_alignment.forward(memory_ptr);
2292 memory_ptr += wasm.base.stack_size;2318 memory_ptr += wasm.base.stack_size;
2293 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));2319 if (stack_ptr) |index| {
2320 wasm.wasm_globals.items[index].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
2321 }
2294 }2322 }
22952323
2296 // One of the linked object files has a reference to the __heap_base symbol.2324 // One of the linked object files has a reference to the __heap_base symbol.
...@@ -2355,17 +2383,17 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2355,17 +2383,17 @@ fn setupMemory(wasm: *Wasm) !void {
2355/// From a given object's index and the index of the segment, returns the corresponding2383/// From a given object's index and the index of the segment, returns the corresponding
2356/// index of the segment within the final data section. When the segment does not yet2384/// index of the segment within the final data section. When the segment does not yet
2357/// exist, a new one will be initialized and appended. The new index will be returned in that case.2385/// exist, a new one will be initialized and appended. The new index will be returned in that case.
2358pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 {2386pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: u32) !u32 {
2359 const comp = wasm.base.comp;2387 const comp = wasm.base.comp;
2360 const gpa = comp.gpa;2388 const gpa = comp.gpa;
2361 const object: Object = wasm.objects.items[object_index];2389 const obj_file = wasm.file(file_index).?;
2362 const symbol = object.symtable[symbol_index];2390 const symbol = obj_file.symbols()[symbol_index];
2363 const index: u32 = @intCast(wasm.segments.items.len);2391 const index: u32 = @intCast(wasm.segments.items.len);
2364 const shared_memory = comp.config.shared_memory;2392 const shared_memory = comp.config.shared_memory;
23652393
2366 switch (symbol.tag) {2394 switch (symbol.tag) {
2367 .data => {2395 .data => {
2368 const segment_info = object.segment_info[symbol.index];2396 const segment_info = obj_file.segmentInfo()[symbol.index];
2369 const merge_segment = comp.config.output_mode != .Obj;2397 const merge_segment = comp.config.output_mode != .Obj;
2370 const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment));2398 const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment));
2371 if (!result.found_existing) {2399 if (!result.found_existing) {
...@@ -2394,7 +2422,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u3...@@ -2394,7 +2422,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u3
2394 break :blk index;2422 break :blk index;
2395 },2423 },
2396 .section => {2424 .section => {
2397 const section_name = object.string_table.get(symbol.name);2425 const section_name = file.symbolName(symbol.index);
2398 if (mem.eql(u8, section_name, ".debug_info")) {2426 if (mem.eql(u8, section_name, ".debug_info")) {
2399 return wasm.debug_info_index orelse blk: {2427 return wasm.debug_info_index orelse blk: {
2400 wasm.debug_info_index = index;2428 wasm.debug_info_index = index;
...@@ -4291,12 +4319,10 @@ fn markReferences(wasm: *Wasm) !void {...@@ -4291,12 +4319,10 @@ fn markReferences(wasm: *Wasm) !void {
4291 // Debug sections may require to be parsed and marked when it contains4319 // Debug sections may require to be parsed and marked when it contains
4292 // relocations to alive symbols.4320 // relocations to alive symbols.
4293 if (sym.tag == .section and comp.config.debug_format != .strip) {4321 if (sym.tag == .section and comp.config.debug_format != .strip) {
4294 const file = sym_loc.file orelse continue; // Incremental debug info is done independently4322 const file_index = sym_loc.file orelse continue; // Incremental debug info is done independently
4295 const object = &wasm.objects.items[file];4323 const obj_file = wasm.file(@enumFromInt(file_index)).?;
4296 const atom_index = try Object.parseSymbolIntoAtom(object, file, sym_loc.index, wasm);4324 _ = try obj_file.parseSymbolIntoAtom(wasm, sym_loc.index);
4297 const atom = wasm.getAtom(atom_index);4325 sym.mark();
4298 const atom_sym = atom.symbolLoc().getSymbol(wasm);
4299 atom_sym.mark();
4300 }4326 }
4301 }4327 }
4302}4328}
...@@ -4319,9 +4345,8 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {...@@ -4319,9 +4345,8 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
4319 }4345 }
43204346
4321 const atom_index = if (loc.file) |file_index| idx: {4347 const atom_index = if (loc.file) |file_index| idx: {
4322 const object = &wasm.objects.items[file_index];4348 const obj_file = wasm.file(@enumFromInt(file_index)).?;
4323 const atom_index = try object.parseSymbolIntoAtom(file_index, loc.index, wasm);4349 break :idx try obj_file.parseSymbolIntoAtom(wasm, loc.index);
4324 break :idx atom_index;
4325 } else wasm.symbol_atom.get(loc) orelse return;4350 } else wasm.symbol_atom.get(loc) orelse return;
43264351
4327 const atom = wasm.getAtom(atom_index);4352 const atom = wasm.getAtom(atom_index);
src/link/Wasm/Object.zig+39-36
...@@ -9,6 +9,7 @@ const std = @import("std");...@@ -9,6 +9,7 @@ const std = @import("std");
9const Wasm = @import("../Wasm.zig");9const Wasm = @import("../Wasm.zig");
10const Symbol = @import("Symbol.zig");10const Symbol = @import("Symbol.zig");
11const Alignment = types.Alignment;11const Alignment = types.Alignment;
12const File = @import("file.zig").File;
1213
13const Allocator = std.mem.Allocator;14const Allocator = std.mem.Allocator;
14const leb = std.leb;15const leb = std.leb;
...@@ -16,12 +17,14 @@ const meta = std.meta;...@@ -16,12 +17,14 @@ const meta = std.meta;
1617
17const log = std.log.scoped(.link);18const log = std.log.scoped(.link);
1819
20/// Index into the list of relocatable object files within the linker driver.
21index: File.Index = .null,
19/// Wasm spec version used for this `Object`22/// Wasm spec version used for this `Object`
20version: u32 = 0,23version: u32 = 0,
21/// The file descriptor that represents the wasm object file.24/// The file descriptor that represents the wasm object file.
22file: ?std.fs.File = null,25file: ?std.fs.File = null,
23/// Name (read path) of the object file.26/// Name (read path) of the object file.
24name: []const u8,27path: []const u8,
25/// Parsed type section28/// Parsed type section
26func_types: []const std.wasm.Type = &.{},29func_types: []const std.wasm.Type = &.{},
27/// A list of all imports for this module30/// A list of all imports for this module
...@@ -64,6 +67,12 @@ relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableDat...@@ -64,6 +67,12 @@ relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableDat
64/// import name, module name and export names. Each string will be deduplicated67/// import name, module name and export names. Each string will be deduplicated
65/// and returns an offset into the table.68/// and returns an offset into the table.
66string_table: Wasm.StringTable = .{},69string_table: Wasm.StringTable = .{},
70/// Amount of functions in the `import` sections.
71imported_functions_count: u32 = 0,
72/// Amount of globals in the `import` section.
73imported_globals_count: u32 = 0,
74/// Amount of tables in the `import` section.
75imported_tables_count: u32 = 0,
6776
68/// Represents a single item within a section (depending on its `type`)77/// Represents a single item within a section (depending on its `type`)
69const RelocatableData = struct {78const RelocatableData = struct {
...@@ -121,7 +130,7 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro...@@ -121,7 +130,7 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro
121pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_size: ?usize) InitError!Object {130pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_size: ?usize) InitError!Object {
122 var object: Object = .{131 var object: Object = .{
123 .file = file,132 .file = file,
124 .name = try gpa.dupe(u8, name),133 .path = try gpa.dupe(u8, name),
125 };134 };
126135
127 var is_object_file: bool = false;136 var is_object_file: bool = false;
...@@ -199,29 +208,17 @@ pub fn deinit(object: *Object, gpa: Allocator) void {...@@ -199,29 +208,17 @@ pub fn deinit(object: *Object, gpa: Allocator) void {
199208
200/// Finds the import within the list of imports from a given kind and index of that kind.209/// Finds the import within the list of imports from a given kind and index of that kind.
201/// Asserts the import exists210/// Asserts the import exists
202pub fn findImport(object: *const Object, import_kind: std.wasm.ExternalKind, index: u32) types.Import {211pub fn findImport(object: *const Object, index: u32) types.Import {
212 const sym = object.symtable[index];
203 var i: u32 = 0;213 var i: u32 = 0;
204 return for (object.imports) |import| {214 return for (object.imports) |import| {
205 if (std.meta.activeTag(import.kind) == import_kind) {215 if (std.meta.activeTag(import.kind) == sym.tag) {
206 if (i == index) return import;216 if (i == index) return import;
207 i += 1;217 i += 1;
208 }218 }
209 } else unreachable; // Only existing imports are allowed to be found219 } else unreachable; // Only existing imports are allowed to be found
210}220}
211221
212/// Counts the entries of imported `kind` and returns the result
213pub fn importedCountByKind(object: *const Object, kind: std.wasm.ExternalKind) u32 {
214 var i: u32 = 0;
215 return for (object.imports) |imp| {
216 if (@as(std.wasm.ExternalKind, imp.kind) == kind) i += 1;
217 } else i;
218}
219
220/// From a given `RelocatableDate`, find the corresponding debug section name
221pub fn getDebugName(object: *const Object, relocatable_data: RelocatableData) []const u8 {
222 return object.string_table.get(relocatable_data.index);
223}
224
225/// Checks if the object file is an MVP version.222/// Checks if the object file is an MVP version.
226/// When that's the case, we check if there's an import table definiton with its name223/// When that's the case, we check if there's an import table definiton with its name
227/// set to '__indirect_function_table". When that's also the case,224/// set to '__indirect_function_table". When that's also the case,
...@@ -427,16 +424,25 @@ fn Parser(comptime ReaderType: type) type {...@@ -427,16 +424,25 @@ fn Parser(comptime ReaderType: type) type {
427424
428 const kind = try readEnum(std.wasm.ExternalKind, reader);425 const kind = try readEnum(std.wasm.ExternalKind, reader);
429 const kind_value: std.wasm.Import.Kind = switch (kind) {426 const kind_value: std.wasm.Import.Kind = switch (kind) {
430 .function => .{ .function = try readLeb(u32, reader) },427 .function => val: {
428 parser.object.imported_functions_count += 1;
429 break :val .{ .function = try readLeb(u32, reader) };
430 },
431 .memory => .{ .memory = try readLimits(reader) },431 .memory => .{ .memory = try readLimits(reader) },
432 .global => .{ .global = .{432 .global => val: {
433 .valtype = try readEnum(std.wasm.Valtype, reader),433 parser.object.imported_globals_count += 1;
434 .mutable = (try reader.readByte()) == 0x01,434 break :val .{ .global = .{
435 } },435 .valtype = try readEnum(std.wasm.Valtype, reader),
436 .table => .{ .table = .{436 .mutable = (try reader.readByte()) == 0x01,
437 .reftype = try readEnum(std.wasm.RefType, reader),437 } };
438 .limits = try readLimits(reader),438 },
439 } },439 .table => val: {
440 parser.object.imported_tables_count += 1;
441 break :val .{ .table = .{
442 .reftype = try readEnum(std.wasm.RefType, reader),
443 .limits = try readLimits(reader),
444 } };
445 },
440 };446 };
441447
442 import.* = .{448 import.* = .{
...@@ -904,7 +910,7 @@ fn assertEnd(reader: anytype) !void {...@@ -904,7 +910,7 @@ fn assertEnd(reader: anytype) !void {
904}910}
905911
906/// Parses an object file into atoms, for code and data sections912/// Parses an object file into atoms, for code and data sections
907pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32, wasm: *Wasm) !Atom.Index {913pub fn parseSymbolIntoAtom(object: *Object, wasm: *Wasm, symbol_index: u32) !Atom.Index {
908 const comp = wasm.base.comp;914 const comp = wasm.base.comp;
909 const gpa = comp.gpa;915 const gpa = comp.gpa;
910 const symbol = &object.symtable[symbol_index];916 const symbol = &object.symtable[symbol_index];
...@@ -922,19 +928,16 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32...@@ -922,19 +928,16 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32
922 },928 },
923 else => unreachable,929 else => unreachable,
924 };930 };
925 const final_index = try wasm.getMatchingSegment(object_index, symbol_index);931 const final_index = try wasm.getMatchingSegment(object.index, symbol_index);
926 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));932 const atom_index = try wasm.createAtom(symbol_index, object.index);
927 const atom = try wasm.managed_atoms.addOne(gpa);
928 atom.* = Atom.empty;
929 try wasm.appendAtomAtIndex(final_index, atom_index);933 try wasm.appendAtomAtIndex(final_index, atom_index);
930934
931 atom.sym_index = symbol_index;935 const atom = wasm.getAtomPtr(atom_index);
932 atom.file = object_index;
933 atom.size = relocatable_data.size;936 atom.size = relocatable_data.size;
934 atom.alignment = relocatable_data.getAlignment(object);937 atom.alignment = relocatable_data.getAlignment(object);
935 atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);938 atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
936 atom.original_offset = relocatable_data.offset;939 atom.original_offset = relocatable_data.offset;
937 try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom_index);940
938 const segment: *Wasm.Segment = &wasm.segments.items[final_index];941 const segment: *Wasm.Segment = &wasm.segments.items[final_index];
939 if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned942 if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
940 segment.alignment = segment.alignment.max(atom.alignment);943 segment.alignment = segment.alignment.max(atom.alignment);
...@@ -952,7 +955,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32...@@ -952,7 +955,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32
952 .R_WASM_TABLE_INDEX_SLEB64,955 .R_WASM_TABLE_INDEX_SLEB64,
953 => {956 => {
954 try wasm.function_table.put(gpa, .{957 try wasm.function_table.put(gpa, .{
955 .file = object_index,958 .file = object.index,
956 .index = reloc.index,959 .index = reloc.index,
957 }, 0);960 }, 0);
958 },961 },
...@@ -963,7 +966,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32...@@ -963,7 +966,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32
963 if (sym.tag != .global) {966 if (sym.tag != .global) {
964 try wasm.got_symbols.append(967 try wasm.got_symbols.append(
965 gpa,968 gpa,
966 .{ .file = object_index, .index = reloc.index },969 .{ .file = object.index, .index = reloc.index },
967 );970 );
968 }971 }
969 },972 },
src/link/Wasm/ZigObject.zig+36
...@@ -11,6 +11,9 @@ index: File.Index,...@@ -11,6 +11,9 @@ index: File.Index,
11decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{},11decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{},
12/// List of function type signatures for this Zig module.12/// List of function type signatures for this Zig module.
13func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{},13func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{},
14/// List of `std.wasm.Func`. Each entry contains the function signature,
15/// rather than the actual body.
16functions: std.ArrayListUnmanaged(std.wasm.Func) = .{},
14/// Map of symbol locations, represented by its `types.Import`.17/// Map of symbol locations, represented by its `types.Import`.
15imports: std.AutoHashMapUnmanaged(u32, types.Import) = .{},18imports: std.AutoHashMapUnmanaged(u32, types.Import) = .{},
16/// List of WebAssembly globals.19/// List of WebAssembly globals.
...@@ -1152,6 +1155,39 @@ pub fn storeDeclType(zig_object: *ZigObject, gpa: std.mem.Allocator, decl_index:...@@ -1152,6 +1155,39 @@ pub fn storeDeclType(zig_object: *ZigObject, gpa: std.mem.Allocator, decl_index:
1152 return index;1155 return index;
1153}1156}
11541157
1158/// The symbols in ZigObject are already represented by an atom as we need to store its data.
1159/// So rather than creating a new Atom and returning its index, we use this oppertunity to scan
1160/// its relocations and create any GOT symbols or function table indexes it may require.
1161pub fn parseSymbolIntoAtom(zig_object: *ZigObject, wasm_file: *Wasm, index: u32) Atom.Index {
1162 const gpa = wasm_file.base.comp.gpa;
1163 const loc: Wasm.SymbolLoc = .{ .file = @intFromEnum(zig_object.index), .index = index };
1164 const final_index = try wasm_file.getMatchingSegment(zig_object.index, index);
1165 const atom_index = wasm_file.symbol_atom.get(loc).?;
1166 try wasm_file.appendAtomAtIndex(final_index, atom_index);
1167 const atom = wasm_file.getAtom(atom_index);
1168 for (atom.relocs.items) |reloc| {
1169 switch (reloc.relocation_type) {
1170 .R_WASM_TABLE_INDEX_I32,
1171 .R_WASM_TABLE_INDEX_I64,
1172 .R_WASM_TABLE_INDEX_SLEB,
1173 .R_WASM_TABLE_INDEX_SLEB64,
1174 => {
1175 try wasm_file.function_table.put(gpa, loc, 0);
1176 },
1177 .R_WASM_GLOBAL_INDEX_I32,
1178 .R_WASM_GLOBAL_INDEX_LEB,
1179 => {
1180 const sym = zig_object.symbol(reloc.index);
1181 if (sym.tag != .global) {
1182 try wasm_file.got_symbols.append(gpa, loc);
1183 }
1184 },
1185 else => {},
1186 }
1187 }
1188 return atom_index;
1189}
1190
1155const build_options = @import("build_options");1191const build_options = @import("build_options");
1156const builtin = @import("builtin");1192const builtin = @import("builtin");
1157const codegen = @import("../../codegen.zig");1193const codegen = @import("../../codegen.zig");