Commit 8856ba7505
Changed files (3)
src
link
src/link/Wasm/Atom.zig
@@ -23,6 +23,10 @@ alignment: Wasm.Alignment,
/// Offset into the section where the atom lives, this already accounts
/// for alignment.
offset: u32,
+/// The original offset within the object file. This value is substracted from
+/// relocation offsets to determine where in the `data` to rewrite the value
+original_offset: u32,
+
/// Represents the index of the file this atom was generated from.
/// This is 'null' when the atom was generated by a Decl from Zig code.
file: ?u16,
@@ -50,11 +54,11 @@ pub const empty: Atom = .{
.prev = null,
.size = 0,
.sym_index = 0,
+ .original_offset = 0,
};
/// Frees all resources owned by this `Atom`.
-pub fn deinit(atom: *Atom, wasm: *Wasm) void {
- const gpa = wasm.base.allocator;
+pub fn deinit(atom: *Atom, gpa: std.mem.Allocator) void {
atom.relocs.deinit(gpa);
atom.code.deinit(gpa);
atom.locals.deinit(gpa);
@@ -114,10 +118,10 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
.R_WASM_GLOBAL_INDEX_I32,
.R_WASM_MEMORY_ADDR_I32,
.R_WASM_SECTION_OFFSET_I32,
- => std.mem.writeInt(u32, atom.code.items[reloc.offset..][0..4], @as(u32, @intCast(value)), .little),
+ => std.mem.writeInt(u32, atom.code.items[reloc.offset - atom.original_offset ..][0..4], @as(u32, @intCast(value)), .little),
.R_WASM_TABLE_INDEX_I64,
.R_WASM_MEMORY_ADDR_I64,
- => std.mem.writeInt(u64, atom.code.items[reloc.offset..][0..8], value, .little),
+ => std.mem.writeInt(u64, atom.code.items[reloc.offset - atom.original_offset ..][0..8], value, .little),
.R_WASM_GLOBAL_INDEX_LEB,
.R_WASM_EVENT_INDEX_LEB,
.R_WASM_FUNCTION_INDEX_LEB,
@@ -127,12 +131,12 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
.R_WASM_TABLE_NUMBER_LEB,
.R_WASM_TYPE_INDEX_LEB,
.R_WASM_MEMORY_ADDR_TLS_SLEB,
- => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset..][0..5], @as(u32, @intCast(value))),
+ => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset - atom.original_offset ..][0..5], @as(u32, @intCast(value))),
.R_WASM_MEMORY_ADDR_LEB64,
.R_WASM_MEMORY_ADDR_SLEB64,
.R_WASM_TABLE_INDEX_SLEB64,
.R_WASM_MEMORY_ADDR_TLS_SLEB64,
- => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset..][0..10], value),
+ => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset - atom.original_offset ..][0..10], value),
}
}
}
@@ -150,7 +154,7 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
.R_WASM_TABLE_INDEX_I64,
.R_WASM_TABLE_INDEX_SLEB,
.R_WASM_TABLE_INDEX_SLEB64,
- => return wasm_bin.function_table.get(target_loc) orelse 0,
+ => return wasm_bin.function_table.get(.{ .file = atom.file, .index = relocation.index }) orelse 0,
.R_WASM_TYPE_INDEX_LEB => {
const file_index = atom.file orelse {
return relocation.index;
src/link/Wasm/Object.zig
@@ -59,20 +59,16 @@ init_funcs: []const types.InitFunc = &.{},
comdat_info: []const types.Comdat = &.{},
/// Represents non-synthetic sections that can essentially be mem-cpy'd into place
/// after performing relocations.
-relocatable_data: []const RelocatableData = &.{},
+relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .{},
/// String table for all strings required by the object file, such as symbol names,
/// import name, module name and export names. Each string will be deduplicated
/// and returns an offset into the table.
string_table: Wasm.StringTable = .{},
-/// All the names of each debug section found in the current object file.
-/// Each name is terminated by a null-terminator. The name can be found,
-/// from the `index` offset within the `RelocatableData`.
-debug_names: [:0]const u8,
/// Represents a single item within a section (depending on its `type`)
const RelocatableData = struct {
/// The type of the relocatable data
- type: enum { data, code, debug },
+ type: Tag,
/// Pointer to the data of the segment, where its length is written to `size`
data: [*]u8,
/// The size in bytes of the data representing the segment within the section
@@ -85,6 +81,8 @@ const RelocatableData = struct {
/// Represents the index of the section it belongs to
section_index: u32,
+ const Tag = enum { data, code, custom };
+
/// Returns the alignment of the segment, by retrieving it from the segment
/// meta data of the given object file.
/// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's
@@ -99,14 +97,14 @@ const RelocatableData = struct {
return switch (relocatable_data.type) {
.data => .data,
.code => .function,
- .debug => .section,
+ .custom => .section,
};
}
- /// Returns the index within a section itrelocatable_data, or in case of a debug section,
+ /// Returns the index within a section, or in case of a custom section,
/// returns the section index within the object file.
pub fn getIndex(relocatable_data: RelocatableData) u32 {
- if (relocatable_data.type == .debug) return relocatable_data.section_index;
+ if (relocatable_data.type == .custom) return relocatable_data.section_index;
return relocatable_data.index;
}
};
@@ -121,7 +119,6 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz
var object: Object = .{
.file = file,
.name = try gpa.dupe(u8, name),
- .debug_names = &.{},
};
var is_object_file: bool = false;
@@ -182,10 +179,16 @@ pub fn deinit(object: *Object, gpa: Allocator) void {
gpa.free(info.name);
}
gpa.free(object.segment_info);
- for (object.relocatable_data) |rel_data| {
- gpa.free(rel_data.data[0..rel_data.size]);
+ {
+ var it = object.relocatable_data.valueIterator();
+ while (it.next()) |relocatable_data| {
+ for (relocatable_data.*) |rel_data| {
+ gpa.free(rel_data.data[0..rel_data.size]);
+ }
+ gpa.free(relocatable_data.*);
+ }
}
- gpa.free(object.relocatable_data);
+ object.relocatable_data.deinit(gpa);
object.string_table.deinit(gpa);
gpa.free(object.name);
object.* = undefined;
@@ -345,23 +348,7 @@ fn Parser(comptime ReaderType: type) type {
errdefer parser.object.deinit(gpa);
try parser.verifyMagicBytes();
const version = try parser.reader.reader().readInt(u32, .little);
-
parser.object.version = version;
- var relocatable_data = std.ArrayList(RelocatableData).init(gpa);
- var debug_names = std.ArrayList(u8).init(gpa);
-
- errdefer {
- // only free the inner contents of relocatable_data if we didn't
- // assign it to the object yet.
- if (parser.object.relocatable_data.len == 0) {
- for (relocatable_data.items) |rel_data| {
- gpa.free(rel_data.data[0..rel_data.size]);
- }
- relocatable_data.deinit();
- }
- gpa.free(debug_names.items);
- debug_names.deinit();
- }
var section_index: u32 = 0;
while (parser.reader.reader().readByte()) |byte| : (section_index += 1) {
@@ -377,26 +364,34 @@ fn Parser(comptime ReaderType: type) type {
if (std.mem.eql(u8, name, "linking")) {
is_object_file.* = true;
- parser.object.relocatable_data = relocatable_data.items; // at this point no new relocatable sections will appear so we're free to store them.
try parser.parseMetadata(gpa, @as(usize, @intCast(reader.context.bytes_left)));
} else if (std.mem.startsWith(u8, name, "reloc")) {
try parser.parseRelocations(gpa);
} else if (std.mem.eql(u8, name, "target_features")) {
try parser.parseFeatures(gpa);
} else if (std.mem.startsWith(u8, name, ".debug")) {
+ const gop = try parser.object.relocatable_data.getOrPut(gpa, .custom);
+ var relocatable_data: std.ArrayListUnmanaged(RelocatableData) = .{};
+ defer relocatable_data.deinit(gpa);
+ if (!gop.found_existing) {
+ gop.value_ptr.* = &.{};
+ } else {
+ relocatable_data = std.ArrayListUnmanaged(RelocatableData).fromOwnedSlice(gop.value_ptr.*);
+ }
const debug_size = @as(u32, @intCast(reader.context.bytes_left));
const debug_content = try gpa.alloc(u8, debug_size);
errdefer gpa.free(debug_content);
try reader.readNoEof(debug_content);
- try relocatable_data.append(.{
- .type = .debug,
+ try relocatable_data.append(gpa, .{
+ .type = .custom,
.data = debug_content.ptr,
.size = debug_size,
.index = try parser.object.string_table.put(gpa, name),
.offset = 0, // debug sections only contain 1 entry, so no need to calculate offset
.section_index = section_index,
});
+ gop.value_ptr.* = try relocatable_data.toOwnedSlice(gpa);
} else {
try reader.skipBytes(reader.context.bytes_left, .{});
}
@@ -515,26 +510,32 @@ fn Parser(comptime ReaderType: type) type {
const start = reader.context.bytes_left;
var index: u32 = 0;
const count = try readLeb(u32, reader);
+ const imported_function_count = parser.object.importedCountByKind(.function);
+ var relocatable_data = try std.ArrayList(RelocatableData).initCapacity(gpa, count);
+ defer relocatable_data.deinit();
while (index < count) : (index += 1) {
const code_len = try readLeb(u32, reader);
const offset = @as(u32, @intCast(start - reader.context.bytes_left));
const data = try gpa.alloc(u8, code_len);
errdefer gpa.free(data);
try reader.readNoEof(data);
- try relocatable_data.append(.{
+ relocatable_data.appendAssumeCapacity(.{
.type = .code,
.data = data.ptr,
.size = code_len,
- .index = parser.object.importedCountByKind(.function) + index,
+ .index = imported_function_count + index,
.offset = offset,
.section_index = section_index,
});
}
+ try parser.object.relocatable_data.put(gpa, .code, try relocatable_data.toOwnedSlice());
},
.data => {
const start = reader.context.bytes_left;
var index: u32 = 0;
const count = try readLeb(u32, reader);
+ var relocatable_data = try std.ArrayList(RelocatableData).initCapacity(gpa, count);
+ defer relocatable_data.deinit();
while (index < count) : (index += 1) {
const flags = try readLeb(u32, reader);
const data_offset = try readInit(reader);
@@ -545,7 +546,7 @@ fn Parser(comptime ReaderType: type) type {
const data = try gpa.alloc(u8, data_len);
errdefer gpa.free(data);
try reader.readNoEof(data);
- try relocatable_data.append(.{
+ relocatable_data.appendAssumeCapacity(.{
.type = .data,
.data = data.ptr,
.size = data_len,
@@ -554,6 +555,7 @@ fn Parser(comptime ReaderType: type) type {
.section_index = section_index,
});
}
+ try parser.object.relocatable_data.put(gpa, .data, try relocatable_data.toOwnedSlice());
},
else => try parser.reader.reader().skipBytes(len, .{}),
}
@@ -561,7 +563,6 @@ fn Parser(comptime ReaderType: type) type {
error.EndOfStream => {}, // finished parsing the file
else => |e| return e,
}
- parser.object.relocatable_data = try relocatable_data.toOwnedSlice();
}
/// Based on the "features" custom section, parses it into a list of
@@ -789,7 +790,8 @@ fn Parser(comptime ReaderType: type) type {
},
.section => {
symbol.index = try leb.readULEB128(u32, reader);
- for (parser.object.relocatable_data) |data| {
+ const section_data = parser.object.relocatable_data.get(.custom).?;
+ for (section_data) |data| {
if (data.section_index == symbol.index) {
symbol.name = data.index;
break;
@@ -798,22 +800,15 @@ fn Parser(comptime ReaderType: type) type {
},
else => {
symbol.index = try leb.readULEB128(u32, reader);
- var maybe_import: ?types.Import = null;
-
const is_undefined = symbol.isUndefined();
- if (is_undefined) {
- maybe_import = parser.object.findImport(symbol.tag.externalType(), symbol.index);
- }
const explicit_name = symbol.hasFlag(.WASM_SYM_EXPLICIT_NAME);
- if (!(is_undefined and !explicit_name)) {
+ symbol.name = if (!is_undefined or (is_undefined and explicit_name)) name: {
const name_len = try leb.readULEB128(u32, reader);
const name = try gpa.alloc(u8, name_len);
defer gpa.free(name);
try reader.readNoEof(name);
- symbol.name = try parser.object.string_table.put(gpa, name);
- } else {
- symbol.name = maybe_import.?.name;
- }
+ break :name try parser.object.string_table.put(gpa, name);
+ } else parser.object.findImport(symbol.tag.externalType(), symbol.index).name;
},
}
return symbol;
@@ -887,110 +882,95 @@ fn assertEnd(reader: anytype) !void {
}
/// Parses an object file into atoms, for code and data sections
-pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_bin: *Wasm) !void {
- const Key = struct {
- kind: Symbol.Tag,
- index: u32,
- };
- var symbol_for_segment = std.AutoArrayHashMap(Key, std.ArrayList(u32)).init(gpa);
- defer for (symbol_for_segment.values()) |*list| {
- list.deinit();
- } else symbol_for_segment.deinit();
-
- for (object.symtable, 0..) |symbol, symbol_index| {
- switch (symbol.tag) {
- .function, .data, .section => if (!symbol.isUndefined()) {
- const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index });
- const sym_idx = @as(u32, @intCast(symbol_index));
- if (!gop.found_existing) {
- gop.value_ptr.* = std.ArrayList(u32).init(gpa);
+pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32, wasm: *Wasm) !Atom.Index {
+ const symbol = &object.symtable[symbol_index];
+ const relocatable_data: RelocatableData = switch (symbol.tag) {
+ .function => object.relocatable_data.get(.code).?[symbol.index - object.importedCountByKind(.function)],
+ .data => object.relocatable_data.get(.data).?[symbol.index],
+ .section => blk: {
+ const data = object.relocatable_data.get(.custom).?;
+ for (data) |dat| {
+ if (dat.section_index == symbol.index) {
+ break :blk dat;
}
- try gop.value_ptr.*.append(sym_idx);
- },
- else => continue,
- }
+ }
+ unreachable;
+ },
+ else => unreachable,
+ };
+ const final_index = try wasm.getMatchingSegment(object_index, symbol_index);
+ const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));
+ const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
+ atom.* = Atom.empty;
+ try wasm.appendAtomAtIndex(final_index, atom_index);
+
+ atom.sym_index = symbol_index;
+ atom.file = object_index;
+ atom.size = relocatable_data.size;
+ atom.alignment = relocatable_data.getAlignment(object);
+ atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
+ atom.original_offset = relocatable_data.offset;
+ try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom_index);
+ const segment: *Wasm.Segment = &wasm.segments.items[final_index];
+ if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
+ segment.alignment = segment.alignment.max(atom.alignment);
}
- for (object.relocatable_data, 0..) |relocatable_data, index| {
- const final_index = (try wasm_bin.getMatchingSegment(object_index, @as(u32, @intCast(index)))) orelse {
- continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
- };
-
- const atom_index: Atom.Index = @intCast(wasm_bin.managed_atoms.items.len);
- const atom = try wasm_bin.managed_atoms.addOne(gpa);
- atom.* = Atom.empty;
- atom.file = object_index;
- atom.size = relocatable_data.size;
- atom.alignment = relocatable_data.getAlignment(object);
-
- const relocations: []types.Relocation = object.relocations.get(relocatable_data.section_index) orelse &.{};
- for (relocations) |relocation| {
- if (isInbetween(relocatable_data.offset, atom.size, relocation.offset)) {
- // set the offset relative to the offset of the segment itobject,
- // rather than within the entire section.
- var reloc = relocation;
- reloc.offset -= relocatable_data.offset;
- try atom.relocs.append(gpa, reloc);
-
- switch (relocation.relocation_type) {
- .R_WASM_TABLE_INDEX_I32,
- .R_WASM_TABLE_INDEX_I64,
- .R_WASM_TABLE_INDEX_SLEB,
- .R_WASM_TABLE_INDEX_SLEB64,
- => {
- try wasm_bin.function_table.put(gpa, .{
- .file = object_index,
- .index = relocation.index,
- }, 0);
- },
- .R_WASM_GLOBAL_INDEX_I32,
- .R_WASM_GLOBAL_INDEX_LEB,
- => {
- const sym = object.symtable[relocation.index];
- if (sym.tag != .global) {
- try wasm_bin.got_symbols.append(
- wasm_bin.base.allocator,
- .{ .file = object_index, .index = relocation.index },
- );
- }
- },
- else => {},
- }
+ if (object.relocations.get(relocatable_data.section_index)) |relocations| {
+ const start = searchRelocStart(relocations, relocatable_data.offset);
+ const len = searchRelocEnd(relocations[start..], relocatable_data.offset + atom.size);
+ atom.relocs = std.ArrayListUnmanaged(types.Relocation).fromOwnedSlice(relocations[start..][0..len]);
+ for (atom.relocs.items) |*reloc| {
+ switch (reloc.relocation_type) {
+ .R_WASM_TABLE_INDEX_I32,
+ .R_WASM_TABLE_INDEX_I64,
+ .R_WASM_TABLE_INDEX_SLEB,
+ .R_WASM_TABLE_INDEX_SLEB64,
+ => {
+ try wasm.function_table.put(wasm.base.allocator, .{
+ .file = object_index,
+ .index = reloc.index,
+ }, 0);
+ },
+ .R_WASM_GLOBAL_INDEX_I32,
+ .R_WASM_GLOBAL_INDEX_LEB,
+ => {
+ const sym = object.symtable[reloc.index];
+ if (sym.tag != .global) {
+ try wasm.got_symbols.append(
+ wasm.base.allocator,
+ .{ .file = object_index, .index = reloc.index },
+ );
+ }
+ },
+ else => {},
}
}
+ }
- try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);
-
- if (symbol_for_segment.getPtr(.{
- .kind = relocatable_data.getSymbolKind(),
- .index = relocatable_data.getIndex(),
- })) |symbols| {
- atom.sym_index = symbols.pop();
- try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom_index);
-
- // symbols referencing the same atom will be added as alias
- // or as 'parent' when they are global.
- while (symbols.popOrNull()) |idx| {
- try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom_index);
- const alias_symbol = object.symtable[idx];
- if (alias_symbol.isGlobal()) {
- atom.sym_index = idx;
- }
- }
- }
+ return atom_index;
+}
- const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];
- if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned
- segment.alignment = segment.alignment.max(atom.alignment);
+fn searchRelocStart(relocs: []const types.Relocation, address: u32) usize {
+ var min: usize = 0;
+ var max: usize = relocs.len;
+ while (min < max) {
+ const index = (min + max) / 2;
+ const curr = relocs[index];
+ if (curr.offset < address) {
+ min = index + 1;
+ } else {
+ max = index;
}
-
- try wasm_bin.appendAtomAtIndex(final_index, atom_index);
- log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index });
}
+ return min;
}
-/// Verifies if a given value is in between a minimum -and maximum value.
-/// The maxmimum value is calculated using the length, both start and end are inclusive.
-inline fn isInbetween(min: u32, length: u32, value: u32) bool {
- return value >= min and value <= min + length;
+fn searchRelocEnd(relocs: []const types.Relocation, address: u32) usize {
+ for (relocs, 0..relocs.len) |reloc, index| {
+ if (reloc.offset > address) {
+ return index;
+ }
+ }
+ return relocs.len;
}
src/link/Wasm.zig
@@ -1309,6 +1309,31 @@ pub fn deinit(wasm: *Wasm) void {
archive.deinit(gpa);
}
+ // For decls and anon decls we free the memory of its atoms.
+ // The memory of atoms parsed from object files is managed by
+ // the object file itself, and therefore we can skip those.
+ {
+ var it = wasm.decls.valueIterator();
+ while (it.next()) |atom_index_ptr| {
+ const atom = wasm.getAtomPtr(atom_index_ptr.*);
+ for (atom.locals.items) |local_index| {
+ const local_atom = wasm.getAtomPtr(local_index);
+ local_atom.deinit(gpa);
+ }
+ atom.deinit(gpa);
+ }
+ }
+ {
+ for (wasm.anon_decls.values()) |atom_index| {
+ const atom = wasm.getAtomPtr(atom_index);
+ for (atom.locals.items) |local_index| {
+ const local_atom = wasm.getAtomPtr(local_index);
+ local_atom.deinit(gpa);
+ }
+ atom.deinit(gpa);
+ }
+ }
+
wasm.decls.deinit(gpa);
wasm.anon_decls.deinit(gpa);
wasm.atom_types.deinit(gpa);
@@ -1321,9 +1346,6 @@ pub fn deinit(wasm: *Wasm) void {
wasm.symbol_atom.deinit(gpa);
wasm.export_names.deinit(gpa);
wasm.atoms.deinit(gpa);
- for (wasm.managed_atoms.items) |*managed_atom| {
- managed_atom.deinit(wasm);
- }
wasm.managed_atoms.deinit(gpa);
wasm.segments.deinit(gpa);
wasm.data_segments.deinit(gpa);
@@ -1342,6 +1364,10 @@ pub fn deinit(wasm: *Wasm) void {
wasm.exports.deinit(gpa);
wasm.string_table.deinit(gpa);
+ for (wasm.synthetic_functions.items) |atom_index| {
+ const atom = wasm.getAtomPtr(atom_index);
+ atom.deinit(gpa);
+ }
wasm.synthetic_functions.deinit(gpa);
if (wasm.dwarf) |*dwarf| {
@@ -2406,7 +2432,7 @@ fn setupErrorsLen(wasm: *Wasm) !void {
prev_atom.next = atom.next;
atom.prev = null;
}
- atom.deinit(wasm);
+ atom.deinit(wasm.base.allocator);
break :blk index;
} else new_atom: {
const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
@@ -2509,6 +2535,7 @@ fn createSyntheticFunction(
.next = null,
.prev = null,
.code = function_body.moveToUnmanaged(),
+ .original_offset = 0,
};
try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);
try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
@@ -2545,6 +2572,7 @@ pub fn createFunction(
.prev = null,
.code = function_body.moveToUnmanaged(),
.relocs = relocations.moveToUnmanaged(),
+ .original_offset = 0,
};
const symbol = loc.getSymbol(wasm);
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); // ensure function does not get exported
@@ -3016,14 +3044,14 @@ 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, relocatable_index: u32) !?u32 {
+pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 {
const object: Object = wasm.objects.items[object_index];
- const relocatable_data = object.relocatable_data[relocatable_index];
+ const symbol = object.symtable[symbol_index];
const index = @as(u32, @intCast(wasm.segments.items.len));
- switch (relocatable_data.type) {
+ switch (symbol.tag) {
.data => {
- const segment_info = object.segment_info[relocatable_data.index];
+ const segment_info = object.segment_info[symbol.index];
const merge_segment = wasm.base.options.output_mode != .Obj;
const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment));
if (!result.found_existing) {
@@ -3041,67 +3069,67 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32
return index;
} else return result.value_ptr.*;
},
- .code => return wasm.code_section_index orelse blk: {
+ .function => return wasm.code_section_index orelse blk: {
wasm.code_section_index = index;
try wasm.appendDummySegment();
break :blk index;
},
- .debug => {
- const debug_name = object.getDebugName(relocatable_data);
- if (mem.eql(u8, debug_name, ".debug_info")) {
+ .section => {
+ const section_name = object.string_table.get(symbol.name);
+ if (mem.eql(u8, section_name, ".debug_info")) {
return wasm.debug_info_index orelse blk: {
wasm.debug_info_index = index;
try wasm.appendDummySegment();
break :blk index;
};
- } else if (mem.eql(u8, debug_name, ".debug_line")) {
+ } else if (mem.eql(u8, section_name, ".debug_line")) {
return wasm.debug_line_index orelse blk: {
wasm.debug_line_index = index;
try wasm.appendDummySegment();
break :blk index;
};
- } else if (mem.eql(u8, debug_name, ".debug_loc")) {
+ } else if (mem.eql(u8, section_name, ".debug_loc")) {
return wasm.debug_loc_index orelse blk: {
wasm.debug_loc_index = index;
try wasm.appendDummySegment();
break :blk index;
};
- } else if (mem.eql(u8, debug_name, ".debug_ranges")) {
+ } else if (mem.eql(u8, section_name, ".debug_ranges")) {
return wasm.debug_line_index orelse blk: {
wasm.debug_ranges_index = index;
try wasm.appendDummySegment();
break :blk index;
};
- } else if (mem.eql(u8, debug_name, ".debug_pubnames")) {
+ } else if (mem.eql(u8, section_name, ".debug_pubnames")) {
return wasm.debug_pubnames_index orelse blk: {
wasm.debug_pubnames_index = index;
try wasm.appendDummySegment();
break :blk index;
};
- } else if (mem.eql(u8, debug_name, ".debug_pubtypes")) {
+ } else if (mem.eql(u8, section_name, ".debug_pubtypes")) {
return wasm.debug_pubtypes_index orelse blk: {
wasm.debug_pubtypes_index = index;
try wasm.appendDummySegment();
break :blk index;
};
- } else if (mem.eql(u8, debug_name, ".debug_abbrev")) {
+ } else if (mem.eql(u8, section_name, ".debug_abbrev")) {
return wasm.debug_abbrev_index orelse blk: {
wasm.debug_abbrev_index = index;
try wasm.appendDummySegment();
break :blk index;
};
- } else if (mem.eql(u8, debug_name, ".debug_str")) {
+ } else if (mem.eql(u8, section_name, ".debug_str")) {
return wasm.debug_str_index orelse blk: {
wasm.debug_str_index = index;
try wasm.appendDummySegment();
break :blk index;
};
} else {
- log.warn("found unknown debug section '{s}'", .{debug_name});
- log.warn(" debug section will be skipped", .{});
- return null;
+ log.warn("found unknown section '{s}'", .{section_name});
+ return error.UnexpectedValue;
}
},
+ else => unreachable,
}
}
@@ -3468,11 +3496,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
try wasm.setupInitFunctions();
try wasm.setupStart();
- for (wasm.objects.items, 0..) |*object, object_index| {
- try object.parseIntoAtoms(gpa, @as(u16, @intCast(object_index)), wasm);
- }
-
- wasm.markReferences();
+ try wasm.markReferences();
try wasm.setupImports();
try wasm.allocateAtoms();
try wasm.setupMemory();
@@ -3558,7 +3582,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
try wasm.setupInitFunctions();
try wasm.setupErrorsLen();
try wasm.setupStart();
- wasm.markReferences();
+ try wasm.markReferences();
try wasm.setupImports();
if (wasm.base.options.module) |mod| {
var decl_it = wasm.decls.iterator();
@@ -3615,10 +3639,6 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
}
}
- for (wasm.objects.items, 0..) |*object, object_index| {
- try object.parseIntoAtoms(wasm.base.allocator, @as(u16, @intCast(object_index)), wasm);
- }
-
try wasm.allocateAtoms();
try wasm.setupMemory();
wasm.allocateVirtualAddresses();
@@ -3885,18 +3905,15 @@ fn writeToFile(
var atom_index = wasm.atoms.get(code_index).?;
// The code section must be sorted in line with the function order.
- var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count());
+ var sorted_atoms = try std.ArrayList(*const Atom).initCapacity(wasm.base.allocator, wasm.functions.count());
defer sorted_atoms.deinit();
while (true) {
- var atom = wasm.getAtomPtr(atom_index);
- if (wasm.resolved_symbols.contains(atom.symbolLoc())) {
- if (!is_obj) {
- atom.resolveRelocs(wasm);
- }
- sorted_atoms.appendAssumeCapacity(atom);
+ const atom = wasm.getAtomPtr(atom_index);
+ if (!is_obj) {
+ atom.resolveRelocs(wasm);
}
- // atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
+ sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions
atom_index = atom.prev orelse break;
}
@@ -3908,7 +3925,7 @@ fn writeToFile(
}
}.sort;
- mem.sort(*Atom, sorted_atoms.items, wasm, atom_sort_fn);
+ mem.sort(*const Atom, sorted_atoms.items, wasm, atom_sort_fn);
for (sorted_atoms.items) |sorted_atom| {
try leb.writeULEB128(binary_writer, sorted_atom.size);
@@ -5060,20 +5077,20 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s
/// Verifies all resolved symbols and checks whether itself needs to be marked alive,
/// as well as any of its references.
-fn markReferences(wasm: *Wasm) void {
+fn markReferences(wasm: *Wasm) !void {
const tracy = trace(@src());
defer tracy.end();
for (wasm.resolved_symbols.keys()) |sym_loc| {
const sym = sym_loc.getSymbol(wasm);
if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip()) {
- wasm.mark(sym_loc);
+ try wasm.mark(sym_loc);
}
}
}
/// Marks a symbol as 'alive' recursively so itself and any references it contains to
/// other symbols will not be omit from the binary.
-fn mark(wasm: *Wasm, loc: SymbolLoc) void {
+fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
const symbol = loc.getSymbol(wasm);
if (symbol.isAlive()) {
// Symbol is already marked alive, including its references.
@@ -5082,13 +5099,20 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) void {
return;
}
symbol.mark();
+ if (symbol.isUndefined()) {
+ // undefined symbols do not have an associated `Atom` and therefore also
+ // do not contain relocations.
+ return;
+ }
- if (wasm.symbol_atom.get(loc)) |atom_index| {
- const atom = wasm.getAtom(atom_index);
- const relocations: []const types.Relocation = atom.relocs.items;
- for (relocations) |reloc| {
- const target_loc: SymbolLoc = .{ .index = reloc.index, .file = loc.file };
- wasm.mark(target_loc.finalLoc(wasm));
- }
+ const file = loc.file orelse return; // Marking synthetic and Zig symbols is done seperately
+ const object = &wasm.objects.items[file];
+ const atom_index = try Object.parseSymbolIntoAtom(object, file, loc.index, wasm);
+
+ const atom = wasm.getAtom(atom_index);
+ const relocations: []const types.Relocation = atom.relocs.items;
+ for (relocations) |reloc| {
+ const target_loc: SymbolLoc = .{ .index = reloc.index, .file = file };
+ try wasm.mark(target_loc.finalLoc(wasm));
}
}