| 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 | 1 | const Wasm = @This(); |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | const builtin = @import("builtin"); | |
| 5 | const mem = std.mem; | |
| 6 | const Allocator = std.mem.Allocator; | |
| 4 | ||
| 7 | 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 | 9 | const fs = std.fs; |
| 9 | 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 | 11 | const link = @import("../link.zig"); |
| 20 | 12 | const lldMain = @import("../main.zig").lldMain; |
| 13 | const log = std.log.scoped(.link); | |
| 14 | const mem = std.mem; | |
| 21 | 15 | const trace = @import("../tracy.zig").trace; |
| 22 | const build_options = @import("build_options"); | |
| 16 | const types = @import("Wasm/types.zig"); | |
| 23 | 17 | const wasi_libc = @import("../wasi_libc.zig"); |
| 24 | const Cache = std.Build.Cache; | |
| 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; | |
| 18 | ||
| 29 | 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 | 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 | 31 | const Object = @import("Wasm/Object.zig"); |
| 33 | const Archive = @import("Wasm/Archive.zig"); | |
| 34 | const types = @import("Wasm/types.zig"); | |
| 32 | const Symbol = @import("Wasm/Symbol.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 | 39 | pub const Relocation = types.Relocation; |
| 36 | 40 | |
| 37 | 41 | pub const base_tag: link.File.Tag = .wasm; |
| ... | ... | @@ -57,6 +61,11 @@ export_table: bool, |
| 57 | 61 | name: []const u8, |
| 58 | 62 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| 59 | 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 | 69 | /// When importing objects from the host environment, a name must be supplied. |
| 61 | 70 | /// LLVM uses "env" by default when none is given. This would be a good default for Zig |
| 62 | 71 | /// to support existing code. |
| ... | ... | @@ -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 | 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 | 589 | /// For a given name, creates a new global synthetic symbol. |
| 563 | 590 | /// Leaves index undefined and the default flags (0). |
| 564 | 591 | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { |
src/link/Wasm/ZigObject.zig+34-9| ... | ... | @@ -3,6 +3,7 @@ |
| 3 | 3 | //! and any relocations that may have been emitted. |
| 4 | 4 | //! Think about this as fake in-memory Object file for the Zig module. |
| 5 | 5 | |
| 6 | path: []const u8, | |
| 6 | 7 | /// List of all `Decl` that are currently alive. |
| 7 | 8 | /// Each index maps to the corresponding `Atom.Index`. |
| 8 | 9 | decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{}, |
| ... | ... | @@ -22,7 +23,7 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{}, |
| 22 | 23 | /// List of symbol indexes which are free to be used. |
| 23 | 24 | symbols_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 24 | 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 | 27 | /// File encapsulated string table, used to deduplicate strings within the generated file. |
| 27 | 28 | string_table: StringTable = .{}, |
| 28 | 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 | 73 | /// The index of the segment representing the custom '.debug_pubtypes' section. |
| 73 | 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 | 100 | /// Frees and invalidates all memory of the incrementally compiled Zig module. |
| 76 | 101 | /// It is illegal behavior to access the `ZigObject` after calling `deinit`. |
| 77 | 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 | 138 | if (zig_object.dwarf) |*dwarf| { |
| 114 | 139 | dwarf.deinit(); |
| 115 | 140 | } |
| 141 | gpa.free(zig_object.path); | |
| 116 | 142 | zig_object.* = undefined; |
| 117 | 143 | } |
| 118 | 144 | |
| ... | ... | @@ -531,32 +557,31 @@ pub fn addOrUpdateImport( |
| 531 | 557 | /// such as an exported or imported symbol. |
| 532 | 558 | /// If the symbol does not yet exist, creates a new one symbol instead |
| 533 | 559 | /// and then returns the index to it. |
| 534 | pub fn getGlobalSymbol(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8) !u32 { | |
| 535 | const gpa = wasm_file.base.comp.gpa; | |
| 560 | pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []const u8, tag: Symbol.Tag) !u32 { | |
| 536 | 561 | const name_index = try zig_object.string_table.insert(gpa, name); |
| 537 | 562 | const gop = try zig_object.global_syms.getOrPut(gpa, name_index); |
| 538 | 563 | if (gop.found_existing) { |
| 539 | return gop.value_ptr.index; | |
| 564 | return gop.value_ptr.*; | |
| 540 | 565 | } |
| 541 | 566 | |
| 542 | 567 | var symbol: Symbol = .{ |
| 543 | 568 | .name = name_index, |
| 544 | 569 | .flags = 0, |
| 545 | .index = undefined, // index to type will be set after merging function symbols | |
| 546 | .tag = .function, | |
| 547 | .virtual_address = undefined, | |
| 570 | .index = undefined, // index to type will be set after merging symbols | |
| 571 | .tag = tag, | |
| 572 | .virtual_address = std.math.maxInt(u32), | |
| 548 | 573 | }; |
| 549 | 574 | symbol.setGlobal(true); |
| 550 | 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 | 578 | const index: u32 = @intCast(zig_object.symbols.items.len); |
| 554 | 579 | try zig_object.symbols.ensureUnusedCapacity(gpa, 1); |
| 555 | 580 | zig_object.symbols.items.len += 1; |
| 556 | 581 | break :blk index; |
| 557 | 582 | }; |
| 558 | 583 | zig_object.symbols.items[sym_index] = symbol; |
| 559 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; | |
| 584 | gop.value_ptr.* = sym_index; | |
| 560 | 585 | return sym_index; |
| 561 | 586 | } |
| 562 | 587 |