diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-10-30 13:08:02 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2024-10-30 19:34:58 -0700 |
| commit | ba2d006634925850fab9d0a0e01d87bdaa368108 (patch) | |
| tree | a0bba99d508fe111cf967cbe5d27b55cf30cc972 /src/link/Wasm/Atom.zig | |
| parent | 17a87d734167b500761ef0d61493342dea0ae01d (diff) | |
| download | zig-ba2d006634925850fab9d0a0e01d87bdaa368108.tar.gz zig-ba2d006634925850fab9d0a0e01d87bdaa368108.zip | |
link.File.Wasm: remove the "files" abstraction
Removes the `files` field from the Wasm linker, storing the ZigObject
as its own field instead using a tagged union.
This removes a layer of indirection when accessing the ZigObject, and
untangles logic so that we can introduce a "pre-link" phase that
prepares the linker state to handle only incremental updates to the
ZigObject and then minimize logic inside flush().
Furthermore, don't make array elements store their own indexes, that's
always a waste.
Flattens some of the file system hierarchy and unifies variable names
for easier refactoring.
Introduces type safety for optional object indexes.
Diffstat (limited to 'src/link/Wasm/Atom.zig')
| -rw-r--r-- | src/link/Wasm/Atom.zig | 204 |
1 files changed, 0 insertions, 204 deletions
diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig deleted file mode 100644 index dd373552d5..0000000000 --- a/src/link/Wasm/Atom.zig +++ /dev/null @@ -1,204 +0,0 @@ -/// Represents the index of the file this atom was generated from. -/// This is 'null' when the atom was generated by a synthetic linker symbol. -file: FileIndex, -/// symbol index of the symbol representing this atom -sym_index: Symbol.Index, -/// Size of the atom, used to calculate section sizes in the final binary -size: u32 = 0, -/// List of relocations belonging to this atom -relocs: std.ArrayListUnmanaged(types.Relocation) = .empty, -/// Contains the binary data of an atom, which can be non-relocated -code: std.ArrayListUnmanaged(u8) = .empty, -/// For code this is 1, for data this is set to the highest value of all segments -alignment: Wasm.Alignment = .@"1", -/// Offset into the section where the atom lives, this already accounts -/// for alignment. -offset: u32 = 0, -/// The original offset within the object file. This value is subtracted from -/// relocation offsets to determine where in the `data` to rewrite the value -original_offset: u32 = 0, -/// Previous atom in relation to this atom. -/// is null when this atom is the first in its order -prev: Atom.Index = .null, -/// Contains atoms local to a decl, all managed by this `Atom`. -/// When the parent atom is being freed, it will also do so for all local atoms. -locals: std.ArrayListUnmanaged(Atom.Index) = .empty, - -/// Represents the index of an Atom where `null` is considered -/// an invalid atom. -pub const Index = enum(u32) { - null = std.math.maxInt(u32), - _, -}; - -/// Frees all resources owned by this `Atom`. -pub fn deinit(atom: *Atom, gpa: std.mem.Allocator) void { - atom.relocs.deinit(gpa); - atom.code.deinit(gpa); - atom.locals.deinit(gpa); - atom.* = undefined; -} - -/// Sets the length of relocations and code to '0', -/// effectively resetting them and allowing them to be re-populated. -pub fn clear(atom: *Atom) void { - atom.relocs.clearRetainingCapacity(); - atom.code.clearRetainingCapacity(); -} - -pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { - _ = fmt; - _ = options; - try writer.print("Atom{{ .sym_index = {d}, .alignment = {d}, .size = {d}, .offset = 0x{x:0>8} }}", .{ - @intFromEnum(atom.sym_index), - atom.alignment, - atom.size, - atom.offset, - }); -} - -/// Returns the location of the symbol that represents this `Atom` -pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc { - return .{ .file = atom.file, .index = atom.sym_index }; -} - -/// Resolves the relocations within the atom, writing the new value -/// at the calculated offset. -pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void { - if (atom.relocs.items.len == 0) return; - const symbol_name = atom.symbolLoc().getName(wasm_bin); - log.debug("Resolving relocs in atom '{s}' count({d})", .{ - symbol_name, - atom.relocs.items.len, - }); - - for (atom.relocs.items) |reloc| { - const value = atom.relocationValue(reloc, wasm_bin); - log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{ - (Wasm.SymbolLoc{ .file = atom.file, .index = @enumFromInt(reloc.index) }).getName(wasm_bin), - symbol_name, - reloc.offset, - value, - }); - - switch (reloc.relocation_type) { - .R_WASM_TABLE_INDEX_I32, - .R_WASM_FUNCTION_OFFSET_I32, - .R_WASM_GLOBAL_INDEX_I32, - .R_WASM_MEMORY_ADDR_I32, - .R_WASM_SECTION_OFFSET_I32, - => std.mem.writeInt(u32, atom.code.items[reloc.offset - atom.original_offset ..][0..4], @as(u32, @truncate(value)), .little), - .R_WASM_TABLE_INDEX_I64, - .R_WASM_MEMORY_ADDR_I64, - => 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, - .R_WASM_MEMORY_ADDR_LEB, - .R_WASM_MEMORY_ADDR_SLEB, - .R_WASM_TABLE_INDEX_SLEB, - .R_WASM_TABLE_NUMBER_LEB, - .R_WASM_TYPE_INDEX_LEB, - .R_WASM_MEMORY_ADDR_TLS_SLEB, - => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset - atom.original_offset ..][0..5], @as(u32, @truncate(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 - atom.original_offset ..][0..10], value), - } - } -} - -/// From a given `relocation` will return the new value to be written. -/// All values will be represented as a `u64` as all values can fit within it. -/// The final value must be casted to the correct size. -fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 { - const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = @enumFromInt(relocation.index) }).finalLoc(wasm_bin); - const symbol = target_loc.getSymbol(wasm_bin); - if (relocation.relocation_type != .R_WASM_TYPE_INDEX_LEB and - symbol.tag != .section and - symbol.isDead()) - { - const val = atom.thombstone(wasm_bin) orelse relocation.addend; - return @bitCast(val); - } - switch (relocation.relocation_type) { - .R_WASM_FUNCTION_INDEX_LEB => return symbol.index, - .R_WASM_TABLE_NUMBER_LEB => return symbol.index, - .R_WASM_TABLE_INDEX_I32, - .R_WASM_TABLE_INDEX_I64, - .R_WASM_TABLE_INDEX_SLEB, - .R_WASM_TABLE_INDEX_SLEB64, - => return wasm_bin.function_table.get(.{ .file = atom.file, .index = @enumFromInt(relocation.index) }) orelse 0, - .R_WASM_TYPE_INDEX_LEB => { - const obj_file = wasm_bin.file(atom.file) orelse return relocation.index; - const original_type = obj_file.funcTypes()[relocation.index]; - return wasm_bin.getTypeIndex(original_type).?; - }, - .R_WASM_GLOBAL_INDEX_I32, - .R_WASM_GLOBAL_INDEX_LEB, - => return symbol.index, - .R_WASM_MEMORY_ADDR_I32, - .R_WASM_MEMORY_ADDR_I64, - .R_WASM_MEMORY_ADDR_LEB, - .R_WASM_MEMORY_ADDR_LEB64, - .R_WASM_MEMORY_ADDR_SLEB, - .R_WASM_MEMORY_ADDR_SLEB64, - => { - std.debug.assert(symbol.tag == .data); - if (symbol.isUndefined()) { - return 0; - } - const va: i33 = @intCast(symbol.virtual_address); - return @intCast(va + relocation.addend); - }, - .R_WASM_EVENT_INDEX_LEB => return symbol.index, - .R_WASM_SECTION_OFFSET_I32 => { - const target_atom_index = wasm_bin.symbol_atom.get(target_loc).?; - const target_atom = wasm_bin.getAtom(target_atom_index); - const rel_value: i33 = @intCast(target_atom.offset); - return @intCast(rel_value + relocation.addend); - }, - .R_WASM_FUNCTION_OFFSET_I32 => { - if (symbol.isUndefined()) { - const val = atom.thombstone(wasm_bin) orelse relocation.addend; - return @bitCast(val); - } - const target_atom_index = wasm_bin.symbol_atom.get(target_loc).?; - const target_atom = wasm_bin.getAtom(target_atom_index); - const rel_value: i33 = @intCast(target_atom.offset); - return @intCast(rel_value + relocation.addend); - }, - .R_WASM_MEMORY_ADDR_TLS_SLEB, - .R_WASM_MEMORY_ADDR_TLS_SLEB64, - => { - const va: i33 = @intCast(symbol.virtual_address); - return @intCast(va + relocation.addend); - }, - } -} - -// For a given `Atom` returns whether it has a thombstone value or not. -/// This defines whether we want a specific value when a section is dead. -fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 { - const atom_name = atom.symbolLoc().getName(wasm); - if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) { - return -2; - } else if (std.mem.startsWith(u8, atom_name, ".debug_")) { - return -1; - } - return null; -} - -const leb = std.leb; -const log = std.log.scoped(.link); -const mem = std.mem; -const std = @import("std"); -const types = @import("types.zig"); - -const Allocator = mem.Allocator; -const Atom = @This(); -const FileIndex = @import("file.zig").File.Index; -const Symbol = @import("Symbol.zig"); -const Wasm = @import("../Wasm.zig"); |
