authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:36-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:27:16-04:00
log7be8e660acaa56d2be110d59b058ff2a31b05e23
tree73d3c9f58ba6266373eb40474032b27d98d0ece4
parent2c3f42724d5131d826674357cecb5731d858ad27

Coff: value / extra rework to allow symbols to have both an alias and symbol table entry

Coff: move pending_shrink handling to flush, as it's a special case of a resolve task that generates idle tasks (moves / resizes). It's also redundant to do this operation more than once.

1 files changed, 152 insertions(+), 108 deletions(-)

src/link/Coff.zig+152-108
...@@ -874,14 +874,15 @@ pub const Symbol = struct {...@@ -874,14 +874,15 @@ pub const Symbol = struct {
874 ni: MappedFile.Node.Index,874 ni: MappedFile.Node.Index,
875 rva: u32,875 rva: u32,
876 value: std.meta.BareUnion(Symbol.Value),876 value: std.meta.BareUnion(Symbol.Value),
877 extra: std.meta.BareUnion(Symbol.Extra),
877 flags: packed struct(u16) {878 flags: packed struct(u16) {
878 value_tag: ValueTag,879 value_tag: ValueTag,
880 extra_tag: ExtraTag,
879 type: Symbol.Type,881 type: Symbol.Type,
880 dll_storage_class: DllStorageClass,882 dll_storage_class: DllStorageClass,
881 // Only defined for .alias_si and .alias_name883 // Only defined for .alias_si and .alias_name
882 weak_external_strat: WeakExternalStrat,884 weak_external_strat: WeakExternalStrat,
883 has_alias: bool,885 _: u6 = 0,
884 _: u7 = 0,
885 },886 },
886 /// Relocations contained within this symbol887 /// Relocations contained within this symbol
887 loc_relocs: Reloc.Index,888 loc_relocs: Reloc.Index,
...@@ -889,16 +890,6 @@ pub const Symbol = struct {...@@ -889,16 +890,6 @@ pub const Symbol = struct {
889 target_relocs: Reloc.Index,890 target_relocs: Reloc.Index,
890 section_number: SectionNumber,891 section_number: SectionNumber,
891 gmi: Node.GlobalMapIndex,892 gmi: Node.GlobalMapIndex,
892 extra: union {
893 /// Only valid when outputting objects
894 sti: SymbolTable.Index,
895 /// Only valid when .ni == .input_section and .value_tag == .node_offset
896 /// TODO: This is only used for name lookups, could just be String?
897 isli: Node.InputSection.LocalIndex,
898 /// Only valid if flags.has_alias is set.
899 /// The next symbol in the list of aliases of this symbol.
900 next_alias_si: Symbol.Index,
901 },
902893
903 pub const DllStorageClass = enum(u2) {894 pub const DllStorageClass = enum(u2) {
904 default,895 default,
...@@ -916,23 +907,41 @@ pub const Symbol = struct {...@@ -916,23 +907,41 @@ pub const Symbol = struct {
916 node_offset,907 node_offset,
917 weak_alias_si,908 weak_alias_si,
918 weak_alias_name,909 weak_alias_name,
919 size,910 sti,
920 };911 };
921912
922 pub const Value = union(ValueTag) {913 pub const Value = union(ValueTag) {
923 /// The offset of the symbol within its node. Used with symbols that914 /// The offset of the symbol within its node. Used with symbols that
924 /// don't create their own nodes: .input_section, .import_address_table915 /// don't create their own nodes: .input_section, .import_address_table
916 /// Images only.
925 node_offset: u32,917 node_offset: u32,
926 /// This is a weak alias that can replace this symbol918 /// This is a weak alias that can replace this symbol
927 /// Globals only.919 /// Globals only, images only.
928 weak_alias_si: Symbol.Index,920 weak_alias_si: Symbol.Index,
929 /// For weak externals that have an alias that is also an undef921 /// For weak externals that have an alias that is also an undef
930 /// external, this is the name of the alias global that should922 /// external, this is the name of the alias global that should
931 /// be generated if this symbol is not resolved.923 /// be generated if this symbol is not resolved.
932 /// Globals only.924 /// Globals only, images only.
933 weak_alias_name: String,925 weak_alias_name: String,
934 /// The symbol size, or 0 if unknown926 /// Index of this symbol in the symbol table
927 /// Only used when outputting objects
928 sti: SymbolTable.Index,
929 };
930
931 const ExtraTag = enum(u2) {
932 size,
933 isli,
934 next_alias_si,
935 };
936
937 pub const Extra = union(ExtraTag) {
938 // The size of the symbol
935 size: u32,939 size: u32,
940 /// Only valid when .ni == .input_section and .value_tag == .node_offset
941 /// TODO: This is only used for name lookups, could just be String?
942 isli: Node.InputSection.LocalIndex,
943 /// The next symbol in the list of aliases of this symbol.
944 next_alias_si: Symbol.Index,
936 };945 };
937946
938 pub fn setValue(sym: *Symbol, value: Symbol.Value) void {947 pub fn setValue(sym: *Symbol, value: Symbol.Value) void {
...@@ -946,6 +955,17 @@ pub const Symbol = struct {...@@ -946,6 +955,17 @@ pub const Symbol = struct {
946 };955 };
947 }956 }
948957
958 pub fn setExtra(sym: *Symbol, extra: Symbol.Extra) void {
959 sym.flags.extra_tag = std.meta.activeTag(extra);
960 sym.extra = switch (sym.flags.extra_tag) {
961 inline else => |t| @unionInit(
962 @FieldType(Symbol, "extra"),
963 @tagName(t),
964 @field(extra, @tagName(t)),
965 ),
966 };
967 }
968
949 pub fn nodeOffset(sym: *const Symbol, coff: *Coff) u32 {969 pub fn nodeOffset(sym: *const Symbol, coff: *Coff) u32 {
950 return switch (sym.flags.value_tag) {970 return switch (sym.flags.value_tag) {
951 .node_offset => offset: {971 .node_offset => offset: {
...@@ -961,7 +981,7 @@ pub const Symbol = struct {...@@ -961,7 +981,7 @@ pub const Symbol = struct {
961 }981 }
962982
963 pub fn size(sym: *const Symbol) u32 {983 pub fn size(sym: *const Symbol) u32 {
964 return if (sym.flags.value_tag == .size) sym.value.size else 0;984 return if (sym.flags.extra_tag == .size) sym.extra.size else 0;
965 }985 }
966986
967 pub const SectionNumber = enum(i16) {987 pub const SectionNumber = enum(i16) {
...@@ -1038,7 +1058,7 @@ pub const Symbol = struct {...@@ -1038,7 +1058,7 @@ pub const Symbol = struct {
1038 si.applyTargetRelocs(coff, .none);1058 si.applyTargetRelocs(coff, .none);
10391059
1040 var alias_sym = sym;1060 var alias_sym = sym;
1041 while (alias_sym.flags.has_alias) {1061 while (alias_sym.flags.extra_tag == .next_alias_si) {
1042 const alias_si = alias_sym.extra.next_alias_si;1062 const alias_si = alias_sym.extra.next_alias_si;
1043 alias_sym = alias_si.get(coff);1063 alias_sym = alias_si.get(coff);
1044 assert(alias_sym.ni == sym.ni);1064 assert(alias_sym.ni == sym.ni);
...@@ -1049,7 +1069,7 @@ pub const Symbol = struct {...@@ -1049,7 +1069,7 @@ pub const Symbol = struct {
10491069
1050 pub fn flushSymbolTableIndex(si: Symbol.Index, coff: *Coff) void {1070 pub fn flushSymbolTableIndex(si: Symbol.Index, coff: *Coff) void {
1051 const sym = si.get(coff);1071 const sym = si.get(coff);
1052 const index = sym.extra.sti.unwrap() orelse return;1072 const index = sym.value.sti.unwrap() orelse return;
1053 var ri = sym.target_relocs;1073 var ri = sym.target_relocs;
1054 while (ri != .none) {1074 while (ri != .none) {
1055 const reloc = ri.get(coff);1075 const reloc = ri.get(coff);
...@@ -1989,6 +2009,7 @@ fn initHeaders(...@@ -1989,6 +2009,7 @@ fn initHeaders(
1989 .resized = true,2009 .resized = true,
1990 });2010 });
1991 coff.nodes.appendAssumeCapacity(.string_table);2011 coff.nodes.appendAssumeCapacity(.string_table);
2012 coff.targetStore(coff.symbolTableStringLenPtr(), @sizeOf(u32));
1992 }2013 }
19932014
1994 try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count);2015 try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count);
...@@ -2193,8 +2214,7 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2193,8 +2214,7 @@ pub fn initBuiltins(coff: *Coff) !void {
2193 list_sym.ni = start_sym.ni;2214 list_sym.ni = start_sym.ni;
2194 list_sym.section_number = start_sym.section_number;2215 list_sym.section_number = start_sym.section_number;
21952216
2196 start_sym.extra = .{ .next_alias_si = list_si };2217 start_sym.setExtra(.{ .next_alias_si = list_si });
2197 start_sym.flags.has_alias = true;
2198 }2218 }
2199 }2219 }
2200}2220}
...@@ -2483,11 +2503,14 @@ pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.c...@@ -2483,11 +2503,14 @@ pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.c
2483 return null;2503 return null;
2484}2504}
24852505
2486pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, si: Symbol.Index) *align(2) std.coff.SectionDefinition {2506pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, si: Symbol.Index) ?*align(2) std.coff.SectionDefinition {
2487 const sti = si.get(coff).extra.sti;2507 const sti = si.get(coff).value.sti;
2488 const entry = symbolTableEntryPtr(coff, sti).?;2508 if (symbolTableEntryPtr(coff, sti)) |entry| {
2489 assert(entry.storage_class == .STATIC and entry.number_of_aux_symbols == 1);2509 assert(entry.storage_class == .STATIC and entry.number_of_aux_symbols == 1);
2490 return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, sti.unwrap().? + 1)));2510 return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, sti.unwrap().? + 1)));
2511 } else {
2512 return null;
2513 }
2491}2514}
24922515
2493pub fn symbolTableStringLenPtr(coff: *Coff) *align(1) u32 {2516pub fn symbolTableStringLenPtr(coff: *Coff) *align(1) u32 {
...@@ -2524,19 +2547,19 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {...@@ -2524,19 +2547,19 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
2524 defer coff.symbols.addOneAssumeCapacity().* = .{2547 defer coff.symbols.addOneAssumeCapacity().* = .{
2525 .ni = .none,2548 .ni = .none,
2526 .rva = 0,2549 .rva = 0,
2527 .value = .{ .size = 0 },2550 .value = .{ .sti = .none },
2551 .extra = .{ .size = 0 },
2528 .flags = .{2552 .flags = .{
2529 .value_tag = .size,2553 .value_tag = .sti,
2554 .extra_tag = .size,
2530 .type = .unknown,2555 .type = .unknown,
2531 .dll_storage_class = .default,2556 .dll_storage_class = .default,
2532 .weak_external_strat = undefined,2557 .weak_external_strat = undefined,
2533 .has_alias = false,
2534 },2558 },
2535 .loc_relocs = .none,2559 .loc_relocs = .none,
2536 .target_relocs = .none,2560 .target_relocs = .none,
2537 .section_number = .UNDEFINED,2561 .section_number = .UNDEFINED,
2538 .gmi = .none,2562 .gmi = .none,
2539 .extra = .{ .sti = .none },
2540 };2563 };
2541 return @enumFromInt(coff.symbols.items.len);2564 return @enumFromInt(coff.symbols.items.len);
2542}2565}
...@@ -2975,7 +2998,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -2975,7 +2998,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
2975 const sym = si.get(coff);2998 const sym = si.get(coff);
2976 assert(sym.ni != .none or sym.gmi != .none);2999 assert(sym.ni != .none or sym.gmi != .none);
29773000
2978 const entry = coff.symbolTableEntryPtr(sym.extra.sti) orelse entry: {3001 const entry = coff.symbolTableEntryPtr(sym.value.sti) orelse entry: {
2979 var buf: [15]u8 = undefined;3002 var buf: [15]u8 = undefined;
2980 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =3003 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =
2981 if (sym.gmi != .none) blk: {3004 if (sym.gmi != .none) blk: {
...@@ -3040,10 +3063,11 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -3040,10 +3063,11 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
3040 try coff.symbol_table.ni.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());3063 try coff.symbol_table.ni.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());
30413064
3042 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);3065 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
3043 sym.extra = .{ .sti = .wrap(old_num_symbols) };3066
3067 sym.value.sti = .wrap(old_num_symbols);
3044 si.flushSymbolTableIndex(coff);3068 si.flushSymbolTableIndex(coff);
30453069
3046 const entry = coff.symbolTableEntryPtr(sym.extra.sti).?;3070 const entry = coff.symbolTableEntryPtr(sym.value.sti).?;
3047 symbol_name.store(coff, &entry.name);3071 symbol_name.store(coff, &entry.name);
30483072
3049 entry.section_number = @enumFromInt(@intFromEnum(sym.section_number));3073 entry.section_number = @enumFromInt(@intFromEnum(sym.section_number));
...@@ -3056,8 +3080,31 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -3056,8 +3080,31 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
3056 if (coff.targetEndian() != native_endian)3080 if (coff.targetEndian() != native_endian)
3057 std.mem.byteSwapAllFieldsAligned(std.coff.Symbol, .@"2", entry);3081 std.mem.byteSwapAllFieldsAligned(std.coff.Symbol, .@"2", entry);
30583082
3059 for (1..num_aux_symbols + 1) |aux_index|3083 if (num_aux_symbols > 0) aux_init: {
3060 @memset(coff.symbolTableEntryStoragePtr(@intCast(old_num_symbols + aux_index)), 0);3084 if (sym.gmi == .none) switch (coff.getNode(sym.ni)) {
3085 .image_section => |sec_si| {
3086 assert(si == sec_si);
3087 const header = sym.section_number.header(coff);
3088 const aux_ptr = coff.symbolTableSectionAuxEntryPtr(si).?;
3089 aux_ptr.* = .{
3090 .length = @intCast(sym.ni.location(&coff.mf).resolve(&coff.mf)[1]),
3091 .number_of_relocations = header.number_of_relocations,
3092 .number_of_linenumbers = header.number_of_linenumbers,
3093 .checksum = 0,
3094 .number = 0,
3095 .selection = .NONE,
3096 .unused = @splat(0),
3097 };
3098 if (coff.targetEndian() != native_endian)
3099 std.mem.byteSwapAllFields(std.coff.SectionDefinition, .@"2", aux_ptr);
3100
3101 break :aux_init;
3102 },
3103 else => {},
3104 };
3105
3106 unreachable;
3107 }
30613108
3062 break :entry entry;3109 break :entry entry;
3063 };3110 };
...@@ -3073,7 +3120,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -3073,7 +3120,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
3073 },3120 },
3074 });3121 });
30753122
3076 log.debug("flushSymbolTableEntry({d}) = {d}", .{ si, sym.extra.sti });3123 log.debug("flushSymbolTableEntry({d}) = {d}", .{ si, sym.value.sti });
3077}3124}
30783125
3079fn flushInputMember(coff: *Coff, iami: InputArchive.Member.Index) !void {3126fn flushInputMember(coff: *Coff, iami: InputArchive.Member.Index) !void {
...@@ -3478,8 +3525,8 @@ pub fn addReloc(...@@ -3478,8 +3525,8 @@ pub fn addReloc(
3478 else => |loc_sn| sri: {3525 else => |loc_sn| sri: {
3479 // The target may not have a node yet, or it could be an extern that will never3526 // The target may not have a node yet, or it could be an extern that will never
3480 // have a node. In that case, flushGlobal will create the symbol table entry.3527 // have a node. In that case, flushGlobal will create the symbol table entry.
3481 const sti: SymbolTable.Index = if (target.extra.sti != .none)3528 const sti: SymbolTable.Index = if (target.value.sti != .none)
3482 target.extra.sti3529 target.value.sti
3483 else if (target.ni != .none) sti: {3530 else if (target.ni != .none) sti: {
3484 try coff.pendingSymbolTableEntry(target_si);3531 try coff.pendingSymbolTableEntry(target_si);
3485 break :sti .none;3532 break :sti .none;
...@@ -3503,14 +3550,9 @@ pub fn addReloc(...@@ -3503,14 +3550,9 @@ pub fn addReloc(
3503 try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);3550 try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);
3504 }3551 }
35053552
3506 coff.targetStore(3553 coff.targetStore(&header.number_of_relocations, new_num_relocations);
3507 &header.number_of_relocations,3554 if (coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff))) |aux_ptr|
3508 new_num_relocations,3555 coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);
3509 );
3510 coff.targetStore(
3511 &coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff)).number_of_relocations,
3512 new_num_relocations,
3513 );
35143556
3515 // TODO: These need to allocate from a free list (once deleting relocs is supported) (or can we just remove swap?)3557 // TODO: These need to allocate from a free list (once deleting relocs is supported) (or can we just remove swap?)
3516 const sri: Section.RelocationIndex = .wrap(old_num_relocations);3558 const sri: Section.RelocationIndex = .wrap(old_num_relocations);
...@@ -3643,7 +3685,7 @@ fn loadObject(...@@ -3643,7 +3685,7 @@ fn loadObject(
36433685
3644 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberNameString(member_name) });3686 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberNameString(member_name) });
36453687
3646 const header = try r.peekStruct(std.coff.Header, .little());3688 const header = try r.peekStruct(std.coff.Header, .little);
3647 if (header.machine != target.toCoffMachine())3689 if (header.machine != target.toCoffMachine())
3648 return diags.failParse(path, "machine mismatch: expected {t}, found {t}", .{3690 return diags.failParse(path, "machine mismatch: expected {t}, found {t}", .{
3649 target.toCoffMachine(),3691 target.toCoffMachine(),
...@@ -3678,7 +3720,7 @@ fn loadObject(...@@ -3678,7 +3720,7 @@ fn loadObject(
3678 const string_table_len = try r.peekInt(u32, target_endian);3720 const string_table_len = try r.peekInt(u32, target_endian);
3679 if (string_table_len < @sizeOf(u32) or3721 if (string_table_len < @sizeOf(u32) or
3680 symbol_table_end + string_table_len > fl.size)3722 symbol_table_end + string_table_len > fl.size)
3681 return diags.failParse(path, "bad string table", .{});3723 return diags.failParse(path, "bad string table length: 0x{x}", .{string_table_len});
36823724
3683 const ioi: InputObject.Index = @enumFromInt(coff.input_objects.items.len);3725 const ioi: InputObject.Index = @enumFromInt(coff.input_objects.items.len);
3684 try coff.input_objects.ensureUnusedCapacity(gpa, 1);3726 try coff.input_objects.ensureUnusedCapacity(gpa, 1);
...@@ -4519,17 +4561,18 @@ fn loadObject(...@@ -4519,17 +4561,18 @@ fn loadObject(
4519 const sym = symbol.si.get(coff);4561 const sym = symbol.si.get(coff);
4520 assert(sym.ni == .none);4562 assert(sym.ni == .none);
4521 sym.ni = section.si.get(coff).ni;4563 sym.ni = section.si.get(coff).ni;
4522 sym.setValue(switch (symbol.value) {4564 switch (symbol.value) {
4523 .section => |v| .{ .size = v },4565 .section => |v| sym.setExtra(.{ .size = v }),
4524 .static => |v| .{ .node_offset = v },4566 .static => |v| sym.setValue(.{ .node_offset = v }),
4525 .external => |v| switch (symbol.section_number) {4567 .external => |v| switch (symbol.section_number) {
4526 .UNDEFINED, .ABSOLUTE, .DEBUG => unreachable,4568 .UNDEFINED, .ABSOLUTE, .DEBUG => unreachable,
4527 else => .{ .node_offset = v },4569 else => sym.setValue(.{ .node_offset = v }),
4528 },4570 },
4529 .weak_external,4571 .weak_external,
4530 .weak_external_aux,4572 .weak_external_aux,
4531 => unreachable,4573 => unreachable,
4532 });4574 }
4575
4533 sym.section_number = section.si.get(coff).section_number;4576 sym.section_number = section.si.get(coff).section_number;
4534 }4577 }
4535 }4578 }
...@@ -4572,7 +4615,7 @@ fn loadObject(...@@ -4572,7 +4615,7 @@ fn loadObject(
4572 symbol.si = global_gop.value_ptr.*;4615 symbol.si = global_gop.value_ptr.*;
4573 if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) {4616 if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) {
4574 const sym = symbol.si.get(coff);4617 const sym = symbol.si.get(coff);
4575 sym.setValue(.{ .size = @max(sym.size(), size) });4618 sym.setExtra(.{ .size = @max(sym.size(), size) });
4576 }4619 }
4577 },4620 },
4578 else => unreachable,4621 else => unreachable,
...@@ -5156,12 +5199,12 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -5156,12 +5199,12 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
5156 error.WriteFailed => return nw.err.?,5199 error.WriteFailed => return nw.err.?,
5157 else => |e| return e,5200 else => |e| return e,
5158 };5201 };
5159 si.get(coff).value.size = @intCast(nw.interface.end);5202 si.get(coff).extra.size = @intCast(nw.interface.end);
5160 si.applyLocationRelocs(coff);5203 si.applyLocationRelocs(coff);
5161 }5204 }
51625205
5163 if (nav.resolved.?.@"linksection".unwrap()) |_| {5206 if (nav.resolved.?.@"linksection".unwrap()) |_| {
5164 try ni.resize(&coff.mf, gpa, si.get(coff).value.size);5207 try ni.resize(&coff.mf, gpa, si.get(coff).extra.size);
5165 var parent_ni = ni;5208 var parent_ni = ni;
5166 while (true) {5209 while (true) {
5167 parent_ni = parent_ni.parent(&coff.mf);5210 parent_ni = parent_ni.parent(&coff.mf);
...@@ -5289,7 +5332,7 @@ fn updateFuncInner(...@@ -5289,7 +5332,7 @@ fn updateFuncInner(
5289 error.WriteFailed => return nw.err.?,5332 error.WriteFailed => return nw.err.?,
5290 else => |e| return e,5333 else => |e| return e,
5291 };5334 };
5292 si.get(coff).value.size = @intCast(nw.interface.end);5335 si.get(coff).extra.size = @intCast(nw.interface.end);
5293 si.applyLocationRelocs(coff);5336 si.applyLocationRelocs(coff);
5294}5337}
52955338
...@@ -5533,6 +5576,7 @@ pub fn flush(...@@ -5533,6 +5576,7 @@ pub fn flush(
5533) !void {5576) !void {
5534 _ = arena;5577 _ = arena;
5535 _ = prog_node;5578 _ = prog_node;
5579 const comp = coff.base.comp;
55365580
5537 // TODO: When https://github.com/ziglang/zig/issues/23617 is in,5581 // TODO: When https://github.com/ziglang/zig/issues/23617 is in,
5538 // this should be set after updateExports instead5582 // this should be set after updateExports instead
...@@ -5541,11 +5585,30 @@ pub fn flush(...@@ -5541,11 +5585,30 @@ pub fn flush(
5541 while (try coff.resolve(tid)) {}5585 while (try coff.resolve(tid)) {}
5542 while (try coff.idle(tid)) {}5586 while (try coff.idle(tid)) {}
55435587
5588 // This has to occur after all other flushMoved / flushResized have resolved,
5589 // but it will also generate one more set of resizes and moves.
5590 if (coff.symbol_table.pending_shrink) {
5591 coff.symbol_table.pending_shrink = false;
5592
5593 const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
5594 coff.symbol_table.ni.shrink(
5595 &coff.mf,
5596 comp.gpa,
5597 number_of_symbols * std.coff.Symbol.sizeOf(),
5598 true,
5599 ) catch |err| switch (err) {
5600 error.OutOfMemory => return error.OutOfMemory,
5601 else => |e| return comp.link_diags.fail(
5602 "linker failed to compact symbol table: {t}",
5603 .{e},
5604 ),
5605 };
5606 }
5607 while (try coff.idle(tid)) {}
5608
5544 if (coff.isImage())5609 if (coff.isImage())
5545 try coff.reportUndefs(tid);5610 try coff.reportUndefs(tid);
55465611
5547 const comp = coff.base.comp;
5548
5549 // Implib generation should instead be done via building a MappedFile progressively5612 // Implib generation should instead be done via building a MappedFile progressively
5550 if (comp.emit_implib) |implib_file|5613 if (comp.emit_implib) |implib_file|
5551 coff.flushImplib(implib_file) catch |err|5614 coff.flushImplib(implib_file) catch |err|
...@@ -5717,31 +5780,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -5717,31 +5780,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
5717 };5780 };
5718 break :task;5781 break :task;
5719 }5782 }
5720 if (coff.symbol_table.pending_shrink) {
5721 defer coff.symbol_table.pending_shrink = false;
5722 const sub_prog_node = coff.idleProgNode(
5723 tid,
5724 coff.symbol_prog_node,
5725 coff.getNode(coff.symbol_table.ni),
5726 );
5727 defer sub_prog_node.end();
5728
5729 const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
5730 coff.symbol_table.ni.shrink(
5731 &coff.mf,
5732 comp.gpa,
5733 number_of_symbols * std.coff.Symbol.sizeOf(),
5734 true,
5735 ) catch |err| switch (err) {
5736 error.OutOfMemory => return error.OutOfMemory,
5737 else => |e| return comp.link_diags.fail(
5738 "linker failed to compact symbol table: {t}",
5739 .{e},
5740 ),
5741 };
5742
5743 break :task;
5744 }
5745 }5783 }
57465784
5747 if (coff.section_merge_pending_index < coff.section_merges.count()) return true;5785 if (coff.section_merge_pending_index < coff.section_merges.count()) return true;
...@@ -5753,7 +5791,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -5753,7 +5791,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
5753 if (coff.exports_complete and coff.pending_special_symbol != .none) return true;5791 if (coff.exports_complete and coff.pending_special_symbol != .none) return true;
5754 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;5792 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
5755 if (coff.symbol_table.pending.count() > 0) return true;5793 if (coff.symbol_table.pending.count() > 0) return true;
5756 if (coff.symbol_table.pending_shrink) return true;
5757 return false;5794 return false;
5758}5795}
57595796
...@@ -5922,7 +5959,7 @@ fn flushUav(...@@ -5922,7 +5959,7 @@ fn flushUav(
5922 error.WriteFailed => return nw.err.?,5959 error.WriteFailed => return nw.err.?,
5923 else => |e| return e,5960 else => |e| return e,
5924 };5961 };
5925 si.get(coff).value.size = @intCast(nw.interface.end);5962 si.get(coff).extra.size = @intCast(nw.interface.end);
5926 si.applyLocationRelocs(coff);5963 si.applyLocationRelocs(coff);
5927}5964}
59285965
...@@ -6358,7 +6395,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6358,7 +6395,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6358 });6395 });
6359 @memcpy(ni.slice(&coff.mf)[0..init.len], &init);6396 @memcpy(ni.slice(&coff.mf)[0..init.len], &init);
6360 sym.ni = ni;6397 sym.ni = ni;
6361 sym.setValue(.{ .size = init.len });6398 sym.extra.size = init.len;
6362 try coff.addReloc(6399 try coff.addReloc(
6363 si,6400 si,
6364 init.len - 4,6401 init.len - 4,
...@@ -6539,7 +6576,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -6539,7 +6576,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
6539 error.WriteFailed => return nw.err.?,6576 error.WriteFailed => return nw.err.?,
6540 else => |e| return e,6577 else => |e| return e,
6541 };6578 };
6542 si.get(coff).value.size = @intCast(nw.interface.end);6579 si.get(coff).extra.size = @intCast(nw.interface.end);
6543 si.applyLocationRelocs(coff);6580 si.applyLocationRelocs(coff);
6544}6581}
65456582
...@@ -6556,13 +6593,15 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6556,13 +6593,15 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6556 .section_table,6593 .section_table,
6557 .placeholder,6594 .placeholder,
6558 => assert(!coff.isImage()),6595 => assert(!coff.isImage()),
6559 .symbol_table => {6596 .symbol_table,
6560 coff.targetStore(6597 .string_table,
6561 &coff.headerPtr().pointer_to_symbol_table,6598 => |_, tag| {
6562 @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]),6599 if (tag == .symbol_table)
6563 );6600 coff.targetStore(
6564 },6601 &coff.headerPtr().pointer_to_symbol_table,
6565 .string_table => {6602 @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]),
6603 );
6604
6566 if (!coff.symbol_table.pending_shrink) {6605 if (!coff.symbol_table.pending_shrink) {
6567 const symbol_table_loc, const symbol_table_size = coff.symbol_table.ni.location(&coff.mf).resolve(&coff.mf);6606 const symbol_table_loc, const symbol_table_size = coff.symbol_table.ni.location(&coff.mf).resolve(&coff.mf);
6568 const string_table_offset, _ = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf);6607 const string_table_offset, _ = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf);
...@@ -6822,10 +6861,8 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6822,10 +6861,8 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
6822 }6861 }
68236862
6824 if (!coff.isImage()) {6863 if (!coff.isImage()) {
6825 coff.targetStore(6864 if (coff.symbolTableSectionAuxEntryPtr(si)) |aux_ptr|
6826 &coff.symbolTableSectionAuxEntryPtr(si).length,6865 coff.targetStore(&aux_ptr.length, @intCast(size));
6827 @intCast(size),
6828 );
6829 }6866 }
6830 },6867 },
6831 .input_section => {},6868 .input_section => {},
...@@ -6853,7 +6890,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6853,7 +6890,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
6853 );6890 );
6854 }6891 }
68556892
6856 smi.symbol(coff).get(coff).value.size = @intCast(size);6893 smi.symbol(coff).get(coff).extra.size = @intCast(size);
6857 },6894 },
6858 .import_thunk,6895 .import_thunk,
6859 .nav,6896 .nav,
...@@ -7091,14 +7128,16 @@ fn updateExportsInner(...@@ -7091,14 +7128,16 @@ fn updateExportsInner(
7091 const export_sym = export_si.get(coff);7128 const export_sym = export_si.get(coff);
7092 export_sym.ni = exported_ni;7129 export_sym.ni = exported_ni;
7093 export_sym.rva = exported_sym.rva;7130 export_sym.rva = exported_sym.rva;
7094 export_sym.setValue(.{ .size = exported_sym.value.size });
7095 export_sym.section_number = exported_sym.section_number;7131 export_sym.section_number = exported_sym.section_number;
7096 defer export_si.applyTargetRelocs(coff, .none);7132 defer export_si.applyTargetRelocs(coff, .none);
70977133
7098 const prev_alias_sym = prev_alias_si.get(coff);7134 const prev_alias_sym = prev_alias_si.get(coff);
7099 assert(!prev_alias_sym.flags.has_alias);7135 switch (prev_alias_sym.flags.extra_tag) {
7100 prev_alias_sym.extra = .{ .next_alias_si = export_si };7136 .size => export_sym.setExtra(.{ .size = prev_alias_sym.extra.size }),
7101 prev_alias_sym.flags.has_alias = true;7137 else => unreachable,
7138 }
7139
7140 prev_alias_sym.setExtra(.{ .next_alias_si = export_si });
7102 prev_alias_si = export_si;7141 prev_alias_si = export_si;
71037142
7104 if (!coff.isImage()) continue;7143 if (!coff.isImage()) continue;
...@@ -7237,7 +7276,7 @@ fn printSection(coff: *Coff, w: *Io.Writer, name: String, si: Symbol.Index) !voi...@@ -7237,7 +7276,7 @@ fn printSection(coff: *Coff, w: *Io.Writer, name: String, si: Symbol.Index) !voi
7237 try w.print("{d:0>6}@{d:0>2} {x:08} n{d:0>8} | {s}\n", .{7276 try w.print("{d:0>6}@{d:0>2} {x:08} n{d:0>8} | {s}\n", .{
7238 si,7277 si,
7239 sym.section_number,7278 sym.section_number,
7240 if (sym.flags.value_tag == .size) sym.value.size else 0,7279 if (sym.flags.extra_tag == .size) sym.extra.size else 0,
7241 sym.ni,7280 sym.ni,
7242 name.toSlice(coff),7281 name.toSlice(coff),
7243 });7282 });
...@@ -7251,11 +7290,11 @@ fn printSymbol(...@@ -7251,11 +7290,11 @@ fn printSymbol(
7251) !void {7290) !void {
7252 const sym = si.get(coff);7291 const sym = si.get(coff);
7253 const node = coff.getNode(sym.ni);7292 const node = coff.getNode(sym.ni);
7254 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} n{d:0>8}+{x:08}:{t: <26} | {x:08} ", .{7293 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{t: <26} | {x:08} ", .{
7255 si,7294 si,
7256 sym.section_number,7295 sym.section_number,
7257 if (sym.flags.value_tag == .size)7296 if (sym.flags.extra_tag == .size)
7258 @as(u64, sym.value.size)7297 @as(u64, sym.extra.size)
7259 else if (sym.ni != .none)7298 else if (sym.ni != .none)
7260 sym.ni.location(&coff.mf).resolve(&coff.mf)[1]7299 sym.ni.location(&coff.mf).resolve(&coff.mf)[1]
7261 else7300 else
...@@ -7264,7 +7303,12 @@ fn printSymbol(...@@ -7264,7 +7303,12 @@ fn printSymbol(
7264 .weak_alias_name => "an",7303 .weak_alias_name => "an",
7265 .weak_alias_si => "as",7304 .weak_alias_si => "as",
7266 .node_offset => "no",7305 .node_offset => "no",
7306 .sti => "st",
7307 },
7308 switch (sym.flags.extra_tag) {
7267 .size => "sz",7309 .size => "sz",
7310 .isli => "li",
7311 .next_alias_si => "na",
7268 },7312 },
7269 switch (sym.flags.type) {7313 switch (sym.flags.type) {
7270 .unknown => "u",7314 .unknown => "u",