authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:34-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:22:41-04:00
log0bfa6e41e9654d35d79ce4b617180a86eb5a2c3d
treec4ee01c0e351c8543f6f67773bf0f1d1e3229638
parent647fe54ef0843018bfc8416ae5f5f46e6bf2d78c

Coff: More progress on archives

- Move flushing symbol table entries to an idle task - Add progress nodes - Wire up --debug-link-snapshot

1 files changed, 225 insertions(+), 135 deletions(-)

src/link/Coff.zig+225-135
...@@ -39,6 +39,7 @@ strings: std.HashMapUnmanaged(...@@ -39,6 +39,7 @@ strings: std.HashMapUnmanaged(
39),39),
40string_bytes: std.ArrayList(u8),40string_bytes: std.ArrayList(u8),
41section_table: std.ArrayList(Section),41section_table: std.ArrayList(Section),
42tls_si: Symbol.Index,
42pseudo_section_table: std.array_hash_map.Auto(String, Symbol.Index),43pseudo_section_table: std.array_hash_map.Auto(String, Symbol.Index),
43object_section_table: std.array_hash_map.Auto(String, Symbol.Index),44object_section_table: std.array_hash_map.Auto(String, Symbol.Index),
44symbols: std.ArrayList(Symbol),45symbols: std.ArrayList(Symbol),
...@@ -56,6 +57,9 @@ pending_uavs: std.array_hash_map.Auto(Node.UavMapIndex, struct {...@@ -56,6 +57,9 @@ pending_uavs: std.array_hash_map.Auto(Node.UavMapIndex, struct {
56relocs: std.ArrayList(Reloc),57relocs: std.ArrayList(Reloc),
57const_prog_node: std.Progress.Node,58const_prog_node: std.Progress.Node,
58synth_prog_node: std.Progress.Node,59synth_prog_node: std.Progress.Node,
60symbol_prog_node: std.Progress.Node,
61member_prog_node: std.Progress.Node,
62dump_snapshot: bool,
5963
60pub const default_file_alignment: u16 = 0x200;64pub const default_file_alignment: u16 = 0x200;
61pub const default_size_of_stack_reserve: u32 = 0x1000000;65pub const default_size_of_stack_reserve: u32 = 0x1000000;
...@@ -158,7 +162,6 @@ pub const Node = union(enum) {...@@ -158,7 +162,6 @@ pub const Node = union(enum) {
158 section_table,162 section_table,
159 // Archives and objects only163 // Archives and objects only
160 symbol_table,164 symbol_table,
161 symbol_table_entry,
162 // Archives and objects only165 // Archives and objects only
163 string_table,166 string_table,
164 // Archives and objects only167 // Archives and objects only
...@@ -314,8 +317,6 @@ pub const Node = union(enum) {...@@ -314,8 +317,6 @@ pub const Node = union(enum) {
314 optional_header,317 optional_header,
315 data_directories,318 data_directories,
316 section_table,319 section_table,
317 symbol_table,
318 string_table,
319 };320 };
320 var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined;321 var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined;
321 const info = @typeInfo(Known).@"enum";322 const info = @typeInfo(Known).@"enum";
...@@ -464,20 +465,18 @@ pub const LongNamesTable = struct {...@@ -464,20 +465,18 @@ pub const LongNamesTable = struct {
464};465};
465466
466pub const SymbolTable = struct {467pub const SymbolTable = struct {
468 ni: MappedFile.Node.Index,
469 strings_ni: MappedFile.Node.Index,
467 strings: std.AutoArrayHashMapUnmanaged(String, StringIndex),470 strings: std.AutoArrayHashMapUnmanaged(String, StringIndex),
471 pending: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),
468472
469 // Adding nodes to the symbol table has the result of accumulating padding473 // Resizing the symbol table node has the result of accumulating padding
470 // between the last symbol in the symbol table node and the start of the474 // between the last symbol in the symbol table node and the start of the
471 // string table node, due to the growth factor in MappedFile.475 // string table node, due to the shifting method when resizing the parent in MappedFile.
472 // The spec requires the string table begin immediately after the last symbol,476 // The spec requires the string table begin immediately after the last symbol,
473 // so we compact the symbol table node if needed.477 // so we compact the symbol table node and move the string table back if needed.
474 pending_shrink: bool,478 pending_shrink: bool,
475479
476 pub const Add = union(enum) {
477 section,
478 global,
479 };
480
481 pub const StringIndex = enum(u32) {480 pub const StringIndex = enum(u32) {
482 _,481 _,
483 };482 };
...@@ -1103,12 +1102,16 @@ fn create(...@@ -1103,12 +1102,16 @@ fn create(
1103 .entries = .empty,1102 .entries = .empty,
1104 },1103 },
1105 .symbol_table = .{1104 .symbol_table = .{
1105 .ni = .none,
1106 .strings_ni = .none,
1106 .strings = .empty,1107 .strings = .empty,
1108 .pending = .empty,
1107 .pending_shrink = false,1109 .pending_shrink = false,
1108 },1110 },
1109 .strings = .empty,1111 .strings = .empty,
1110 .string_bytes = .empty,1112 .string_bytes = .empty,
1111 .section_table = .empty,1113 .section_table = .empty,
1114 .tls_si = .null,
1112 .pseudo_section_table = .empty,1115 .pseudo_section_table = .empty,
1113 .object_section_table = .empty,1116 .object_section_table = .empty,
1114 .symbols = .empty,1117 .symbols = .empty,
...@@ -1124,6 +1127,9 @@ fn create(...@@ -1124,6 +1127,9 @@ fn create(
1124 .relocs = .empty,1127 .relocs = .empty,
1125 .const_prog_node = .none,1128 .const_prog_node = .none,
1126 .synth_prog_node = .none,1129 .synth_prog_node = .none,
1130 .symbol_prog_node = .none,
1131 .member_prog_node = .none,
1132 .dump_snapshot = options.enable_link_snapshots,
1127 };1133 };
1128 errdefer coff.deinit();1134 errdefer coff.deinit();
11291135
...@@ -1155,6 +1161,7 @@ pub fn deinit(coff: *Coff) void {...@@ -1155,6 +1161,7 @@ pub fn deinit(coff: *Coff) void {
1155 coff.import_table.entries.deinit(gpa);1161 coff.import_table.entries.deinit(gpa);
1156 coff.export_table.entries.deinit(gpa);1162 coff.export_table.entries.deinit(gpa);
1157 coff.symbol_table.strings.deinit(gpa);1163 coff.symbol_table.strings.deinit(gpa);
1164 coff.symbol_table.pending.deinit(gpa);
1158 coff.strings.deinit(gpa);1165 coff.strings.deinit(gpa);
1159 coff.string_bytes.deinit(gpa);1166 coff.string_bytes.deinit(gpa);
1160 coff.section_table.deinit(gpa);1167 coff.section_table.deinit(gpa);
...@@ -1222,14 +1229,21 @@ fn initHeaders(...@@ -1222,14 +1229,21 @@ fn initHeaders(
12221229
1223 var expected_nodes_len: usize = Node.known_count;1230 var expected_nodes_len: usize = Node.known_count;
1224 if (comp.zcu != null) {1231 if (comp.zcu != null) {
1225 // Section nodes1232 // Sections
1226 expected_nodes_len += 3;1233 expected_nodes_len += 3;
1227 // // Symbol table nodes1234
1228 // if (is_archive) expected_nodes_len += 6;1235 if (is_image)
1229 // Pseudo-sections and import / export table nodes1236 // Pseudo-sections and import / export table
1230 if (is_image) expected_nodes_len += 9;1237 expected_nodes_len += 9
1231 // TLS section nodes1238 else
1232 expected_nodes_len += @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2;1239 // Symbol table
1240 expected_nodes_len += 2;
1241
1242 // TLS section
1243 if (comp.config.any_non_single_threaded) {
1244 if (!is_image) expected_nodes_len += 1;
1245 expected_nodes_len += 2;
1246 }
1233 }1247 }
1234 defer assert(coff.nodes.len == expected_nodes_len);1248 defer assert(coff.nodes.len == expected_nodes_len);
12351249
...@@ -1486,25 +1500,25 @@ fn initHeaders(...@@ -1486,25 +1500,25 @@ fn initHeaders(
1486 }));1500 }));
1487 coff.nodes.appendAssumeCapacity(.section_table);1501 coff.nodes.appendAssumeCapacity(.section_table);
14881502
1489 // TODO: These two nodes could be inside one movable node?1503 assert(coff.nodes.len == Node.known_count);
1490 const symbol_table_ni = Node.known.symbol_table;
1491 assert(symbol_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{
1492 .alignment = .@"2",
1493 .fixed = true,
1494 .moved = true,
1495 }));
1496 coff.nodes.appendAssumeCapacity(.symbol_table);
14971504
1498 const string_table_ni = Node.known.string_table;1505 if (!is_image) {
1499 assert(string_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{1506 // TODO: These two nodes could be inside one movable node?
1500 .alignment = .@"2",1507 coff.symbol_table.ni = try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{
1501 .size = if (!is_image) @sizeOf(u32) else 0,1508 .alignment = .@"2",
1502 .fixed = true,1509 .fixed = true,
1503 .resized = true,1510 .moved = true,
1504 }));1511 });
1505 coff.nodes.appendAssumeCapacity(.string_table);1512 coff.nodes.appendAssumeCapacity(.symbol_table);
15061513
1507 assert(coff.nodes.len == Node.known_count);1514 coff.symbol_table.strings_ni = try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{
1515 .alignment = .@"2",
1516 .size = @sizeOf(u32),
1517 .fixed = true,
1518 .resized = true,
1519 });
1520 coff.nodes.appendAssumeCapacity(.string_table);
1521 }
15081522
1509 try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count);1523 try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count);
1510 coff.symbols.addOneAssumeCapacity().* = .{1524 coff.symbols.addOneAssumeCapacity().* = .{
...@@ -1618,12 +1632,23 @@ fn initHeaders(...@@ -1618,12 +1632,23 @@ fn initHeaders(
1618 std.mem.byteSwapAllFields(std.coff.ExportDirectoryTable, export_directory_table);1632 std.mem.byteSwapAllFields(std.coff.ExportDirectoryTable, export_directory_table);
1619 }1633 }
16201634
1621 // While tls variables allocated at runtime are writable, the template itself is not1635 if (comp.config.any_non_single_threaded) {
1622 if (comp.config.any_non_single_threaded) _ = try coff.objectSectionMapIndex(1636 if (!is_image)
1623 .@".tls$",1637 coff.tls_si = try coff.addSection(".tls$", .{
1624 if (is_image) coff.mf.flags.block_size else .@"1",1638 .CNT_INITIALIZED_DATA = true,
1625 .{ .read = true },1639 .MEM_READ = true,
1626 );1640 .MEM_WRITE = true,
1641 });
1642
1643 // While tls variables allocated at runtime are writable, the template itself is not.
1644 // In images, this call triggers the creation of a .tls pseudo section in .rdata.
1645 // In objects / archives, this section is part of the above .tls$ section.
1646 _ = try coff.objectSectionMapIndex(
1647 .@".tls$",
1648 coff.mf.flags.block_size,
1649 .{ .read = true, .write = !is_image, .tls = true },
1650 );
1651 }
1627}1652}
16281653
1629pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void {1654pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void {
...@@ -1634,12 +1659,23 @@ pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void {...@@ -1634,12 +1659,23 @@ pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void {
1634 for (&coff.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;1659 for (&coff.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
1635 break :count count;1660 break :count count;
1636 });1661 });
1662 if (!isImage(coff)) {
1663 prog_node.increaseEstimatedTotalItems(2);
1664 coff.symbol_prog_node = prog_node.start("Symbols", coff.symbol_table.pending.count());
1665 coff.member_prog_node = prog_node.start("Members", coff.pending_members.count());
1666 }
1637 coff.mf.update_prog_node = prog_node.start("Relocations", coff.mf.updates.items.len);1667 coff.mf.update_prog_node = prog_node.start("Relocations", coff.mf.updates.items.len);
1638}1668}
16391669
1640pub fn endProgress(coff: *Coff) void {1670pub fn endProgress(coff: *Coff) void {
1641 coff.mf.update_prog_node.end();1671 coff.mf.update_prog_node.end();
1642 coff.mf.update_prog_node = .none;1672 coff.mf.update_prog_node = .none;
1673 if (!isImage(coff)) {
1674 coff.member_prog_node.end();
1675 coff.member_prog_node = .none;
1676 coff.symbol_prog_node.end();
1677 coff.symbol_prog_node = .none;
1678 }
1643 coff.synth_prog_node.end();1679 coff.synth_prog_node.end();
1644 coff.synth_prog_node = .none;1680 coff.synth_prog_node = .none;
1645 coff.const_prog_node.end();1681 coff.const_prog_node.end();
...@@ -1665,7 +1701,6 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {...@@ -1665,7 +1701,6 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
1665 .placeholder,1701 .placeholder,
16661702
1667 .symbol_table,1703 .symbol_table,
1668 .symbol_table_entry,
1669 .string_table,1704 .string_table,
1670 .relocation_table,1705 .relocation_table,
1671 .relocation_table_entry,1706 .relocation_table_entry,
...@@ -1858,7 +1893,7 @@ pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader {...@@ -1858,7 +1893,7 @@ pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader {
1858pub fn symbolTableEntryStoragePtr(coff: *Coff, index: u32) *[std.coff.Symbol.sizeOf()]u8 {1893pub fn symbolTableEntryStoragePtr(coff: *Coff, index: u32) *[std.coff.Symbol.sizeOf()]u8 {
1859 assert(!coff.isImage());1894 assert(!coff.isImage());
1860 const offset = index * std.coff.Symbol.sizeOf();1895 const offset = index * std.coff.Symbol.sizeOf();
1861 return @ptrCast(@alignCast(Node.known.symbol_table.slice(&coff.mf)[offset..][0..std.coff.Symbol.sizeOf()]));1896 return @ptrCast(@alignCast(coff.symbol_table.ni.slice(&coff.mf)[offset..][0..std.coff.Symbol.sizeOf()]));
1862}1897}
18631898
1864pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.coff.Symbol {1899pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.coff.Symbol {
...@@ -1876,7 +1911,7 @@ pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, si: Symbol.Index) *align(2) st...@@ -1876,7 +1911,7 @@ pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, si: Symbol.Index) *align(2) st
1876}1911}
18771912
1878pub fn symbolTableStringLenPtr(coff: *Coff) *align(2) u32 {1913pub fn symbolTableStringLenPtr(coff: *Coff) *align(2) u32 {
1879 return @ptrCast(@alignCast(Node.known.string_table.slice(&coff.mf)[0..@sizeOf(u32)]));1914 return @ptrCast(@alignCast(coff.symbol_table.strings_ni.slice(&coff.mf)[0..@sizeOf(u32)]));
1880}1915}
18811916
1882pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry {1917pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry {
...@@ -1971,6 +2006,18 @@ pub fn globalSymbol(coff: *Coff, opts: struct {...@@ -1971,6 +2006,18 @@ pub fn globalSymbol(coff: *Coff, opts: struct {
1971 return sym_gop.value_ptr.*;2006 return sym_gop.value_ptr.*;
1972}2007}
19732008
2009pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void {
2010 assert(!coff.isImage());
2011 const sym = si.get(coff);
2012 assert(sym.ni != .none or sym.gmi != .none);
2013
2014 const gpa = coff.base.comp.gpa;
2015 const pending_gop = try coff.symbol_table.pending.getOrPut(gpa, si);
2016 if (!pending_gop.found_existing) {
2017 coff.symbol_prog_node.increaseEstimatedTotalItems(1);
2018 }
2019}
2020
1974fn navSection(2021fn navSection(
1975 coff: *Coff,2022 coff: *Coff,
1976 zcu: *Zcu,2023 zcu: *Zcu,
...@@ -1979,7 +2026,7 @@ fn navSection(...@@ -1979,7 +2026,7 @@ fn navSection(
1979 const ip = &zcu.intern_pool;2026 const ip = &zcu.intern_pool;
1980 const default: String, const attributes: ObjectSectionAttributes =2027 const default: String, const attributes: ObjectSectionAttributes =
1981 if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{2028 if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{
1982 .@".tls$", .{ .read = true, .write = true },2029 .@".tls$", .{ .read = true, .write = true, .tls = true },
1983 } else if (ip.isFunctionType(nav_resolved.type)) .{2030 } else if (ip.isFunctionType(nav_resolved.type)) .{
1984 .@".text", .{ .read = true, .execute = true },2031 .@".text", .{ .read = true, .execute = true },
1985 } else if (nav_resolved.@"const") .{2032 } else if (nav_resolved.@"const") .{
...@@ -2149,6 +2196,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: Member.Kind, size: usize) !Member....@@ -2149,6 +2196,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: Member.Kind, size: usize) !Member.
2149 gpa,2196 gpa,
2150 coff.pending_members.capacity() + 1,2197 coff.pending_members.capacity() + 1,
2151 );2198 );
2199 coff.member_prog_node.increaseEstimatedTotalItems(1);
2152 },2200 },
2153 }2201 }
21542202
...@@ -2249,16 +2297,15 @@ fn ensureMemberSymbol(...@@ -2249,16 +2297,15 @@ fn ensureMemberSymbol(
2249 }2297 }
22502298
2251 coff.pending_members.putAssumeCapacity(mi, {});2299 coff.pending_members.putAssumeCapacity(mi, {});
2300 coff.member_prog_node.increaseEstimatedTotalItems(1);
2252}2301}
22532302
2254// TODO: -> flushSymbolTableEntry, and push all call sites onto a pending list instead?2303fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void {
2255fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {
2256 assert(!coff.isImage());2304 assert(!coff.isImage());
2257 const gpa = coff.base.comp.gpa;2305 const gpa = coff.base.comp.gpa;
22582306
2259 const sym = si.get(coff);2307 const sym = si.get(coff);
2260 const has_node = sym.ni != .none;2308 assert(sym.ni != .none or sym.gmi != .none);
2261 assert(has_node or sym.gmi != .none);
22622309
2263 const entry = coff.symbolTableEntryPtr(sym.sti) orelse entry: {2310 const entry = coff.symbolTableEntryPtr(sym.sti) orelse entry: {
2264 var buf: [15]u8 = undefined;2311 var buf: [15]u8 = undefined;
...@@ -2274,14 +2321,14 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {...@@ -2274,14 +2321,14 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {
2274 else2321 else
2275 .NULL,2322 .NULL,
2276 };2323 };
2277 } else switch (coff.getNode(sym.ni)) {2324 } else blk: switch (coff.getNode(sym.ni)) {
2278 .image_section => .{2325 .image_section => .{
2279 &sym.section_number.header(coff).name,2326 &sym.section_number.header(coff).name,
2280 null,2327 null,
2281 1,2328 1,
2282 .NULL,2329 .NULL,
2283 },2330 },
2284 .nav => |nmi| blk: {2331 .nav => |nmi| {
2285 const zcu = coff.base.comp.zcu.?;2332 const zcu = coff.base.comp.zcu.?;
2286 const ip = &zcu.intern_pool;2333 const ip = &zcu.intern_pool;
2287 const nav = ip.getNav(nmi.navIndex(coff));2334 const nav = ip.getNav(nmi.navIndex(coff));
...@@ -2292,14 +2339,25 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {...@@ -2292,14 +2339,25 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {
2292 if (ip.isFunctionType(nav.resolved.?.type)) .FUNCTION else .NULL,2339 if (ip.isFunctionType(nav.resolved.?.type)) .FUNCTION else .NULL,
2293 };2340 };
2294 },2341 },
2295 .uav => |umi| blk: {2342 .uav => |umi| {
2296 var w = Io.Writer.fixed(&buf);2343 var w = Io.Writer.fixed(&buf);
2297 w.print("__anon_{x}", .{umi.uavValue(coff)}) catch unreachable;2344 w.print("__anon_{x}", .{umi.uavValue(coff)}) catch unreachable;
2298 break :blk .{ w.buffered(), null, 0, .NULL };2345 break :blk .{ w.buffered(), null, 0, .NULL };
2299 },2346 },
2347 inline .lazy_code, .lazy_const_data => |mi, tag| {
2348 const lazy_sym = mi.lazySymbol(coff);
2349 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{
2350 @tagName(lazy_sym.kind),
2351 Type.fromInterned(lazy_sym.ty).fmt(pt),
2352 });
2353 defer gpa.free(name);
2354
2355 const string = try coff.getOrPutString(name);
2356 break :blk .{ string.toSlice(coff), string, 0, if (tag == .lazy_code) .FUNCTION else .NULL };
2357 },
2300 else => {2358 else => {
2301 log.err("TODO implement symbol table init for {s}", .{@tagName(coff.getNode(sym.ni))});2359 log.err("TODO implement symbol table init for {s} ({d})", .{ @tagName(coff.getNode(sym.ni)), si });
2302 return .none;2360 unreachable;
2303 },2361 },
2304 };2362 };
23052363
...@@ -2307,11 +2365,11 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {...@@ -2307,11 +2365,11 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {
2307 const string = opt_name_string orelse try coff.getOrPutString(name_slice);2365 const string = opt_name_string orelse try coff.getOrPutString(name_slice);
2308 const string_gop = try coff.symbol_table.strings.getOrPut(gpa, string);2366 const string_gop = try coff.symbol_table.strings.getOrPut(gpa, string);
2309 if (!string_gop.found_existing) {2367 if (!string_gop.found_existing) {
2310 const string_index = Node.known.string_table.location(&coff.mf).resolve(&coff.mf)[1];2368 const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1];
2311 string_gop.value_ptr.* = @enumFromInt(string_index);2369 string_gop.value_ptr.* = @enumFromInt(string_index);
23122370
2313 try Node.known.string_table.resize(&coff.mf, gpa, string_index + name_slice.len + 1);2371 try coff.symbol_table.strings_ni.resize(&coff.mf, gpa, string_index + name_slice.len + 1);
2314 const slice = Node.known.string_table.slice(&coff.mf);2372 const slice = coff.symbol_table.strings_ni.slice(&coff.mf);
2315 @memcpy(slice[string_index..][0..name_slice.len], name_slice);2373 @memcpy(slice[string_index..][0..name_slice.len], name_slice);
2316 slice[string_index + name_slice.len] = 0;2374 slice[string_index + name_slice.len] = 0;
2317 }2375 }
...@@ -2322,11 +2380,7 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {...@@ -2322,11 +2380,7 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {
2322 const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);2380 const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
2323 const new_num_symbols = old_num_symbols + 1 + num_aux_symbols;2381 const new_num_symbols = old_num_symbols + 1 + num_aux_symbols;
23242382
2325 try Node.known.symbol_table.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());2383 try coff.symbol_table.ni.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());
2326
2327 const symbol_table_loc = Node.known.symbol_table.location(&coff.mf).resolve(&coff.mf);
2328 const string_table_loc = Node.known.string_table.location(&coff.mf).resolve(&coff.mf);
2329 coff.symbol_table.pending_shrink = string_table_loc[0] - (symbol_table_loc[0] + symbol_table_loc[1]) > 0;
23302384
2331 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);2385 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
2332 sym.sti = .wrap(old_num_symbols);2386 sym.sti = .wrap(old_num_symbols);
...@@ -2373,8 +2427,6 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {...@@ -2373,8 +2427,6 @@ fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {
2373 });2427 });
23742428
2375 log.debug("updateSymbolTableEntry({d}) = {d}", .{ si, sym.sti });2429 log.debug("updateSymbolTableEntry({d}) = {d}", .{ si, sym.sti });
2376
2377 return sym.sti;
2378}2430}
23792431
2380fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index {2432fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index {
...@@ -2384,6 +2436,7 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags...@@ -2384,6 +2436,7 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
2384 try coff.nodes.ensureUnusedCapacity(gpa, 1);2436 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2385 try coff.section_table.ensureUnusedCapacity(gpa, 1);2437 try coff.section_table.ensureUnusedCapacity(gpa, 1);
2386 try coff.symbols.ensureUnusedCapacity(gpa, 1);2438 try coff.symbols.ensureUnusedCapacity(gpa, 1);
2439 if (!isImage(coff)) try coff.symbol_table.pending.ensureUnusedCapacity(gpa, 1);
23872440
2388 const coff_header = coff.headerPtr();2441 const coff_header = coff.headerPtr();
2389 const section_index = coff.targetLoad(&coff_header.number_of_sections);2442 const section_index = coff.targetLoad(&coff_header.number_of_sections);
...@@ -2457,7 +2510,7 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags...@@ -2457,7 +2510,7 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
2457 ),2510 ),
2458 }2511 }
2459 } else {2512 } else {
2460 assert(try coff.updateSymbolTableEntry(si) != .none);2513 try coff.pendingSymbolTableEntry(si);
2461 }2514 }
24622515
2463 return si;2516 return si;
...@@ -2472,7 +2525,9 @@ const ObjectSectionAttributes = packed struct {...@@ -2472,7 +2525,9 @@ const ObjectSectionAttributes = packed struct {
2472 nocache: bool = false,2525 nocache: bool = false,
2473 discard: bool = false,2526 discard: bool = false,
2474 remove: bool = false,2527 remove: bool = false,
2528 tls: bool = false,
2475};2529};
2530
2476fn pseudoSectionMapIndex(2531fn pseudoSectionMapIndex(
2477 coff: *Coff,2532 coff: *Coff,
2478 name: String,2533 name: String,
...@@ -2485,6 +2540,8 @@ fn pseudoSectionMapIndex(...@@ -2485,6 +2540,8 @@ fn pseudoSectionMapIndex(
2485 if (!pseudo_section_gop.found_existing) {2540 if (!pseudo_section_gop.found_existing) {
2486 const parent: Symbol.Index = if (attributes.execute)2541 const parent: Symbol.Index = if (attributes.execute)
2487 .text2542 .text
2543 else if (attributes.tls and coff.tls_si != .null)
2544 coff.tls_si
2488 else if (attributes.write)2545 else if (attributes.write)
2489 .data2546 .data
2490 else2547 else
...@@ -2556,35 +2613,6 @@ fn objectSectionMapIndex(...@@ -2556,35 +2613,6 @@ fn objectSectionMapIndex(
2556 return osmi;2613 return osmi;
2557}2614}
25582615
2559fn ensureUnusedRelocCapacity(coff: *Coff, loc_si: Symbol.Index, len: usize) !void {
2560 const gpa = coff.base.comp.gpa;
2561
2562 try coff.relocs.ensureUnusedCapacity(gpa, len);
2563 if (isImage(coff)) return;
2564
2565 switch (loc_si.get(coff).section_number) {
2566 .UNDEFINED, .ABSOLUTE, .DEBUG => {},
2567 else => |sn| {
2568 const section = sn.section(coff);
2569 const header = sn.header(coff);
2570 const new_size = (len + coff.targetLoad(&header.number_of_relocations)) * std.coff.Relocation.sizeOf();
2571 if (section.relocation_table_ni == .none) {
2572 // The entry's length in the file is shorter than its @sizeOf
2573 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2574 section.relocation_table_ni = try coff.mf.addLastChildNode(gpa, Node.known.zcu_member, .{
2575 .size = new_size,
2576 .alignment = .@"2",
2577 .moved = true,
2578 .resized = true,
2579 });
2580 coff.nodes.appendAssumeCapacity(.{ .relocation_table = sn });
2581 } else {
2582 try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);
2583 }
2584 },
2585 }
2586}
2587
2588pub fn addReloc(2616pub fn addReloc(
2589 coff: *Coff,2617 coff: *Coff,
2590 loc_si: Symbol.Index,2618 loc_si: Symbol.Index,
...@@ -2612,10 +2640,10 @@ pub fn addReloc(...@@ -2612,10 +2640,10 @@ pub fn addReloc(
2612 // have a node. In that case, flushGlobal will create the symbol table entry.2640 // have a node. In that case, flushGlobal will create the symbol table entry.
2613 const sti: SymbolTable.Index = if (target.sti != .none)2641 const sti: SymbolTable.Index = if (target.sti != .none)
2614 target.sti2642 target.sti
2615 else if (target.ni != .none)2643 else if (target.ni != .none) sti: {
2616 try updateSymbolTableEntry(coff, target_si)2644 try coff.pendingSymbolTableEntry(target_si);
2617 else2645 break :sti .none;
2618 .none;2646 } else .none;
26192647
2620 const section = loc_sn.section(coff);2648 const section = loc_sn.section(coff);
2621 const header = loc_sn.header(coff);2649 const header = loc_sn.header(coff);
...@@ -2714,6 +2742,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -2714,6 +2742,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
2714 .none => {2742 .none => {
2715 const sec_si = try coff.navSection(zcu, nav.resolved.?);2743 const sec_si = try coff.navSection(zcu, nav.resolved.?);
2716 try coff.nodes.ensureUnusedCapacity(gpa, 1);2744 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2745 if (!isImage(coff)) try coff.symbol_table.pending.ensureUnusedCapacity(gpa, 1);
2717 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{2746 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
2718 .alignment = zcu.navAlignment(nav_index).toStdMem(),2747 .alignment = zcu.navAlignment(nav_index).toStdMem(),
2719 .moved = true,2748 .moved = true,
...@@ -2728,8 +2757,8 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -2728,8 +2757,8 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
2728 const sym = si.get(coff);2757 const sym = si.get(coff);
2729 assert(sym.loc_relocs == .none);2758 assert(sym.loc_relocs == .none);
2730 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);2759 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
2731 if (sym.target_relocs != .none)2760 if (!isImage(coff) and sym.target_relocs != .none)
2732 _ = try coff.updateSymbolTableEntry(si);2761 try coff.pendingSymbolTableEntry(si);
27332762
2734 break :ni sym.ni;2763 break :ni sym.ni;
2735 };2764 };
...@@ -2836,6 +2865,7 @@ fn updateFuncInner(...@@ -2836,6 +2865,7 @@ fn updateFuncInner(
2836 .none => {2865 .none => {
2837 const sec_si = try coff.navSection(zcu, nav.resolved.?);2866 const sec_si = try coff.navSection(zcu, nav.resolved.?);
2838 try coff.nodes.ensureUnusedCapacity(gpa, 1);2867 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2868 if (!isImage(coff)) try coff.symbol_table.pending.ensureUnusedCapacity(gpa, 1);
2839 const mod = zcu.navFileScope(func.owner_nav).mod.?;2869 const mod = zcu.navFileScope(func.owner_nav).mod.?;
2840 const target = &mod.resolved_target.result;2870 const target = &mod.resolved_target.result;
2841 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{2871 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
...@@ -2861,8 +2891,8 @@ fn updateFuncInner(...@@ -2861,8 +2891,8 @@ fn updateFuncInner(
2861 const sym = si.get(coff);2891 const sym = si.get(coff);
2862 assert(sym.loc_relocs == .none);2892 assert(sym.loc_relocs == .none);
2863 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);2893 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
2864 if (sym.target_relocs != .none)2894 if (!isImage(coff) and sym.target_relocs != .none)
2865 _ = try coff.updateSymbolTableEntry(si);2895 try coff.pendingSymbolTableEntry(si);
2866 break :ni sym.ni;2896 break :ni sym.ni;
2867 };2897 };
28682898
...@@ -3015,8 +3045,9 @@ pub fn flush(...@@ -3015,8 +3045,9 @@ pub fn flush(
3015 else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}),3045 else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}),
3016 };3046 };
30173047
3018 coff.dumpStderr(tid) catch |err|3048 if (coff.dump_snapshot)
3019 return comp.link_diags.fail("dumping link snapshot failed: {t}", .{err});3049 coff.dumpStderr(tid) catch |err|
3050 return comp.link_diags.fail("dumping link snapshot failed: {t}", .{err});
3020}3051}
30213052
3022pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {3053pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
...@@ -3083,6 +3114,29 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -3083,6 +3114,29 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
3083 };3114 };
3084 break :task;3115 break :task;
3085 };3116 };
3117 while (coff.symbol_table.pending.pop()) |pending_si| {
3118 const sym = pending_si.key.get(coff);
3119 const sub_prog_node = coff.idleProgNode(
3120 tid,
3121 coff.symbol_prog_node,
3122 if (sym.ni != .none)
3123 coff.getNode(sym.ni)
3124 else
3125 .{ .global = pending_si.key.get(coff).gmi },
3126 );
3127 defer sub_prog_node.end();
3128 coff.flushSymbolTableEntry(
3129 pending_si.key,
3130 .{ .zcu = comp.zcu.?, .tid = tid },
3131 ) catch |err| switch (err) {
3132 error.OutOfMemory => return error.OutOfMemory,
3133 else => |e| return comp.link_diags.fail(
3134 "linker failed to flush symbol table entry: {t}",
3135 .{e},
3136 ),
3137 };
3138 break :task;
3139 }
3086 while (coff.mf.updates.pop()) |ni| {3140 while (coff.mf.updates.pop()) |ni| {
3087 const clean_moved = ni.cleanMoved(&coff.mf);3141 const clean_moved = ni.cleanMoved(&coff.mf);
3088 const clean_resized = ni.cleanResized(&coff.mf);3142 const clean_resized = ni.cleanResized(&coff.mf);
...@@ -3096,22 +3150,39 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -3096,22 +3150,39 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
3096 } else coff.mf.update_prog_node.completeOne();3150 } else coff.mf.update_prog_node.completeOne();
3097 }3151 }
3098 while (coff.pending_members.pop()) |pending_mi| {3152 while (coff.pending_members.pop()) |pending_mi| {
3099 // TODO: Prog node3153 const sub_prog_node = coff.idleProgNode(
3154 tid,
3155 coff.symbol_prog_node,
3156 coff.getNode(pending_mi.key.get(coff).content_ni),
3157 );
3158 defer sub_prog_node.end();
3100 try coff.flushMember(pending_mi.key);3159 try coff.flushMember(pending_mi.key);
3101 break :task;3160 break :task;
3102 }3161 }
3162 // TODO: This and the next task ideally only run once, as it's wasteful otherwise
3103 if (coff.export_table.pending_sort) {3163 if (coff.export_table.pending_sort) {
3104 // TODO: Prog node3164 defer coff.export_table.pending_sort = false;
3105 coff.export_table.pending_sort = false;3165 const sub_prog_node = coff.idleProgNode(
3166 tid,
3167 coff.synth_prog_node,
3168 coff.getNode(coff.export_table.ni),
3169 );
3170 defer sub_prog_node.end();
3171
3106 coff.flushExportsSort();3172 coff.flushExportsSort();
3107 break :task;3173 break :task;
3108 }3174 }
3109 // TODO: This and the above task ideally run only once, as it's wasteful otherwise
3110 if (coff.symbol_table.pending_shrink) {3175 if (coff.symbol_table.pending_shrink) {
3111 coff.symbol_table.pending_shrink = false;3176 defer coff.symbol_table.pending_shrink = false;
3112 // TODO: Prog node3177 const sub_prog_node = coff.idleProgNode(
3178 tid,
3179 coff.symbol_prog_node,
3180 coff.getNode(coff.symbol_table.ni),
3181 );
3182 defer sub_prog_node.end();
3183
3113 const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);3184 const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
3114 Node.known.symbol_table.shrink(3185 coff.symbol_table.ni.shrink(
3115 &coff.mf,3186 &coff.mf,
3116 comp.gpa,3187 comp.gpa,
3117 number_of_symbols * std.coff.Symbol.sizeOf(),3188 number_of_symbols * std.coff.Symbol.sizeOf(),
...@@ -3119,7 +3190,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -3119,7 +3190,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
3119 ) catch |err| switch (err) {3190 ) catch |err| switch (err) {
3120 error.OutOfMemory => return error.OutOfMemory,3191 error.OutOfMemory => return error.OutOfMemory,
3121 else => |e| return comp.link_diags.fail(3192 else => |e| return comp.link_diags.fail(
3122 "linker failed to shrink symbol table: {t}",3193 "linker failed to compact symbol table: {t}",
3123 .{e},3194 .{e},
3124 ),3195 ),
3125 };3196 };
...@@ -3129,6 +3200,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -3129,6 +3200,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
3129 }3200 }
3130 if (coff.pending_uavs.count() > 0) return true;3201 if (coff.pending_uavs.count() > 0) return true;
3131 if (coff.globals.count() > coff.global_pending_index) return true;3202 if (coff.globals.count() > coff.global_pending_index) return true;
3203 if (coff.symbol_table.pending.count() > 0) return true;
3132 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;3204 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
3133 if (coff.mf.updates.items.len > 0) return true;3205 if (coff.mf.updates.items.len > 0) return true;
3134 if (coff.pending_members.count() > 0) return true;3206 if (coff.pending_members.count() > 0) return true;
...@@ -3159,6 +3231,7 @@ fn idleProgNode(...@@ -3159,6 +3231,7 @@ fn idleProgNode(
3159 .tid = tid,3231 .tid = tid,
3160 }),3232 }),
3161 }) catch &name,3233 }) catch &name,
3234 .archive_member => |mi| &mi.get(coff).headerPtr(coff).name,
3162 }, 0);3235 }, 0);
3163}3236}
31643237
...@@ -3182,6 +3255,7 @@ fn flushUav(...@@ -3182,6 +3255,7 @@ fn flushUav(
3182 .{ .read = true },3255 .{ .read = true },
3183 )).symbol(coff);3256 )).symbol(coff);
3184 try coff.nodes.ensureUnusedCapacity(gpa, 1);3257 try coff.nodes.ensureUnusedCapacity(gpa, 1);
3258 if (!isImage(coff)) try coff.symbol_table.pending.ensureUnusedCapacity(gpa, 1);
3185 const sym = si.get(coff);3259 const sym = si.get(coff);
3186 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{3260 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
3187 .alignment = uav_align.toStdMem(),3261 .alignment = uav_align.toStdMem(),
...@@ -3200,8 +3274,8 @@ fn flushUav(...@@ -3200,8 +3274,8 @@ fn flushUav(
3200 const sym = si.get(coff);3274 const sym = si.get(coff);
3201 assert(sym.loc_relocs == .none);3275 assert(sym.loc_relocs == .none);
3202 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);3276 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
3203 if (sym.target_relocs != .none)3277 if (!isImage(coff) and sym.target_relocs != .none)
3204 _ = try coff.updateSymbolTableEntry(si);3278 try coff.pendingSymbolTableEntry(si);
32053279
3206 break :ni sym.ni;3280 break :ni sym.ni;
3207 };3281 };
...@@ -3232,7 +3306,8 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {...@@ -3232,7 +3306,8 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
32323306
3233 if (!coff.isImage()) {3307 if (!coff.isImage()) {
3234 const si = gmi.symbol(coff);3308 const si = gmi.symbol(coff);
3235 assert(try coff.updateSymbolTableEntry(si) != .none);3309 try coff.pendingSymbolTableEntry(si);
3310
3236 if (si.get(coff).ni != .none)3311 if (si.get(coff).ni != .none)
3237 try coff.ensureMemberSymbol(3312 try coff.ensureMemberSymbol(
3238 gn.name,3313 gn.name,
...@@ -3429,6 +3504,9 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -3429,6 +3504,9 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
3429 }3504 }
3430 assert(sym.loc_relocs == .none);3505 assert(sym.loc_relocs == .none);
3431 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);3506 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
3507 if (!isImage(coff) and sym.target_relocs != .none)
3508 try coff.pendingSymbolTableEntry(si);
3509
3432 break :ni sym.ni;3510 break :ni sym.ni;
3433 };3511 };
34343512
...@@ -3464,15 +3542,20 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -3464,15 +3542,20 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
3464 .data_directories,3542 .data_directories,
3465 .section_table,3543 .section_table,
3466 .placeholder,3544 .placeholder,
3467 .symbol_table_entry, // TODO: Need to impl this for symbol table updates to work?3545 => if (coff.isImage()) unreachable,
3468 .string_table,
3469 => if (!coff.isArchive()) unreachable,
3470 .symbol_table => {3546 .symbol_table => {
3471 coff.targetStore(3547 coff.targetStore(
3472 &coff.headerPtr().pointer_to_symbol_table,3548 &coff.headerPtr().pointer_to_symbol_table,
3473 @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]),3549 @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]),
3474 );3550 );
3475 },3551 },
3552 .string_table => {
3553 if (!coff.symbol_table.pending_shrink) {
3554 const symbol_table_loc, const symbol_table_size = coff.symbol_table.ni.location(&coff.mf).resolve(&coff.mf);
3555 const string_table_offset, _ = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf);
3556 coff.symbol_table.pending_shrink = string_table_offset - (symbol_table_loc + symbol_table_size) > 0;
3557 }
3558 },
3476 .relocation_table => |sn| {3559 .relocation_table => |sn| {
3477 coff.targetStore(3560 coff.targetStore(
3478 &sn.header(coff).pointer_to_relocations,3561 &sn.header(coff).pointer_to_relocations,
...@@ -3621,7 +3704,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -3621,7 +3704,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
3621}3704}
36223705
3623fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {3706fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
3624 _, const size = ni.location(&coff.mf).resolve(&coff.mf);3707 const offset, const size = ni.location(&coff.mf).resolve(&coff.mf);
3625 log.debug("flushResized({s}, 0x{x})", .{ @tagName(coff.getNode(ni)), size });3708 log.debug("flushResized({s}, 0x{x})", .{ @tagName(coff.getNode(ni)), size });
36263709
3627 switch (coff.getNode(ni)) {3710 switch (coff.getNode(ni)) {
...@@ -3657,7 +3740,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -3657,7 +3740,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
3657 .archive_member => |mi| {3740 .archive_member => |mi| {
3658 const content_ni = mi.get(coff).content_ni;3741 const content_ni = mi.get(coff).content_ni;
3659 const next_ni = content_ni.next(&coff.mf);3742 const next_ni = content_ni.next(&coff.mf);
3660 const offset, _ = content_ni.location(&coff.mf).resolve(&coff.mf);3743 const content_offset, _ = content_ni.location(&coff.mf).resolve(&coff.mf);
3661 const next_offset = switch (next_ni) {3744 const next_offset = switch (next_ni) {
3662 .none => offset: {3745 .none => offset: {
3663 assert(content_ni.parent(&coff.mf) == Node.known.file);3746 assert(content_ni.parent(&coff.mf) == Node.known.file);
...@@ -3672,15 +3755,22 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -3672,15 +3755,22 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
3672 };3755 };
36733756
3674 // Not inserting IMAGE_ARCHIVE_PAD `\n` byte here, because we are expanding to full size3757 // Not inserting IMAGE_ARCHIVE_PAD `\n` byte here, because we are expanding to full size
3675 Member.storeHeaderDecimalStr(&mi.get(coff).headerPtr(coff).size, next_offset - offset);3758 Member.storeHeaderDecimalStr(&mi.get(coff).headerPtr(coff).size, next_offset - content_offset);
3676 },3759 },
3677 .coff_header,3760 .coff_header,
3678 .optional_header,3761 .optional_header,
3679 .data_directories,3762 .data_directories,
3680 => unreachable,3763 => unreachable,
3681 .section_table => {},3764 .section_table => {},
3682 .symbol_table => assert(!coff.isImage()),3765 .symbol_table => {
3683 .symbol_table_entry => unreachable,3766 assert(!coff.isImage());
3767 if (!coff.symbol_table.pending_shrink) {
3768 const string_table_offset, _ = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf);
3769 coff.symbol_table.pending_shrink =
3770 size > coff.targetLoad(&coff.headerPtr().number_of_symbols) * std.coff.Symbol.sizeOf() or
3771 string_table_offset - (offset + size) > 0;
3772 }
3773 },
3684 .string_table => {3774 .string_table => {
3685 assert(!coff.isImage());3775 assert(!coff.isImage());
3686 coff.targetStore(coff.symbolTableStringLenPtr(), @intCast(size));3776 coff.targetStore(coff.symbolTableStringLenPtr(), @intCast(size));
...@@ -3904,17 +3994,18 @@ fn updateExportsInner(...@@ -3904,17 +3994,18 @@ fn updateExportsInner(
3904 export_sym.rva = exported_sym.rva;3994 export_sym.rva = exported_sym.rva;
3905 export_sym.size = exported_sym.size;3995 export_sym.size = exported_sym.size;
3906 export_sym.section_number = exported_sym.section_number;3996 export_sym.section_number = exported_sym.section_number;
3907 export_si.applyTargetRelocs(coff);3997 defer export_si.applyTargetRelocs(coff);
3908 if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) {3998
3909 coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva;3999 if (isImage(coff)) {
3910 } else if (@"export".opts.name.eqlSlice("_tls_used", ip)) {4000 if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) {
3911 const tls_directory = coff.dataDirectoryPtr(.TLS);4001 coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva;
3912 tls_directory.* = .{ .virtual_address = exported_sym.rva, .size = exported_sym.size };4002 } else if (@"export".opts.name.eqlSlice("_tls_used", ip)) {
3913 if (coff.targetEndian() != native_endian)4003 const tls_directory = coff.dataDirectoryPtr(.TLS);
3914 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);4004 tls_directory.* = .{ .virtual_address = exported_sym.rva, .size = exported_sym.size };
3915 }4005 if (coff.targetEndian() != native_endian)
39164006 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);
3917 if (coff.export_table.ni == .none) continue;4007 }
4008 } else continue;
39184009
3919 const entries_ctx = ExportTable.Adapter{ .coff = coff };4010 const entries_ctx = ExportTable.Adapter{ .coff = coff };
3920 const gop = try coff.export_table.entries.getOrPutAdapted(4011 const gop = try coff.export_table.entries.getOrPutAdapted(
...@@ -4002,7 +4093,6 @@ fn updateExportsInner(...@@ -4002,7 +4093,6 @@ fn updateExportsInner(
4002 gop.value_ptr.si = export_si;4093 gop.value_ptr.si = export_si;
4003 const reloc = gop.value_ptr.*.export_address_table_ri.get(coff);4094 const reloc = gop.value_ptr.*.export_address_table_ri.get(coff);
4004 reloc.target = export_si;4095 reloc.target = export_si;
4005 export_si.applyTargetRelocs(coff); // TODO: Potentially doing this twice, defer first one?
4006 }4096 }
4007 }4097 }
4008}4098}