| ... | ... | @@ -36,11 +36,16 @@ const Value = @import("../Value.zig"); |
| 36 | 36 | const ZigObject = @import("Wasm/ZigObject.zig"); |
| 37 | 37 | |
| 38 | 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 | 44 | /// Symbol name of the entry function to export |
| 40 | | entry_name: ?[]const u8, |
| 45 | entry_name: OptionalString, |
| 41 | 46 | /// When true, will allow undefined symbols |
| 42 | 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 | 49 | export_symbol_names: []const []const u8, |
| 45 | 50 | /// When defined, sets the start of the data section. |
| 46 | 51 | global_base: ?u64, |
| ... | ... | @@ -63,32 +68,14 @@ objects: std.ArrayListUnmanaged(Object) = .{}, |
| 63 | 68 | /// LLVM uses "env" by default when none is given. This would be a good default for Zig |
| 64 | 69 | /// to support existing code. |
| 65 | 70 | /// TODO: Allow setting this through a flag? |
| 66 | | host_name: []const u8 = "env", |
| 71 | host_name: String, |
| 67 | 72 | /// List of symbols generated by the linker. |
| 68 | 73 | synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .empty, |
| 69 | 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 | 76 | /// List of all atoms. |
| 72 | 77 | managed_atoms: std.ArrayListUnmanaged(Atom) = .empty, |
| 73 | | /// Represents the index into `segments` where the 'code' section |
| 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, |
| 78 | |
| 92 | 79 | /// The count of imported functions. This number will be appended |
| 93 | 80 | /// to the function indexes as their index starts at the lowest non-extern function. |
| 94 | 81 | imported_functions_count: u32 = 0, |
| ... | ... | @@ -104,13 +91,11 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty, |
| 104 | 91 | /// Used for code, data and custom sections. |
| 105 | 92 | segments: std.ArrayListUnmanaged(Segment) = .empty, |
| 106 | 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 | 95 | /// A table of `NamedSegment` which provide meta data |
| 109 | 96 | /// about a data symbol such as its name where the key is |
| 110 | 97 | /// the segment index, which can be found from `data_segments` |
| 111 | | segment_info: std.AutoArrayHashMapUnmanaged(u32, NamedSegment) = .empty, |
| 112 | | /// Deduplicated string table for strings used by symbols, imports and exports. |
| 113 | | string_table: StringTable = .{}, |
| 98 | segment_info: std.AutoArrayHashMapUnmanaged(Segment.Index, NamedSegment) = .empty, |
| 114 | 99 | |
| 115 | 100 | // Output sections |
| 116 | 101 | /// Output type section |
| ... | ... | @@ -158,8 +143,8 @@ function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty, |
| 158 | 143 | /// e.g. when an undefined symbol references a symbol from the archive. |
| 159 | 144 | lazy_archives: std.ArrayListUnmanaged(LazyArchive) = .empty, |
| 160 | 145 | |
| 161 | | /// A map of global names (read: offset into string table) to their symbol location |
| 162 | | globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .empty, |
| 146 | /// A map of global names to their symbol location |
| 147 | globals: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty, |
| 163 | 148 | /// The list of GOT symbols and their location |
| 164 | 149 | got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .empty, |
| 165 | 150 | /// Maps discarded symbols and their positions to the location of the symbol |
| ... | ... | @@ -169,8 +154,7 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .empty, |
| 169 | 154 | /// into the final binary. |
| 170 | 155 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .empty, |
| 171 | 156 | /// Symbols that remain undefined after symbol resolution. |
| 172 | | /// Note: The key represents an offset into the string table, rather than the actual string. |
| 173 | | undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty, |
| 157 | undefs: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty, |
| 174 | 158 | /// Maps a symbol's location to an atom. This can be used to find meta |
| 175 | 159 | /// data of a symbol, such as its size, or its offset to perform a relocation. |
| 176 | 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 | 162 | |
| 179 | 163 | /// `--verbose-link` output. |
| 180 | 164 | /// Initialized on creation, appended to as inputs are added, printed during `flush`. |
| 165 | /// String data is allocated into Compilation arena. |
| 181 | 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 | 262 | /// Index into objects array or the zig object. |
| 184 | 263 | pub const ObjectId = enum(u16) { |
| 185 | 264 | zig_object = std.math.maxInt(u16) - 1, |
| ... | ... | @@ -222,6 +301,26 @@ pub const Segment = struct { |
| 222 | 301 | offset: u32, |
| 223 | 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 | 324 | pub const Flag = enum(u32) { |
| 226 | 325 | WASM_DATA_SEGMENT_IS_PASSIVE = 0x01, |
| 227 | 326 | WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02, |
| ... | ... | @@ -260,26 +359,8 @@ pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol { |
| 260 | 359 | } |
| 261 | 360 | |
| 262 | 361 | /// From a given location, returns the name of the symbol. |
| 263 | | pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) []const u8 { |
| 264 | | if (wasm.discarded.get(loc)) |new_loc| { |
| 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 | | } |
| 362 | pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) [:0]const u8 { |
| 363 | return wasm.stringSlice(wasm.symbolLocSymbol(loc).name); |
| 283 | 364 | } |
| 284 | 365 | |
| 285 | 366 | /// From a given symbol location, returns the final location. |
| ... | ... | @@ -325,75 +406,6 @@ pub const InitFuncLoc = struct { |
| 325 | 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 | 410 | pub fn open( |
| 399 | 411 | arena: Allocator, |
| ... | ... | @@ -451,6 +463,8 @@ pub fn createEmpty( |
| 451 | 463 | .build_id = options.build_id, |
| 452 | 464 | }, |
| 453 | 465 | .name = undefined, |
| 466 | .string_table = .empty, |
| 467 | .string_bytes = .empty, |
| 454 | 468 | .import_table = options.import_table, |
| 455 | 469 | .export_table = options.export_table, |
| 456 | 470 | .import_symbols = options.import_symbols, |
| ... | ... | @@ -459,20 +473,38 @@ pub fn createEmpty( |
| 459 | 473 | .initial_memory = options.initial_memory, |
| 460 | 474 | .max_memory = options.max_memory, |
| 461 | 475 | |
| 462 | | .entry_name = switch (options.entry) { |
| 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 | | }, |
| 476 | .entry_name = undefined, |
| 468 | 477 | .zig_object = null, |
| 469 | 478 | .dump_argv_list = .empty, |
| 479 | .host_name = undefined, |
| 480 | .custom_sections = undefined, |
| 481 | .preloaded_strings = undefined, |
| 470 | 482 | }; |
| 471 | 483 | if (use_llvm and comp.config.have_zcu) { |
| 472 | 484 | wasm.llvm_object = try LlvmObject.create(arena, comp); |
| 473 | 485 | } |
| 474 | 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 | 508 | if (use_lld and (use_llvm or !comp.config.have_zcu)) { |
| 477 | 509 | // LLVM emits the object file (if any); LLD links it into the final product. |
| 478 | 510 | return wasm; |
| ... | ... | @@ -498,22 +530,18 @@ pub fn createEmpty( |
| 498 | 530 | |
| 499 | 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 | 534 | const symbol = wasm.symbolLocSymbol(loc); |
| 503 | 535 | // For object files we will import the stack pointer symbol |
| 504 | 536 | if (output_mode == .Obj) { |
| 505 | 537 | symbol.setUndefined(true); |
| 506 | 538 | symbol.index = @intCast(wasm.imported_globals_count); |
| 507 | 539 | wasm.imported_globals_count += 1; |
| 508 | | try wasm.imports.putNoClobber( |
| 509 | | gpa, |
| 510 | | loc, |
| 511 | | .{ |
| 512 | | .module_name = try wasm.string_table.put(gpa, wasm.host_name), |
| 513 | | .name = symbol.name, |
| 514 | | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, |
| 515 | | }, |
| 516 | | ); |
| 540 | try wasm.imports.putNoClobber(gpa, loc, .{ |
| 541 | .module_name = wasm.host_name, |
| 542 | .name = symbol.name, |
| 543 | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, |
| 544 | }); |
| 517 | 545 | } else { |
| 518 | 546 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| 519 | 547 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| ... | ... | @@ -530,7 +558,7 @@ pub fn createEmpty( |
| 530 | 558 | |
| 531 | 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 | 562 | const symbol = wasm.symbolLocSymbol(loc); |
| 535 | 563 | const table: std.wasm.Table = .{ |
| 536 | 564 | .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable` |
| ... | ... | @@ -541,7 +569,7 @@ pub fn createEmpty( |
| 541 | 569 | symbol.index = @intCast(wasm.imported_tables_count); |
| 542 | 570 | wasm.imported_tables_count += 1; |
| 543 | 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 | 573 | .name = symbol.name, |
| 546 | 574 | .kind = .{ .table = table }, |
| 547 | 575 | }); |
| ... | ... | @@ -558,7 +586,7 @@ pub fn createEmpty( |
| 558 | 586 | |
| 559 | 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 | 590 | const symbol = wasm.symbolLocSymbol(loc); |
| 563 | 591 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 564 | 592 | // we do not know the function index until after we merged all sections. |
| ... | ... | @@ -569,7 +597,7 @@ pub fn createEmpty( |
| 569 | 597 | // shared-memory symbols for TLS support |
| 570 | 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 | 601 | const symbol = wasm.symbolLocSymbol(loc); |
| 574 | 602 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 575 | 603 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| ... | ... | @@ -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 | 612 | const symbol = wasm.symbolLocSymbol(loc); |
| 585 | 613 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 586 | 614 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| ... | ... | @@ -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 | 623 | const symbol = wasm.symbolLocSymbol(loc); |
| 596 | 624 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 597 | 625 | symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| ... | ... | @@ -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 | 634 | const symbol = wasm.symbolLocSymbol(loc); |
| 607 | 635 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 608 | 636 | } |
| ... | ... | @@ -655,13 +683,11 @@ pub fn addOrUpdateImport( |
| 655 | 683 | |
| 656 | 684 | /// For a given name, creates a new global synthetic symbol. |
| 657 | 685 | /// Leaves index undefined and the default flags (0). |
| 658 | | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { |
| 659 | | const gpa = wasm.base.comp.gpa; |
| 660 | | const name_offset = try wasm.string_table.put(gpa, name); |
| 661 | | return wasm.createSyntheticSymbolOffset(name_offset, tag); |
| 686 | fn createSyntheticSymbol(wasm: *Wasm, name: String, tag: Symbol.Tag) !SymbolLoc { |
| 687 | return wasm.createSyntheticSymbolOffset(name, 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 | 691 | const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len); |
| 666 | 692 | const loc: SymbolLoc = .{ .index = sym_index, .file = .none }; |
| 667 | 693 | const gpa = wasm.base.comp.gpa; |
| ... | ... | @@ -803,16 +829,6 @@ fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Sy |
| 803 | 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 | 832 | fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func { |
| 817 | 833 | const obj = wasm.objectById(object_id) orelse { |
| 818 | 834 | const zo = wasm.zig_object.?; |
| ... | ... | @@ -850,13 +866,6 @@ fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Ind |
| 850 | 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 | 869 | /// Returns the object element pointer, or null if it is the ZigObject. |
| 861 | 870 | fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object { |
| 862 | 871 | if (object_id == .zig_object) return null; |
| ... | ... | @@ -876,27 +885,25 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 876 | 885 | .file = object_id.toOptional(), |
| 877 | 886 | .index = sym_index, |
| 878 | 887 | }; |
| 879 | | const sym_name = objectString(wasm, object_id, symbol.name); |
| 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); |
| 888 | if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue; |
| 884 | 889 | |
| 885 | 890 | if (symbol.isLocal()) { |
| 886 | 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 | 896 | try wasm.resolved_symbols.putNoClobber(gpa, location, {}); |
| 890 | 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 | 901 | if (!maybe_existing.found_existing) { |
| 895 | 902 | maybe_existing.value_ptr.* = location; |
| 896 | 903 | try wasm.resolved_symbols.putNoClobber(gpa, location, {}); |
| 897 | 904 | |
| 898 | 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 | 908 | continue; |
| 902 | 909 | } |
| ... | ... | @@ -918,7 +925,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 918 | 925 | } |
| 919 | 926 | // both are defined and weak, we have a symbol collision. |
| 920 | 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 | 929 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 923 | 930 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| 924 | 931 | } |
| ... | ... | @@ -929,7 +936,9 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 929 | 936 | |
| 930 | 937 | if (symbol.tag != existing_sym.tag) { |
| 931 | 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 | 942 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 934 | 943 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| 935 | 944 | } |
| ... | ... | @@ -937,22 +946,18 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 937 | 946 | if (existing_sym.isUndefined() and symbol.isUndefined()) { |
| 938 | 947 | // only verify module/import name for function symbols |
| 939 | 948 | if (symbol.tag == .function) { |
| 940 | | const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| blk: { |
| 941 | | const imp = objectImport(wasm, existing_obj_id, existing_loc.index); |
| 942 | | break :blk objectString(wasm, existing_obj_id, imp.module_name); |
| 943 | | } else blk: { |
| 944 | | const name_index = wasm.imports.get(existing_loc).?.module_name; |
| 945 | | break :blk wasm.string_table.get(name_index); |
| 946 | | }; |
| 949 | const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| |
| 950 | objectImport(wasm, existing_obj_id, existing_loc.index).module_name |
| 951 | else |
| 952 | wasm.imports.get(existing_loc).?.module_name; |
| 947 | 953 | |
| 948 | | const imp = objectImport(wasm, object_id, sym_index); |
| 949 | | const module_name = objectString(wasm, object_id, imp.module_name); |
| 950 | | if (!mem.eql(u8, existing_name, module_name)) { |
| 954 | const module_name = objectImport(wasm, object_id, sym_index).module_name; |
| 955 | if (existing_name != module_name) { |
| 951 | 956 | var err = try diags.addErrorWithNotes(2); |
| 952 | 957 | try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{ |
| 953 | | sym_name, |
| 954 | | existing_name, |
| 955 | | module_name, |
| 958 | wasm.stringSlice(symbol.name), |
| 959 | wasm.stringSlice(existing_name), |
| 960 | wasm.stringSlice(module_name), |
| 956 | 961 | }); |
| 957 | 962 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 958 | 963 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| ... | ... | @@ -969,7 +974,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 969 | 974 | const new_ty = wasm.getGlobalType(location); |
| 970 | 975 | if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) { |
| 971 | 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 | 978 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 974 | 979 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| 975 | 980 | } |
| ... | ... | @@ -980,7 +985,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 980 | 985 | const new_ty = wasm.getFunctionSignature(location); |
| 981 | 986 | if (!existing_ty.eql(new_ty)) { |
| 982 | 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 | 989 | try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty }); |
| 985 | 990 | try err.addNote("first definition in '{'}'", .{existing_file_path}); |
| 986 | 991 | try err.addNote("next definition in '{'}'", .{obj_path}); |
| ... | ... | @@ -996,16 +1001,16 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void { |
| 996 | 1001 | } |
| 997 | 1002 | |
| 998 | 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 | 1005 | log.debug(" old definition in '{'}'", .{existing_file_path}); |
| 1001 | 1006 | log.debug(" new definition in '{'}'", .{obj_path}); |
| 1002 | 1007 | try wasm.discarded.putNoClobber(gpa, existing_loc, location); |
| 1003 | 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 | 1010 | try wasm.resolved_symbols.put(gpa, location, {}); |
| 1006 | 1011 | assert(wasm.resolved_symbols.swapRemove(existing_loc)); |
| 1007 | 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 | 1026 | const sym_name_index = wasm.undefs.keys()[index]; |
| 1022 | 1027 | |
| 1023 | 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 | 1030 | log.debug("Detected symbol '{s}' in archive '{'}', parsing objects..", .{ |
| 1026 | 1031 | sym_name, lazy_archive.path, |
| 1027 | 1032 | }); |
| ... | ... | @@ -1066,13 +1071,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1066 | 1071 | if (!wasm.hasPassiveInitializationSegments()) { |
| 1067 | 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 | 1075 | wasm.symbolLocSymbol(sym_loc).mark(); |
| 1071 | 1076 | |
| 1072 | 1077 | const flag_address: u32 = if (shared_memory) address: { |
| 1073 | 1078 | // when we have passive initialization segments and shared memory |
| 1074 | 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 | 1081 | break :address wasm.symbolLocSymbol(loc).virtual_address; |
| 1077 | 1082 | } else 0; |
| 1078 | 1083 | |
| ... | ... | @@ -1113,31 +1118,30 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1113 | 1118 | try writer.writeByte(std.wasm.opcode(.end)); |
| 1114 | 1119 | } |
| 1115 | 1120 | |
| 1116 | | var it = wasm.data_segments.iterator(); |
| 1117 | | var segment_index: u32 = 0; |
| 1118 | | while (it.next()) |entry| : (segment_index += 1) { |
| 1119 | | const segment: Segment = wasm.segments.items[entry.value_ptr.*]; |
| 1120 | | if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { |
| 1121 | for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |key, value, segment_index_usize| { |
| 1122 | const segment_index: u32 = @intCast(segment_index_usize); |
| 1123 | const segment = wasm.segmentPtr(value); |
| 1124 | if (segment.needsPassiveInitialization(import_memory, key)) { |
| 1121 | 1125 | // For passive BSS segments we can simple issue a memory.fill(0). |
| 1122 | 1126 | // For non-BSS segments we do a memory.init. Both these |
| 1123 | 1127 | // instructions take as their first argument the destination |
| 1124 | 1128 | // address. |
| 1125 | 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 | 1132 | // When we initialize the TLS segment we also set the `__tls_base` |
| 1129 | 1133 | // global. This allows the runtime to use this static copy of the |
| 1130 | 1134 | // TLS data for the first/main thread. |
| 1131 | 1135 | try writeI32Const(writer, segment.offset); |
| 1132 | 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 | 1138 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index); |
| 1135 | 1139 | } |
| 1136 | 1140 | |
| 1137 | 1141 | try writeI32Const(writer, 0); |
| 1138 | 1142 | try writeI32Const(writer, segment.size); |
| 1139 | 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 | 1145 | // fill bss segment with zeroes |
| 1142 | 1146 | try leb.writeUleb128(writer, std.wasm.miscOpcode(.memory_fill)); |
| 1143 | 1147 | } else { |
| ... | ... | @@ -1187,11 +1191,9 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1187 | 1191 | try writer.writeByte(std.wasm.opcode(.end)); // end $drop |
| 1188 | 1192 | } |
| 1189 | 1193 | |
| 1190 | | it.reset(); |
| 1191 | | segment_index = 0; |
| 1192 | | while (it.next()) |entry| : (segment_index += 1) { |
| 1193 | | const name = entry.key_ptr.*; |
| 1194 | | const segment: Segment = wasm.segments.items[entry.value_ptr.*]; |
| 1194 | for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |name, value, segment_index_usize| { |
| 1195 | const segment_index: u32 = @intCast(segment_index_usize); |
| 1196 | const segment = wasm.segmentPtr(value); |
| 1195 | 1197 | if (segment.needsPassiveInitialization(import_memory, name) and |
| 1196 | 1198 | !std.mem.eql(u8, name, ".bss")) |
| 1197 | 1199 | { |
| ... | ... | @@ -1211,7 +1213,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 1211 | 1213 | try writer.writeByte(std.wasm.opcode(.end)); |
| 1212 | 1214 | |
| 1213 | 1215 | try wasm.createSyntheticFunction( |
| 1214 | | "__wasm_init_memory", |
| 1216 | wasm.preloaded_strings.__wasm_init_memory, |
| 1215 | 1217 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, |
| 1216 | 1218 | &function_body, |
| 1217 | 1219 | ); |
| ... | ... | @@ -1230,7 +1232,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1230 | 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 | 1236 | wasm.symbolLocSymbol(loc).mark(); |
| 1235 | 1237 | var function_body = std.ArrayList(u8).init(gpa); |
| 1236 | 1238 | defer function_body.deinit(); |
| ... | ... | @@ -1244,7 +1246,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1244 | 1246 | if (sym.tag == .data and sym.isDefined()) { |
| 1245 | 1247 | // get __tls_base |
| 1246 | 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 | 1251 | // add the virtual address of the symbol |
| 1250 | 1252 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| ... | ... | @@ -1260,7 +1262,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { |
| 1260 | 1262 | try writer.writeByte(std.wasm.opcode(.end)); |
| 1261 | 1263 | |
| 1262 | 1264 | try wasm.createSyntheticFunction( |
| 1263 | | "__wasm_apply_global_tls_relocs", |
| 1265 | wasm.preloaded_strings.__wasm_apply_global_tls_relocs, |
| 1264 | 1266 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, |
| 1265 | 1267 | &function_body, |
| 1266 | 1268 | ); |
| ... | ... | @@ -1422,7 +1424,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1422 | 1424 | const gpa = comp.gpa; |
| 1423 | 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 | 1428 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1427 | 1429 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); |
| 1428 | 1430 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); |
| ... | ... | @@ -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 | 1436 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1435 | 1437 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); |
| 1436 | 1438 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); |
| ... | ... | @@ -1439,7 +1441,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1439 | 1441 | } |
| 1440 | 1442 | |
| 1441 | 1443 | if (!shared_memory) { |
| 1442 | | if (wasm.string_table.getOffset("__tls_base")) |name_offset| { |
| 1444 | if (wasm.getExistingString("__tls_base")) |name_offset| { |
| 1443 | 1445 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1444 | 1446 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); |
| 1445 | 1447 | try wasm.discarded.putNoClobber(gpa, kv.value, loc); |
| ... | ... | @@ -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, |
| 1460 | | /// and its location when it is found. |
| 1461 | | pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc { |
| 1462 | | const offset = wasm.string_table.getOffset(name) orelse return null; |
| 1463 | | return wasm.globals.get(offset); |
| 1461 | pub fn findGlobalSymbol(wasm: *const Wasm, name: []const u8) ?SymbolLoc { |
| 1462 | const name_index = wasm.getExistingString(name) orelse return null; |
| 1463 | return wasm.globals.get(name_index); |
| 1464 | 1464 | } |
| 1465 | 1465 | |
| 1466 | 1466 | fn checkUndefinedSymbols(wasm: *const Wasm) !void { |
| ... | ... | @@ -1516,7 +1516,7 @@ pub fn deinit(wasm: *Wasm) void { |
| 1516 | 1516 | for (wasm.lazy_archives.items) |*lazy_archive| lazy_archive.deinit(gpa); |
| 1517 | 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 | 1520 | const atom = wasm.symbol_atom.get(loc).?; |
| 1521 | 1521 | wasm.getAtomPtr(atom).deinit(gpa); |
| 1522 | 1522 | } |
| ... | ... | @@ -1544,6 +1544,7 @@ pub fn deinit(wasm: *Wasm) void { |
| 1544 | 1544 | wasm.init_funcs.deinit(gpa); |
| 1545 | 1545 | wasm.exports.deinit(gpa); |
| 1546 | 1546 | |
| 1547 | wasm.string_bytes.deinit(gpa); |
| 1547 | 1548 | wasm.string_table.deinit(gpa); |
| 1548 | 1549 | wasm.dump_argv_list.deinit(gpa); |
| 1549 | 1550 | } |
| ... | ... | @@ -1649,7 +1650,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1649 | 1650 | /// and then returns the index to it. |
| 1650 | 1651 | pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { |
| 1651 | 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 | 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 | 1723 | } |
| 1722 | 1724 | |
| 1723 | 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 | 1727 | const import = wasm.imports.getPtr(sym_loc).?; |
| 1726 | 1728 | import.kind.table.limits.min = index - 1; // we start at index 1. |
| 1727 | 1729 | } else if (index > 1) { |
| 1728 | 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 | 1732 | const symbol = wasm.symbolLocSymbol(sym_loc); |
| 1731 | 1733 | const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count]; |
| 1732 | 1734 | table.limits = .{ .min = index, .max = index, .flags = 0x1 }; |
| ... | ... | @@ -1735,7 +1737,7 @@ fn mapFunctionTable(wasm: *Wasm) void { |
| 1735 | 1737 | |
| 1736 | 1738 | /// From a given index, append the given `Atom` at the back of the linked list. |
| 1737 | 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 | 1741 | const gpa = wasm.base.comp.gpa; |
| 1740 | 1742 | const atom = wasm.getAtomPtr(atom_index); |
| 1741 | 1743 | if (wasm.atoms.getPtr(index)) |last_index_ptr| { |
| ... | ... | @@ -1752,9 +1754,9 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 1752 | 1754 | |
| 1753 | 1755 | var it = wasm.atoms.iterator(); |
| 1754 | 1756 | while (it.next()) |entry| { |
| 1755 | | const segment = &wasm.segments.items[entry.key_ptr.*]; |
| 1757 | const segment = wasm.segmentPtr(entry.key_ptr.*); |
| 1756 | 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 | 1760 | // Code section is allocated upon writing as they are required to be ordered |
| 1759 | 1761 | // to synchronise with the function section. |
| 1760 | 1762 | continue; |
| ... | ... | @@ -1825,7 +1827,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { |
| 1825 | 1827 | }; |
| 1826 | 1828 | const segment_name = segment_info[symbol.index].outputName(merge_segment); |
| 1827 | 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 | 1832 | // TLS symbols have their virtual address set relative to their own TLS segment, |
| 1831 | 1833 | // rather than the entire Data section. |
| ... | ... | @@ -1839,7 +1841,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { |
| 1839 | 1841 | |
| 1840 | 1842 | fn sortDataSegments(wasm: *Wasm) !void { |
| 1841 | 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 | 1845 | try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count()); |
| 1844 | 1846 | errdefer new_mapping.deinit(gpa); |
| 1845 | 1847 | |
| ... | ... | @@ -1894,9 +1896,9 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 1894 | 1896 | }; |
| 1895 | 1897 | if (ty.params.len != 0) { |
| 1896 | 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 | 1902 | wasm.init_funcs.appendAssumeCapacity(.{ |
| 1901 | 1903 | .index = @enumFromInt(init_func.symbol_index), |
| 1902 | 1904 | .file = @enumFromInt(object_index), |
| ... | ... | @@ -1913,7 +1915,7 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 1913 | 1915 | mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan); |
| 1914 | 1916 | |
| 1915 | 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 | 1919 | try wasm.mark(loc); |
| 1918 | 1920 | } |
| 1919 | 1921 | } |
| ... | ... | @@ -1927,10 +1929,10 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 1927 | 1929 | fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 1928 | 1930 | const gpa = wasm.base.comp.gpa; |
| 1929 | 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 | 1933 | // Make sure to remove it from the resolved symbols so we do not emit |
| 1932 | 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 | 1936 | assert(wasm.resolved_symbols.swapRemove(loc)); |
| 1935 | 1937 | return; |
| 1936 | 1938 | } |
| ... | ... | @@ -1965,7 +1967,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 1965 | 1967 | } |
| 1966 | 1968 | |
| 1967 | 1969 | try wasm.createSyntheticFunction( |
| 1968 | | "__wasm_call_ctors", |
| 1970 | wasm.preloaded_strings.__wasm_call_ctors, |
| 1969 | 1971 | std.wasm.Type{ .params = &.{}, .returns = &.{} }, |
| 1970 | 1972 | &function_body, |
| 1971 | 1973 | ); |
| ... | ... | @@ -1973,12 +1975,12 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void { |
| 1973 | 1975 | |
| 1974 | 1976 | fn createSyntheticFunction( |
| 1975 | 1977 | wasm: *Wasm, |
| 1976 | | symbol_name: []const u8, |
| 1978 | symbol_name: String, |
| 1977 | 1979 | func_ty: std.wasm.Type, |
| 1978 | 1980 | function_body: *std.ArrayList(u8), |
| 1979 | 1981 | ) !void { |
| 1980 | 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 | 1984 | const symbol = wasm.symbolLocSymbol(loc); |
| 1983 | 1985 | if (symbol.isDead()) { |
| 1984 | 1986 | return; |
| ... | ... | @@ -1998,7 +2000,7 @@ fn createSyntheticFunction( |
| 1998 | 2000 | const atom = wasm.getAtomPtr(atom_index); |
| 1999 | 2001 | atom.size = @intCast(function_body.items.len); |
| 2000 | 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 | 2006 | /// Unlike `createSyntheticFunction` this function is to be called by |
| ... | ... | @@ -2016,7 +2018,7 @@ pub fn createFunction( |
| 2016 | 2018 | |
| 2017 | 2019 | /// If required, sets the function index in the `start` section. |
| 2018 | 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 | 2022 | wasm.entry = wasm.symbolLocSymbol(loc).index; |
| 2021 | 2023 | } |
| 2022 | 2024 | } |
| ... | ... | @@ -2029,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2029 | 2031 | if (!shared_memory) return; |
| 2030 | 2032 | |
| 2031 | 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 | 2036 | var function_body = std.ArrayList(u8).init(gpa); |
| 2035 | 2037 | defer function_body.deinit(); |
| ... | ... | @@ -2041,14 +2043,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2041 | 2043 | // If there's a TLS segment, initialize it during runtime using the bulk-memory feature |
| 2042 | 2044 | if (wasm.data_segments.getIndex(".tdata")) |data_index| { |
| 2043 | 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 | 2048 | const param_local: u32 = 0; |
| 2047 | 2049 | |
| 2048 | 2050 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 2049 | 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 | 2054 | try writer.writeByte(std.wasm.opcode(.global_set)); |
| 2053 | 2055 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index); |
| 2054 | 2056 | |
| ... | ... | @@ -2076,7 +2078,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2076 | 2078 | // If we have to perform any TLS relocations, call the corresponding function |
| 2077 | 2079 | // which performs all runtime TLS relocations. This is a synthetic function, |
| 2078 | 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 | 2082 | try writer.writeByte(std.wasm.opcode(.call)); |
| 2081 | 2083 | try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index); |
| 2082 | 2084 | wasm.symbolLocSymbol(loc).mark(); |
| ... | ... | @@ -2085,7 +2087,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2085 | 2087 | try writer.writeByte(std.wasm.opcode(.end)); |
| 2086 | 2088 | |
| 2087 | 2089 | try wasm.createSyntheticFunction( |
| 2088 | | "__wasm_init_tls", |
| 2090 | wasm.preloaded_strings.__wasm_init_tls, |
| 2089 | 2091 | std.wasm.Type{ .params = &.{.i32}, .returns = &.{} }, |
| 2090 | 2092 | &function_body, |
| 2091 | 2093 | ); |
| ... | ... | @@ -2101,21 +2103,18 @@ fn setupImports(wasm: *Wasm) !void { |
| 2101 | 2103 | }; |
| 2102 | 2104 | |
| 2103 | 2105 | const symbol = wasm.symbolLocSymbol(symbol_loc); |
| 2104 | | if (symbol.isDead() or |
| 2105 | | !symbol.requiresImport() or |
| 2106 | | std.mem.eql(u8, wasm.symbolLocName(symbol_loc), "__indirect_function_table")) |
| 2107 | | { |
| 2108 | | continue; |
| 2109 | | } |
| 2106 | if (symbol.isDead()) continue; |
| 2107 | if (!symbol.requiresImport()) continue; |
| 2108 | if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue; |
| 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 | 2111 | const import = objectImport(wasm, object_id, symbol_loc.index); |
| 2113 | 2112 | |
| 2114 | 2113 | // We copy the import to a new import to ensure the names contain references |
| 2115 | 2114 | // to the internal string table, rather than of the object file. |
| 2116 | 2115 | const new_imp: Import = .{ |
| 2117 | | .module_name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.module_name)), |
| 2118 | | .name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.name)), |
| 2116 | .module_name = import.module_name, |
| 2117 | .name = import.name, |
| 2119 | 2118 | .kind = import.kind, |
| 2120 | 2119 | }; |
| 2121 | 2120 | // TODO: De-duplicate imports when they contain the same names and type |
| ... | ... | @@ -2283,7 +2282,8 @@ fn checkExportNames(wasm: *Wasm) !void { |
| 2283 | 2282 | var failed_exports = false; |
| 2284 | 2283 | |
| 2285 | 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 | 2287 | var err = try diags.addErrorWithNotes(0); |
| 2288 | 2288 | try err.addMsg("could not export '{s}', symbol not found", .{exp_name}); |
| 2289 | 2289 | failed_exports = true; |
| ... | ... | @@ -2310,11 +2310,6 @@ fn setupExports(wasm: *Wasm) !void { |
| 2310 | 2310 | const symbol = wasm.symbolLocSymbol(sym_loc); |
| 2311 | 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 | 2313 | const exp: Export = if (symbol.tag == .data) exp: { |
| 2319 | 2314 | const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len)); |
| 2320 | 2315 | try wasm.wasm_globals.append(gpa, .{ |
| ... | ... | @@ -2322,18 +2317,18 @@ fn setupExports(wasm: *Wasm) !void { |
| 2322 | 2317 | .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) }, |
| 2323 | 2318 | }); |
| 2324 | 2319 | break :exp .{ |
| 2325 | | .name = export_name, |
| 2320 | .name = symbol.name, |
| 2326 | 2321 | .kind = .global, |
| 2327 | 2322 | .index = global_index, |
| 2328 | 2323 | }; |
| 2329 | 2324 | } else .{ |
| 2330 | | .name = export_name, |
| 2325 | .name = symbol.name, |
| 2331 | 2326 | .kind = symbol.tag.externalType(), |
| 2332 | 2327 | .index = symbol.index, |
| 2333 | 2328 | }; |
| 2334 | 2329 | log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ |
| 2335 | | sym_name, |
| 2336 | | wasm.string_table.get(exp.name), |
| 2330 | wasm.stringSlice(symbol.name), |
| 2331 | wasm.stringSlice(exp.name), |
| 2337 | 2332 | exp.index, |
| 2338 | 2333 | }); |
| 2339 | 2334 | try wasm.exports.append(gpa, exp); |
| ... | ... | @@ -2346,20 +2341,18 @@ fn setupStart(wasm: *Wasm) !void { |
| 2346 | 2341 | const comp = wasm.base.comp; |
| 2347 | 2342 | const diags = &wasm.base.comp.link_diags; |
| 2348 | 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 { |
| 2352 | | var err = try diags.addErrorWithNotes(0); |
| 2353 | | try err.addMsg("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name}); |
| 2354 | | return error.FlushFailure; |
| 2346 | const symbol_loc = wasm.globals.get(entry_name) orelse { |
| 2347 | var err = try diags.addErrorWithNotes(1); |
| 2348 | try err.addMsg("entry symbol '{s}' missing", .{wasm.stringSlice(entry_name)}); |
| 2349 | try err.addNote("'-fno-entry' suppresses this error", .{}); |
| 2350 | return error.LinkFailure; |
| 2355 | 2351 | }; |
| 2356 | 2352 | |
| 2357 | 2353 | const symbol = wasm.symbolLocSymbol(symbol_loc); |
| 2358 | | if (symbol.tag != .function) { |
| 2359 | | var err = try diags.addErrorWithNotes(0); |
| 2360 | | try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name}); |
| 2361 | | return error.FlushFailure; |
| 2362 | | } |
| 2354 | if (symbol.tag != .function) |
| 2355 | return diags.fail("entry symbol '{s}' is not a function", .{wasm.stringSlice(entry_name)}); |
| 2363 | 2356 | |
| 2364 | 2357 | // Ensure the symbol is exported so host environment can access it |
| 2365 | 2358 | if (comp.config.output_mode != .Obj) { |
| ... | ... | @@ -2387,7 +2380,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2387 | 2380 | |
| 2388 | 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 | 2384 | const sym = wasm.symbolLocSymbol(loc); |
| 2392 | 2385 | break :index sym.index - wasm.imported_globals_count; |
| 2393 | 2386 | } else null; |
| ... | ... | @@ -2404,20 +2397,20 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2404 | 2397 | var offset: u32 = @as(u32, @intCast(memory_ptr)); |
| 2405 | 2398 | var data_seg_it = wasm.data_segments.iterator(); |
| 2406 | 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 | 2401 | memory_ptr = segment.alignment.forward(memory_ptr); |
| 2409 | 2402 | |
| 2410 | 2403 | // set TLS-related symbols |
| 2411 | 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 | 2406 | const sym = wasm.symbolLocSymbol(loc); |
| 2414 | 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 | 2410 | const sym = wasm.symbolLocSymbol(loc); |
| 2418 | 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 | 2414 | const sym = wasm.symbolLocSymbol(loc); |
| 2422 | 2415 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory) |
| 2423 | 2416 | @as(i32, 0) |
| ... | ... | @@ -2435,7 +2428,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2435 | 2428 | if (shared_memory and wasm.hasPassiveInitializationSegments()) { |
| 2436 | 2429 | // align to pointer size |
| 2437 | 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 | 2432 | const sym = wasm.symbolLocSymbol(loc); |
| 2440 | 2433 | sym.mark(); |
| 2441 | 2434 | sym.virtual_address = @as(u32, @intCast(memory_ptr)); |
| ... | ... | @@ -2452,7 +2445,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2452 | 2445 | |
| 2453 | 2446 | // One of the linked object files has a reference to the __heap_base symbol. |
| 2454 | 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 | 2449 | const symbol = wasm.symbolLocSymbol(loc); |
| 2457 | 2450 | symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr)); |
| 2458 | 2451 | } |
| ... | ... | @@ -2482,7 +2475,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2482 | 2475 | wasm.memories.limits.min = @as(u32, @intCast(memory_ptr / page_size)); |
| 2483 | 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 | 2479 | const symbol = wasm.symbolLocSymbol(loc); |
| 2487 | 2480 | symbol.virtual_address = @as(u32, @intCast(memory_ptr)); |
| 2488 | 2481 | } |
| ... | ... | @@ -2512,12 +2505,12 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2512 | 2505 | /// From a given object's index and the index of the segment, returns the corresponding |
| 2513 | 2506 | /// index of the segment within the final data section. When the segment does not yet |
| 2514 | 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 | 2509 | const comp = wasm.base.comp; |
| 2517 | 2510 | const gpa = comp.gpa; |
| 2518 | 2511 | const diags = &wasm.base.comp.link_diags; |
| 2519 | 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 | 2514 | const shared_memory = comp.config.shared_memory; |
| 2522 | 2515 | |
| 2523 | 2516 | switch (symbol.tag) { |
| ... | ... | @@ -2545,66 +2538,27 @@ pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol |
| 2545 | 2538 | return index; |
| 2546 | 2539 | } else return result.value_ptr.*; |
| 2547 | 2540 | }, |
| 2548 | | .function => return wasm.code_section_index orelse blk: { |
| 2549 | | wasm.code_section_index = index; |
| 2541 | .function => return wasm.code_section_index.unwrap() orelse blk: { |
| 2542 | wasm.code_section_index = index.toOptional(); |
| 2550 | 2543 | try wasm.appendDummySegment(); |
| 2551 | 2544 | break :blk index; |
| 2552 | 2545 | }, |
| 2553 | 2546 | .section => { |
| 2554 | | const section_name = objectSymbolName(wasm, object_id, symbol_index); |
| 2555 | | if (mem.eql(u8, section_name, ".debug_info")) { |
| 2556 | | return wasm.debug_info_index orelse blk: { |
| 2557 | | wasm.debug_info_index = index; |
| 2558 | | try wasm.appendDummySegment(); |
| 2559 | | break :blk index; |
| 2560 | | }; |
| 2561 | | } else if (mem.eql(u8, section_name, ".debug_line")) { |
| 2562 | | return wasm.debug_line_index orelse blk: { |
| 2563 | | wasm.debug_line_index = index; |
| 2564 | | try wasm.appendDummySegment(); |
| 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 | | }; |
| 2547 | const section_name = wasm.objectSymbol(object_id, symbol_index).name; |
| 2548 | |
| 2549 | inline for (@typeInfo(CustomSections).@"struct".fields) |field| { |
| 2550 | if (@field(wasm.custom_sections, field.name).name == section_name) { |
| 2551 | const field_ptr = &@field(wasm.custom_sections, field.name).index; |
| 2552 | return field_ptr.unwrap() orelse { |
| 2553 | field_ptr.* = index.toOptional(); |
| 2554 | try wasm.appendDummySegment(); |
| 2555 | return index; |
| 2556 | }; |
| 2557 | } |
| 2603 | 2558 | } else { |
| 2604 | | var err = try diags.addErrorWithNotes(1); |
| 2605 | | try err.addMsg("found unknown section '{s}'", .{section_name}); |
| 2606 | | try err.addNote("defined in '{'}'", .{objectPath(wasm, object_id)}); |
| 2607 | | return error.UnexpectedValue; |
| 2559 | return diags.failParse(objectPath(wasm, object_id), "unknown section: {s}", .{ |
| 2560 | wasm.stringSlice(section_name), |
| 2561 | }); |
| 2608 | 2562 | } |
| 2609 | 2563 | }, |
| 2610 | 2564 | else => unreachable, |
| ... | ... | @@ -2803,10 +2757,9 @@ fn writeToFile( |
| 2803 | 2757 | } |
| 2804 | 2758 | |
| 2805 | 2759 | if (import_memory) { |
| 2806 | | const mem_name = if (is_obj) "__linear_memory" else "memory"; |
| 2807 | 2760 | const mem_imp: Import = .{ |
| 2808 | | .module_name = try wasm.string_table.put(gpa, wasm.host_name), |
| 2809 | | .name = try wasm.string_table.put(gpa, mem_name), |
| 2761 | .module_name = wasm.host_name, |
| 2762 | .name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory, |
| 2810 | 2763 | .kind = .{ .memory = wasm.memories.limits }, |
| 2811 | 2764 | }; |
| 2812 | 2765 | try wasm.emitImport(binary_writer, mem_imp); |
| ... | ... | @@ -2898,7 +2851,7 @@ fn writeToFile( |
| 2898 | 2851 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2899 | 2852 | |
| 2900 | 2853 | for (wasm.exports.items) |exp| { |
| 2901 | | const name = wasm.string_table.get(exp.name); |
| 2854 | const name = wasm.stringSlice(exp.name); |
| 2902 | 2855 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); |
| 2903 | 2856 | try binary_writer.writeAll(name); |
| 2904 | 2857 | try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind)); |
| ... | ... | @@ -2937,7 +2890,7 @@ fn writeToFile( |
| 2937 | 2890 | if (wasm.function_table.count() > 0) { |
| 2938 | 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 | 2894 | const table_sym = wasm.symbolLocSymbol(table_loc); |
| 2942 | 2895 | |
| 2943 | 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 | 2935 | } |
| 2983 | 2936 | |
| 2984 | 2937 | // Code section |
| 2985 | | if (wasm.code_section_index != null) { |
| 2938 | if (wasm.code_section_index != .none) { |
| 2986 | 2939 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2987 | 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 | 2975 | // want to guarantee the data is zero initialized |
| 3023 | 2976 | if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue; |
| 3024 | 2977 | const segment_index = entry.value_ptr.*; |
| 3025 | | const segment = wasm.segments.items[segment_index]; |
| 2978 | const segment = wasm.segmentPtr(segment_index); |
| 3026 | 2979 | if (segment.size == 0) continue; // do not emit empty segments |
| 3027 | 2980 | segment_count += 1; |
| 3028 | 2981 | var atom_index = wasm.atoms.get(segment_index).?; |
| ... | ... | @@ -3133,24 +3086,8 @@ fn writeToFile( |
| 3133 | 3086 | var debug_bytes = std.ArrayList(u8).init(gpa); |
| 3134 | 3087 | defer debug_bytes.deinit(); |
| 3135 | 3088 | |
| 3136 | | const DebugSection = struct { |
| 3137 | | name: []const u8, |
| 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| { |
| 3089 | inline for (@typeInfo(CustomSections).@"struct".fields) |field| { |
| 3090 | if (@field(wasm.custom_sections, field.name).index.unwrap()) |index| { |
| 3154 | 3091 | var atom = wasm.getAtomPtr(wasm.atoms.get(index).?); |
| 3155 | 3092 | while (true) { |
| 3156 | 3093 | atom.resolveRelocs(wasm); |
| ... | ... | @@ -3158,7 +3095,7 @@ fn writeToFile( |
| 3158 | 3095 | if (atom.prev == .null) break; |
| 3159 | 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 | 3099 | debug_bytes.clearRetainingCapacity(); |
| 3163 | 3100 | } |
| 3164 | 3101 | } |
| ... | ... | @@ -3430,11 +3367,11 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { |
| 3430 | 3367 | } |
| 3431 | 3368 | |
| 3432 | 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 | 3371 | try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len))); |
| 3435 | 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 | 3375 | try leb.writeUleb128(writer, @as(u32, @intCast(name.len))); |
| 3439 | 3376 | try writer.writeAll(name); |
| 3440 | 3377 | |
| ... | ... | @@ -3515,7 +3452,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: |
| 3515 | 3452 | } |
| 3516 | 3453 | try man.addOptionalFile(module_obj_path); |
| 3517 | 3454 | try man.addOptionalFilePath(compiler_rt_path); |
| 3518 | | man.hash.addOptionalBytes(wasm.entry_name); |
| 3455 | man.hash.addOptionalBytes(wasm.optionalStringSlice(wasm.entry_name)); |
| 3519 | 3456 | man.hash.add(wasm.base.stack_size); |
| 3520 | 3457 | man.hash.add(wasm.base.build_id); |
| 3521 | 3458 | man.hash.add(import_memory); |
| ... | ... | @@ -3664,7 +3601,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: |
| 3664 | 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 | 3605 | try argv.appendSlice(&.{ "--entry", entry_name }); |
| 3669 | 3606 | } else { |
| 3670 | 3607 | try argv.append("--no-entry"); |
| ... | ... | @@ -4009,7 +3946,7 @@ fn emitCodeRelocations( |
| 4009 | 3946 | section_index: u32, |
| 4010 | 3947 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), |
| 4011 | 3948 | ) !void { |
| 4012 | | const code_index = wasm.code_section_index orelse return; |
| 3949 | const code_index = wasm.code_section_index.unwrap() orelse return; |
| 4013 | 3950 | const writer = binary_bytes.writer(); |
| 4014 | 3951 | const header_offset = try reserveCustomSectionHeader(binary_bytes); |
| 4015 | 3952 | |
| ... | ... | @@ -4106,7 +4043,7 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool { |
| 4106 | 4043 | |
| 4107 | 4044 | var it = wasm.data_segments.iterator(); |
| 4108 | 4045 | while (it.next()) |entry| { |
| 4109 | | const segment: Segment = wasm.segments.items[entry.value_ptr.*]; |
| 4046 | const segment = wasm.segmentPtr(entry.value_ptr.*); |
| 4110 | 4047 | if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { |
| 4111 | 4048 | return true; |
| 4112 | 4049 | } |
| ... | ... | @@ -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 | 4157 | return switch (wasi_exec_model) { |
| 4218 | | .reactor => "_initialize", |
| 4219 | | .command => "_start", |
| 4158 | .reactor => preloaded_strings._initialize, |
| 4159 | .command => preloaded_strings._start, |
| 4220 | 4160 | }; |
| 4221 | 4161 | } |
| 4222 | 4162 | |
| ... | ... | @@ -4352,7 +4292,7 @@ pub const Atom = struct { |
| 4352 | 4292 | symbol.tag != .section and |
| 4353 | 4293 | symbol.isDead()) |
| 4354 | 4294 | { |
| 4355 | | const val = atom.thombstone(wasm) orelse relocation.addend; |
| 4295 | const val = atom.tombstone(wasm) orelse relocation.addend; |
| 4356 | 4296 | return @bitCast(val); |
| 4357 | 4297 | } |
| 4358 | 4298 | switch (relocation.relocation_type) { |
| ... | ... | @@ -4394,7 +4334,7 @@ pub const Atom = struct { |
| 4394 | 4334 | }, |
| 4395 | 4335 | .R_WASM_FUNCTION_OFFSET_I32 => { |
| 4396 | 4336 | if (symbol.isUndefined()) { |
| 4397 | | const val = atom.thombstone(wasm) orelse relocation.addend; |
| 4337 | const val = atom.tombstone(wasm) orelse relocation.addend; |
| 4398 | 4338 | return @bitCast(val); |
| 4399 | 4339 | } |
| 4400 | 4340 | const target_atom_index = wasm.symbol_atom.get(target_loc).?; |
| ... | ... | @@ -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 | 4355 | /// This defines whether we want a specific value when a section is dead. |
| 4416 | | fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 { |
| 4417 | | const atom_name = wasm.symbolLocName(atom.symbolLoc()); |
| 4418 | | if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) { |
| 4356 | fn tombstone(atom: Atom, wasm: *const Wasm) ?i64 { |
| 4357 | const atom_name = wasm.symbolLocSymbol(atom.symbolLoc()).name; |
| 4358 | if (atom_name == wasm.custom_sections.@".debug_ranges".name or |
| 4359 | atom_name == wasm.custom_sections.@".debug_loc".name) |
| 4360 | { |
| 4419 | 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 | 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 | 4452 | /// of the import using offsets into a string table, rather than the slices itself. |
| 4510 | 4453 | /// This saves us (potentially) 24 bytes per import on 64bit machines. |
| 4511 | 4454 | pub const Import = struct { |
| 4512 | | module_name: u32, |
| 4513 | | name: u32, |
| 4455 | module_name: String, |
| 4456 | name: String, |
| 4514 | 4457 | kind: std.wasm.Import.Kind, |
| 4515 | 4458 | }; |
| 4516 | 4459 | |
| ... | ... | @@ -4519,7 +4462,7 @@ pub const Import = struct { |
| 4519 | 4462 | /// of the export using offsets into a string table, rather than the slice itself. |
| 4520 | 4463 | /// This saves us (potentially) 12 bytes per export on 64bit machines. |
| 4521 | 4464 | pub const Export = struct { |
| 4522 | | name: u32, |
| 4465 | name: String, |
| 4523 | 4466 | index: u32, |
| 4524 | 4467 | kind: std.wasm.ExternalKind, |
| 4525 | 4468 | }; |
| ... | ... | @@ -4719,7 +4662,7 @@ fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.In |
| 4719 | 4662 | atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]); |
| 4720 | 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 | 4666 | if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned |
| 4724 | 4667 | segment.alignment = segment.alignment.max(atom.alignment); |
| 4725 | 4668 | } |
| ... | ... | @@ -4782,3 +4725,48 @@ fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize { |
| 4782 | 4725 | } |
| 4783 | 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 | } |