| ... | @@ -36,11 +36,16 @@ const Value = @import("../Value.zig"); | ... | @@ -36,11 +36,16 @@ const Value = @import("../Value.zig"); |
| 36 | const ZigObject = @import("Wasm/ZigObject.zig"); | 36 | const ZigObject = @import("Wasm/ZigObject.zig"); |
| 37 | | 37 | |
| 38 | base: link.File, | 38 | base: link.File, |
| | 39 | /// Null-terminated strings, indexes have type String and string_table provides |
| | 40 | /// lookup. |
| | 41 | string_bytes: std.ArrayListUnmanaged(u8), |
| | 42 | /// Omitted when serializing linker state. |
| | 43 | string_table: String.Table, |
| 39 | /// Symbol name of the entry function to export | 44 | /// Symbol name of the entry function to export |
| 40 | entry_name: ?[]const u8, | 45 | entry_name: OptionalString, |
| 41 | /// When true, will allow undefined symbols | 46 | /// When true, will allow undefined symbols |
| 42 | import_symbols: bool, | 47 | import_symbols: bool, |
| 43 | /// List of *global* symbol names to export to the host environment. | 48 | /// Set of *global* symbol names to export to the host environment. |
| 44 | export_symbol_names: []const []const u8, | 49 | export_symbol_names: []const []const u8, |
| 45 | /// When defined, sets the start of the data section. | 50 | /// When defined, sets the start of the data section. |
| 46 | global_base: ?u64, | 51 | global_base: ?u64, |
| ... | @@ -63,32 +68,14 @@ objects: std.ArrayListUnmanaged(Object) = .{}, | ... | @@ -63,32 +68,14 @@ objects: std.ArrayListUnmanaged(Object) = .{}, |
| 63 | /// LLVM uses "env" by default when none is given. This would be a good default for Zig | 68 | /// LLVM uses "env" by default when none is given. This would be a good default for Zig |
| 64 | /// to support existing code. | 69 | /// to support existing code. |
| 65 | /// TODO: Allow setting this through a flag? | 70 | /// TODO: Allow setting this through a flag? |
| 66 | host_name: []const u8 = "env", | 71 | host_name: String, |
| 67 | /// List of symbols generated by the linker. | 72 | /// List of symbols generated by the linker. |
| 68 | synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .empty, | 73 | synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .empty, |
| 69 | /// Maps atoms to their segment index | 74 | /// Maps atoms to their segment index |
| 70 | atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .empty, | 75 | atoms: std.AutoHashMapUnmanaged(Segment.Index, Atom.Index) = .empty, |
| 71 | /// List of all atoms. | 76 | /// List of all atoms. |
| 72 | managed_atoms: std.ArrayListUnmanaged(Atom) = .empty, | 77 | managed_atoms: std.ArrayListUnmanaged(Atom) = .empty, |
| 73 | /// Represents the index into `segments` where the 'code' section | 78 | |
| 74 | /// lives. | | |
| 75 | code_section_index: ?u32 = null, | | |
| 76 | /// The index of the segment representing the custom '.debug_info' section. | | |
| 77 | debug_info_index: ?u32 = null, | | |
| 78 | /// The index of the segment representing the custom '.debug_line' section. | | |
| 79 | debug_line_index: ?u32 = null, | | |
| 80 | /// The index of the segment representing the custom '.debug_loc' section. | | |
| 81 | debug_loc_index: ?u32 = null, | | |
| 82 | /// The index of the segment representing the custom '.debug_ranges' section. | | |
| 83 | debug_ranges_index: ?u32 = null, | | |
| 84 | /// The index of the segment representing the custom '.debug_pubnames' section. | | |
| 85 | debug_pubnames_index: ?u32 = null, | | |
| 86 | /// The index of the segment representing the custom '.debug_pubtypes' section. | | |
| 87 | debug_pubtypes_index: ?u32 = null, | | |
| 88 | /// The index of the segment representing the custom '.debug_pubtypes' section. | | |
| 89 | debug_str_index: ?u32 = null, | | |
| 90 | /// The index of the segment representing the custom '.debug_pubtypes' section. | | |
| 91 | debug_abbrev_index: ?u32 = null, | | |
| 92 | /// The count of imported functions. This number will be appended | 79 | /// The count of imported functions. This number will be appended |
| 93 | /// to the function indexes as their index starts at the lowest non-extern function. | 80 | /// to the function indexes as their index starts at the lowest non-extern function. |
| 94 | imported_functions_count: u32 = 0, | 81 | imported_functions_count: u32 = 0, |
| ... | @@ -104,13 +91,11 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty, | ... | @@ -104,13 +91,11 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty, |
| 104 | /// Used for code, data and custom sections. | 91 | /// Used for code, data and custom sections. |
| 105 | segments: std.ArrayListUnmanaged(Segment) = .empty, | 92 | segments: std.ArrayListUnmanaged(Segment) = .empty, |
| 106 | /// Maps a data segment key (such as .rodata) to the index into `segments`. | 93 | /// Maps a data segment key (such as .rodata) to the index into `segments`. |
| 107 | data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty, | 94 | data_segments: std.StringArrayHashMapUnmanaged(Segment.Index) = .empty, |
| 108 | /// A table of `NamedSegment` which provide meta data | 95 | /// A table of `NamedSegment` which provide meta data |
| 109 | /// about a data symbol such as its name where the key is | 96 | /// about a data symbol such as its name where the key is |
| 110 | /// the segment index, which can be found from `data_segments` | 97 | /// the segment index, which can be found from `data_segments` |
| 111 | segment_info: std.AutoArrayHashMapUnmanaged(u32, NamedSegment) = .empty, | 98 | segment_info: std.AutoArrayHashMapUnmanaged(Segment.Index, NamedSegment) = .empty, |
| 112 | /// Deduplicated string table for strings used by symbols, imports and exports. | | |
| 113 | string_table: StringTable = .{}, | | |
| 114 | | 99 | |
| 115 | // Output sections | 100 | // Output sections |
| 116 | /// Output type section | 101 | /// Output type section |
| ... | @@ -158,8 +143,8 @@ function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty, | ... | @@ -158,8 +143,8 @@ function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty, |
| 158 | /// e.g. when an undefined symbol references a symbol from the archive. | 143 | /// e.g. when an undefined symbol references a symbol from the archive. |
| 159 | lazy_archives: std.ArrayListUnmanaged(LazyArchive) = .empty, | 144 | lazy_archives: std.ArrayListUnmanaged(LazyArchive) = .empty, |
| 160 | | 145 | |
| 161 | /// A map of global names (read: offset into string table) to their symbol location | 146 | /// A map of global names to their symbol location |
| 162 | globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .empty, | 147 | globals: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty, |
| 163 | /// The list of GOT symbols and their location | 148 | /// The list of GOT symbols and their location |
| 164 | got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .empty, | 149 | got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .empty, |
| 165 | /// Maps discarded symbols and their positions to the location of the symbol | 150 | /// Maps discarded symbols and their positions to the location of the symbol |
| ... | @@ -169,8 +154,7 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .empty, | ... | @@ -169,8 +154,7 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .empty, |
| 169 | /// into the final binary. | 154 | /// into the final binary. |
| 170 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .empty, | 155 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .empty, |
| 171 | /// Symbols that remain undefined after symbol resolution. | 156 | /// Symbols that remain undefined after symbol resolution. |
| 172 | /// Note: The key represents an offset into the string table, rather than the actual string. | 157 | undefs: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty, |
| 173 | undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty, | | |
| 174 | /// Maps a symbol's location to an atom. This can be used to find meta | 158 | /// Maps a symbol's location to an atom. This can be used to find meta |
| 175 | /// data of a symbol, such as its size, or its offset to perform a relocation. | 159 | /// data of a symbol, such as its size, or its offset to perform a relocation. |
| 176 | /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. | 160 | /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. |
| ... | @@ -178,8 +162,103 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty, | ... | @@ -178,8 +162,103 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty, |
| 178 | | 162 | |
| 179 | /// `--verbose-link` output. | 163 | /// `--verbose-link` output. |
| 180 | /// Initialized on creation, appended to as inputs are added, printed during `flush`. | 164 | /// Initialized on creation, appended to as inputs are added, printed during `flush`. |
| | 165 | /// String data is allocated into Compilation arena. |
| 181 | dump_argv_list: std.ArrayListUnmanaged([]const u8), | 166 | dump_argv_list: std.ArrayListUnmanaged([]const u8), |
| 182 | | 167 | |
| | 168 | /// Represents the index into `segments` where the 'code' section lives. |
| | 169 | code_section_index: Segment.OptionalIndex = .none, |
| | 170 | custom_sections: CustomSections, |
| | 171 | preloaded_strings: PreloadedStrings, |
| | 172 | |
| | 173 | /// Type reflection is used on the field names to autopopulate each field |
| | 174 | /// during initialization. |
| | 175 | const PreloadedStrings = struct { |
| | 176 | __heap_base: String, |
| | 177 | __heap_end: String, |
| | 178 | __indirect_function_table: String, |
| | 179 | __linear_memory: String, |
| | 180 | __stack_pointer: String, |
| | 181 | __tls_align: String, |
| | 182 | __tls_base: String, |
| | 183 | __tls_size: String, |
| | 184 | __wasm_apply_global_tls_relocs: String, |
| | 185 | __wasm_call_ctors: String, |
| | 186 | __wasm_init_memory: String, |
| | 187 | __wasm_init_memory_flag: String, |
| | 188 | __wasm_init_tls: String, |
| | 189 | __zig_err_name_table: String, |
| | 190 | __zig_err_names: String, |
| | 191 | __zig_errors_len: String, |
| | 192 | _initialize: String, |
| | 193 | _start: String, |
| | 194 | memory: String, |
| | 195 | }; |
| | 196 | |
| | 197 | /// Type reflection is used on the field names to autopopulate each inner `name` field. |
| | 198 | const CustomSections = struct { |
| | 199 | @".debug_info": CustomSection, |
| | 200 | @".debug_pubtypes": CustomSection, |
| | 201 | @".debug_abbrev": CustomSection, |
| | 202 | @".debug_line": CustomSection, |
| | 203 | @".debug_str": CustomSection, |
| | 204 | @".debug_pubnames": CustomSection, |
| | 205 | @".debug_loc": CustomSection, |
| | 206 | @".debug_ranges": CustomSection, |
| | 207 | }; |
| | 208 | |
| | 209 | const CustomSection = struct { |
| | 210 | name: String, |
| | 211 | index: Segment.OptionalIndex, |
| | 212 | }; |
| | 213 | |
| | 214 | /// Index into string_bytes |
| | 215 | pub const String = enum(u32) { |
| | 216 | _, |
| | 217 | |
| | 218 | const Table = std.HashMapUnmanaged(String, void, TableContext, std.hash_map.default_max_load_percentage); |
| | 219 | |
| | 220 | const TableContext = struct { |
| | 221 | bytes: []const u8, |
| | 222 | |
| | 223 | pub fn eql(_: @This(), a: String, b: String) bool { |
| | 224 | return a == b; |
| | 225 | } |
| | 226 | |
| | 227 | pub fn hash(ctx: @This(), key: String) u64 { |
| | 228 | return std.hash_map.hashString(mem.sliceTo(ctx.bytes[@intFromEnum(key)..], 0)); |
| | 229 | } |
| | 230 | }; |
| | 231 | |
| | 232 | const TableIndexAdapter = struct { |
| | 233 | bytes: []const u8, |
| | 234 | |
| | 235 | pub fn eql(ctx: @This(), a: []const u8, b: String) bool { |
| | 236 | return mem.eql(u8, a, mem.sliceTo(ctx.bytes[@intFromEnum(b)..], 0)); |
| | 237 | } |
| | 238 | |
| | 239 | pub fn hash(_: @This(), adapted_key: []const u8) u64 { |
| | 240 | assert(mem.indexOfScalar(u8, adapted_key, 0) == null); |
| | 241 | return std.hash_map.hashString(adapted_key); |
| | 242 | } |
| | 243 | }; |
| | 244 | |
| | 245 | pub fn toOptional(i: String) OptionalString { |
| | 246 | const result: OptionalString = @enumFromInt(@intFromEnum(i)); |
| | 247 | assert(result != .none); |
| | 248 | return result; |
| | 249 | } |
| | 250 | }; |
| | 251 | |
| | 252 | pub const OptionalString = enum(u32) { |
| | 253 | none = std.math.maxInt(u32), |
| | 254 | _, |
| | 255 | |
| | 256 | pub fn unwrap(i: OptionalString) ?String { |
| | 257 | if (i == .none) return null; |
| | 258 | return @enumFromInt(@intFromEnum(i)); |
| | 259 | } |
| | 260 | }; |
| | 261 | |
| 183 | /// Index into objects array or the zig object. | 262 | /// Index into objects array or the zig object. |
| 184 | pub const ObjectId = enum(u16) { | 263 | pub const ObjectId = enum(u16) { |
| 185 | zig_object = std.math.maxInt(u16) - 1, | 264 | zig_object = std.math.maxInt(u16) - 1, |
| ... | @@ -222,6 +301,26 @@ pub const Segment = struct { | ... | @@ -222,6 +301,26 @@ pub const Segment = struct { |
| 222 | offset: u32, | 301 | offset: u32, |
| 223 | flags: u32, | 302 | flags: u32, |
| 224 | | 303 | |
| | 304 | const Index = enum(u32) { |
| | 305 | _, |
| | 306 | |
| | 307 | pub fn toOptional(i: Index) OptionalIndex { |
| | 308 | const result: OptionalIndex = @enumFromInt(@intFromEnum(i)); |
| | 309 | assert(result != .none); |
| | 310 | return result; |
| | 311 | } |
| | 312 | }; |
| | 313 | |
| | 314 | const OptionalIndex = enum(u32) { |
| | 315 | none = std.math.maxInt(u32), |
| | 316 | _, |
| | 317 | |
| | 318 | pub fn unwrap(i: OptionalIndex) ?Index { |
| | 319 | if (i == .none) return null; |
| | 320 | return @enumFromInt(@intFromEnum(i)); |
| | 321 | } |
| | 322 | }; |
| | 323 | |
| 225 | pub const Flag = enum(u32) { | 324 | pub const Flag = enum(u32) { |
| 226 | WASM_DATA_SEGMENT_IS_PASSIVE = 0x01, | 325 | WASM_DATA_SEGMENT_IS_PASSIVE = 0x01, |
| 227 | WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02, | 326 | WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02, |
| ... | @@ -260,26 +359,8 @@ pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol { | ... | @@ -260,26 +359,8 @@ pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol { |
| 260 | } | 359 | } |
| 261 | | 360 | |
| 262 | /// From a given location, returns the name of the symbol. | 361 | /// From a given location, returns the name of the symbol. |
| 263 | pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) []const u8 { | 362 | pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) [:0]const u8 { |
| 264 | if (wasm.discarded.get(loc)) |new_loc| { | 363 | return wasm.stringSlice(wasm.symbolLocSymbol(loc).name); |
| 265 | return wasm.symbolLocName(new_loc); | | |
| 266 | } | | |
| 267 | switch (loc.file) { | | |
| 268 | .none => { | | |
| 269 | const sym = wasm.synthetic_symbols.items[@intFromEnum(loc.index)]; | | |
| 270 | return wasm.string_table.get(sym.name); | | |
| 271 | }, | | |
| 272 | .zig_object => { | | |
| 273 | const zo = wasm.zig_object.?; | | |
| 274 | const sym = zo.symbols.items[@intFromEnum(loc.index)]; | | |
| 275 | return zo.string_table.get(sym.name).?; | | |
| 276 | }, | | |
| 277 | _ => { | | |
| 278 | const obj = &wasm.objects.items[@intFromEnum(loc.file)]; | | |
| 279 | const sym = obj.symtable[@intFromEnum(loc.index)]; | | |
| 280 | return obj.string_table.get(sym.name); | | |
| 281 | }, | | |
| 282 | } | | |
| 283 | } | 364 | } |
| 284 | | 365 | |
| 285 | /// From a given symbol location, returns the final location. | 366 | /// From a given symbol location, returns the final location. |
| ... | @@ -325,75 +406,6 @@ pub const InitFuncLoc = struct { | ... | @@ -325,75 +406,6 @@ pub const InitFuncLoc = struct { |
| 325 | return lhs.priority < rhs.priority; | 406 | return lhs.priority < rhs.priority; |
| 326 | } | 407 | } |
| 327 | }; | 408 | }; |
| 328 | /// Generic string table that duplicates strings | | |
| 329 | /// and converts them into offsets instead. | | |
| 330 | pub const StringTable = struct { | | |
| 331 | /// Table that maps string offsets, which is used to de-duplicate strings. | | |
| 332 | /// Rather than having the offset map to the data, the `StringContext` holds all bytes of the string. | | |
| 333 | /// The strings are stored as a contigious array where each string is zero-terminated. | | |
| 334 | string_table: std.HashMapUnmanaged( | | |
| 335 | u32, | | |
| 336 | void, | | |
| 337 | std.hash_map.StringIndexContext, | | |
| 338 | std.hash_map.default_max_load_percentage, | | |
| 339 | ) = .{}, | | |
| 340 | /// Holds the actual data of the string table. | | |
| 341 | string_data: std.ArrayListUnmanaged(u8) = .empty, | | |
| 342 | | | |
| 343 | /// Accepts a string and searches for a corresponding string. | | |
| 344 | /// When found, de-duplicates the string and returns the existing offset instead. | | |
| 345 | /// When the string is not found in the `string_table`, a new entry will be inserted | | |
| 346 | /// and the new offset to its data will be returned. | | |
| 347 | pub fn put(table: *StringTable, allocator: Allocator, string: []const u8) !u32 { | | |
| 348 | const gop = try table.string_table.getOrPutContextAdapted( | | |
| 349 | allocator, | | |
| 350 | string, | | |
| 351 | std.hash_map.StringIndexAdapter{ .bytes = &table.string_data }, | | |
| 352 | .{ .bytes = &table.string_data }, | | |
| 353 | ); | | |
| 354 | if (gop.found_existing) { | | |
| 355 | const off = gop.key_ptr.*; | | |
| 356 | log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off }); | | |
| 357 | return off; | | |
| 358 | } | | |
| 359 | | | |
| 360 | try table.string_data.ensureUnusedCapacity(allocator, string.len + 1); | | |
| 361 | const offset: u32 = @intCast(table.string_data.items.len); | | |
| 362 | | | |
| 363 | log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset }); | | |
| 364 | | | |
| 365 | table.string_data.appendSliceAssumeCapacity(string); | | |
| 366 | table.string_data.appendAssumeCapacity(0); | | |
| 367 | | | |
| 368 | gop.key_ptr.* = offset; | | |
| 369 | | | |
| 370 | return offset; | | |
| 371 | } | | |
| 372 | | | |
| 373 | /// From a given offset, returns its corresponding string value. | | |
| 374 | /// Asserts offset does not exceed bounds. | | |
| 375 | pub fn get(table: StringTable, off: u32) []const u8 { | | |
| 376 | assert(off < table.string_data.items.len); | | |
| 377 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(table.string_data.items.ptr + off)), 0); | | |
| 378 | } | | |
| 379 | | | |
| 380 | /// Returns the offset of a given string when it exists. | | |
| 381 | /// Will return null if the given string does not yet exist within the string table. | | |
| 382 | pub fn getOffset(table: *StringTable, string: []const u8) ?u32 { | | |
| 383 | return table.string_table.getKeyAdapted( | | |
| 384 | string, | | |
| 385 | std.hash_map.StringIndexAdapter{ .bytes = &table.string_data }, | | |
| 386 | ); | | |
| 387 | } | | |
| 388 | | | |
| 389 | /// Frees all resources of the string table. Any references pointing | | |
| 390 | /// to the strings will be invalid. | | |
| 391 | pub fn deinit(table: *StringTable, allocator: Allocator) void { | | |
| 392 | table.string_data.deinit(allocator); | | |
| 393 | table.string_table.deinit(allocator); | | |
| 394 | table.* = undefined; | | |
| 395 | } | | |
| 396 | }; | | |
| 397 | | 409 | |
| 398 | pub fn open( | 410 | pub fn open( |
| 399 | arena: Allocator, | 411 | arena: Allocator, |
| ... | @@ -451,6 +463,8 @@ pub fn createEmpty( | ... | @@ -451,6 +463,8 @@ pub fn createEmpty( |
| 451 | .build_id = options.build_id, | 463 | .build_id = options.build_id, |
| 452 | }, | 464 | }, |
| 453 | .name = undefined, | 465 | .name = undefined, |
| | 466 | .string_table = .empty, |
| | 467 | .string_bytes = .empty, |
| 454 | .import_table = options.import_table, | 468 | .import_table = options.import_table, |
| 455 | .export_table = options.export_table, | 469 | .export_table = options.export_table, |
| 456 | .import_symbols = options.import_symbols, | 470 | .import_symbols = options.import_symbols, |
| ... | @@ -459,20 +473,38 @@ pub fn createEmpty( | ... | @@ -459,20 +473,38 @@ pub fn createEmpty( |
| 459 | .initial_memory = options.initial_memory, | 473 | .initial_memory = options.initial_memory, |
| 460 | .max_memory = options.max_memory, | 474 | .max_memory = options.max_memory, |
| 461 | | 475 | |
| 462 | .entry_name = switch (options.entry) { | 476 | .entry_name = undefined, |
| 463 | .disabled => null, | | |
| 464 | .default => if (output_mode != .Exe) null else defaultEntrySymbolName(wasi_exec_model), | | |
| 465 | .enabled => defaultEntrySymbolName(wasi_exec_model), | | |
| 466 | .named => |name| name, | | |
| 467 | }, | | |
| 468 | .zig_object = null, | 477 | .zig_object = null, |
| 469 | .dump_argv_list = .empty, | 478 | .dump_argv_list = .empty, |
| | 479 | .host_name = undefined, |
| | 480 | .custom_sections = undefined, |
| | 481 | .preloaded_strings = undefined, |
| 470 | }; | 482 | }; |
| 471 | if (use_llvm and comp.config.have_zcu) { | 483 | if (use_llvm and comp.config.have_zcu) { |
| 472 | wasm.llvm_object = try LlvmObject.create(arena, comp); | 484 | wasm.llvm_object = try LlvmObject.create(arena, comp); |
| 473 | } | 485 | } |
| 474 | errdefer wasm.base.destroy(); | 486 | errdefer wasm.base.destroy(); |
| 475 | | 487 | |
| | 488 | wasm.host_name = try wasm.internString("env"); |
| | 489 | |
| | 490 | inline for (@typeInfo(CustomSections).@"struct".fields) |field| { |
| | 491 | @field(wasm.custom_sections, field.name) = .{ |
| | 492 | .index = .none, |
| | 493 | .name = try wasm.internString(field.name), |
| | 494 | }; |
| | 495 | } |
| | 496 | |
| | 497 | inline for (@typeInfo(PreloadedStrings).@"struct".fields) |field| { |
| | 498 | @field(wasm.preloaded_strings, field.name) = try wasm.internString(field.name); |
| | 499 | } |
| | 500 | |
| | 501 | wasm.entry_name = switch (options.entry) { |
| | 502 | .disabled => .none, |
| | 503 | .default => if (output_mode != .Exe) .none else defaultEntrySymbolName(&wasm.preloaded_strings, wasi_exec_model).toOptional(), |
| | 504 | .enabled => defaultEntrySymbolName(&wasm.preloaded_strings, wasi_exec_model).toOptional(), |
| | 505 | .named => |name| (try wasm.internString(name)).toOptional(), |
| | 506 | }; |
| | 507 | |
| 476 | if (use_lld and (use_llvm or !comp.config.have_zcu)) { | 508 | if (use_lld and (use_llvm or !comp.config.have_zcu)) { |
| 477 | // LLVM emits the object file (if any); LLD links it into the final product. | 509 | // LLVM emits the object file (if any); LLD links it into the final product. |
| 478 | return wasm; | 510 | return wasm; |
| ... | @@ -498,22 +530,18 @@ pub fn createEmpty( | ... | @@ -498,22 +530,18 @@ pub fn createEmpty( |
| 498 | | 530 | |
| 499 | // create stack pointer symbol | 531 | // create stack pointer symbol |
| 500 | { | 532 | { |
| 501 | const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global); | 533 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__stack_pointer, .global); |
| 502 | const symbol = wasm.symbolLocSymbol(loc); | 534 | const symbol = wasm.symbolLocSymbol(loc); |
| 503 | // For object files we will import the stack pointer symbol | 535 | // For object files we will import the stack pointer symbol |
| 504 | if (output_mode == .Obj) { | 536 | if (output_mode == .Obj) { |
| 505 | symbol.setUndefined(true); | 537 | symbol.setUndefined(true); |
| 506 | symbol.index = @intCast(wasm.imported_globals_count); | 538 | symbol.index = @intCast(wasm.imported_globals_count); |
| 507 | wasm.imported_globals_count += 1; | 539 | wasm.imported_globals_count += 1; |
| 508 | try wasm.imports.putNoClobber( | 540 | try wasm.imports.putNoClobber(gpa, loc, .{ |
| 509 | gpa, | 541 | .module_name = wasm.host_name, |
| 510 | loc, | 542 | .name = symbol.name, |
| 511 | .{ | 543 | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, |
| 512 | .module_name = try wasm.string_table.put(gpa, wasm.host_name), | 544 | }); |
| 513 | .name = symbol.name, | | |
| 514 | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, | | |
| 515 | }, | | |
| 516 | ); | | |
| 517 | } else { | 545 | } else { |
| 518 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); | 546 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| 519 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 547 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| ... | @@ -530,7 +558,7 @@ pub fn createEmpty( | ... | @@ -530,7 +558,7 @@ pub fn createEmpty( |
| 530 | | 558 | |
| 531 | // create indirect function pointer symbol | 559 | // create indirect function pointer symbol |
| 532 | { | 560 | { |
| 533 | const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table); | 561 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__indirect_function_table, .table); |
| 534 | const symbol = wasm.symbolLocSymbol(loc); | 562 | const symbol = wasm.symbolLocSymbol(loc); |
| 535 | const table: std.wasm.Table = .{ | 563 | const table: std.wasm.Table = .{ |
| 536 | .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable` | 564 | .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable` |
| ... | @@ -541,7 +569,7 @@ pub fn createEmpty( | ... | @@ -541,7 +569,7 @@ pub fn createEmpty( |
| 541 | symbol.index = @intCast(wasm.imported_tables_count); | 569 | symbol.index = @intCast(wasm.imported_tables_count); |
| 542 | wasm.imported_tables_count += 1; | 570 | wasm.imported_tables_count += 1; |
| 543 | try wasm.imports.put(gpa, loc, .{ | 571 | try wasm.imports.put(gpa, loc, .{ |
| 544 | .module_name = try wasm.string_table.put(gpa, wasm.host_name), | 572 | .module_name = wasm.host_name, |
| 545 | .name = symbol.name, | 573 | .name = symbol.name, |
| 546 | .kind = .{ .table = table }, | 574 | .kind = .{ .table = table }, |
| 547 | }); | 575 | }); |
| ... | @@ -558,7 +586,7 @@ pub fn createEmpty( | ... | @@ -558,7 +586,7 @@ pub fn createEmpty( |
| 558 | | 586 | |
| 559 | // create __wasm_call_ctors | 587 | // create __wasm_call_ctors |
| 560 | { | 588 | { |
| 561 | const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function); | 589 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_call_ctors, .function); |
| 562 | const symbol = wasm.symbolLocSymbol(loc); | 590 | const symbol = wasm.symbolLocSymbol(loc); |
| 563 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 591 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 564 | // we do not know the function index until after we merged all sections. | 592 | // we do not know the function index until after we merged all sections. |
| ... | @@ -569,7 +597,7 @@ pub fn createEmpty( | ... | @@ -569,7 +597,7 @@ pub fn createEmpty( |
| 569 | // shared-memory symbols for TLS support | 597 | // shared-memory symbols for TLS support |
| 570 | if (shared_memory) { | 598 | if (shared_memory) { |
| 571 | { | 599 | { |
| 572 | const loc = try wasm.createSyntheticSymbol("__tls_base", .global); | 600 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_base, .global); |
| 573 | const symbol = wasm.symbolLocSymbol(loc); | 601 | const symbol = wasm.symbolLocSymbol(loc); |
| 574 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 602 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 575 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); | 603 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| ... | @@ -580,7 +608,7 @@ pub fn createEmpty( | ... | @@ -580,7 +608,7 @@ pub fn createEmpty( |
| 580 | }); | 608 | }); |
| 581 | } | 609 | } |
| 582 | { | 610 | { |
| 583 | const loc = try wasm.createSyntheticSymbol("__tls_size", .global); | 611 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_size, .global); |
| 584 | const symbol = wasm.symbolLocSymbol(loc); | 612 | const symbol = wasm.symbolLocSymbol(loc); |
| 585 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 613 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 586 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); | 614 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| ... | @@ -591,7 +619,7 @@ pub fn createEmpty( | ... | @@ -591,7 +619,7 @@ pub fn createEmpty( |
| 591 | }); | 619 | }); |
| 592 | } | 620 | } |
| 593 | { | 621 | { |
| 594 | const loc = try wasm.createSyntheticSymbol("__tls_align", .global); | 622 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_align, .global); |
| 595 | const symbol = wasm.symbolLocSymbol(loc); | 623 | const symbol = wasm.symbolLocSymbol(loc); |
| 596 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 624 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 597 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); | 625 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| ... | @@ -602,7 +630,7 @@ pub fn createEmpty( | ... | @@ -602,7 +630,7 @@ pub fn createEmpty( |
| 602 | }); | 630 | }); |
| 603 | } | 631 | } |
| 604 | { | 632 | { |
| 605 | const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function); | 633 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_tls, .function); |
| 606 | const symbol = wasm.symbolLocSymbol(loc); | 634 | const symbol = wasm.symbolLocSymbol(loc); |
| 607 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 635 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 608 | } | 636 | } |
| ... | @@ -655,13 +683,11 @@ pub fn addOrUpdateImport( | ... | @@ -655,13 +683,11 @@ pub fn addOrUpdateImport( |
| 655 | | 683 | |
| 656 | /// For a given name, creates a new global synthetic symbol. | 684 | /// For a given name, creates a new global synthetic symbol. |
| 657 | /// Leaves index undefined and the default flags (0). | 685 | /// Leaves index undefined and the default flags (0). |
| 658 | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { | 686 | fn createSyntheticSymbol(wasm: *Wasm, name: String, tag: Symbol.Tag) !SymbolLoc { |
| 659 | const gpa = wasm.base.comp.gpa; | 687 | return wasm.createSyntheticSymbolOffset(name, tag); |
| 660 | const name_offset = try wasm.string_table.put(gpa, name); | | |
| 661 | return wasm.createSyntheticSymbolOffset(name_offset, tag); | | |
| 662 | } | 688 | } |
| 663 | | 689 | |
| 664 | fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc { | 690 | fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: String, tag: Symbol.Tag) !SymbolLoc { |
| 665 | const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len); | 691 | const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len); |
| 666 | const loc: SymbolLoc = .{ .index = sym_index, .file = .none }; | 692 | const loc: SymbolLoc = .{ .index = sym_index, .file = .none }; |
| 667 | const gpa = wasm.base.comp.gpa; | 693 | const gpa = wasm.base.comp.gpa; |
| ... | @@ -803,16 +829,6 @@ fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Sy | ... | @@ -803,16 +829,6 @@ fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Sy |
| 803 | return &obj.symtable[@intFromEnum(index)]; | 829 | return &obj.symtable[@intFromEnum(index)]; |
| 804 | } | 830 | } |
| 805 | | 831 | |
| 806 | fn objectSymbolName(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) []const u8 { | | |
| 807 | const obj = wasm.objectById(object_id) orelse { | | |
| 808 | const zo = wasm.zig_object.?; | | |
| 809 | const sym = zo.symbols.items[@intFromEnum(index)]; | | |
| 810 | return zo.string_table.get(sym.name).?; | | |
| 811 | }; | | |
| 812 | const sym = obj.symtable[@intFromEnum(index)]; | | |
| 813 | return obj.string_table.get(sym.name); | | |
| 814 | } | | |
| 815 | | | |
| 816 | fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func { | 832 | fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func { |
| 817 | const obj = wasm.objectById(object_id) orelse { | 833 | const obj = wasm.objectById(object_id) orelse { |
| 818 | const zo = wasm.zig_object.?; | 834 | const zo = wasm.zig_object.?; |
| ... | @@ -850,13 +866,6 @@ fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Ind | ... | @@ -850,13 +866,6 @@ fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Ind |
| 850 | return obj.findImport(obj.symtable[@intFromEnum(symbol_index)]); | 866 | return obj.findImport(obj.symtable[@intFromEnum(symbol_index)]); |
| 851 | } | 867 | } |
| 852 | | 868 | |
| 853 | /// For a given offset, returns its string value. | | |
| 854 | /// Asserts string exists in the object string table. | | |
| 855 | fn objectString(wasm: *const Wasm, object_id: ObjectId, offset: u32) []const u8 { | | |
| 856 | const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.string_table.get(offset).?; | | |
| 857 | return obj.string_table.get(offset); | | |
| 858 | } | | |
| 859 | | | |
| 860 | /// Returns the object element pointer, or null if it is the ZigObject. | 869 | /// Returns the object element pointer, or null if it is the ZigObject. |
| 861 | fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object { | 870 | fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object { |
| 862 | if (object_id == .zig_object) return null; | 871 | if (object_id == .zig_object) return null; |
| ... | @@ -876,27 +885,25 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { | ... | @@ -876,27 +885,25 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 876 | .file = object_id.toOptional(), | 885 | .file = object_id.toOptional(), |
| 877 | .index = sym_index, | 886 | .index = sym_index, |
| 878 | }; | 887 | }; |
| 879 | const sym_name = objectString(wasm, object_id, symbol.name); | 888 | if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue; |
| 880 | if (mem.eql(u8, sym_name, "__indirect_function_table")) { | | |
| 881 | continue; | | |
| 882 | } | | |
| 883 | const sym_name_index = try wasm.string_table.put(gpa, sym_name); | | |
| 884 | | 889 | |
| 885 | if (symbol.isLocal()) { | 890 | if (symbol.isLocal()) { |
| 886 | if (symbol.isUndefined()) { | 891 | if (symbol.isUndefined()) { |
| 887 | diags.addParseError(obj_path, "local symbol '{s}' references import", .{sym_name}); | 892 | diags.addParseError(obj_path, "local symbol '{s}' references import", .{ |
| | 893 | wasm.stringSlice(symbol.name), |
| | 894 | }); |
| 888 | } | 895 | } |
| 889 | try wasm.resolved_symbols.putNoClobber(gpa, location, {}); | 896 | try wasm.resolved_symbols.putNoClobber(gpa, location, {}); |
| 890 | continue; | 897 | continue; |
| 891 | } | 898 | } |
| 892 | | 899 | |
| 893 | const maybe_existing = try wasm.globals.getOrPut(gpa, sym_name_index); | 900 | const maybe_existing = try wasm.globals.getOrPut(gpa, symbol.name); |
| 894 | if (!maybe_existing.found_existing) { | 901 | if (!maybe_existing.found_existing) { |
| 895 | maybe_existing.value_ptr.* = location; | 902 | maybe_existing.value_ptr.* = location; |
| 896 | try wasm.resolved_symbols.putNoClobber(gpa, location, {}); | 903 | try wasm.resolved_symbols.putNoClobber(gpa, location, {}); |
| 897 | | 904 | |
| 898 | if (symbol.isUndefined()) { | 905 | if (symbol.isUndefined()) { |
| 899 | try wasm.undefs.putNoClobber(gpa, sym_name_index, location); | 906 | try wasm.undefs.putNoClobber(gpa, symbol.name, location); |
| 900 | } | 907 | } |
| 901 | continue; | 908 | continue; |
| 902 | } | 909 | } |
| ... | @@ -918,7 +925,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { | ... | @@ -918,7 +925,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 918 | } | 925 | } |
| 919 | // both are defined and weak, we have a symbol collision. | 926 | // both are defined and weak, we have a symbol collision. |
| 920 | var err = try diags.addErrorWithNotes(2); | 927 | var err = try diags.addErrorWithNotes(2); |
| 921 | try err.addMsg("symbol '{s}' defined multiple times", .{sym_name}); | 928 | try err.addMsg("symbol '{s}' defined multiple times", .{wasm.stringSlice(symbol.name)}); |
| 922 | try err.addNote("first definition in '{'}'", .{existing_file_path}); | 929 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 923 | try err.addNote("next definition in '{'}'", .{obj_path}); | 930 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| 924 | } | 931 | } |
| ... | @@ -929,7 +936,9 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { | ... | @@ -929,7 +936,9 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 929 | | 936 | |
| 930 | if (symbol.tag != existing_sym.tag) { | 937 | if (symbol.tag != existing_sym.tag) { |
| 931 | var err = try diags.addErrorWithNotes(2); | 938 | var err = try diags.addErrorWithNotes(2); |
| 932 | try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) }); | 939 | try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ |
| | 940 | wasm.stringSlice(symbol.name), @tagName(symbol.tag), @tagName(existing_sym.tag), |
| | 941 | }); |
| 933 | try err.addNote("first definition in '{'}'", .{existing_file_path}); | 942 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 934 | try err.addNote("next definition in '{'}'", .{obj_path}); | 943 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| 935 | } | 944 | } |
| ... | @@ -937,22 +946,18 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { | ... | @@ -937,22 +946,18 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 937 | if (existing_sym.isUndefined() and symbol.isUndefined()) { | 946 | if (existing_sym.isUndefined() and symbol.isUndefined()) { |
| 938 | // only verify module/import name for function symbols | 947 | // only verify module/import name for function symbols |
| 939 | if (symbol.tag == .function) { | 948 | if (symbol.tag == .function) { |
| 940 | const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| blk: { | 949 | const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| |
| 941 | const imp = objectImport(wasm, existing_obj_id, existing_loc.index); | 950 | objectImport(wasm, existing_obj_id, existing_loc.index).module_name |
| 942 | break :blk objectString(wasm, existing_obj_id, imp.module_name); | 951 | else |
| 943 | } else blk: { | 952 | wasm.imports.get(existing_loc).?.module_name; |
| 944 | const name_index = wasm.imports.get(existing_loc).?.module_name; | | |
| 945 | break :blk wasm.string_table.get(name_index); | | |
| 946 | }; | | |
| 947 | | 953 | |
| 948 | const imp = objectImport(wasm, object_id, sym_index); | 954 | const module_name = objectImport(wasm, object_id, sym_index).module_name; |
| 949 | const module_name = objectString(wasm, object_id, imp.module_name); | 955 | if (existing_name != module_name) { |
| 950 | if (!mem.eql(u8, existing_name, module_name)) { | | |
| 951 | var err = try diags.addErrorWithNotes(2); | 956 | var err = try diags.addErrorWithNotes(2); |
| 952 | try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{ | 957 | try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{ |
| 953 | sym_name, | 958 | wasm.stringSlice(symbol.name), |
| 954 | existing_name, | 959 | wasm.stringSlice(existing_name), |
| 955 | module_name, | 960 | wasm.stringSlice(module_name), |
| 956 | }); | 961 | }); |
| 957 | try err.addNote("first definition in '{'}'", .{existing_file_path}); | 962 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 958 | try err.addNote("next definition in '{'}'", .{obj_path}); | 963 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| ... | @@ -969,7 +974,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { | ... | @@ -969,7 +974,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 969 | const new_ty = wasm.getGlobalType(location); | 974 | const new_ty = wasm.getGlobalType(location); |
| 970 | if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) { | 975 | if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) { |
| 971 | var err = try diags.addErrorWithNotes(2); | 976 | var err = try diags.addErrorWithNotes(2); |
| 972 | try err.addMsg("symbol '{s}' mismatching global types", .{sym_name}); | 977 | try err.addMsg("symbol '{s}' mismatching global types", .{wasm.stringSlice(symbol.name)}); |
| 973 | try err.addNote("first definition in '{'}'", .{existing_file_path}); | 978 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 974 | try err.addNote("next definition in '{'}'", .{obj_path}); | 979 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| 975 | } | 980 | } |
| ... | @@ -980,7 +985,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { | ... | @@ -980,7 +985,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 980 | const new_ty = wasm.getFunctionSignature(location); | 985 | const new_ty = wasm.getFunctionSignature(location); |
| 981 | if (!existing_ty.eql(new_ty)) { | 986 | if (!existing_ty.eql(new_ty)) { |
| 982 | var err = try diags.addErrorWithNotes(3); | 987 | var err = try diags.addErrorWithNotes(3); |
| 983 | try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name}); | 988 | try err.addMsg("symbol '{s}' mismatching function signatures.", .{wasm.stringSlice(symbol.name)}); |
| 984 | try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty }); | 989 | try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty }); |
| 985 | try err.addNote("first definition in '{'}'", .{existing_file_path}); | 990 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 986 | try err.addNote("next definition in '{'}'", .{obj_path}); | 991 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| ... | @@ -996,16 +1001,16 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { | ... | @@ -996,16 +1001,16 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 996 | } | 1001 | } |
| 997 | | 1002 | |
| 998 | // simply overwrite with the new symbol | 1003 | // simply overwrite with the new symbol |
| 999 | log.debug("Overwriting symbol '{s}'", .{sym_name}); | 1004 | log.debug("Overwriting symbol '{s}'", .{wasm.stringSlice(symbol.name)}); |
| 1000 | log.debug(" old definition in '{'}'", .{existing_file_path}); | 1005 | log.debug(" old definition in '{'}'", .{existing_file_path}); |
| 1001 | log.debug(" new definition in '{'}'", .{obj_path}); | 1006 | log.debug(" new definition in '{'}'", .{obj_path}); |
| 1002 | try wasm.discarded.putNoClobber(gpa, existing_loc, location); | 1007 | try wasm.discarded.putNoClobber(gpa, existing_loc, location); |
| 1003 | maybe_existing.value_ptr.* = location; | 1008 | maybe_existing.value_ptr.* = location; |
| 1004 | try wasm.globals.put(gpa, sym_name_index, location); | 1009 | try wasm.globals.put(gpa, symbol.name, location); |
| 1005 | try wasm.resolved_symbols.put(gpa, location, {}); | 1010 | try wasm.resolved_symbols.put(gpa, location, {}); |
| 1006 | assert(wasm.resolved_symbols.swapRemove(existing_loc)); | 1011 | assert(wasm.resolved_symbols.swapRemove(existing_loc)); |
| 1007 | if (existing_sym.isUndefined()) { | 1012 | if (existing_sym.isUndefined()) { |
| 1008 | _ = wasm.undefs.swapRemove(sym_name_index); | 1013 | _ = wasm.undefs.swapRemove(symbol.name); |
| 1009 | } | 1014 | } |
| 1010 | } | 1015 | } |
| 1011 | } | 1016 | } |
| ... | @@ -1021,7 +1026,7 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { | ... | @@ -1021,7 +1026,7 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { |
| 1021 | const sym_name_index = wasm.undefs.keys()[index]; | 1026 | const sym_name_index = wasm.undefs.keys()[index]; |
| 1022 | | 1027 | |
| 1023 | for (wasm.lazy_archives.items) |lazy_archive| { | 1028 | for (wasm.lazy_archives.items) |lazy_archive| { |
| 1024 | const sym_name = wasm.string_table.get(sym_name_index); | 1029 | const sym_name = wasm.stringSlice(sym_name_index); |
| 1025 | log.debug("Detected symbol '{s}' in archive '{'}', parsing objects..", .{ | 1030 | log.debug("Detected symbol '{s}' in archive '{'}', parsing objects..", .{ |
| 1026 | sym_name, lazy_archive.path, | 1031 | sym_name, lazy_archive.path, |
| 1027 | }); | 1032 | }); |
| ... | @@ -1066,13 +1071,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { | ... | @@ -1066,13 +1071,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1066 | if (!wasm.hasPassiveInitializationSegments()) { | 1071 | if (!wasm.hasPassiveInitializationSegments()) { |
| 1067 | return; | 1072 | return; |
| 1068 | } | 1073 | } |
| 1069 | const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function); | 1074 | const sym_loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_memory, .function); |
| 1070 | wasm.symbolLocSymbol(sym_loc).mark(); | 1075 | wasm.symbolLocSymbol(sym_loc).mark(); |
| 1071 | | 1076 | |
| 1072 | const flag_address: u32 = if (shared_memory) address: { | 1077 | const flag_address: u32 = if (shared_memory) address: { |
| 1073 | // when we have passive initialization segments and shared memory | 1078 | // when we have passive initialization segments and shared memory |
| 1074 | // `setupMemory` will create this symbol and set its virtual address. | 1079 | // `setupMemory` will create this symbol and set its virtual address. |
| 1075 | const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?; | 1080 | const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_init_memory_flag).?; |
| 1076 | break :address wasm.symbolLocSymbol(loc).virtual_address; | 1081 | break :address wasm.symbolLocSymbol(loc).virtual_address; |
| 1077 | } else 0; | 1082 | } else 0; |
| 1078 | | 1083 | |
| ... | @@ -1113,31 +1118,30 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { | ... | @@ -1113,31 +1118,30 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1113 | try writer.writeByte(std.wasm.opcode(.end)); | 1118 | try writer.writeByte(std.wasm.opcode(.end)); |
| 1114 | } | 1119 | } |
| 1115 | | 1120 | |
| 1116 | var it = wasm.data_segments.iterator(); | 1121 | for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |key, value, segment_index_usize| { |
| 1117 | var segment_index: u32 = 0; | 1122 | const segment_index: u32 = @intCast(segment_index_usize); |
| 1118 | while (it.next()) |entry| : (segment_index += 1) { | 1123 | const segment = wasm.segmentPtr(value); |
| 1119 | const segment: Segment = wasm.segments.items[entry.value_ptr.*]; | 1124 | if (segment.needsPassiveInitialization(import_memory, key)) { |
| 1120 | if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { | | |
| 1121 | // For passive BSS segments we can simple issue a memory.fill(0). | 1125 | // For passive BSS segments we can simple issue a memory.fill(0). |
| 1122 | // For non-BSS segments we do a memory.init. Both these | 1126 | // For non-BSS segments we do a memory.init. Both these |
| 1123 | // instructions take as their first argument the destination | 1127 | // instructions take as their first argument the destination |
| 1124 | // address. | 1128 | // address. |
| 1125 | try writeI32Const(writer, segment.offset); | 1129 | try writeI32Const(writer, segment.offset); |
| 1126 | | 1130 | |
| 1127 | if (shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) { | 1131 | if (shared_memory and std.mem.eql(u8, key, ".tdata")) { |
| 1128 | // When we initialize the TLS segment we also set the `__tls_base` | 1132 | // When we initialize the TLS segment we also set the `__tls_base` |
| 1129 | // global. This allows the runtime to use this static copy of the | 1133 | // global. This allows the runtime to use this static copy of the |
| 1130 | // TLS data for the first/main thread. | 1134 | // TLS data for the first/main thread. |
| 1131 | try writeI32Const(writer, segment.offset); | 1135 | try writeI32Const(writer, segment.offset); |
| 1132 | try writer.writeByte(std.wasm.opcode(.global_set)); | 1136 | try writer.writeByte(std.wasm.opcode(.global_set)); |
| 1133 | const loc = wasm.findGlobalSymbol("__tls_base").?; | 1137 | const loc = wasm.globals.get(wasm.preloaded_strings.__tls_base).?; |
| 1134 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index); | 1138 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index); |
| 1135 | } | 1139 | } |
| 1136 | | 1140 | |
| 1137 | try writeI32Const(writer, 0); | 1141 | try writeI32Const(writer, 0); |
| 1138 | try writeI32Const(writer, segment.size); | 1142 | try writeI32Const(writer, segment.size); |
| 1139 | try writer.writeByte(std.wasm.opcode(.misc_prefix)); | 1143 | try writer.writeByte(std.wasm.opcode(.misc_prefix)); |
| 1140 | if (std.mem.eql(u8, entry.key_ptr.*, ".bss")) { | 1144 | if (std.mem.eql(u8, key, ".bss")) { |
| 1141 | // fill bss segment with zeroes | 1145 | // fill bss segment with zeroes |
| 1142 | try leb.writeUleb128(writer, std.wasm.miscOpcode(.memory_fill)); | 1146 | try leb.writeUleb128(writer, std.wasm.miscOpcode(.memory_fill)); |
| 1143 | } else { | 1147 | } else { |
| ... | @@ -1187,11 +1191,9 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { | ... | @@ -1187,11 +1191,9 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1187 | try writer.writeByte(std.wasm.opcode(.end)); // end $drop | 1191 | try writer.writeByte(std.wasm.opcode(.end)); // end $drop |
| 1188 | } | 1192 | } |
| 1189 | | 1193 | |
| 1190 | it.reset(); | 1194 | for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |name, value, segment_index_usize| { |
| 1191 | segment_index = 0; | 1195 | const segment_index: u32 = @intCast(segment_index_usize); |
| 1192 | while (it.next()) |entry| : (segment_index += 1) { | 1196 | const segment = wasm.segmentPtr(value); |
| 1193 | const name = entry.key_ptr.*; | | |
| 1194 | const segment: Segment = wasm.segments.items[entry.value_ptr.*]; | | |
| 1195 | if (segment.needsPassiveInitialization(import_memory, name) and | 1197 | if (segment.needsPassiveInitialization(import_memory, name) and |
| 1196 | !std.mem.eql(u8, name, ".bss")) | 1198 | !std.mem.eql(u8, name, ".bss")) |
| 1197 | { | 1199 | { |
| ... | @@ -1211,7 +1213,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { | ... | @@ -1211,7 +1213,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1211 | try writer.writeByte(std.wasm.opcode(.end)); | 1213 | try writer.writeByte(std.wasm.opcode(.end)); |
| 1212 | | 1214 | |
| 1213 | try wasm.createSyntheticFunction( | 1215 | try wasm.createSyntheticFunction( |
| 1214 | "__wasm_init_memory", | 1216 | wasm.preloaded_strings.__wasm_init_memory, |
| 1215 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, | 1217 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, |
| 1216 | &function_body, | 1218 | &function_body, |
| 1217 | ); | 1219 | ); |
| ... | @@ -1230,7 +1232,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { | ... | @@ -1230,7 +1232,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1230 | return; | 1232 | return; |
| 1231 | } | 1233 | } |
| 1232 | | 1234 | |
| 1233 | const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function); | 1235 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_apply_global_tls_relocs, .function); |
| 1234 | wasm.symbolLocSymbol(loc).mark(); | 1236 | wasm.symbolLocSymbol(loc).mark(); |
| 1235 | var function_body = std.ArrayList(u8).init(gpa); | 1237 | var function_body = std.ArrayList(u8).init(gpa); |
| 1236 | defer function_body.deinit(); | 1238 | defer function_body.deinit(); |
| ... | @@ -1244,7 +1246,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { | ... | @@ -1244,7 +1246,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1244 | if (sym.tag == .data and sym.isDefined()) { | 1246 | if (sym.tag == .data and sym.isDefined()) { |
| 1245 | // get __tls_base | 1247 | // get __tls_base |
| 1246 | try writer.writeByte(std.wasm.opcode(.global_get)); | 1248 | try writer.writeByte(std.wasm.opcode(.global_get)); |
| 1247 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.findGlobalSymbol("__tls_base").?).index); | 1249 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.globals.get(wasm.preloaded_strings.__tls_base).?).index); |
| 1248 | | 1250 | |
| 1249 | // add the virtual address of the symbol | 1251 | // add the virtual address of the symbol |
| 1250 | try writer.writeByte(std.wasm.opcode(.i32_const)); | 1252 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| ... | @@ -1260,7 +1262,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { | ... | @@ -1260,7 +1262,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1260 | try writer.writeByte(std.wasm.opcode(.end)); | 1262 | try writer.writeByte(std.wasm.opcode(.end)); |
| 1261 | | 1263 | |
| 1262 | try wasm.createSyntheticFunction( | 1264 | try wasm.createSyntheticFunction( |
| 1263 | "__wasm_apply_global_tls_relocs", | 1265 | wasm.preloaded_strings.__wasm_apply_global_tls_relocs, |
| 1264 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, | 1266 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, |
| 1265 | &function_body, | 1267 | &function_body, |
| 1266 | ); | 1268 | ); |
| ... | @@ -1422,7 +1424,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { | ... | @@ -1422,7 +1424,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1422 | const gpa = comp.gpa; | 1424 | const gpa = comp.gpa; |
| 1423 | const shared_memory = comp.config.shared_memory; | 1425 | const shared_memory = comp.config.shared_memory; |
| 1424 | | 1426 | |
| 1425 | if (wasm.string_table.getOffset("__heap_base")) |name_offset| { | 1427 | if (wasm.getExistingString("__heap_base")) |name_offset| { |
| 1426 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { | 1428 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1427 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); | 1429 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); |
| 1428 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); | 1430 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); |
| ... | @@ -1430,7 +1432,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { | ... | @@ -1430,7 +1432,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1430 | } | 1432 | } |
| 1431 | } | 1433 | } |
| 1432 | | 1434 | |
| 1433 | if (wasm.string_table.getOffset("__heap_end")) |name_offset| { | 1435 | if (wasm.getExistingString("__heap_end")) |name_offset| { |
| 1434 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { | 1436 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1435 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); | 1437 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); |
| 1436 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); | 1438 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); |
| ... | @@ -1439,7 +1441,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { | ... | @@ -1439,7 +1441,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1439 | } | 1441 | } |
| 1440 | | 1442 | |
| 1441 | if (!shared_memory) { | 1443 | if (!shared_memory) { |
| 1442 | if (wasm.string_table.getOffset("__tls_base")) |name_offset| { | 1444 | if (wasm.getExistingString("__tls_base")) |name_offset| { |
| 1443 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { | 1445 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1444 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); | 1446 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); |
| 1445 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); | 1447 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); |
| ... | @@ -1456,11 +1458,9 @@ fn resolveLazySymbols(wasm: *Wasm) !void { | ... | @@ -1456,11 +1458,9 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1456 | } | 1458 | } |
| 1457 | } | 1459 | } |
| 1458 | | 1460 | |
| 1459 | // Tries to find a global symbol by its name. Returns null when not found, | 1461 | pub fn findGlobalSymbol(wasm: *const Wasm, name: []const u8) ?SymbolLoc { |
| 1460 | /// and its location when it is found. | 1462 | const name_index = wasm.getExistingString(name) orelse return null; |
| 1461 | pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc { | 1463 | return wasm.globals.get(name_index); |
| 1462 | const offset = wasm.string_table.getOffset(name) orelse return null; | | |
| 1463 | return wasm.globals.get(offset); | | |
| 1464 | } | 1464 | } |
| 1465 | | 1465 | |
| 1466 | fn checkUndefinedSymbols(wasm: *const Wasm) !void { | 1466 | fn checkUndefinedSymbols(wasm: *const Wasm) !void { |
| ... | @@ -1516,7 +1516,7 @@ pub fn deinit(wasm: *Wasm) void { | ... | @@ -1516,7 +1516,7 @@ pub fn deinit(wasm: *Wasm) void { |
| 1516 | for (wasm.lazy_archives.items) |*lazy_archive| lazy_archive.deinit(gpa); | 1516 | for (wasm.lazy_archives.items) |*lazy_archive| lazy_archive.deinit(gpa); |
| 1517 | wasm.lazy_archives.deinit(gpa); | 1517 | wasm.lazy_archives.deinit(gpa); |
| 1518 | | 1518 | |
| 1519 | if (wasm.findGlobalSymbol("__wasm_init_tls")) |loc| { | 1519 | if (wasm.globals.get(wasm.preloaded_strings.__wasm_init_tls)) |loc| { |
| 1520 | const atom = wasm.symbol_atom.get(loc).?; | 1520 | const atom = wasm.symbol_atom.get(loc).?; |
| 1521 | wasm.getAtomPtr(atom).deinit(gpa); | 1521 | wasm.getAtomPtr(atom).deinit(gpa); |
| 1522 | } | 1522 | } |
| ... | @@ -1544,6 +1544,7 @@ pub fn deinit(wasm: *Wasm) void { | ... | @@ -1544,6 +1544,7 @@ pub fn deinit(wasm: *Wasm) void { |
| 1544 | wasm.init_funcs.deinit(gpa); | 1544 | wasm.init_funcs.deinit(gpa); |
| 1545 | wasm.exports.deinit(gpa); | 1545 | wasm.exports.deinit(gpa); |
| 1546 | | 1546 | |
| | 1547 | wasm.string_bytes.deinit(gpa); |
| 1547 | wasm.string_table.deinit(gpa); | 1548 | wasm.string_table.deinit(gpa); |
| 1548 | wasm.dump_argv_list.deinit(gpa); | 1549 | wasm.dump_argv_list.deinit(gpa); |
| 1549 | } | 1550 | } |
| ... | @@ -1649,7 +1650,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { | ... | @@ -1649,7 +1650,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1649 | /// and then returns the index to it. | 1650 | /// and then returns the index to it. |
| 1650 | pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { | 1651 | pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { |
| 1651 | _ = lib_name; | 1652 | _ = lib_name; |
| 1652 | return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name); | 1653 | const name_index = try wasm.internString(name); |
| | 1654 | return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name_index); |
| 1653 | } | 1655 | } |
| 1654 | | 1656 | |
| 1655 | /// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type. | 1657 | /// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type. |
| ... | @@ -1721,12 +1723,12 @@ fn mapFunctionTable(wasm: *Wasm) void { | ... | @@ -1721,12 +1723,12 @@ fn mapFunctionTable(wasm: *Wasm) void { |
| 1721 | } | 1723 | } |
| 1722 | | 1724 | |
| 1723 | if (wasm.import_table or wasm.base.comp.config.output_mode == .Obj) { | 1725 | if (wasm.import_table or wasm.base.comp.config.output_mode == .Obj) { |
| 1724 | const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?; | 1726 | const sym_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?; |
| 1725 | const import = wasm.imports.getPtr(sym_loc).?; | 1727 | const import = wasm.imports.getPtr(sym_loc).?; |
| 1726 | import.kind.table.limits.min = index - 1; // we start at index 1. | 1728 | import.kind.table.limits.min = index - 1; // we start at index 1. |
| 1727 | } else if (index > 1) { | 1729 | } else if (index > 1) { |
| 1728 | log.debug("Appending indirect function table", .{}); | 1730 | log.debug("Appending indirect function table", .{}); |
| 1729 | const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?; | 1731 | const sym_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?; |
| 1730 | const symbol = wasm.symbolLocSymbol(sym_loc); | 1732 | const symbol = wasm.symbolLocSymbol(sym_loc); |
| 1731 | const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count]; | 1733 | const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count]; |
| 1732 | table.limits = .{ .min = index, .max = index, .flags = 0x1 }; | 1734 | table.limits = .{ .min = index, .max = index, .flags = 0x1 }; |
| ... | @@ -1735,7 +1737,7 @@ fn mapFunctionTable(wasm: *Wasm) void { | ... | @@ -1735,7 +1737,7 @@ fn mapFunctionTable(wasm: *Wasm) void { |
| 1735 | | 1737 | |
| 1736 | /// From a given index, append the given `Atom` at the back of the linked list. | 1738 | /// From a given index, append the given `Atom` at the back of the linked list. |
| 1737 | /// Simply inserts it into the map of atoms when it doesn't exist yet. | 1739 | /// Simply inserts it into the map of atoms when it doesn't exist yet. |
| 1738 | pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void { | 1740 | pub fn appendAtomAtIndex(wasm: *Wasm, index: Segment.Index, atom_index: Atom.Index) !void { |
| 1739 | const gpa = wasm.base.comp.gpa; | 1741 | const gpa = wasm.base.comp.gpa; |
| 1740 | const atom = wasm.getAtomPtr(atom_index); | 1742 | const atom = wasm.getAtomPtr(atom_index); |
| 1741 | if (wasm.atoms.getPtr(index)) |last_index_ptr| { | 1743 | if (wasm.atoms.getPtr(index)) |last_index_ptr| { |
| ... | @@ -1752,9 +1754,9 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -1752,9 +1754,9 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 1752 | | 1754 | |
| 1753 | var it = wasm.atoms.iterator(); | 1755 | var it = wasm.atoms.iterator(); |
| 1754 | while (it.next()) |entry| { | 1756 | while (it.next()) |entry| { |
| 1755 | const segment = &wasm.segments.items[entry.key_ptr.*]; | 1757 | const segment = wasm.segmentPtr(entry.key_ptr.*); |
| 1756 | var atom_index = entry.value_ptr.*; | 1758 | var atom_index = entry.value_ptr.*; |
| 1757 | if (entry.key_ptr.* == wasm.code_section_index) { | 1759 | if (entry.key_ptr.toOptional() == wasm.code_section_index) { |
| 1758 | // Code section is allocated upon writing as they are required to be ordered | 1760 | // Code section is allocated upon writing as they are required to be ordered |
| 1759 | // to synchronise with the function section. | 1761 | // to synchronise with the function section. |
| 1760 | continue; | 1762 | continue; |
| ... | @@ -1825,7 +1827,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { | ... | @@ -1825,7 +1827,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { |
| 1825 | }; | 1827 | }; |
| 1826 | const segment_name = segment_info[symbol.index].outputName(merge_segment); | 1828 | const segment_name = segment_info[symbol.index].outputName(merge_segment); |
| 1827 | const segment_index = wasm.data_segments.get(segment_name).?; | 1829 | const segment_index = wasm.data_segments.get(segment_name).?; |
| 1828 | const segment = wasm.segments.items[segment_index]; | 1830 | const segment = wasm.segmentPtr(segment_index); |
| 1829 | | 1831 | |
| 1830 | // TLS symbols have their virtual address set relative to their own TLS segment, | 1832 | // TLS symbols have their virtual address set relative to their own TLS segment, |
| 1831 | // rather than the entire Data section. | 1833 | // rather than the entire Data section. |
| ... | @@ -1839,7 +1841,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { | ... | @@ -1839,7 +1841,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { |
| 1839 | | 1841 | |
| 1840 | fn sortDataSegments(wasm: *Wasm) !void { | 1842 | fn sortDataSegments(wasm: *Wasm) !void { |
| 1841 | const gpa = wasm.base.comp.gpa; | 1843 | const gpa = wasm.base.comp.gpa; |
| 1842 | var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .empty; | 1844 | var new_mapping: std.StringArrayHashMapUnmanaged(Segment.Index) = .empty; |
| 1843 | try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count()); | 1845 | try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count()); |
| 1844 | errdefer new_mapping.deinit(gpa); | 1846 | errdefer new_mapping.deinit(gpa); |
| 1845 | | 1847 | |
| ... | @@ -1894,9 +1896,9 @@ fn setupInitFunctions(wasm: *Wasm) !void { | ... | @@ -1894,9 +1896,9 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 1894 | }; | 1896 | }; |
| 1895 | if (ty.params.len != 0) { | 1897 | if (ty.params.len != 0) { |
| 1896 | var err = try diags.addErrorWithNotes(0); | 1898 | var err = try diags.addErrorWithNotes(0); |
| 1897 | try err.addMsg("constructor functions cannot take arguments: '{s}'", .{object.string_table.get(symbol.name)}); | 1899 | try err.addMsg("constructor functions cannot take arguments: '{s}'", .{wasm.stringSlice(symbol.name)}); |
| 1898 | } | 1900 | } |
| 1899 | log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)}); | 1901 | log.debug("appended init func '{s}'\n", .{wasm.stringSlice(symbol.name)}); |
| 1900 | wasm.init_funcs.appendAssumeCapacity(.{ | 1902 | wasm.init_funcs.appendAssumeCapacity(.{ |
| 1901 | .index = @enumFromInt(init_func.symbol_index), | 1903 | .index = @enumFromInt(init_func.symbol_index), |
| 1902 | .file = @enumFromInt(object_index), | 1904 | .file = @enumFromInt(object_index), |
| ... | @@ -1913,7 +1915,7 @@ fn setupInitFunctions(wasm: *Wasm) !void { | ... | @@ -1913,7 +1915,7 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 1913 | mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan); | 1915 | mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan); |
| 1914 | | 1916 | |
| 1915 | if (wasm.init_funcs.items.len > 0) { | 1917 | if (wasm.init_funcs.items.len > 0) { |
| 1916 | const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?; | 1918 | const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_call_ctors).?; |
| 1917 | try wasm.mark(loc); | 1919 | try wasm.mark(loc); |
| 1918 | } | 1920 | } |
| 1919 | } | 1921 | } |
| ... | @@ -1927,10 +1929,10 @@ fn setupInitFunctions(wasm: *Wasm) !void { | ... | @@ -1927,10 +1929,10 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 1927 | fn initializeCallCtorsFunction(wasm: *Wasm) !void { | 1929 | fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 1928 | const gpa = wasm.base.comp.gpa; | 1930 | const gpa = wasm.base.comp.gpa; |
| 1929 | // No code to emit, so also no ctors to call | 1931 | // No code to emit, so also no ctors to call |
| 1930 | if (wasm.code_section_index == null) { | 1932 | if (wasm.code_section_index == .none) { |
| 1931 | // Make sure to remove it from the resolved symbols so we do not emit | 1933 | // Make sure to remove it from the resolved symbols so we do not emit |
| 1932 | // it within any section. TODO: Remove this once we implement garbage collection. | 1934 | // it within any section. TODO: Remove this once we implement garbage collection. |
| 1933 | const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?; | 1935 | const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_call_ctors).?; |
| 1934 | assert(wasm.resolved_symbols.swapRemove(loc)); | 1936 | assert(wasm.resolved_symbols.swapRemove(loc)); |
| 1935 | return; | 1937 | return; |
| 1936 | } | 1938 | } |
| ... | @@ -1965,7 +1967,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { | ... | @@ -1965,7 +1967,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 1965 | } | 1967 | } |
| 1966 | | 1968 | |
| 1967 | try wasm.createSyntheticFunction( | 1969 | try wasm.createSyntheticFunction( |
| 1968 | "__wasm_call_ctors", | 1970 | wasm.preloaded_strings.__wasm_call_ctors, |
| 1969 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, | 1971 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, |
| 1970 | &function_body, | 1972 | &function_body, |
| 1971 | ); | 1973 | ); |
| ... | @@ -1973,12 +1975,12 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { | ... | @@ -1973,12 +1975,12 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 1973 | | 1975 | |
| 1974 | fn createSyntheticFunction( | 1976 | fn createSyntheticFunction( |
| 1975 | wasm: *Wasm, | 1977 | wasm: *Wasm, |
| 1976 | symbol_name: []const u8, | 1978 | symbol_name: String, |
| 1977 | func_ty: std.wasm.Type, | 1979 | func_ty: std.wasm.Type, |
| 1978 | function_body: *std.ArrayList(u8), | 1980 | function_body: *std.ArrayList(u8), |
| 1979 | ) !void { | 1981 | ) !void { |
| 1980 | const gpa = wasm.base.comp.gpa; | 1982 | const gpa = wasm.base.comp.gpa; |
| 1981 | const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol? | 1983 | const loc = wasm.globals.get(symbol_name).?; |
| 1982 | const symbol = wasm.symbolLocSymbol(loc); | 1984 | const symbol = wasm.symbolLocSymbol(loc); |
| 1983 | if (symbol.isDead()) { | 1985 | if (symbol.isDead()) { |
| 1984 | return; | 1986 | return; |
| ... | @@ -1998,7 +2000,7 @@ fn createSyntheticFunction( | ... | @@ -1998,7 +2000,7 @@ fn createSyntheticFunction( |
| 1998 | const atom = wasm.getAtomPtr(atom_index); | 2000 | const atom = wasm.getAtomPtr(atom_index); |
| 1999 | atom.size = @intCast(function_body.items.len); | 2001 | atom.size = @intCast(function_body.items.len); |
| 2000 | atom.code = function_body.moveToUnmanaged(); | 2002 | atom.code = function_body.moveToUnmanaged(); |
| 2001 | try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index); | 2003 | try wasm.appendAtomAtIndex(wasm.code_section_index.unwrap().?, atom_index); |
| 2002 | } | 2004 | } |
| 2003 | | 2005 | |
| 2004 | /// Unlike `createSyntheticFunction` this function is to be called by | 2006 | /// Unlike `createSyntheticFunction` this function is to be called by |
| ... | @@ -2016,7 +2018,7 @@ pub fn createFunction( | ... | @@ -2016,7 +2018,7 @@ pub fn createFunction( |
| 2016 | | 2018 | |
| 2017 | /// If required, sets the function index in the `start` section. | 2019 | /// If required, sets the function index in the `start` section. |
| 2018 | fn setupStartSection(wasm: *Wasm) !void { | 2020 | fn setupStartSection(wasm: *Wasm) !void { |
| 2019 | if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| { | 2021 | if (wasm.globals.get(wasm.preloaded_strings.__wasm_init_memory)) |loc| { |
| 2020 | wasm.entry = wasm.symbolLocSymbol(loc).index; | 2022 | wasm.entry = wasm.symbolLocSymbol(loc).index; |
| 2021 | } | 2023 | } |
| 2022 | } | 2024 | } |
| ... | @@ -2029,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { | ... | @@ -2029,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2029 | if (!shared_memory) return; | 2031 | if (!shared_memory) return; |
| 2030 | | 2032 | |
| 2031 | // ensure function is marked as we must emit it | 2033 | // ensure function is marked as we must emit it |
| 2032 | wasm.symbolLocSymbol(wasm.findGlobalSymbol("__wasm_init_tls").?).mark(); | 2034 | wasm.symbolLocSymbol(wasm.globals.get(wasm.preloaded_strings.__wasm_init_tls).?).mark(); |
| 2033 | | 2035 | |
| 2034 | var function_body = std.ArrayList(u8).init(gpa); | 2036 | var function_body = std.ArrayList(u8).init(gpa); |
| 2035 | defer function_body.deinit(); | 2037 | defer function_body.deinit(); |
| ... | @@ -2041,14 +2043,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void { | ... | @@ -2041,14 +2043,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2041 | // If there's a TLS segment, initialize it during runtime using the bulk-memory feature | 2043 | // If there's a TLS segment, initialize it during runtime using the bulk-memory feature |
| 2042 | if (wasm.data_segments.getIndex(".tdata")) |data_index| { | 2044 | if (wasm.data_segments.getIndex(".tdata")) |data_index| { |
| 2043 | const segment_index = wasm.data_segments.entries.items(.value)[data_index]; | 2045 | const segment_index = wasm.data_segments.entries.items(.value)[data_index]; |
| 2044 | const segment = wasm.segments.items[segment_index]; | 2046 | const segment = wasm.segmentPtr(segment_index); |
| 2045 | | 2047 | |
| 2046 | const param_local: u32 = 0; | 2048 | const param_local: u32 = 0; |
| 2047 | | 2049 | |
| 2048 | try writer.writeByte(std.wasm.opcode(.local_get)); | 2050 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 2049 | try leb.writeUleb128(writer, param_local); | 2051 | try leb.writeUleb128(writer, param_local); |
| 2050 | | 2052 | |
| 2051 | const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?; | 2053 | const tls_base_loc = wasm.globals.get(wasm.preloaded_strings.__tls_base).?; |
| 2052 | try writer.writeByte(std.wasm.opcode(.global_set)); | 2054 | try writer.writeByte(std.wasm.opcode(.global_set)); |
| 2053 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index); | 2055 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index); |
| 2054 | | 2056 | |
| ... | @@ -2076,7 +2078,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { | ... | @@ -2076,7 +2078,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2076 | // If we have to perform any TLS relocations, call the corresponding function | 2078 | // If we have to perform any TLS relocations, call the corresponding function |
| 2077 | // which performs all runtime TLS relocations. This is a synthetic function, | 2079 | // which performs all runtime TLS relocations. This is a synthetic function, |
| 2078 | // generated by the linker. | 2080 | // generated by the linker. |
| 2079 | if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| { | 2081 | if (wasm.globals.get(wasm.preloaded_strings.__wasm_apply_global_tls_relocs)) |loc| { |
| 2080 | try writer.writeByte(std.wasm.opcode(.call)); | 2082 | try writer.writeByte(std.wasm.opcode(.call)); |
| 2081 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index); | 2083 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index); |
| 2082 | wasm.symbolLocSymbol(loc).mark(); | 2084 | wasm.symbolLocSymbol(loc).mark(); |
| ... | @@ -2085,7 +2087,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { | ... | @@ -2085,7 +2087,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2085 | try writer.writeByte(std.wasm.opcode(.end)); | 2087 | try writer.writeByte(std.wasm.opcode(.end)); |
| 2086 | | 2088 | |
| 2087 | try wasm.createSyntheticFunction( | 2089 | try wasm.createSyntheticFunction( |
| 2088 | "__wasm_init_tls", | 2090 | wasm.preloaded_strings.__wasm_init_tls, |
| 2089 | std.wasm.Type{ .params = &.{.i32}, .returns = &.{} }, | 2091 | std.wasm.Type{ .params = &.{.i32}, .returns = &.{} }, |
| 2090 | &function_body, | 2092 | &function_body, |
| 2091 | ); | 2093 | ); |
| ... | @@ -2101,21 +2103,18 @@ fn setupImports(wasm: *Wasm) !void { | ... | @@ -2101,21 +2103,18 @@ fn setupImports(wasm: *Wasm) !void { |
| 2101 | }; | 2103 | }; |
| 2102 | | 2104 | |
| 2103 | const symbol = wasm.symbolLocSymbol(symbol_loc); | 2105 | const symbol = wasm.symbolLocSymbol(symbol_loc); |
| 2104 | if (symbol.isDead() or | 2106 | if (symbol.isDead()) continue; |
| 2105 | !symbol.requiresImport() or | 2107 | if (!symbol.requiresImport()) continue; |
| 2106 | std.mem.eql(u8, wasm.symbolLocName(symbol_loc), "__indirect_function_table")) | 2108 | if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue; |
| 2107 | { | | |
| 2108 | continue; | | |
| 2109 | } | | |
| 2110 | | 2109 | |
| 2111 | log.debug("Symbol '{s}' will be imported from the host", .{wasm.symbolLocName(symbol_loc)}); | 2110 | log.debug("Symbol '{s}' will be imported from the host", .{wasm.stringSlice(symbol.name)}); |
| 2112 | const import = objectImport(wasm, object_id, symbol_loc.index); | 2111 | const import = objectImport(wasm, object_id, symbol_loc.index); |
| 2113 | | 2112 | |
| 2114 | // We copy the import to a new import to ensure the names contain references | 2113 | // We copy the import to a new import to ensure the names contain references |
| 2115 | // to the internal string table, rather than of the object file. | 2114 | // to the internal string table, rather than of the object file. |
| 2116 | const new_imp: Import = .{ | 2115 | const new_imp: Import = .{ |
| 2117 | .module_name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.module_name)), | 2116 | .module_name = import.module_name, |
| 2118 | .name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.name)), | 2117 | .name = import.name, |
| 2119 | .kind = import.kind, | 2118 | .kind = import.kind, |
| 2120 | }; | 2119 | }; |
| 2121 | // TODO: De-duplicate imports when they contain the same names and type | 2120 | // TODO: De-duplicate imports when they contain the same names and type |
| ... | @@ -2283,7 +2282,8 @@ fn checkExportNames(wasm: *Wasm) !void { | ... | @@ -2283,7 +2282,8 @@ fn checkExportNames(wasm: *Wasm) !void { |
| 2283 | var failed_exports = false; | 2282 | var failed_exports = false; |
| 2284 | | 2283 | |
| 2285 | for (force_exp_names) |exp_name| { | 2284 | for (force_exp_names) |exp_name| { |
| 2286 | const loc = wasm.findGlobalSymbol(exp_name) orelse { | 2285 | const exp_name_interned = try wasm.internString(exp_name); |
| | 2286 | const loc = wasm.globals.get(exp_name_interned) orelse { |
| 2287 | var err = try diags.addErrorWithNotes(0); | 2287 | var err = try diags.addErrorWithNotes(0); |
| 2288 | try err.addMsg("could not export '{s}', symbol not found", .{exp_name}); | 2288 | try err.addMsg("could not export '{s}', symbol not found", .{exp_name}); |
| 2289 | failed_exports = true; | 2289 | failed_exports = true; |
| ... | @@ -2310,11 +2310,6 @@ fn setupExports(wasm: *Wasm) !void { | ... | @@ -2310,11 +2310,6 @@ fn setupExports(wasm: *Wasm) !void { |
| 2310 | const symbol = wasm.symbolLocSymbol(sym_loc); | 2310 | const symbol = wasm.symbolLocSymbol(sym_loc); |
| 2311 | if (!symbol.isExported(comp.config.rdynamic)) continue; | 2311 | if (!symbol.isExported(comp.config.rdynamic)) continue; |
| 2312 | | 2312 | |
| 2313 | const sym_name = wasm.symbolLocName(sym_loc); | | |
| 2314 | const export_name = if (sym_loc.file == .none) | | |
| 2315 | symbol.name | | |
| 2316 | else | | |
| 2317 | try wasm.string_table.put(gpa, sym_name); | | |
| 2318 | const exp: Export = if (symbol.tag == .data) exp: { | 2313 | const exp: Export = if (symbol.tag == .data) exp: { |
| 2319 | const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len)); | 2314 | const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len)); |
| 2320 | try wasm.wasm_globals.append(gpa, .{ | 2315 | try wasm.wasm_globals.append(gpa, .{ |
| ... | @@ -2322,18 +2317,18 @@ fn setupExports(wasm: *Wasm) !void { | ... | @@ -2322,18 +2317,18 @@ fn setupExports(wasm: *Wasm) !void { |
| 2322 | .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) }, | 2317 | .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) }, |
| 2323 | }); | 2318 | }); |
| 2324 | break :exp .{ | 2319 | break :exp .{ |
| 2325 | .name = export_name, | 2320 | .name = symbol.name, |
| 2326 | .kind = .global, | 2321 | .kind = .global, |
| 2327 | .index = global_index, | 2322 | .index = global_index, |
| 2328 | }; | 2323 | }; |
| 2329 | } else .{ | 2324 | } else .{ |
| 2330 | .name = export_name, | 2325 | .name = symbol.name, |
| 2331 | .kind = symbol.tag.externalType(), | 2326 | .kind = symbol.tag.externalType(), |
| 2332 | .index = symbol.index, | 2327 | .index = symbol.index, |
| 2333 | }; | 2328 | }; |
| 2334 | log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ | 2329 | log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ |
| 2335 | sym_name, | 2330 | wasm.stringSlice(symbol.name), |
| 2336 | wasm.string_table.get(exp.name), | 2331 | wasm.stringSlice(exp.name), |
| 2337 | exp.index, | 2332 | exp.index, |
| 2338 | }); | 2333 | }); |
| 2339 | try wasm.exports.append(gpa, exp); | 2334 | try wasm.exports.append(gpa, exp); |
| ... | @@ -2346,20 +2341,18 @@ fn setupStart(wasm: *Wasm) !void { | ... | @@ -2346,20 +2341,18 @@ fn setupStart(wasm: *Wasm) !void { |
| 2346 | const comp = wasm.base.comp; | 2341 | const comp = wasm.base.comp; |
| 2347 | const diags = &wasm.base.comp.link_diags; | 2342 | const diags = &wasm.base.comp.link_diags; |
| 2348 | // do not export entry point if user set none or no default was set. | 2343 | // do not export entry point if user set none or no default was set. |
| 2349 | const entry_name = wasm.entry_name orelse return; | 2344 | const entry_name = wasm.entry_name.unwrap() orelse return; |
| 2350 | | 2345 | |
| 2351 | const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse { | 2346 | const symbol_loc = wasm.globals.get(entry_name) orelse { |
| 2352 | var err = try diags.addErrorWithNotes(0); | 2347 | var err = try diags.addErrorWithNotes(1); |
| 2353 | try err.addMsg("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name}); | 2348 | try err.addMsg("entry symbol '{s}' missing", .{wasm.stringSlice(entry_name)}); |
| 2354 | return error.FlushFailure; | 2349 | try err.addNote("'-fno-entry' suppresses this error", .{}); |
| | 2350 | return error.LinkFailure; |
| 2355 | }; | 2351 | }; |
| 2356 | | 2352 | |
| 2357 | const symbol = wasm.symbolLocSymbol(symbol_loc); | 2353 | const symbol = wasm.symbolLocSymbol(symbol_loc); |
| 2358 | if (symbol.tag != .function) { | 2354 | if (symbol.tag != .function) |
| 2359 | var err = try diags.addErrorWithNotes(0); | 2355 | return diags.fail("entry symbol '{s}' is not a function", .{wasm.stringSlice(entry_name)}); |
| 2360 | try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name}); | | |
| 2361 | return error.FlushFailure; | | |
| 2362 | } | | |
| 2363 | | 2356 | |
| 2364 | // Ensure the symbol is exported so host environment can access it | 2357 | // Ensure the symbol is exported so host environment can access it |
| 2365 | if (comp.config.output_mode != .Obj) { | 2358 | if (comp.config.output_mode != .Obj) { |
| ... | @@ -2387,7 +2380,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2387,7 +2380,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2387 | | 2380 | |
| 2388 | const is_obj = comp.config.output_mode == .Obj; | 2381 | const is_obj = comp.config.output_mode == .Obj; |
| 2389 | | 2382 | |
| 2390 | const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: { | 2383 | const stack_ptr = if (wasm.globals.get(wasm.preloaded_strings.__stack_pointer)) |loc| index: { |
| 2391 | const sym = wasm.symbolLocSymbol(loc); | 2384 | const sym = wasm.symbolLocSymbol(loc); |
| 2392 | break :index sym.index - wasm.imported_globals_count; | 2385 | break :index sym.index - wasm.imported_globals_count; |
| 2393 | } else null; | 2386 | } else null; |
| ... | @@ -2404,20 +2397,20 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2404,20 +2397,20 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2404 | var offset: u32 = @as(u32, @intCast(memory_ptr)); | 2397 | var offset: u32 = @as(u32, @intCast(memory_ptr)); |
| 2405 | var data_seg_it = wasm.data_segments.iterator(); | 2398 | var data_seg_it = wasm.data_segments.iterator(); |
| 2406 | while (data_seg_it.next()) |entry| { | 2399 | while (data_seg_it.next()) |entry| { |
| 2407 | const segment = &wasm.segments.items[entry.value_ptr.*]; | 2400 | const segment = wasm.segmentPtr(entry.value_ptr.*); |
| 2408 | memory_ptr = segment.alignment.forward(memory_ptr); | 2401 | memory_ptr = segment.alignment.forward(memory_ptr); |
| 2409 | | 2402 | |
| 2410 | // set TLS-related symbols | 2403 | // set TLS-related symbols |
| 2411 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { | 2404 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { |
| 2412 | if (wasm.findGlobalSymbol("__tls_size")) |loc| { | 2405 | if (wasm.globals.get(wasm.preloaded_strings.__tls_size)) |loc| { |
| 2413 | const sym = wasm.symbolLocSymbol(loc); | 2406 | const sym = wasm.symbolLocSymbol(loc); |
| 2414 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size); | 2407 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size); |
| 2415 | } | 2408 | } |
| 2416 | if (wasm.findGlobalSymbol("__tls_align")) |loc| { | 2409 | if (wasm.globals.get(wasm.preloaded_strings.__tls_align)) |loc| { |
| 2417 | const sym = wasm.symbolLocSymbol(loc); | 2410 | const sym = wasm.symbolLocSymbol(loc); |
| 2418 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?); | 2411 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?); |
| 2419 | } | 2412 | } |
| 2420 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { | 2413 | if (wasm.globals.get(wasm.preloaded_strings.__tls_base)) |loc| { |
| 2421 | const sym = wasm.symbolLocSymbol(loc); | 2414 | const sym = wasm.symbolLocSymbol(loc); |
| 2422 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory) | 2415 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory) |
| 2423 | @as(i32, 0) | 2416 | @as(i32, 0) |
| ... | @@ -2435,7 +2428,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2435,7 +2428,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2435 | if (shared_memory and wasm.hasPassiveInitializationSegments()) { | 2428 | if (shared_memory and wasm.hasPassiveInitializationSegments()) { |
| 2436 | // align to pointer size | 2429 | // align to pointer size |
| 2437 | memory_ptr = mem.alignForward(u64, memory_ptr, 4); | 2430 | memory_ptr = mem.alignForward(u64, memory_ptr, 4); |
| 2438 | const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data); | 2431 | const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_memory_flag, .data); |
| 2439 | const sym = wasm.symbolLocSymbol(loc); | 2432 | const sym = wasm.symbolLocSymbol(loc); |
| 2440 | sym.mark(); | 2433 | sym.mark(); |
| 2441 | sym.virtual_address = @as(u32, @intCast(memory_ptr)); | 2434 | sym.virtual_address = @as(u32, @intCast(memory_ptr)); |
| ... | @@ -2452,7 +2445,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2452,7 +2445,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2452 | | 2445 | |
| 2453 | // One of the linked object files has a reference to the __heap_base symbol. | 2446 | // One of the linked object files has a reference to the __heap_base symbol. |
| 2454 | // We must set its virtual address so it can be used in relocations. | 2447 | // We must set its virtual address so it can be used in relocations. |
| 2455 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { | 2448 | if (wasm.globals.get(wasm.preloaded_strings.__heap_base)) |loc| { |
| 2456 | const symbol = wasm.symbolLocSymbol(loc); | 2449 | const symbol = wasm.symbolLocSymbol(loc); |
| 2457 | symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr)); | 2450 | symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr)); |
| 2458 | } | 2451 | } |
| ... | @@ -2482,7 +2475,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2482,7 +2475,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2482 | wasm.memories.limits.min = @as(u32, @intCast(memory_ptr / page_size)); | 2475 | wasm.memories.limits.min = @as(u32, @intCast(memory_ptr / page_size)); |
| 2483 | log.debug("Total memory pages: {d}", .{wasm.memories.limits.min}); | 2476 | log.debug("Total memory pages: {d}", .{wasm.memories.limits.min}); |
| 2484 | | 2477 | |
| 2485 | if (wasm.findGlobalSymbol("__heap_end")) |loc| { | 2478 | if (wasm.globals.get(wasm.preloaded_strings.__heap_end)) |loc| { |
| 2486 | const symbol = wasm.symbolLocSymbol(loc); | 2479 | const symbol = wasm.symbolLocSymbol(loc); |
| 2487 | symbol.virtual_address = @as(u32, @intCast(memory_ptr)); | 2480 | symbol.virtual_address = @as(u32, @intCast(memory_ptr)); |
| 2488 | } | 2481 | } |
| ... | @@ -2512,12 +2505,12 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2512,12 +2505,12 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2512 | /// From a given object's index and the index of the segment, returns the corresponding | 2505 | /// From a given object's index and the index of the segment, returns the corresponding |
| 2513 | /// index of the segment within the final data section. When the segment does not yet | 2506 | /// index of the segment within the final data section. When the segment does not yet |
| 2514 | /// exist, a new one will be initialized and appended. The new index will be returned in that case. | 2507 | /// exist, a new one will be initialized and appended. The new index will be returned in that case. |
| 2515 | pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !u32 { | 2508 | pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !Segment.Index { |
| 2516 | const comp = wasm.base.comp; | 2509 | const comp = wasm.base.comp; |
| 2517 | const gpa = comp.gpa; | 2510 | const gpa = comp.gpa; |
| 2518 | const diags = &wasm.base.comp.link_diags; | 2511 | const diags = &wasm.base.comp.link_diags; |
| 2519 | const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)]; | 2512 | const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)]; |
| 2520 | const index: u32 = @intCast(wasm.segments.items.len); | 2513 | const index: Segment.Index = @enumFromInt(wasm.segments.items.len); |
| 2521 | const shared_memory = comp.config.shared_memory; | 2514 | const shared_memory = comp.config.shared_memory; |
| 2522 | | 2515 | |
| 2523 | switch (symbol.tag) { | 2516 | switch (symbol.tag) { |
| ... | @@ -2545,66 +2538,27 @@ pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol | ... | @@ -2545,66 +2538,27 @@ pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol |
| 2545 | return index; | 2538 | return index; |
| 2546 | } else return result.value_ptr.*; | 2539 | } else return result.value_ptr.*; |
| 2547 | }, | 2540 | }, |
| 2548 | .function => return wasm.code_section_index orelse blk: { | 2541 | .function => return wasm.code_section_index.unwrap() orelse blk: { |
| 2549 | wasm.code_section_index = index; | 2542 | wasm.code_section_index = index.toOptional(); |
| 2550 | try wasm.appendDummySegment(); | 2543 | try wasm.appendDummySegment(); |
| 2551 | break :blk index; | 2544 | break :blk index; |
| 2552 | }, | 2545 | }, |
| 2553 | .section => { | 2546 | .section => { |
| 2554 | const section_name = objectSymbolName(wasm, object_id, symbol_index); | 2547 | const section_name = wasm.objectSymbol(object_id, symbol_index).name; |
| 2555 | if (mem.eql(u8, section_name, ".debug_info")) { | 2548 | |
| 2556 | return wasm.debug_info_index orelse blk: { | 2549 | inline for (@typeInfo(CustomSections).@"struct".fields) |field| { |
| 2557 | wasm.debug_info_index = index; | 2550 | if (@field(wasm.custom_sections, field.name).name == section_name) { |
| 2558 | try wasm.appendDummySegment(); | 2551 | const field_ptr = &@field(wasm.custom_sections, field.name).index; |
| 2559 | break :blk index; | 2552 | return field_ptr.unwrap() orelse { |
| 2560 | }; | 2553 | field_ptr.* = index.toOptional(); |
| 2561 | } else if (mem.eql(u8, section_name, ".debug_line")) { | 2554 | try wasm.appendDummySegment(); |
| 2562 | return wasm.debug_line_index orelse blk: { | 2555 | return index; |
| 2563 | wasm.debug_line_index = index; | 2556 | }; |
| 2564 | try wasm.appendDummySegment(); | 2557 | } |
| 2565 | break :blk index; | | |
| 2566 | }; | | |
| 2567 | } else if (mem.eql(u8, section_name, ".debug_loc")) { | | |
| 2568 | return wasm.debug_loc_index orelse blk: { | | |
| 2569 | wasm.debug_loc_index = index; | | |
| 2570 | try wasm.appendDummySegment(); | | |
| 2571 | break :blk index; | | |
| 2572 | }; | | |
| 2573 | } else if (mem.eql(u8, section_name, ".debug_ranges")) { | | |
| 2574 | return wasm.debug_ranges_index orelse blk: { | | |
| 2575 | wasm.debug_ranges_index = index; | | |
| 2576 | try wasm.appendDummySegment(); | | |
| 2577 | break :blk index; | | |
| 2578 | }; | | |
| 2579 | } else if (mem.eql(u8, section_name, ".debug_pubnames")) { | | |
| 2580 | return wasm.debug_pubnames_index orelse blk: { | | |
| 2581 | wasm.debug_pubnames_index = index; | | |
| 2582 | try wasm.appendDummySegment(); | | |
| 2583 | break :blk index; | | |
| 2584 | }; | | |
| 2585 | } else if (mem.eql(u8, section_name, ".debug_pubtypes")) { | | |
| 2586 | return wasm.debug_pubtypes_index orelse blk: { | | |
| 2587 | wasm.debug_pubtypes_index = index; | | |
| 2588 | try wasm.appendDummySegment(); | | |
| 2589 | break :blk index; | | |
| 2590 | }; | | |
| 2591 | } else if (mem.eql(u8, section_name, ".debug_abbrev")) { | | |
| 2592 | return wasm.debug_abbrev_index orelse blk: { | | |
| 2593 | wasm.debug_abbrev_index = index; | | |
| 2594 | try wasm.appendDummySegment(); | | |
| 2595 | break :blk index; | | |
| 2596 | }; | | |
| 2597 | } else if (mem.eql(u8, section_name, ".debug_str")) { | | |
| 2598 | return wasm.debug_str_index orelse blk: { | | |
| 2599 | wasm.debug_str_index = index; | | |
| 2600 | try wasm.appendDummySegment(); | | |
| 2601 | break :blk index; | | |
| 2602 | }; | | |
| 2603 | } else { | 2558 | } else { |
| 2604 | var err = try diags.addErrorWithNotes(1); | 2559 | return diags.failParse(objectPath(wasm, object_id), "unknown section: {s}", .{ |
| 2605 | try err.addMsg("found unknown section '{s}'", .{section_name}); | 2560 | wasm.stringSlice(section_name), |
| 2606 | try err.addNote("defined in '{'}'", .{objectPath(wasm, object_id)}); | 2561 | }); |
| 2607 | return error.UnexpectedValue; | | |
| 2608 | } | 2562 | } |
| 2609 | }, | 2563 | }, |
| 2610 | else => unreachable, | 2564 | else => unreachable, |
| ... | @@ -2803,10 +2757,9 @@ fn writeToFile( | ... | @@ -2803,10 +2757,9 @@ fn writeToFile( |
| 2803 | } | 2757 | } |
| 2804 | | 2758 | |
| 2805 | if (import_memory) { | 2759 | if (import_memory) { |
| 2806 | const mem_name = if (is_obj) "__linear_memory" else "memory"; | | |
| 2807 | const mem_imp: Import = .{ | 2760 | const mem_imp: Import = .{ |
| 2808 | .module_name = try wasm.string_table.put(gpa, wasm.host_name), | 2761 | .module_name = wasm.host_name, |
| 2809 | .name = try wasm.string_table.put(gpa, mem_name), | 2762 | .name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory, |
| 2810 | .kind = .{ .memory = wasm.memories.limits }, | 2763 | .kind = .{ .memory = wasm.memories.limits }, |
| 2811 | }; | 2764 | }; |
| 2812 | try wasm.emitImport(binary_writer, mem_imp); | 2765 | try wasm.emitImport(binary_writer, mem_imp); |
| ... | @@ -2898,7 +2851,7 @@ fn writeToFile( | ... | @@ -2898,7 +2851,7 @@ fn writeToFile( |
| 2898 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2851 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2899 | | 2852 | |
| 2900 | for (wasm.exports.items) |exp| { | 2853 | for (wasm.exports.items) |exp| { |
| 2901 | const name = wasm.string_table.get(exp.name); | 2854 | const name = wasm.stringSlice(exp.name); |
| 2902 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); | 2855 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); |
| 2903 | try binary_writer.writeAll(name); | 2856 | try binary_writer.writeAll(name); |
| 2904 | try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind)); | 2857 | try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind)); |
| ... | @@ -2937,7 +2890,7 @@ fn writeToFile( | ... | @@ -2937,7 +2890,7 @@ fn writeToFile( |
| 2937 | if (wasm.function_table.count() > 0) { | 2890 | if (wasm.function_table.count() > 0) { |
| 2938 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2891 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2939 | | 2892 | |
| 2940 | const table_loc = wasm.findGlobalSymbol("__indirect_function_table").?; | 2893 | const table_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?; |
| 2941 | const table_sym = wasm.symbolLocSymbol(table_loc); | 2894 | const table_sym = wasm.symbolLocSymbol(table_loc); |
| 2942 | | 2895 | |
| 2943 | const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually | 2896 | const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually |
| ... | @@ -2982,7 +2935,7 @@ fn writeToFile( | ... | @@ -2982,7 +2935,7 @@ fn writeToFile( |
| 2982 | } | 2935 | } |
| 2983 | | 2936 | |
| 2984 | // Code section | 2937 | // Code section |
| 2985 | if (wasm.code_section_index != null) { | 2938 | if (wasm.code_section_index != .none) { |
| 2986 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2939 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2987 | const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count | 2940 | const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count |
| 2988 | | 2941 | |
| ... | @@ -3022,7 +2975,7 @@ fn writeToFile( | ... | @@ -3022,7 +2975,7 @@ fn writeToFile( |
| 3022 | // want to guarantee the data is zero initialized | 2975 | // want to guarantee the data is zero initialized |
| 3023 | if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue; | 2976 | if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue; |
| 3024 | const segment_index = entry.value_ptr.*; | 2977 | const segment_index = entry.value_ptr.*; |
| 3025 | const segment = wasm.segments.items[segment_index]; | 2978 | const segment = wasm.segmentPtr(segment_index); |
| 3026 | if (segment.size == 0) continue; // do not emit empty segments | 2979 | if (segment.size == 0) continue; // do not emit empty segments |
| 3027 | segment_count += 1; | 2980 | segment_count += 1; |
| 3028 | var atom_index = wasm.atoms.get(segment_index).?; | 2981 | var atom_index = wasm.atoms.get(segment_index).?; |
| ... | @@ -3133,24 +3086,8 @@ fn writeToFile( | ... | @@ -3133,24 +3086,8 @@ fn writeToFile( |
| 3133 | var debug_bytes = std.ArrayList(u8).init(gpa); | 3086 | var debug_bytes = std.ArrayList(u8).init(gpa); |
| 3134 | defer debug_bytes.deinit(); | 3087 | defer debug_bytes.deinit(); |
| 3135 | | 3088 | |
| 3136 | const DebugSection = struct { | 3089 | inline for (@typeInfo(CustomSections).@"struct".fields) |field| { |
| 3137 | name: []const u8, | 3090 | if (@field(wasm.custom_sections, field.name).index.unwrap()) |index| { |
| 3138 | index: ?u32, | | |
| 3139 | }; | | |
| 3140 | | | |
| 3141 | const debug_sections: []const DebugSection = &.{ | | |
| 3142 | .{ .name = ".debug_info", .index = wasm.debug_info_index }, | | |
| 3143 | .{ .name = ".debug_pubtypes", .index = wasm.debug_pubtypes_index }, | | |
| 3144 | .{ .name = ".debug_abbrev", .index = wasm.debug_abbrev_index }, | | |
| 3145 | .{ .name = ".debug_line", .index = wasm.debug_line_index }, | | |
| 3146 | .{ .name = ".debug_str", .index = wasm.debug_str_index }, | | |
| 3147 | .{ .name = ".debug_pubnames", .index = wasm.debug_pubnames_index }, | | |
| 3148 | .{ .name = ".debug_loc", .index = wasm.debug_loc_index }, | | |
| 3149 | .{ .name = ".debug_ranges", .index = wasm.debug_ranges_index }, | | |
| 3150 | }; | | |
| 3151 | | | |
| 3152 | for (debug_sections) |item| { | | |
| 3153 | if (item.index) |index| { | | |
| 3154 | var atom = wasm.getAtomPtr(wasm.atoms.get(index).?); | 3091 | var atom = wasm.getAtomPtr(wasm.atoms.get(index).?); |
| 3155 | while (true) { | 3092 | while (true) { |
| 3156 | atom.resolveRelocs(wasm); | 3093 | atom.resolveRelocs(wasm); |
| ... | @@ -3158,7 +3095,7 @@ fn writeToFile( | ... | @@ -3158,7 +3095,7 @@ fn writeToFile( |
| 3158 | if (atom.prev == .null) break; | 3095 | if (atom.prev == .null) break; |
| 3159 | atom = wasm.getAtomPtr(atom.prev); | 3096 | atom = wasm.getAtomPtr(atom.prev); |
| 3160 | } | 3097 | } |
| 3161 | try emitDebugSection(&binary_bytes, debug_bytes.items, item.name); | 3098 | try emitDebugSection(&binary_bytes, debug_bytes.items, field.name); |
| 3162 | debug_bytes.clearRetainingCapacity(); | 3099 | debug_bytes.clearRetainingCapacity(); |
| 3163 | } | 3100 | } |
| 3164 | } | 3101 | } |
| ... | @@ -3430,11 +3367,11 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { | ... | @@ -3430,11 +3367,11 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { |
| 3430 | } | 3367 | } |
| 3431 | | 3368 | |
| 3432 | fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void { | 3369 | fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void { |
| 3433 | const module_name = wasm.string_table.get(import.module_name); | 3370 | const module_name = wasm.stringSlice(import.module_name); |
| 3434 | try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len))); | 3371 | try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len))); |
| 3435 | try writer.writeAll(module_name); | 3372 | try writer.writeAll(module_name); |
| 3436 | | 3373 | |
| 3437 | const name = wasm.string_table.get(import.name); | 3374 | const name = wasm.stringSlice(import.name); |
| 3438 | try leb.writeUleb128(writer, @as(u32, @intCast(name.len))); | 3375 | try leb.writeUleb128(writer, @as(u32, @intCast(name.len))); |
| 3439 | try writer.writeAll(name); | 3376 | try writer.writeAll(name); |
| 3440 | | 3377 | |
| ... | @@ -3515,7 +3452,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: | ... | @@ -3515,7 +3452,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: |
| 3515 | } | 3452 | } |
| 3516 | try man.addOptionalFile(module_obj_path); | 3453 | try man.addOptionalFile(module_obj_path); |
| 3517 | try man.addOptionalFilePath(compiler_rt_path); | 3454 | try man.addOptionalFilePath(compiler_rt_path); |
| 3518 | man.hash.addOptionalBytes(wasm.entry_name); | 3455 | man.hash.addOptionalBytes(wasm.optionalStringSlice(wasm.entry_name)); |
| 3519 | man.hash.add(wasm.base.stack_size); | 3456 | man.hash.add(wasm.base.stack_size); |
| 3520 | man.hash.add(wasm.base.build_id); | 3457 | man.hash.add(wasm.base.build_id); |
| 3521 | man.hash.add(import_memory); | 3458 | man.hash.add(import_memory); |
| ... | @@ -3664,7 +3601,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: | ... | @@ -3664,7 +3601,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: |
| 3664 | try argv.append("--export-dynamic"); | 3601 | try argv.append("--export-dynamic"); |
| 3665 | } | 3602 | } |
| 3666 | | 3603 | |
| 3667 | if (wasm.entry_name) |entry_name| { | 3604 | if (wasm.optionalStringSlice(wasm.entry_name)) |entry_name| { |
| 3668 | try argv.appendSlice(&.{ "--entry", entry_name }); | 3605 | try argv.appendSlice(&.{ "--entry", entry_name }); |
| 3669 | } else { | 3606 | } else { |
| 3670 | try argv.append("--no-entry"); | 3607 | try argv.append("--no-entry"); |
| ... | @@ -4009,7 +3946,7 @@ fn emitCodeRelocations( | ... | @@ -4009,7 +3946,7 @@ fn emitCodeRelocations( |
| 4009 | section_index: u32, | 3946 | section_index: u32, |
| 4010 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), | 3947 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), |
| 4011 | ) !void { | 3948 | ) !void { |
| 4012 | const code_index = wasm.code_section_index orelse return; | 3949 | const code_index = wasm.code_section_index.unwrap() orelse return; |
| 4013 | const writer = binary_bytes.writer(); | 3950 | const writer = binary_bytes.writer(); |
| 4014 | const header_offset = try reserveCustomSectionHeader(binary_bytes); | 3951 | const header_offset = try reserveCustomSectionHeader(binary_bytes); |
| 4015 | | 3952 | |
| ... | @@ -4106,7 +4043,7 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool { | ... | @@ -4106,7 +4043,7 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool { |
| 4106 | | 4043 | |
| 4107 | var it = wasm.data_segments.iterator(); | 4044 | var it = wasm.data_segments.iterator(); |
| 4108 | while (it.next()) |entry| { | 4045 | while (it.next()) |entry| { |
| 4109 | const segment: Segment = wasm.segments.items[entry.value_ptr.*]; | 4046 | const segment = wasm.segmentPtr(entry.value_ptr.*); |
| 4110 | if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { | 4047 | if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { |
| 4111 | return true; | 4048 | return true; |
| 4112 | } | 4049 | } |
| ... | @@ -4213,10 +4150,13 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void { | ... | @@ -4213,10 +4150,13 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void { |
| 4213 | } | 4150 | } |
| 4214 | } | 4151 | } |
| 4215 | | 4152 | |
| 4216 | fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 { | 4153 | fn defaultEntrySymbolName( |
| | 4154 | preloaded_strings: *const PreloadedStrings, |
| | 4155 | wasi_exec_model: std.builtin.WasiExecModel, |
| | 4156 | ) String { |
| 4217 | return switch (wasi_exec_model) { | 4157 | return switch (wasi_exec_model) { |
| 4218 | .reactor => "_initialize", | 4158 | .reactor => preloaded_strings._initialize, |
| 4219 | .command => "_start", | 4159 | .command => preloaded_strings._start, |
| 4220 | }; | 4160 | }; |
| 4221 | } | 4161 | } |
| 4222 | | 4162 | |
| ... | @@ -4352,7 +4292,7 @@ pub const Atom = struct { | ... | @@ -4352,7 +4292,7 @@ pub const Atom = struct { |
| 4352 | symbol.tag != .section and | 4292 | symbol.tag != .section and |
| 4353 | symbol.isDead()) | 4293 | symbol.isDead()) |
| 4354 | { | 4294 | { |
| 4355 | const val = atom.thombstone(wasm) orelse relocation.addend; | 4295 | const val = atom.tombstone(wasm) orelse relocation.addend; |
| 4356 | return @bitCast(val); | 4296 | return @bitCast(val); |
| 4357 | } | 4297 | } |
| 4358 | switch (relocation.relocation_type) { | 4298 | switch (relocation.relocation_type) { |
| ... | @@ -4394,7 +4334,7 @@ pub const Atom = struct { | ... | @@ -4394,7 +4334,7 @@ pub const Atom = struct { |
| 4394 | }, | 4334 | }, |
| 4395 | .R_WASM_FUNCTION_OFFSET_I32 => { | 4335 | .R_WASM_FUNCTION_OFFSET_I32 => { |
| 4396 | if (symbol.isUndefined()) { | 4336 | if (symbol.isUndefined()) { |
| 4397 | const val = atom.thombstone(wasm) orelse relocation.addend; | 4337 | const val = atom.tombstone(wasm) orelse relocation.addend; |
| 4398 | return @bitCast(val); | 4338 | return @bitCast(val); |
| 4399 | } | 4339 | } |
| 4400 | const target_atom_index = wasm.symbol_atom.get(target_loc).?; | 4340 | const target_atom_index = wasm.symbol_atom.get(target_loc).?; |
| ... | @@ -4411,16 +4351,19 @@ pub const Atom = struct { | ... | @@ -4411,16 +4351,19 @@ pub const Atom = struct { |
| 4411 | } | 4351 | } |
| 4412 | } | 4352 | } |
| 4413 | | 4353 | |
| 4414 | // For a given `Atom` returns whether it has a thombstone value or not. | 4354 | // For a given `Atom` returns whether it has a tombstone value or not. |
| 4415 | /// This defines whether we want a specific value when a section is dead. | 4355 | /// This defines whether we want a specific value when a section is dead. |
| 4416 | fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 { | 4356 | fn tombstone(atom: Atom, wasm: *const Wasm) ?i64 { |
| 4417 | const atom_name = wasm.symbolLocName(atom.symbolLoc()); | 4357 | const atom_name = wasm.symbolLocSymbol(atom.symbolLoc()).name; |
| 4418 | if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) { | 4358 | if (atom_name == wasm.custom_sections.@".debug_ranges".name or |
| | 4359 | atom_name == wasm.custom_sections.@".debug_loc".name) |
| | 4360 | { |
| 4419 | return -2; | 4361 | return -2; |
| 4420 | } else if (std.mem.startsWith(u8, atom_name, ".debug_")) { | 4362 | } else if (std.mem.startsWith(u8, wasm.stringSlice(atom_name), ".debug_")) { |
| 4421 | return -1; | 4363 | return -1; |
| | 4364 | } else { |
| | 4365 | return null; |
| 4422 | } | 4366 | } |
| 4423 | return null; | | |
| 4424 | } | 4367 | } |
| 4425 | }; | 4368 | }; |
| 4426 | | 4369 | |
| ... | @@ -4509,8 +4452,8 @@ pub const Relocation = struct { | ... | @@ -4509,8 +4452,8 @@ pub const Relocation = struct { |
| 4509 | /// of the import using offsets into a string table, rather than the slices itself. | 4452 | /// of the import using offsets into a string table, rather than the slices itself. |
| 4510 | /// This saves us (potentially) 24 bytes per import on 64bit machines. | 4453 | /// This saves us (potentially) 24 bytes per import on 64bit machines. |
| 4511 | pub const Import = struct { | 4454 | pub const Import = struct { |
| 4512 | module_name: u32, | 4455 | module_name: String, |
| 4513 | name: u32, | 4456 | name: String, |
| 4514 | kind: std.wasm.Import.Kind, | 4457 | kind: std.wasm.Import.Kind, |
| 4515 | }; | 4458 | }; |
| 4516 | | 4459 | |
| ... | @@ -4519,7 +4462,7 @@ pub const Import = struct { | ... | @@ -4519,7 +4462,7 @@ pub const Import = struct { |
| 4519 | /// of the export using offsets into a string table, rather than the slice itself. | 4462 | /// of the export using offsets into a string table, rather than the slice itself. |
| 4520 | /// This saves us (potentially) 12 bytes per export on 64bit machines. | 4463 | /// This saves us (potentially) 12 bytes per export on 64bit machines. |
| 4521 | pub const Export = struct { | 4464 | pub const Export = struct { |
| 4522 | name: u32, | 4465 | name: String, |
| 4523 | index: u32, | 4466 | index: u32, |
| 4524 | kind: std.wasm.ExternalKind, | 4467 | kind: std.wasm.ExternalKind, |
| 4525 | }; | 4468 | }; |
| ... | @@ -4719,7 +4662,7 @@ fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.In | ... | @@ -4719,7 +4662,7 @@ fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.In |
| 4719 | atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]); | 4662 | atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]); |
| 4720 | atom.original_offset = relocatable_data.offset; | 4663 | atom.original_offset = relocatable_data.offset; |
| 4721 | | 4664 | |
| 4722 | const segment: *Wasm.Segment = &wasm.segments.items[final_index]; | 4665 | const segment = wasm.segmentPtr(final_index); |
| 4723 | if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned | 4666 | if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned |
| 4724 | segment.alignment = segment.alignment.max(atom.alignment); | 4667 | segment.alignment = segment.alignment.max(atom.alignment); |
| 4725 | } | 4668 | } |
| ... | @@ -4782,3 +4725,48 @@ fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize { | ... | @@ -4782,3 +4725,48 @@ fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize { |
| 4782 | } | 4725 | } |
| 4783 | return relocs.len; | 4726 | return relocs.len; |
| 4784 | } | 4727 | } |
| | 4728 | |
| | 4729 | pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String { |
| | 4730 | const gpa = wasm.base.comp.gpa; |
| | 4731 | const gop = try wasm.string_table.getOrPutContextAdapted( |
| | 4732 | gpa, |
| | 4733 | @as([]const u8, bytes), |
| | 4734 | @as(String.TableIndexAdapter, .{ .bytes = wasm.string_bytes.items }), |
| | 4735 | @as(String.TableContext, .{ .bytes = wasm.string_bytes.items }), |
| | 4736 | ); |
| | 4737 | if (gop.found_existing) return gop.key_ptr.*; |
| | 4738 | |
| | 4739 | try wasm.string_bytes.ensureUnusedCapacity(gpa, bytes.len + 1); |
| | 4740 | const new_off: String = @enumFromInt(wasm.string_bytes.items.len); |
| | 4741 | |
| | 4742 | wasm.string_bytes.appendSliceAssumeCapacity(bytes); |
| | 4743 | wasm.string_bytes.appendAssumeCapacity(0); |
| | 4744 | |
| | 4745 | gop.key_ptr.* = new_off; |
| | 4746 | |
| | 4747 | return new_off; |
| | 4748 | } |
| | 4749 | |
| | 4750 | pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String { |
| | 4751 | return wasm.string_table.getKeyAdapted(bytes, @as(String.TableIndexAdapter, .{ |
| | 4752 | .bytes = wasm.string_bytes.items, |
| | 4753 | })); |
| | 4754 | } |
| | 4755 | |
| | 4756 | pub fn stringSlice(wasm: *const Wasm, index: String) [:0]const u8 { |
| | 4757 | const slice = wasm.string_bytes.items[@intFromEnum(index)..]; |
| | 4758 | return slice[0..mem.indexOfScalar(u8, slice, 0).? :0]; |
| | 4759 | } |
| | 4760 | |
| | 4761 | pub fn optionalStringSlice(wasm: *const Wasm, index: OptionalString) ?[:0]const u8 { |
| | 4762 | return stringSlice(wasm, index.unwrap() orelse return null); |
| | 4763 | } |
| | 4764 | |
| | 4765 | pub fn castToString(wasm: *const Wasm, index: u32) String { |
| | 4766 | assert(index == 0 or wasm.string_bytes.items[index - 1] == 0); |
| | 4767 | return @enumFromInt(index); |
| | 4768 | } |
| | 4769 | |
| | 4770 | fn segmentPtr(wasm: *const Wasm, index: Segment.Index) *Segment { |
| | 4771 | return &wasm.segments.items[@intFromEnum(index)]; |
| | 4772 | } |