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
log8c2737fd95f46d43a13a69a0a2cdedecb61a1157
treed446834156daff8b047d6f7096871abd835430c5
parentf81bd30057d6a1d1d50851b65a644aa86296cd4c

Coff: Start working on symbol and relocation tables


2 files changed, 339 insertions(+), 139 deletions(-)

src/codegen/x86_64/Emit.zig+6-6
......@@ -161,13 +161,13 @@ pub fn emitMir(emit: *Emit) Error!void {
161161 .type = .FUNC,
162162 }) else if (emit.bin_file.cast(.macho)) |macho_file|
163163 @enumFromInt(try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null))
164 else if (emit.bin_file.cast(.coff2)) |coff| @enumFromInt(@intFromEnum(try coff.globalSymbol(
165 extern_func.toSlice(&emit.lower.mir).?,
166 switch (comp.compiler_rt_strat) {
164 else if (emit.bin_file.cast(.coff2)) |coff| @enumFromInt(@intFromEnum(try coff.globalSymbol(.{
165 .name = extern_func.toSlice(&emit.lower.mir).?,
166 .lib_name = switch (comp.compiler_rt_strat) {
167167 .none, .lib, .obj, .zcu => null,
168168 .dyn_lib => "compiler_rt",
169169 },
170 ))) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
170 }))) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
171171 .is_extern = true,
172172 } },
173173 },
......@@ -374,7 +374,7 @@ pub fn emitMir(emit: *Emit) Error!void {
374374 .op_index = 1,
375375 .target = .{ .symbol = .{
376376 .symbol = @enumFromInt(@intFromEnum(
377 try coff.globalSymbol("__tls_index", null),
377 try coff.globalSymbol(.{ .name = "__tls_index" }),
378378 )),
379379 .is_extern = false,
380380 } },
......@@ -409,7 +409,7 @@ pub fn emitMir(emit: *Emit) Error!void {
409409 .op_index = 1,
410410 .target = .{ .symbol = .{
411411 .symbol = @enumFromInt(@intFromEnum(
412 try coff.globalSymbol("_tls_index", null),
412 try coff.globalSymbol(.{ .name = "_tls_index" }),
413413 )),
414414 .is_extern = false,
415415 } },
src/link/Coff.zig+333-133
......@@ -38,7 +38,7 @@ strings: std.HashMapUnmanaged(
3838 std.hash_map.default_max_load_percentage,
3939),
4040string_bytes: std.ArrayList(u8),
41section_table: std.ArrayList(Symbol.Index),
41section_table: std.ArrayList(Section),
4242pseudo_section_table: std.array_hash_map.Auto(String, Symbol.Index),
4343object_section_table: std.array_hash_map.Auto(String, Symbol.Index),
4444symbols: std.ArrayList(Symbol),
......@@ -161,8 +161,11 @@ pub const Node = union(enum) {
161161 symbol_table_entry,
162162 // Archives and objects only
163163 string_table,
164 // Archives and objects only
165 relocation_table: Symbol.SectionNumber,
166 relocation_table_entry: Reloc.Index,
164167
165 image_section: Symbol.Index, // TODO: image_section -> section
168 image_section: Symbol.Index, // TODO: rename image_section -> section
166169
167170 /// Images only
168171 import_directory_table,
......@@ -318,9 +321,7 @@ pub const Member = struct {
318321 kind: Kind,
319322 header_ni: MappedFile.Node.Index,
320323 content_ni: MappedFile.Node.Index,
321 // Maps symbols contained in this member to their index in the first linker member's symbol table
322 // TODO: This could contain information about the name string if we need
323 symbol_offsets: std.AutoArrayHashMapUnmanaged(Symbol.Index, u33),
324 first_linker_indices: std.AutoArrayHashMapUnmanaged(Symbol.Index, FirstLinkerIndex),
324325
325326 pub const Kind = enum {
326327 first_linker,
......@@ -343,6 +344,10 @@ pub const Member = struct {
343344 }
344345 };
345346
347 pub const FirstLinkerIndex = enum(u32) {
348 _,
349 };
350
346351 pub fn headerPtr(member: *Member, coff: *Coff) *std.coff.ArchiveMemberHeader {
347352 return @ptrCast(@alignCast(member.header_ni.slice(&coff.mf)));
348353 }
......@@ -458,14 +463,12 @@ pub const SymbolTable = struct {
458463
459464 pub const Entry = struct {
460465 entry_si: Symbol.Index,
461 index: Index,
466 sti: Index, // TODO: Is this redundant now that we store it on symbol?
462467 };
463468
464469 pub const Add = union(enum) {
465470 section,
466 global: struct {
467 import: bool,
468 },
471 global,
469472 };
470473
471474 pub const SymbolName = union(enum) {
......@@ -473,12 +476,25 @@ pub const SymbolTable = struct {
473476 long: StringIndex,
474477 };
475478
476 // Symbol.Index does not map 1:1 with SymbolTable.Index due to auxiliary entries
479 // Symbol.Index does not map 1:1 with SymbolTable.Index due to
480 // variable number of auxiliary entries that may trail each symbol
477481 pub const Index = enum(u32) {
482 none,
478483 _,
479484
485 pub fn wrap(i: ?u32) Index {
486 return @enumFromInt((i orelse return .none) + 1);
487 }
488
489 pub fn unwrap(sti: Index) ?u32 {
490 return switch (sti) {
491 .none => null,
492 _ => @intFromEnum(sti) - 1,
493 };
494 }
495
480496 pub fn get(sti: SymbolTable.Index, coff: *Coff) *Entry {
481 return &coff.symbol_table.entries.values()[@intFromEnum(sti)];
497 return &coff.symbol_table.entries.values()[sti.unwrap().?];
482498 }
483499 };
484500
......@@ -607,6 +623,37 @@ pub const String = enum(u32) {
607623 }
608624};
609625
626pub const Section = struct {
627 si: Symbol.Index,
628 relocation_table_ni: MappedFile.Node.Index,
629
630 pub const RelocationIndex = enum(u32) {
631 none,
632 _,
633
634 pub fn wrap(i: ?u32) RelocationIndex {
635 return @enumFromInt((i orelse return .none) + 1);
636 }
637
638 pub fn unwrap(sri: RelocationIndex) ?u32 {
639 return switch (sri) {
640 .none => null,
641 _ => @intFromEnum(sri) - 1,
642 };
643 }
644
645 pub fn entry(
646 sri: RelocationIndex,
647 coff: *Coff,
648 sn: Symbol.SectionNumber,
649 ) ?*align(2) std.coff.Relocation {
650 if (sri == .none) return null;
651 const table_slice = sn.section(coff).relocation_table_ni.slice(&coff.mf);
652 return @ptrCast(@alignCast(&table_slice[sri.unwrap().? * std.coff.Relocation.sizeOf()]));
653 }
654 };
655};
656
610657pub const GlobalName = struct { name: String, lib_name: String.Optional };
611658
612659pub const Symbol = struct {
......@@ -618,9 +665,9 @@ pub const Symbol = struct {
618665 /// Relocations targeting this symbol
619666 target_relocs: Reloc.Index,
620667 section_number: SectionNumber,
668 sti: SymbolTable.Index,
621669 unused0: u32 = 0,
622 unused1: u32 = 0,
623 unused2: u16 = 0,
670 unused1: u16 = 0,
624671
625672 pub const SectionNumber = enum(i16) {
626673 UNDEFINED = 0,
......@@ -633,7 +680,11 @@ pub const Symbol = struct {
633680 }
634681
635682 pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index {
636 return coff.section_table.items[sn.toIndex()];
683 return sn.section(coff).si;
684 }
685
686 pub fn section(sn: SectionNumber, coff: *const Coff) *Section {
687 return &coff.section_table.items[sn.toIndex()];
637688 }
638689
639690 pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader {
......@@ -692,6 +743,17 @@ pub const Symbol = struct {
692743 }
693744 sym.loc_relocs = .none;
694745 }
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 }
695757 };
696758
697759 comptime {
......@@ -705,7 +767,7 @@ pub const Reloc = extern struct {
705767 next: Reloc.Index,
706768 loc: Symbol.Index,
707769 target: Symbol.Index,
708 unused: u32,
770 sri: Section.RelocationIndex,
709771 offset: u64,
710772 addend: i64,
711773
......@@ -725,8 +787,8 @@ pub const Reloc = extern struct {
725787 none = std.math.maxInt(u32),
726788 _,
727789
728 pub fn get(si: Reloc.Index, coff: *Coff) *Reloc {
729 return &coff.relocs.items[@intFromEnum(si)];
790 pub fn get(ri: Reloc.Index, coff: *Coff) *Reloc {
791 return &coff.relocs.items[@intFromEnum(ri)];
730792 }
731793 };
732794
......@@ -861,6 +923,8 @@ pub const Reloc = extern struct {
861923 }
862924
863925 pub fn delete(reloc: *Reloc, coff: *Coff) void {
926 // TODO: Need to remove this from the COFF relocation table (remove swap)
927
864928 switch (reloc.prev) {
865929 .none => {
866930 const target = reloc.target.get(coff);
......@@ -1021,10 +1085,11 @@ pub fn deinit(coff: *Coff) void {
10211085 const gpa = coff.base.comp.gpa;
10221086 coff.mf.deinit(gpa);
10231087 coff.nodes.deinit(gpa);
1024 // TODO: Update this
10251088 coff.long_names_table.entries.deinit(gpa);
10261089 coff.import_table.entries.deinit(gpa);
10271090 coff.export_table.entries.deinit(gpa);
1091 coff.symbol_table.string_offsets.deinit(gpa);
1092 coff.symbol_table.entries.deinit(gpa);
10281093 coff.strings.deinit(gpa);
10291094 coff.string_bytes.deinit(gpa);
10301095 coff.section_table.deinit(gpa);
......@@ -1356,9 +1421,10 @@ fn initHeaders(
13561421 }));
13571422 coff.nodes.appendAssumeCapacity(.section_table);
13581423
1424 // TODO: These two nodes could be inside one movable node
13591425 const symbol_table_ni = Node.known.symbol_table;
13601426 assert(symbol_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{
1361 .alignment = .@"4",
1427 .alignment = .@"2",
13621428 .fixed = true,
13631429 .moved = true,
13641430 }));
......@@ -1366,7 +1432,8 @@ fn initHeaders(
13661432
13671433 const string_table_ni = Node.known.string_table;
13681434 assert(string_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{
1369 .size = @sizeOf(u32),
1435 .alignment = .@"2",
1436 .size = if (!is_image) @sizeOf(u32) else 0,
13701437 .fixed = true,
13711438 .resized = true,
13721439 }));
......@@ -1382,6 +1449,7 @@ fn initHeaders(
13821449 .loc_relocs = .none,
13831450 .target_relocs = .none,
13841451 .section_number = .UNDEFINED,
1452 .sti = .none,
13851453 };
13861454 assert(try coff.addSection(".data", .{
13871455 .CNT_INITIALIZED_DATA = true,
......@@ -1533,6 +1601,8 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
15331601 .symbol_table,
15341602 .symbol_table_entry,
15351603 .string_table,
1604 .relocation_table,
1605 .relocation_table_entry,
15361606 => unreachable,
15371607 .image_section => |si| si,
15381608 .import_directory_table => break :parent_rva coff.targetLoad(
......@@ -1721,17 +1791,18 @@ pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader {
17211791
17221792pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) *align(2) std.coff.Symbol {
17231793 return @ptrCast(@alignCast(
1724 &Node.known.symbol_table.slice(&coff.mf)[@intFromEnum(sti) * std.coff.Symbol.sizeOf()],
1794 &Node.known.symbol_table.slice(&coff.mf)[sti.unwrap().? * std.coff.Symbol.sizeOf()],
17251795 ));
17261796}
17271797
17281798pub fn symbolAuxSectionDefinitionPtr(coff: *Coff, si: Symbol.Index) *align(2) std.coff.SectionDefinition {
1729 const sti = coff.symbol_table.entries.get(si).?.index;
1730
1799 const sti = coff.symbol_table.entries.get(si).?.sti;
17311800 const symbol = coff.symbolTableEntryPtr(sti);
17321801 assert(symbol.storage_class == .STATIC and symbol.number_of_aux_symbols == 1);
17331802
1734 return @ptrCast(symbolTableEntryPtr(coff, @enumFromInt(@intFromEnum(sti) + 1)));
1803 return @ptrCast(@alignCast(
1804 &Node.known.symbol_table.slice(&coff.mf)[(sti.unwrap().? + 1) * std.coff.Symbol.sizeOf()],
1805 ));
17351806}
17361807
17371808pub fn symbolTableStringLenPtr(coff: *Coff) *align(2) u32 {
......@@ -1772,6 +1843,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
17721843 .loc_relocs = .none,
17731844 .target_relocs = .none,
17741845 .section_number = .UNDEFINED,
1846 .sti = .none,
17751847 };
17761848 return @enumFromInt(coff.symbols.items.len);
17771849}
......@@ -1808,27 +1880,22 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {
18081880 return @enumFromInt(gop.key_ptr.*);
18091881}
18101882
1811pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {
1812 return (try getOrPutGlobalSymbol(coff, name, lib_name)).value_ptr.*;
1813}
1814
1815fn getOrPutGlobalSymbol(
1816 coff: *Coff,
1883pub fn globalSymbol(coff: *Coff, opts: struct {
18171884 name: []const u8,
1818 lib_name: ?[]const u8,
1819) !std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index).GetOrPutResult {
1885 lib_name: ?[]const u8 = null,
1886}) !Symbol.Index {
18201887 const gpa = coff.base.comp.gpa;
18211888 try coff.symbols.ensureUnusedCapacity(gpa, 1);
18221889 const sym_gop = try coff.globals.getOrPut(gpa, .{
1823 .name = try coff.getOrPutString(name),
1824 .lib_name = try coff.getOrPutOptionalString(lib_name),
1890 .name = try coff.getOrPutString(opts.name),
1891 .lib_name = try coff.getOrPutOptionalString(opts.lib_name),
18251892 });
18261893 if (!sym_gop.found_existing) {
18271894 sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();
18281895 coff.synth_prog_node.increaseEstimatedTotalItems(1);
18291896 }
18301897
1831 return sym_gop;
1898 return sym_gop.value_ptr.*;
18321899}
18331900
18341901fn navSection(
......@@ -1870,10 +1937,10 @@ fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.Na
18701937pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
18711938 const ip = &zcu.intern_pool;
18721939 const nav = ip.getNav(nav_index);
1873 if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(
1874 @"extern".name.toSlice(ip),
1875 @"extern".lib_name.toSlice(ip),
1876 );
1940 if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(.{
1941 .name = @"extern".name.toSlice(ip),
1942 .lib_name = @"extern".lib_name.toSlice(ip),
1943 });
18771944 const nmi = try coff.navMapIndex(zcu, nav_index);
18781945 return nmi.symbol(coff);
18791946}
......@@ -1926,7 +1993,7 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.
19261993 reloc_info.addend,
19271994 switch (coff.targetLoad(&coff.headerPtr().machine)) {
19281995 else => unreachable,
1929 .AMD64 => .{ .AMD64 = .ADDR64 },
1996 .AMD64 => .{ .AMD64 = .ADDR64 }, // TODO: Switch to REL32 for obj/archive
19301997 .I386 => .{ .I386 = .DIR32 },
19311998 },
19321999 );
......@@ -1941,7 +2008,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: Member.Kind, size: usize) !Member.
19412008 const comp = coff.base.comp;
19422009 const gpa = comp.gpa;
19432010
1944 // TODO: These two nodes could to be inside a movable node? Only if coff or import
2011 // TODO: These two nodes could to be inside a movable node if kind == .coff|.import
19452012
19462013 const header_ni = try coff.mf.addLastChildNode(gpa, Node.known.file, .{
19472014 .size = @sizeOf(std.coff.ArchiveMemberHeader),
......@@ -1967,7 +2034,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: Member.Kind, size: usize) !Member.
19672034 .kind = kind,
19682035 .header_ni = header_ni,
19692036 .content_ni = content_ni,
1970 .symbol_offsets = .empty,
2037 .first_linker_indices = .empty,
19712038 });
19722039
19732040 coff.nodes.appendAssumeCapacity(.{ .archive_member_header = mi });
......@@ -2028,9 +2095,9 @@ fn appendMemberSymbolString(
20282095 name_slice[name.len] = 0;
20292096}
20302097
2031fn addMemberSymbol(
2098fn ensureMemberSymbol(
20322099 coff: *Coff,
2033 name: String,
2100 name: []const u8,
20342101 mi: Member.Index,
20352102 si: Symbol.Index,
20362103) !void {
......@@ -2038,66 +2105,69 @@ fn addMemberSymbol(
20382105 const member = mi.get(coff);
20392106 assert(member.kind == .coff);
20402107
2041 const gop = try member.symbol_offsets.getOrPut(gpa, si);
2108 const name_string = try coff.getOrPutString(name);
2109 const gop = try member.first_linker_indices.getOrPut(gpa, si);
20422110 if (gop.found_existing) return;
20432111
2044 // TODO: Detect duplicate names (ie. a name used by a symbol in another member, not the zcu since those already go through globals)
2112 // TODO: Detect duplicate names (ie. a name used by a symbol in another member,
2113 // not the zcu since those already go through globals)
20452114
2046 const symbol_index = blk: {
2115 const mfli: Member.FirstLinkerIndex = blk: {
20472116 const num_symbols_ptr = coff.firstLinkerMemberNumSymbolsPtr();
20482117 const num_symbols = std.mem.toNative(u32, num_symbols_ptr.*, .big);
20492118 num_symbols_ptr.* = std.mem.nativeTo(u32, num_symbols + 1, .big);
2050 break :blk num_symbols;
2119 break :blk @enumFromInt(num_symbols);
20512120 };
20522121
2053 gop.value_ptr.* = symbol_index;
2054 const name_slice = name.toSlice(coff);
2122 gop.value_ptr.* = mfli;
20552123
20562124 // Linker member fields are not modeled as nodes because MappedFile
20572125 // can't guarantee that they will be tightly packed after resizing
20582126
2059 const new_string_table_size = coff.lib_string_len + name_slice.len + 1;
2127 const new_string_table_size = coff.lib_string_len + name.len + 1;
20602128 defer coff.lib_string_len = new_string_table_size;
20612129
20622130 {
2063 const old_header_size = @sizeOf(u32) + symbol_index * @sizeOf(u32);
2131 const old_header_size = @sizeOf(u32) + @intFromEnum(mfli) * @sizeOf(u32);
20642132 const new_header_size = old_header_size + @sizeOf(u32);
20652133 try Node.known.first_linker_member.resize(&coff.mf, gpa, new_header_size + new_string_table_size);
20662134
20672135 const slice = Node.known.first_linker_member.slice(&coff.mf);
20682136 @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]);
2069 @memcpy(slice[new_header_size + coff.lib_string_len ..][0 .. name_slice.len + 1], name_slice[0 .. name_slice.len + 1]);
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;
20702139
20712140 // New offset entry is written in flushMember
20722141 }
20732142
20742143 {
20752144 const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr());
2076 const old_header_size = 2 * @sizeOf(u32) + num_members * @sizeOf(u32) + symbol_index * @sizeOf(u16);
2145 const old_header_size = 2 * @sizeOf(u32) + num_members * @sizeOf(u32) + @intFromEnum(mfli) * @sizeOf(u16);
20772146 const new_header_size = old_header_size + @sizeOf(u16);
20782147 try Node.known.second_linker_member.resize(&coff.mf, gpa, new_header_size + new_string_table_size);
20792148
20802149 const needs_sort = if (coff.lib_string_table.items.len > 0)
20812150 std.mem.lessThan(
20822151 u8,
2083 name_slice,
2152 name,
20842153 coff.lib_string_table.items[coff.lib_string_table.items.len - 1].toSlice(coff),
20852154 )
20862155 else
20872156 false;
20882157
2089 try coff.lib_string_table.append(gpa, name);
2158 try coff.lib_string_table.append(gpa, name_string);
20902159
20912160 const slice = Node.known.second_linker_member.slice(&coff.mf);
20922161 const num_symbols_ptr: *u32 = @ptrCast(@alignCast(slice[@sizeOf(u32) + num_members * @sizeOf(u32) ..]));
2093 coff.targetStore(num_symbols_ptr, symbol_index + 1);
2162 coff.targetStore(num_symbols_ptr, @intFromEnum(mfli) + 1);
20942163
20952164 if (needs_sort) {
20962165 // The entire string table is rebuilt in flushMember after sorting
20972166 coff.pending_members.putAssumeCapacity(Member.Index.second, {});
20982167 } else {
20992168 @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]);
2100 @memcpy(slice[new_header_size + coff.lib_string_len ..][0 .. name_slice.len + 1], name_slice[0 .. name_slice.len + 1]);
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;
21012171 }
21022172
21032173 // Indices in this table are 1-based
......@@ -2120,6 +2190,7 @@ fn addSymbolTableEntry(
21202190 assert(!coff.isImage());
21212191 const gpa = coff.base.comp.gpa;
21222192
2193 // TODO: Avoid geOrPutString if it fits (only need to actually make the String for adding member symbol)
21232194 const string, const name_slice = switch (name) {
21242195 .bytes => |bytes| .{ try coff.getOrPutString(bytes), bytes },
21252196 .string => |s| .{ s, s.toSlice(coff) },
......@@ -2140,11 +2211,18 @@ fn addSymbolTableEntry(
21402211 break :index .{ .long = string_gop.value_ptr.* };
21412212 } else .{ .short = name_slice };
21422213
2143 const symbol_index = coff.targetLoad(&coff.headerPtr().number_of_symbols);
2214 const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
2215
2216 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
21442224 const symbols_added: u8 = switch (add) {
21452225 .section => count: {
2146 const sym = si.get(coff);
2147
21482226 try coff.nodes.ensureUnusedCapacity(gpa, 2);
21492227 _ = try coff.addSymbolTableEntryAssumeCapacity(
21502228 symbol_name,
......@@ -2159,28 +2237,32 @@ fn addSymbolTableEntry(
21592237 );
21602238
21612239 // Aux entry ields are updated by flushMoved / flushResized
2162
21632240 try coff.symbol_table.entries.put(gpa, si, .{
21642241 .entry_si = .null,
2165 .index = @enumFromInt(symbol_index),
2242 .sti = sym.sti,
21662243 });
21672244
21682245 break :count 2;
21692246 },
2170 .global => |global| count: {
2171 const sym = si.get(coff);
2172
2247 .global => count: {
21732248 try coff.nodes.ensureUnusedCapacity(gpa, 1);
21742249 try coff.symbols.ensureUnusedCapacity(gpa, 1);
21752250
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
21762259 const entry_ni = try coff.addSymbolTableEntryAssumeCapacity(
21772260 symbol_name,
2178 if (global.import) 0 else coff.computeNodeSectionOffset(sym.ni),
2179 if (global.import) .UNDEFINED else sym.section_number,
2261 if (sym.ni == .none) 0 else coff.computeNodeSectionOffset(sym.ni),
2262 sym.section_number,
21802263 .{
21812264 .base_type = .NULL,
2182 .complex_type = if (global.import or
2183 Symbol.Index.text.get(coff).section_number == sym.section_number)
2265 .complex_type = if (Symbol.Index.text.get(coff).section_number == sym.section_number)
21842266 .FUNCTION
21852267 else
21862268 .NULL,
......@@ -2198,24 +2280,27 @@ fn addSymbolTableEntry(
21982280 entry_sym.section_number = .UNDEFINED;
21992281 }
22002282
2201 try coff.addReloc(
2202 entry_si,
2203 @offsetOf(std.coff.Symbol, "value"),
2204 si,
2205 0,
2206 .{ .AMD64 = .SECREL },
2207 );
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 }
22082293
22092294 try coff.symbol_table.entries.put(gpa, si, .{
22102295 .entry_si = entry_si,
2211 .index = @enumFromInt(symbol_index),
2296 .sti = sym.sti,
22122297 });
22132298
22142299 break :count 1;
22152300 },
22162301 };
22172302
2218 const new_num_symbols = symbol_index + symbols_added;
2303 const new_num_symbols = old_num_symbols + symbols_added;
22192304 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
22202305 coff.symbol_table.pending_shrink =
22212306 Node.known.symbol_table.location(&coff.mf).resolve(&coff.mf)[1] >
......@@ -2243,15 +2328,6 @@ fn addSymbolTableEntryAssumeCapacity(
22432328 coff.nodes.appendAssumeCapacity(.symbol_table_entry);
22442329
22452330 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
22552331 switch (name) {
22562332 .short => |s| {
22572333 @memcpy(entry.name[0..s.len], s);
......@@ -2264,6 +2340,13 @@ fn addSymbolTableEntryAssumeCapacity(
22642340 },
22652341 }
22662342
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;
2349
22672350 if (coff.targetEndian() != native_endian)
22682351 std.mem.byteSwapAllFields(std.coff.SectionHeader, entry.*);
22692352
......@@ -2310,7 +2393,10 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
23102393 });
23112394
23122395 const si = coff.addSymbolAssumeCapacity();
2313 coff.section_table.appendAssumeCapacity(si);
2396 coff.section_table.appendAssumeCapacity(.{
2397 .si = si,
2398 .relocation_table_ni = .none,
2399 });
23142400 coff.nodes.appendAssumeCapacity(.{ .image_section = si });
23152401 const section_table = coff.sectionTableSlice();
23162402
......@@ -2318,7 +2404,7 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
23182404 const virtual_size = coff.optionalHeaderField(.section_alignment);
23192405 const rva: u32 = switch (section_index) {
23202406 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]),
2321 else => coff.section_table.items[section_index - 1].get(coff).rva +
2407 else => coff.section_table.items[section_index - 1].si.get(coff).rva +
23222408 coff.targetLoad(&section_table[section_index - 1].virtual_size),
23232409 };
23242410
......@@ -2456,6 +2542,35 @@ fn objectSectionMapIndex(
24562542 return osmi;
24572543}
24582544
2545fn ensureUnusedRelocCapacity(coff: *Coff, loc_si: Symbol.Index, len: usize) !void {
2546 const gpa = coff.base.comp.gpa;
2547
2548 try coff.relocs.ensureUnusedCapacity(gpa, len);
2549 if (isImage(coff)) return;
2550
2551 switch (loc_si.get(coff).section_number) {
2552 .UNDEFINED, .ABSOLUTE, .DEBUG => {},
2553 else => |sn| {
2554 const section = sn.section(coff);
2555 const header = sn.header(coff);
2556 const new_size = (len + coff.targetLoad(&header.number_of_relocations)) * std.coff.Relocation.sizeOf();
2557 if (section.relocation_table_ni == .none) {
2558 // The entry's length in the file is shorter than its @sizeOf
2559 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2560 section.relocation_table_ni = try coff.mf.addLastChildNode(gpa, Node.known.zcu_member, .{
2561 .size = new_size,
2562 .alignment = .@"2",
2563 .moved = true,
2564 .resized = true,
2565 });
2566 coff.nodes.appendAssumeCapacity(.{ .relocation_table = sn });
2567 } else {
2568 try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);
2569 }
2570 },
2571 }
2572}
2573
24592574pub fn addReloc(
24602575 coff: *Coff,
24612576 loc_si: Symbol.Index,
......@@ -2464,16 +2579,80 @@ pub fn addReloc(
24642579 addend: i64,
24652580 @"type": Reloc.Type,
24662581) !void {
2467 const gpa = coff.base.comp.gpa;
24682582 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 });
2584
2585 try ensureUnusedRelocCapacity(coff, loc_si, 1);
2586
2587 // TODO: The switch should be in an ensure capacity for reloc fn
2588
2589 const sri: Section.RelocationIndex = if (isImage(coff))
2590 .none
2591 else switch (loc_si.get(coff).section_number) {
2592 .UNDEFINED, .ABSOLUTE, .DEBUG => .none,
2593 else => |loc_sn| sri: {
2594 const header = loc_sn.header(coff);
2595 const old_num_relocations = coff.targetLoad(&header.number_of_relocations);
2596 const new_num_relocations = old_num_relocations + 1;
2597 coff.targetStore(
2598 &header.number_of_relocations,
2599 new_num_relocations,
2600 );
2601 coff.targetStore(
2602 &coff.symbolAuxSectionDefinitionPtr(loc_sn.symbol(coff)).number_of_relocations,
2603 new_num_relocations,
2604 );
2605
2606 const sri: Section.RelocationIndex = .wrap(old_num_relocations);
2607 const entry = sri.entry(coff, loc_sn).?;
2608
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);
2643
2644 break :sri sri;
2645 },
2646 };
2647
24692648 const ri: Reloc.Index = @enumFromInt(coff.relocs.items.len);
2470 (try coff.relocs.addOne(gpa)).* = .{
2649 coff.relocs.addOneAssumeCapacity().* = .{
24712650 .type = @"type",
24722651 .prev = .none,
24732652 .next = target.target_relocs,
24742653 .loc = loc_si,
24752654 .target = target_si,
2476 .unused = 0,
2655 .sri = sri,
24772656 .offset = offset,
24782657 .addend = addend,
24792658 };
......@@ -2516,6 +2695,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
25162695
25172696 const nmi = try coff.navMapIndex(zcu, nav_index);
25182697 const si = nmi.symbol(coff);
2698 log.debug("updateNav({f}) = {d}", .{ nav.fqn.fmt(ip), si });
25192699 const ni = ni: {
25202700 switch (si.get(coff).ni) {
25212701 .none => {
......@@ -2530,7 +2710,13 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
25302710 sym.ni = ni;
25312711 sym.section_number = sec_si.get(coff).section_number;
25322712
2533 // TODO: Add symbol table entry
2713 // if (!isImage(coff)) {
2714 // try coff.addSymbolTableEntry(
2715 // .{ .bytes = nav.fqn.toSlice(ip) },
2716 // si,
2717 // .{ .global = .{ .external = false, .import = false } },
2718 // );
2719 // }
25342720 },
25352721 else => si.deleteLocationRelocs(coff),
25362722 }
......@@ -2660,6 +2846,14 @@ fn updateFuncInner(
26602846 const sym = si.get(coff);
26612847 sym.ni = ni;
26622848 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 // }
26632857 },
26642858 else => si.deleteLocationRelocs(coff),
26652859 }
......@@ -2993,6 +3187,19 @@ fn flushUav(
29933187 coff.nodes.appendAssumeCapacity(.{ .uav = umi });
29943188 sym.ni = ni;
29953189 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 // }
29963203 },
29973204 else => {
29983205 if (si.get(coff).ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte))
......@@ -3028,21 +3235,14 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
30283235 const comp = zcu.comp;
30293236 const gpa = zcu.gpa;
30303237 const gn = gmi.globalName(coff);
3238 log.debug("flushGlobal({s}, {?s}) = {d}", .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), gmi.symbol(coff) });
30313239
30323240 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 // );
3241 try coff.addSymbolTableEntry(
3242 .{ .string = gn.name },
3243 gmi.symbol(coff),
3244 .global,
3245 );
30463246
30473247 return;
30483248 }
......@@ -3268,8 +3468,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
32683468 .data_directories,
32693469 .section_table,
32703470 .placeholder,
3271
3272 .symbol_table_entry,
3471 .symbol_table_entry, // TODO: Need to impl this for symbol table updates to work?
32733472 .string_table,
32743473 => if (!coff.isArchive()) unreachable,
32753474 .symbol_table => {
......@@ -3278,6 +3477,13 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
32783477 @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]),
32793478 );
32803479 },
3480 .relocation_table => |sn| {
3481 coff.targetStore(
3482 &sn.header(coff).pointer_to_relocations,
3483 @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]),
3484 );
3485 },
3486 .relocation_table_entry => {},
32813487 .archive_member_header => |mi| {
32823488 const member = mi.get(coff);
32833489 switch (member.kind) {
......@@ -3439,7 +3645,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
34393645 ),
34403646 }
34413647
3442 if (size > coff.section_table.items[0].get(coff).rva) try coff.virtualSlide(
3648 if (size > coff.section_table.items[0].si.get(coff).rva) try coff.virtualSlide(
34433649 0,
34443650 std.mem.alignForward(
34453651 u32,
......@@ -3483,6 +3689,9 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
34833689 assert(!coff.isImage());
34843690 coff.targetStore(coff.symbolTableStringLenPtr(), @intCast(size));
34853691 },
3692 .relocation_table,
3693 .relocation_table_entry,
3694 => assert(!coff.isImage()),
34863695 .image_section => |si| {
34873696 const sym = si.get(coff);
34883697 const section_index = sym.section_number.toIndex();
......@@ -3587,8 +3796,8 @@ fn flushMember(coff: *Coff, mi: Member.Index) !void {
35873796 .coff => {
35883797 const file_offset: u32 = @intCast(member.header_ni.fileLocation(&coff.mf, false).offset);
35893798 const first_linker_offsets = coff.firstLinkerMemberOffsetsSlice();
3590 for (member.symbol_offsets.values()) |offset_index|
3591 first_linker_offsets[offset_index] = std.mem.nativeTo(u32, file_offset, .big);
3799 for (member.first_linker_indices.values()) |mfli|
3800 first_linker_offsets[@intFromEnum(mfli)] = std.mem.nativeTo(u32, file_offset, .big);
35923801 },
35933802 }
35943803}
......@@ -3631,12 +3840,12 @@ fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {
36313840 for (
36323841 coff.section_table.items[start_section_index..],
36333842 coff.sectionTableSlice()[start_section_index..],
3634 ) |section_si, *section| {
3635 const section_sym = section_si.get(coff);
3843 ) |*section, *header| {
3844 const section_sym = section.si.get(coff);
36363845 section_sym.rva = rva;
3637 coff.targetStore(&section.virtual_address, rva);
3846 coff.targetStore(&header.virtual_address, rva);
36383847 try section_sym.ni.childrenMoved(coff.base.comp.gpa, &coff.mf);
3639 rva += coff.targetLoad(&section.virtual_size);
3848 rva += coff.targetLoad(&header.virtual_size);
36403849 }
36413850 switch (coff.optionalHeaderPtr()) {
36423851 inline else => |optional_header| coff.targetStore(
......@@ -3690,8 +3899,10 @@ fn updateExportsInner(
36903899 for (export_indices) |export_index| {
36913900 const @"export" = export_index.ptr(zcu);
36923901 const name = @"export".opts.name.toSlice(ip);
3693 const symbol_gop = try coff.getOrPutGlobalSymbol(name, null);
3694 const export_si = symbol_gop.value_ptr.*;
3902 const export_si = try coff.globalSymbol(.{
3903 .name = name,
3904 .lib_name = null,
3905 });
36953906 const export_sym = export_si.get(coff);
36963907 export_sym.ni = exported_ni;
36973908 export_sym.rva = exported_sym.rva;
......@@ -3707,20 +3918,6 @@ fn updateExportsInner(
37073918 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);
37083919 }
37093920
3710 if (coff.isArchive()) {
3711 try coff.addMemberSymbol(
3712 symbol_gop.key_ptr.*.name,
3713 coff.getNode(Node.known.zcu_member).archive_member,
3714 export_si,
3715 );
3716
3717 try coff.addSymbolTableEntry(
3718 .{ .bytes = name },
3719 export_si,
3720 .{ .global = .{ .import = false } },
3721 );
3722 }
3723
37243921 if (coff.export_table.ni == .none) continue;
37253922
37263923 const entries_ctx = ExportTable.Adapter{ .coff = coff };
......@@ -3809,7 +4006,7 @@ fn updateExportsInner(
38094006 gop.value_ptr.si = export_si;
38104007 const reloc = gop.value_ptr.*.export_address_table_ri.get(coff);
38114008 reloc.target = export_si;
3812 export_si.applyTargetRelocs(coff);
4009 export_si.applyTargetRelocs(coff); // TODO: Potentially doing this twice, defer first one?
38134010 }
38144011 }
38154012}
......@@ -3818,6 +4015,9 @@ pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTe
38184015 _ = coff;
38194016 _ = exported;
38204017 _ = name;
4018
4019 // TODO: Delete from first / second linker member table (remove swap?)
4020 // TODO: Delete from symbol table inside section
38214021}
38224022
38234023fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) !void {