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
log647fe54ef0843018bfc8416ae5f5f46e6bf2d78c
tree1c2b351c5d8ca1a6ba95be263b2f8e6bba6336a9
parent8c2737fd95f46d43a13a69a0a2cdedecb61a1157

Coff: Writing relocations and symbol table


3 files changed, 321 insertions(+), 321 deletions(-)

lib/std/coff.zig+4
......@@ -1392,6 +1392,10 @@ pub const Relocation = extern struct {
13921392 virtual_address: u32,
13931393 symbol_table_index: u32,
13941394 type: u16,
1395
1396 pub fn sizeOf() usize {
1397 return 10;
1398 }
13951399};
13961400
13971401pub const IMAGE = struct {
src/link/Coff.zig+314-318
......@@ -216,14 +216,26 @@ pub const Node = union(enum) {
216216 };
217217
218218 pub const GlobalMapIndex = enum(u32) {
219 none,
219220 _,
220221
222 pub fn wrap(i: ?u32) GlobalMapIndex {
223 return @enumFromInt((i orelse return .none) + 1);
224 }
225
226 pub fn unwrap(gmi: GlobalMapIndex) ?u32 {
227 return switch (gmi) {
228 .none => null,
229 _ => @intFromEnum(gmi) - 1,
230 };
231 }
232
221233 pub fn globalName(gmi: GlobalMapIndex, coff: *const Coff) GlobalName {
222 return coff.globals.keys()[@intFromEnum(gmi)];
234 return coff.globals.keys()[gmi.unwrap().?];
223235 }
224236
225237 pub fn symbol(gmi: GlobalMapIndex, coff: *const Coff) Symbol.Index {
226 return coff.globals.values()[@intFromEnum(gmi)];
238 return coff.globals.values()[gmi.unwrap().?];
227239 }
228240 };
229241
......@@ -452,32 +464,32 @@ pub const LongNamesTable = struct {
452464};
453465
454466pub const SymbolTable = struct {
455 string_offsets: std.AutoArrayHashMapUnmanaged(String, StringIndex),
456 entries: std.AutoArrayHashMapUnmanaged(Symbol.Index, Entry),
467 strings: std.AutoArrayHashMapUnmanaged(String, StringIndex),
457468
458469 // Adding nodes to the symbol table has the result of accumulating padding
459 // between the last symbol and the string table, due to the growth factor
460 // in MappedFile. The spec requires the string table begin immediately
461 // after the last symbol, so we compact the symbol table node if needed.
470 // 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.
472 // The spec requires the string table begin immediately after the last symbol,
473 // so we compact the symbol table node if needed.
462474 pending_shrink: bool,
463475
464 pub const Entry = struct {
465 entry_si: Symbol.Index,
466 sti: Index, // TODO: Is this redundant now that we store it on symbol?
467 };
468
469476 pub const Add = union(enum) {
470477 section,
471478 global,
472479 };
473480
481 pub const StringIndex = enum(u32) {
482 _,
483 };
484
474485 pub const SymbolName = union(enum) {
475486 short: []const u8,
476487 long: StringIndex,
477488 };
478489
479 // Symbol.Index does not map 1:1 with SymbolTable.Index due to
480 // variable number of auxiliary entries that may trail each symbol
490 // Symbol.Index does not map 1:1 with SymbolTable.Index:
491 // - Not all symbols need a symbol table entry
492 // - A variable number of auxiliary entries may trail each symbol
481493 pub const Index = enum(u32) {
482494 none,
483495 _,
......@@ -492,14 +504,6 @@ pub const SymbolTable = struct {
492504 _ => @intFromEnum(sti) - 1,
493505 };
494506 }
495
496 pub fn get(sti: SymbolTable.Index, coff: *Coff) *Entry {
497 return &coff.symbol_table.entries.values()[sti.unwrap().?];
498 }
499 };
500
501 pub const StringIndex = enum(u32) {
502 _,
503507 };
504508};
505509
......@@ -666,7 +670,7 @@ pub const Symbol = struct {
666670 target_relocs: Reloc.Index,
667671 section_number: SectionNumber,
668672 sti: SymbolTable.Index,
669 unused0: u32 = 0,
673 gmi: Node.GlobalMapIndex,
670674 unused1: u16 = 0,
671675
672676 pub const SectionNumber = enum(i16) {
......@@ -718,9 +722,27 @@ pub const Symbol = struct {
718722 si.applyTargetRelocs(coff);
719723 }
720724
725 pub fn flushSymbolTableIndex(si: Symbol.Index, coff: *Coff) void {
726 const sym = si.get(coff);
727 const index = sym.sti.unwrap() orelse return;
728 var ri = sym.target_relocs;
729 while (ri != .none) {
730 const reloc = ri.get(coff);
731 assert(reloc.target == si);
732 if (reloc.sri.entry(coff, reloc.loc.get(coff).section_number)) |entry|
733 coff.targetStore(&entry.symbol_table_index, index);
734 ri = reloc.next;
735 }
736 }
737
721738 pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void {
722 for (coff.relocs.items[@intFromEnum(si.get(coff).loc_relocs)..]) |*reloc| {
739 const sym = si.get(coff);
740 for (coff.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| {
723741 if (reloc.loc != si) break;
742 if (reloc.sri.entry(coff, sym.section_number)) |entry| coff.targetStore(
743 &entry.virtual_address,
744 @intCast(coff.computeNodeSectionOffset(sym.ni) + reloc.offset),
745 );
724746 reloc.apply(coff);
725747 }
726748 }
......@@ -743,17 +765,6 @@ pub const Symbol = struct {
743765 }
744766 sym.loc_relocs = .none;
745767 }
746
747 pub fn updateRelocsSymbolTableIndex(si: Symbol.Index, coff: *Coff) void {
748 const sym = si.get(coff);
749 var ri = sym.target_relocs;
750 while (ri != .none) {
751 const reloc = ri.get(coff);
752 if (reloc.sri.entry(coff, reloc.loc.get(coff).section_number)) |entry|
753 coff.targetStore(&entry.symbol_table_index, sym.sti.unwrap().?);
754 ri = reloc.next;
755 }
756 }
757768 };
758769
759770 comptime {
......@@ -798,20 +809,72 @@ pub const Reloc = extern struct {
798809 .none => return,
799810 else => |ni| if (ni.hasMoved(&coff.mf)) return,
800811 }
812
813 const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..];
814 const target_endian = coff.targetEndian();
815
816 if (!coff.isImage()) {
817 switch (coff.targetLoad(&coff.headerPtr().machine)) {
818 else => |machine| @panic(@tagName(machine)),
819 .AMD64 => switch (reloc.type.AMD64) {
820 else => |kind| @panic(@tagName(kind)),
821 .ABSOLUTE => {},
822 .ADDR64 => std.mem.writeInt(
823 u64,
824 loc_slice[0..8],
825 @intCast(reloc.addend),
826 target_endian,
827 ),
828 .ADDR32,
829 .ADDR32NB,
830 .REL32,
831 .REL32_1,
832 .REL32_2,
833 .REL32_3,
834 .REL32_4,
835 .REL32_5,
836 .SECREL,
837 => std.mem.writeInt(
838 u32,
839 loc_slice[0..4],
840 @intCast(reloc.addend),
841 target_endian,
842 ),
843 },
844 .I386 => switch (reloc.type.I386) {
845 else => |kind| @panic(@tagName(kind)),
846 .ABSOLUTE => {},
847 .DIR16,
848 .REL16,
849 => std.mem.writeInt(
850 u16,
851 loc_slice[0..2],
852 @intCast(reloc.addend),
853 target_endian,
854 ),
855 .DIR32,
856 .DIR32NB,
857 .REL32,
858 .SECREL,
859 => std.mem.writeInt(
860 u32,
861 loc_slice[0..4],
862 @intCast(reloc.addend),
863 target_endian,
864 ),
865 },
866 }
867
868 return;
869 }
870
801871 const target_sym = reloc.target.get(coff);
802872 switch (target_sym.ni) {
803873 .none => return,
804874 else => |ni| if (ni.hasMoved(&coff.mf)) return,
805875 }
806 const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..];
807 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));
808 const target_endian = coff.targetEndian();
809876
810 // TODO: Is this right?
811 const base = if (coff.isImage())
812 coff.optionalHeaderField(.image_base)
813 else
814 0; // should be offset within section - take target_rva - section_rva (but section is 0!)
877 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));
815878
816879 switch (coff.targetLoad(&coff.headerPtr().machine)) {
817880 else => |machine| @panic(@tagName(machine)),
......@@ -821,13 +884,13 @@ pub const Reloc = extern struct {
821884 .ADDR64 => std.mem.writeInt(
822885 u64,
823886 loc_slice[0..8],
824 base + target_rva,
887 coff.optionalHeaderField(.image_base) + target_rva,
825888 target_endian,
826889 ),
827890 .ADDR32 => std.mem.writeInt(
828891 u32,
829892 loc_slice[0..4],
830 @intCast(base + target_rva),
893 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
831894 target_endian,
832895 ),
833896 .ADDR32NB => std.mem.writeInt(
......@@ -875,7 +938,7 @@ pub const Reloc = extern struct {
875938 .SECREL => std.mem.writeInt(
876939 u32,
877940 loc_slice[0..4],
878 coff.computeNodeSectionOffset(target_sym.ni),
941 @intCast(coff.computeNodeSectionOffset(target_sym.ni) + reloc.addend),
879942 target_endian,
880943 ),
881944 },
......@@ -885,7 +948,7 @@ pub const Reloc = extern struct {
885948 .DIR16 => std.mem.writeInt(
886949 u16,
887950 loc_slice[0..2],
888 @intCast(base + target_rva),
951 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
889952 target_endian,
890953 ),
891954 .REL16 => std.mem.writeInt(
......@@ -897,7 +960,7 @@ pub const Reloc = extern struct {
897960 .DIR32 => std.mem.writeInt(
898961 u32,
899962 loc_slice[0..4],
900 @intCast(base + target_rva),
963 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
901964 target_endian,
902965 ),
903966 .DIR32NB => std.mem.writeInt(
......@@ -915,7 +978,7 @@ pub const Reloc = extern struct {
915978 .SECREL => std.mem.writeInt(
916979 u32,
917980 loc_slice[0..4],
918 coff.computeNodeSectionOffset(target_sym.ni),
981 @intCast(coff.computeNodeSectionOffset(target_sym.ni) + reloc.addend),
919982 target_endian,
920983 ),
921984 },
......@@ -923,7 +986,11 @@ pub const Reloc = extern struct {
923986 }
924987
925988 pub fn delete(reloc: *Reloc, coff: *Coff) void {
926 // TODO: Need to remove this from the COFF relocation table (remove swap)
989 if (reloc.sri != .none) {
990 // TODO: Need to remove this from the COFF relocation table (maybe removeswap?)
991 // TODO: If this was the last reloc causing something to be in the symbol table, we should remove the sti
992 // That will require flushSymbolTableIndex on the swapped symbol if we exchange indices
993 }
927994
928995 switch (reloc.prev) {
929996 .none => {
......@@ -1036,8 +1103,7 @@ fn create(
10361103 .entries = .empty,
10371104 },
10381105 .symbol_table = .{
1039 .string_offsets = .empty,
1040 .entries = .empty,
1106 .strings = .empty,
10411107 .pending_shrink = false,
10421108 },
10431109 .strings = .empty,
......@@ -1088,8 +1154,7 @@ pub fn deinit(coff: *Coff) void {
10881154 coff.long_names_table.entries.deinit(gpa);
10891155 coff.import_table.entries.deinit(gpa);
10901156 coff.export_table.entries.deinit(gpa);
1091 coff.symbol_table.string_offsets.deinit(gpa);
1092 coff.symbol_table.entries.deinit(gpa);
1157 coff.symbol_table.strings.deinit(gpa);
10931158 coff.strings.deinit(gpa);
10941159 coff.string_bytes.deinit(gpa);
10951160 coff.section_table.deinit(gpa);
......@@ -1159,8 +1224,8 @@ fn initHeaders(
11591224 if (comp.zcu != null) {
11601225 // Section nodes
11611226 expected_nodes_len += 3;
1162 // Symbol table nodes
1163 if (is_archive) expected_nodes_len += 6;
1227 // // Symbol table nodes
1228 // if (is_archive) expected_nodes_len += 6;
11641229 // Pseudo-sections and import / export table nodes
11651230 if (is_image) expected_nodes_len += 9;
11661231 // TLS section nodes
......@@ -1421,7 +1486,7 @@ fn initHeaders(
14211486 }));
14221487 coff.nodes.appendAssumeCapacity(.section_table);
14231488
1424 // TODO: These two nodes could be inside one movable node
1489 // TODO: These two nodes could be inside one movable node?
14251490 const symbol_table_ni = Node.known.symbol_table;
14261491 assert(symbol_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{
14271492 .alignment = .@"2",
......@@ -1450,6 +1515,7 @@ fn initHeaders(
14501515 .target_relocs = .none,
14511516 .section_number = .UNDEFINED,
14521517 .sti = .none,
1518 .gmi = .none,
14531519 };
14541520 assert(try coff.addSection(".data", .{
14551521 .CNT_INITIALIZED_DATA = true,
......@@ -1789,20 +1855,24 @@ pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader {
17891855 ));
17901856}
17911857
1792pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) *align(2) std.coff.Symbol {
1793 return @ptrCast(@alignCast(
1794 &Node.known.symbol_table.slice(&coff.mf)[sti.unwrap().? * std.coff.Symbol.sizeOf()],
1795 ));
1858pub fn symbolTableEntryStoragePtr(coff: *Coff, index: u32) *[std.coff.Symbol.sizeOf()]u8 {
1859 assert(!coff.isImage());
1860 const offset = index * std.coff.Symbol.sizeOf();
1861 return @ptrCast(@alignCast(Node.known.symbol_table.slice(&coff.mf)[offset..][0..std.coff.Symbol.sizeOf()]));
17961862}
17971863
1798pub fn symbolAuxSectionDefinitionPtr(coff: *Coff, si: Symbol.Index) *align(2) std.coff.SectionDefinition {
1799 const sti = coff.symbol_table.entries.get(si).?.sti;
1800 const symbol = coff.symbolTableEntryPtr(sti);
1801 assert(symbol.storage_class == .STATIC and symbol.number_of_aux_symbols == 1);
1864pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.coff.Symbol {
1865 if (sti.unwrap()) |index|
1866 return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, index)))
1867 else
1868 return null;
1869}
18021870
1803 return @ptrCast(@alignCast(
1804 &Node.known.symbol_table.slice(&coff.mf)[(sti.unwrap().? + 1) * std.coff.Symbol.sizeOf()],
1805 ));
1871pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, si: Symbol.Index) *align(2) std.coff.SectionDefinition {
1872 const sti = si.get(coff).sti;
1873 const entry = symbolTableEntryPtr(coff, sti).?;
1874 assert(entry.storage_class == .STATIC and entry.number_of_aux_symbols == 1);
1875 return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, sti.unwrap().? + 1)));
18061876}
18071877
18081878pub fn symbolTableStringLenPtr(coff: *Coff) *align(2) u32 {
......@@ -1844,6 +1914,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
18441914 .target_relocs = .none,
18451915 .section_number = .UNDEFINED,
18461916 .sti = .none,
1917 .gmi = .none,
18471918 };
18481919 return @enumFromInt(coff.symbols.items.len);
18491920}
......@@ -1891,7 +1962,9 @@ pub fn globalSymbol(coff: *Coff, opts: struct {
18911962 .lib_name = try coff.getOrPutOptionalString(opts.lib_name),
18921963 });
18931964 if (!sym_gop.found_existing) {
1894 sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();
1965 const si = coff.addSymbolAssumeCapacity();
1966 si.get(coff).gmi = .wrap(@intCast(sym_gop.index));
1967 sym_gop.value_ptr.* = si;
18951968 coff.synth_prog_node.increaseEstimatedTotalItems(1);
18961969 }
18971970
......@@ -1993,7 +2066,7 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.
19932066 reloc_info.addend,
19942067 switch (coff.targetLoad(&coff.headerPtr().machine)) {
19952068 else => unreachable,
1996 .AMD64 => .{ .AMD64 = .ADDR64 }, // TODO: Switch to REL32 for obj/archive
2069 .AMD64 => .{ .AMD64 = .ADDR64 },
19972070 .I386 => .{ .I386 = .DIR32 },
19982071 },
19992072 );
......@@ -2097,7 +2170,7 @@ fn appendMemberSymbolString(
20972170
20982171fn ensureMemberSymbol(
20992172 coff: *Coff,
2100 name: []const u8,
2173 name: String,
21012174 mi: Member.Index,
21022175 si: Symbol.Index,
21032176) !void {
......@@ -2105,7 +2178,6 @@ fn ensureMemberSymbol(
21052178 const member = mi.get(coff);
21062179 assert(member.kind == .coff);
21072180
2108 const name_string = try coff.getOrPutString(name);
21092181 const gop = try member.first_linker_indices.getOrPut(gpa, si);
21102182 if (gop.found_existing) return;
21112183
......@@ -2124,7 +2196,8 @@ fn ensureMemberSymbol(
21242196 // Linker member fields are not modeled as nodes because MappedFile
21252197 // can't guarantee that they will be tightly packed after resizing
21262198
2127 const new_string_table_size = coff.lib_string_len + name.len + 1;
2199 const name_slice = name.toSlice(coff);
2200 const new_string_table_size = coff.lib_string_len + name_slice.len + 1;
21282201 defer coff.lib_string_len = new_string_table_size;
21292202
21302203 {
......@@ -2134,8 +2207,8 @@ fn ensureMemberSymbol(
21342207
21352208 const slice = Node.known.first_linker_member.slice(&coff.mf);
21362209 @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]);
2137 @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name.len], name[0..name.len]);
2138 slice[new_header_size + coff.lib_string_len + name.len] = 0;
2210 @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice[0..name_slice.len]);
2211 slice[new_header_size + coff.lib_string_len + name_slice.len] = 0;
21392212
21402213 // New offset entry is written in flushMember
21412214 }
......@@ -2149,13 +2222,13 @@ fn ensureMemberSymbol(
21492222 const needs_sort = if (coff.lib_string_table.items.len > 0)
21502223 std.mem.lessThan(
21512224 u8,
2152 name,
2225 name_slice,
21532226 coff.lib_string_table.items[coff.lib_string_table.items.len - 1].toSlice(coff),
21542227 )
21552228 else
21562229 false;
21572230
2158 try coff.lib_string_table.append(gpa, name_string);
2231 try coff.lib_string_table.append(gpa, name);
21592232
21602233 const slice = Node.known.second_linker_member.slice(&coff.mf);
21612234 const num_symbols_ptr: *u32 = @ptrCast(@alignCast(slice[@sizeOf(u32) + num_members * @sizeOf(u32) ..]));
......@@ -2166,8 +2239,8 @@ fn ensureMemberSymbol(
21662239 coff.pending_members.putAssumeCapacity(Member.Index.second, {});
21672240 } else {
21682241 @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]);
2169 @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name.len], name[0..name.len]);
2170 slice[new_header_size + coff.lib_string_len + name.len] = 0;
2242 @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice[0..name_slice.len]);
2243 slice[new_header_size + coff.lib_string_len + name_slice.len] = 0;
21712244 }
21722245
21732246 // Indices in this table are 1-based
......@@ -2178,189 +2251,130 @@ fn ensureMemberSymbol(
21782251 coff.pending_members.putAssumeCapacity(mi, {});
21792252}
21802253
2181fn addSymbolTableEntry(
2182 coff: *Coff,
2183 name: union(enum) {
2184 bytes: []const u8,
2185 string: String,
2186 },
2187 si: Symbol.Index,
2188 add: SymbolTable.Add,
2189) !void {
2254// TODO: -> flushSymbolTableEntry, and push all call sites onto a pending list instead?
2255fn updateSymbolTableEntry(coff: *Coff, si: Symbol.Index) !SymbolTable.Index {
21902256 assert(!coff.isImage());
21912257 const gpa = coff.base.comp.gpa;
21922258
2193 // TODO: Avoid geOrPutString if it fits (only need to actually make the String for adding member symbol)
2194 const string, const name_slice = switch (name) {
2195 .bytes => |bytes| .{ try coff.getOrPutString(bytes), bytes },
2196 .string => |s| .{ s, s.toSlice(coff) },
2197 };
2198
2199 const symbol_name: SymbolTable.SymbolName = if (name_slice.len > 8) index: {
2200 const string_gop = try coff.symbol_table.string_offsets.getOrPut(gpa, string);
2201 if (!string_gop.found_existing) {
2202 const string_index = Node.known.string_table.location(&coff.mf).resolve(&coff.mf)[1];
2203 string_gop.value_ptr.* = @enumFromInt(string_index);
2204
2205 try Node.known.string_table.resize(&coff.mf, gpa, string_index + name_slice.len + 1);
2206 const slice = Node.known.string_table.slice(&coff.mf);
2207 @memcpy(slice[string_index..][0..name_slice.len], name_slice);
2208 slice[string_index + name_slice.len] = 0;
2209 }
2210
2211 break :index .{ .long = string_gop.value_ptr.* };
2212 } else .{ .short = name_slice };
2213
2214 const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
2215
22162259 const sym = si.get(coff);
2217 sym.sti = .wrap(old_num_symbols);
2218 si.updateRelocsSymbolTableIndex(coff);
2219
2220 log.debug("addSymbolTableEntry({s}, {d}) = {d}", .{ name_slice, si, sym.sti.unwrap().? });
2221
2222 // TODO: Can look at sym.ni to know what kind this is
2223
2224 const symbols_added: u8 = switch (add) {
2225 .section => count: {
2226 try coff.nodes.ensureUnusedCapacity(gpa, 2);
2227 _ = try coff.addSymbolTableEntryAssumeCapacity(
2228 symbol_name,
2229 0,
2230 sym.section_number,
2231 .{
2232 .complex_type = .NULL,
2233 .base_type = .NULL,
2234 },
2235 .STATIC,
2236 1,
2237 );
2238
2239 // Aux entry ields are updated by flushMoved / flushResized
2240 try coff.symbol_table.entries.put(gpa, si, .{
2241 .entry_si = .null,
2242 .sti = sym.sti,
2243 });
2244
2245 break :count 2;
2246 },
2247 .global => count: {
2248 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2249 try coff.symbols.ensureUnusedCapacity(gpa, 1);
2250
2251 if (sym.ni != .none) {
2252 try coff.ensureMemberSymbol(
2253 name_slice, // TODO: Swap to string?
2254 coff.getNode(Node.known.zcu_member).archive_member,
2255 si,
2256 );
2257 }
2258
2259 const entry_ni = try coff.addSymbolTableEntryAssumeCapacity(
2260 symbol_name,
2261 if (sym.ni == .none) 0 else coff.computeNodeSectionOffset(sym.ni),
2262 sym.section_number,
2263 .{
2264 .base_type = .NULL,
2265 .complex_type = if (Symbol.Index.text.get(coff).section_number == sym.section_number)
2260 const has_node = sym.ni != .none;
2261 assert(has_node or sym.gmi != .none);
2262
2263 const entry = coff.symbolTableEntryPtr(sym.sti) orelse entry: {
2264 var buf: [15]u8 = undefined;
2265 const name_slice, const opt_name_string, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =
2266 if (sym.gmi != .none) blk: {
2267 const gn = sym.gmi.globalName(coff);
2268 break :blk .{
2269 gn.name.toSlice(coff),
2270 gn.name,
2271 0,
2272 if (Symbol.Index.text.get(coff).section_number == sym.section_number)
22662273 .FUNCTION
22672274 else
22682275 .NULL,
2276 };
2277 } else switch (coff.getNode(sym.ni)) {
2278 .image_section => .{
2279 &sym.section_number.header(coff).name,
2280 null,
2281 1,
2282 .NULL,
22692283 },
2270 .EXTERNAL,
2271 0,
2272 );
2284 .nav => |nmi| blk: {
2285 const zcu = coff.base.comp.zcu.?;
2286 const ip = &zcu.intern_pool;
2287 const nav = ip.getNav(nmi.navIndex(coff));
2288 break :blk .{
2289 nav.fqn.toSlice(ip),
2290 null,
2291 0,
2292 if (ip.isFunctionType(nav.resolved.?.type)) .FUNCTION else .NULL,
2293 };
2294 },
2295 .uav => |umi| blk: {
2296 var w = Io.Writer.fixed(&buf);
2297 w.print("__anon_{x}", .{umi.uavValue(coff)}) catch unreachable;
2298 break :blk .{ w.buffered(), null, 0, .NULL };
2299 },
2300 else => {
2301 log.err("TODO implement symbol table init for {s}", .{@tagName(coff.getNode(sym.ni))});
2302 return .none;
2303 },
2304 };
22732305
2274 const entry_si = coff.addSymbolAssumeCapacity();
2275 {
2276 const entry_sym = entry_si.get(coff);
2277 entry_sym.ni = entry_ni;
2278 assert(entry_sym.loc_relocs == .none);
2279 entry_sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
2280 entry_sym.section_number = .UNDEFINED;
2306 const symbol_name: SymbolTable.SymbolName = if (name_slice.len > 8) name: {
2307 const string = opt_name_string orelse try coff.getOrPutString(name_slice);
2308 const string_gop = try coff.symbol_table.strings.getOrPut(gpa, string);
2309 if (!string_gop.found_existing) {
2310 const string_index = Node.known.string_table.location(&coff.mf).resolve(&coff.mf)[1];
2311 string_gop.value_ptr.* = @enumFromInt(string_index);
2312
2313 try Node.known.string_table.resize(&coff.mf, gpa, string_index + name_slice.len + 1);
2314 const slice = Node.known.string_table.slice(&coff.mf);
2315 @memcpy(slice[string_index..][0..name_slice.len], name_slice);
2316 slice[string_index + name_slice.len] = 0;
22812317 }
22822318
2283 if (sym.ni != .none) {
2284 // TODO: This serves to update the std.coff.Symbol.value (to VA of si), is this working?
2285 try coff.addReloc(
2286 entry_si,
2287 @offsetOf(std.coff.Symbol, "value"),
2288 si,
2289 0,
2290 .{ .AMD64 = .SECREL }, // TODO: x86 too
2291 );
2292 }
2319 break :name .{ .long = string_gop.value_ptr.* };
2320 } else .{ .short = name_slice };
22932321
2294 try coff.symbol_table.entries.put(gpa, si, .{
2295 .entry_si = entry_si,
2296 .sti = sym.sti,
2297 });
2322 const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
2323 const new_num_symbols = old_num_symbols + 1 + num_aux_symbols;
22982324
2299 break :count 1;
2300 },
2301 };
2325 try Node.known.symbol_table.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());
23022326
2303 const new_num_symbols = old_num_symbols + symbols_added;
2304 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
2305 coff.symbol_table.pending_shrink =
2306 Node.known.symbol_table.location(&coff.mf).resolve(&coff.mf)[1] >
2307 new_num_symbols * std.coff.Symbol.sizeOf();
2308}
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;
23092330
2310/// Caller guarantees there is capacity for 1 + number_of_aux_symbols nodes.
2311/// Auxiliary nodes are zero-initialized.
2312fn addSymbolTableEntryAssumeCapacity(
2313 coff: *Coff,
2314 name: SymbolTable.SymbolName,
2315 value: u32,
2316 section_number: Symbol.SectionNumber,
2317 @"type": std.coff.SymType,
2318 storage_class: std.coff.StorageClass,
2319 number_of_aux_symbols: u8,
2320) !MappedFile.Node.Index {
2321 const gpa = coff.base.comp.gpa;
2331 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
2332 sym.sti = .wrap(old_num_symbols);
2333 si.flushSymbolTableIndex(coff);
23222334
2323 const entry_ni = try coff.mf.addLastChildNode(gpa, Node.known.symbol_table, .{
2324 .alignment = .@"2",
2325 .size = std.coff.Symbol.sizeOf(),
2326 .fixed = true,
2327 });
2328 coff.nodes.appendAssumeCapacity(.symbol_table_entry);
2335 const entry = coff.symbolTableEntryPtr(sym.sti).?;
2336 switch (symbol_name) {
2337 .short => |s| {
2338 @memcpy(entry.name[0..s.len], s);
2339 @memset(entry.name[s.len..], 0);
2340 },
2341 .long => |l| {
2342 @memset(entry.name[0..4], 0);
2343 const offset_ptr: *align(2) u32 = @ptrCast(entry.name[4..]);
2344 coff.targetStore(offset_ptr, @intFromEnum(l));
2345 },
2346 }
23292347
2330 const entry: *align(2) std.coff.Symbol = @ptrCast(@alignCast(entry_ni.slice(&coff.mf)));
2331 switch (name) {
2332 .short => |s| {
2333 @memcpy(entry.name[0..s.len], s);
2334 @memset(entry.name[s.len..], 0);
2335 },
2336 .long => |l| {
2337 @memset(entry.name[0..4], 0);
2338 const offset_ptr: *align(2) u32 = @ptrCast(entry.name[4..]);
2339 coff.targetStore(offset_ptr, @intFromEnum(l));
2340 },
2341 }
2348 entry.section_number = @enumFromInt(@intFromEnum(sym.section_number));
2349 entry.type = .{
2350 .complex_type = complex_type,
2351 .base_type = .NULL,
2352 };
2353 entry.storage_class = if (sym.gmi == .none) .STATIC else .EXTERNAL;
2354 entry.number_of_aux_symbols = num_aux_symbols;
2355 if (coff.targetEndian() != native_endian)
2356 std.mem.byteSwapAllFieldsAligned(std.coff.Symbol, .@"2", entry);
23422357
2343 // TODO: Would be ideal to assign entry.*, but given @sizeOf() > entry.sizeOf(), is that valid?
2344 entry.value = value;
2345 entry.section_number = @enumFromInt(@intFromEnum(section_number));
2346 entry.type = @"type";
2347 entry.storage_class = storage_class;
2348 entry.number_of_aux_symbols = number_of_aux_symbols;
2358 for (1..num_aux_symbols + 1) |aux_index|
2359 @memset(coff.symbolTableEntryStoragePtr(@intCast(old_num_symbols + aux_index)), 0);
23492360
2350 if (coff.targetEndian() != native_endian)
2351 std.mem.byteSwapAllFields(std.coff.SectionHeader, entry.*);
2361 break :entry entry;
2362 };
23522363
2353 for (0..number_of_aux_symbols) |_| {
2354 const aux_ni = try coff.mf.addLastChildNode(gpa, Node.known.symbol_table, .{
2355 .alignment = .@"2",
2356 .size = std.coff.Symbol.sizeOf(),
2357 .fixed = true,
2358 });
2359 coff.nodes.appendAssumeCapacity(.symbol_table_entry);
2360 @memset(aux_ni.slice(&coff.mf), 0);
2361 }
2364 coff.targetStore(&entry.value, switch (sym.section_number) {
2365 .UNDEFINED => sym.size,
2366 .ABSOLUTE,
2367 .DEBUG,
2368 => unreachable,
2369 else => switch (coff.getNode(sym.ni)) {
2370 .image_section => 0,
2371 else => coff.computeNodeSectionOffset(sym.ni),
2372 },
2373 });
23622374
2363 return entry_ni;
2375 log.debug("updateSymbolTableEntry({d}) = {d}", .{ si, sym.sti });
2376
2377 return sym.sti;
23642378}
23652379
23662380fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index {
......@@ -2443,7 +2457,7 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
24432457 ),
24442458 }
24452459 } else {
2446 try coff.addSymbolTableEntry(.{ .bytes = name }, si, .section);
2460 assert(try coff.updateSymbolTableEntry(si) != .none);
24472461 }
24482462
24492463 return si;
......@@ -2579,67 +2593,66 @@ pub fn addReloc(
25792593 addend: i64,
25802594 @"type": Reloc.Type,
25812595) !void {
2596 const gpa = coff.base.comp.gpa;
25822597 const target = target_si.get(coff);
2583 log.debug("addReloc({d}@{d} + {d} -> {d}@{d} + {d})", .{ loc_si, loc_si.get(coff).section_number, offset, target_si, target_si.get(coff).section_number, addend });
25842598
2585 try ensureUnusedRelocCapacity(coff, loc_si, 1);
2599 log.debug("addReloc({d}@{d}+{d} -> {d}@{d}+{d})", .{ loc_si, loc_si.get(coff).section_number, offset, target_si, target_si.get(coff).section_number, addend });
25862600
2587 // TODO: The switch should be in an ensure capacity for reloc fn
2601 try coff.relocs.ensureUnusedCapacity(gpa, 1);
25882602
25892603 const sri: Section.RelocationIndex = if (isImage(coff))
25902604 .none
25912605 else switch (loc_si.get(coff).section_number) {
2592 .UNDEFINED, .ABSOLUTE, .DEBUG => .none,
2606 .UNDEFINED,
2607 .ABSOLUTE,
2608 .DEBUG,
2609 => .none,
25932610 else => |loc_sn| sri: {
2611 // The target may not have a node yet, or it could be an extern that will never
2612 // have a node. In that case, flushGlobal will create the symbol table entry.
2613 const sti: SymbolTable.Index = if (target.sti != .none)
2614 target.sti
2615 else if (target.ni != .none)
2616 try updateSymbolTableEntry(coff, target_si)
2617 else
2618 .none;
2619
2620 const section = loc_sn.section(coff);
25942621 const header = loc_sn.header(coff);
25952622 const old_num_relocations = coff.targetLoad(&header.number_of_relocations);
25962623 const new_num_relocations = old_num_relocations + 1;
2624 const new_size = new_num_relocations * std.coff.Relocation.sizeOf();
2625 if (section.relocation_table_ni == .none) {
2626 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2627 section.relocation_table_ni = try coff.mf.addLastChildNode(gpa, Node.known.zcu_member, .{
2628 .size = new_size,
2629 .alignment = .@"2",
2630 .moved = true,
2631 .resized = true,
2632 });
2633 coff.nodes.appendAssumeCapacity(.{ .relocation_table = loc_sn });
2634 } else {
2635 try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);
2636 }
2637
25972638 coff.targetStore(
25982639 &header.number_of_relocations,
25992640 new_num_relocations,
26002641 );
26012642 coff.targetStore(
2602 &coff.symbolAuxSectionDefinitionPtr(loc_sn.symbol(coff)).number_of_relocations,
2643 &coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff)).number_of_relocations,
26032644 new_num_relocations,
26042645 );
26052646
2647 // TODO: These need to allocate from a free list (once deleting relocs is supported) (or can we just remove swap?)
2648
26062649 const sri: Section.RelocationIndex = .wrap(old_num_relocations);
26072650 const entry = sri.entry(coff, loc_sn).?;
2651 if (sti.unwrap()) |index| coff.targetStore(&entry.symbol_table_index, index);
26082652
2609 entry.virtual_address = @intCast(offset);
2610 switch (target.sti) {
2611 .none => {
2612 // TODO: Now is the moment when we know we need to add this to the symbol table
2613
2614 // DEBUG
2615 var iter = coff.globals.iterator();
2616 while (iter.next()) |kv| {
2617 if (kv.value_ptr.* == target_si) {
2618 log.warn("creating reloc but there is no symbol table entry yet `{s}` {d}!", .{ kv.key_ptr.name.toSlice(coff), target_si });
2619 break;
2620 }
2621 } else {
2622 log.warn("creating reloc but there is no symbol table entry yet (not global) {d}!", .{target_si});
2623 }
2624 // DEBUG
2625
2626 // TODO: Check all relocs at the end and assert if some of sri == .none
2627 entry.symbol_table_index = 0;
2628 },
2629 else => |sti| {
2630 entry.symbol_table_index = sti.unwrap().?;
2631 },
2632 }
2633
2634 // const reloc_type: Reloc.Type = switch (coff.targetLoad(&coff.headerPtr().machine)) {
2635 // else => unreachableaddrelo,
2636 // .AMD64 => .{ .AMD64 = .REL32 },
2637 // .I386 => .{ .I386 = .REL32 },
2638 // };
2639
2640 entry.type = @bitCast(@"type"); //@bitCast(reloc_type);
2641 if (coff.targetEndian() != native_endian)
2642 std.mem.byteSwapAllFieldsAligned(std.coff.Relocation, .@"2", entry);
2653 // applyLocationRelocs updates `virtual_address`
2654 // flushSymbolTableIndex updates `symbol_table_index`
2655 coff.targetStore(&entry.type, @bitCast(@"type"));
26432656
26442657 break :sri sri;
26452658 },
......@@ -2709,20 +2722,15 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
27092722 const sym = si.get(coff);
27102723 sym.ni = ni;
27112724 sym.section_number = sec_si.get(coff).section_number;
2712
2713 // if (!isImage(coff)) {
2714 // try coff.addSymbolTableEntry(
2715 // .{ .bytes = nav.fqn.toSlice(ip) },
2716 // si,
2717 // .{ .global = .{ .external = false, .import = false } },
2718 // );
2719 // }
27202725 },
27212726 else => si.deleteLocationRelocs(coff),
27222727 }
27232728 const sym = si.get(coff);
27242729 assert(sym.loc_relocs == .none);
27252730 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
2731 if (sym.target_relocs != .none)
2732 _ = try coff.updateSymbolTableEntry(si);
2733
27262734 break :ni sym.ni;
27272735 };
27282736
......@@ -2744,6 +2752,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
27442752 si.applyLocationRelocs(coff);
27452753 }
27462754
2755 // TODO: Did my MappedFile resize change affect this?
27472756 if (nav.resolved.?.@"linksection".unwrap()) |_| {
27482757 try ni.resize(&coff.mf, gpa, si.get(coff).size);
27492758 var parent_ni = ni;
......@@ -2846,20 +2855,14 @@ fn updateFuncInner(
28462855 const sym = si.get(coff);
28472856 sym.ni = ni;
28482857 sym.section_number = sec_si.get(coff).section_number;
2849 //
2850 // if (!isImage(coff)) {
2851 // try coff.addSymbolTableEntry(
2852 // .{ .bytes = nav.fqn.toSlice(ip) },
2853 // si,
2854 // .{ .global = .{ .external = false, .import = false } },
2855 // );
2856 // }
28572858 },
28582859 else => si.deleteLocationRelocs(coff),
28592860 }
28602861 const sym = si.get(coff);
28612862 assert(sym.loc_relocs == .none);
28622863 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
2864 if (sym.target_relocs != .none)
2865 _ = try coff.updateSymbolTableEntry(si);
28632866 break :ni sym.ni;
28642867 };
28652868
......@@ -3037,7 +3040,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
30373040 }
30383041 if (coff.global_pending_index < coff.globals.count()) {
30393042 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
3040 const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index);
3043 const gmi: Node.GlobalMapIndex = .wrap(coff.global_pending_index);
30413044 coff.global_pending_index += 1;
30423045 const sub_prog_node = coff.synth_prog_node.start(
30433046 gmi.globalName(coff).name.toSlice(coff),
......@@ -3187,19 +3190,6 @@ fn flushUav(
31873190 coff.nodes.appendAssumeCapacity(.{ .uav = umi });
31883191 sym.ni = ni;
31893192 sym.section_number = sec_si.get(coff).section_number;
3190
3191 // if (!isImage(coff)) {
3192 // var name: [12]u8 = undefined;
3193 // var w = std.Io.Writer.fixed(&name);
3194 // w.print("uav.{x}", .{umi}) catch unreachable;
3195 // // TODO: This is a bit awkward, the symbol table requires a name, and we
3196 // // need to be in the sym table to be the target of relocs
3197 // try coff.addSymbolTableEntry(
3198 // .{ .bytes = w.buffered() },
3199 // si,
3200 // .{ .global = .{ .external = false, .import = false } },
3201 // );
3202 // }
32033193 },
32043194 else => {
32053195 if (si.get(coff).ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte))
......@@ -3210,6 +3200,9 @@ fn flushUav(
32103200 const sym = si.get(coff);
32113201 assert(sym.loc_relocs == .none);
32123202 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
3203 if (sym.target_relocs != .none)
3204 _ = try coff.updateSymbolTableEntry(si);
3205
32133206 break :ni sym.ni;
32143207 };
32153208
......@@ -3238,11 +3231,14 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
32383231 log.debug("flushGlobal({s}, {?s}) = {d}", .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), gmi.symbol(coff) });
32393232
32403233 if (!coff.isImage()) {
3241 try coff.addSymbolTableEntry(
3242 .{ .string = gn.name },
3243 gmi.symbol(coff),
3244 .global,
3245 );
3234 const si = gmi.symbol(coff);
3235 assert(try coff.updateSymbolTableEntry(si) != .none);
3236 if (si.get(coff).ni != .none)
3237 try coff.ensureMemberSymbol(
3238 gn.name,
3239 coff.getNode(Node.known.zcu_member).archive_member,
3240 si,
3241 );
32463242
32473243 return;
32483244 }
......@@ -3707,9 +3703,9 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
37073703 try coff.virtualSlide(section_index + 1, sym.rva + virtual_size);
37083704 }
37093705
3710 if (coff.isArchive()) {
3706 if (!coff.isImage()) {
37113707 coff.targetStore(
3712 &coff.symbolAuxSectionDefinitionPtr(si).length,
3708 &coff.symbolTableSectionAuxEntryPtr(si).length,
37133709 @intCast(size),
37143710 );
37153711 }
src/link/MappedFile.zig+3-3
......@@ -696,7 +696,7 @@ fn shrinkNode(
696696 gpa: std.mem.Allocator,
697697 ni: Node.Index,
698698 size: u64,
699 shrink_next: bool,
699 shift_next: bool,
700700) !void {
701701 const node = ni.get(mf);
702702 const old_offset, _ = node.location().resolve(mf);
......@@ -714,7 +714,7 @@ fn shrinkNode(
714714 try mf.updates.ensureUnusedCapacity(gpa, 2);
715715
716716 ni.setLocationAssumeCapacity(mf, old_offset, size);
717 if (!shrink_next or node.next == .none) return;
717 if (!shift_next or node.next == .none) return;
718718
719719 const next = node.next.get(mf);
720720 const old_next_offset, const next_size = next.location().resolve(mf);
......@@ -738,7 +738,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
738738 const node = ni.get(mf);
739739 const old_offset, const old_size = node.location().resolve(mf);
740740 const new_size = node.flags.alignment.forward(@intCast(requested_size));
741 if (new_size <= old_size) return;
741 //if (new_size <= old_size) return;
742742
743743 // Resize the entire file
744744 if (ni == Node.Index.root) {