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
logf81bd30057d6a1d1d50851b65a644aa86296cd4c
tree0837dfb5cf66bfbc0e7af3d5a2bed7a172bcc871
parente7d452338c07fd1c8469ae78ed28451ee43089dc

Coff: Symbol table output


3 files changed, 393 insertions(+), 56 deletions(-)

lib/std/coff.zig+9-9
......@@ -658,7 +658,7 @@ pub const SectionHeader = extern struct {
658658 };
659659};
660660
661pub const Symbol = struct {
661pub const Symbol = extern struct {
662662 name: [8]u8,
663663 value: u32,
664664 section_number: SectionNumber,
......@@ -683,18 +683,18 @@ pub const Symbol = struct {
683683 }
684684};
685685
686pub const SectionNumber = enum(u16) {
686pub const SectionNumber = enum(i16) {
687687 /// The symbol record is not yet assigned a section.
688688 /// A value of zero indicates that a reference to an external symbol is defined elsewhere.
689689 /// A value of non-zero is a common symbol with a size that is specified by the value.
690690 UNDEFINED = 0,
691691
692692 /// The symbol has an absolute (non-relocatable) value and is not an address.
693 ABSOLUTE = 0xffff,
693 ABSOLUTE = -1,
694694
695695 /// The symbol provides general type or debugging information but does not correspond to a section.
696696 /// Microsoft tools use this setting along with .file records (storage class FILE).
697 DEBUG = 0xfffe,
697 DEBUG = -2,
698698 _,
699699};
700700
......@@ -866,7 +866,7 @@ pub const StorageClass = enum(u8) {
866866 _,
867867};
868868
869pub const FunctionDefinition = struct {
869pub const FunctionDefinition = extern struct {
870870 /// The symbol-table index of the corresponding .bf (begin function) symbol record.
871871 tag_index: u32,
872872
......@@ -885,7 +885,7 @@ pub const FunctionDefinition = struct {
885885 unused: [2]u8,
886886};
887887
888pub const SectionDefinition = struct {
888pub const SectionDefinition = extern struct {
889889 /// The size of section data; the same as SizeOfRawData in the section header.
890890 length: u32,
891891
......@@ -907,7 +907,7 @@ pub const SectionDefinition = struct {
907907 unused: [3]u8,
908908};
909909
910pub const FileDefinition = struct {
910pub const FileDefinition = extern struct {
911911 /// An ANSI string that gives the name of the source file.
912912 /// This is padded with nulls if it is less than the maximum length.
913913 file_name: [18]u8,
......@@ -918,7 +918,7 @@ pub const FileDefinition = struct {
918918 }
919919};
920920
921pub const WeakExternalDefinition = struct {
921pub const WeakExternalDefinition = extern struct {
922922 /// The symbol-table index of sym2, the symbol to be linked if sym1 is not found.
923923 tag_index: u32,
924924
......@@ -977,7 +977,7 @@ pub const ComdatSelection = enum(u8) {
977977 _,
978978};
979979
980pub const DebugInfoDefinition = struct {
980pub const DebugInfoDefinition = extern struct {
981981 unused_1: [4]u8,
982982
983983 /// The actual ordinal line number (1, 2, 3, and so on) within the source file, corresponding to the .bf or .ef record.
src/libs/mingw/implib.zig+1-1
......@@ -1012,7 +1012,7 @@ fn getShortImport(
10121012fn writeSymbol(writer: *std.Io.Writer, symbol: std.coff.Symbol) !void {
10131013 try writer.writeAll(&symbol.name);
10141014 try writer.writeInt(u32, symbol.value, .little);
1015 try writer.writeInt(u16, @intFromEnum(symbol.section_number), .little);
1015 try writer.writeInt(i16, @intFromEnum(symbol.section_number), .little);
10161016 try writer.writeInt(u8, @intFromEnum(symbol.type.base_type), .little);
10171017 try writer.writeInt(u8, @intFromEnum(symbol.type.complex_type), .little);
10181018 try writer.writeInt(u8, @intFromEnum(symbol.storage_class), .little);
src/link/Coff.zig+383-46
......@@ -30,6 +30,7 @@ lib_string_len: u64,
3030long_names_table: LongNamesTable,
3131import_table: ImportTable,
3232export_table: ExportTable,
33symbol_table: SymbolTable,
3334strings: std.HashMapUnmanaged(
3435 u32,
3536 void,
......@@ -37,10 +38,10 @@ strings: std.HashMapUnmanaged(
3738 std.hash_map.default_max_load_percentage,
3839),
3940string_bytes: std.ArrayList(u8),
40image_section_table: std.ArrayList(Symbol.Index),
41section_table: std.ArrayList(Symbol.Index),
4142pseudo_section_table: std.array_hash_map.Auto(String, Symbol.Index),
4243object_section_table: std.array_hash_map.Auto(String, Symbol.Index),
43symbol_table: std.ArrayList(Symbol),
44symbols: std.ArrayList(Symbol),
4445globals: std.array_hash_map.Auto(GlobalName, Symbol.Index),
4546global_pending_index: u32,
4647navs: std.array_hash_map.Auto(InternPool.Nav.Index, Symbol.Index),
......@@ -144,6 +145,7 @@ pub const Node = union(enum) {
144145 header,
145146 /// Images and archives only.
146147 signature,
148
147149 /// Archives only.
148150 archive_member_header: Member.Index,
149151 archive_member: Member.Index,
......@@ -154,15 +156,21 @@ pub const Node = union(enum) {
154156 /// Image only
155157 data_directories,
156158 section_table,
157 image_section: Symbol.Index,
159 // Archives and objects only
160 symbol_table,
161 symbol_table_entry,
162 // Archives and objects only
163 string_table,
164
165 image_section: Symbol.Index, // TODO: image_section -> section
158166
159 /// Only images contain imports
167 /// Images only
160168 import_directory_table,
161169 import_lookup_table: ImportTable.Index,
162170 import_address_table: ImportTable.Index,
163171 import_hint_name_table: ImportTable.Index,
164172
165 /// Only images contain exports
173 /// Images only
166174 export_directory_table,
167175 export_address_table,
168176 export_name_pointer_table,
......@@ -291,6 +299,8 @@ pub const Node = union(enum) {
291299 optional_header,
292300 data_directories,
293301 section_table,
302 symbol_table,
303 string_table,
294304 };
295305 var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined;
296306 const info = @typeInfo(Known).@"enum";
......@@ -436,6 +446,47 @@ pub const LongNamesTable = struct {
436446 };
437447};
438448
449pub const SymbolTable = struct {
450 string_offsets: std.AutoArrayHashMapUnmanaged(String, StringIndex),
451 entries: std.AutoArrayHashMapUnmanaged(Symbol.Index, Entry),
452
453 // Adding nodes to the symbol table has the result of accumulating padding
454 // between the last symbol and the string table, due to the growth factor
455 // in MappedFile. The spec requires the string table begin immediately
456 // after the last symbol, so we compact the symbol table node if needed.
457 pending_shrink: bool,
458
459 pub const Entry = struct {
460 entry_si: Symbol.Index,
461 index: Index,
462 };
463
464 pub const Add = union(enum) {
465 section,
466 global: struct {
467 import: bool,
468 },
469 };
470
471 pub const SymbolName = union(enum) {
472 short: []const u8,
473 long: StringIndex,
474 };
475
476 // Symbol.Index does not map 1:1 with SymbolTable.Index due to auxiliary entries
477 pub const Index = enum(u32) {
478 _,
479
480 pub fn get(sti: SymbolTable.Index, coff: *Coff) *Entry {
481 return &coff.symbol_table.entries.values()[@intFromEnum(sti)];
482 }
483 };
484
485 pub const StringIndex = enum(u32) {
486 _,
487 };
488};
489
439490pub const ExportTable = struct {
440491 ni: MappedFile.Node.Index,
441492 export_directory_table_ni: MappedFile.Node.Index,
......@@ -582,7 +633,7 @@ pub const Symbol = struct {
582633 }
583634
584635 pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index {
585 return coff.image_section_table.items[sn.toIndex()];
636 return coff.section_table.items[sn.toIndex()];
586637 }
587638
588639 pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader {
......@@ -600,7 +651,7 @@ pub const Symbol = struct {
600651 const known_count = @typeInfo(Index).@"enum".field_names.len;
601652
602653 pub fn get(si: Symbol.Index, coff: *Coff) *Symbol {
603 return &coff.symbol_table.items[@intFromEnum(si)];
654 return &coff.symbols.items[@intFromEnum(si)];
604655 }
605656
606657 pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index {
......@@ -920,12 +971,17 @@ fn create(
920971 .name_table_ni = .none,
921972 .entries = .empty,
922973 },
974 .symbol_table = .{
975 .string_offsets = .empty,
976 .entries = .empty,
977 .pending_shrink = false,
978 },
923979 .strings = .empty,
924980 .string_bytes = .empty,
925 .image_section_table = .empty,
981 .section_table = .empty,
926982 .pseudo_section_table = .empty,
927983 .object_section_table = .empty,
928 .symbol_table = .empty,
984 .symbols = .empty,
929985 .globals = .empty,
930986 .global_pending_index = 0,
931987 .navs = .empty,
......@@ -965,15 +1021,16 @@ pub fn deinit(coff: *Coff) void {
9651021 const gpa = coff.base.comp.gpa;
9661022 coff.mf.deinit(gpa);
9671023 coff.nodes.deinit(gpa);
1024 // TODO: Update this
9681025 coff.long_names_table.entries.deinit(gpa);
9691026 coff.import_table.entries.deinit(gpa);
9701027 coff.export_table.entries.deinit(gpa);
9711028 coff.strings.deinit(gpa);
9721029 coff.string_bytes.deinit(gpa);
973 coff.image_section_table.deinit(gpa);
1030 coff.section_table.deinit(gpa);
9741031 coff.pseudo_section_table.deinit(gpa);
9751032 coff.object_section_table.deinit(gpa);
976 coff.symbol_table.deinit(gpa);
1033 coff.symbols.deinit(gpa);
9771034 coff.globals.deinit(gpa);
9781035 coff.navs.deinit(gpa);
9791036 coff.uavs.deinit(gpa);
......@@ -1035,8 +1092,13 @@ fn initHeaders(
10351092
10361093 var expected_nodes_len: usize = Node.known_count;
10371094 if (comp.zcu != null) {
1095 // Section nodes
10381096 expected_nodes_len += 3;
1097 // Symbol table nodes
1098 if (is_archive) expected_nodes_len += 6;
1099 // Pseudo-sections and import / export table nodes
10391100 if (is_image) expected_nodes_len += 9;
1101 // TLS section nodes
10401102 expected_nodes_len += @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2;
10411103 }
10421104 defer assert(coff.nodes.len == expected_nodes_len);
......@@ -1294,10 +1356,26 @@ fn initHeaders(
12941356 }));
12951357 coff.nodes.appendAssumeCapacity(.section_table);
12961358
1359 const symbol_table_ni = Node.known.symbol_table;
1360 assert(symbol_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{
1361 .alignment = .@"4",
1362 .fixed = true,
1363 .moved = true,
1364 }));
1365 coff.nodes.appendAssumeCapacity(.symbol_table);
1366
1367 const string_table_ni = Node.known.string_table;
1368 assert(string_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{
1369 .size = @sizeOf(u32),
1370 .fixed = true,
1371 .resized = true,
1372 }));
1373 coff.nodes.appendAssumeCapacity(.string_table);
1374
12971375 assert(coff.nodes.len == Node.known_count);
12981376
1299 try coff.symbol_table.ensureTotalCapacity(gpa, Symbol.Index.known_count);
1300 coff.symbol_table.addOneAssumeCapacity().* = .{
1377 try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count);
1378 coff.symbols.addOneAssumeCapacity().* = .{
13011379 .ni = .none,
13021380 .rva = 0,
13031381 .size = 0,
......@@ -1360,7 +1438,7 @@ fn initHeaders(
13601438 });
13611439 coff.nodes.appendAssumeCapacity(.export_address_table);
13621440
1363 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
1441 try coff.symbols.ensureUnusedCapacity(gpa, 1);
13641442 coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity();
13651443
13661444 const export_address_table_sym = coff.export_table.export_address_table_si.get(coff);
......@@ -1451,6 +1529,10 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
14511529 .section_table,
14521530 .export_name_table,
14531531 .placeholder,
1532
1533 .symbol_table,
1534 .symbol_table_entry,
1535 .string_table,
14541536 => unreachable,
14551537 .image_section => |si| si,
14561538 .import_directory_table => break :parent_rva coff.targetLoad(
......@@ -1632,7 +1714,28 @@ pub fn dataDirectoryPtr(
16321714}
16331715
16341716pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader {
1635 return @ptrCast(@alignCast(Node.known.section_table.slice(&coff.mf)));
1717 return @ptrCast(@alignCast(
1718 Node.known.section_table.slice(&coff.mf)[0 .. coff.section_table.items.len * @sizeOf(std.coff.SectionHeader)],
1719 ));
1720}
1721
1722pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) *align(2) std.coff.Symbol {
1723 return @ptrCast(@alignCast(
1724 &Node.known.symbol_table.slice(&coff.mf)[@intFromEnum(sti) * std.coff.Symbol.sizeOf()],
1725 ));
1726}
1727
1728pub fn symbolAuxSectionDefinitionPtr(coff: *Coff, si: Symbol.Index) *align(2) std.coff.SectionDefinition {
1729 const sti = coff.symbol_table.entries.get(si).?.index;
1730
1731 const symbol = coff.symbolTableEntryPtr(sti);
1732 assert(symbol.storage_class == .STATIC and symbol.number_of_aux_symbols == 1);
1733
1734 return @ptrCast(symbolTableEntryPtr(coff, @enumFromInt(@intFromEnum(sti) + 1)));
1735}
1736
1737pub fn symbolTableStringLenPtr(coff: *Coff) *align(2) u32 {
1738 return @ptrCast(@alignCast(Node.known.string_table.slice(&coff.mf)[0..@sizeOf(u32)]));
16361739}
16371740
16381741pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry {
......@@ -1662,7 +1765,7 @@ pub fn exportOrdinalTableSlice(coff: *Coff) []std.coff.ExportOrdinalTableEntry {
16621765}
16631766
16641767fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
1665 defer coff.symbol_table.addOneAssumeCapacity().* = .{
1768 defer coff.symbols.addOneAssumeCapacity().* = .{
16661769 .ni = .none,
16671770 .rva = 0,
16681771 .size = 0,
......@@ -1670,7 +1773,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
16701773 .target_relocs = .none,
16711774 .section_number = .UNDEFINED,
16721775 };
1673 return @enumFromInt(coff.symbol_table.items.len);
1776 return @enumFromInt(coff.symbols.items.len);
16741777}
16751778
16761779fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index {
......@@ -1715,7 +1818,7 @@ fn getOrPutGlobalSymbol(
17151818 lib_name: ?[]const u8,
17161819) !std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index).GetOrPutResult {
17171820 const gpa = coff.base.comp.gpa;
1718 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
1821 try coff.symbols.ensureUnusedCapacity(gpa, 1);
17191822 const sym_gop = try coff.globals.getOrPut(gpa, .{
17201823 .name = try coff.getOrPutString(name),
17211824 .lib_name = try coff.getOrPutOptionalString(lib_name),
......@@ -1724,6 +1827,7 @@ fn getOrPutGlobalSymbol(
17241827 sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();
17251828 coff.synth_prog_node.increaseEstimatedTotalItems(1);
17261829 }
1830
17271831 return sym_gop;
17281832}
17291833
......@@ -1758,7 +1862,7 @@ fn navSection(
17581862}
17591863fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
17601864 const gpa = zcu.gpa;
1761 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
1865 try coff.symbols.ensureUnusedCapacity(gpa, 1);
17621866 const sym_gop = try coff.navs.getOrPut(gpa, nav_index);
17631867 if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();
17641868 return @enumFromInt(sym_gop.index);
......@@ -1776,7 +1880,7 @@ pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbo
17761880
17771881fn uavMapIndex(coff: *Coff, uav_val: InternPool.Index) !Node.UavMapIndex {
17781882 const gpa = coff.base.comp.gpa;
1779 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
1883 try coff.symbols.ensureUnusedCapacity(gpa, 1);
17801884 const sym_gop = try coff.uavs.getOrPut(gpa, uav_val);
17811885 if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();
17821886 return @enumFromInt(sym_gop.index);
......@@ -1788,7 +1892,7 @@ pub fn uavSymbol(coff: *Coff, uav_val: InternPool.Index) !Symbol.Index {
17881892
17891893pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index {
17901894 const gpa = coff.base.comp.gpa;
1791 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
1895 try coff.symbols.ensureUnusedCapacity(gpa, 1);
17921896 const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
17931897 if (!sym_gop.found_existing) {
17941898 sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity();
......@@ -2004,13 +2108,185 @@ fn addMemberSymbol(
20042108 coff.pending_members.putAssumeCapacity(mi, {});
20052109}
20062110
2111fn addSymbolTableEntry(
2112 coff: *Coff,
2113 name: union(enum) {
2114 bytes: []const u8,
2115 string: String,
2116 },
2117 si: Symbol.Index,
2118 add: SymbolTable.Add,
2119) !void {
2120 assert(!coff.isImage());
2121 const gpa = coff.base.comp.gpa;
2122
2123 const string, const name_slice = switch (name) {
2124 .bytes => |bytes| .{ try coff.getOrPutString(bytes), bytes },
2125 .string => |s| .{ s, s.toSlice(coff) },
2126 };
2127
2128 const symbol_name: SymbolTable.SymbolName = if (name_slice.len > 8) index: {
2129 const string_gop = try coff.symbol_table.string_offsets.getOrPut(gpa, string);
2130 if (!string_gop.found_existing) {
2131 const string_index = Node.known.string_table.location(&coff.mf).resolve(&coff.mf)[1];
2132 string_gop.value_ptr.* = @enumFromInt(string_index);
2133
2134 try Node.known.string_table.resize(&coff.mf, gpa, string_index + name_slice.len + 1);
2135 const slice = Node.known.string_table.slice(&coff.mf);
2136 @memcpy(slice[string_index..][0..name_slice.len], name_slice);
2137 slice[string_index + name_slice.len] = 0;
2138 }
2139
2140 break :index .{ .long = string_gop.value_ptr.* };
2141 } else .{ .short = name_slice };
2142
2143 const symbol_index = coff.targetLoad(&coff.headerPtr().number_of_symbols);
2144 const symbols_added: u8 = switch (add) {
2145 .section => count: {
2146 const sym = si.get(coff);
2147
2148 try coff.nodes.ensureUnusedCapacity(gpa, 2);
2149 _ = try coff.addSymbolTableEntryAssumeCapacity(
2150 symbol_name,
2151 0,
2152 sym.section_number,
2153 .{
2154 .complex_type = .NULL,
2155 .base_type = .NULL,
2156 },
2157 .STATIC,
2158 1,
2159 );
2160
2161 // Aux entry ields are updated by flushMoved / flushResized
2162
2163 try coff.symbol_table.entries.put(gpa, si, .{
2164 .entry_si = .null,
2165 .index = @enumFromInt(symbol_index),
2166 });
2167
2168 break :count 2;
2169 },
2170 .global => |global| count: {
2171 const sym = si.get(coff);
2172
2173 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2174 try coff.symbols.ensureUnusedCapacity(gpa, 1);
2175
2176 const entry_ni = try coff.addSymbolTableEntryAssumeCapacity(
2177 symbol_name,
2178 if (global.import) 0 else coff.computeNodeSectionOffset(sym.ni),
2179 if (global.import) .UNDEFINED else sym.section_number,
2180 .{
2181 .base_type = .NULL,
2182 .complex_type = if (global.import or
2183 Symbol.Index.text.get(coff).section_number == sym.section_number)
2184 .FUNCTION
2185 else
2186 .NULL,
2187 },
2188 .EXTERNAL,
2189 0,
2190 );
2191
2192 const entry_si = coff.addSymbolAssumeCapacity();
2193 {
2194 const entry_sym = entry_si.get(coff);
2195 entry_sym.ni = entry_ni;
2196 assert(entry_sym.loc_relocs == .none);
2197 entry_sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
2198 entry_sym.section_number = .UNDEFINED;
2199 }
2200
2201 try coff.addReloc(
2202 entry_si,
2203 @offsetOf(std.coff.Symbol, "value"),
2204 si,
2205 0,
2206 .{ .AMD64 = .SECREL },
2207 );
2208
2209 try coff.symbol_table.entries.put(gpa, si, .{
2210 .entry_si = entry_si,
2211 .index = @enumFromInt(symbol_index),
2212 });
2213
2214 break :count 1;
2215 },
2216 };
2217
2218 const new_num_symbols = symbol_index + symbols_added;
2219 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
2220 coff.symbol_table.pending_shrink =
2221 Node.known.symbol_table.location(&coff.mf).resolve(&coff.mf)[1] >
2222 new_num_symbols * std.coff.Symbol.sizeOf();
2223}
2224
2225/// Caller guarantees there is capacity for 1 + number_of_aux_symbols nodes.
2226/// Auxiliary nodes are zero-initialized.
2227fn addSymbolTableEntryAssumeCapacity(
2228 coff: *Coff,
2229 name: SymbolTable.SymbolName,
2230 value: u32,
2231 section_number: Symbol.SectionNumber,
2232 @"type": std.coff.SymType,
2233 storage_class: std.coff.StorageClass,
2234 number_of_aux_symbols: u8,
2235) !MappedFile.Node.Index {
2236 const gpa = coff.base.comp.gpa;
2237
2238 const entry_ni = try coff.mf.addLastChildNode(gpa, Node.known.symbol_table, .{
2239 .alignment = .@"2",
2240 .size = std.coff.Symbol.sizeOf(),
2241 .fixed = true,
2242 });
2243 coff.nodes.appendAssumeCapacity(.symbol_table_entry);
2244
2245 const entry: *align(2) std.coff.Symbol = @ptrCast(@alignCast(entry_ni.slice(&coff.mf)));
2246 entry.* = .{
2247 .name = undefined,
2248 .value = value,
2249 .section_number = @enumFromInt(@intFromEnum(section_number)),
2250 .type = @"type",
2251 .storage_class = storage_class,
2252 .number_of_aux_symbols = number_of_aux_symbols,
2253 };
2254
2255 switch (name) {
2256 .short => |s| {
2257 @memcpy(entry.name[0..s.len], s);
2258 @memset(entry.name[s.len..], 0);
2259 },
2260 .long => |l| {
2261 @memset(entry.name[0..4], 0);
2262 const offset_ptr: *align(2) u32 = @ptrCast(entry.name[4..]);
2263 coff.targetStore(offset_ptr, @intFromEnum(l));
2264 },
2265 }
2266
2267 if (coff.targetEndian() != native_endian)
2268 std.mem.byteSwapAllFields(std.coff.SectionHeader, entry.*);
2269
2270 for (0..number_of_aux_symbols) |_| {
2271 const aux_ni = try coff.mf.addLastChildNode(gpa, Node.known.symbol_table, .{
2272 .alignment = .@"2",
2273 .size = std.coff.Symbol.sizeOf(),
2274 .fixed = true,
2275 });
2276 coff.nodes.appendAssumeCapacity(.symbol_table_entry);
2277 @memset(aux_ni.slice(&coff.mf), 0);
2278 }
2279
2280 return entry_ni;
2281}
2282
20072283fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index {
20082284 assert(coff.base.comp.zcu != null);
20092285
20102286 const gpa = coff.base.comp.gpa;
20112287 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2012 try coff.image_section_table.ensureUnusedCapacity(gpa, 1);
2013 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
2288 try coff.section_table.ensureUnusedCapacity(gpa, 1);
2289 try coff.symbols.ensureUnusedCapacity(gpa, 1);
20142290
20152291 const coff_header = coff.headerPtr();
20162292 const section_index = coff.targetLoad(&coff_header.number_of_sections);
......@@ -2022,19 +2298,19 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
20222298 @sizeOf(std.coff.SectionHeader) * section_table_len,
20232299 );
20242300
2025 const parent_ni, const alignment = if (coff.isArchive())
2026 .{ Node.known.zcu_member, .@"1" }
2301 const parent_ni = if (coff.isArchive())
2302 Node.known.zcu_member
20272303 else
2028 .{ Node.known.file, coff.mf.flags.block_size };
2304 Node.known.file;
20292305
20302306 const ni = try coff.mf.addLastChildNode(gpa, parent_ni, .{
2031 .alignment = alignment,
2307 .alignment = coff.mf.flags.block_size,
20322308 .moved = true,
20332309 .bubbles_moved = false,
20342310 });
20352311
20362312 const si = coff.addSymbolAssumeCapacity();
2037 coff.image_section_table.appendAssumeCapacity(si);
2313 coff.section_table.appendAssumeCapacity(si);
20382314 coff.nodes.appendAssumeCapacity(.{ .image_section = si });
20392315 const section_table = coff.sectionTableSlice();
20402316
......@@ -2042,7 +2318,7 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
20422318 const virtual_size = coff.optionalHeaderField(.section_alignment);
20432319 const rva: u32 = switch (section_index) {
20442320 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]),
2045 else => coff.image_section_table.items[section_index - 1].get(coff).rva +
2321 else => coff.section_table.items[section_index - 1].get(coff).rva +
20462322 coff.targetLoad(&section_table[section_index - 1].virtual_size),
20472323 };
20482324
......@@ -2080,6 +2356,8 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
20802356 @intCast(rva + virtual_size),
20812357 ),
20822358 }
2359 } else {
2360 try coff.addSymbolTableEntry(.{ .bytes = name }, si, .section);
20832361 }
20842362
20852363 return si;
......@@ -2112,7 +2390,7 @@ fn pseudoSectionMapIndex(
21122390 else
21132391 .rdata;
21142392 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2115 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
2393 try coff.symbols.ensureUnusedCapacity(gpa, 1);
21162394 const ni = try coff.mf.addLastChildNode(gpa, parent.node(coff), .{ .alignment = alignment });
21172395 const si = coff.addSymbolAssumeCapacity();
21182396 pseudo_section_gop.value_ptr.* = si;
......@@ -2142,7 +2420,7 @@ fn objectSectionMapIndex(
21422420 name_slice[0 .. std.mem.indexOfScalar(u8, name_slice, '$') orelse name_slice.len],
21432421 ), alignment, attributes)).symbol(coff);
21442422 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2145 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
2423 try coff.symbols.ensureUnusedCapacity(gpa, 1);
21462424 const parent_ni = parent.node(coff);
21472425 var prev_ni: MappedFile.Node.Index = .none;
21482426 var next_it = parent_ni.children(&coff.mf);
......@@ -2251,6 +2529,8 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
22512529 const sym = si.get(coff);
22522530 sym.ni = ni;
22532531 sym.section_number = sec_si.get(coff).section_number;
2532
2533 // TODO: Add symbol table entry
22542534 },
22552535 else => si.deleteLocationRelocs(coff),
22562536 }
......@@ -2506,11 +2786,6 @@ pub fn flush(
25062786 _ = prog_node;
25072787 while (try coff.idle(tid)) {}
25082788
2509 // TODO: Second linker member symbol tables are built here
2510 if (isArchive(coff)) {
2511 //Member.Index.second.get(coff).content_ni;
2512 }
2513
25142789 const comp = coff.base.comp;
25152790
25162791 // Implib generation should instead be done via building a MappedFile progressively
......@@ -2634,6 +2909,26 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
26342909 coff.flushExportsSort();
26352910 break :task;
26362911 }
2912 // TODO: This and the above task ideally run only once, as it's wasteful otherwise
2913 if (coff.symbol_table.pending_shrink) {
2914 coff.symbol_table.pending_shrink = false;
2915 // TODO: Prog node
2916 const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
2917 Node.known.symbol_table.shrink(
2918 &coff.mf,
2919 comp.gpa,
2920 number_of_symbols * std.coff.Symbol.sizeOf(),
2921 true,
2922 ) catch |err| switch (err) {
2923 error.OutOfMemory => return error.OutOfMemory,
2924 else => |e| return comp.link_diags.fail(
2925 "linker failed to shrink symbol table: {t}",
2926 .{e},
2927 ),
2928 };
2929
2930 break :task;
2931 }
26372932 }
26382933 if (coff.pending_uavs.count() > 0) return true;
26392934 if (coff.globals.count() > coff.global_pending_index) return true;
......@@ -2641,6 +2936,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
26412936 if (coff.mf.updates.items.len > 0) return true;
26422937 if (coff.pending_members.count() > 0) return true;
26432938 if (coff.export_table.pending_sort) return true;
2939 if (coff.symbol_table.pending_shrink) return true;
26442940 return false;
26452941}
26462942
......@@ -2733,14 +3029,28 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
27333029 const gpa = zcu.gpa;
27343030 const gn = gmi.globalName(coff);
27353031
2736 // TODO: We still need to emit a reloc for the __imp_Name symbol?
3032 if (!coff.isImage()) {
3033 // TODO: What about data imports?
3034
3035 // const si = gmi.symbol(coff);
3036 // const sym = si.get(coff);
3037 // sym.section_number = Symbol.Index.text.get(coff).section_number;
3038 // assert(sym.loc_relocs == .none);
3039 // sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
3040 //
3041 // try coff.addSymbolTableEntry(
3042 // .{ .bytes = gn.name.toSlice(coff) },
3043 // si,
3044 // .{ .global = .{ .import = true } },
3045 // );
27373046
2738 if (!coff.isImage()) return;
3047 return;
3048 }
27393049
27403050 if (gn.lib_name.toSlice(coff)) |lib_name| {
27413051 const name = gn.name.toSlice(coff);
27423052 try coff.nodes.ensureUnusedCapacity(gpa, 4);
2743 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
3053 try coff.symbols.ensureUnusedCapacity(gpa, 1);
27443054
27453055 const target_endian = coff.targetEndian();
27463056 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);
......@@ -2749,7 +3059,6 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
27493059 .PE32 => .{ 4, .@"4" },
27503060 .@"PE32+" => .{ 8, .@"8" },
27513061 };
2752
27533062 const gop = try coff.import_table.entries.getOrPutAdapted(
27543063 gpa,
27553064 lib_name,
......@@ -2959,7 +3268,16 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
29593268 .data_directories,
29603269 .section_table,
29613270 .placeholder,
3271
3272 .symbol_table_entry,
3273 .string_table,
29623274 => if (!coff.isArchive()) unreachable,
3275 .symbol_table => {
3276 coff.targetStore(
3277 &coff.headerPtr().pointer_to_symbol_table,
3278 @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]),
3279 );
3280 },
29633281 .archive_member_header => |mi| {
29643282 const member = mi.get(coff);
29653283 switch (member.kind) {
......@@ -3121,7 +3439,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
31213439 ),
31223440 }
31233441
3124 if (size > coff.image_section_table.items[0].get(coff).rva) try coff.virtualSlide(
3442 if (size > coff.section_table.items[0].get(coff).rva) try coff.virtualSlide(
31253443 0,
31263444 std.mem.alignForward(
31273445 u32,
......@@ -3159,6 +3477,12 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
31593477 .data_directories,
31603478 => unreachable,
31613479 .section_table => {},
3480 .symbol_table => assert(!coff.isImage()),
3481 .symbol_table_entry => unreachable,
3482 .string_table => {
3483 assert(!coff.isImage());
3484 coff.targetStore(coff.symbolTableStringLenPtr(), @intCast(size));
3485 },
31623486 .image_section => |si| {
31633487 const sym = si.get(coff);
31643488 const section_index = sym.section_number.toIndex();
......@@ -3173,6 +3497,13 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
31733497 coff.targetStore(&section.virtual_size, virtual_size);
31743498 try coff.virtualSlide(section_index + 1, sym.rva + virtual_size);
31753499 }
3500
3501 if (coff.isArchive()) {
3502 coff.targetStore(
3503 &coff.symbolAuxSectionDefinitionPtr(si).length,
3504 @intCast(size),
3505 );
3506 }
31763507 },
31773508 .import_directory_table => coff.targetStore(
31783509 &coff.dataDirectoryPtr(.IMPORT).size,
......@@ -3298,7 +3629,7 @@ fn flushExportsSort(coff: *Coff) void {
32983629fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {
32993630 var rva = start_rva;
33003631 for (
3301 coff.image_section_table.items[start_section_index..],
3632 coff.section_table.items[start_section_index..],
33023633 coff.sectionTableSlice()[start_section_index..],
33033634 ) |section_si, *section| {
33043635 const section_sym = section_si.get(coff);
......@@ -3343,7 +3674,7 @@ fn updateExportsInner(
33433674 Value.fromInterned(uav).fmtValue(pt),
33443675 }),
33453676 }
3346 try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len);
3677 try coff.symbols.ensureUnusedCapacity(gpa, export_indices.len);
33473678 const exported_si: Symbol.Index = switch (exported) {
33483679 .nav => |nav| try coff.navSymbol(zcu, nav),
33493680 .uav => |uav| @enumFromInt(@intFromEnum(try coff.lowerUav(
......@@ -3376,13 +3707,20 @@ fn updateExportsInner(
33763707 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);
33773708 }
33783709
3379 if (coff.isArchive())
3710 if (coff.isArchive()) {
33803711 try coff.addMemberSymbol(
33813712 symbol_gop.key_ptr.*.name,
33823713 coff.getNode(Node.known.zcu_member).archive_member,
33833714 export_si,
33843715 );
33853716
3717 try coff.addSymbolTableEntry(
3718 .{ .bytes = name },
3719 export_si,
3720 .{ .global = .{ .import = false } },
3721 );
3722 }
3723
33863724 if (coff.export_table.ni == .none) continue;
33873725
33883726 const entries_ctx = ExportTable.Adapter{ .coff = coff };
......@@ -3425,8 +3763,7 @@ fn updateExportsInner(
34253763 coff.targetStore(&edt.number_of_names, @intCast(export_count));
34263764 edt.number_of_entries = edt.number_of_names;
34273765
3428 // TODO: If we had an estimate of the total number of exports this could be a lot more efficient
3429
3766 // TODO: These should all be resized ahead of time to fit all exports (after https://github.com/ziglang/zig/issues/23616)
34303767 try coff.export_table.export_address_table_si.node(coff).resize(
34313768 &coff.mf,
34323769 gpa,