| ... | @@ -49,7 +49,7 @@ input_sections: std.ArrayList(Node.InputSection), | ... | @@ -49,7 +49,7 @@ input_sections: std.ArrayList(Node.InputSection), |
| 49 | input_section_pending_index: u32, | 49 | input_section_pending_index: u32, |
| 50 | inputs_complete: bool, | 50 | inputs_complete: bool, |
| 51 | exports_complete: bool, | 51 | exports_complete: bool, |
| 52 | special_symbols_complete: bool, | 52 | pending_special_symbol: SpecialSymbol, |
| 53 | strings: std.HashMapUnmanaged( | 53 | strings: std.HashMapUnmanaged( |
| 54 | u32, | 54 | u32, |
| 55 | void, | 55 | void, |
| ... | @@ -790,6 +790,7 @@ pub const ImportTable = struct { | ... | @@ -790,6 +790,7 @@ pub const ImportTable = struct { |
| 790 | }; | 790 | }; |
| 791 | | 791 | |
| 792 | pub const String = enum(u32) { | 792 | pub const String = enum(u32) { |
| | 793 | // TODO: Re-order |
| 793 | @".data" = 0, | 794 | @".data" = 0, |
| 794 | @".idata" = 6, | 795 | @".idata" = 6, |
| 795 | @".rdata" = 13, | 796 | @".rdata" = 13, |
| ... | @@ -802,6 +803,7 @@ pub const String = enum(u32) { | ... | @@ -802,6 +803,7 @@ pub const String = enum(u32) { |
| 802 | @".dtors$ZZZ" = 64, | 803 | @".dtors$ZZZ" = 64, |
| 803 | @".bss" = 75, | 804 | @".bss" = 75, |
| 804 | @".fptable" = 80, | 805 | @".fptable" = 80, |
| | 806 | @".tls" = 89, |
| 805 | _, | 807 | _, |
| 806 | | 808 | |
| 807 | pub const Optional = enum(u32) { | 809 | pub const Optional = enum(u32) { |
| ... | @@ -817,6 +819,7 @@ pub const String = enum(u32) { | ... | @@ -817,6 +819,7 @@ pub const String = enum(u32) { |
| 817 | @".dtors$ZZZ" = @intFromEnum(String.@".dtors$ZZZ"), | 819 | @".dtors$ZZZ" = @intFromEnum(String.@".dtors$ZZZ"), |
| 818 | @".bss" = @intFromEnum(String.@".bss"), | 820 | @".bss" = @intFromEnum(String.@".bss"), |
| 819 | @".fptable" = @intFromEnum(String.@".fptable"), | 821 | @".fptable" = @intFromEnum(String.@".fptable"), |
| | 822 | @".tls" = @intFromEnum(String.@".tls"), |
| 820 | none = std.math.maxInt(u32), | 823 | none = std.math.maxInt(u32), |
| 821 | _, | 824 | _, |
| 822 | | 825 | |
| ... | @@ -892,6 +895,12 @@ pub const WeakExternalStrat = enum(u2) { | ... | @@ -892,6 +895,12 @@ pub const WeakExternalStrat = enum(u2) { |
| 892 | } | 895 | } |
| 893 | }; | 896 | }; |
| 894 | | 897 | |
| | 898 | const SpecialSymbol = enum { |
| | 899 | entry, |
| | 900 | tls, |
| | 901 | none, |
| | 902 | }; |
| | 903 | |
| 895 | pub const Symbol = struct { | 904 | pub const Symbol = struct { |
| 896 | ni: MappedFile.Node.Index, | 905 | ni: MappedFile.Node.Index, |
| 897 | rva: u32, | 906 | rva: u32, |
| ... | @@ -1538,7 +1547,7 @@ fn create( | ... | @@ -1538,7 +1547,7 @@ fn create( |
| 1538 | .input_section_pending_index = 0, | 1547 | .input_section_pending_index = 0, |
| 1539 | .inputs_complete = false, | 1548 | .inputs_complete = false, |
| 1540 | .exports_complete = false, | 1549 | .exports_complete = false, |
| 1541 | .special_symbols_complete = false, | 1550 | .pending_special_symbol = .entry, |
| 1542 | .strings = .empty, | 1551 | .strings = .empty, |
| 1543 | .string_bytes = .empty, | 1552 | .string_bytes = .empty, |
| 1544 | .section_table = .empty, | 1553 | .section_table = .empty, |
| ... | @@ -1718,7 +1727,7 @@ fn initHeaders( | ... | @@ -1718,7 +1727,7 @@ fn initHeaders( |
| 1718 | // TLS section | 1727 | // TLS section |
| 1719 | if (comp.config.any_non_single_threaded) { | 1728 | if (comp.config.any_non_single_threaded) { |
| 1720 | if (!is_image) expected_nodes_len += 1; | 1729 | if (!is_image) expected_nodes_len += 1; |
| 1721 | expected_nodes_len += 2; | 1730 | expected_nodes_len += 1; |
| 1722 | } | 1731 | } |
| 1723 | } | 1732 | } |
| 1724 | defer assert(coff.nodes.len == expected_nodes_len); | 1733 | defer assert(coff.nodes.len == expected_nodes_len); |
| ... | @@ -2130,10 +2139,11 @@ fn initHeaders( | ... | @@ -2130,10 +2139,11 @@ fn initHeaders( |
| 2130 | }); | 2139 | }); |
| 2131 | | 2140 | |
| 2132 | // While tls variables allocated at runtime are writable, the template itself is not. | 2141 | // While tls variables allocated at runtime are writable, the template itself is not. |
| 2133 | // In images, this call triggers the creation of a .tls pseudo section in .rdata. | 2142 | // In images, the template is in a .tls pseudo section in .rdata. |
| 2134 | // In objects / archives, this section is part of the above .tls$ section. | 2143 | // In objects / archives, this section is part of the above .tls$ section. The suffix |
| 2135 | _ = try coff.objectSectionMapIndex( | 2144 | // is maintained so merging can occur with other input tls symbols when linked later. |
| 2136 | .@".tls$", | 2145 | _ = try coff.pseudoSectionMapIndex( |
| | 2146 | if (is_image) .@".tls" else .@".tls$", |
| 2137 | coff.mf.flags.block_size, | 2147 | coff.mf.flags.block_size, |
| 2138 | .{ .read = true, .write = !is_image, .initialized = true }, | 2148 | .{ .read = true, .write = !is_image, .initialized = true }, |
| 2139 | ); | 2149 | ); |
| ... | @@ -5622,15 +5632,15 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ... | @@ -5622,15 +5632,15 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5622 | }) coff.late_globals_pending_index += 1; | 5632 | }) coff.late_globals_pending_index += 1; |
| 5623 | break :task; | 5633 | break :task; |
| 5624 | } | 5634 | } |
| 5625 | if (coff.exports_complete and !coff.special_symbols_complete) { | 5635 | if (coff.exports_complete and coff.pending_special_symbol != .none) { |
| 5626 | coff.special_symbols_complete = true; | 5636 | coff.pending_special_symbol = coff.flushSpecialSymbol(coff.pending_special_symbol) catch |err| |
| 5627 | coff.flushSpecialSymbols() catch |err| switch (err) { | 5637 | switch (err) { |
| 5628 | error.OutOfMemory => |e| return e, | 5638 | error.OutOfMemory => |e| return e, |
| 5629 | else => |e| return comp.link_diags.fail( | 5639 | else => |e| return comp.link_diags.fail( |
| 5630 | "linker failed to flush special symbols: {t}", | 5640 | "linker failed to flush special symbols: {t}", |
| 5631 | .{e}, | 5641 | .{e}, |
| 5632 | ), | 5642 | ), |
| 5633 | }; | 5643 | }; |
| 5634 | break :task; | 5644 | break :task; |
| 5635 | } | 5645 | } |
| 5636 | var lazy_it = coff.lazy.iterator(); | 5646 | var lazy_it = coff.lazy.iterator(); |
| ... | @@ -5773,7 +5783,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ... | @@ -5773,7 +5783,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5773 | if (coff.inputs_complete and coff.globals.count() > coff.global_pending_index) return true; | 5783 | if (coff.inputs_complete and coff.globals.count() > coff.global_pending_index) return true; |
| 5774 | assert(!coff.exports_complete or coff.inputs_complete); | 5784 | assert(!coff.exports_complete or coff.inputs_complete); |
| 5775 | if (coff.exports_complete and coff.late_globals.items.len > coff.late_globals_pending_index) return true; | 5785 | if (coff.exports_complete and coff.late_globals.items.len > coff.late_globals_pending_index) return true; |
| 5776 | if (coff.exports_complete and !coff.special_symbols_complete) return true; | 5786 | if (coff.exports_complete and coff.pending_special_symbol != .none) return true; |
| 5777 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | 5787 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 5778 | if (coff.symbol_table.pending.count() > 0) return true; | 5788 | if (coff.symbol_table.pending.count() > 0) return true; |
| 5779 | if (coff.input_sections.items.len > coff.input_section_pending_index) return true; | 5789 | if (coff.input_sections.items.len > coff.input_section_pending_index) return true; |
| ... | @@ -6318,103 +6328,116 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -6318,103 +6328,116 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6318 | return true; | 6328 | return true; |
| 6319 | } | 6329 | } |
| 6320 | | 6330 | |
| 6321 | fn flushSpecialSymbols(coff: *Coff) !void { | 6331 | fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol { |
| 6322 | const comp = coff.base.comp; | 6332 | const comp = coff.base.comp; |
| 6323 | const gpa = comp.gpa; | 6333 | const gpa = comp.gpa; |
| 6324 | const machine = coff.targetLoad(&coff.headerPtr().machine); | 6334 | const machine = coff.targetLoad(&coff.headerPtr().machine); |
| 6325 | | 6335 | |
| 6326 | if (coff.isImage()) { | 6336 | if (!coff.isImage()) return .none; |
| 6327 | // TODO: Use explicitly specified entry if set, add err if not found | 6337 | return next: switch (pending) { |
| 6328 | const entries: []const struct { ?[]const u8, []const u8 } = if (coff.isExe()) | 6338 | .entry => { |
| 6329 | if (comp.config.link_libc) switch (coff.optionalHeaderField(.subsystem)) { | 6339 | // TODO: Use explicitly specified entry if set, add err if not found |
| 6330 | .WINDOWS_CUI => &.{ | 6340 | const entries: []const struct { ?[]const u8, []const u8 } = if (coff.isExe()) |
| 6331 | .{ "main", "mainCRTStartup" }, | 6341 | if (comp.config.link_libc) switch (coff.optionalHeaderField(.subsystem)) { |
| 6332 | .{ "wmain", "wmainCRTStartup" }, | 6342 | .WINDOWS_CUI => &.{ |
| 6333 | }, | 6343 | .{ "main", "mainCRTStartup" }, |
| 6334 | .WINDOWS_GUI => &.{ | 6344 | .{ "wmain", "wmainCRTStartup" }, |
| 6335 | .{ "WinMain", "WinMainCRTStartup" }, | 6345 | }, |
| 6336 | .{ "wWinMain", "wWinMainCRTStartup" }, | 6346 | .WINDOWS_GUI => &.{ |
| 6337 | }, | 6347 | .{ "WinMain", "WinMainCRTStartup" }, |
| 6338 | else => unreachable, | 6348 | .{ "wWinMain", "wWinMainCRTStartup" }, |
| 6339 | } else &.{ | 6349 | }, |
| 6340 | .{ "wWinMainCRTStartup", "wWinMainCRTStartup" }, | 6350 | else => unreachable, |
| 6341 | } | 6351 | } else &.{ |
| 6342 | else | 6352 | .{ "wWinMainCRTStartup", "wWinMainCRTStartup" }, |
| 6343 | &.{.{ null, "_DllMainCRTStartup" }}; | 6353 | } |
| | 6354 | else |
| | 6355 | &.{.{ null, "_DllMainCRTStartup" }}; |
| 6344 | | 6356 | |
| 6345 | const entry_si = for (entries) |entry| { | 6357 | const entry_si = for (entries) |entry| { |
| 6346 | if (entry[0]) |required_name| | 6358 | if (entry[0]) |required_name| |
| 6347 | if (coff.getDefinedGlobal(required_name) == .null) continue; | 6359 | if (coff.getDefinedGlobal(required_name) == .null) continue; |
| 6348 | | 6360 | |
| 6349 | break try coff.globalSymbol(.{ .name = entry[1], .type = .code }); | 6361 | break try coff.globalSymbol(.{ .name = entry[1], .type = .code }); |
| 6350 | } else .null; | 6362 | } else .null; |
| 6351 | | 6363 | |
| 6352 | if (entry_si != .null) { | 6364 | if (entry_si != .null) { |
| 6353 | log.debug( | 6365 | log.debug( |
| 6354 | "entry({s}, {d})", | 6366 | "entry({s}, {d})", |
| 6355 | .{ entry_si.get(coff).gmi.globalName(coff).name.toSlice(coff), entry_si }, | 6367 | .{ entry_si.get(coff).gmi.globalName(coff).name.toSlice(coff), entry_si }, |
| 6356 | ); | 6368 | ); |
| 6357 | | 6369 | |
| 6358 | try coff.symbols.ensureTotalCapacity(gpa, 1); | 6370 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 6359 | const optional_hdr_si = coff.addSymbolAssumeCapacity(); | 6371 | const optional_hdr_si = coff.addSymbolAssumeCapacity(); |
| 6360 | const optional_hdr_sym = optional_hdr_si.get(coff); | 6372 | const optional_hdr_sym = optional_hdr_si.get(coff); |
| 6361 | optional_hdr_sym.ni = Node.known.optional_header; | 6373 | optional_hdr_sym.ni = Node.known.optional_header; |
| 6362 | assert(optional_hdr_sym.loc_relocs == .none); | 6374 | assert(optional_hdr_sym.loc_relocs == .none); |
| 6363 | optional_hdr_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | 6375 | optional_hdr_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 6364 | | | |
| 6365 | const optional_hdr = coff.optionalHeaderStandardPtr(); | | |
| 6366 | optional_hdr.address_of_entry_point = std.mem.nativeTo( | | |
| 6367 | u32, | | |
| 6368 | entry_si.get(coff).rva, | | |
| 6369 | coff.targetEndian(), | | |
| 6370 | ); | | |
| 6371 | | 6376 | |
| 6372 | try coff.addReloc( | 6377 | const optional_hdr = coff.optionalHeaderStandardPtr(); |
| 6373 | optional_hdr_si, | 6378 | optional_hdr.address_of_entry_point = std.mem.nativeTo( |
| 6374 | @intFromPtr(&optional_hdr.address_of_entry_point) - @intFromPtr(optional_hdr), | 6379 | u32, |
| 6375 | entry_si, | 6380 | entry_si.get(coff).rva, |
| 6376 | .{ .known = 0 }, | 6381 | coff.targetEndian(), |
| 6377 | switch (machine) { | 6382 | ); |
| 6378 | else => |tag| @panic(@tagName(tag)), | | |
| 6379 | .AMD64 => .{ .AMD64 = .ADDR32NB }, | | |
| 6380 | .I386 => .{ .I386 = .DIR32NB }, | | |
| 6381 | }, | | |
| 6382 | ); | | |
| 6383 | } | | |
| 6384 | } | | |
| 6385 | | 6383 | |
| 6386 | if (coff.getDefinedGlobal("_tls_used").unwrap()) |tls_used_si| { | 6384 | try coff.addReloc( |
| 6387 | const tls_directory = coff.dataDirectoryPtr(.TLS); | 6385 | optional_hdr_si, |
| 6388 | tls_directory.* = .{ | 6386 | @intFromPtr(&optional_hdr.address_of_entry_point) - @intFromPtr(optional_hdr), |
| 6389 | .virtual_address = tls_used_si.get(coff).rva, | 6387 | entry_si, |
| 6390 | .size = switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { | 6388 | .{ .known = 0 }, |
| 6391 | _ => unreachable, | 6389 | switch (machine) { |
| 6392 | .PE32 => 24, | 6390 | else => |tag| @panic(@tagName(tag)), |
| 6393 | .@"PE32+" => 40, | 6391 | .AMD64 => .{ .AMD64 = .ADDR32NB }, |
| 6394 | }, | 6392 | .I386 => .{ .I386 = .DIR32NB }, |
| 6395 | }; | 6393 | }, |
| 6396 | if (coff.targetEndian() != native_endian) | 6394 | ); |
| 6397 | std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory); | 6395 | } |
| 6398 | | 6396 | |
| 6399 | try coff.symbols.ensureTotalCapacity(gpa, 1); | 6397 | // Referencing the startup functions may trigger loading the object containing them, |
| 6400 | const data_dir_si = coff.addSymbolAssumeCapacity(); | 6398 | // we need to wait until that is done before looking for further symbols. |
| 6401 | const data_dir_sym = data_dir_si.get(coff); | 6399 | break :next .tls; |
| 6402 | data_dir_sym.ni = Node.known.data_directories; | 6400 | }, |
| 6403 | assert(data_dir_sym.loc_relocs == .none); | 6401 | .tls => { |
| 6404 | data_dir_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | 6402 | if (coff.getDefinedGlobal("_tls_used").unwrap()) |tls_used_si| { |
| 6405 | | 6403 | log.debug("tlsDir({d})", .{tls_used_si}); |
| 6406 | try coff.addReloc( | 6404 | |
| 6407 | data_dir_si, | 6405 | const tls_directory = coff.dataDirectoryPtr(.TLS); |
| 6408 | @intFromPtr(&tls_directory.virtual_address) - @intFromPtr(coff.dataDirectorySlice().ptr), | 6406 | tls_directory.* = .{ |
| 6409 | tls_used_si, | 6407 | .virtual_address = tls_used_si.get(coff).rva, |
| 6410 | .{ .known = 0 }, | 6408 | .size = switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { |
| 6411 | switch (machine) { | 6409 | _ => unreachable, |
| 6412 | else => |tag| @panic(@tagName(tag)), | 6410 | .PE32 => 24, |
| 6413 | .AMD64 => .{ .AMD64 = .ADDR32NB }, | 6411 | .@"PE32+" => 40, |
| 6414 | .I386 => .{ .I386 = .DIR32NB }, | 6412 | }, |
| 6415 | }, | 6413 | }; |
| 6416 | ); | 6414 | if (coff.targetEndian() != native_endian) |
| 6417 | } | 6415 | std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory); |
| | 6416 | |
| | 6417 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| | 6418 | const data_dir_si = coff.addSymbolAssumeCapacity(); |
| | 6419 | const data_dir_sym = data_dir_si.get(coff); |
| | 6420 | data_dir_sym.ni = Node.known.data_directories; |
| | 6421 | assert(data_dir_sym.loc_relocs == .none); |
| | 6422 | data_dir_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| | 6423 | |
| | 6424 | try coff.addReloc( |
| | 6425 | data_dir_si, |
| | 6426 | @intFromPtr(&tls_directory.virtual_address) - @intFromPtr(coff.dataDirectorySlice().ptr), |
| | 6427 | tls_used_si, |
| | 6428 | .{ .known = 0 }, |
| | 6429 | switch (machine) { |
| | 6430 | else => |tag| @panic(@tagName(tag)), |
| | 6431 | .AMD64 => .{ .AMD64 = .ADDR32NB }, |
| | 6432 | .I386 => .{ .I386 = .DIR32NB }, |
| | 6433 | }, |
| | 6434 | ); |
| | 6435 | } |
| | 6436 | |
| | 6437 | break :next .none; |
| | 6438 | }, |
| | 6439 | .none => unreachable, |
| | 6440 | }; |
| 6418 | } | 6441 | } |
| 6419 | | 6442 | |
| 6420 | fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | 6443 | fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| ... | @@ -7137,11 +7160,68 @@ fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) !void { | ... | @@ -7137,11 +7160,68 @@ fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 7137 | pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpResult { | 7160 | pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpResult { |
| 7138 | if (coff.dump_snapshot) { | 7161 | if (coff.dump_snapshot) { |
| 7139 | try coff.printNode(tid, w, .root, 0); | 7162 | try coff.printNode(tid, w, .root, 0); |
| | 7163 | try w.writeAll("Section table:\n"); |
| | 7164 | for (coff.section_table.keys(), coff.section_table.values()) |name, sec| |
| | 7165 | try coff.printSection(w, name, sec.si); |
| | 7166 | try w.writeAll("Symbol table:\n"); |
| | 7167 | for (1..coff.symbols.items.len) |si| |
| | 7168 | try coff.printSymbol(w, @enumFromInt(si)); |
| | 7169 | |
| 7140 | return .enabled; | 7170 | return .enabled; |
| 7141 | } | 7171 | } |
| 7142 | return .disabled; | 7172 | return .disabled; |
| 7143 | } | 7173 | } |
| 7144 | | 7174 | |
| | 7175 | fn printSection(coff: *Coff, w: *Io.Writer, name: String, si: Symbol.Index) !void { |
| | 7176 | const sym = si.get(coff); |
| | 7177 | try w.print("{d:0>6}@{d:0>2} {x:08} n{d:0>8} | {s}\n", .{ |
| | 7178 | si, |
| | 7179 | sym.section_number, |
| | 7180 | if (sym.flags.value_tag == .size) sym.value.size else 0, |
| | 7181 | sym.ni, |
| | 7182 | name.toSlice(coff), |
| | 7183 | }); |
| | 7184 | } |
| | 7185 | |
| | 7186 | fn printSymbol(coff: *Coff, w: *Io.Writer, si: Symbol.Index) !void { |
| | 7187 | const sym = si.get(coff); |
| | 7188 | const node = coff.getNode(sym.ni); |
| | 7189 | try w.print("{d:0>6}@{d:0>2} {x:08} {s} n{d:0>8}+{x:08}:{t: <26} | {x:08} | {f}\n", .{ |
| | 7190 | si, |
| | 7191 | sym.section_number, |
| | 7192 | if (sym.flags.value_tag == .size) |
| | 7193 | @as(u64, sym.value.size) |
| | 7194 | else if (sym.ni != .none) |
| | 7195 | sym.ni.location(&coff.mf).resolve(&coff.mf)[1] |
| | 7196 | else |
| | 7197 | 0, |
| | 7198 | switch (sym.flags.type) { |
| | 7199 | .unknown => "u", |
| | 7200 | .code => "c", |
| | 7201 | .data => "d", |
| | 7202 | }, |
| | 7203 | sym.ni, |
| | 7204 | if (sym.flags.value_tag == .node_offset) sym.value.node_offset else 0, |
| | 7205 | node, |
| | 7206 | sym.rva, |
| | 7207 | fmtGlobalName(coff, sym.gmi), |
| | 7208 | }); |
| | 7209 | } |
| | 7210 | |
| | 7211 | const FmtGlobalName = struct { coff: *Coff, gmi: Node.GlobalMapIndex }; |
| | 7212 | |
| | 7213 | fn fmtGlobalName(coff: *Coff, gmi: Node.GlobalMapIndex) std.fmt.Alt(FmtGlobalName, globalNameEscape) { |
| | 7214 | return .{ .data = .{ .coff = coff, .gmi = gmi } }; |
| | 7215 | } |
| | 7216 | |
| | 7217 | fn globalNameEscape(data: FmtGlobalName, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| | 7218 | if (data.gmi == .none) return; |
| | 7219 | const gn = data.gmi.globalName(data.coff); |
| | 7220 | try w.writeAll(gn.name.toSlice(data.coff)); |
| | 7221 | if (gn.lib_name.unwrap()) |lib_name| |
| | 7222 | try w.print("({s})", .{lib_name.toSlice(data.coff)}); |
| | 7223 | } |
| | 7224 | |
| 7145 | pub fn printNode( | 7225 | pub fn printNode( |
| 7146 | coff: *Coff, | 7226 | coff: *Coff, |
| 7147 | tid: Zcu.PerThread.Id, | 7227 | tid: Zcu.PerThread.Id, |