| author | |
| committer | |
| log | 9b3c8fd3a8aef81f3a6face78f9e0b34508edc1b |
| tree | 7026f5e6baf349298971e6dd3aa68cf0d8edb452 |
| parent | e54177e852e5674ff14a850586b7517697e52297 |
| signature |
When we have a ZigCompileUnit and don't use LLVM, we initialize the
ZigObject which will encapsulate the Zig Module as an object file in-
memory. During initialization we also create symbols which the object
will need such as the stack pointer.2 files changed, 82 insertions(+), 30 deletions(-)
src/link/Wasm.zig+48-21| ... | @@ -1,37 +1,41 @@ | ... | @@ -1,37 +1,41 @@ |
| 1 | const Wasm = @This(); | 1 | const Wasm = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const builtin = @import("builtin"); | 4 | |
| 5 | const mem = std.mem; | ||
| 6 | const Allocator = std.mem.Allocator; | ||
| 7 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 6 | const build_options = @import("build_options"); | ||
| 7 | const builtin = @import("builtin"); | ||
| 8 | const codegen = @import("../codegen.zig"); | ||
| 8 | const fs = std.fs; | 9 | const fs = std.fs; |
| 9 | const leb = std.leb; | 10 | const leb = std.leb; |
| 10 | const log = std.log.scoped(.link); | ||
| 11 | |||
| 12 | pub const Atom = @import("Wasm/Atom.zig"); | ||
| 13 | const Dwarf = @import("Dwarf.zig"); | ||
| 14 | const Module = @import("../Module.zig"); | ||
| 15 | const InternPool = @import("../InternPool.zig"); | ||
| 16 | const Compilation = @import("../Compilation.zig"); | ||
| 17 | const CodeGen = @import("../arch/wasm/CodeGen.zig"); | ||
| 18 | const codegen = @import("../codegen.zig"); | ||
| 19 | const link = @import("../link.zig"); | 11 | const link = @import("../link.zig"); |
| 20 | const lldMain = @import("../main.zig").lldMain; | 12 | const lldMain = @import("../main.zig").lldMain; |
| 13 | const log = std.log.scoped(.link); | ||
| 14 | const mem = std.mem; | ||
| 21 | const trace = @import("../tracy.zig").trace; | 15 | const trace = @import("../tracy.zig").trace; |
| 22 | const build_options = @import("build_options"); | 16 | const types = @import("Wasm/types.zig"); |
| 23 | const wasi_libc = @import("../wasi_libc.zig"); | 17 | const wasi_libc = @import("../wasi_libc.zig"); |
| 24 | const Cache = std.Build.Cache; | 18 | |
| 25 | const Type = @import("../type.zig").Type; | ||
| 26 | const Value = @import("../Value.zig"); | ||
| 27 | const TypedValue = @import("../TypedValue.zig"); | ||
| 28 | const LlvmObject = @import("../codegen/llvm.zig").Object; | ||
| 29 | const Air = @import("../Air.zig"); | 19 | const Air = @import("../Air.zig"); |
| 20 | const Allocator = std.mem.Allocator; | ||
| 21 | const Archive = @import("Wasm/Archive.zig"); | ||
| 22 | const Cache = std.Build.Cache; | ||
| 23 | const CodeGen = @import("../arch/wasm/CodeGen.zig"); | ||
| 24 | const Compilation = @import("../Compilation.zig"); | ||
| 25 | const Dwarf = @import("Dwarf.zig"); | ||
| 26 | const File = @import("Wasm/file.zig").File; | ||
| 27 | const InternPool = @import("../InternPool.zig"); | ||
| 30 | const Liveness = @import("../Liveness.zig"); | 28 | const Liveness = @import("../Liveness.zig"); |
| 31 | const Symbol = @import("Wasm/Symbol.zig"); | 29 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 30 | const Module = @import("../Module.zig"); | ||
| 32 | const Object = @import("Wasm/Object.zig"); | 31 | const Object = @import("Wasm/Object.zig"); |
| 33 | const Archive = @import("Wasm/Archive.zig"); | 32 | const Symbol = @import("Wasm/Symbol.zig"); |
| 34 | const types = @import("Wasm/types.zig"); | 33 | const Type = @import("../type.zig").Type; |
| 34 | const TypedValue = @import("../TypedValue.zig"); | ||
| 35 | const Value = @import("../value.zig").Value; | ||
| 36 | const ZigObject = @import("Wasm/ZigObject.zig"); | ||
| 37 | |||
| 38 | pub const Atom = @import("Wasm/Atom.zig"); | ||
| 35 | pub const Relocation = types.Relocation; | 39 | pub const Relocation = types.Relocation; |
| 36 | 40 | ||
| 37 | pub const base_tag: link.File.Tag = .wasm; | 41 | pub const base_tag: link.File.Tag = .wasm; |
| ... | @@ -57,6 +61,11 @@ export_table: bool, | ... | @@ -57,6 +61,11 @@ export_table: bool, |
| 57 | name: []const u8, | 61 | name: []const u8, |
| 58 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. | 62 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| 59 | llvm_object: ?*LlvmObject = null, | 63 | llvm_object: ?*LlvmObject = null, |
| 64 | /// The file index of a `ZigObject`. This will only contain a valid index when a zcu exists, | ||
| 65 | /// and the chosen backend is the Wasm backend. | ||
| 66 | zig_object_index: File.Index = .null, | ||
| 67 | /// List of relocatable files to be linked into the final binary. | ||
| 68 | files: std.MultiArrayList(File.Entry) = .{}, | ||
| 60 | /// When importing objects from the host environment, a name must be supplied. | 69 | /// When importing objects from the host environment, a name must be supplied. |
| 61 | /// LLVM uses "env" by default when none is given. This would be a good default for Zig | 70 | /// LLVM uses "env" by default when none is given. This would be a good default for Zig |
| 62 | /// to support existing code. | 71 | /// to support existing code. |
| ... | @@ -556,9 +565,27 @@ pub fn createEmpty( | ... | @@ -556,9 +565,27 @@ pub fn createEmpty( |
| 556 | } | 565 | } |
| 557 | } | 566 | } |
| 558 | 567 | ||
| 568 | if (comp.module) |zcu| { | ||
| 569 | if (!use_llvm) { | ||
| 570 | const index: File.Index = @enumFromInt(wasm.files.len); | ||
| 571 | var zig_object: ZigObject = .{ | ||
| 572 | .path = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(zcu.main_mod.root_src_path)}), | ||
| 573 | .stack_pointer_sym = undefined, | ||
| 574 | }; | ||
| 575 | try zig_object.init(wasm); | ||
| 576 | try wasm.files.append(gpa, .{ .zig_object = zig_object }); | ||
| 577 | wasm.zig_object_index = index; | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 559 | return wasm; | 581 | return wasm; |
| 560 | } | 582 | } |
| 561 | 583 | ||
| 584 | fn zigObjectPtr(wasm: *Wasm) ?*ZigObject { | ||
| 585 | if (wasm.zig_object_index == .null) return null; | ||
| 586 | return &wasm.files.items(.data)[@intFromEnum(wasm.zig_object_index)].zig_object; | ||
| 587 | } | ||
| 588 | |||
| 562 | /// For a given name, creates a new global synthetic symbol. | 589 | /// For a given name, creates a new global synthetic symbol. |
| 563 | /// Leaves index undefined and the default flags (0). | 590 | /// Leaves index undefined and the default flags (0). |
| 564 | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { | 591 | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { |
src/link/Wasm/ZigObject.zig+34-9| ... | @@ -3,6 +3,7 @@ | ... | @@ -3,6 +3,7 @@ |
| 3 | //! and any relocations that may have been emitted. | 3 | //! and any relocations that may have been emitted. |
| 4 | //! Think about this as fake in-memory Object file for the Zig module. | 4 | //! Think about this as fake in-memory Object file for the Zig module. |
| 5 | 5 | ||
| 6 | path: []const u8, | ||
| 6 | /// List of all `Decl` that are currently alive. | 7 | /// List of all `Decl` that are currently alive. |
| 7 | /// Each index maps to the corresponding `Atom.Index`. | 8 | /// Each index maps to the corresponding `Atom.Index`. |
| 8 | decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{}, | 9 | decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{}, |
| ... | @@ -22,7 +23,7 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{}, | ... | @@ -22,7 +23,7 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{}, |
| 22 | /// List of symbol indexes which are free to be used. | 23 | /// List of symbol indexes which are free to be used. |
| 23 | symbols_free_list: std.ArrayListUnmanaged(u32) = .{}, | 24 | symbols_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 24 | /// Extra metadata about the linking section, such as alignment of segments and their name. | 25 | /// Extra metadata about the linking section, such as alignment of segments and their name. |
| 25 | segment_info: std.ArrayListUnmanage(types.Segment) = &.{}, | 26 | segment_info: std.ArrayListUnmanaged(types.Segment) = .{}, |
| 26 | /// File encapsulated string table, used to deduplicate strings within the generated file. | 27 | /// File encapsulated string table, used to deduplicate strings within the generated file. |
| 27 | string_table: StringTable = .{}, | 28 | string_table: StringTable = .{}, |
| 28 | /// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index. | 29 | /// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index. |
| ... | @@ -72,6 +73,30 @@ debug_str_index: ?u32 = null, | ... | @@ -72,6 +73,30 @@ debug_str_index: ?u32 = null, |
| 72 | /// The index of the segment representing the custom '.debug_pubtypes' section. | 73 | /// The index of the segment representing the custom '.debug_pubtypes' section. |
| 73 | debug_abbrev_index: ?u32 = null, | 74 | debug_abbrev_index: ?u32 = null, |
| 74 | 75 | ||
| 76 | /// Initializes the `ZigObject` with initial symbols. | ||
| 77 | pub fn init(zig_object: *ZigObject, wasm_file: *Wasm) !void { | ||
| 78 | // Initialize an undefined global with the name __stack_pointer. Codegen will use | ||
| 79 | // this to generate relocations when moving the stack pointer. This symbol will be | ||
| 80 | // resolved automatically by the final linking stage. | ||
| 81 | try zig_object.createStackPointer(wasm_file); | ||
| 82 | |||
| 83 | // TODO: Initialize debug information when we reimplement Dwarf support. | ||
| 84 | } | ||
| 85 | |||
| 86 | fn createStackPointer(zig_object: *ZigObject, wasm_file: *Wasm) !void { | ||
| 87 | const gpa = wasm_file.base.comp.gpa; | ||
| 88 | const sym_index = try zig_object.getGlobalSymbol(gpa, "__stack_pointer", .global); | ||
| 89 | zig_object.symbols.items[sym_index].index = zig_object.imported_globals_count; | ||
| 90 | const is_wasm32 = wasm_file.base.comp.root_mod.resolved_target.result.cpu.arch == .wasm32; | ||
| 91 | try zig_object.imports.putNoClobber(gpa, sym_index, .{ | ||
| 92 | .name = zig_object.symbols.items[sym_index].name, | ||
| 93 | .module_name = try zig_object.string_table.insert(gpa, wasm_file.host_name), | ||
| 94 | .kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } }, | ||
| 95 | }); | ||
| 96 | zig_object.imported_globals_count += 1; | ||
| 97 | zig_object.stack_pointer_sym = sym_index; | ||
| 98 | } | ||
| 99 | |||
| 75 | /// Frees and invalidates all memory of the incrementally compiled Zig module. | 100 | /// Frees and invalidates all memory of the incrementally compiled Zig module. |
| 76 | /// It is illegal behavior to access the `ZigObject` after calling `deinit`. | 101 | /// It is illegal behavior to access the `ZigObject` after calling `deinit`. |
| 77 | pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void { | 102 | pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void { |
| ... | @@ -113,6 +138,7 @@ pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void { | ... | @@ -113,6 +138,7 @@ pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void { |
| 113 | if (zig_object.dwarf) |*dwarf| { | 138 | if (zig_object.dwarf) |*dwarf| { |
| 114 | dwarf.deinit(); | 139 | dwarf.deinit(); |
| 115 | } | 140 | } |
| 141 | gpa.free(zig_object.path); | ||
| 116 | zig_object.* = undefined; | 142 | zig_object.* = undefined; |
| 117 | } | 143 | } |
| 118 | 144 | ||
| ... | @@ -531,32 +557,31 @@ pub fn addOrUpdateImport( | ... | @@ -531,32 +557,31 @@ pub fn addOrUpdateImport( |
| 531 | /// such as an exported or imported symbol. | 557 | /// such as an exported or imported symbol. |
| 532 | /// If the symbol does not yet exist, creates a new one symbol instead | 558 | /// If the symbol does not yet exist, creates a new one symbol instead |
| 533 | /// and then returns the index to it. | 559 | /// and then returns the index to it. |
| 534 | pub fn getGlobalSymbol(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8) !u32 { | 560 | pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []const u8, tag: Symbol.Tag) !u32 { |
| 535 | const gpa = wasm_file.base.comp.gpa; | ||
| 536 | const name_index = try zig_object.string_table.insert(gpa, name); | 561 | const name_index = try zig_object.string_table.insert(gpa, name); |
| 537 | const gop = try zig_object.global_syms.getOrPut(gpa, name_index); | 562 | const gop = try zig_object.global_syms.getOrPut(gpa, name_index); |
| 538 | if (gop.found_existing) { | 563 | if (gop.found_existing) { |
| 539 | return gop.value_ptr.index; | 564 | return gop.value_ptr.*; |
| 540 | } | 565 | } |
| 541 | 566 | ||
| 542 | var symbol: Symbol = .{ | 567 | var symbol: Symbol = .{ |
| 543 | .name = name_index, | 568 | .name = name_index, |
| 544 | .flags = 0, | 569 | .flags = 0, |
| 545 | .index = undefined, // index to type will be set after merging function symbols | 570 | .index = undefined, // index to type will be set after merging symbols |
| 546 | .tag = .function, | 571 | .tag = tag, |
| 547 | .virtual_address = undefined, | 572 | .virtual_address = std.math.maxInt(u32), |
| 548 | }; | 573 | }; |
| 549 | symbol.setGlobal(true); | 574 | symbol.setGlobal(true); |
| 550 | symbol.setUndefined(true); | 575 | symbol.setUndefined(true); |
| 551 | 576 | ||
| 552 | const sym_index = if (zig_object.symbol.popOrNull()) |index| index else blk: { | 577 | const sym_index = if (zig_object.symbols_free_list.popOrNull()) |index| index else blk: { |
| 553 | const index: u32 = @intCast(zig_object.symbols.items.len); | 578 | const index: u32 = @intCast(zig_object.symbols.items.len); |
| 554 | try zig_object.symbols.ensureUnusedCapacity(gpa, 1); | 579 | try zig_object.symbols.ensureUnusedCapacity(gpa, 1); |
| 555 | zig_object.symbols.items.len += 1; | 580 | zig_object.symbols.items.len += 1; |
| 556 | break :blk index; | 581 | break :blk index; |
| 557 | }; | 582 | }; |
| 558 | zig_object.symbols.items[sym_index] = symbol; | 583 | zig_object.symbols.items[sym_index] = symbol; |
| 559 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; | 584 | gop.value_ptr.* = sym_index; |
| 560 | return sym_index; | 585 | return sym_index; |
| 561 | } | 586 | } |
| 562 | 587 |