| ... | @@ -15,7 +15,6 @@ const log = std.log.scoped(.link); | ... | @@ -15,7 +15,6 @@ const log = std.log.scoped(.link); |
| 15 | const gc_log = std.log.scoped(.gc); | 15 | const gc_log = std.log.scoped(.gc); |
| 16 | const mem = std.mem; | 16 | const mem = std.mem; |
| 17 | const trace = @import("../tracy.zig").trace; | 17 | const trace = @import("../tracy.zig").trace; |
| 18 | const types = @import("Wasm/types.zig"); | | |
| 19 | const wasi_libc = @import("../wasi_libc.zig"); | 18 | const wasi_libc = @import("../wasi_libc.zig"); |
| 20 | | 19 | |
| 21 | const Air = @import("../Air.zig"); | 20 | const Air = @import("../Air.zig"); |
| ... | @@ -26,7 +25,6 @@ const Path = Cache.Path; | ... | @@ -26,7 +25,6 @@ const Path = Cache.Path; |
| 26 | const CodeGen = @import("../arch/wasm/CodeGen.zig"); | 25 | const CodeGen = @import("../arch/wasm/CodeGen.zig"); |
| 27 | const Compilation = @import("../Compilation.zig"); | 26 | const Compilation = @import("../Compilation.zig"); |
| 28 | const Dwarf = @import("Dwarf.zig"); | 27 | const Dwarf = @import("Dwarf.zig"); |
| 29 | const File = @import("Wasm/file.zig").File; | | |
| 30 | const InternPool = @import("../InternPool.zig"); | 28 | const InternPool = @import("../InternPool.zig"); |
| 31 | const Liveness = @import("../Liveness.zig"); | 29 | const Liveness = @import("../Liveness.zig"); |
| 32 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 30 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| ... | @@ -37,9 +35,6 @@ const Type = @import("../Type.zig"); | ... | @@ -37,9 +35,6 @@ const Type = @import("../Type.zig"); |
| 37 | const Value = @import("../Value.zig"); | 35 | const Value = @import("../Value.zig"); |
| 38 | const ZigObject = @import("Wasm/ZigObject.zig"); | 36 | const ZigObject = @import("Wasm/ZigObject.zig"); |
| 39 | | 37 | |
| 40 | pub const Atom = @import("Wasm/Atom.zig"); | | |
| 41 | pub const Relocation = types.Relocation; | | |
| 42 | | | |
| 43 | base: link.File, | 38 | base: link.File, |
| 44 | /// Symbol name of the entry function to export | 39 | /// Symbol name of the entry function to export |
| 45 | entry_name: ?[]const u8, | 40 | entry_name: ?[]const u8, |
| ... | @@ -61,11 +56,9 @@ export_table: bool, | ... | @@ -61,11 +56,9 @@ export_table: bool, |
| 61 | name: []const u8, | 56 | name: []const u8, |
| 62 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. | 57 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| 63 | llvm_object: ?LlvmObject.Ptr = null, | 58 | llvm_object: ?LlvmObject.Ptr = null, |
| 64 | /// The file index of a `ZigObject`. This will only contain a valid index when a zcu exists, | 59 | zig_object: ?*ZigObject, |
| 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. | 60 | /// List of relocatable files to be linked into the final binary. |
| 68 | files: std.MultiArrayList(File.Entry) = .{}, | 61 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| 69 | /// When importing objects from the host environment, a name must be supplied. | 62 | /// When importing objects from the host environment, a name must be supplied. |
| 70 | /// LLVM uses "env" by default when none is given. This would be a good default for Zig | 63 | /// LLVM uses "env" by default when none is given. This would be a good default for Zig |
| 71 | /// to support existing code. | 64 | /// to support existing code. |
| ... | @@ -105,17 +98,17 @@ imported_globals_count: u32 = 0, | ... | @@ -105,17 +98,17 @@ imported_globals_count: u32 = 0, |
| 105 | /// The count of imported tables. This number will be appended | 98 | /// The count of imported tables. This number will be appended |
| 106 | /// to the table indexes when sections are merged. | 99 | /// to the table indexes when sections are merged. |
| 107 | imported_tables_count: u32 = 0, | 100 | imported_tables_count: u32 = 0, |
| 108 | /// Map of symbol locations, represented by its `types.Import` | 101 | /// Map of symbol locations, represented by its `Import` |
| 109 | imports: std.AutoHashMapUnmanaged(SymbolLoc, types.Import) = .empty, | 102 | imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty, |
| 110 | /// Represents non-synthetic section entries. | 103 | /// Represents non-synthetic section entries. |
| 111 | /// Used for code, data and custom sections. | 104 | /// Used for code, data and custom sections. |
| 112 | segments: std.ArrayListUnmanaged(Segment) = .empty, | 105 | segments: std.ArrayListUnmanaged(Segment) = .empty, |
| 113 | /// Maps a data segment key (such as .rodata) to the index into `segments`. | 106 | /// Maps a data segment key (such as .rodata) to the index into `segments`. |
| 114 | data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty, | 107 | data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty, |
| 115 | /// A table of `types.Segment` which provide meta data | 108 | /// A table of `NamedSegment` which provide meta data |
| 116 | /// about a data symbol such as its name where the key is | 109 | /// about a data symbol such as its name where the key is |
| 117 | /// the segment index, which can be found from `data_segments` | 110 | /// the segment index, which can be found from `data_segments` |
| 118 | segment_info: std.AutoArrayHashMapUnmanaged(u32, types.Segment) = .empty, | 111 | segment_info: std.AutoArrayHashMapUnmanaged(u32, NamedSegment) = .empty, |
| 119 | /// Deduplicated string table for strings used by symbols, imports and exports. | 112 | /// Deduplicated string table for strings used by symbols, imports and exports. |
| 120 | string_table: StringTable = .{}, | 113 | string_table: StringTable = .{}, |
| 121 | | 114 | |
| ... | @@ -126,8 +119,15 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .empty, | ... | @@ -126,8 +119,15 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .empty, |
| 126 | /// function index and the value is function. | 119 | /// function index and the value is function. |
| 127 | /// This allows us to map multiple symbols to the same function. | 120 | /// This allows us to map multiple symbols to the same function. |
| 128 | functions: std.AutoArrayHashMapUnmanaged( | 121 | functions: std.AutoArrayHashMapUnmanaged( |
| 129 | struct { file: File.Index, index: u32 }, | 122 | struct { |
| 130 | struct { func: std.wasm.Func, sym_index: Symbol.Index }, | 123 | /// `none` in the case of synthetic sections. |
| | 124 | file: OptionalObjectId, |
| | 125 | index: u32, |
| | 126 | }, |
| | 127 | struct { |
| | 128 | func: std.wasm.Func, |
| | 129 | sym_index: Symbol.Index, |
| | 130 | }, |
| 131 | ) = .{}, | 131 | ) = .{}, |
| 132 | /// Output global section | 132 | /// Output global section |
| 133 | wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty, | 133 | wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty, |
| ... | @@ -140,7 +140,7 @@ memories: std.wasm.Memory = .{ .limits = .{ | ... | @@ -140,7 +140,7 @@ memories: std.wasm.Memory = .{ .limits = .{ |
| 140 | /// Output table section | 140 | /// Output table section |
| 141 | tables: std.ArrayListUnmanaged(std.wasm.Table) = .empty, | 141 | tables: std.ArrayListUnmanaged(std.wasm.Table) = .empty, |
| 142 | /// Output export section | 142 | /// Output export section |
| 143 | exports: std.ArrayListUnmanaged(types.Export) = .empty, | 143 | exports: std.ArrayListUnmanaged(Export) = .empty, |
| 144 | /// List of initialization functions. These must be called in order of priority | 144 | /// List of initialization functions. These must be called in order of priority |
| 145 | /// by the (synthetic) __wasm_call_ctors function. | 145 | /// by the (synthetic) __wasm_call_ctors function. |
| 146 | init_funcs: std.ArrayListUnmanaged(InitFuncLoc) = .empty, | 146 | init_funcs: std.ArrayListUnmanaged(InitFuncLoc) = .empty, |
| ... | @@ -154,8 +154,6 @@ entry: ?u32 = null, | ... | @@ -154,8 +154,6 @@ entry: ?u32 = null, |
| 154 | /// Note: Key is symbol location, value represents the index into the table | 154 | /// Note: Key is symbol location, value represents the index into the table |
| 155 | function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty, | 155 | function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty, |
| 156 | | 156 | |
| 157 | /// All object files and their data which are linked into the final binary | | |
| 158 | objects: std.ArrayListUnmanaged(File.Index) = .empty, | | |
| 159 | /// All archive files that are lazy loaded. | 157 | /// All archive files that are lazy loaded. |
| 160 | /// e.g. when an undefined symbol references a symbol from the archive. | 158 | /// e.g. when an undefined symbol references a symbol from the archive. |
| 161 | archives: std.ArrayListUnmanaged(Archive) = .empty, | 159 | archives: std.ArrayListUnmanaged(Archive) = .empty, |
| ... | @@ -178,7 +176,29 @@ undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty, | ... | @@ -178,7 +176,29 @@ undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty, |
| 178 | /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. | 176 | /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. |
| 179 | symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty, | 177 | symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty, |
| 180 | | 178 | |
| 181 | pub const Alignment = types.Alignment; | 179 | /// Index into objects array or the zig object. |
| | 180 | pub const ObjectId = enum(u16) { |
| | 181 | zig_object = std.math.maxInt(u16) - 1, |
| | 182 | _, |
| | 183 | |
| | 184 | pub fn toOptional(i: ObjectId) OptionalObjectId { |
| | 185 | const result: OptionalObjectId = @enumFromInt(@intFromEnum(i)); |
| | 186 | assert(result != .none); |
| | 187 | return result; |
| | 188 | } |
| | 189 | }; |
| | 190 | |
| | 191 | /// Optional index into objects array or the zig object. |
| | 192 | pub const OptionalObjectId = enum(u16) { |
| | 193 | zig_object = std.math.maxInt(u16) - 1, |
| | 194 | none = std.math.maxInt(u16), |
| | 195 | _, |
| | 196 | |
| | 197 | pub fn unwrap(i: OptionalObjectId) ?ObjectId { |
| | 198 | if (i == .none) return null; |
| | 199 | return @enumFromInt(@intFromEnum(i)); |
| | 200 | } |
| | 201 | }; |
| 182 | | 202 | |
| 183 | pub const Segment = struct { | 203 | pub const Segment = struct { |
| 184 | alignment: Alignment, | 204 | alignment: Alignment, |
| ... | @@ -208,43 +228,55 @@ pub const SymbolLoc = struct { | ... | @@ -208,43 +228,55 @@ pub const SymbolLoc = struct { |
| 208 | /// The index of the symbol within the specified file | 228 | /// The index of the symbol within the specified file |
| 209 | index: Symbol.Index, | 229 | index: Symbol.Index, |
| 210 | /// The index of the object file where the symbol resides. | 230 | /// The index of the object file where the symbol resides. |
| 211 | file: File.Index, | 231 | file: OptionalObjectId, |
| | 232 | }; |
| 212 | | 233 | |
| 213 | /// From a given location, returns the corresponding symbol in the wasm binary | 234 | /// From a given location, returns the corresponding symbol in the wasm binary |
| 214 | pub fn getSymbol(loc: SymbolLoc, wasm_file: *const Wasm) *Symbol { | 235 | pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol { |
| 215 | if (wasm_file.discarded.get(loc)) |new_loc| { | 236 | if (wasm.discarded.get(loc)) |new_loc| { |
| 216 | return new_loc.getSymbol(wasm_file); | 237 | return symbolLocSymbol(wasm, new_loc); |
| 217 | } | | |
| 218 | if (wasm_file.file(loc.file)) |obj_file| { | | |
| 219 | return obj_file.symbol(loc.index); | | |
| 220 | } | | |
| 221 | return &wasm_file.synthetic_symbols.items[@intFromEnum(loc.index)]; | | |
| 222 | } | 238 | } |
| | 239 | return switch (loc.file) { |
| | 240 | .none => &wasm.synthetic_symbols.items[@intFromEnum(loc.index)], |
| | 241 | .zig_object => wasm.zig_object.?.symbol(loc.index), |
| | 242 | _ => &wasm.objects.items[@intFromEnum(loc.file)].symtable[@intFromEnum(loc.index)], |
| | 243 | }; |
| | 244 | } |
| 223 | | 245 | |
| 224 | /// From a given location, returns the name of the symbol. | 246 | /// From a given location, returns the name of the symbol. |
| 225 | pub fn getName(loc: SymbolLoc, wasm_file: *const Wasm) []const u8 { | 247 | pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) []const u8 { |
| 226 | if (wasm_file.discarded.get(loc)) |new_loc| { | 248 | if (wasm.discarded.get(loc)) |new_loc| { |
| 227 | return new_loc.getName(wasm_file); | 249 | return wasm.symbolLocName(new_loc); |
| 228 | } | 250 | } |
| 229 | if (wasm_file.file(loc.file)) |obj_file| { | 251 | switch (loc.file) { |
| 230 | return obj_file.symbolName(loc.index); | 252 | .none => { |
| 231 | } | 253 | const sym = wasm.synthetic_symbols.items[@intFromEnum(loc.index)]; |
| 232 | const sym = wasm_file.synthetic_symbols.items[@intFromEnum(loc.index)]; | 254 | return wasm.string_table.get(sym.name); |
| 233 | return wasm_file.string_table.get(sym.name); | 255 | }, |
| | 256 | .zig_object => { |
| | 257 | const zo = wasm.zig_object.?; |
| | 258 | const sym = zo.symbols.items[@intFromEnum(loc.index)]; |
| | 259 | return zo.string_table.get(sym.name).?; |
| | 260 | }, |
| | 261 | _ => { |
| | 262 | const obj = &wasm.objects.items[@intFromEnum(loc.file)]; |
| | 263 | const sym = obj.symtable[@intFromEnum(loc.index)]; |
| | 264 | return obj.string_table.get(sym.name); |
| | 265 | }, |
| 234 | } | 266 | } |
| | 267 | } |
| 235 | | 268 | |
| 236 | /// From a given symbol location, returns the final location. | 269 | /// From a given symbol location, returns the final location. |
| 237 | /// e.g. when a symbol was resolved and replaced by the symbol | 270 | /// e.g. when a symbol was resolved and replaced by the symbol |
| 238 | /// in a different file, this will return said location. | 271 | /// in a different file, this will return said location. |
| 239 | /// If the symbol wasn't replaced by another, this will return | 272 | /// If the symbol wasn't replaced by another, this will return |
| 240 | /// the given location itwasm. | 273 | /// the given location itwasm. |
| 241 | pub fn finalLoc(loc: SymbolLoc, wasm_file: *const Wasm) SymbolLoc { | 274 | pub fn symbolLocFinalLoc(wasm: *const Wasm, loc: SymbolLoc) SymbolLoc { |
| 242 | if (wasm_file.discarded.get(loc)) |new_loc| { | 275 | if (wasm.discarded.get(loc)) |new_loc| { |
| 243 | return new_loc.finalLoc(wasm_file); | 276 | return symbolLocFinalLoc(wasm, new_loc); |
| 244 | } | | |
| 245 | return loc; | | |
| 246 | } | 277 | } |
| 247 | }; | 278 | return loc; |
| | 279 | } |
| 248 | | 280 | |
| 249 | // Contains the location of the function symbol, as well as | 281 | // Contains the location of the function symbol, as well as |
| 250 | /// the priority itself of the initialization function. | 282 | /// the priority itself of the initialization function. |
| ... | @@ -252,7 +284,7 @@ pub const InitFuncLoc = struct { | ... | @@ -252,7 +284,7 @@ pub const InitFuncLoc = struct { |
| 252 | /// object file index in the list of objects. | 284 | /// object file index in the list of objects. |
| 253 | /// Unlike `SymbolLoc` this cannot be `null` as we never define | 285 | /// Unlike `SymbolLoc` this cannot be `null` as we never define |
| 254 | /// our own ctors. | 286 | /// our own ctors. |
| 255 | file: File.Index, | 287 | file: ObjectId, |
| 256 | /// Symbol index within the corresponding object file. | 288 | /// Symbol index within the corresponding object file. |
| 257 | index: Symbol.Index, | 289 | index: Symbol.Index, |
| 258 | /// The priority in which the constructor must be called. | 290 | /// The priority in which the constructor must be called. |
| ... | @@ -260,12 +292,15 @@ pub const InitFuncLoc = struct { | ... | @@ -260,12 +292,15 @@ pub const InitFuncLoc = struct { |
| 260 | | 292 | |
| 261 | /// From a given `InitFuncLoc` returns the corresponding function symbol | 293 | /// From a given `InitFuncLoc` returns the corresponding function symbol |
| 262 | fn getSymbol(loc: InitFuncLoc, wasm: *const Wasm) *Symbol { | 294 | fn getSymbol(loc: InitFuncLoc, wasm: *const Wasm) *Symbol { |
| 263 | return getSymbolLoc(loc).getSymbol(wasm); | 295 | return wasm.symbolLocSymbol(getSymbolLoc(loc)); |
| 264 | } | 296 | } |
| 265 | | 297 | |
| 266 | /// Turns the given `InitFuncLoc` into a `SymbolLoc` | 298 | /// Turns the given `InitFuncLoc` into a `SymbolLoc` |
| 267 | fn getSymbolLoc(loc: InitFuncLoc) SymbolLoc { | 299 | fn getSymbolLoc(loc: InitFuncLoc) SymbolLoc { |
| 268 | return .{ .file = loc.file, .index = loc.index }; | 300 | return .{ |
| | 301 | .file = loc.file.toOptional(), |
| | 302 | .index = loc.index, |
| | 303 | }; |
| 269 | } | 304 | } |
| 270 | | 305 | |
| 271 | /// Returns true when `lhs` has a higher priority (e.i. value closer to 0) than `rhs`. | 306 | /// Returns true when `lhs` has a higher priority (e.i. value closer to 0) than `rhs`. |
| ... | @@ -307,7 +342,7 @@ pub const StringTable = struct { | ... | @@ -307,7 +342,7 @@ pub const StringTable = struct { |
| 307 | } | 342 | } |
| 308 | | 343 | |
| 309 | try table.string_data.ensureUnusedCapacity(allocator, string.len + 1); | 344 | try table.string_data.ensureUnusedCapacity(allocator, string.len + 1); |
| 310 | const offset = @as(u32, @intCast(table.string_data.items.len)); | 345 | const offset: u32 = @intCast(table.string_data.items.len); |
| 311 | | 346 | |
| 312 | log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset }); | 347 | log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset }); |
| 313 | | 348 | |
| ... | @@ -414,6 +449,7 @@ pub fn createEmpty( | ... | @@ -414,6 +449,7 @@ pub fn createEmpty( |
| 414 | .enabled => defaultEntrySymbolName(wasi_exec_model), | 449 | .enabled => defaultEntrySymbolName(wasi_exec_model), |
| 415 | .named => |name| name, | 450 | .named => |name| name, |
| 416 | }, | 451 | }, |
| | 452 | .zig_object = null, |
| 417 | }; | 453 | }; |
| 418 | if (use_llvm and comp.config.have_zcu) { | 454 | if (use_llvm and comp.config.have_zcu) { |
| 419 | wasm.llvm_object = try LlvmObject.create(arena, comp); | 455 | wasm.llvm_object = try LlvmObject.create(arena, comp); |
| ... | @@ -446,7 +482,7 @@ pub fn createEmpty( | ... | @@ -446,7 +482,7 @@ pub fn createEmpty( |
| 446 | // create stack pointer symbol | 482 | // create stack pointer symbol |
| 447 | { | 483 | { |
| 448 | const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global); | 484 | const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global); |
| 449 | const symbol = loc.getSymbol(wasm); | 485 | const symbol = wasm.symbolLocSymbol(loc); |
| 450 | // For object files we will import the stack pointer symbol | 486 | // For object files we will import the stack pointer symbol |
| 451 | if (output_mode == .Obj) { | 487 | if (output_mode == .Obj) { |
| 452 | symbol.setUndefined(true); | 488 | symbol.setUndefined(true); |
| ... | @@ -478,7 +514,7 @@ pub fn createEmpty( | ... | @@ -478,7 +514,7 @@ pub fn createEmpty( |
| 478 | // create indirect function pointer symbol | 514 | // create indirect function pointer symbol |
| 479 | { | 515 | { |
| 480 | const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table); | 516 | const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table); |
| 481 | const symbol = loc.getSymbol(wasm); | 517 | const symbol = wasm.symbolLocSymbol(loc); |
| 482 | const table: std.wasm.Table = .{ | 518 | const table: std.wasm.Table = .{ |
| 483 | .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable` | 519 | .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable` |
| 484 | .reftype = .funcref, | 520 | .reftype = .funcref, |
| ... | @@ -506,7 +542,7 @@ pub fn createEmpty( | ... | @@ -506,7 +542,7 @@ pub fn createEmpty( |
| 506 | // create __wasm_call_ctors | 542 | // create __wasm_call_ctors |
| 507 | { | 543 | { |
| 508 | const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function); | 544 | const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function); |
| 509 | const symbol = loc.getSymbol(wasm); | 545 | const symbol = wasm.symbolLocSymbol(loc); |
| 510 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 546 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 511 | // we do not know the function index until after we merged all sections. | 547 | // we do not know the function index until after we merged all sections. |
| 512 | // Therefore we set `symbol.index` and create its corresponding references | 548 | // Therefore we set `symbol.index` and create its corresponding references |
| ... | @@ -517,7 +553,7 @@ pub fn createEmpty( | ... | @@ -517,7 +553,7 @@ pub fn createEmpty( |
| 517 | if (shared_memory) { | 553 | if (shared_memory) { |
| 518 | { | 554 | { |
| 519 | const loc = try wasm.createSyntheticSymbol("__tls_base", .global); | 555 | const loc = try wasm.createSyntheticSymbol("__tls_base", .global); |
| 520 | const symbol = loc.getSymbol(wasm); | 556 | const symbol = wasm.symbolLocSymbol(loc); |
| 521 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 557 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 522 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); | 558 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| 523 | symbol.mark(); | 559 | symbol.mark(); |
| ... | @@ -528,7 +564,7 @@ pub fn createEmpty( | ... | @@ -528,7 +564,7 @@ pub fn createEmpty( |
| 528 | } | 564 | } |
| 529 | { | 565 | { |
| 530 | const loc = try wasm.createSyntheticSymbol("__tls_size", .global); | 566 | const loc = try wasm.createSyntheticSymbol("__tls_size", .global); |
| 531 | const symbol = loc.getSymbol(wasm); | 567 | const symbol = wasm.symbolLocSymbol(loc); |
| 532 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 568 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 533 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); | 569 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| 534 | symbol.mark(); | 570 | symbol.mark(); |
| ... | @@ -539,7 +575,7 @@ pub fn createEmpty( | ... | @@ -539,7 +575,7 @@ pub fn createEmpty( |
| 539 | } | 575 | } |
| 540 | { | 576 | { |
| 541 | const loc = try wasm.createSyntheticSymbol("__tls_align", .global); | 577 | const loc = try wasm.createSyntheticSymbol("__tls_align", .global); |
| 542 | const symbol = loc.getSymbol(wasm); | 578 | const symbol = wasm.symbolLocSymbol(loc); |
| 543 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 579 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 544 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); | 580 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| 545 | symbol.mark(); | 581 | symbol.mark(); |
| ... | @@ -550,42 +586,26 @@ pub fn createEmpty( | ... | @@ -550,42 +586,26 @@ pub fn createEmpty( |
| 550 | } | 586 | } |
| 551 | { | 587 | { |
| 552 | const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function); | 588 | const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function); |
| 553 | const symbol = loc.getSymbol(wasm); | 589 | const symbol = wasm.symbolLocSymbol(loc); |
| 554 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 590 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 555 | } | 591 | } |
| 556 | } | 592 | } |
| 557 | | 593 | |
| 558 | if (comp.zcu) |zcu| { | 594 | if (comp.zcu) |zcu| { |
| 559 | if (!use_llvm) { | 595 | if (!use_llvm) { |
| 560 | const index: File.Index = @enumFromInt(wasm.files.len); | 596 | const zig_object = try arena.create(ZigObject); |
| 561 | var zig_object: ZigObject = .{ | 597 | wasm.zig_object = zig_object; |
| 562 | .index = index, | 598 | zig_object.* = .{ |
| 563 | .path = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(zcu.main_mod.root_src_path)}), | 599 | .path = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(zcu.main_mod.root_src_path)}), |
| 564 | .stack_pointer_sym = .null, | 600 | .stack_pointer_sym = .null, |
| 565 | }; | 601 | }; |
| 566 | try zig_object.init(wasm); | 602 | try zig_object.init(wasm); |
| 567 | try wasm.files.append(gpa, .{ .zig_object = zig_object }); | | |
| 568 | wasm.zig_object_index = index; | | |
| 569 | } | 603 | } |
| 570 | } | 604 | } |
| 571 | | 605 | |
| 572 | return wasm; | 606 | return wasm; |
| 573 | } | 607 | } |
| 574 | | 608 | |
| 575 | pub fn file(wasm: *const Wasm, index: File.Index) ?File { | | |
| 576 | if (index == .null) return null; | | |
| 577 | const tag = wasm.files.items(.tags)[@intFromEnum(index)]; | | |
| 578 | return switch (tag) { | | |
| 579 | .zig_object => .{ .zig_object = &wasm.files.items(.data)[@intFromEnum(index)].zig_object }, | | |
| 580 | .object => .{ .object = &wasm.files.items(.data)[@intFromEnum(index)].object }, | | |
| 581 | }; | | |
| 582 | } | | |
| 583 | | | |
| 584 | pub 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 | | | |
| 589 | pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 { | 609 | pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 { |
| 590 | var index: u32 = 0; | 610 | var index: u32 = 0; |
| 591 | while (index < wasm.func_types.items.len) : (index += 1) { | 611 | while (index < wasm.func_types.items.len) : (index += 1) { |
| ... | @@ -610,7 +630,7 @@ pub fn addOrUpdateImport( | ... | @@ -610,7 +630,7 @@ pub fn addOrUpdateImport( |
| 610 | /// is asserted instead. | 630 | /// is asserted instead. |
| 611 | type_index: ?u32, | 631 | type_index: ?u32, |
| 612 | ) !void { | 632 | ) !void { |
| 613 | return wasm.zigObjectPtr().?.addOrUpdateImport(wasm, name, symbol_index, lib_name, type_index); | 633 | return wasm.zig_object.?.addOrUpdateImport(wasm, name, symbol_index, lib_name, type_index); |
| 614 | } | 634 | } |
| 615 | | 635 | |
| 616 | /// For a given name, creates a new global synthetic symbol. | 636 | /// For a given name, creates a new global synthetic symbol. |
| ... | @@ -623,7 +643,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol | ... | @@ -623,7 +643,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol |
| 623 | | 643 | |
| 624 | fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc { | 644 | fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc { |
| 625 | const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len); | 645 | const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len); |
| 626 | const loc: SymbolLoc = .{ .index = sym_index, .file = .null }; | 646 | const loc: SymbolLoc = .{ .index = sym_index, .file = .none }; |
| 627 | const gpa = wasm.base.comp.gpa; | 647 | const gpa = wasm.base.comp.gpa; |
| 628 | try wasm.synthetic_symbols.append(gpa, .{ | 648 | try wasm.synthetic_symbols.append(gpa, .{ |
| 629 | .name = name_offset, | 649 | .name = name_offset, |
| ... | @@ -657,28 +677,29 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool { | ... | @@ -657,28 +677,29 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool { |
| 657 | }, | 677 | }, |
| 658 | }; | 678 | }; |
| 659 | errdefer object.deinit(gpa); | 679 | errdefer object.deinit(gpa); |
| 660 | object.index = @enumFromInt(wasm.files.len); | 680 | try wasm.objects.append(gpa, object); |
| 661 | try wasm.files.append(gpa, .{ .object = object }); | | |
| 662 | try wasm.objects.append(gpa, object.index); | | |
| 663 | return true; | 681 | return true; |
| 664 | } | 682 | } |
| 665 | | 683 | |
| 666 | /// Creates a new empty `Atom` and returns its `Atom.Index` | 684 | /// Creates a new empty `Atom` and returns its `Atom.Index` |
| 667 | pub fn createAtom(wasm: *Wasm, sym_index: Symbol.Index, file_index: File.Index) !Atom.Index { | 685 | pub fn createAtom(wasm: *Wasm, sym_index: Symbol.Index, object_index: OptionalObjectId) !Atom.Index { |
| 668 | const gpa = wasm.base.comp.gpa; | 686 | const gpa = wasm.base.comp.gpa; |
| 669 | const index: Atom.Index = @enumFromInt(wasm.managed_atoms.items.len); | 687 | const index: Atom.Index = @enumFromInt(wasm.managed_atoms.items.len); |
| 670 | const atom = try wasm.managed_atoms.addOne(gpa); | 688 | const atom = try wasm.managed_atoms.addOne(gpa); |
| 671 | atom.* = .{ .file = file_index, .sym_index = sym_index }; | 689 | atom.* = .{ |
| | 690 | .file = object_index, |
| | 691 | .sym_index = sym_index, |
| | 692 | }; |
| 672 | try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), index); | 693 | try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), index); |
| 673 | | 694 | |
| 674 | return index; | 695 | return index; |
| 675 | } | 696 | } |
| 676 | | 697 | |
| 677 | pub inline fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom { | 698 | pub fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom { |
| 678 | return wasm.managed_atoms.items[@intFromEnum(index)]; | 699 | return wasm.managed_atoms.items[@intFromEnum(index)]; |
| 679 | } | 700 | } |
| 680 | | 701 | |
| 681 | pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom { | 702 | pub fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom { |
| 682 | return &wasm.managed_atoms.items[@intFromEnum(index)]; | 703 | return &wasm.managed_atoms.items[@intFromEnum(index)]; |
| 683 | } | 704 | } |
| 684 | | 705 | |
| ... | @@ -733,15 +754,13 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { | ... | @@ -733,15 +754,13 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { |
| 733 | } | 754 | } |
| 734 | | 755 | |
| 735 | for (offsets.keys()) |file_offset| { | 756 | for (offsets.keys()) |file_offset| { |
| 736 | var object = archive.parseObject(wasm, file_offset) catch |e| { | 757 | const object = archive.parseObject(wasm, file_offset) catch |e| { |
| 737 | var err_note = try diags.addErrorWithNotes(1); | 758 | var err_note = try diags.addErrorWithNotes(1); |
| 738 | try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)}); | 759 | try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)}); |
| 739 | try err_note.addNote("while parsing object in archive {s}", .{path}); | 760 | try err_note.addNote("while parsing object in archive {s}", .{path}); |
| 740 | return error.FlushFailure; | 761 | return error.FlushFailure; |
| 741 | }; | 762 | }; |
| 742 | object.index = @enumFromInt(wasm.files.len); | 763 | try wasm.objects.append(gpa, object); |
| 743 | try wasm.files.append(gpa, .{ .object = object }); | | |
| 744 | try wasm.objects.append(gpa, object.index); | | |
| 745 | } | 764 | } |
| 746 | | 765 | |
| 747 | return true; | 766 | return true; |
| ... | @@ -749,23 +768,102 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { | ... | @@ -749,23 +768,102 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { |
| 749 | | 768 | |
| 750 | fn requiresTLSReloc(wasm: *const Wasm) bool { | 769 | fn requiresTLSReloc(wasm: *const Wasm) bool { |
| 751 | for (wasm.got_symbols.items) |loc| { | 770 | for (wasm.got_symbols.items) |loc| { |
| 752 | if (loc.getSymbol(wasm).isTLS()) { | 771 | if (wasm.symbolLocSymbol(loc).isTLS()) { |
| 753 | return true; | 772 | return true; |
| 754 | } | 773 | } |
| 755 | } | 774 | } |
| 756 | return false; | 775 | return false; |
| 757 | } | 776 | } |
| 758 | | 777 | |
| 759 | fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | 778 | fn objectPath(wasm: *const Wasm, object_id: ObjectId) []const u8 { |
| | 779 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.path; |
| | 780 | return obj.path; |
| | 781 | } |
| | 782 | |
| | 783 | fn objectSymbols(wasm: *const Wasm, object_id: ObjectId) []const Symbol { |
| | 784 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.symbols.items; |
| | 785 | return obj.symtable; |
| | 786 | } |
| | 787 | |
| | 788 | fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Symbol { |
| | 789 | const obj = wasm.objectById(object_id) orelse return &wasm.zig_object.?.symbols.items[@intFromEnum(index)]; |
| | 790 | return &obj.symtable[@intFromEnum(index)]; |
| | 791 | } |
| | 792 | |
| | 793 | fn objectSymbolName(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) []const u8 { |
| | 794 | const obj = wasm.objectById(object_id) orelse { |
| | 795 | const zo = wasm.zig_object.?; |
| | 796 | const sym = zo.symbols.items[@intFromEnum(index)]; |
| | 797 | return zo.string_table.get(sym.name).?; |
| | 798 | }; |
| | 799 | const sym = obj.symtable[@intFromEnum(index)]; |
| | 800 | return obj.string_table.get(sym.name); |
| | 801 | } |
| | 802 | |
| | 803 | fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func { |
| | 804 | const obj = wasm.objectById(object_id) orelse { |
| | 805 | const zo = wasm.zig_object.?; |
| | 806 | const sym = zo.symbols.items[@intFromEnum(sym_index)]; |
| | 807 | return zo.functions.items[sym.index]; |
| | 808 | }; |
| | 809 | const sym = obj.symtable[@intFromEnum(sym_index)]; |
| | 810 | return obj.functions[sym.index - obj.imported_functions_count]; |
| | 811 | } |
| | 812 | |
| | 813 | fn objectImportedFunctions(wasm: *const Wasm, object_id: ObjectId) u32 { |
| | 814 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.imported_functions_count; |
| | 815 | return obj.imported_functions_count; |
| | 816 | } |
| | 817 | |
| | 818 | fn objectGlobals(wasm: *const Wasm, object_id: ObjectId) []const std.wasm.Global { |
| | 819 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.globals.items; |
| | 820 | return obj.globals; |
| | 821 | } |
| | 822 | |
| | 823 | fn objectFuncTypes(wasm: *const Wasm, object_id: ObjectId) []const std.wasm.Type { |
| | 824 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.func_types.items; |
| | 825 | return obj.func_types; |
| | 826 | } |
| | 827 | |
| | 828 | fn objectSegmentInfo(wasm: *const Wasm, object_id: ObjectId) []const NamedSegment { |
| | 829 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.segment_info.items; |
| | 830 | return obj.segment_info; |
| | 831 | } |
| | 832 | |
| | 833 | /// For a given symbol index, find its corresponding import. |
| | 834 | /// Asserts import exists. |
| | 835 | fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Index) Import { |
| | 836 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.imports.get(symbol_index).?; |
| | 837 | return obj.findImport(obj.symtable[@intFromEnum(symbol_index)]); |
| | 838 | } |
| | 839 | |
| | 840 | /// For a given offset, returns its string value. |
| | 841 | /// Asserts string exists in the object string table. |
| | 842 | fn objectString(wasm: *const Wasm, object_id: ObjectId, offset: u32) []const u8 { |
| | 843 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.string_table.get(offset).?; |
| | 844 | return obj.string_table.get(offset); |
| | 845 | } |
| | 846 | |
| | 847 | /// Returns the object element pointer, or null if it is the ZigObject. |
| | 848 | fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object { |
| | 849 | if (object_id == .zig_object) return null; |
| | 850 | return &wasm.objects.items[@intFromEnum(object_id)]; |
| | 851 | } |
| | 852 | |
| | 853 | fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 760 | const gpa = wasm.base.comp.gpa; | 854 | const gpa = wasm.base.comp.gpa; |
| 761 | const diags = &wasm.base.comp.link_diags; | 855 | const diags = &wasm.base.comp.link_diags; |
| 762 | const obj_file = wasm.file(file_index).?; | 856 | const obj_path = objectPath(wasm, object_id); |
| 763 | log.debug("Resolving symbols in object: '{s}'", .{obj_file.path()}); | 857 | log.debug("Resolving symbols in object: '{s}'", .{obj_path}); |
| | 858 | const symbols = objectSymbols(wasm, object_id); |
| 764 | | 859 | |
| 765 | for (obj_file.symbols(), 0..) |symbol, i| { | 860 | for (symbols, 0..) |symbol, i| { |
| 766 | const sym_index: Symbol.Index = @enumFromInt(i); | 861 | const sym_index: Symbol.Index = @enumFromInt(i); |
| 767 | const location: SymbolLoc = .{ .file = file_index, .index = sym_index }; | 862 | const location: SymbolLoc = .{ |
| 768 | const sym_name = obj_file.string(symbol.name); | 863 | .file = object_id.toOptional(), |
| | 864 | .index = sym_index, |
| | 865 | }; |
| | 866 | const sym_name = objectString(wasm, object_id, symbol.name); |
| 769 | if (mem.eql(u8, sym_name, "__indirect_function_table")) { | 867 | if (mem.eql(u8, sym_name, "__indirect_function_table")) { |
| 770 | continue; | 868 | continue; |
| 771 | } | 869 | } |
| ... | @@ -775,7 +873,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | ... | @@ -775,7 +873,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { |
| 775 | if (symbol.isUndefined()) { | 873 | if (symbol.isUndefined()) { |
| 776 | var err = try diags.addErrorWithNotes(1); | 874 | var err = try diags.addErrorWithNotes(1); |
| 777 | try err.addMsg("Local symbols are not allowed to reference imports", .{}); | 875 | try err.addMsg("Local symbols are not allowed to reference imports", .{}); |
| 778 | try err.addNote("symbol '{s}' defined in '{s}'", .{ sym_name, obj_file.path() }); | 876 | try err.addNote("symbol '{s}' defined in '{s}'", .{ sym_name, obj_path }); |
| 779 | } | 877 | } |
| 780 | try wasm.resolved_symbols.putNoClobber(gpa, location, {}); | 878 | try wasm.resolved_symbols.putNoClobber(gpa, location, {}); |
| 781 | continue; | 879 | continue; |
| ... | @@ -793,13 +891,8 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | ... | @@ -793,13 +891,8 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { |
| 793 | } | 891 | } |
| 794 | | 892 | |
| 795 | const existing_loc = maybe_existing.value_ptr.*; | 893 | const existing_loc = maybe_existing.value_ptr.*; |
| 796 | const existing_sym: *Symbol = existing_loc.getSymbol(wasm); | 894 | const existing_sym: *Symbol = wasm.symbolLocSymbol(existing_loc); |
| 797 | const existing_file = wasm.file(existing_loc.file); | 895 | const existing_file_path = if (existing_loc.file.unwrap()) |id| objectPath(wasm, id) else wasm.name; |
| 798 | | | |
| 799 | const existing_file_path = if (existing_file) |existing_obj_file| | | |
| 800 | existing_obj_file.path() | | |
| 801 | else | | |
| 802 | wasm.name; | | |
| 803 | | 896 | |
| 804 | if (!existing_sym.isUndefined()) outer: { | 897 | if (!existing_sym.isUndefined()) outer: { |
| 805 | if (!symbol.isUndefined()) inner: { | 898 | if (!symbol.isUndefined()) inner: { |
| ... | @@ -813,7 +906,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | ... | @@ -813,7 +906,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { |
| 813 | var err = try diags.addErrorWithNotes(2); | 906 | var err = try diags.addErrorWithNotes(2); |
| 814 | try err.addMsg("symbol '{s}' defined multiple times", .{sym_name}); | 907 | try err.addMsg("symbol '{s}' defined multiple times", .{sym_name}); |
| 815 | try err.addNote("first definition in '{s}'", .{existing_file_path}); | 908 | try err.addNote("first definition in '{s}'", .{existing_file_path}); |
| 816 | try err.addNote("next definition in '{s}'", .{obj_file.path()}); | 909 | try err.addNote("next definition in '{s}'", .{obj_path}); |
| 817 | } | 910 | } |
| 818 | | 911 | |
| 819 | try wasm.discarded.put(gpa, location, existing_loc); | 912 | try wasm.discarded.put(gpa, location, existing_loc); |
| ... | @@ -824,22 +917,22 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | ... | @@ -824,22 +917,22 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { |
| 824 | var err = try diags.addErrorWithNotes(2); | 917 | var err = try diags.addErrorWithNotes(2); |
| 825 | try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) }); | 918 | try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) }); |
| 826 | try err.addNote("first definition in '{s}'", .{existing_file_path}); | 919 | try err.addNote("first definition in '{s}'", .{existing_file_path}); |
| 827 | try err.addNote("next definition in '{s}'", .{obj_file.path()}); | 920 | try err.addNote("next definition in '{s}'", .{obj_path}); |
| 828 | } | 921 | } |
| 829 | | 922 | |
| 830 | if (existing_sym.isUndefined() and symbol.isUndefined()) { | 923 | if (existing_sym.isUndefined() and symbol.isUndefined()) { |
| 831 | // only verify module/import name for function symbols | 924 | // only verify module/import name for function symbols |
| 832 | if (symbol.tag == .function) { | 925 | if (symbol.tag == .function) { |
| 833 | const existing_name = if (existing_file) |existing_obj| blk: { | 926 | const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| blk: { |
| 834 | const imp = existing_obj.import(existing_loc.index); | 927 | const imp = objectImport(wasm, existing_obj_id, existing_loc.index); |
| 835 | break :blk existing_obj.string(imp.module_name); | 928 | break :blk objectString(wasm, existing_obj_id, imp.module_name); |
| 836 | } else blk: { | 929 | } else blk: { |
| 837 | const name_index = wasm.imports.get(existing_loc).?.module_name; | 930 | const name_index = wasm.imports.get(existing_loc).?.module_name; |
| 838 | break :blk wasm.string_table.get(name_index); | 931 | break :blk wasm.string_table.get(name_index); |
| 839 | }; | 932 | }; |
| 840 | | 933 | |
| 841 | const imp = obj_file.import(sym_index); | 934 | const imp = objectImport(wasm, object_id, sym_index); |
| 842 | const module_name = obj_file.string(imp.module_name); | 935 | const module_name = objectString(wasm, object_id, imp.module_name); |
| 843 | if (!mem.eql(u8, existing_name, module_name)) { | 936 | if (!mem.eql(u8, existing_name, module_name)) { |
| 844 | var err = try diags.addErrorWithNotes(2); | 937 | var err = try diags.addErrorWithNotes(2); |
| 845 | try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{ | 938 | try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{ |
| ... | @@ -848,7 +941,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | ... | @@ -848,7 +941,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { |
| 848 | module_name, | 941 | module_name, |
| 849 | }); | 942 | }); |
| 850 | try err.addNote("first definition in '{s}'", .{existing_file_path}); | 943 | try err.addNote("first definition in '{s}'", .{existing_file_path}); |
| 851 | try err.addNote("next definition in '{s}'", .{obj_file.path()}); | 944 | try err.addNote("next definition in '{s}'", .{obj_path}); |
| 852 | } | 945 | } |
| 853 | } | 946 | } |
| 854 | | 947 | |
| ... | @@ -864,7 +957,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | ... | @@ -864,7 +957,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { |
| 864 | var err = try diags.addErrorWithNotes(2); | 957 | var err = try diags.addErrorWithNotes(2); |
| 865 | try err.addMsg("symbol '{s}' mismatching global types", .{sym_name}); | 958 | try err.addMsg("symbol '{s}' mismatching global types", .{sym_name}); |
| 866 | try err.addNote("first definition in '{s}'", .{existing_file_path}); | 959 | try err.addNote("first definition in '{s}'", .{existing_file_path}); |
| 867 | try err.addNote("next definition in '{s}'", .{obj_file.path()}); | 960 | try err.addNote("next definition in '{s}'", .{obj_path}); |
| 868 | } | 961 | } |
| 869 | } | 962 | } |
| 870 | | 963 | |
| ... | @@ -876,7 +969,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | ... | @@ -876,7 +969,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { |
| 876 | try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name}); | 969 | try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name}); |
| 877 | try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty }); | 970 | try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty }); |
| 878 | try err.addNote("first definition in '{s}'", .{existing_file_path}); | 971 | try err.addNote("first definition in '{s}'", .{existing_file_path}); |
| 879 | try err.addNote("next definition in '{s}'", .{obj_file.path()}); | 972 | try err.addNote("next definition in '{s}'", .{obj_path}); |
| 880 | } | 973 | } |
| 881 | } | 974 | } |
| 882 | | 975 | |
| ... | @@ -891,7 +984,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { | ... | @@ -891,7 +984,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, file_index: File.Index) !void { |
| 891 | // simply overwrite with the new symbol | 984 | // simply overwrite with the new symbol |
| 892 | log.debug("Overwriting symbol '{s}'", .{sym_name}); | 985 | log.debug("Overwriting symbol '{s}'", .{sym_name}); |
| 893 | log.debug(" old definition in '{s}'", .{existing_file_path}); | 986 | log.debug(" old definition in '{s}'", .{existing_file_path}); |
| 894 | log.debug(" new definition in '{s}'", .{obj_file.path()}); | 987 | log.debug(" new definition in '{s}'", .{obj_path}); |
| 895 | try wasm.discarded.putNoClobber(gpa, existing_loc, location); | 988 | try wasm.discarded.putNoClobber(gpa, existing_loc, location); |
| 896 | maybe_existing.value_ptr.* = location; | 989 | maybe_existing.value_ptr.* = location; |
| 897 | try wasm.globals.put(gpa, sym_name_index, location); | 990 | try wasm.globals.put(gpa, sym_name_index, location); |
| ... | @@ -924,16 +1017,14 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { | ... | @@ -924,16 +1017,14 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { |
| 924 | // Symbol is found in unparsed object file within current archive. | 1017 | // Symbol is found in unparsed object file within current archive. |
| 925 | // Parse object and and resolve symbols again before we check remaining | 1018 | // Parse object and and resolve symbols again before we check remaining |
| 926 | // undefined symbols. | 1019 | // undefined symbols. |
| 927 | var object = archive.parseObject(wasm, offset.items[0]) catch |e| { | 1020 | const object = archive.parseObject(wasm, offset.items[0]) catch |e| { |
| 928 | var err_note = try diags.addErrorWithNotes(1); | 1021 | var err_note = try diags.addErrorWithNotes(1); |
| 929 | try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)}); | 1022 | try err_note.addMsg("Failed parsing object: {s}", .{@errorName(e)}); |
| 930 | try err_note.addNote("while parsing object in archive {s}", .{archive.name}); | 1023 | try err_note.addNote("while parsing object in archive {s}", .{archive.name}); |
| 931 | return error.FlushFailure; | 1024 | return error.FlushFailure; |
| 932 | }; | 1025 | }; |
| 933 | object.index = @enumFromInt(wasm.files.len); | 1026 | try wasm.objects.append(gpa, object); |
| 934 | try wasm.files.append(gpa, .{ .object = object }); | 1027 | try wasm.resolveSymbolsInObject(@enumFromInt(wasm.objects.items.len - 1)); |
| 935 | try wasm.objects.append(gpa, object.index); | | |
| 936 | try wasm.resolveSymbolsInObject(object.index); | | |
| 937 | | 1028 | |
| 938 | // continue loop for any remaining undefined symbols that still exist | 1029 | // continue loop for any remaining undefined symbols that still exist |
| 939 | // after resolving last object file | 1030 | // after resolving last object file |
| ... | @@ -964,13 +1055,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { | ... | @@ -964,13 +1055,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 964 | return; | 1055 | return; |
| 965 | } | 1056 | } |
| 966 | const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function); | 1057 | const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function); |
| 967 | sym_loc.getSymbol(wasm).mark(); | 1058 | wasm.symbolLocSymbol(sym_loc).mark(); |
| 968 | | 1059 | |
| 969 | const flag_address: u32 = if (shared_memory) address: { | 1060 | const flag_address: u32 = if (shared_memory) address: { |
| 970 | // when we have passive initialization segments and shared memory | 1061 | // when we have passive initialization segments and shared memory |
| 971 | // `setupMemory` will create this symbol and set its virtual address. | 1062 | // `setupMemory` will create this symbol and set its virtual address. |
| 972 | const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?; | 1063 | const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?; |
| 973 | break :address loc.getSymbol(wasm).virtual_address; | 1064 | break :address wasm.symbolLocSymbol(loc).virtual_address; |
| 974 | } else 0; | 1065 | } else 0; |
| 975 | | 1066 | |
| 976 | var function_body = std.ArrayList(u8).init(gpa); | 1067 | var function_body = std.ArrayList(u8).init(gpa); |
| ... | @@ -1028,7 +1119,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { | ... | @@ -1028,7 +1119,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1028 | try writeI32Const(writer, segment.offset); | 1119 | try writeI32Const(writer, segment.offset); |
| 1029 | try writer.writeByte(std.wasm.opcode(.global_set)); | 1120 | try writer.writeByte(std.wasm.opcode(.global_set)); |
| 1030 | const loc = wasm.findGlobalSymbol("__tls_base").?; | 1121 | const loc = wasm.findGlobalSymbol("__tls_base").?; |
| 1031 | try leb.writeUleb128(writer, loc.getSymbol(wasm).index); | 1122 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index); |
| 1032 | } | 1123 | } |
| 1033 | | 1124 | |
| 1034 | try writeI32Const(writer, 0); | 1125 | try writeI32Const(writer, 0); |
| ... | @@ -1128,7 +1219,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { | ... | @@ -1128,7 +1219,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1128 | } | 1219 | } |
| 1129 | | 1220 | |
| 1130 | const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function); | 1221 | const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function); |
| 1131 | loc.getSymbol(wasm).mark(); | 1222 | wasm.symbolLocSymbol(loc).mark(); |
| 1132 | var function_body = std.ArrayList(u8).init(gpa); | 1223 | var function_body = std.ArrayList(u8).init(gpa); |
| 1133 | defer function_body.deinit(); | 1224 | defer function_body.deinit(); |
| 1134 | const writer = function_body.writer(); | 1225 | const writer = function_body.writer(); |
| ... | @@ -1136,12 +1227,12 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { | ... | @@ -1136,12 +1227,12 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1136 | // locals (we have none) | 1227 | // locals (we have none) |
| 1137 | try writer.writeByte(0); | 1228 | try writer.writeByte(0); |
| 1138 | for (wasm.got_symbols.items, 0..) |got_loc, got_index| { | 1229 | for (wasm.got_symbols.items, 0..) |got_loc, got_index| { |
| 1139 | const sym: *Symbol = got_loc.getSymbol(wasm); | 1230 | const sym: *Symbol = wasm.symbolLocSymbol(got_loc); |
| 1140 | if (!sym.isTLS()) continue; // only relocate TLS symbols | 1231 | if (!sym.isTLS()) continue; // only relocate TLS symbols |
| 1141 | if (sym.tag == .data and sym.isDefined()) { | 1232 | if (sym.tag == .data and sym.isDefined()) { |
| 1142 | // get __tls_base | 1233 | // get __tls_base |
| 1143 | try writer.writeByte(std.wasm.opcode(.global_get)); | 1234 | try writer.writeByte(std.wasm.opcode(.global_get)); |
| 1144 | try leb.writeUleb128(writer, wasm.findGlobalSymbol("__tls_base").?.getSymbol(wasm).index); | 1235 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.findGlobalSymbol("__tls_base").?).index); |
| 1145 | | 1236 | |
| 1146 | // add the virtual address of the symbol | 1237 | // add the virtual address of the symbol |
| 1147 | try writer.writeByte(std.wasm.opcode(.i32_const)); | 1238 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| ... | @@ -1165,7 +1256,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { | ... | @@ -1165,7 +1256,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1165 | | 1256 | |
| 1166 | fn validateFeatures( | 1257 | fn validateFeatures( |
| 1167 | wasm: *const Wasm, | 1258 | wasm: *const Wasm, |
| 1168 | to_emit: *[@typeInfo(types.Feature.Tag).@"enum".fields.len]bool, | 1259 | to_emit: *[@typeInfo(Feature.Tag).@"enum".fields.len]bool, |
| 1169 | emit_features_count: *u32, | 1260 | emit_features_count: *u32, |
| 1170 | ) !void { | 1261 | ) !void { |
| 1171 | const comp = wasm.base.comp; | 1262 | const comp = wasm.base.comp; |
| ... | @@ -1174,7 +1265,7 @@ fn validateFeatures( | ... | @@ -1174,7 +1265,7 @@ fn validateFeatures( |
| 1174 | const shared_memory = comp.config.shared_memory; | 1265 | const shared_memory = comp.config.shared_memory; |
| 1175 | const cpu_features = target.cpu.features; | 1266 | const cpu_features = target.cpu.features; |
| 1176 | const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects. | 1267 | const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects. |
| 1177 | const known_features_count = @typeInfo(types.Feature.Tag).@"enum".fields.len; | 1268 | const known_features_count = @typeInfo(Feature.Tag).@"enum".fields.len; |
| 1178 | | 1269 | |
| 1179 | var allowed = [_]bool{false} ** known_features_count; | 1270 | var allowed = [_]bool{false} ** known_features_count; |
| 1180 | var used = [_]u17{0} ** known_features_count; | 1271 | var used = [_]u17{0} ** known_features_count; |
| ... | @@ -1199,10 +1290,9 @@ fn validateFeatures( | ... | @@ -1199,10 +1290,9 @@ fn validateFeatures( |
| 1199 | | 1290 | |
| 1200 | // extract all the used, disallowed and required features from each | 1291 | // extract all the used, disallowed and required features from each |
| 1201 | // linked object file so we can test them. | 1292 | // linked object file so we can test them. |
| 1202 | for (wasm.objects.items) |file_index| { | 1293 | for (wasm.objects.items, 0..) |*object, file_index| { |
| 1203 | const object: Object = wasm.files.items(.data)[@intFromEnum(file_index)].object; | | |
| 1204 | for (object.features) |feature| { | 1294 | for (object.features) |feature| { |
| 1205 | const value = @as(u16, @intFromEnum(file_index)) << 1 | @as(u1, 1); | 1295 | const value = (@as(u16, @intCast(file_index)) << 1) | 1; |
| 1206 | switch (feature.prefix) { | 1296 | switch (feature.prefix) { |
| 1207 | .used => { | 1297 | .used => { |
| 1208 | used[@intFromEnum(feature.tag)] = value; | 1298 | used[@intFromEnum(feature.tag)] = value; |
| ... | @@ -1234,8 +1324,8 @@ fn validateFeatures( | ... | @@ -1234,8 +1324,8 @@ fn validateFeatures( |
| 1234 | emit_features_count.* += @intFromBool(is_enabled); | 1324 | emit_features_count.* += @intFromBool(is_enabled); |
| 1235 | } else if (is_enabled and !allowed[used_index]) { | 1325 | } else if (is_enabled and !allowed[used_index]) { |
| 1236 | var err = try diags.addErrorWithNotes(1); | 1326 | var err = try diags.addErrorWithNotes(1); |
| 1237 | try err.addMsg("feature '{}' not allowed, but used by linked object", .{@as(types.Feature.Tag, @enumFromInt(used_index))}); | 1327 | try err.addMsg("feature '{}' not allowed, but used by linked object", .{@as(Feature.Tag, @enumFromInt(used_index))}); |
| 1238 | try err.addNote("defined in '{s}'", .{wasm.files.items(.data)[used_set >> 1].object.path}); | 1328 | try err.addNote("defined in '{s}'", .{wasm.objects.items[used_set >> 1].path}); |
| 1239 | valid_feature_set = false; | 1329 | valid_feature_set = false; |
| 1240 | } | 1330 | } |
| 1241 | } | 1331 | } |
| ... | @@ -1245,17 +1335,17 @@ fn validateFeatures( | ... | @@ -1245,17 +1335,17 @@ fn validateFeatures( |
| 1245 | } | 1335 | } |
| 1246 | | 1336 | |
| 1247 | if (shared_memory) { | 1337 | if (shared_memory) { |
| 1248 | const disallowed_feature = disallowed[@intFromEnum(types.Feature.Tag.shared_mem)]; | 1338 | const disallowed_feature = disallowed[@intFromEnum(Feature.Tag.shared_mem)]; |
| 1249 | if (@as(u1, @truncate(disallowed_feature)) != 0) { | 1339 | if (@as(u1, @truncate(disallowed_feature)) != 0) { |
| 1250 | var err = try diags.addErrorWithNotes(0); | 1340 | var err = try diags.addErrorWithNotes(0); |
| 1251 | try err.addMsg( | 1341 | try err.addMsg( |
| 1252 | "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled", | 1342 | "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled", |
| 1253 | .{wasm.files.items(.data)[disallowed_feature >> 1].object.path}, | 1343 | .{wasm.objects.items[disallowed_feature >> 1].path}, |
| 1254 | ); | 1344 | ); |
| 1255 | valid_feature_set = false; | 1345 | valid_feature_set = false; |
| 1256 | } | 1346 | } |
| 1257 | | 1347 | |
| 1258 | for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| { | 1348 | for ([_]Feature.Tag{ .atomics, .bulk_memory }) |feature| { |
| 1259 | if (!allowed[@intFromEnum(feature)]) { | 1349 | if (!allowed[@intFromEnum(feature)]) { |
| 1260 | var err = try diags.addErrorWithNotes(0); | 1350 | var err = try diags.addErrorWithNotes(0); |
| 1261 | try err.addMsg("feature '{}' is not used but is required for shared-memory", .{feature}); | 1351 | try err.addMsg("feature '{}' is not used but is required for shared-memory", .{feature}); |
| ... | @@ -1264,7 +1354,7 @@ fn validateFeatures( | ... | @@ -1264,7 +1354,7 @@ fn validateFeatures( |
| 1264 | } | 1354 | } |
| 1265 | | 1355 | |
| 1266 | if (has_tls) { | 1356 | if (has_tls) { |
| 1267 | for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| { | 1357 | for ([_]Feature.Tag{ .atomics, .bulk_memory }) |feature| { |
| 1268 | if (!allowed[@intFromEnum(feature)]) { | 1358 | if (!allowed[@intFromEnum(feature)]) { |
| 1269 | var err = try diags.addErrorWithNotes(0); | 1359 | var err = try diags.addErrorWithNotes(0); |
| 1270 | try err.addMsg("feature '{}' is not used but is required for thread-local storage", .{feature}); | 1360 | try err.addMsg("feature '{}' is not used but is required for thread-local storage", .{feature}); |
| ... | @@ -1272,9 +1362,8 @@ fn validateFeatures( | ... | @@ -1272,9 +1362,8 @@ fn validateFeatures( |
| 1272 | } | 1362 | } |
| 1273 | } | 1363 | } |
| 1274 | // For each linked object, validate the required and disallowed features | 1364 | // For each linked object, validate the required and disallowed features |
| 1275 | for (wasm.objects.items) |file_index| { | 1365 | for (wasm.objects.items) |*object| { |
| 1276 | var object_used_features = [_]bool{false} ** known_features_count; | 1366 | var object_used_features = [_]bool{false} ** known_features_count; |
| 1277 | const object = wasm.files.items(.data)[@intFromEnum(file_index)].object; | | |
| 1278 | for (object.features) |feature| { | 1367 | for (object.features) |feature| { |
| 1279 | if (feature.prefix == .disallowed) continue; // already defined in 'disallowed' set. | 1368 | if (feature.prefix == .disallowed) continue; // already defined in 'disallowed' set. |
| 1280 | // from here a feature is always used | 1369 | // from here a feature is always used |
| ... | @@ -1282,7 +1371,7 @@ fn validateFeatures( | ... | @@ -1282,7 +1371,7 @@ fn validateFeatures( |
| 1282 | if (@as(u1, @truncate(disallowed_feature)) != 0) { | 1371 | if (@as(u1, @truncate(disallowed_feature)) != 0) { |
| 1283 | var err = try diags.addErrorWithNotes(2); | 1372 | var err = try diags.addErrorWithNotes(2); |
| 1284 | try err.addMsg("feature '{}' is disallowed, but used by linked object", .{feature.tag}); | 1373 | try err.addMsg("feature '{}' is disallowed, but used by linked object", .{feature.tag}); |
| 1285 | try err.addNote("disallowed by '{s}'", .{wasm.files.items(.data)[disallowed_feature >> 1].object.path}); | 1374 | try err.addNote("disallowed by '{s}'", .{wasm.objects.items[disallowed_feature >> 1].path}); |
| 1286 | try err.addNote("used in '{s}'", .{object.path}); | 1375 | try err.addNote("used in '{s}'", .{object.path}); |
| 1287 | valid_feature_set = false; | 1376 | valid_feature_set = false; |
| 1288 | } | 1377 | } |
| ... | @@ -1295,8 +1384,8 @@ fn validateFeatures( | ... | @@ -1295,8 +1384,8 @@ fn validateFeatures( |
| 1295 | const is_required = @as(u1, @truncate(required_feature)) != 0; | 1384 | const is_required = @as(u1, @truncate(required_feature)) != 0; |
| 1296 | if (is_required and !object_used_features[feature_index]) { | 1385 | if (is_required and !object_used_features[feature_index]) { |
| 1297 | var err = try diags.addErrorWithNotes(2); | 1386 | var err = try diags.addErrorWithNotes(2); |
| 1298 | try err.addMsg("feature '{}' is required but not used in linked object", .{@as(types.Feature.Tag, @enumFromInt(feature_index))}); | 1387 | try err.addMsg("feature '{}' is required but not used in linked object", .{@as(Feature.Tag, @enumFromInt(feature_index))}); |
| 1299 | try err.addNote("required by '{s}'", .{wasm.files.items(.data)[required_feature >> 1].object.path}); | 1388 | try err.addNote("required by '{s}'", .{wasm.objects.items[required_feature >> 1].path}); |
| 1300 | try err.addNote("missing in '{s}'", .{object.path}); | 1389 | try err.addNote("missing in '{s}'", .{object.path}); |
| 1301 | valid_feature_set = false; | 1390 | valid_feature_set = false; |
| 1302 | } | 1391 | } |
| ... | @@ -1341,7 +1430,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { | ... | @@ -1341,7 +1430,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1341 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); | 1430 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); |
| 1342 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); | 1431 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); |
| 1343 | _ = wasm.resolved_symbols.swapRemove(kv.value); | 1432 | _ = wasm.resolved_symbols.swapRemove(kv.value); |
| 1344 | const symbol = loc.getSymbol(wasm); | 1433 | const symbol = wasm.symbolLocSymbol(loc); |
| 1345 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 1434 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 1346 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); | 1435 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| 1347 | try wasm.wasm_globals.append(gpa, .{ | 1436 | try wasm.wasm_globals.append(gpa, .{ |
| ... | @@ -1368,14 +1457,15 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void { | ... | @@ -1368,14 +1457,15 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void { |
| 1368 | | 1457 | |
| 1369 | var found_undefined_symbols = false; | 1458 | var found_undefined_symbols = false; |
| 1370 | for (wasm.undefs.values()) |undef| { | 1459 | for (wasm.undefs.values()) |undef| { |
| 1371 | const symbol = undef.getSymbol(wasm); | 1460 | const symbol = wasm.symbolLocSymbol(undef); |
| 1372 | if (symbol.tag == .data) { | 1461 | if (symbol.tag == .data) { |
| 1373 | found_undefined_symbols = true; | 1462 | found_undefined_symbols = true; |
| 1374 | const file_name = if (wasm.file(undef.file)) |obj_file| | 1463 | const file_name = switch (undef.file) { |
| 1375 | obj_file.path() | 1464 | .zig_object => wasm.zig_object.?.path, |
| 1376 | else | 1465 | .none => wasm.name, |
| 1377 | wasm.name; | 1466 | _ => wasm.objects.items[@intFromEnum(undef.file)].path, |
| 1378 | const symbol_name = undef.getName(wasm); | 1467 | }; |
| | 1468 | const symbol_name = wasm.symbolLocName(undef); |
| 1379 | var err = try diags.addErrorWithNotes(1); | 1469 | var err = try diags.addErrorWithNotes(1); |
| 1380 | try err.addMsg("could not resolve undefined symbol '{s}'", .{symbol_name}); | 1470 | try err.addMsg("could not resolve undefined symbol '{s}'", .{symbol_name}); |
| 1381 | try err.addNote("defined in '{s}'", .{file_name}); | 1471 | try err.addNote("defined in '{s}'", .{file_name}); |
| ... | @@ -1396,11 +1486,11 @@ pub fn deinit(wasm: *Wasm) void { | ... | @@ -1396,11 +1486,11 @@ pub fn deinit(wasm: *Wasm) void { |
| 1396 | for (wasm.segment_info.values()) |segment_info| { | 1486 | for (wasm.segment_info.values()) |segment_info| { |
| 1397 | gpa.free(segment_info.name); | 1487 | gpa.free(segment_info.name); |
| 1398 | } | 1488 | } |
| 1399 | if (wasm.zigObjectPtr()) |zig_obj| { | 1489 | if (wasm.zig_object) |zig_obj| { |
| 1400 | zig_obj.deinit(wasm); | 1490 | zig_obj.deinit(wasm); |
| 1401 | } | 1491 | } |
| 1402 | for (wasm.objects.items) |obj_index| { | 1492 | for (wasm.objects.items) |*object| { |
| 1403 | wasm.file(obj_index).?.object.deinit(gpa); | 1493 | object.deinit(gpa); |
| 1404 | } | 1494 | } |
| 1405 | | 1495 | |
| 1406 | for (wasm.archives.items) |*archive| { | 1496 | for (wasm.archives.items) |*archive| { |
| ... | @@ -1437,7 +1527,6 @@ pub fn deinit(wasm: *Wasm) void { | ... | @@ -1437,7 +1527,6 @@ pub fn deinit(wasm: *Wasm) void { |
| 1437 | wasm.exports.deinit(gpa); | 1527 | wasm.exports.deinit(gpa); |
| 1438 | | 1528 | |
| 1439 | wasm.string_table.deinit(gpa); | 1529 | wasm.string_table.deinit(gpa); |
| 1440 | wasm.files.deinit(gpa); | | |
| 1441 | } | 1530 | } |
| 1442 | | 1531 | |
| 1443 | pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { | 1532 | pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { |
| ... | @@ -1445,7 +1534,7 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, | ... | @@ -1445,7 +1534,7 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, |
| 1445 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1534 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1446 | } | 1535 | } |
| 1447 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness); | 1536 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness); |
| 1448 | try wasm.zigObjectPtr().?.updateFunc(wasm, pt, func_index, air, liveness); | 1537 | try wasm.zig_object.?.updateFunc(wasm, pt, func_index, air, liveness); |
| 1449 | } | 1538 | } |
| 1450 | | 1539 | |
| 1451 | // Generate code for the "Nav", storing it in memory to be later written to | 1540 | // Generate code for the "Nav", storing it in memory to be later written to |
| ... | @@ -1455,51 +1544,84 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !voi | ... | @@ -1455,51 +1544,84 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !voi |
| 1455 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1544 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1456 | } | 1545 | } |
| 1457 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav); | 1546 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav); |
| 1458 | try wasm.zigObjectPtr().?.updateNav(wasm, pt, nav); | 1547 | try wasm.zig_object.?.updateNav(wasm, pt, nav); |
| 1459 | } | 1548 | } |
| 1460 | | 1549 | |
| 1461 | pub fn updateNavLineNumber(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void { | 1550 | pub fn updateNavLineNumber(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void { |
| 1462 | if (wasm.llvm_object) |_| return; | 1551 | if (wasm.llvm_object) |_| return; |
| 1463 | try wasm.zigObjectPtr().?.updateNavLineNumber(pt, nav); | 1552 | try wasm.zig_object.?.updateNavLineNumber(pt, nav); |
| 1464 | } | 1553 | } |
| 1465 | | 1554 | |
| 1466 | /// From a given symbol location, returns its `wasm.GlobalType`. | 1555 | /// From a given symbol location, returns its `wasm.GlobalType`. |
| 1467 | /// Asserts the Symbol represents a global. | 1556 | /// Asserts the Symbol represents a global. |
| 1468 | fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType { | 1557 | fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType { |
| 1469 | const symbol = loc.getSymbol(wasm); | 1558 | const symbol = wasm.symbolLocSymbol(loc); |
| 1470 | assert(symbol.tag == .global); | 1559 | assert(symbol.tag == .global); |
| 1471 | const is_undefined = symbol.isUndefined(); | 1560 | const is_undefined = symbol.isUndefined(); |
| 1472 | if (wasm.file(loc.file)) |obj_file| { | 1561 | switch (loc.file) { |
| 1473 | if (is_undefined) { | 1562 | .zig_object => { |
| 1474 | return obj_file.import(loc.index).kind.global; | 1563 | const zo = wasm.zig_object.?; |
| 1475 | } | 1564 | return if (is_undefined) |
| 1476 | return obj_file.globals()[symbol.index - obj_file.importedGlobals()].global_type; | 1565 | zo.imports.get(loc.index).?.kind.global |
| 1477 | } | 1566 | else |
| 1478 | if (is_undefined) { | 1567 | zo.globals.items[symbol.index - zo.imported_globals_count].global_type; |
| 1479 | return wasm.imports.get(loc).?.kind.global; | 1568 | }, |
| | 1569 | .none => { |
| | 1570 | return if (is_undefined) |
| | 1571 | wasm.imports.get(loc).?.kind.global |
| | 1572 | else |
| | 1573 | wasm.wasm_globals.items[symbol.index].global_type; |
| | 1574 | }, |
| | 1575 | _ => { |
| | 1576 | const obj = &wasm.objects.items[@intFromEnum(loc.file)]; |
| | 1577 | return if (is_undefined) |
| | 1578 | obj.findImport(obj.symtable[@intFromEnum(loc.index)]).kind.global |
| | 1579 | else |
| | 1580 | obj.globals[symbol.index - obj.imported_globals_count].global_type; |
| | 1581 | }, |
| 1480 | } | 1582 | } |
| 1481 | return wasm.wasm_globals.items[symbol.index].global_type; | | |
| 1482 | } | 1583 | } |
| 1483 | | 1584 | |
| 1484 | /// From a given symbol location, returns its `wasm.Type`. | 1585 | /// From a given symbol location, returns its `wasm.Type`. |
| 1485 | /// Asserts the Symbol represents a function. | 1586 | /// Asserts the Symbol represents a function. |
| 1486 | fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { | 1587 | fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1487 | const symbol = loc.getSymbol(wasm); | 1588 | const symbol = wasm.symbolLocSymbol(loc); |
| 1488 | assert(symbol.tag == .function); | 1589 | assert(symbol.tag == .function); |
| 1489 | const is_undefined = symbol.isUndefined(); | 1590 | const is_undefined = symbol.isUndefined(); |
| 1490 | if (wasm.file(loc.file)) |obj_file| { | 1591 | switch (loc.file) { |
| 1491 | if (is_undefined) { | 1592 | .zig_object => { |
| 1492 | const ty_index = obj_file.import(loc.index).kind.function; | 1593 | const zo = wasm.zig_object.?; |
| 1493 | return obj_file.funcTypes()[ty_index]; | 1594 | if (is_undefined) { |
| 1494 | } | 1595 | const type_index = zo.imports.get(loc.index).?.kind.function; |
| 1495 | const type_index = obj_file.function(loc.index).type_index; | 1596 | return zo.func_types.items[type_index]; |
| 1496 | return obj_file.funcTypes()[type_index]; | 1597 | } |
| 1497 | } | 1598 | const sym = zo.symbols.items[@intFromEnum(loc.index)]; |
| 1498 | if (is_undefined) { | 1599 | const type_index = zo.functions.items[sym.index].type_index; |
| 1499 | const ty_index = wasm.imports.get(loc).?.kind.function; | 1600 | return zo.func_types.items[type_index]; |
| 1500 | return wasm.func_types.items[ty_index]; | 1601 | }, |
| | 1602 | .none => { |
| | 1603 | if (is_undefined) { |
| | 1604 | const type_index = wasm.imports.get(loc).?.kind.function; |
| | 1605 | return wasm.func_types.items[type_index]; |
| | 1606 | } |
| | 1607 | return wasm.func_types.items[ |
| | 1608 | wasm.functions.get(.{ |
| | 1609 | .file = .none, |
| | 1610 | .index = symbol.index, |
| | 1611 | }).?.func.type_index |
| | 1612 | ]; |
| | 1613 | }, |
| | 1614 | _ => { |
| | 1615 | const obj = &wasm.objects.items[@intFromEnum(loc.file)]; |
| | 1616 | if (is_undefined) { |
| | 1617 | const type_index = obj.findImport(obj.symtable[@intFromEnum(loc.index)]).kind.function; |
| | 1618 | return obj.func_types[type_index]; |
| | 1619 | } |
| | 1620 | const sym = obj.symtable[@intFromEnum(loc.index)]; |
| | 1621 | const type_index = obj.functions[sym.index - obj.imported_functions_count].type_index; |
| | 1622 | return obj.func_types[type_index]; |
| | 1623 | }, |
| 1501 | } | 1624 | } |
| 1502 | return wasm.func_types.items[wasm.functions.get(.{ .file = loc.file, .index = symbol.index }).?.func.type_index]; | | |
| 1503 | } | 1625 | } |
| 1504 | | 1626 | |
| 1505 | /// Returns the symbol index from a symbol of which its flag is set global, | 1627 | /// Returns the symbol index from a symbol of which its flag is set global, |
| ... | @@ -1508,7 +1630,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { | ... | @@ -1508,7 +1630,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1508 | /// and then returns the index to it. | 1630 | /// and then returns the index to it. |
| 1509 | pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { | 1631 | pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { |
| 1510 | _ = lib_name; | 1632 | _ = lib_name; |
| 1511 | return wasm.zigObjectPtr().?.getGlobalSymbol(wasm.base.comp.gpa, name); | 1633 | return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name); |
| 1512 | } | 1634 | } |
| 1513 | | 1635 | |
| 1514 | /// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type. | 1636 | /// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type. |
| ... | @@ -1519,7 +1641,7 @@ pub fn getNavVAddr( | ... | @@ -1519,7 +1641,7 @@ pub fn getNavVAddr( |
| 1519 | nav: InternPool.Nav.Index, | 1641 | nav: InternPool.Nav.Index, |
| 1520 | reloc_info: link.File.RelocInfo, | 1642 | reloc_info: link.File.RelocInfo, |
| 1521 | ) !u64 { | 1643 | ) !u64 { |
| 1522 | return wasm.zigObjectPtr().?.getNavVAddr(wasm, pt, nav, reloc_info); | 1644 | return wasm.zig_object.?.getNavVAddr(wasm, pt, nav, reloc_info); |
| 1523 | } | 1645 | } |
| 1524 | | 1646 | |
| 1525 | pub fn lowerUav( | 1647 | pub fn lowerUav( |
| ... | @@ -1529,11 +1651,11 @@ pub fn lowerUav( | ... | @@ -1529,11 +1651,11 @@ pub fn lowerUav( |
| 1529 | explicit_alignment: Alignment, | 1651 | explicit_alignment: Alignment, |
| 1530 | src_loc: Zcu.LazySrcLoc, | 1652 | src_loc: Zcu.LazySrcLoc, |
| 1531 | ) !codegen.GenResult { | 1653 | ) !codegen.GenResult { |
| 1532 | return wasm.zigObjectPtr().?.lowerUav(wasm, pt, uav, explicit_alignment, src_loc); | 1654 | return wasm.zig_object.?.lowerUav(wasm, pt, uav, explicit_alignment, src_loc); |
| 1533 | } | 1655 | } |
| 1534 | | 1656 | |
| 1535 | pub fn getUavVAddr(wasm: *Wasm, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { | 1657 | pub fn getUavVAddr(wasm: *Wasm, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { |
| 1536 | return wasm.zigObjectPtr().?.getUavVAddr(wasm, uav, reloc_info); | 1658 | return wasm.zig_object.?.getUavVAddr(wasm, uav, reloc_info); |
| 1537 | } | 1659 | } |
| 1538 | | 1660 | |
| 1539 | pub fn deleteExport( | 1661 | pub fn deleteExport( |
| ... | @@ -1542,7 +1664,7 @@ pub fn deleteExport( | ... | @@ -1542,7 +1664,7 @@ pub fn deleteExport( |
| 1542 | name: InternPool.NullTerminatedString, | 1664 | name: InternPool.NullTerminatedString, |
| 1543 | ) void { | 1665 | ) void { |
| 1544 | if (wasm.llvm_object) |_| return; | 1666 | if (wasm.llvm_object) |_| return; |
| 1545 | return wasm.zigObjectPtr().?.deleteExport(wasm, exported, name); | 1667 | return wasm.zig_object.?.deleteExport(wasm, exported, name); |
| 1546 | } | 1668 | } |
| 1547 | | 1669 | |
| 1548 | pub fn updateExports( | 1670 | pub fn updateExports( |
| ... | @@ -1555,12 +1677,12 @@ pub fn updateExports( | ... | @@ -1555,12 +1677,12 @@ pub fn updateExports( |
| 1555 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1677 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1556 | } | 1678 | } |
| 1557 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); | 1679 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); |
| 1558 | return wasm.zigObjectPtr().?.updateExports(wasm, pt, exported, export_indices); | 1680 | return wasm.zig_object.?.updateExports(wasm, pt, exported, export_indices); |
| 1559 | } | 1681 | } |
| 1560 | | 1682 | |
| 1561 | pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void { | 1683 | pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void { |
| 1562 | if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index); | 1684 | if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index); |
| 1563 | return wasm.zigObjectPtr().?.freeDecl(wasm, decl_index); | 1685 | return wasm.zig_object.?.freeDecl(wasm, decl_index); |
| 1564 | } | 1686 | } |
| 1565 | | 1687 | |
| 1566 | /// Assigns indexes to all indirect functions. | 1688 | /// Assigns indexes to all indirect functions. |
| ... | @@ -1570,7 +1692,7 @@ fn mapFunctionTable(wasm: *Wasm) void { | ... | @@ -1570,7 +1692,7 @@ fn mapFunctionTable(wasm: *Wasm) void { |
| 1570 | var it = wasm.function_table.iterator(); | 1692 | var it = wasm.function_table.iterator(); |
| 1571 | var index: u32 = 1; | 1693 | var index: u32 = 1; |
| 1572 | while (it.next()) |entry| { | 1694 | while (it.next()) |entry| { |
| 1573 | const symbol = entry.key_ptr.*.getSymbol(wasm); | 1695 | const symbol = wasm.symbolLocSymbol(entry.key_ptr.*); |
| 1574 | if (symbol.isAlive()) { | 1696 | if (symbol.isAlive()) { |
| 1575 | entry.value_ptr.* = index; | 1697 | entry.value_ptr.* = index; |
| 1576 | index += 1; | 1698 | index += 1; |
| ... | @@ -1586,7 +1708,7 @@ fn mapFunctionTable(wasm: *Wasm) void { | ... | @@ -1586,7 +1708,7 @@ fn mapFunctionTable(wasm: *Wasm) void { |
| 1586 | } else if (index > 1) { | 1708 | } else if (index > 1) { |
| 1587 | log.debug("Appending indirect function table", .{}); | 1709 | log.debug("Appending indirect function table", .{}); |
| 1588 | const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?; | 1710 | const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?; |
| 1589 | const symbol = sym_loc.getSymbol(wasm); | 1711 | const symbol = wasm.symbolLocSymbol(sym_loc); |
| 1590 | const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count]; | 1712 | const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count]; |
| 1591 | table.limits = .{ .min = index, .max = index, .flags = 0x1 }; | 1713 | table.limits = .{ .min = index, .max = index, .flags = 0x1 }; |
| 1592 | } | 1714 | } |
| ... | @@ -1625,10 +1747,11 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -1625,10 +1747,11 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 1625 | // Ensure we get the original symbol, so we verify the correct symbol on whether | 1747 | // Ensure we get the original symbol, so we verify the correct symbol on whether |
| 1626 | // it is dead or not and ensure an atom is removed when dead. | 1748 | // it is dead or not and ensure an atom is removed when dead. |
| 1627 | // This is required as we may have parsed aliases into atoms. | 1749 | // This is required as we may have parsed aliases into atoms. |
| 1628 | const sym = if (wasm.file(symbol_loc.file)) |obj_file| | 1750 | const sym = switch (symbol_loc.file) { |
| 1629 | obj_file.symbol(symbol_loc.index).* | 1751 | .zig_object => wasm.zig_object.?.symbols.items[@intFromEnum(symbol_loc.index)], |
| 1630 | else | 1752 | .none => wasm.synthetic_symbols.items[@intFromEnum(symbol_loc.index)], |
| 1631 | wasm.synthetic_symbols.items[@intFromEnum(symbol_loc.index)]; | 1753 | _ => wasm.objects.items[@intFromEnum(symbol_loc.file)].symtable[@intFromEnum(symbol_loc.index)], |
| | 1754 | }; |
| 1632 | | 1755 | |
| 1633 | // Dead symbols must be unlinked from the linked-list to prevent them | 1756 | // Dead symbols must be unlinked from the linked-list to prevent them |
| 1634 | // from being emit into the binary. | 1757 | // from being emit into the binary. |
| ... | @@ -1647,7 +1770,7 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -1647,7 +1770,7 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 1647 | offset = @intCast(atom.alignment.forward(offset)); | 1770 | offset = @intCast(atom.alignment.forward(offset)); |
| 1648 | atom.offset = offset; | 1771 | atom.offset = offset; |
| 1649 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ | 1772 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ |
| 1650 | symbol_loc.getName(wasm), | 1773 | wasm.symbolLocName(symbol_loc), |
| 1651 | offset, | 1774 | offset, |
| 1652 | offset + atom.size, | 1775 | offset + atom.size, |
| 1653 | atom.size, | 1776 | atom.size, |
| ... | @@ -1663,7 +1786,7 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -1663,7 +1786,7 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 1663 | /// For each data symbol, sets the virtual address. | 1786 | /// For each data symbol, sets the virtual address. |
| 1664 | fn allocateVirtualAddresses(wasm: *Wasm) void { | 1787 | fn allocateVirtualAddresses(wasm: *Wasm) void { |
| 1665 | for (wasm.resolved_symbols.keys()) |loc| { | 1788 | for (wasm.resolved_symbols.keys()) |loc| { |
| 1666 | const symbol = loc.getSymbol(wasm); | 1789 | const symbol = wasm.symbolLocSymbol(loc); |
| 1667 | if (symbol.tag != .data or symbol.isDead()) { | 1790 | if (symbol.tag != .data or symbol.isDead()) { |
| 1668 | // Only data symbols have virtual addresses. | 1791 | // Only data symbols have virtual addresses. |
| 1669 | // Dead symbols do not get allocated, so we don't need to set their virtual address either. | 1792 | // Dead symbols do not get allocated, so we don't need to set their virtual address either. |
| ... | @@ -1676,10 +1799,11 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { | ... | @@ -1676,10 +1799,11 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { |
| 1676 | | 1799 | |
| 1677 | const atom = wasm.getAtom(atom_index); | 1800 | const atom = wasm.getAtom(atom_index); |
| 1678 | const merge_segment = wasm.base.comp.config.output_mode != .Obj; | 1801 | const merge_segment = wasm.base.comp.config.output_mode != .Obj; |
| 1679 | const segment_info = if (atom.file != .null) | 1802 | const segment_info = switch (atom.file) { |
| 1680 | wasm.file(atom.file).?.segmentInfo() | 1803 | .zig_object => wasm.zig_object.?.segment_info.items, |
| 1681 | else | 1804 | .none => wasm.segment_info.values(), |
| 1682 | wasm.segment_info.values(); | 1805 | _ => wasm.objects.items[@intFromEnum(atom.file)].segment_info, |
| | 1806 | }; |
| 1683 | const segment_name = segment_info[symbol.index].outputName(merge_segment); | 1807 | const segment_name = segment_info[symbol.index].outputName(merge_segment); |
| 1684 | const segment_index = wasm.data_segments.get(segment_name).?; | 1808 | const segment_index = wasm.data_segments.get(segment_name).?; |
| 1685 | const segment = wasm.segments.items[segment_index]; | 1809 | const segment = wasm.segments.items[segment_index]; |
| ... | @@ -1737,13 +1861,12 @@ fn setupInitFunctions(wasm: *Wasm) !void { | ... | @@ -1737,13 +1861,12 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 1737 | const gpa = wasm.base.comp.gpa; | 1861 | const gpa = wasm.base.comp.gpa; |
| 1738 | const diags = &wasm.base.comp.link_diags; | 1862 | const diags = &wasm.base.comp.link_diags; |
| 1739 | // There's no constructors for Zig so we can simply search through linked object files only. | 1863 | // There's no constructors for Zig so we can simply search through linked object files only. |
| 1740 | for (wasm.objects.items) |file_index| { | 1864 | for (wasm.objects.items, 0..) |*object, object_index| { |
| 1741 | const object: Object = wasm.files.items(.data)[@intFromEnum(file_index)].object; | | |
| 1742 | try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len); | 1865 | try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len); |
| 1743 | for (object.init_funcs) |init_func| { | 1866 | for (object.init_funcs) |init_func| { |
| 1744 | const symbol = object.symtable[init_func.symbol_index]; | 1867 | const symbol = object.symtable[init_func.symbol_index]; |
| 1745 | const ty: std.wasm.Type = if (symbol.isUndefined()) ty: { | 1868 | const ty: std.wasm.Type = if (symbol.isUndefined()) ty: { |
| 1746 | const imp: types.Import = object.findImport(symbol); | 1869 | const imp: Import = object.findImport(symbol); |
| 1747 | break :ty object.func_types[imp.kind.function]; | 1870 | break :ty object.func_types[imp.kind.function]; |
| 1748 | } else ty: { | 1871 | } else ty: { |
| 1749 | const func_index = symbol.index - object.imported_functions_count; | 1872 | const func_index = symbol.index - object.imported_functions_count; |
| ... | @@ -1757,10 +1880,13 @@ fn setupInitFunctions(wasm: *Wasm) !void { | ... | @@ -1757,10 +1880,13 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 1757 | log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)}); | 1880 | log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)}); |
| 1758 | wasm.init_funcs.appendAssumeCapacity(.{ | 1881 | wasm.init_funcs.appendAssumeCapacity(.{ |
| 1759 | .index = @enumFromInt(init_func.symbol_index), | 1882 | .index = @enumFromInt(init_func.symbol_index), |
| 1760 | .file = file_index, | 1883 | .file = @enumFromInt(object_index), |
| 1761 | .priority = init_func.priority, | 1884 | .priority = init_func.priority, |
| 1762 | }); | 1885 | }); |
| 1763 | try wasm.mark(.{ .index = @enumFromInt(init_func.symbol_index), .file = file_index }); | 1886 | try wasm.mark(.{ |
| | 1887 | .index = @enumFromInt(init_func.symbol_index), |
| | 1888 | .file = @enumFromInt(object_index), |
| | 1889 | }); |
| 1764 | } | 1890 | } |
| 1765 | } | 1891 | } |
| 1766 | | 1892 | |
| ... | @@ -1834,7 +1960,7 @@ fn createSyntheticFunction( | ... | @@ -1834,7 +1960,7 @@ fn createSyntheticFunction( |
| 1834 | ) !void { | 1960 | ) !void { |
| 1835 | const gpa = wasm.base.comp.gpa; | 1961 | const gpa = wasm.base.comp.gpa; |
| 1836 | const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol? | 1962 | const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol? |
| 1837 | const symbol = loc.getSymbol(wasm); | 1963 | const symbol = wasm.symbolLocSymbol(loc); |
| 1838 | if (symbol.isDead()) { | 1964 | if (symbol.isDead()) { |
| 1839 | return; | 1965 | return; |
| 1840 | } | 1966 | } |
| ... | @@ -1843,13 +1969,13 @@ fn createSyntheticFunction( | ... | @@ -1843,13 +1969,13 @@ fn createSyntheticFunction( |
| 1843 | const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count())); | 1969 | const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count())); |
| 1844 | try wasm.functions.putNoClobber( | 1970 | try wasm.functions.putNoClobber( |
| 1845 | gpa, | 1971 | gpa, |
| 1846 | .{ .file = .null, .index = func_index }, | 1972 | .{ .file = .none, .index = func_index }, |
| 1847 | .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index }, | 1973 | .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index }, |
| 1848 | ); | 1974 | ); |
| 1849 | symbol.index = func_index; | 1975 | symbol.index = func_index; |
| 1850 | | 1976 | |
| 1851 | // create the atom that will be output into the final binary | 1977 | // create the atom that will be output into the final binary |
| 1852 | const atom_index = try wasm.createAtom(loc.index, .null); | 1978 | const atom_index = try wasm.createAtom(loc.index, .none); |
| 1853 | const atom = wasm.getAtomPtr(atom_index); | 1979 | const atom = wasm.getAtomPtr(atom_index); |
| 1854 | atom.size = @intCast(function_body.items.len); | 1980 | atom.size = @intCast(function_body.items.len); |
| 1855 | atom.code = function_body.moveToUnmanaged(); | 1981 | atom.code = function_body.moveToUnmanaged(); |
| ... | @@ -1866,13 +1992,13 @@ pub fn createFunction( | ... | @@ -1866,13 +1992,13 @@ pub fn createFunction( |
| 1866 | function_body: *std.ArrayList(u8), | 1992 | function_body: *std.ArrayList(u8), |
| 1867 | relocations: *std.ArrayList(Relocation), | 1993 | relocations: *std.ArrayList(Relocation), |
| 1868 | ) !Symbol.Index { | 1994 | ) !Symbol.Index { |
| 1869 | return wasm.zigObjectPtr().?.createFunction(wasm, symbol_name, func_ty, function_body, relocations); | 1995 | return wasm.zig_object.?.createFunction(wasm, symbol_name, func_ty, function_body, relocations); |
| 1870 | } | 1996 | } |
| 1871 | | 1997 | |
| 1872 | /// If required, sets the function index in the `start` section. | 1998 | /// If required, sets the function index in the `start` section. |
| 1873 | fn setupStartSection(wasm: *Wasm) !void { | 1999 | fn setupStartSection(wasm: *Wasm) !void { |
| 1874 | if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| { | 2000 | if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| { |
| 1875 | wasm.entry = loc.getSymbol(wasm).index; | 2001 | wasm.entry = wasm.symbolLocSymbol(loc).index; |
| 1876 | } | 2002 | } |
| 1877 | } | 2003 | } |
| 1878 | | 2004 | |
| ... | @@ -1884,7 +2010,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { | ... | @@ -1884,7 +2010,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 1884 | if (!shared_memory) return; | 2010 | if (!shared_memory) return; |
| 1885 | | 2011 | |
| 1886 | // ensure function is marked as we must emit it | 2012 | // ensure function is marked as we must emit it |
| 1887 | wasm.findGlobalSymbol("__wasm_init_tls").?.getSymbol(wasm).mark(); | 2013 | wasm.symbolLocSymbol(wasm.findGlobalSymbol("__wasm_init_tls").?).mark(); |
| 1888 | | 2014 | |
| 1889 | var function_body = std.ArrayList(u8).init(gpa); | 2015 | var function_body = std.ArrayList(u8).init(gpa); |
| 1890 | defer function_body.deinit(); | 2016 | defer function_body.deinit(); |
| ... | @@ -1905,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { | ... | @@ -1905,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 1905 | | 2031 | |
| 1906 | const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?; | 2032 | const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?; |
| 1907 | try writer.writeByte(std.wasm.opcode(.global_set)); | 2033 | try writer.writeByte(std.wasm.opcode(.global_set)); |
| 1908 | try leb.writeUleb128(writer, tls_base_loc.getSymbol(wasm).index); | 2034 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index); |
| 1909 | | 2035 | |
| 1910 | // load stack values for the bulk-memory operation | 2036 | // load stack values for the bulk-memory operation |
| 1911 | { | 2037 | { |
| ... | @@ -1933,8 +2059,8 @@ fn initializeTLSFunction(wasm: *Wasm) !void { | ... | @@ -1933,8 +2059,8 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 1933 | // generated by the linker. | 2059 | // generated by the linker. |
| 1934 | if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| { | 2060 | if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| { |
| 1935 | try writer.writeByte(std.wasm.opcode(.call)); | 2061 | try writer.writeByte(std.wasm.opcode(.call)); |
| 1936 | try leb.writeUleb128(writer, loc.getSymbol(wasm).index); | 2062 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index); |
| 1937 | loc.getSymbol(wasm).mark(); | 2063 | wasm.symbolLocSymbol(loc).mark(); |
| 1938 | } | 2064 | } |
| 1939 | | 2065 | |
| 1940 | try writer.writeByte(std.wasm.opcode(.end)); | 2066 | try writer.writeByte(std.wasm.opcode(.end)); |
| ... | @@ -1950,27 +2076,27 @@ fn setupImports(wasm: *Wasm) !void { | ... | @@ -1950,27 +2076,27 @@ fn setupImports(wasm: *Wasm) !void { |
| 1950 | const gpa = wasm.base.comp.gpa; | 2076 | const gpa = wasm.base.comp.gpa; |
| 1951 | log.debug("Merging imports", .{}); | 2077 | log.debug("Merging imports", .{}); |
| 1952 | for (wasm.resolved_symbols.keys()) |symbol_loc| { | 2078 | for (wasm.resolved_symbols.keys()) |symbol_loc| { |
| 1953 | const obj_file = wasm.file(symbol_loc.file) orelse { | 2079 | const object_id = symbol_loc.file.unwrap() orelse { |
| 1954 | // Synthetic symbols will already exist in the `import` section | 2080 | // Synthetic symbols will already exist in the `import` section |
| 1955 | continue; | 2081 | continue; |
| 1956 | }; | 2082 | }; |
| 1957 | | 2083 | |
| 1958 | const symbol = symbol_loc.getSymbol(wasm); | 2084 | const symbol = wasm.symbolLocSymbol(symbol_loc); |
| 1959 | if (symbol.isDead() or | 2085 | if (symbol.isDead() or |
| 1960 | !symbol.requiresImport() or | 2086 | !symbol.requiresImport() or |
| 1961 | std.mem.eql(u8, symbol_loc.getName(wasm), "__indirect_function_table")) | 2087 | std.mem.eql(u8, wasm.symbolLocName(symbol_loc), "__indirect_function_table")) |
| 1962 | { | 2088 | { |
| 1963 | continue; | 2089 | continue; |
| 1964 | } | 2090 | } |
| 1965 | | 2091 | |
| 1966 | log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)}); | 2092 | log.debug("Symbol '{s}' will be imported from the host", .{wasm.symbolLocName(symbol_loc)}); |
| 1967 | const import = obj_file.import(symbol_loc.index); | 2093 | const import = objectImport(wasm, object_id, symbol_loc.index); |
| 1968 | | 2094 | |
| 1969 | // We copy the import to a new import to ensure the names contain references | 2095 | // We copy the import to a new import to ensure the names contain references |
| 1970 | // to the internal string table, rather than of the object file. | 2096 | // to the internal string table, rather than of the object file. |
| 1971 | const new_imp: types.Import = .{ | 2097 | const new_imp: Import = .{ |
| 1972 | .module_name = try wasm.string_table.put(gpa, obj_file.string(import.module_name)), | 2098 | .module_name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.module_name)), |
| 1973 | .name = try wasm.string_table.put(gpa, obj_file.string(import.name)), | 2099 | .name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.name)), |
| 1974 | .kind = import.kind, | 2100 | .kind = import.kind, |
| 1975 | }; | 2101 | }; |
| 1976 | // TODO: De-duplicate imports when they contain the same names and type | 2102 | // TODO: De-duplicate imports when they contain the same names and type |
| ... | @@ -1983,8 +2109,8 @@ fn setupImports(wasm: *Wasm) !void { | ... | @@ -1983,8 +2109,8 @@ fn setupImports(wasm: *Wasm) !void { |
| 1983 | var table_index: u32 = 0; | 2109 | var table_index: u32 = 0; |
| 1984 | var it = wasm.imports.iterator(); | 2110 | var it = wasm.imports.iterator(); |
| 1985 | while (it.next()) |entry| { | 2111 | while (it.next()) |entry| { |
| 1986 | const symbol = entry.key_ptr.*.getSymbol(wasm); | 2112 | const symbol = wasm.symbolLocSymbol(entry.key_ptr.*); |
| 1987 | const import: types.Import = entry.value_ptr.*; | 2113 | const import: Import = entry.value_ptr.*; |
| 1988 | switch (import.kind) { | 2114 | switch (import.kind) { |
| 1989 | .function => { | 2115 | .function => { |
| 1990 | symbol.index = function_index; | 2116 | symbol.index = function_index; |
| ... | @@ -2021,12 +2147,12 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2021,12 +2147,12 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2021 | defer removed_duplicates.deinit(); | 2147 | defer removed_duplicates.deinit(); |
| 2022 | | 2148 | |
| 2023 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 2149 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 2024 | const obj_file = wasm.file(sym_loc.file) orelse { | 2150 | const object_id = sym_loc.file.unwrap() orelse { |
| 2025 | // Synthetic symbols already live in the corresponding sections. | 2151 | // Synthetic symbols already live in the corresponding sections. |
| 2026 | continue; | 2152 | continue; |
| 2027 | }; | 2153 | }; |
| 2028 | | 2154 | |
| 2029 | const symbol = obj_file.symbol(sym_loc.index); | 2155 | const symbol = objectSymbol(wasm, object_id, sym_loc.index); |
| 2030 | if (symbol.isDead() or symbol.isUndefined()) { | 2156 | if (symbol.isDead() or symbol.isUndefined()) { |
| 2031 | // Skip undefined symbols as they go in the `import` section | 2157 | // Skip undefined symbols as they go in the `import` section |
| 2032 | continue; | 2158 | continue; |
| ... | @@ -2044,7 +2170,7 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2044,7 +2170,7 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2044 | // we only emit a single function, instead of duplicates. | 2170 | // we only emit a single function, instead of duplicates. |
| 2045 | // we favor keeping the global over a local. | 2171 | // we favor keeping the global over a local. |
| 2046 | const original_loc: SymbolLoc = .{ .file = gop.key_ptr.file, .index = gop.value_ptr.sym_index }; | 2172 | const original_loc: SymbolLoc = .{ .file = gop.key_ptr.file, .index = gop.value_ptr.sym_index }; |
| 2047 | const original_sym = original_loc.getSymbol(wasm); | 2173 | const original_sym = wasm.symbolLocSymbol(original_loc); |
| 2048 | if (original_sym.isLocal() and symbol.isGlobal()) { | 2174 | if (original_sym.isLocal() and symbol.isGlobal()) { |
| 2049 | original_sym.unmark(); | 2175 | original_sym.unmark(); |
| 2050 | try wasm.discarded.put(gpa, original_loc, sym_loc); | 2176 | try wasm.discarded.put(gpa, original_loc, sym_loc); |
| ... | @@ -2056,20 +2182,23 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2056,20 +2182,23 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2056 | continue; | 2182 | continue; |
| 2057 | } | 2183 | } |
| 2058 | } | 2184 | } |
| 2059 | gop.value_ptr.* = .{ .func = obj_file.function(sym_loc.index), .sym_index = sym_loc.index }; | 2185 | gop.value_ptr.* = .{ |
| | 2186 | .func = objectFunction(wasm, object_id, sym_loc.index), |
| | 2187 | .sym_index = sym_loc.index, |
| | 2188 | }; |
| 2060 | symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count; | 2189 | symbol.index = @as(u32, @intCast(gop.index)) + wasm.imported_functions_count; |
| 2061 | }, | 2190 | }, |
| 2062 | .global => { | 2191 | .global => { |
| 2063 | const index = symbol.index - obj_file.importedFunctions(); | 2192 | const index = symbol.index - objectImportedFunctions(wasm, object_id); |
| 2064 | const original_global = obj_file.globals()[index]; | 2193 | const original_global = objectGlobals(wasm, object_id)[index]; |
| 2065 | symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count; | 2194 | symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count; |
| 2066 | try wasm.wasm_globals.append(gpa, original_global); | 2195 | try wasm.wasm_globals.append(gpa, original_global); |
| 2067 | }, | 2196 | }, |
| 2068 | .table => { | 2197 | .table => { |
| 2069 | const index = symbol.index - obj_file.importedFunctions(); | 2198 | const index = symbol.index - objectImportedFunctions(wasm, object_id); |
| 2070 | // assert it's a regular relocatable object file as `ZigObject` will never | 2199 | // assert it's a regular relocatable object file as `ZigObject` will never |
| 2071 | // contain a table. | 2200 | // contain a table. |
| 2072 | const original_table = obj_file.object.tables[index]; | 2201 | const original_table = wasm.objectById(object_id).?.tables[index]; |
| 2073 | symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count; | 2202 | symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count; |
| 2074 | try wasm.tables.append(gpa, original_table); | 2203 | try wasm.tables.append(gpa, original_table); |
| 2075 | }, | 2204 | }, |
| ... | @@ -2081,7 +2210,7 @@ fn mergeSections(wasm: *Wasm) !void { | ... | @@ -2081,7 +2210,7 @@ fn mergeSections(wasm: *Wasm) !void { |
| 2081 | // For any removed duplicates, remove them from the resolved symbols list | 2210 | // For any removed duplicates, remove them from the resolved symbols list |
| 2082 | for (removed_duplicates.items) |sym_loc| { | 2211 | for (removed_duplicates.items) |sym_loc| { |
| 2083 | assert(wasm.resolved_symbols.swapRemove(sym_loc)); | 2212 | assert(wasm.resolved_symbols.swapRemove(sym_loc)); |
| 2084 | gc_log.debug("Removed duplicate for function '{s}'", .{sym_loc.getName(wasm)}); | 2213 | gc_log.debug("Removed duplicate for function '{s}'", .{wasm.symbolLocName(sym_loc)}); |
| 2085 | } | 2214 | } |
| 2086 | | 2215 | |
| 2087 | log.debug("Merged ({d}) functions", .{wasm.functions.count()}); | 2216 | log.debug("Merged ({d}) functions", .{wasm.functions.count()}); |
| ... | @@ -2102,26 +2231,26 @@ fn mergeTypes(wasm: *Wasm) !void { | ... | @@ -2102,26 +2231,26 @@ fn mergeTypes(wasm: *Wasm) !void { |
| 2102 | defer dirty.deinit(); | 2231 | defer dirty.deinit(); |
| 2103 | | 2232 | |
| 2104 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 2233 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 2105 | const obj_file = wasm.file(sym_loc.file) orelse { | 2234 | const object_id = sym_loc.file.unwrap() orelse { |
| 2106 | // zig code-generated symbols are already present in final type section | 2235 | // zig code-generated symbols are already present in final type section |
| 2107 | continue; | 2236 | continue; |
| 2108 | }; | 2237 | }; |
| 2109 | | 2238 | |
| 2110 | const symbol = obj_file.symbol(sym_loc.index); | 2239 | const symbol = objectSymbol(wasm, object_id, sym_loc.index); |
| 2111 | if (symbol.tag != .function or symbol.isDead()) { | 2240 | if (symbol.tag != .function or symbol.isDead()) { |
| 2112 | // Only functions have types. Only retrieve the type of referenced functions. | 2241 | // Only functions have types. Only retrieve the type of referenced functions. |
| 2113 | continue; | 2242 | continue; |
| 2114 | } | 2243 | } |
| 2115 | | 2244 | |
| 2116 | if (symbol.isUndefined()) { | 2245 | if (symbol.isUndefined()) { |
| 2117 | log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(wasm)}); | 2246 | log.debug("Adding type from extern function '{s}'", .{wasm.symbolLocName(sym_loc)}); |
| 2118 | const import: *types.Import = wasm.imports.getPtr(sym_loc) orelse continue; | 2247 | const import: *Import = wasm.imports.getPtr(sym_loc) orelse continue; |
| 2119 | const original_type = obj_file.funcTypes()[import.kind.function]; | 2248 | const original_type = objectFuncTypes(wasm, object_id)[import.kind.function]; |
| 2120 | import.kind.function = try wasm.putOrGetFuncType(original_type); | 2249 | import.kind.function = try wasm.putOrGetFuncType(original_type); |
| 2121 | } else if (!dirty.contains(symbol.index)) { | 2250 | } else if (!dirty.contains(symbol.index)) { |
| 2122 | log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)}); | 2251 | log.debug("Adding type from function '{s}'", .{wasm.symbolLocName(sym_loc)}); |
| 2123 | const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func; | 2252 | const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count].func; |
| 2124 | func.type_index = try wasm.putOrGetFuncType(obj_file.funcTypes()[func.type_index]); | 2253 | func.type_index = try wasm.putOrGetFuncType(objectFuncTypes(wasm, object_id)[func.type_index]); |
| 2125 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); | 2254 | dirty.putAssumeCapacityNoClobber(symbol.index, {}); |
| 2126 | } | 2255 | } |
| 2127 | } | 2256 | } |
| ... | @@ -2142,7 +2271,7 @@ fn checkExportNames(wasm: *Wasm) !void { | ... | @@ -2142,7 +2271,7 @@ fn checkExportNames(wasm: *Wasm) !void { |
| 2142 | continue; | 2271 | continue; |
| 2143 | }; | 2272 | }; |
| 2144 | | 2273 | |
| 2145 | const symbol = loc.getSymbol(wasm); | 2274 | const symbol = wasm.symbolLocSymbol(loc); |
| 2146 | symbol.setFlag(.WASM_SYM_EXPORTED); | 2275 | symbol.setFlag(.WASM_SYM_EXPORTED); |
| 2147 | } | 2276 | } |
| 2148 | | 2277 | |
| ... | @@ -2159,15 +2288,15 @@ fn setupExports(wasm: *Wasm) !void { | ... | @@ -2159,15 +2288,15 @@ fn setupExports(wasm: *Wasm) !void { |
| 2159 | log.debug("Building exports from symbols", .{}); | 2288 | log.debug("Building exports from symbols", .{}); |
| 2160 | | 2289 | |
| 2161 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 2290 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 2162 | const symbol = sym_loc.getSymbol(wasm); | 2291 | const symbol = wasm.symbolLocSymbol(sym_loc); |
| 2163 | if (!symbol.isExported(comp.config.rdynamic)) continue; | 2292 | if (!symbol.isExported(comp.config.rdynamic)) continue; |
| 2164 | | 2293 | |
| 2165 | const sym_name = sym_loc.getName(wasm); | 2294 | const sym_name = wasm.symbolLocName(sym_loc); |
| 2166 | const export_name = if (sym_loc.file == .null) | 2295 | const export_name = if (sym_loc.file == .none) |
| 2167 | symbol.name | 2296 | symbol.name |
| 2168 | else | 2297 | else |
| 2169 | try wasm.string_table.put(gpa, sym_name); | 2298 | try wasm.string_table.put(gpa, sym_name); |
| 2170 | const exp: types.Export = if (symbol.tag == .data) exp: { | 2299 | const exp: Export = if (symbol.tag == .data) exp: { |
| 2171 | const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len)); | 2300 | const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len)); |
| 2172 | try wasm.wasm_globals.append(gpa, .{ | 2301 | try wasm.wasm_globals.append(gpa, .{ |
| 2173 | .global_type = .{ .valtype = .i32, .mutable = false }, | 2302 | .global_type = .{ .valtype = .i32, .mutable = false }, |
| ... | @@ -2206,7 +2335,7 @@ fn setupStart(wasm: *Wasm) !void { | ... | @@ -2206,7 +2335,7 @@ fn setupStart(wasm: *Wasm) !void { |
| 2206 | return error.FlushFailure; | 2335 | return error.FlushFailure; |
| 2207 | }; | 2336 | }; |
| 2208 | | 2337 | |
| 2209 | const symbol = symbol_loc.getSymbol(wasm); | 2338 | const symbol = wasm.symbolLocSymbol(symbol_loc); |
| 2210 | if (symbol.tag != .function) { | 2339 | if (symbol.tag != .function) { |
| 2211 | var err = try diags.addErrorWithNotes(0); | 2340 | var err = try diags.addErrorWithNotes(0); |
| 2212 | try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name}); | 2341 | try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name}); |
| ... | @@ -2240,7 +2369,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2240,7 +2369,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2240 | const is_obj = comp.config.output_mode == .Obj; | 2369 | const is_obj = comp.config.output_mode == .Obj; |
| 2241 | | 2370 | |
| 2242 | const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: { | 2371 | const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: { |
| 2243 | const sym = loc.getSymbol(wasm); | 2372 | const sym = wasm.symbolLocSymbol(loc); |
| 2244 | break :index sym.index - wasm.imported_globals_count; | 2373 | break :index sym.index - wasm.imported_globals_count; |
| 2245 | } else null; | 2374 | } else null; |
| 2246 | | 2375 | |
| ... | @@ -2262,15 +2391,15 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2262,15 +2391,15 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2262 | // set TLS-related symbols | 2391 | // set TLS-related symbols |
| 2263 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { | 2392 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { |
| 2264 | if (wasm.findGlobalSymbol("__tls_size")) |loc| { | 2393 | if (wasm.findGlobalSymbol("__tls_size")) |loc| { |
| 2265 | const sym = loc.getSymbol(wasm); | 2394 | const sym = wasm.symbolLocSymbol(loc); |
| 2266 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size); | 2395 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size); |
| 2267 | } | 2396 | } |
| 2268 | if (wasm.findGlobalSymbol("__tls_align")) |loc| { | 2397 | if (wasm.findGlobalSymbol("__tls_align")) |loc| { |
| 2269 | const sym = loc.getSymbol(wasm); | 2398 | const sym = wasm.symbolLocSymbol(loc); |
| 2270 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?); | 2399 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?); |
| 2271 | } | 2400 | } |
| 2272 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { | 2401 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { |
| 2273 | const sym = loc.getSymbol(wasm); | 2402 | const sym = wasm.symbolLocSymbol(loc); |
| 2274 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory) | 2403 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory) |
| 2275 | @as(i32, 0) | 2404 | @as(i32, 0) |
| 2276 | else | 2405 | else |
| ... | @@ -2288,7 +2417,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2288,7 +2417,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2288 | // align to pointer size | 2417 | // align to pointer size |
| 2289 | memory_ptr = mem.alignForward(u64, memory_ptr, 4); | 2418 | memory_ptr = mem.alignForward(u64, memory_ptr, 4); |
| 2290 | const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data); | 2419 | const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data); |
| 2291 | const sym = loc.getSymbol(wasm); | 2420 | const sym = wasm.symbolLocSymbol(loc); |
| 2292 | sym.mark(); | 2421 | sym.mark(); |
| 2293 | sym.virtual_address = @as(u32, @intCast(memory_ptr)); | 2422 | sym.virtual_address = @as(u32, @intCast(memory_ptr)); |
| 2294 | memory_ptr += 4; | 2423 | memory_ptr += 4; |
| ... | @@ -2305,7 +2434,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2305,7 +2434,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2305 | // One of the linked object files has a reference to the __heap_base symbol. | 2434 | // One of the linked object files has a reference to the __heap_base symbol. |
| 2306 | // We must set its virtual address so it can be used in relocations. | 2435 | // We must set its virtual address so it can be used in relocations. |
| 2307 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { | 2436 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { |
| 2308 | const symbol = loc.getSymbol(wasm); | 2437 | const symbol = wasm.symbolLocSymbol(loc); |
| 2309 | symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr)); | 2438 | symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr)); |
| 2310 | } | 2439 | } |
| 2311 | | 2440 | |
| ... | @@ -2335,7 +2464,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2335,7 +2464,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2335 | log.debug("Total memory pages: {d}", .{wasm.memories.limits.min}); | 2464 | log.debug("Total memory pages: {d}", .{wasm.memories.limits.min}); |
| 2336 | | 2465 | |
| 2337 | if (wasm.findGlobalSymbol("__heap_end")) |loc| { | 2466 | if (wasm.findGlobalSymbol("__heap_end")) |loc| { |
| 2338 | const symbol = loc.getSymbol(wasm); | 2467 | const symbol = wasm.symbolLocSymbol(loc); |
| 2339 | symbol.virtual_address = @as(u32, @intCast(memory_ptr)); | 2468 | symbol.virtual_address = @as(u32, @intCast(memory_ptr)); |
| 2340 | } | 2469 | } |
| 2341 | | 2470 | |
| ... | @@ -2364,18 +2493,17 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2364,18 +2493,17 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2364 | /// From a given object's index and the index of the segment, returns the corresponding | 2493 | /// From a given object's index and the index of the segment, returns the corresponding |
| 2365 | /// index of the segment within the final data section. When the segment does not yet | 2494 | /// index of the segment within the final data section. When the segment does not yet |
| 2366 | /// exist, a new one will be initialized and appended. The new index will be returned in that case. | 2495 | /// exist, a new one will be initialized and appended. The new index will be returned in that case. |
| 2367 | pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Symbol.Index) !u32 { | 2496 | pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !u32 { |
| 2368 | const comp = wasm.base.comp; | 2497 | const comp = wasm.base.comp; |
| 2369 | const gpa = comp.gpa; | 2498 | const gpa = comp.gpa; |
| 2370 | const diags = &wasm.base.comp.link_diags; | 2499 | const diags = &wasm.base.comp.link_diags; |
| 2371 | const obj_file = wasm.file(file_index).?; | 2500 | const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)]; |
| 2372 | const symbol = obj_file.symbols()[@intFromEnum(symbol_index)]; | | |
| 2373 | const index: u32 = @intCast(wasm.segments.items.len); | 2501 | const index: u32 = @intCast(wasm.segments.items.len); |
| 2374 | const shared_memory = comp.config.shared_memory; | 2502 | const shared_memory = comp.config.shared_memory; |
| 2375 | | 2503 | |
| 2376 | switch (symbol.tag) { | 2504 | switch (symbol.tag) { |
| 2377 | .data => { | 2505 | .data => { |
| 2378 | const segment_info = obj_file.segmentInfo()[symbol.index]; | 2506 | const segment_info = objectSegmentInfo(wasm, object_id)[symbol.index]; |
| 2379 | const merge_segment = comp.config.output_mode != .Obj; | 2507 | const merge_segment = comp.config.output_mode != .Obj; |
| 2380 | const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment)); | 2508 | const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment)); |
| 2381 | if (!result.found_existing) { | 2509 | if (!result.found_existing) { |
| ... | @@ -2404,7 +2532,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym | ... | @@ -2404,7 +2532,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym |
| 2404 | break :blk index; | 2532 | break :blk index; |
| 2405 | }, | 2533 | }, |
| 2406 | .section => { | 2534 | .section => { |
| 2407 | const section_name = obj_file.symbolName(symbol_index); | 2535 | const section_name = objectSymbolName(wasm, object_id, symbol_index); |
| 2408 | if (mem.eql(u8, section_name, ".debug_info")) { | 2536 | if (mem.eql(u8, section_name, ".debug_info")) { |
| 2409 | return wasm.debug_info_index orelse blk: { | 2537 | return wasm.debug_info_index orelse blk: { |
| 2410 | wasm.debug_info_index = index; | 2538 | wasm.debug_info_index = index; |
| ... | @@ -2456,7 +2584,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym | ... | @@ -2456,7 +2584,7 @@ pub fn getMatchingSegment(wasm: *Wasm, file_index: File.Index, symbol_index: Sym |
| 2456 | } else { | 2584 | } else { |
| 2457 | var err = try diags.addErrorWithNotes(1); | 2585 | var err = try diags.addErrorWithNotes(1); |
| 2458 | try err.addMsg("found unknown section '{s}'", .{section_name}); | 2586 | try err.addMsg("found unknown section '{s}'", .{section_name}); |
| 2459 | try err.addNote("defined in '{s}'", .{obj_file.path()}); | 2587 | try err.addNote("defined in '{s}'", .{objectPath(wasm, object_id)}); |
| 2460 | return error.UnexpectedValue; | 2588 | return error.UnexpectedValue; |
| 2461 | } | 2589 | } |
| 2462 | }, | 2590 | }, |
| ... | @@ -2523,7 +2651,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no | ... | @@ -2523,7 +2651,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no |
| 2523 | const link_libcpp = comp.config.link_libcpp; | 2651 | const link_libcpp = comp.config.link_libcpp; |
| 2524 | const wasi_exec_model = comp.config.wasi_exec_model; | 2652 | const wasi_exec_model = comp.config.wasi_exec_model; |
| 2525 | | 2653 | |
| 2526 | if (wasm.zigObjectPtr()) |zig_object| { | 2654 | if (wasm.zig_object) |zig_object| { |
| 2527 | try zig_object.flushModule(wasm, tid); | 2655 | try zig_object.flushModule(wasm, tid); |
| 2528 | } | 2656 | } |
| 2529 | | 2657 | |
| ... | @@ -2578,17 +2706,17 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no | ... | @@ -2578,17 +2706,17 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no |
| 2578 | log.warn("Unexpected file format at path: '{s}'", .{path}); | 2706 | log.warn("Unexpected file format at path: '{s}'", .{path}); |
| 2579 | } | 2707 | } |
| 2580 | | 2708 | |
| 2581 | if (wasm.zig_object_index != .null) { | 2709 | if (wasm.zig_object != null) { |
| 2582 | try wasm.resolveSymbolsInObject(wasm.zig_object_index); | 2710 | try wasm.resolveSymbolsInObject(.zig_object); |
| 2583 | } | 2711 | } |
| 2584 | if (diags.hasErrors()) return error.FlushFailure; | 2712 | if (diags.hasErrors()) return error.FlushFailure; |
| 2585 | for (wasm.objects.items) |object_index| { | 2713 | for (0..wasm.objects.items.len) |object_index| { |
| 2586 | try wasm.resolveSymbolsInObject(object_index); | 2714 | try wasm.resolveSymbolsInObject(@enumFromInt(object_index)); |
| 2587 | } | 2715 | } |
| 2588 | if (diags.hasErrors()) return error.FlushFailure; | 2716 | if (diags.hasErrors()) return error.FlushFailure; |
| 2589 | | 2717 | |
| 2590 | var emit_features_count: u32 = 0; | 2718 | var emit_features_count: u32 = 0; |
| 2591 | var enabled_features: [@typeInfo(types.Feature.Tag).@"enum".fields.len]bool = undefined; | 2719 | var enabled_features: [@typeInfo(Feature.Tag).@"enum".fields.len]bool = undefined; |
| 2592 | try wasm.validateFeatures(&enabled_features, &emit_features_count); | 2720 | try wasm.validateFeatures(&enabled_features, &emit_features_count); |
| 2593 | try wasm.resolveSymbolsInArchives(); | 2721 | try wasm.resolveSymbolsInArchives(); |
| 2594 | if (diags.hasErrors()) return error.FlushFailure; | 2722 | if (diags.hasErrors()) return error.FlushFailure; |
| ... | @@ -2622,7 +2750,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no | ... | @@ -2622,7 +2750,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no |
| 2622 | /// Writes the WebAssembly in-memory module to the file | 2750 | /// Writes the WebAssembly in-memory module to the file |
| 2623 | fn writeToFile( | 2751 | fn writeToFile( |
| 2624 | wasm: *Wasm, | 2752 | wasm: *Wasm, |
| 2625 | enabled_features: [@typeInfo(types.Feature.Tag).@"enum".fields.len]bool, | 2753 | enabled_features: [@typeInfo(Feature.Tag).@"enum".fields.len]bool, |
| 2626 | feature_count: u32, | 2754 | feature_count: u32, |
| 2627 | arena: Allocator, | 2755 | arena: Allocator, |
| 2628 | ) !void { | 2756 | ) !void { |
| ... | @@ -2688,14 +2816,14 @@ fn writeToFile( | ... | @@ -2688,14 +2816,14 @@ fn writeToFile( |
| 2688 | | 2816 | |
| 2689 | var it = wasm.imports.iterator(); | 2817 | var it = wasm.imports.iterator(); |
| 2690 | while (it.next()) |entry| { | 2818 | while (it.next()) |entry| { |
| 2691 | assert(entry.key_ptr.*.getSymbol(wasm).isUndefined()); | 2819 | assert(wasm.symbolLocSymbol(entry.key_ptr.*).isUndefined()); |
| 2692 | const import = entry.value_ptr.*; | 2820 | const import = entry.value_ptr.*; |
| 2693 | try wasm.emitImport(binary_writer, import); | 2821 | try wasm.emitImport(binary_writer, import); |
| 2694 | } | 2822 | } |
| 2695 | | 2823 | |
| 2696 | if (import_memory) { | 2824 | if (import_memory) { |
| 2697 | const mem_name = if (is_obj) "__linear_memory" else "memory"; | 2825 | const mem_name = if (is_obj) "__linear_memory" else "memory"; |
| 2698 | const mem_imp: types.Import = .{ | 2826 | const mem_imp: Import = .{ |
| 2699 | .module_name = try wasm.string_table.put(gpa, wasm.host_name), | 2827 | .module_name = try wasm.string_table.put(gpa, wasm.host_name), |
| 2700 | .name = try wasm.string_table.put(gpa, mem_name), | 2828 | .name = try wasm.string_table.put(gpa, mem_name), |
| 2701 | .kind = .{ .memory = wasm.memories.limits }, | 2829 | .kind = .{ .memory = wasm.memories.limits }, |
| ... | @@ -2829,7 +2957,7 @@ fn writeToFile( | ... | @@ -2829,7 +2957,7 @@ fn writeToFile( |
| 2829 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2957 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2830 | | 2958 | |
| 2831 | const table_loc = wasm.findGlobalSymbol("__indirect_function_table").?; | 2959 | const table_loc = wasm.findGlobalSymbol("__indirect_function_table").?; |
| 2832 | const table_sym = table_loc.getSymbol(wasm); | 2960 | const table_sym = wasm.symbolLocSymbol(table_loc); |
| 2833 | | 2961 | |
| 2834 | const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually | 2962 | const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually |
| 2835 | try leb.writeUleb128(binary_writer, flags); | 2963 | try leb.writeUleb128(binary_writer, flags); |
| ... | @@ -2843,7 +2971,7 @@ fn writeToFile( | ... | @@ -2843,7 +2971,7 @@ fn writeToFile( |
| 2843 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.function_table.count()))); | 2971 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.function_table.count()))); |
| 2844 | var symbol_it = wasm.function_table.keyIterator(); | 2972 | var symbol_it = wasm.function_table.keyIterator(); |
| 2845 | while (symbol_it.next()) |symbol_loc_ptr| { | 2973 | while (symbol_it.next()) |symbol_loc_ptr| { |
| 2846 | const sym = symbol_loc_ptr.getSymbol(wasm); | 2974 | const sym = wasm.symbolLocSymbol(symbol_loc_ptr.*); |
| 2847 | std.debug.assert(sym.isAlive()); | 2975 | std.debug.assert(sym.isAlive()); |
| 2848 | std.debug.assert(sym.index < wasm.functions.count() + wasm.imported_functions_count); | 2976 | std.debug.assert(sym.index < wasm.functions.count() + wasm.imported_functions_count); |
| 2849 | try leb.writeUleb128(binary_writer, sym.index); | 2977 | try leb.writeUleb128(binary_writer, sym.index); |
| ... | @@ -3183,7 +3311,7 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con | ... | @@ -3183,7 +3311,7 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con |
| 3183 | try leb.writeUleb128(writer, features_count); | 3311 | try leb.writeUleb128(writer, features_count); |
| 3184 | for (enabled_features, 0..) |enabled, feature_index| { | 3312 | for (enabled_features, 0..) |enabled, feature_index| { |
| 3185 | if (enabled) { | 3313 | if (enabled) { |
| 3186 | const feature: types.Feature = .{ .prefix = .used, .tag = @as(types.Feature.Tag, @enumFromInt(feature_index)) }; | 3314 | const feature: Feature = .{ .prefix = .used, .tag = @as(Feature.Tag, @enumFromInt(feature_index)) }; |
| 3187 | try leb.writeUleb128(writer, @intFromEnum(feature.prefix)); | 3315 | try leb.writeUleb128(writer, @intFromEnum(feature.prefix)); |
| 3188 | var buf: [100]u8 = undefined; | 3316 | var buf: [100]u8 = undefined; |
| 3189 | const string = try std.fmt.bufPrint(&buf, "{}", .{feature.tag}); | 3317 | const string = try std.fmt.bufPrint(&buf, "{}", .{feature.tag}); |
| ... | @@ -3219,11 +3347,11 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem | ... | @@ -3219,11 +3347,11 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem |
| 3219 | var segments = try std.ArrayList(Name).initCapacity(arena, wasm.data_segments.count()); | 3347 | var segments = try std.ArrayList(Name).initCapacity(arena, wasm.data_segments.count()); |
| 3220 | | 3348 | |
| 3221 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 3349 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 3222 | const symbol = sym_loc.getSymbol(wasm).*; | 3350 | const symbol = wasm.symbolLocSymbol(sym_loc).*; |
| 3223 | if (symbol.isDead()) { | 3351 | if (symbol.isDead()) { |
| 3224 | continue; | 3352 | continue; |
| 3225 | } | 3353 | } |
| 3226 | const name = sym_loc.getName(wasm); | 3354 | const name = wasm.symbolLocName(sym_loc); |
| 3227 | switch (symbol.tag) { | 3355 | switch (symbol.tag) { |
| 3228 | .function => { | 3356 | .function => { |
| 3229 | const gop = funcs.getOrPutAssumeCapacity(symbol.index); | 3357 | const gop = funcs.getOrPutAssumeCapacity(symbol.index); |
| ... | @@ -3320,7 +3448,7 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { | ... | @@ -3320,7 +3448,7 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { |
| 3320 | try writer.writeByte(std.wasm.opcode(.end)); | 3448 | try writer.writeByte(std.wasm.opcode(.end)); |
| 3321 | } | 3449 | } |
| 3322 | | 3450 | |
| 3323 | fn emitImport(wasm: *Wasm, writer: anytype, import: types.Import) !void { | 3451 | fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void { |
| 3324 | const module_name = wasm.string_table.get(import.module_name); | 3452 | const module_name = wasm.string_table.get(import.module_name); |
| 3325 | try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len))); | 3453 | try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len))); |
| 3326 | try writer.writeAll(module_name); | 3454 | try writer.writeAll(module_name); |
| ... | @@ -3800,7 +3928,7 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: | ... | @@ -3800,7 +3928,7 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: |
| 3800 | // meta data version, which is currently '2' | 3928 | // meta data version, which is currently '2' |
| 3801 | try leb.writeUleb128(writer, @as(u32, 2)); | 3929 | try leb.writeUleb128(writer, @as(u32, 2)); |
| 3802 | | 3930 | |
| 3803 | // For each subsection type (found in types.Subsection) we can emit a section. | 3931 | // For each subsection type (found in Subsection) we can emit a section. |
| 3804 | // Currently, we only support emitting segment info and the symbol table. | 3932 | // Currently, we only support emitting segment info and the symbol table. |
| 3805 | try wasm.emitSymbolTable(binary_bytes, symbol_table); | 3933 | try wasm.emitSymbolTable(binary_bytes, symbol_table); |
| 3806 | try wasm.emitSegmentInfo(binary_bytes); | 3934 | try wasm.emitSegmentInfo(binary_bytes); |
| ... | @@ -3812,12 +3940,12 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: | ... | @@ -3812,12 +3940,12 @@ fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: |
| 3812 | fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void { | 3940 | fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void { |
| 3813 | const writer = binary_bytes.writer(); | 3941 | const writer = binary_bytes.writer(); |
| 3814 | | 3942 | |
| 3815 | try leb.writeUleb128(writer, @intFromEnum(types.SubsectionType.WASM_SYMBOL_TABLE)); | 3943 | try leb.writeUleb128(writer, @intFromEnum(SubsectionType.WASM_SYMBOL_TABLE)); |
| 3816 | const table_offset = binary_bytes.items.len; | 3944 | const table_offset = binary_bytes.items.len; |
| 3817 | | 3945 | |
| 3818 | var symbol_count: u32 = 0; | 3946 | var symbol_count: u32 = 0; |
| 3819 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 3947 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 3820 | const symbol = sym_loc.getSymbol(wasm).*; | 3948 | const symbol = wasm.symbolLocSymbol(sym_loc).*; |
| 3821 | if (symbol.tag == .dead) continue; // Do not emit dead symbols | 3949 | if (symbol.tag == .dead) continue; // Do not emit dead symbols |
| 3822 | try symbol_table.putNoClobber(sym_loc, symbol_count); | 3950 | try symbol_table.putNoClobber(sym_loc, symbol_count); |
| 3823 | symbol_count += 1; | 3951 | symbol_count += 1; |
| ... | @@ -3825,7 +3953,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: | ... | @@ -3825,7 +3953,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: |
| 3825 | try leb.writeUleb128(writer, @intFromEnum(symbol.tag)); | 3953 | try leb.writeUleb128(writer, @intFromEnum(symbol.tag)); |
| 3826 | try leb.writeUleb128(writer, symbol.flags); | 3954 | try leb.writeUleb128(writer, symbol.flags); |
| 3827 | | 3955 | |
| 3828 | const sym_name = sym_loc.getName(wasm); | 3956 | const sym_name = wasm.symbolLocName(sym_loc); |
| 3829 | switch (symbol.tag) { | 3957 | switch (symbol.tag) { |
| 3830 | .data => { | 3958 | .data => { |
| 3831 | try leb.writeUleb128(writer, @as(u32, @intCast(sym_name.len))); | 3959 | try leb.writeUleb128(writer, @as(u32, @intCast(sym_name.len))); |
| ... | @@ -3860,7 +3988,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: | ... | @@ -3860,7 +3988,7 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: |
| 3860 | | 3988 | |
| 3861 | fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { | 3989 | fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { |
| 3862 | const writer = binary_bytes.writer(); | 3990 | const writer = binary_bytes.writer(); |
| 3863 | try leb.writeUleb128(writer, @intFromEnum(types.SubsectionType.WASM_SEGMENT_INFO)); | 3991 | try leb.writeUleb128(writer, @intFromEnum(SubsectionType.WASM_SEGMENT_INFO)); |
| 3864 | const segment_offset = binary_bytes.items.len; | 3992 | const segment_offset = binary_bytes.items.len; |
| 3865 | | 3993 | |
| 3866 | try leb.writeUleb128(writer, @as(u32, @intCast(wasm.segment_info.count()))); | 3994 | try leb.writeUleb128(writer, @as(u32, @intCast(wasm.segment_info.count()))); |
| ... | @@ -4030,22 +4158,22 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 { | ... | @@ -4030,22 +4158,22 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 { |
| 4030 | /// Asserts declaration has an associated `Atom`. | 4158 | /// Asserts declaration has an associated `Atom`. |
| 4031 | /// Returns the index into the list of types. | 4159 | /// Returns the index into the list of types. |
| 4032 | pub fn storeNavType(wasm: *Wasm, nav: InternPool.Nav.Index, func_type: std.wasm.Type) !u32 { | 4160 | pub fn storeNavType(wasm: *Wasm, nav: InternPool.Nav.Index, func_type: std.wasm.Type) !u32 { |
| 4033 | return wasm.zigObjectPtr().?.storeDeclType(wasm.base.comp.gpa, nav, func_type); | 4161 | return wasm.zig_object.?.storeDeclType(wasm.base.comp.gpa, nav, func_type); |
| 4034 | } | 4162 | } |
| 4035 | | 4163 | |
| 4036 | /// Returns the symbol index of the error name table. | 4164 | /// Returns the symbol index of the error name table. |
| 4037 | /// | 4165 | /// |
| 4038 | /// When the symbol does not yet exist, it will create a new one instead. | 4166 | /// When the symbol does not yet exist, it will create a new one instead. |
| 4039 | pub fn getErrorTableSymbol(wasm_file: *Wasm, pt: Zcu.PerThread) !u32 { | 4167 | pub fn getErrorTableSymbol(wasm: *Wasm, pt: Zcu.PerThread) !u32 { |
| 4040 | const sym_index = try wasm_file.zigObjectPtr().?.getErrorTableSymbol(wasm_file, pt); | 4168 | const sym_index = try wasm.zig_object.?.getErrorTableSymbol(wasm, pt); |
| 4041 | return @intFromEnum(sym_index); | 4169 | return @intFromEnum(sym_index); |
| 4042 | } | 4170 | } |
| 4043 | | 4171 | |
| 4044 | /// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`. | 4172 | /// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`. |
| 4045 | /// When the index was not found, a new `Atom` will be created, and its index will be returned. | 4173 | /// When the index was not found, a new `Atom` will be created, and its index will be returned. |
| 4046 | /// The newly created Atom is empty with default fields as specified by `Atom.empty`. | 4174 | /// The newly created Atom is empty with default fields as specified by `Atom.empty`. |
| 4047 | pub fn getOrCreateAtomForNav(wasm_file: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !Atom.Index { | 4175 | pub fn getOrCreateAtomForNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !Atom.Index { |
| 4048 | return wasm_file.zigObjectPtr().?.getOrCreateAtomForNav(wasm_file, pt, nav); | 4176 | return wasm.zig_object.?.getOrCreateAtomForNav(wasm, pt, nav); |
| 4049 | } | 4177 | } |
| 4050 | | 4178 | |
| 4051 | /// Verifies all resolved symbols and checks whether itself needs to be marked alive, | 4179 | /// Verifies all resolved symbols and checks whether itself needs to be marked alive, |
| ... | @@ -4058,7 +4186,7 @@ fn markReferences(wasm: *Wasm) !void { | ... | @@ -4058,7 +4186,7 @@ fn markReferences(wasm: *Wasm) !void { |
| 4058 | const comp = wasm.base.comp; | 4186 | const comp = wasm.base.comp; |
| 4059 | | 4187 | |
| 4060 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 4188 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 4061 | const sym = sym_loc.getSymbol(wasm); | 4189 | const sym = wasm.symbolLocSymbol(sym_loc); |
| 4062 | if (sym.isExported(comp.config.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { | 4190 | if (sym.isExported(comp.config.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { |
| 4063 | try wasm.mark(sym_loc); | 4191 | try wasm.mark(sym_loc); |
| 4064 | continue; | 4192 | continue; |
| ... | @@ -4067,8 +4195,8 @@ fn markReferences(wasm: *Wasm) !void { | ... | @@ -4067,8 +4195,8 @@ fn markReferences(wasm: *Wasm) !void { |
| 4067 | // Debug sections may require to be parsed and marked when it contains | 4195 | // Debug sections may require to be parsed and marked when it contains |
| 4068 | // relocations to alive symbols. | 4196 | // relocations to alive symbols. |
| 4069 | if (sym.tag == .section and comp.config.debug_format != .strip) { | 4197 | if (sym.tag == .section and comp.config.debug_format != .strip) { |
| 4070 | const obj_file = wasm.file(sym_loc.file) orelse continue; // Incremental debug info is done independently | 4198 | const object_id = sym_loc.file.unwrap() orelse continue; // Incremental debug info is done independently |
| 4071 | _ = try obj_file.parseSymbolIntoAtom(wasm, sym_loc.index); | 4199 | _ = try wasm.parseSymbolIntoAtom(object_id, sym_loc.index); |
| 4072 | sym.mark(); | 4200 | sym.mark(); |
| 4073 | } | 4201 | } |
| 4074 | } | 4202 | } |
| ... | @@ -4077,7 +4205,7 @@ fn markReferences(wasm: *Wasm) !void { | ... | @@ -4077,7 +4205,7 @@ fn markReferences(wasm: *Wasm) !void { |
| 4077 | /// Marks a symbol as 'alive' recursively so itself and any references it contains to | 4205 | /// Marks a symbol as 'alive' recursively so itself and any references it contains to |
| 4078 | /// other symbols will not be omit from the binary. | 4206 | /// other symbols will not be omit from the binary. |
| 4079 | fn mark(wasm: *Wasm, loc: SymbolLoc) !void { | 4207 | fn mark(wasm: *Wasm, loc: SymbolLoc) !void { |
| 4080 | const symbol = loc.getSymbol(wasm); | 4208 | const symbol = wasm.symbolLocSymbol(loc); |
| 4081 | if (symbol.isAlive()) { | 4209 | if (symbol.isAlive()) { |
| 4082 | // Symbol is already marked alive, including its references. | 4210 | // Symbol is already marked alive, including its references. |
| 4083 | // This means we can skip it so we don't end up marking the same symbols | 4211 | // This means we can skip it so we don't end up marking the same symbols |
| ... | @@ -4085,22 +4213,22 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void { | ... | @@ -4085,22 +4213,22 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void { |
| 4085 | return; | 4213 | return; |
| 4086 | } | 4214 | } |
| 4087 | symbol.mark(); | 4215 | symbol.mark(); |
| 4088 | gc_log.debug("Marked symbol '{s}'", .{loc.getName(wasm)}); | 4216 | gc_log.debug("Marked symbol '{s}'", .{wasm.symbolLocName(loc)}); |
| 4089 | if (symbol.isUndefined()) { | 4217 | if (symbol.isUndefined()) { |
| 4090 | // undefined symbols do not have an associated `Atom` and therefore also | 4218 | // undefined symbols do not have an associated `Atom` and therefore also |
| 4091 | // do not contain relocations. | 4219 | // do not contain relocations. |
| 4092 | return; | 4220 | return; |
| 4093 | } | 4221 | } |
| 4094 | | 4222 | |
| 4095 | const atom_index = if (wasm.file(loc.file)) |obj_file| | 4223 | const atom_index = if (loc.file.unwrap()) |object_id| |
| 4096 | try obj_file.parseSymbolIntoAtom(wasm, loc.index) | 4224 | try wasm.parseSymbolIntoAtom(object_id, loc.index) |
| 4097 | else | 4225 | else |
| 4098 | wasm.symbol_atom.get(loc) orelse return; | 4226 | wasm.symbol_atom.get(loc) orelse return; |
| 4099 | | 4227 | |
| 4100 | const atom = wasm.getAtom(atom_index); | 4228 | const atom = wasm.getAtom(atom_index); |
| 4101 | for (atom.relocs.items) |reloc| { | 4229 | for (atom.relocs.items) |reloc| { |
| 4102 | const target_loc: SymbolLoc = .{ .index = @enumFromInt(reloc.index), .file = loc.file }; | 4230 | const target_loc: SymbolLoc = .{ .index = @enumFromInt(reloc.index), .file = loc.file }; |
| 4103 | try wasm.mark(target_loc.finalLoc(wasm)); | 4231 | try wasm.mark(wasm.symbolLocFinalLoc(target_loc)); |
| 4104 | } | 4232 | } |
| 4105 | } | 4233 | } |
| 4106 | | 4234 | |
| ... | @@ -4110,3 +4238,566 @@ fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 | ... | @@ -4110,3 +4238,566 @@ fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 |
| 4110 | .command => "_start", | 4238 | .command => "_start", |
| 4111 | }; | 4239 | }; |
| 4112 | } | 4240 | } |
| | 4241 | |
| | 4242 | pub const Atom = struct { |
| | 4243 | /// Represents the index of the file this atom was generated from. |
| | 4244 | /// This is `none` when the atom was generated by a synthetic linker symbol. |
| | 4245 | file: OptionalObjectId, |
| | 4246 | /// symbol index of the symbol representing this atom |
| | 4247 | sym_index: Symbol.Index, |
| | 4248 | /// Size of the atom, used to calculate section sizes in the final binary |
| | 4249 | size: u32 = 0, |
| | 4250 | /// List of relocations belonging to this atom |
| | 4251 | relocs: std.ArrayListUnmanaged(Relocation) = .empty, |
| | 4252 | /// Contains the binary data of an atom, which can be non-relocated |
| | 4253 | code: std.ArrayListUnmanaged(u8) = .empty, |
| | 4254 | /// For code this is 1, for data this is set to the highest value of all segments |
| | 4255 | alignment: Wasm.Alignment = .@"1", |
| | 4256 | /// Offset into the section where the atom lives, this already accounts |
| | 4257 | /// for alignment. |
| | 4258 | offset: u32 = 0, |
| | 4259 | /// The original offset within the object file. This value is subtracted from |
| | 4260 | /// relocation offsets to determine where in the `data` to rewrite the value |
| | 4261 | original_offset: u32 = 0, |
| | 4262 | /// Previous atom in relation to this atom. |
| | 4263 | /// is null when this atom is the first in its order |
| | 4264 | prev: Atom.Index = .null, |
| | 4265 | /// Contains atoms local to a decl, all managed by this `Atom`. |
| | 4266 | /// When the parent atom is being freed, it will also do so for all local atoms. |
| | 4267 | locals: std.ArrayListUnmanaged(Atom.Index) = .empty, |
| | 4268 | |
| | 4269 | /// Represents the index of an Atom where `null` is considered |
| | 4270 | /// an invalid atom. |
| | 4271 | pub const Index = enum(u32) { |
| | 4272 | null = std.math.maxInt(u32), |
| | 4273 | _, |
| | 4274 | }; |
| | 4275 | |
| | 4276 | /// Frees all resources owned by this `Atom`. |
| | 4277 | pub fn deinit(atom: *Atom, gpa: std.mem.Allocator) void { |
| | 4278 | atom.relocs.deinit(gpa); |
| | 4279 | atom.code.deinit(gpa); |
| | 4280 | atom.locals.deinit(gpa); |
| | 4281 | atom.* = undefined; |
| | 4282 | } |
| | 4283 | |
| | 4284 | /// Sets the length of relocations and code to '0', |
| | 4285 | /// effectively resetting them and allowing them to be re-populated. |
| | 4286 | pub fn clear(atom: *Atom) void { |
| | 4287 | atom.relocs.clearRetainingCapacity(); |
| | 4288 | atom.code.clearRetainingCapacity(); |
| | 4289 | } |
| | 4290 | |
| | 4291 | pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| | 4292 | _ = fmt; |
| | 4293 | _ = options; |
| | 4294 | try writer.print("Atom{{ .sym_index = {d}, .alignment = {d}, .size = {d}, .offset = 0x{x:0>8} }}", .{ |
| | 4295 | @intFromEnum(atom.sym_index), |
| | 4296 | atom.alignment, |
| | 4297 | atom.size, |
| | 4298 | atom.offset, |
| | 4299 | }); |
| | 4300 | } |
| | 4301 | |
| | 4302 | /// Returns the location of the symbol that represents this `Atom` |
| | 4303 | pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc { |
| | 4304 | return .{ |
| | 4305 | .file = atom.file, |
| | 4306 | .index = atom.sym_index, |
| | 4307 | }; |
| | 4308 | } |
| | 4309 | |
| | 4310 | /// Resolves the relocations within the atom, writing the new value |
| | 4311 | /// at the calculated offset. |
| | 4312 | pub fn resolveRelocs(atom: *Atom, wasm: *const Wasm) void { |
| | 4313 | if (atom.relocs.items.len == 0) return; |
| | 4314 | const symbol_name = wasm.symbolLocName(atom.symbolLoc()); |
| | 4315 | log.debug("Resolving relocs in atom '{s}' count({d})", .{ |
| | 4316 | symbol_name, |
| | 4317 | atom.relocs.items.len, |
| | 4318 | }); |
| | 4319 | |
| | 4320 | for (atom.relocs.items) |reloc| { |
| | 4321 | const value = atom.relocationValue(reloc, wasm); |
| | 4322 | log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{ |
| | 4323 | wasm.symbolLocName(.{ |
| | 4324 | .file = atom.file, |
| | 4325 | .index = @enumFromInt(reloc.index), |
| | 4326 | }), |
| | 4327 | symbol_name, |
| | 4328 | reloc.offset, |
| | 4329 | value, |
| | 4330 | }); |
| | 4331 | |
| | 4332 | switch (reloc.relocation_type) { |
| | 4333 | .R_WASM_TABLE_INDEX_I32, |
| | 4334 | .R_WASM_FUNCTION_OFFSET_I32, |
| | 4335 | .R_WASM_GLOBAL_INDEX_I32, |
| | 4336 | .R_WASM_MEMORY_ADDR_I32, |
| | 4337 | .R_WASM_SECTION_OFFSET_I32, |
| | 4338 | => std.mem.writeInt(u32, atom.code.items[reloc.offset - atom.original_offset ..][0..4], @as(u32, @truncate(value)), .little), |
| | 4339 | .R_WASM_TABLE_INDEX_I64, |
| | 4340 | .R_WASM_MEMORY_ADDR_I64, |
| | 4341 | => std.mem.writeInt(u64, atom.code.items[reloc.offset - atom.original_offset ..][0..8], value, .little), |
| | 4342 | .R_WASM_GLOBAL_INDEX_LEB, |
| | 4343 | .R_WASM_EVENT_INDEX_LEB, |
| | 4344 | .R_WASM_FUNCTION_INDEX_LEB, |
| | 4345 | .R_WASM_MEMORY_ADDR_LEB, |
| | 4346 | .R_WASM_MEMORY_ADDR_SLEB, |
| | 4347 | .R_WASM_TABLE_INDEX_SLEB, |
| | 4348 | .R_WASM_TABLE_NUMBER_LEB, |
| | 4349 | .R_WASM_TYPE_INDEX_LEB, |
| | 4350 | .R_WASM_MEMORY_ADDR_TLS_SLEB, |
| | 4351 | => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset - atom.original_offset ..][0..5], @as(u32, @truncate(value))), |
| | 4352 | .R_WASM_MEMORY_ADDR_LEB64, |
| | 4353 | .R_WASM_MEMORY_ADDR_SLEB64, |
| | 4354 | .R_WASM_TABLE_INDEX_SLEB64, |
| | 4355 | .R_WASM_MEMORY_ADDR_TLS_SLEB64, |
| | 4356 | => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset - atom.original_offset ..][0..10], value), |
| | 4357 | } |
| | 4358 | } |
| | 4359 | } |
| | 4360 | |
| | 4361 | /// From a given `relocation` will return the new value to be written. |
| | 4362 | /// All values will be represented as a `u64` as all values can fit within it. |
| | 4363 | /// The final value must be casted to the correct size. |
| | 4364 | fn relocationValue(atom: Atom, relocation: Relocation, wasm: *const Wasm) u64 { |
| | 4365 | const target_loc = wasm.symbolLocFinalLoc(.{ |
| | 4366 | .file = atom.file, |
| | 4367 | .index = @enumFromInt(relocation.index), |
| | 4368 | }); |
| | 4369 | const symbol = wasm.symbolLocSymbol(target_loc); |
| | 4370 | if (relocation.relocation_type != .R_WASM_TYPE_INDEX_LEB and |
| | 4371 | symbol.tag != .section and |
| | 4372 | symbol.isDead()) |
| | 4373 | { |
| | 4374 | const val = atom.thombstone(wasm) orelse relocation.addend; |
| | 4375 | return @bitCast(val); |
| | 4376 | } |
| | 4377 | switch (relocation.relocation_type) { |
| | 4378 | .R_WASM_FUNCTION_INDEX_LEB => return symbol.index, |
| | 4379 | .R_WASM_TABLE_NUMBER_LEB => return symbol.index, |
| | 4380 | .R_WASM_TABLE_INDEX_I32, |
| | 4381 | .R_WASM_TABLE_INDEX_I64, |
| | 4382 | .R_WASM_TABLE_INDEX_SLEB, |
| | 4383 | .R_WASM_TABLE_INDEX_SLEB64, |
| | 4384 | => return wasm.function_table.get(.{ .file = atom.file, .index = @enumFromInt(relocation.index) }) orelse 0, |
| | 4385 | .R_WASM_TYPE_INDEX_LEB => { |
| | 4386 | const object_id = atom.file.unwrap() orelse return relocation.index; |
| | 4387 | const original_type = objectFuncTypes(wasm, object_id)[relocation.index]; |
| | 4388 | return wasm.getTypeIndex(original_type).?; |
| | 4389 | }, |
| | 4390 | .R_WASM_GLOBAL_INDEX_I32, |
| | 4391 | .R_WASM_GLOBAL_INDEX_LEB, |
| | 4392 | => return symbol.index, |
| | 4393 | .R_WASM_MEMORY_ADDR_I32, |
| | 4394 | .R_WASM_MEMORY_ADDR_I64, |
| | 4395 | .R_WASM_MEMORY_ADDR_LEB, |
| | 4396 | .R_WASM_MEMORY_ADDR_LEB64, |
| | 4397 | .R_WASM_MEMORY_ADDR_SLEB, |
| | 4398 | .R_WASM_MEMORY_ADDR_SLEB64, |
| | 4399 | => { |
| | 4400 | std.debug.assert(symbol.tag == .data); |
| | 4401 | if (symbol.isUndefined()) { |
| | 4402 | return 0; |
| | 4403 | } |
| | 4404 | const va: i33 = @intCast(symbol.virtual_address); |
| | 4405 | return @intCast(va + relocation.addend); |
| | 4406 | }, |
| | 4407 | .R_WASM_EVENT_INDEX_LEB => return symbol.index, |
| | 4408 | .R_WASM_SECTION_OFFSET_I32 => { |
| | 4409 | const target_atom_index = wasm.symbol_atom.get(target_loc).?; |
| | 4410 | const target_atom = wasm.getAtom(target_atom_index); |
| | 4411 | const rel_value: i33 = @intCast(target_atom.offset); |
| | 4412 | return @intCast(rel_value + relocation.addend); |
| | 4413 | }, |
| | 4414 | .R_WASM_FUNCTION_OFFSET_I32 => { |
| | 4415 | if (symbol.isUndefined()) { |
| | 4416 | const val = atom.thombstone(wasm) orelse relocation.addend; |
| | 4417 | return @bitCast(val); |
| | 4418 | } |
| | 4419 | const target_atom_index = wasm.symbol_atom.get(target_loc).?; |
| | 4420 | const target_atom = wasm.getAtom(target_atom_index); |
| | 4421 | const rel_value: i33 = @intCast(target_atom.offset); |
| | 4422 | return @intCast(rel_value + relocation.addend); |
| | 4423 | }, |
| | 4424 | .R_WASM_MEMORY_ADDR_TLS_SLEB, |
| | 4425 | .R_WASM_MEMORY_ADDR_TLS_SLEB64, |
| | 4426 | => { |
| | 4427 | const va: i33 = @intCast(symbol.virtual_address); |
| | 4428 | return @intCast(va + relocation.addend); |
| | 4429 | }, |
| | 4430 | } |
| | 4431 | } |
| | 4432 | |
| | 4433 | // For a given `Atom` returns whether it has a thombstone value or not. |
| | 4434 | /// This defines whether we want a specific value when a section is dead. |
| | 4435 | fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 { |
| | 4436 | const atom_name = wasm.symbolLocName(atom.symbolLoc()); |
| | 4437 | if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) { |
| | 4438 | return -2; |
| | 4439 | } else if (std.mem.startsWith(u8, atom_name, ".debug_")) { |
| | 4440 | return -1; |
| | 4441 | } |
| | 4442 | return null; |
| | 4443 | } |
| | 4444 | }; |
| | 4445 | |
| | 4446 | pub const Relocation = struct { |
| | 4447 | /// Represents the type of the `Relocation` |
| | 4448 | relocation_type: RelocationType, |
| | 4449 | /// Offset of the value to rewrite relative to the relevant section's contents. |
| | 4450 | /// When `offset` is zero, its position is immediately after the id and size of the section. |
| | 4451 | offset: u32, |
| | 4452 | /// The index of the symbol used. |
| | 4453 | /// When the type is `R_WASM_TYPE_INDEX_LEB`, it represents the index of the type. |
| | 4454 | index: u32, |
| | 4455 | /// Addend to add to the address. |
| | 4456 | /// This field is only non-zero for `R_WASM_MEMORY_ADDR_*`, `R_WASM_FUNCTION_OFFSET_I32` and `R_WASM_SECTION_OFFSET_I32`. |
| | 4457 | addend: i32 = 0, |
| | 4458 | |
| | 4459 | /// All possible relocation types currently existing. |
| | 4460 | /// This enum is exhaustive as the spec is WIP and new types |
| | 4461 | /// can be added which means that a generated binary will be invalid, |
| | 4462 | /// so instead we will show an error in such cases. |
| | 4463 | pub const RelocationType = enum(u8) { |
| | 4464 | R_WASM_FUNCTION_INDEX_LEB = 0, |
| | 4465 | R_WASM_TABLE_INDEX_SLEB = 1, |
| | 4466 | R_WASM_TABLE_INDEX_I32 = 2, |
| | 4467 | R_WASM_MEMORY_ADDR_LEB = 3, |
| | 4468 | R_WASM_MEMORY_ADDR_SLEB = 4, |
| | 4469 | R_WASM_MEMORY_ADDR_I32 = 5, |
| | 4470 | R_WASM_TYPE_INDEX_LEB = 6, |
| | 4471 | R_WASM_GLOBAL_INDEX_LEB = 7, |
| | 4472 | R_WASM_FUNCTION_OFFSET_I32 = 8, |
| | 4473 | R_WASM_SECTION_OFFSET_I32 = 9, |
| | 4474 | R_WASM_EVENT_INDEX_LEB = 10, |
| | 4475 | R_WASM_GLOBAL_INDEX_I32 = 13, |
| | 4476 | R_WASM_MEMORY_ADDR_LEB64 = 14, |
| | 4477 | R_WASM_MEMORY_ADDR_SLEB64 = 15, |
| | 4478 | R_WASM_MEMORY_ADDR_I64 = 16, |
| | 4479 | R_WASM_TABLE_INDEX_SLEB64 = 18, |
| | 4480 | R_WASM_TABLE_INDEX_I64 = 19, |
| | 4481 | R_WASM_TABLE_NUMBER_LEB = 20, |
| | 4482 | R_WASM_MEMORY_ADDR_TLS_SLEB = 21, |
| | 4483 | R_WASM_MEMORY_ADDR_TLS_SLEB64 = 25, |
| | 4484 | |
| | 4485 | /// Returns true for relocation types where the `addend` field is present. |
| | 4486 | pub fn addendIsPresent(self: RelocationType) bool { |
| | 4487 | return switch (self) { |
| | 4488 | .R_WASM_MEMORY_ADDR_LEB, |
| | 4489 | .R_WASM_MEMORY_ADDR_SLEB, |
| | 4490 | .R_WASM_MEMORY_ADDR_I32, |
| | 4491 | .R_WASM_MEMORY_ADDR_LEB64, |
| | 4492 | .R_WASM_MEMORY_ADDR_SLEB64, |
| | 4493 | .R_WASM_MEMORY_ADDR_I64, |
| | 4494 | .R_WASM_MEMORY_ADDR_TLS_SLEB, |
| | 4495 | .R_WASM_MEMORY_ADDR_TLS_SLEB64, |
| | 4496 | .R_WASM_FUNCTION_OFFSET_I32, |
| | 4497 | .R_WASM_SECTION_OFFSET_I32, |
| | 4498 | => true, |
| | 4499 | else => false, |
| | 4500 | }; |
| | 4501 | } |
| | 4502 | }; |
| | 4503 | |
| | 4504 | /// Verifies the relocation type of a given `Relocation` and returns |
| | 4505 | /// true when the relocation references a function call or address to a function. |
| | 4506 | pub fn isFunction(self: Relocation) bool { |
| | 4507 | return switch (self.relocation_type) { |
| | 4508 | .R_WASM_FUNCTION_INDEX_LEB, |
| | 4509 | .R_WASM_TABLE_INDEX_SLEB, |
| | 4510 | => true, |
| | 4511 | else => false, |
| | 4512 | }; |
| | 4513 | } |
| | 4514 | |
| | 4515 | pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| | 4516 | _ = fmt; |
| | 4517 | _ = options; |
| | 4518 | try writer.print("{s} offset=0x{x:0>6} symbol={d}", .{ |
| | 4519 | @tagName(self.relocation_type), |
| | 4520 | self.offset, |
| | 4521 | self.index, |
| | 4522 | }); |
| | 4523 | } |
| | 4524 | }; |
| | 4525 | |
| | 4526 | /// Unlike the `Import` object defined by the wasm spec, and existing |
| | 4527 | /// in the std.wasm namespace, this construct saves the 'module name' and 'name' |
| | 4528 | /// of the import using offsets into a string table, rather than the slices itself. |
| | 4529 | /// This saves us (potentially) 24 bytes per import on 64bit machines. |
| | 4530 | pub const Import = struct { |
| | 4531 | module_name: u32, |
| | 4532 | name: u32, |
| | 4533 | kind: std.wasm.Import.Kind, |
| | 4534 | }; |
| | 4535 | |
| | 4536 | /// Unlike the `Export` object defined by the wasm spec, and existing |
| | 4537 | /// in the std.wasm namespace, this construct saves the 'name' |
| | 4538 | /// of the export using offsets into a string table, rather than the slice itself. |
| | 4539 | /// This saves us (potentially) 12 bytes per export on 64bit machines. |
| | 4540 | pub const Export = struct { |
| | 4541 | name: u32, |
| | 4542 | index: u32, |
| | 4543 | kind: std.wasm.ExternalKind, |
| | 4544 | }; |
| | 4545 | |
| | 4546 | pub const SubsectionType = enum(u8) { |
| | 4547 | WASM_SEGMENT_INFO = 5, |
| | 4548 | WASM_INIT_FUNCS = 6, |
| | 4549 | WASM_COMDAT_INFO = 7, |
| | 4550 | WASM_SYMBOL_TABLE = 8, |
| | 4551 | }; |
| | 4552 | |
| | 4553 | pub const Alignment = @import("../InternPool.zig").Alignment; |
| | 4554 | |
| | 4555 | pub const NamedSegment = struct { |
| | 4556 | /// Segment's name, encoded as UTF-8 bytes. |
| | 4557 | name: []const u8, |
| | 4558 | /// The required alignment of the segment, encoded as a power of 2 |
| | 4559 | alignment: Alignment, |
| | 4560 | /// Bitfield containing flags for a segment |
| | 4561 | flags: u32, |
| | 4562 | |
| | 4563 | pub fn isTLS(segment: NamedSegment) bool { |
| | 4564 | return segment.flags & @intFromEnum(Flags.WASM_SEG_FLAG_TLS) != 0; |
| | 4565 | } |
| | 4566 | |
| | 4567 | /// Returns the name as how it will be output into the final object |
| | 4568 | /// file or binary. When `merge_segments` is true, this will return the |
| | 4569 | /// short name. i.e. ".rodata". When false, it returns the entire name instead. |
| | 4570 | pub fn outputName(segment: NamedSegment, merge_segments: bool) []const u8 { |
| | 4571 | if (segment.isTLS()) { |
| | 4572 | return ".tdata"; |
| | 4573 | } else if (!merge_segments) { |
| | 4574 | return segment.name; |
| | 4575 | } else if (std.mem.startsWith(u8, segment.name, ".rodata.")) { |
| | 4576 | return ".rodata"; |
| | 4577 | } else if (std.mem.startsWith(u8, segment.name, ".text.")) { |
| | 4578 | return ".text"; |
| | 4579 | } else if (std.mem.startsWith(u8, segment.name, ".data.")) { |
| | 4580 | return ".data"; |
| | 4581 | } else if (std.mem.startsWith(u8, segment.name, ".bss.")) { |
| | 4582 | return ".bss"; |
| | 4583 | } |
| | 4584 | return segment.name; |
| | 4585 | } |
| | 4586 | |
| | 4587 | pub const Flags = enum(u32) { |
| | 4588 | WASM_SEG_FLAG_STRINGS = 0x1, |
| | 4589 | WASM_SEG_FLAG_TLS = 0x2, |
| | 4590 | }; |
| | 4591 | }; |
| | 4592 | |
| | 4593 | pub const InitFunc = struct { |
| | 4594 | /// Priority of the init function |
| | 4595 | priority: u32, |
| | 4596 | /// The symbol index of init function (not the function index). |
| | 4597 | symbol_index: u32, |
| | 4598 | }; |
| | 4599 | |
| | 4600 | pub const Comdat = struct { |
| | 4601 | name: []const u8, |
| | 4602 | /// Must be zero, no flags are currently defined by the tool-convention. |
| | 4603 | flags: u32, |
| | 4604 | symbols: []const ComdatSym, |
| | 4605 | }; |
| | 4606 | |
| | 4607 | pub const ComdatSym = struct { |
| | 4608 | kind: @This().Type, |
| | 4609 | /// Index of the data segment/function/global/event/table within a WASM module. |
| | 4610 | /// The object must not be an import. |
| | 4611 | index: u32, |
| | 4612 | |
| | 4613 | pub const Type = enum(u8) { |
| | 4614 | WASM_COMDAT_DATA = 0, |
| | 4615 | WASM_COMDAT_FUNCTION = 1, |
| | 4616 | WASM_COMDAT_GLOBAL = 2, |
| | 4617 | WASM_COMDAT_EVENT = 3, |
| | 4618 | WASM_COMDAT_TABLE = 4, |
| | 4619 | WASM_COMDAT_SECTION = 5, |
| | 4620 | }; |
| | 4621 | }; |
| | 4622 | |
| | 4623 | pub const Feature = struct { |
| | 4624 | /// Provides information about the usage of the feature. |
| | 4625 | /// - '0x2b' (+): Object uses this feature, and the link fails if feature is not in the allowed set. |
| | 4626 | /// - '0x2d' (-): Object does not use this feature, and the link fails if this feature is in the allowed set. |
| | 4627 | /// - '0x3d' (=): Object uses this feature, and the link fails if this feature is not in the allowed set, |
| | 4628 | /// or if any object does not use this feature. |
| | 4629 | prefix: Prefix, |
| | 4630 | /// Type of the feature, must be unique in the sequence of features. |
| | 4631 | tag: Tag, |
| | 4632 | |
| | 4633 | /// Unlike `std.Target.wasm.Feature` this also contains linker-features such as shared-mem |
| | 4634 | pub const Tag = enum { |
| | 4635 | atomics, |
| | 4636 | bulk_memory, |
| | 4637 | exception_handling, |
| | 4638 | extended_const, |
| | 4639 | half_precision, |
| | 4640 | multimemory, |
| | 4641 | multivalue, |
| | 4642 | mutable_globals, |
| | 4643 | nontrapping_fptoint, |
| | 4644 | reference_types, |
| | 4645 | relaxed_simd, |
| | 4646 | sign_ext, |
| | 4647 | simd128, |
| | 4648 | tail_call, |
| | 4649 | shared_mem, |
| | 4650 | |
| | 4651 | /// From a given cpu feature, returns its linker feature |
| | 4652 | pub fn fromCpuFeature(feature: std.Target.wasm.Feature) Tag { |
| | 4653 | return @as(Tag, @enumFromInt(@intFromEnum(feature))); |
| | 4654 | } |
| | 4655 | |
| | 4656 | pub fn format(tag: Tag, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { |
| | 4657 | _ = fmt; |
| | 4658 | _ = opt; |
| | 4659 | try writer.writeAll(switch (tag) { |
| | 4660 | .atomics => "atomics", |
| | 4661 | .bulk_memory => "bulk-memory", |
| | 4662 | .exception_handling => "exception-handling", |
| | 4663 | .extended_const => "extended-const", |
| | 4664 | .half_precision => "half-precision", |
| | 4665 | .multimemory => "multimemory", |
| | 4666 | .multivalue => "multivalue", |
| | 4667 | .mutable_globals => "mutable-globals", |
| | 4668 | .nontrapping_fptoint => "nontrapping-fptoint", |
| | 4669 | .reference_types => "reference-types", |
| | 4670 | .relaxed_simd => "relaxed-simd", |
| | 4671 | .sign_ext => "sign-ext", |
| | 4672 | .simd128 => "simd128", |
| | 4673 | .tail_call => "tail-call", |
| | 4674 | .shared_mem => "shared-mem", |
| | 4675 | }); |
| | 4676 | } |
| | 4677 | }; |
| | 4678 | |
| | 4679 | pub const Prefix = enum(u8) { |
| | 4680 | used = '+', |
| | 4681 | disallowed = '-', |
| | 4682 | required = '=', |
| | 4683 | }; |
| | 4684 | |
| | 4685 | pub fn format(feature: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { |
| | 4686 | _ = opt; |
| | 4687 | _ = fmt; |
| | 4688 | try writer.print("{c} {}", .{ feature.prefix, feature.tag }); |
| | 4689 | } |
| | 4690 | }; |
| | 4691 | |
| | 4692 | pub const known_features = std.StaticStringMap(Feature.Tag).initComptime(.{ |
| | 4693 | .{ "atomics", .atomics }, |
| | 4694 | .{ "bulk-memory", .bulk_memory }, |
| | 4695 | .{ "exception-handling", .exception_handling }, |
| | 4696 | .{ "extended-const", .extended_const }, |
| | 4697 | .{ "half-precision", .half_precision }, |
| | 4698 | .{ "multimemory", .multimemory }, |
| | 4699 | .{ "multivalue", .multivalue }, |
| | 4700 | .{ "mutable-globals", .mutable_globals }, |
| | 4701 | .{ "nontrapping-fptoint", .nontrapping_fptoint }, |
| | 4702 | .{ "reference-types", .reference_types }, |
| | 4703 | .{ "relaxed-simd", .relaxed_simd }, |
| | 4704 | .{ "sign-ext", .sign_ext }, |
| | 4705 | .{ "simd128", .simd128 }, |
| | 4706 | .{ "tail-call", .tail_call }, |
| | 4707 | .{ "shared-mem", .shared_mem }, |
| | 4708 | }); |
| | 4709 | |
| | 4710 | /// Parses an object file into atoms, for code and data sections |
| | 4711 | fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !Atom.Index { |
| | 4712 | const object = wasm.objectById(object_id) orelse |
| | 4713 | return wasm.zig_object.?.parseSymbolIntoAtom(wasm, symbol_index); |
| | 4714 | const comp = wasm.base.comp; |
| | 4715 | const gpa = comp.gpa; |
| | 4716 | const symbol = &object.symtable[@intFromEnum(symbol_index)]; |
| | 4717 | const relocatable_data: Object.RelocatableData = switch (symbol.tag) { |
| | 4718 | .function => object.relocatable_data.get(.code).?[symbol.index - object.imported_functions_count], |
| | 4719 | .data => object.relocatable_data.get(.data).?[symbol.index], |
| | 4720 | .section => blk: { |
| | 4721 | const data = object.relocatable_data.get(.custom).?; |
| | 4722 | for (data) |dat| { |
| | 4723 | if (dat.section_index == symbol.index) { |
| | 4724 | break :blk dat; |
| | 4725 | } |
| | 4726 | } |
| | 4727 | unreachable; |
| | 4728 | }, |
| | 4729 | else => unreachable, |
| | 4730 | }; |
| | 4731 | const final_index = try wasm.getMatchingSegment(object_id, symbol_index); |
| | 4732 | const atom_index = try wasm.createAtom(symbol_index, object_id.toOptional()); |
| | 4733 | try wasm.appendAtomAtIndex(final_index, atom_index); |
| | 4734 | |
| | 4735 | const atom = wasm.getAtomPtr(atom_index); |
| | 4736 | atom.size = relocatable_data.size; |
| | 4737 | atom.alignment = relocatable_data.getAlignment(object); |
| | 4738 | atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]); |
| | 4739 | atom.original_offset = relocatable_data.offset; |
| | 4740 | |
| | 4741 | const segment: *Wasm.Segment = &wasm.segments.items[final_index]; |
| | 4742 | if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned |
| | 4743 | segment.alignment = segment.alignment.max(atom.alignment); |
| | 4744 | } |
| | 4745 | |
| | 4746 | if (object.relocations.get(relocatable_data.section_index)) |relocations| { |
| | 4747 | const start = searchRelocStart(relocations, relocatable_data.offset); |
| | 4748 | const len = searchRelocEnd(relocations[start..], relocatable_data.offset + atom.size); |
| | 4749 | atom.relocs = std.ArrayListUnmanaged(Wasm.Relocation).fromOwnedSlice(relocations[start..][0..len]); |
| | 4750 | for (atom.relocs.items) |reloc| { |
| | 4751 | switch (reloc.relocation_type) { |
| | 4752 | .R_WASM_TABLE_INDEX_I32, |
| | 4753 | .R_WASM_TABLE_INDEX_I64, |
| | 4754 | .R_WASM_TABLE_INDEX_SLEB, |
| | 4755 | .R_WASM_TABLE_INDEX_SLEB64, |
| | 4756 | => { |
| | 4757 | try wasm.function_table.put(gpa, .{ |
| | 4758 | .file = object_id.toOptional(), |
| | 4759 | .index = @enumFromInt(reloc.index), |
| | 4760 | }, 0); |
| | 4761 | }, |
| | 4762 | .R_WASM_GLOBAL_INDEX_I32, |
| | 4763 | .R_WASM_GLOBAL_INDEX_LEB, |
| | 4764 | => { |
| | 4765 | const sym = object.symtable[reloc.index]; |
| | 4766 | if (sym.tag != .global) { |
| | 4767 | try wasm.got_symbols.append(gpa, .{ |
| | 4768 | .file = object_id.toOptional(), |
| | 4769 | .index = @enumFromInt(reloc.index), |
| | 4770 | }); |
| | 4771 | } |
| | 4772 | }, |
| | 4773 | else => {}, |
| | 4774 | } |
| | 4775 | } |
| | 4776 | } |
| | 4777 | |
| | 4778 | return atom_index; |
| | 4779 | } |
| | 4780 | |
| | 4781 | fn searchRelocStart(relocs: []const Wasm.Relocation, address: u32) usize { |
| | 4782 | var min: usize = 0; |
| | 4783 | var max: usize = relocs.len; |
| | 4784 | while (min < max) { |
| | 4785 | const index = (min + max) / 2; |
| | 4786 | const curr = relocs[index]; |
| | 4787 | if (curr.offset < address) { |
| | 4788 | min = index + 1; |
| | 4789 | } else { |
| | 4790 | max = index; |
| | 4791 | } |
| | 4792 | } |
| | 4793 | return min; |
| | 4794 | } |
| | 4795 | |
| | 4796 | fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize { |
| | 4797 | for (relocs, 0..relocs.len) |reloc, index| { |
| | 4798 | if (reloc.offset > address) { |
| | 4799 | return index; |
| | 4800 | } |
| | 4801 | } |
| | 4802 | return relocs.len; |
| | 4803 | } |