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:42-04:00
logb6192adfb22da64973c961297b60a74a5b6c9b23
treeb680901e7b2545dacb9fed22b022455ee4b4d46f
parent14a7131c4f97895d6ab600b88940b6afb6d6ae4e

Coff: Linking input objects

- Input object validation - Load sections, symbols, and relocs from input objects - Load reloc addends from the reloc locations in input objects - Flush input sections into the output

3 files changed, 669 insertions(+), 139 deletions(-)

lib/std/coff.zig+12-9
...@@ -666,7 +666,7 @@ pub const Symbol = extern struct {...@@ -666,7 +666,7 @@ pub const Symbol = extern struct {
666 storage_class: StorageClass,666 storage_class: StorageClass,
667 number_of_aux_symbols: u8,667 number_of_aux_symbols: u8,
668668
669 pub fn sizeOf() usize {669 pub fn sizeOf() comptime_int {
670 return 18;670 return 18;
671 }671 }
672672
...@@ -929,7 +929,7 @@ pub const WeakExternalDefinition = extern struct {...@@ -929,7 +929,7 @@ pub const WeakExternalDefinition = extern struct {
929929
930 unused: [10]u8,930 unused: [10]u8,
931931
932 pub fn sizeOf() usize {932 pub fn sizeOf() comptime_int {
933 return 18;933 return 18;
934 }934 }
935};935};
...@@ -1393,7 +1393,7 @@ pub const Relocation = extern struct {...@@ -1393,7 +1393,7 @@ pub const Relocation = extern struct {
1393 symbol_table_index: u32,1393 symbol_table_index: u32,
1394 type: u16,1394 type: u16,
13951395
1396 pub fn sizeOf() usize {1396 pub fn sizeOf() comptime_int {
1397 return 10;1397 return 10;
1398 }1398 }
1399};1399};
...@@ -1986,11 +1986,14 @@ pub const ArchiveMemberHeader = extern struct {...@@ -1986,11 +1986,14 @@ pub const ArchiveMemberHeader = extern struct {
1986 end_of_header: [2]u8,1986 end_of_header: [2]u8,
1987};1987};
19881988
1989pub const FirstLinkerMemberHeader = extern struct {1989pub const LineNumber = extern struct {
1990 /// Big-endian symbol count1990 type: extern union {
1991 number_of_symbols: u32,1991 symbol_table_index: u32,
1992};1992 virtual_address: u32,
1993 },
1994 line_number: u16,
19931995
1994pub const SecondLinkerMemberHeader = extern struct {1996 pub fn sizeOf() comptime_int {
1995 number_of_members: u32,1997 return 6;
1998 }
1996};1999};
src/codegen/x86_64/Emit.zig+3-3
...@@ -816,7 +816,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -816,7 +816,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
816 @enumFromInt(@intFromEnum(emit.atom_id)),816 @enumFromInt(@intFromEnum(emit.atom_id)),
817 end_offset - 4,817 end_offset - 4,
818 @enumFromInt(@intFromEnum(target.symbol)),818 @enumFromInt(@intFromEnum(target.symbol)),
819 reloc.off,819 .{ .known = reloc.off },
820 .{ .AMD64 = .REL32 },820 .{ .AMD64 = .REL32 },
821 ) else unreachable,821 ) else unreachable,
822 .branch => |target| if (emit.bin_file.cast(.elf)) |elf_file| {822 .branch => |target| if (emit.bin_file.cast(.elf)) |elf_file| {
...@@ -854,7 +854,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -854,7 +854,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
854 @enumFromInt(@intFromEnum(emit.atom_id)),854 @enumFromInt(@intFromEnum(emit.atom_id)),
855 end_offset - 4,855 end_offset - 4,
856 @enumFromInt(@intFromEnum(target.symbol)),856 @enumFromInt(@intFromEnum(target.symbol)),
857 reloc.off,857 .{ .known = reloc.off },
858 .{ .AMD64 = .REL32 },858 .{ .AMD64 = .REL32 },
859 ) else return emit.fail("TODO implement {s} reloc for {s}", .{859 ) else return emit.fail("TODO implement {s} reloc for {s}", .{
860 @tagName(reloc.target), @tagName(emit.bin_file.tag),860 @tagName(reloc.target), @tagName(emit.bin_file.tag),
...@@ -912,7 +912,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -912,7 +912,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
912 @enumFromInt(@intFromEnum(emit.atom_id)),912 @enumFromInt(@intFromEnum(emit.atom_id)),
913 end_offset - 4,913 end_offset - 4,
914 @enumFromInt(@intFromEnum(target.symbol)),914 @enumFromInt(@intFromEnum(target.symbol)),
915 reloc.off,915 .{ .known = reloc.off },
916 .{ .AMD64 = .SECREL },916 .{ .AMD64 = .SECREL },
917 ) else return emit.fail("TODO implement {s} reloc for {s}", .{917 ) else return emit.fail("TODO implement {s} reloc for {s}", .{
918 @tagName(reloc.target), @tagName(emit.bin_file.tag),918 @tagName(reloc.target), @tagName(emit.bin_file.tag),
src/link/Coff.zig+654-127
...@@ -31,6 +31,18 @@ long_names_table: LongNamesTable,...@@ -31,6 +31,18 @@ long_names_table: LongNamesTable,
31import_table: ImportTable,31import_table: ImportTable,
32export_table: ExportTable,32export_table: ExportTable,
33symbol_table: SymbolTable,33symbol_table: SymbolTable,
34inputs: std.ArrayList(struct {
35 path: std.Build.Cache.Path,
36 archive_name: ?[]const u8,
37 first_si: Symbol.Index,
38 last_si: Symbol.Index,
39}),
40input_sections: std.ArrayList(struct {
41 ii: Node.InputIndex,
42 si: Symbol.Index,
43 file_location: MappedFile.Node.FileLocation,
44}),
45input_section_pending_index: u32,
34strings: std.HashMapUnmanaged(46strings: std.HashMapUnmanaged(
35 u32,47 u32,
36 void,48 void,
...@@ -59,6 +71,7 @@ const_prog_node: std.Progress.Node,...@@ -59,6 +71,7 @@ const_prog_node: std.Progress.Node,
59synth_prog_node: std.Progress.Node,71synth_prog_node: std.Progress.Node,
60symbol_prog_node: std.Progress.Node,72symbol_prog_node: std.Progress.Node,
61member_prog_node: std.Progress.Node,73member_prog_node: std.Progress.Node,
74input_prog_node: std.Progress.Node,
62dump_snapshot: bool,75dump_snapshot: bool,
6376
64pub const default_file_alignment: u16 = 0x200;77pub const default_file_alignment: u16 = 0x200;
...@@ -185,6 +198,7 @@ pub const Node = union(enum) {...@@ -185,6 +198,7 @@ pub const Node = union(enum) {
185198
186 pseudo_section: PseudoSectionMapIndex,199 pseudo_section: PseudoSectionMapIndex,
187 object_section: ObjectSectionMapIndex,200 object_section: ObjectSectionMapIndex,
201 input_section: InputSectionIndex,
188 global: GlobalMapIndex,202 global: GlobalMapIndex,
189 nav: NavMapIndex,203 nav: NavMapIndex,
190 uav: UavMapIndex,204 uav: UavMapIndex,
...@@ -266,6 +280,46 @@ pub const Node = union(enum) {...@@ -266,6 +280,46 @@ pub const Node = union(enum) {
266 }280 }
267 };281 };
268282
283 pub const InputIndex = enum(u32) {
284 _,
285
286 pub fn path(ii: InputIndex, coff: *const Coff) std.Build.Cache.Path {
287 return coff.inputs.items[@intFromEnum(ii)].path;
288 }
289
290 pub fn archiveName(ii: InputIndex, coff: *const Coff) ?[]const u8 {
291 return coff.inputs.items[@intFromEnum(ii)].archive_name;
292 }
293
294 pub fn firstSymbol(ii: InputIndex, coff: *const Coff) Symbol.Index {
295 return coff.inputs.items[@intFromEnum(ii)].first_si;
296 }
297
298 pub fn lastSymbol(ii: InputIndex, coff: *const Coff) Symbol.Index {
299 return coff.inputs.items[@intFromEnum(ii)].last_si;
300 }
301 };
302
303 pub const InputSectionIndex = enum(u32) {
304 _,
305
306 pub fn input(isi: InputSectionIndex, coff: *const Coff) InputIndex {
307 return coff.input_sections.items[@intFromEnum(isi)].ii;
308 }
309
310 pub fn fileLocation(isi: InputSectionIndex, coff: *const Coff) MappedFile.Node.FileLocation {
311 return coff.input_sections.items[@intFromEnum(isi)].file_location;
312 }
313
314 pub fn symbol(isi: InputSectionIndex, coff: *const Coff) Symbol.Index {
315 return coff.input_sections.items[@intFromEnum(isi)].si;
316 }
317
318 pub fn lastSymbol(isi: InputSectionIndex, coff: *const Coff) Symbol.Index {
319 return coff.input_sections.items[@intFromEnum(isi)].last_si;
320 }
321 };
322
269 pub const LazyMapRef = struct {323 pub const LazyMapRef = struct {
270 kind: link.File.LazySymbol.Kind,324 kind: link.File.LazySymbol.Kind,
271 index: u32,325 index: u32,
...@@ -648,15 +702,15 @@ pub const Section = struct {...@@ -648,15 +702,15 @@ pub const Section = struct {
648 si: Symbol.Index,702 si: Symbol.Index,
649 relocation_table_ni: MappedFile.Node.Index,703 relocation_table_ni: MappedFile.Node.Index,
650704
651 pub const RelocationIndex = enum(u32) {705 pub const RelocationIndex = enum(u16) {
652 none,706 none,
653 _,707 _,
654708
655 pub fn wrap(i: ?u32) RelocationIndex {709 pub fn wrap(i: ?u16) RelocationIndex {
656 return @enumFromInt((i orelse return .none) + 1);710 return @enumFromInt((i orelse return .none) + 1);
657 }711 }
658712
659 pub fn unwrap(sri: RelocationIndex) ?u32 {713 pub fn unwrap(sri: RelocationIndex) ?u16 {
660 return switch (sri) {714 return switch (sri) {
661 .none => null,715 .none => null,
662 _ => @intFromEnum(sri) - 1,716 _ => @intFromEnum(sri) - 1,
...@@ -680,7 +734,12 @@ pub const GlobalName = struct { name: String, lib_name: String.Optional };...@@ -680,7 +734,12 @@ pub const GlobalName = struct { name: String, lib_name: String.Optional };
680pub const Symbol = struct {734pub const Symbol = struct {
681 ni: MappedFile.Node.Index,735 ni: MappedFile.Node.Index,
682 rva: u32,736 rva: u32,
683 size: u32,737 value: union {
738 /// For generated symbols, this is their size
739 size: u32,
740 /// For globals from input sections, this is the offset within the input section
741 input_offset: u32,
742 },
684 /// Relocations contained within this symbol743 /// Relocations contained within this symbol
685 loc_relocs: Reloc.Index,744 loc_relocs: Reloc.Index,
686 /// Relocations targeting this symbol745 /// Relocations targeting this symbol
...@@ -704,6 +763,10 @@ pub const Symbol = struct {...@@ -704,6 +763,10 @@ pub const Symbol = struct {
704 return sn.section(coff).si;763 return sn.section(coff).si;
705 }764 }
706765
766 pub fn name(sn: SectionNumber, coff: *const Coff) String {
767 return coff.section_table.keys()[sn.toIndex()];
768 }
769
707 pub fn section(sn: SectionNumber, coff: *const Coff) *Section {770 pub fn section(sn: SectionNumber, coff: *const Coff) *Section {
708 return &coff.section_table.values()[sn.toIndex()];771 return &coff.section_table.values()[sn.toIndex()];
709 }772 }
...@@ -732,6 +795,10 @@ pub const Symbol = struct {...@@ -732,6 +795,10 @@ pub const Symbol = struct {
732 return ni;795 return ni;
733 }796 }
734797
798 pub fn next(si: Symbol.Index) Symbol.Index {
799 return @enumFromInt(@intFromEnum(si) + 1);
800 }
801
735 pub fn knownString(si: Symbol.Index) String.Optional {802 pub fn knownString(si: Symbol.Index) String.Optional {
736 return switch (si) {803 return switch (si) {
737 .null, _ => .none,804 .null, _ => .none,
...@@ -742,6 +809,10 @@ pub const Symbol = struct {...@@ -742,6 +809,10 @@ pub const Symbol = struct {
742 pub fn flushMoved(si: Symbol.Index, coff: *Coff) void {809 pub fn flushMoved(si: Symbol.Index, coff: *Coff) void {
743 const sym = si.get(coff);810 const sym = si.get(coff);
744 sym.rva = coff.computeNodeRva(sym.ni);811 sym.rva = coff.computeNodeRva(sym.ni);
812 if (sym.gmi != .none and coff.getNode(sym.ni) == .input_section) {
813 // Symbols in input sections share a ni with their section
814 sym.rva += sym.value.input_offset;
815 }
745 si.applyLocationRelocs(coff);816 si.applyLocationRelocs(coff);
746 si.applyTargetRelocs(coff);817 si.applyTargetRelocs(coff);
747 }818 }
...@@ -761,13 +832,18 @@ pub const Symbol = struct {...@@ -761,13 +832,18 @@ pub const Symbol = struct {
761832
762 pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void {833 pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void {
763 const sym = si.get(coff);834 const sym = si.get(coff);
764 for (coff.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| {835 switch (sym.loc_relocs) {
765 if (reloc.loc != si) break;836 .none => {},
766 if (reloc.sri.entry(coff, sym.section_number)) |entry| coff.targetStore(837 else => |loc_relocs| {
767 &entry.virtual_address,838 for (coff.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
768 @intCast(coff.computeNodeSectionOffset(sym.ni) + reloc.offset),839 if (reloc.loc != si) break;
769 );840 if (reloc.sri.entry(coff, sym.section_number)) |entry| coff.targetStore(
770 reloc.apply(coff);841 &entry.virtual_address,
842 @intCast(coff.computeSymbolSectionOffset(sym) + reloc.offset),
843 );
844 reloc.apply(coff);
845 }
846 },
771 }847 }
772 }848 }
773849
...@@ -783,11 +859,16 @@ pub const Symbol = struct {...@@ -783,11 +859,16 @@ pub const Symbol = struct {
783859
784 pub fn deleteLocationRelocs(si: Symbol.Index, coff: *Coff) void {860 pub fn deleteLocationRelocs(si: Symbol.Index, coff: *Coff) void {
785 const sym = si.get(coff);861 const sym = si.get(coff);
786 for (coff.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| {862 switch (sym.loc_relocs) {
787 if (reloc.loc != si) break;863 .none => {},
788 reloc.delete(coff);864 else => |loc_relocs| {
865 for (coff.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
866 if (reloc.loc != si) break;
867 reloc.delete(coff);
868 }
869 sym.loc_relocs = .none;
870 },
789 }871 }
790 sym.loc_relocs = .none;
791 }872 }
792 };873 };
793874
...@@ -797,14 +878,20 @@ pub const Symbol = struct {...@@ -797,14 +878,20 @@ pub const Symbol = struct {
797};878};
798879
799pub const Reloc = extern struct {880pub const Reloc = extern struct {
881 offset: u64,
882 addend: i64,
800 type: Reloc.Type,883 type: Reloc.Type,
884 sri: Section.RelocationIndex,
801 prev: Reloc.Index,885 prev: Reloc.Index,
802 next: Reloc.Index,886 next: Reloc.Index,
803 loc: Symbol.Index,887 loc: Symbol.Index,
804 target: Symbol.Index,888 target: Symbol.Index,
805 sri: Section.RelocationIndex,889 flags: packed struct(u8) {
806 offset: u64,890 // Indicates the addend is not known and should be recovered from the location itself.
807 addend: i64,891 // COFF relocation tables don't encode the addend, only the location.
892 recover_addend: bool,
893 _: u7 = 0,
894 },
808895
809 pub const Type = extern union {896 pub const Type = extern union {
810 AMD64: std.coff.IMAGE.REL.AMD64,897 AMD64: std.coff.IMAGE.REL.AMD64,
...@@ -827,7 +914,7 @@ pub const Reloc = extern struct {...@@ -827,7 +914,7 @@ pub const Reloc = extern struct {
827 }914 }
828 };915 };
829916
830 pub fn apply(reloc: *const Reloc, coff: *Coff) void {917 pub fn apply(reloc: *Reloc, coff: *Coff) void {
831 const loc_sym = reloc.loc.get(coff);918 const loc_sym = reloc.loc.get(coff);
832 switch (loc_sym.ni) {919 switch (loc_sym.ni) {
833 .none => return,920 .none => return,
...@@ -836,9 +923,11 @@ pub const Reloc = extern struct {...@@ -836,9 +923,11 @@ pub const Reloc = extern struct {
836923
837 const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..];924 const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..];
838 const target_endian = coff.targetEndian();925 const target_endian = coff.targetEndian();
926 const target_machine = coff.targetLoad(&coff.headerPtr().machine);
839927
840 if (!coff.isImage()) {928 if (!coff.isImage()) {
841 switch (coff.targetLoad(&coff.headerPtr().machine)) {929 assert(!reloc.flags.recover_addend);
930 switch (target_machine) {
842 else => |machine| @panic(@tagName(machine)),931 else => |machine| @panic(@tagName(machine)),
843 .AMD64 => switch (reloc.type.AMD64) {932 .AMD64 => switch (reloc.type.AMD64) {
844 else => |kind| @panic(@tagName(kind)),933 else => |kind| @panic(@tagName(kind)),
...@@ -890,6 +979,54 @@ pub const Reloc = extern struct {...@@ -890,6 +979,54 @@ pub const Reloc = extern struct {
890 }979 }
891980
892 return;981 return;
982 } else if (reloc.flags.recover_addend) {
983 reloc.flags.recover_addend = false;
984 reloc.addend = switch (target_machine) {
985 else => |machine| @panic(@tagName(machine)),
986 .AMD64 => switch (reloc.type.AMD64) {
987 else => |kind| @panic(@tagName(kind)),
988 .ABSOLUTE => 0,
989 .ADDR64 => @bitCast(std.mem.readInt(
990 u64,
991 loc_slice[0..8],
992 target_endian,
993 )),
994 .ADDR32,
995 .ADDR32NB,
996 .REL32,
997 .REL32_1,
998 .REL32_2,
999 .REL32_3,
1000 .REL32_4,
1001 .REL32_5,
1002 .SECREL,
1003 => std.mem.readInt(
1004 u32,
1005 loc_slice[0..4],
1006 target_endian,
1007 ),
1008 },
1009 .I386 => switch (reloc.type.I386) {
1010 else => |kind| @panic(@tagName(kind)),
1011 .ABSOLUTE => 0,
1012 .DIR16,
1013 .REL16,
1014 => std.mem.readInt(
1015 u16,
1016 loc_slice[0..2],
1017 target_endian,
1018 ),
1019 .DIR32,
1020 .DIR32NB,
1021 .REL32,
1022 .SECREL,
1023 => std.mem.readInt(
1024 u32,
1025 loc_slice[0..4],
1026 target_endian,
1027 ),
1028 },
1029 };
893 }1030 }
8941031
895 const target_sym = reloc.target.get(coff);1032 const target_sym = reloc.target.get(coff);
...@@ -899,8 +1036,7 @@ pub const Reloc = extern struct {...@@ -899,8 +1036,7 @@ pub const Reloc = extern struct {
899 }1036 }
9001037
901 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));1038 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));
9021039 switch (target_machine) {
903 switch (coff.targetLoad(&coff.headerPtr().machine)) {
904 else => |machine| @panic(@tagName(machine)),1040 else => |machine| @panic(@tagName(machine)),
905 .AMD64 => switch (reloc.type.AMD64) {1041 .AMD64 => switch (reloc.type.AMD64) {
906 else => |kind| @panic(@tagName(kind)),1042 else => |kind| @panic(@tagName(kind)),
...@@ -962,7 +1098,7 @@ pub const Reloc = extern struct {...@@ -962,7 +1098,7 @@ pub const Reloc = extern struct {
962 .SECREL => std.mem.writeInt(1098 .SECREL => std.mem.writeInt(
963 u32,1099 u32,
964 loc_slice[0..4],1100 loc_slice[0..4],
965 @intCast(coff.computeNodeSectionOffset(target_sym.ni) + reloc.addend),1101 @intCast(coff.computeSymbolSectionOffset(target_sym) + reloc.addend),
966 target_endian,1102 target_endian,
967 ),1103 ),
968 },1104 },
...@@ -1002,7 +1138,7 @@ pub const Reloc = extern struct {...@@ -1002,7 +1138,7 @@ pub const Reloc = extern struct {
1002 .SECREL => std.mem.writeInt(1138 .SECREL => std.mem.writeInt(
1003 u32,1139 u32,
1004 loc_slice[0..4],1140 loc_slice[0..4],
1005 @intCast(coff.computeNodeSectionOffset(target_sym.ni) + reloc.addend),1141 @intCast(coff.computeSymbolSectionOffset(target_sym) + reloc.addend),
1006 target_endian,1142 target_endian,
1007 ),1143 ),
1008 },1144 },
...@@ -1133,6 +1269,9 @@ fn create(...@@ -1133,6 +1269,9 @@ fn create(
1133 .pending = .empty,1269 .pending = .empty,
1134 .pending_shrink = false,1270 .pending_shrink = false,
1135 },1271 },
1272 .inputs = .empty,
1273 .input_sections = .empty,
1274 .input_section_pending_index = 0,
1136 .strings = .empty,1275 .strings = .empty,
1137 .string_bytes = .empty,1276 .string_bytes = .empty,
1138 .section_table = .empty,1277 .section_table = .empty,
...@@ -1154,6 +1293,7 @@ fn create(...@@ -1154,6 +1293,7 @@ fn create(
1154 .synth_prog_node = .none,1293 .synth_prog_node = .none,
1155 .symbol_prog_node = .none,1294 .symbol_prog_node = .none,
1156 .member_prog_node = .none,1295 .member_prog_node = .none,
1296 .input_prog_node = .none,
1157 .dump_snapshot = options.enable_link_snapshots,1297 .dump_snapshot = options.enable_link_snapshots,
1158 };1298 };
1159 errdefer coff.deinit();1299 errdefer coff.deinit();
...@@ -1561,7 +1701,7 @@ fn initHeaders(...@@ -1561,7 +1701,7 @@ fn initHeaders(
1561 coff.symbols.addOneAssumeCapacity().* = .{1701 coff.symbols.addOneAssumeCapacity().* = .{
1562 .ni = .none,1702 .ni = .none,
1563 .rva = 0,1703 .rva = 0,
1564 .size = 0,1704 .value = .{ .size = 0 },
1565 .loc_relocs = .none,1705 .loc_relocs = .none,
1566 .target_relocs = .none,1706 .target_relocs = .none,
1567 .section_number = .UNDEFINED,1707 .section_number = .UNDEFINED,
...@@ -1701,12 +1841,18 @@ pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void {...@@ -1701,12 +1841,18 @@ pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void {
1701 coff.symbol_prog_node = prog_node.start("Symbols", coff.symbol_table.pending.count());1841 coff.symbol_prog_node = prog_node.start("Symbols", coff.symbol_table.pending.count());
1702 coff.member_prog_node = prog_node.start("Members", coff.pending_members.count());1842 coff.member_prog_node = prog_node.start("Members", coff.pending_members.count());
1703 }1843 }
1844 coff.input_prog_node = prog_node.start(
1845 "Inputs",
1846 coff.input_sections.items.len - coff.input_section_pending_index,
1847 );
1704 coff.mf.update_prog_node = prog_node.start("Relocations", coff.mf.updates.items.len);1848 coff.mf.update_prog_node = prog_node.start("Relocations", coff.mf.updates.items.len);
1705}1849}
17061850
1707pub fn endProgress(coff: *Coff) void {1851pub fn endProgress(coff: *Coff) void {
1708 coff.mf.update_prog_node.end();1852 coff.mf.update_prog_node.end();
1709 coff.mf.update_prog_node = .none;1853 coff.mf.update_prog_node = .none;
1854 coff.input_prog_node.end();
1855 coff.input_prog_node = .none;
1710 if (!isImage(coff)) {1856 if (!isImage(coff)) {
1711 coff.member_prog_node.end();1857 coff.member_prog_node.end();
1712 coff.member_prog_node = .none;1858 coff.member_prog_node = .none;
...@@ -1736,11 +1882,11 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {...@@ -1736,11 +1882,11 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
1736 .section_table,1882 .section_table,
1737 .export_name_table,1883 .export_name_table,
1738 .placeholder,1884 .placeholder,
1739
1740 .symbol_table,1885 .symbol_table,
1741 .string_table,1886 .string_table,
1742 .relocation_table,1887 .relocation_table,
1743 .relocation_table_entry,1888 .relocation_table_entry,
1889 .input_section,
1744 => unreachable,1890 => unreachable,
1745 .image_section => |si| si,1891 .image_section => |si| si,
1746 .import_directory_table => break :parent_rva coff.targetLoad(1892 .import_directory_table => break :parent_rva coff.targetLoad(
...@@ -1781,9 +1927,12 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {...@@ -1781,9 +1927,12 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
1781 const offset, _ = ni.location(&coff.mf).resolve(&coff.mf);1927 const offset, _ = ni.location(&coff.mf).resolve(&coff.mf);
1782 return @intCast(parent_rva + offset);1928 return @intCast(parent_rva + offset);
1783}1929}
1784fn computeNodeSectionOffset(coff: *Coff, ni: MappedFile.Node.Index) u32 {1930fn computeSymbolSectionOffset(coff: *Coff, sym: *const Symbol) u32 {
1785 var section_offset: u32 = 0;1931 var section_offset: u32 = if (sym.gmi != .none and coff.getNode(sym.ni) == .input_section)
1786 var parent_ni = ni;1932 sym.value.input_offset
1933 else
1934 0;
1935 var parent_ni = sym.ni;
1787 while (true) {1936 while (true) {
1788 const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf);1937 const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf);
1789 section_offset += @intCast(offset);1938 section_offset += @intCast(offset);
...@@ -1981,7 +2130,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {...@@ -1981,7 +2130,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
1981 defer coff.symbols.addOneAssumeCapacity().* = .{2130 defer coff.symbols.addOneAssumeCapacity().* = .{
1982 .ni = .none,2131 .ni = .none,
1983 .rva = 0,2132 .rva = 0,
1984 .size = 0,2133 .value = .{ .size = 0 },
1985 .loc_relocs = .none,2134 .loc_relocs = .none,
1986 .target_relocs = .none,2135 .target_relocs = .none,
1987 .section_number = .UNDEFINED,2136 .section_number = .UNDEFINED,
...@@ -2003,6 +2152,15 @@ fn getOrPutString(coff: *Coff, string: []const u8) !String {...@@ -2003,6 +2152,15 @@ fn getOrPutString(coff: *Coff, string: []const u8) !String {
2003fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional {2152fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional {
2004 return (try coff.getOrPutString(string orelse return .none)).toOptional();2153 return (try coff.getOrPutString(string orelse return .none)).toOptional();
2005}2154}
2155fn getString(coff: *Coff, string: []const u8) ?String {
2156 if (coff.strings.getKeyAdapted(
2157 string,
2158 std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes },
2159 )) |key|
2160 return @enumFromInt(key)
2161 else
2162 return null;
2163}
20062164
2007/// If the name does not fit in the symbol header, adds it to the symbol table string table.2165/// If the name does not fit in the symbol header, adds it to the symbol table string table.
2008/// If the caller knows this name already has a String associated with it, they can avoid2166/// If the caller knows this name already has a String associated with it, they can avoid
...@@ -2105,7 +2263,7 @@ fn navSection(...@@ -2105,7 +2263,7 @@ fn navSection(
2105 const ip = &zcu.intern_pool;2263 const ip = &zcu.intern_pool;
2106 const default: String, const attributes: ObjectSectionAttributes =2264 const default: String, const attributes: ObjectSectionAttributes =
2107 if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{2265 if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{
2108 .@".tls$", .{ .read = true, .write = !coff.isImage() },2266 .@".tls$", .{ .read = true, .write = true },
2109 } else if (ip.isFunctionType(nav_resolved.type)) .{2267 } else if (ip.isFunctionType(nav_resolved.type)) .{
2110 .@".text", .{ .read = true, .execute = true },2268 .@".text", .{ .read = true, .execute = true },
2111 } else if (nav_resolved.@"const") .{2269 } else if (nav_resolved.@"const") .{
...@@ -2189,7 +2347,7 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol....@@ -2189,7 +2347,7 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.
2189 @enumFromInt(@intFromEnum(reloc_info.parent.atom_index)),2347 @enumFromInt(@intFromEnum(reloc_info.parent.atom_index)),
2190 reloc_info.offset,2348 reloc_info.offset,
2191 target_si,2349 target_si,
2192 reloc_info.addend,2350 .{ .known = reloc_info.addend },
2193 switch (coff.targetLoad(&coff.headerPtr().machine)) {2351 switch (coff.targetLoad(&coff.headerPtr().machine)) {
2194 else => unreachable,2352 else => unreachable,
2195 .AMD64 => .{ .AMD64 = .ADDR64 },2353 .AMD64 => .{ .AMD64 = .ADDR64 },
...@@ -2467,19 +2625,40 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -2467,19 +2625,40 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
2467 };2625 };
24682626
2469 coff.targetStore(&entry.value, switch (sym.section_number) {2627 coff.targetStore(&entry.value, switch (sym.section_number) {
2470 .UNDEFINED => sym.size,2628 .UNDEFINED => sym.value.size,
2471 .ABSOLUTE,2629 .ABSOLUTE,
2472 .DEBUG,2630 .DEBUG,
2473 => unreachable,2631 => unreachable,
2474 else => switch (coff.getNode(sym.ni)) {2632 else => switch (coff.getNode(sym.ni)) {
2475 .image_section => 0,2633 .image_section => 0,
2476 else => coff.computeNodeSectionOffset(sym.ni),2634 else => coff.computeSymbolSectionOffset(sym),
2477 },2635 },
2478 });2636 });
24792637
2480 log.debug("updateSymbolTableEntry({d}) = {d}", .{ si, sym.sti });2638 log.debug("updateSymbolTableEntry({d}) = {d}", .{ si, sym.sti });
2481}2639}
24822640
2641fn flushInputSection(coff: *Coff, isi: Node.InputSectionIndex) !void {
2642 const file_loc = isi.fileLocation(coff);
2643 if (file_loc.size == 0) return;
2644 const comp = coff.base.comp;
2645 const io = comp.io;
2646 const gpa = comp.gpa;
2647 const ii = isi.input(coff);
2648 const path = ii.path(coff);
2649 const file = try path.root_dir.handle.openFile(io, path.sub_path, .{});
2650 defer file.close(io);
2651 var fr = file.reader(io, &.{});
2652 try fr.seekTo(file_loc.offset);
2653 var nw: MappedFile.Node.Writer = undefined;
2654 const si = isi.symbol(coff);
2655 si.node(coff).writer(&coff.mf, gpa, &nw);
2656 defer nw.deinit();
2657 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)
2658 return error.EndOfStream;
2659 si.applyLocationRelocs(coff);
2660}
2661
2483fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !Symbol.Index {2662fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !Symbol.Index {
2484 assert(coff.base.comp.zcu != null);2663 assert(coff.base.comp.zcu != null);
24852664
...@@ -2612,7 +2791,7 @@ fn pseudoSectionMapIndex(...@@ -2612,7 +2791,7 @@ fn pseudoSectionMapIndex(
2612 const gpa = coff.base.comp.gpa;2791 const gpa = coff.base.comp.gpa;
2613 const pseudo_section_gop = try coff.pseudo_section_table.getOrPut(gpa, name);2792 const pseudo_section_gop = try coff.pseudo_section_table.getOrPut(gpa, name);
2614 const psmi: Node.PseudoSectionMapIndex = @enumFromInt(pseudo_section_gop.index);2793 const psmi: Node.PseudoSectionMapIndex = @enumFromInt(pseudo_section_gop.index);
2615 if (!pseudo_section_gop.found_existing) {2794 const sn = if (!pseudo_section_gop.found_existing) sn: {
2616 const default_parent: Symbol.Index = if (attributes.execute)2795 const default_parent: Symbol.Index = if (attributes.execute)
2617 .text2796 .text
2618 else if (attributes.write)2797 else if (attributes.write)
...@@ -2626,11 +2805,10 @@ fn pseudoSectionMapIndex(...@@ -2626,11 +2805,10 @@ fn pseudoSectionMapIndex(
2626 default_parent.knownString().toSlice(coff).?,2805 default_parent.knownString().toSlice(coff).?,
2627 ))2806 ))
2628 default_parent2807 default_parent
2629 else if (coff.section_table.get(name)) |section| parent: {2808 else if (coff.section_table.get(name)) |section|
2630 const header = section.si.get(coff).section_number.header(coff);2809 section.si
2631 try coff.verifyParentSectionAttributes(name, name, .fromFlags(header.flags), attributes);2810 else
2632 break :parent section.si;2811 try coff.addSection(name, attributes.asFlags());
2633 } else try coff.addSection(name, attributes.asFlags());
26342812
2635 try coff.nodes.ensureUnusedCapacity(gpa, 1);2813 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2636 try coff.symbols.ensureUnusedCapacity(gpa, 1);2814 try coff.symbols.ensureUnusedCapacity(gpa, 1);
...@@ -2644,9 +2822,30 @@ fn pseudoSectionMapIndex(...@@ -2644,9 +2822,30 @@ fn pseudoSectionMapIndex(
2644 assert(sym.loc_relocs == .none);2822 assert(sym.loc_relocs == .none);
2645 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);2823 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
2646 coff.nodes.appendAssumeCapacity(.{ .pseudo_section = psmi });2824 coff.nodes.appendAssumeCapacity(.{ .pseudo_section = psmi });
2647 }2825 break :sn sym.section_number;
2826 } else pseudo_section_gop.value_ptr.get(coff).section_number;
2827
2828 try coff.verifyParentSectionAttributes(
2829 .pseudo,
2830 sn.name(coff),
2831 name,
2832 .fromFlags(sn.header(coff).flags),
2833 attributes,
2834 );
2835
2648 return psmi;2836 return psmi;
2649}2837}
2838
2839fn objectSectionParentName(coff: *Coff, name: []const u8) []const u8 {
2840 // In images we want to sort object sections into the final root section name.
2841 // Otherwise, we want to keep the full name so that this sort can occur correctly when
2842 // the object is finally linked into an image.
2843 return if (coff.isImage())
2844 name[0 .. std.mem.indexOfScalar(u8, name, '$') orelse name.len]
2845 else
2846 name;
2847}
2848
2650fn objectSectionMapIndex(2849fn objectSectionMapIndex(
2651 coff: *Coff,2850 coff: *Coff,
2652 name: String,2851 name: String,
...@@ -2654,23 +2853,20 @@ fn objectSectionMapIndex(...@@ -2654,23 +2853,20 @@ fn objectSectionMapIndex(
2654 attributes: ObjectSectionAttributes,2853 attributes: ObjectSectionAttributes,
2655) !Node.ObjectSectionMapIndex {2854) !Node.ObjectSectionMapIndex {
2656 const gpa = coff.base.comp.gpa;2855 const gpa = coff.base.comp.gpa;
2856 const effective_attributes = if (coff.isImage() and std.mem.startsWith(u8, name.toSlice(coff), ".tls")) attr: {
2857 // In images, the .tls section is a read-only template
2858 var attr = attributes;
2859 attr.write = false;
2860 break :attr attr;
2861 } else attributes;
2862
2657 const object_section_gop = try coff.object_section_table.getOrPut(gpa, name);2863 const object_section_gop = try coff.object_section_table.getOrPut(gpa, name);
2658 const osmi: Node.ObjectSectionMapIndex = @enumFromInt(object_section_gop.index);2864 const osmi: Node.ObjectSectionMapIndex = @enumFromInt(object_section_gop.index);
2659 if (!object_section_gop.found_existing) {2865 const sn = if (!object_section_gop.found_existing) sn: {
2660 try coff.ensureUnusedStringCapacity(name.toSlice(coff).len);2866 try coff.ensureUnusedStringCapacity(name.toSlice(coff).len);
2661 const name_slice = name.toSlice(coff);2867 const name_slice = name.toSlice(coff);
2662 const prefix_index = std.mem.indexOfScalar(u8, name_slice, '$') orelse name_slice.len;2868 const parent_name = coff.getOrPutStringAssumeCapacity(coff.objectSectionParentName(name_slice));
2663 const parent_name = coff.getOrPutStringAssumeCapacity(if (coff.isImage())2869 const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, effective_attributes)).symbol(coff);
2664 name_slice[0..prefix_index]
2665 else
2666 name_slice[0..@min(prefix_index + 1, name_slice.len)]);
2667 const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, attributes)).symbol(coff);
2668 try coff.verifyParentSectionAttributes(
2669 parent_name,
2670 name,
2671 .fromFlags(parent.get(coff).section_number.header(coff).flags),
2672 attributes,
2673 );
2674 try coff.nodes.ensureUnusedCapacity(gpa, 1);2870 try coff.nodes.ensureUnusedCapacity(gpa, 1);
2675 try coff.symbols.ensureUnusedCapacity(gpa, 1);2871 try coff.symbols.ensureUnusedCapacity(gpa, 1);
2676 const parent_ni = parent.node(coff);2872 const parent_ni = parent.node(coff);
...@@ -2704,12 +2900,23 @@ fn objectSectionMapIndex(...@@ -2704,12 +2900,23 @@ fn objectSectionMapIndex(
2704 assert(sym.loc_relocs == .none);2900 assert(sym.loc_relocs == .none);
2705 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);2901 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
2706 coff.nodes.appendAssumeCapacity(.{ .object_section = osmi });2902 coff.nodes.appendAssumeCapacity(.{ .object_section = osmi });
2707 }2903 break :sn sym.section_number;
2904 } else object_section_gop.value_ptr.get(coff).section_number;
2905
2906 try coff.verifyParentSectionAttributes(
2907 .object,
2908 sn.name(coff),
2909 name,
2910 .fromFlags(sn.header(coff).flags),
2911 effective_attributes,
2912 );
2913
2708 return osmi;2914 return osmi;
2709}2915}
27102916
2711fn verifyParentSectionAttributes(2917fn verifyParentSectionAttributes(
2712 coff: *Coff,2918 coff: *Coff,
2919 kind: enum { pseudo, object },
2713 parent_name: String,2920 parent_name: String,
2714 child_name: String,2921 child_name: String,
2715 parent_attrs: ObjectSectionAttributes,2922 parent_attrs: ObjectSectionAttributes,
...@@ -2718,18 +2925,25 @@ fn verifyParentSectionAttributes(...@@ -2718,18 +2925,25 @@ fn verifyParentSectionAttributes(
2718 if (parent_attrs == child_attrs) return;2925 if (parent_attrs == child_attrs) return;
27192926
2720 const fields = std.meta.fields(ObjectSectionAttributes);2927 const fields = std.meta.fields(ObjectSectionAttributes);
2721 var err = try coff.base.comp.link_diags.addErrorWithNotes(fields.len);2928 const BackingT = @typeInfo(ObjectSectionAttributes).@"struct".backing_integer.?;
2722 try err.addMsg("object '{s}' was placed in parent section '{s}' with mismatched flags", .{2929 const num_notes = @popCount(@as(BackingT, @bitCast(parent_attrs)) ^ @as(BackingT, @bitCast(child_attrs)));
2930 var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes);
2931 try err.addMsg("{t} section '{s}' was placed in parent section '{s}' with mismatched flags", .{
2932 kind,
2723 child_name.toSlice(coff),2933 child_name.toSlice(coff),
2724 parent_name.toSlice(coff),2934 parent_name.toSlice(coff),
2725 });2935 });
27262936
2727 inline for (fields) |field| {2937 inline for (fields) |field| {
2728 err.addNote("{s}: parent = {d} child = {d}", .{2938 if (@field(child_attrs, field.name) != @field(parent_attrs, field.name)) {
2729 field.name,2939 err.addNote("flags.{s} was {d} in {s}, but {d} in {s}", .{
2730 @intFromBool(@field(child_attrs, field.name)),2940 field.name,
2731 @intFromBool(@field(parent_attrs, field.name)),2941 @intFromBool(@field(child_attrs, field.name)),
2732 });2942 child_name.toSlice(coff),
2943 @intFromBool(@field(parent_attrs, field.name)),
2944 parent_name.toSlice(coff),
2945 });
2946 }
2733 }2947 }
27342948
2735 return error.LinkFailure;2949 return error.LinkFailure;
...@@ -2740,13 +2954,24 @@ pub fn addReloc(...@@ -2740,13 +2954,24 @@ pub fn addReloc(
2740 loc_si: Symbol.Index,2954 loc_si: Symbol.Index,
2741 offset: u64,2955 offset: u64,
2742 target_si: Symbol.Index,2956 target_si: Symbol.Index,
2743 addend: i64,2957 addend: union(enum) {
2958 known: i64,
2959 pending: void,
2960 },
2744 @"type": Reloc.Type,2961 @"type": Reloc.Type,
2745) !void {2962) !void {
2746 const gpa = coff.base.comp.gpa;2963 const gpa = coff.base.comp.gpa;
2747 const target = target_si.get(coff);2964 const target = target_si.get(coff);
27482965
2749 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 });2966 log.debug("addReloc({d}@{d}+{d} -> {d}@{d}+{d}{s})", .{
2967 loc_si,
2968 loc_si.get(coff).section_number,
2969 offset,
2970 target_si,
2971 target_si.get(coff).section_number,
2972 if (addend == .pending) 0 else addend.known,
2973 if (addend == .pending) "p" else "k",
2974 });
27502975
2751 try coff.relocs.ensureUnusedCapacity(gpa, 1);2976 try coff.relocs.ensureUnusedCapacity(gpa, 1);
27522977
...@@ -2817,7 +3042,10 @@ pub fn addReloc(...@@ -2817,7 +3042,10 @@ pub fn addReloc(
2817 .target = target_si,3042 .target = target_si,
2818 .sri = sri,3043 .sri = sri,
2819 .offset = offset,3044 .offset = offset,
2820 .addend = addend,3045 .addend = if (addend == .pending) 0 else addend.known,
3046 .flags = .{
3047 .recover_addend = addend == .pending,
3048 },
2821 };3049 };
2822 switch (target.target_relocs) {3050 switch (target.target_relocs) {
2823 .none => {},3051 .none => {},
...@@ -2869,10 +3097,34 @@ pub fn loadInput(coff: *Coff, input: link.Input) (Io.File.Reader.SizeError ||...@@ -2869,10 +3097,34 @@ pub fn loadInput(coff: *Coff, input: link.Input) (Io.File.Reader.SizeError ||
2869fn fmtArchiveNameString(archiveName: ?[]const u8) std.fmt.Alt(?[]const u8, archiveNameStringEscape) {3097fn fmtArchiveNameString(archiveName: ?[]const u8) std.fmt.Alt(?[]const u8, archiveNameStringEscape) {
2870 return .{ .data = archiveName };3098 return .{ .data = archiveName };
2871}3099}
3100
2872fn archiveNameStringEscape(archiveName: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {3101fn archiveNameStringEscape(archiveName: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {
2873 try w.print("({f})", .{std.zig.fmtString(archiveName orelse return)});3102 try w.print("({f})", .{std.zig.fmtString(archiveName orelse return)});
2874}3103}
28753104
3105fn inputSectionHeaderNameSlice(
3106 coff: *Coff,
3107 header: *const std.coff.SectionHeader,
3108 string_table: []const u8,
3109 path: std.Build.Cache.Path,
3110 section_i: usize,
3111) ![]const u8 {
3112 const diags = &coff.base.comp.link_diags;
3113 return if (header.name[0] == '/') name: {
3114 const offset_str = std.mem.sliceTo(header.name[1..], 0);
3115 const name_offset = std.fmt.parseUnsigned(u24, offset_str, 10) catch
3116 return diags.failParse(path, "ill-formed section name in section {d}: '{s}'", .{
3117 section_i,
3118 header.name[0 .. offset_str.len + 1],
3119 });
3120
3121 if (name_offset > string_table.len)
3122 return diags.failParse(path, "out-of-bounds section name offset in section {d}: {d}", .{ section_i, name_offset });
3123
3124 break :name std.mem.sliceTo(string_table[name_offset..], 0);
3125 } else std.mem.sliceTo(&header.name, 0);
3126}
3127
2876fn loadObject(3128fn loadObject(
2877 coff: *Coff,3129 coff: *Coff,
2878 path: std.Build.Cache.Path,3130 path: std.Build.Cache.Path,
...@@ -2890,6 +3142,7 @@ fn loadObject(...@@ -2890,6 +3142,7 @@ fn loadObject(
2890 assert(!coff.isObj());3142 assert(!coff.isObj());
28913143
2892 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtArchiveNameString(archive_name) });3144 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtArchiveNameString(archive_name) });
3145
2893 const header = try r.peekStruct(std.coff.Header, coff.targetEndian());3146 const header = try r.peekStruct(std.coff.Header, coff.targetEndian());
2894 if (header.machine != target.toCoffMachine())3147 if (header.machine != target.toCoffMachine())
2895 return diags.failParse(path, "machine mismatch: expected {t}, found {t}", .{3148 return diags.failParse(path, "machine mismatch: expected {t}, found {t}", .{
...@@ -2927,6 +3180,16 @@ fn loadObject(...@@ -2927,6 +3180,16 @@ fn loadObject(
2927 symbol_table_end + string_table_len > fl.size)3180 symbol_table_end + string_table_len > fl.size)
2928 return diags.failParse(path, "bad string table", .{});3181 return diags.failParse(path, "bad string table", .{});
29293182
3183 const ii: Node.InputIndex = @enumFromInt(coff.inputs.items.len);
3184 try coff.inputs.ensureUnusedCapacity(gpa, 1);
3185 const input = coff.inputs.addOneAssumeCapacity();
3186 input.* = .{
3187 .path = path,
3188 .archive_name = if (archive_name) |m| try gpa.dupe(u8, m) else null,
3189 .first_si = .null,
3190 .last_si = .null,
3191 };
3192
2930 const string_table = string_table: {3193 const string_table = string_table: {
2931 const string_table = try gpa.alloc(u8, string_table_len);3194 const string_table = try gpa.alloc(u8, string_table_len);
2932 errdefer gpa.free(string_table);3195 errdefer gpa.free(string_table);
...@@ -2942,38 +3205,34 @@ fn loadObject(...@@ -2942,38 +3205,34 @@ fn loadObject(
29423205
2943 const InputSection = struct {3206 const InputSection = struct {
2944 header: std.coff.SectionHeader,3207 header: std.coff.SectionHeader,
2945 psmi: Node.PseudoSectionMapIndex,3208 name: String,
3209 si: Symbol.Index,
2946 };3210 };
29473211
2948 try fr.seekTo(fl.offset + @sizeOf(std.coff.Header));
2949 const sections: []const InputSection = if (coff.isImage()) sections: {3212 const sections: []const InputSection = if (coff.isImage()) sections: {
2950 const sections = try gpa.alloc(InputSection, header.number_of_sections);3213 const sections = try gpa.alloc(InputSection, header.number_of_sections);
2951 errdefer gpa.free(sections);3214 errdefer gpa.free(sections);
29523215
2953 for (sections, 0..) |*section, section_i| {3216 var num_input_sections: u16 = 0;
2954 section.header = try r.takeStruct(std.coff.SectionHeader, target_endian);3217 var reqd_object_sections: std.AutoArrayHashMapUnmanaged(String, void) = .empty;
2955 if (section.header.flags.LNK_INFO) {3218 defer reqd_object_sections.deinit(gpa);
2956 if (std.mem.eql(u8, &section.header.name, ".drectve"))3219 var reqd_pseudo_sections: std.StringArrayHashMapUnmanaged(void) = .empty;
2957 return diags.failParse(path, "TODO handle arguments in .drectve section", .{});3220 defer reqd_pseudo_sections.deinit(gpa);
3221 try reqd_object_sections.ensureUnusedCapacity(gpa, sections.len);
3222 try reqd_pseudo_sections.ensureUnusedCapacity(gpa, sections.len);
29583223
2959 continue;3224 try fr.seekTo(fl.offset + @sizeOf(std.coff.Header));
2960 }3225 for (sections, 0..) |*section, section_i| {
29613226 section.* = .{
2962 if (section.header.flags.LNK_REMOVE or3227 .header = try r.takeStruct(std.coff.SectionHeader, target_endian),
2963 section.header.flags.MEM_DISCARDABLE)3228 .name = undefined,
2964 {3229 .si = .null,
2965 // TODO: Merge .debug$* sections and output to PDB3230 };
2966 continue;
2967 }
2968
2969 if (section.header.flags.LNK_COMDAT)
2970 // This will be necessary if we do the equivalent of /Gy for compiler-rt
2971 return diags.failParse(path, "TODO handle COMDAT sections in input objects", .{});
29723231
2973 const section_name_slice = if (section.header.name[0] == '/') name: {3232 const section_name_slice = if (section.header.name[0] == '/') name: {
2974 const offset_str = std.mem.sliceTo(section.header.name[1..], 0);3233 const offset_str = std.mem.sliceTo(section.header.name[1..], 0);
2975 const name_offset = std.fmt.parseUnsigned(u24, offset_str, 10) catch3234 const name_offset = std.fmt.parseUnsigned(u24, offset_str, 10) catch
2976 return diags.failParse(path, "ill-formed section name in section {d}: '{s}'", .{3235 return diags.failParse(path, "ill-formed section name offset in section {d}: '{s}'", .{
2977 section_i,3236 section_i,
2978 section.header.name[0 .. offset_str.len + 1],3237 section.header.name[0 .. offset_str.len + 1],
2979 });3238 });
...@@ -2983,26 +3242,137 @@ fn loadObject(...@@ -2983,26 +3242,137 @@ fn loadObject(
29833242
2984 break :name std.mem.sliceTo(string_table[name_offset..], 0);3243 break :name std.mem.sliceTo(string_table[name_offset..], 0);
2985 } else std.mem.sliceTo(&section.header.name, 0);3244 } else std.mem.sliceTo(&section.header.name, 0);
3245 section.name = coff.getOrPutStringAssumeCapacity(section_name_slice);
29863246
2987 const section_name = coff.getOrPutStringAssumeCapacity(section_name_slice);3247 if (section.header.pointer_to_linenumbers +
2988 const osmi = try coff.objectSectionMapIndex(3248 section.header.number_of_linenumbers * std.coff.LineNumber.sizeOf() > fl.size)
2989 section_name,3249 return diags.failParse(path, "bad line numbers location in section {d} `{s}`", .{
2990 if (section.header.flags.ALIGN.toByteUnits()) |align_bytes|3250 section_i,
2991 .fromByteUnits(align_bytes)3251 section_name_slice,
2992 else3252 });
2993 .@"1",3253
2994 .fromFlags(section.header.flags),3254 if (section.header.pointer_to_relocations +
3255 section.header.number_of_relocations * std.coff.Relocation.sizeOf() > fl.size)
3256 return diags.failParse(path, "bad relocations location in section {d} `{s}`", .{
3257 section_i,
3258 section_name_slice,
3259 });
3260
3261 if (section.header.pointer_to_raw_data + section.header.size_of_raw_data > fl.size)
3262 return diags.failParse(path, "bad raw data location in section {d} `{s}`", .{
3263 section_i,
3264 section_name_slice,
3265 });
3266
3267 if (section.header.flags.LNK_REMOVE or
3268 section.header.flags.MEM_DISCARDABLE)
3269 {
3270 // TODO: Merge .debug$* sections and output to PDB
3271 continue;
3272 }
3273
3274 num_input_sections += 1;
3275 _ = reqd_object_sections.getOrPutAssumeCapacity(section.name);
3276 _ = reqd_pseudo_sections.getOrPutAssumeCapacity(
3277 coff.objectSectionParentName(section.name.toSlice(coff)),
2995 );3278 );
3279 }
3280
3281 var symbol_capacity: u16 = num_input_sections;
3282 var node_capacity: u16 = 0;
3283 {
3284 var iter = reqd_object_sections.count();
3285 while (iter > 0) {
3286 iter -= 1;
3287 if (coff.object_section_table.contains(reqd_object_sections.keys()[iter]))
3288 reqd_object_sections.swapRemoveAt(iter);
3289 }
29963290
2997 _ = osmi;3291 node_capacity += @intCast(reqd_object_sections.count());
3292 symbol_capacity += @intCast(reqd_object_sections.count());
3293 }
3294
3295 {
3296 var iter = reqd_pseudo_sections.count();
3297 while (iter > 0) {
3298 // TODO: Track the extra number of strings and their length and reserve? These have not been reserved as
3299 // part of the ensureManyUnusedStringCapacity call above
3300 iter -= 1;
3301 const name = coff.getString(reqd_pseudo_sections.keys()[iter]) orelse continue;
3302 if (coff.pseudo_section_table.contains(name))
3303 reqd_pseudo_sections.swapRemoveAt(iter);
3304 }
3305
3306 node_capacity += @intCast(reqd_pseudo_sections.count());
3307 symbol_capacity += @intCast(reqd_pseudo_sections.count());
3308 }
3309
3310 try coff.nodes.ensureUnusedCapacity(gpa, node_capacity);
3311 try coff.symbols.ensureUnusedCapacity(gpa, symbol_capacity + num_input_sections);
3312 try coff.input_sections.ensureUnusedCapacity(gpa, num_input_sections);
3313
3314 for (sections) |*section| {
3315 if (section.header.flags.LNK_INFO) {
3316 if (std.mem.eql(u8, &section.header.name, ".drectve")) {
3317 try fr.seekTo(fl.offset + section.header.pointer_to_raw_data);
3318 var buf: [128]u8 = undefined;
3319 var section_r = r.limited(.limited(section.header.size_of_raw_data), &buf);
3320 while (section_r.interface.takeDelimiter(' ') catch |err| switch (err) {
3321 error.StreamTooLong => return diags.failParse(path, "unexpectedly long .drectve argument", .{}),
3322 else => |e| return e,
3323 }) |arg| {
3324 // Microsoft tools emit 3 space characters into this section even with /Zl
3325 if (arg.len > 0)
3326 return diags.failParse(path, "unsupported argument in .drectve section: `{s}`", .{arg});
3327 }
3328 }
3329
3330 continue;
3331 }
29983332
2999 // TODO: Decide to merge this section3333 if (section.header.flags.LNK_REMOVE or
3000 // TODO: Map flags (might need to figure out a better tls flag?)3334 section.header.flags.MEM_DISCARDABLE)
3335 {
3336 continue;
3337 }
30013338
3002 //coff.objectSectionMapIndex(name: String, alignment: Alignment, attributes: ObjectSectionAttributes)3339 if (section.header.flags.LNK_COMDAT)
3340 // This will be necessary if we do the equivalent of /Gy for compiler-rt
3341 return diags.failParse(path, "TODO handle COMDAT sections in input objects", .{});
30033342
3004 // TODO: Load relocations, update for new offset? Or can just work with the object section parent?3343 log.debug("loadInputSection({s})", .{section.name.toSlice(coff)});
30053344
3345 const parent_osmi = try coff.objectSectionMapIndex(
3346 section.name,
3347 coff.mf.flags.block_size,
3348 .fromFlags(section.header.flags),
3349 );
3350 const parent_si = parent_osmi.symbol(coff);
3351 const ni = try coff.mf.addLastChildNode(gpa, parent_si.node(coff), .{
3352 .size = section.header.size_of_raw_data,
3353 .alignment = if (section.header.flags.ALIGN.toByteUnits()) |align_bytes|
3354 .fromByteUnits(align_bytes)
3355 else
3356 .@"1",
3357 .moved = true,
3358 });
3359 coff.nodes.appendAssumeCapacity(.{ .input_section = @enumFromInt(coff.input_sections.items.len) });
3360
3361 section.si = coff.addSymbolAssumeCapacity();
3362 const sym = section.si.get(coff);
3363 sym.ni = ni;
3364 sym.section_number = parent_si.get(coff).section_number;
3365
3366 coff.input_sections.addOneAssumeCapacity().* = .{
3367 .ii = ii,
3368 .si = section.si,
3369 .file_location = .{
3370 .offset = fl.offset + section.header.pointer_to_raw_data,
3371 .size = section.header.size_of_raw_data,
3372 },
3373 };
3374
3375 coff.synth_prog_node.increaseEstimatedTotalItems(1);
3006 }3376 }
30073377
3008 break :sections sections;3378 break :sections sections;
...@@ -3019,38 +3389,42 @@ fn loadObject(...@@ -3019,38 +3389,42 @@ fn loadObject(
3019 const member = mi.get(coff);3389 const member = mi.get(coff);
3020 try member.initHeader(coff, path_str, header.time_date_stamp);3390 try member.initHeader(coff, path_str, header.time_date_stamp);
30213391
3392 // TODO: This could be deferred to an idle task?
3393
3022 {3394 {
3023 var nw: MappedFile.Node.Writer = undefined;3395 var nw: MappedFile.Node.Writer = undefined;
3024 member.content_ni.writer(&coff.mf, gpa, &nw);3396 member.content_ni.writer(&coff.mf, gpa, &nw);
3025 defer nw.deinit();3397 defer nw.deinit();
30263398
3027 try fr.seekTo(fl.offset);3399 try fr.seekTo(fl.offset);
3028 try r.streamExact(&nw.interface, fl.size);3400 if (try nw.interface.sendFileAll(fr, .limited64(fl.size)) != fl.size)
3401 return error.EndOfStream;
3029 }3402 }
30303403
3031 break :mi mi;3404 break :mi mi;
3032 } else undefined;3405 } else undefined;
30333406
3407 // TODO: Also reserve memory for the symbols / globals / relocs within each section
3408
3034 try fr.seekTo(fl.offset + header.pointer_to_symbol_table);3409 try fr.seekTo(fl.offset + header.pointer_to_symbol_table);
3035 const symbol_size = std.coff.Symbol.sizeOf();3410 const symbol_size = comptime std.coff.Symbol.sizeOf();
30363411
3412 var symbols: std.ArrayList(Symbol.Index) = .empty;
3413 try symbols.ensureUnusedCapacity(gpa, header.number_of_symbols);
3414
3415 const first_si = coff.symbols.items.len;
3037 var symbol_ix: u32 = 0;3416 var symbol_ix: u32 = 0;
3038 while (symbol_ix < header.number_of_symbols) {3417 while (symbol_ix < header.number_of_symbols) {
3039 const symbol: *align(2) std.coff.Symbol = @ptrCast(@alignCast(try r.take(symbol_size)));3418 var symbol: std.coff.Symbol = undefined;
3419 @memcpy(std.mem.asBytes(&symbol)[0..symbol_size], try r.take(symbol_size));
3420 if (target_endian != native_endian)
3421 std.mem.byteSwapAllFields(std.coff.Symbol, &symbol);
3422
3040 defer {3423 defer {
3041 r.toss(symbol.number_of_aux_symbols * symbol_size);3424 r.toss(symbol.number_of_aux_symbols * symbol_size);
3042 symbol_ix += symbol.number_of_aux_symbols + 1;3425 symbol_ix += symbol.number_of_aux_symbols + 1;
3043 }3426 }
30443427
3045 switch (symbol.section_number) {
3046 .UNDEFINED, .ABSOLUTE, .DEBUG => continue,
3047 else => switch (symbol.storage_class) {
3048 .STATIC => if (symbol.value == 0) continue,
3049 .EXTERNAL => {},
3050 else => continue,
3051 },
3052 }
3053
3054 const name = std.mem.sliceTo(if (std.mem.eql(u8, symbol.name[0..4], "\x00\x00\x00\x00")) name: {3428 const name = std.mem.sliceTo(if (std.mem.eql(u8, symbol.name[0..4], "\x00\x00\x00\x00")) name: {
3055 const index = std.mem.readInt(u32, symbol.name[4..], target_endian);3429 const index = std.mem.readInt(u32, symbol.name[4..], target_endian);
3056 if (index >= string_table.len)3430 if (index >= string_table.len)
...@@ -3058,21 +3432,125 @@ fn loadObject(...@@ -3058,21 +3432,125 @@ fn loadObject(
3058 break :name string_table[index..];3432 break :name string_table[index..];
3059 } else &symbol.name, 0);3433 } else &symbol.name, 0);
30603434
3061 // Section numbers are 1-based here3435 const si = symbols.addOneAssumeCapacity();
3062 if (!is_archive and @intFromEnum(symbol.section_number) > sections.len)3436 si.* = .null;
3063 return diags.failParse(path, "bad section number {d} for '{s}'", .{ symbol.section_number, name });3437
3438 switch (symbol.section_number) {
3439 .UNDEFINED, .ABSOLUTE, .DEBUG => continue,
3440 else => switch (symbol.storage_class) {
3441 .STATIC => if (symbol.value == 0 and symbol.type == std.coff.SymType{
3442 .complex_type = .NULL,
3443 .base_type = .NULL,
3444 }) {
3445 if (symbol.number_of_aux_symbols != 1)
3446 return diags.failParse(path, "invalid number of aux symbols for section {d}: {d}", .{
3447 symbol_ix,
3448 symbol.number_of_aux_symbols,
3449 });
3450
3451 var section_def: std.coff.SectionDefinition = undefined;
3452 @memcpy(std.mem.asBytes(&section_def)[0..symbol_size], try r.peek(symbol_size));
3453 if (target_endian != native_endian)
3454 std.mem.byteSwapAllFields(std.coff.SectionDefinition, &section_def);
3455
3456 // TODO: Extract the COMDAT section info
3457
3458 if (section_def.number > sections.len)
3459 return diags.failParse(
3460 path,
3461 "section symbol for '{s}' contained an out of bounds section number: {d}",
3462 .{ name, section_def.number },
3463 );
3464
3465 // It's valid for this to not match the symbol's section number (ie. .drectve sets this)
3466 if (section_def.number == 0)
3467 continue;
3468
3469 const section = &sections[section_def.number - 1];
3470 if (section_def.number_of_relocations != section.header.number_of_relocations)
3471 return diags.failParse(
3472 path,
3473 "section symbol for '{s}' relocation count did not match section header: {d} vs {d}",
3474 .{ name, section_def.number_of_relocations, section.header.number_of_relocations },
3475 );
3476
3477 if (section_def.number_of_linenumbers != section.header.number_of_linenumbers)
3478 return diags.failParse(
3479 path,
3480 "section symbol for '{s}' line number count did not match section header: {d} vs {d}",
3481 .{ name, section_def.number_of_linenumbers, section.header.number_of_linenumbers },
3482 );
3483
3484 si.* = section.si;
3485 continue;
3486 },
3487 .EXTERNAL => {},
3488 else => continue,
3489 },
3490 }
30643491
3065 if (is_archive) {3492 if (is_archive) {
3066 try coff.ensureMemberSymbol(mi, coff.getOrPutStringAssumeCapacity(name));3493 try coff.ensureMemberSymbol(mi, coff.getOrPutStringAssumeCapacity(name));
3067 continue;3494 continue;
3068 }3495 }
30693496
3497 // Section numbers are 1-based here
3498 if (@intFromEnum(symbol.section_number) <= 0 or @intFromEnum(symbol.section_number) > sections.len)
3499 return diags.failParse(path, "bad section number {d} for '{s}'", .{ symbol.section_number, name });
3500
3070 const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = name });3501 const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = name });
3502 // TODO: Support weak symbols
3071 if (global_gop.found_existing)3503 if (global_gop.found_existing)
3072 return diags.failParse(path, "multiple definitions of '{s}'", .{name});3504 return diags.failParse(path, "multiple definitions of '{s}'", .{name});
3505 si.* = global_gop.value_ptr.*;
3506
3507 const section = sections[@intCast(@intFromEnum(symbol.section_number) - 1)];
3508 const section_sym = section.si.get(coff);
30733509
3074 // TODO: Get the sym and set the ni to point to wherever it was copied in the pseudo section3510 const sym = si.get(coff);
3075 // TODO: May need to cache offsets and determine symbol sizes later (once we can sort by section offset)3511 sym.ni = section_sym.ni;
3512 sym.value = .{ .input_offset = symbol.value };
3513 sym.section_number = section_sym.section_number;
3514 }
3515
3516 if (coff.symbols.items.len > first_si) {
3517 input.first_si = @enumFromInt(first_si);
3518 input.last_si = @enumFromInt(coff.symbols.items.len - 1);
3519 }
3520
3521 const relocation_size = std.coff.Relocation.sizeOf();
3522 for (sections) |section| {
3523 if (section.si == .null) continue;
3524
3525 const loc_sym = section.si.get(coff);
3526 assert(loc_sym.loc_relocs == .none);
3527 loc_sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
3528
3529 if (section.header.number_of_relocations == 0) continue;
3530
3531 try coff.relocs.ensureUnusedCapacity(gpa, section.header.number_of_relocations);
3532 try fr.seekTo(fl.offset + section.header.pointer_to_relocations);
3533 for (0..section.header.number_of_relocations) |reloc_i| {
3534 var reloc: std.coff.Relocation = undefined;
3535 @memcpy(std.mem.asBytes(&reloc)[0..relocation_size], try r.take(relocation_size));
3536 if (target_endian != native_endian)
3537 std.mem.byteSwapAllFields(std.coff.Relocation, &reloc);
3538
3539 if (reloc.symbol_table_index >= symbols.items.len)
3540 return diags.failParse(
3541 path,
3542 "relocation {d} in section '{s}' targets invalid symbol index {d}",
3543 .{ reloc_i, section.name.toSlice(coff), reloc.symbol_table_index },
3544 );
3545
3546 try coff.addReloc(
3547 section.si,
3548 reloc.virtual_address - section.header.virtual_address,
3549 symbols.items[reloc.symbol_table_index],
3550 .pending,
3551 @bitCast(reloc.type), // TODO: Checks on this cast?
3552 );
3553 }
3076 }3554 }
3077}3555}
30783556
...@@ -3184,13 +3662,13 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -3184,13 +3662,13 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
3184 error.WriteFailed => return nw.err.?,3662 error.WriteFailed => return nw.err.?,
3185 else => |e| return e,3663 else => |e| return e,
3186 };3664 };
3187 si.get(coff).size = @intCast(nw.interface.end);3665 si.get(coff).value.size = @intCast(nw.interface.end);
3188 si.applyLocationRelocs(coff);3666 si.applyLocationRelocs(coff);
3189 }3667 }
31903668
3191 // TODO: Did my MappedFile resize change affect this?3669 // TODO: Did my MappedFile resize change affect this?
3192 if (nav.resolved.?.@"linksection".unwrap()) |_| {3670 if (nav.resolved.?.@"linksection".unwrap()) |_| {
3193 try ni.resize(&coff.mf, gpa, si.get(coff).size);3671 try ni.resize(&coff.mf, gpa, si.get(coff).value.size);
3194 var parent_ni = ni;3672 var parent_ni = ni;
3195 while (true) {3673 while (true) {
3196 parent_ni = parent_ni.parent(&coff.mf);3674 parent_ni = parent_ni.parent(&coff.mf);
...@@ -3318,7 +3796,7 @@ fn updateFuncInner(...@@ -3318,7 +3796,7 @@ fn updateFuncInner(
3318 error.WriteFailed => return nw.err.?,3796 error.WriteFailed => return nw.err.?,
3319 else => |e| return e,3797 else => |e| return e,
3320 };3798 };
3321 si.get(coff).size = @intCast(nw.interface.end);3799 si.get(coff).value.size = @intCast(nw.interface.end);
3322 si.applyLocationRelocs(coff);3800 si.applyLocationRelocs(coff);
3323}3801}
33243802
...@@ -3543,6 +4021,28 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -3543,6 +4021,28 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
3543 };4021 };
3544 break :task;4022 break :task;
3545 }4023 }
4024 // TODO: Idle task for flushing obj into lib?
4025 if (coff.input_section_pending_index < coff.input_sections.items.len) {
4026 const isi: Node.InputSectionIndex = @enumFromInt(coff.input_section_pending_index);
4027 coff.input_section_pending_index += 1;
4028 const sub_prog_node = coff.idleProgNode(tid, coff.input_prog_node, coff.getNode(isi.symbol(coff).node(coff)));
4029 defer sub_prog_node.end();
4030 coff.flushInputSection(isi) catch |err| switch (err) {
4031 else => |e| {
4032 const ii = isi.input(coff);
4033 return comp.link_diags.fail(
4034 "linker failed to read input section '{s}' from \"{f}{f}\": {t}",
4035 .{
4036 isi.symbol(coff).get(coff).section_number.name(coff).toSlice(coff),
4037 ii.path(coff).fmtEscapeString(),
4038 fmtArchiveNameString(ii.archiveName(coff)),
4039 e,
4040 },
4041 );
4042 },
4043 };
4044 break :task;
4045 }
3546 while (coff.mf.updates.pop()) |ni| {4046 while (coff.mf.updates.pop()) |ni| {
3547 const clean_moved = ni.cleanMoved(&coff.mf);4047 const clean_moved = ni.cleanMoved(&coff.mf);
3548 const clean_resized = ni.cleanResized(&coff.mf);4048 const clean_resized = ni.cleanResized(&coff.mf);
...@@ -3608,6 +4108,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -3608,6 +4108,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
3608 if (coff.globals.count() > coff.global_pending_index) return true;4108 if (coff.globals.count() > coff.global_pending_index) return true;
3609 if (coff.symbol_table.pending.count() > 0) return true;4109 if (coff.symbol_table.pending.count() > 0) return true;
3610 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;4110 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
4111 if (coff.input_sections.items.len > coff.input_section_pending_index) return true;
3611 if (coff.mf.updates.items.len > 0) return true;4112 if (coff.mf.updates.items.len > 0) return true;
3612 if (coff.pending_members.count() > 0) return true;4113 if (coff.pending_members.count() > 0) return true;
3613 if (coff.export_table.pending_sort) return true;4114 if (coff.export_table.pending_sort) return true;
...@@ -3626,6 +4127,14 @@ fn idleProgNode(...@@ -3626,6 +4127,14 @@ fn idleProgNode(
3626 else => |tag| @tagName(tag),4127 else => |tag| @tagName(tag),
3627 .image_section => |si| std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0),4128 .image_section => |si| std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0),
3628 inline .pseudo_section, .object_section => |smi| smi.name(coff).toSlice(coff),4129 inline .pseudo_section, .object_section => |smi| smi.name(coff).toSlice(coff),
4130 .input_section => |isi| {
4131 const ii = isi.input(coff);
4132 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
4133 ii.path(coff).fmtEscapeString(),
4134 fmtArchiveNameString(ii.archiveName(coff)),
4135 isi.symbol(coff).get(coff).section_number.name(coff).toSlice(coff),
4136 }) catch &name;
4137 },
3629 .global => |gmi| gmi.globalName(coff).name.toSlice(coff),4138 .global => |gmi| gmi.globalName(coff).name.toSlice(coff),
3630 .nav => |nmi| {4139 .nav => |nmi| {
3631 const ip = &coff.base.comp.zcu.?.intern_pool;4140 const ip = &coff.base.comp.zcu.?.intern_pool;
...@@ -3699,7 +4208,7 @@ fn flushUav(...@@ -3699,7 +4208,7 @@ fn flushUav(
3699 error.WriteFailed => return nw.err.?,4208 error.WriteFailed => return nw.err.?,
3700 else => |e| return e,4209 else => |e| return e,
3701 };4210 };
3702 si.get(coff).size = @intCast(nw.interface.end);4211 si.get(coff).value.size = @intCast(nw.interface.end);
3703 si.applyLocationRelocs(coff);4212 si.applyLocationRelocs(coff);
3704}4213}
37054214
...@@ -3864,12 +4373,12 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !void {...@@ -3864,12 +4373,12 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !void {
3864 });4373 });
3865 @memcpy(ni.slice(&coff.mf)[0..init.len], &init);4374 @memcpy(ni.slice(&coff.mf)[0..init.len], &init);
3866 sym.ni = ni;4375 sym.ni = ni;
3867 sym.size = init.len;4376 sym.value.size = init.len;
3868 try coff.addReloc(4377 try coff.addReloc(
3869 si,4378 si,
3870 init.len - 4,4379 init.len - 4,
3871 gop.value_ptr.import_address_table_si,4380 gop.value_ptr.import_address_table_si,
3872 @intCast(addr_size * import_symbol_index),4381 .{ .known = @intCast(addr_size * import_symbol_index) },
3873 .{ .AMD64 = .REL32 },4382 .{ .AMD64 = .REL32 },
3874 );4383 );
3875 },4384 },
...@@ -3929,7 +4438,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -3929,7 +4438,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
3929 error.WriteFailed => return nw.err.?,4438 error.WriteFailed => return nw.err.?,
3930 else => |e| return e,4439 else => |e| return e,
3931 };4440 };
3932 si.get(coff).size = @intCast(nw.interface.end);4441 si.get(coff).value.size = @intCast(nw.interface.end);
3933 si.applyLocationRelocs(coff);4442 si.applyLocationRelocs(coff);
3934}4443}
39354444
...@@ -3992,6 +4501,15 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -3992,6 +4501,15 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
3992 @intCast(file_offset),4501 @intCast(file_offset),
3993 );4502 );
3994 },4503 },
4504 .input_section => |isi| {
4505 const ii = isi.input(coff);
4506 var si = ii.firstSymbol(coff);
4507 const last_si = ii.lastSymbol(coff);
4508 while (@intFromEnum(si) <= @intFromEnum(last_si)) : (si = si.next()) {
4509 if (si.get(coff).ni != ni) continue;
4510 si.flushMoved(coff);
4511 }
4512 },
3995 .import_directory_table => coff.targetStore(4513 .import_directory_table => coff.targetStore(
3996 &coff.dataDirectoryPtr(.IMPORT).virtual_address,4514 &coff.dataDirectoryPtr(.IMPORT).virtual_address,
3997 coff.computeNodeRva(ni),4515 coff.computeNodeRva(ni),
...@@ -4204,6 +4722,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -4204,6 +4722,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
4204 );4722 );
4205 }4723 }
4206 },4724 },
4725 .input_section => {},
4207 .import_directory_table => coff.targetStore(4726 .import_directory_table => coff.targetStore(
4208 &coff.dataDirectoryPtr(.IMPORT).size,4727 &coff.dataDirectoryPtr(.IMPORT).size,
4209 @intCast(size),4728 @intCast(size),
...@@ -4228,7 +4747,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -4228,7 +4747,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
4228 );4747 );
4229 }4748 }
42304749
4231 smi.symbol(coff).get(coff).size = @intCast(size);4750 smi.symbol(coff).get(coff).value.size = @intCast(size);
4232 },4751 },
4233 .global,4752 .global,
4234 .nav,4753 .nav,
...@@ -4398,7 +4917,7 @@ fn updateExportsInner(...@@ -4398,7 +4917,7 @@ fn updateExportsInner(
4398 const export_sym = export_si.get(coff);4917 const export_sym = export_si.get(coff);
4399 export_sym.ni = exported_ni;4918 export_sym.ni = exported_ni;
4400 export_sym.rva = exported_sym.rva;4919 export_sym.rva = exported_sym.rva;
4401 export_sym.size = exported_sym.size;4920 export_sym.value.size = exported_sym.value.size;
4402 export_sym.section_number = exported_sym.section_number;4921 export_sym.section_number = exported_sym.section_number;
4403 defer export_si.applyTargetRelocs(coff);4922 defer export_si.applyTargetRelocs(coff);
44044923
...@@ -4407,7 +4926,7 @@ fn updateExportsInner(...@@ -4407,7 +4926,7 @@ fn updateExportsInner(
4407 coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva;4926 coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva;
4408 } else if (@"export".opts.name.eqlSlice("_tls_used", ip)) {4927 } else if (@"export".opts.name.eqlSlice("_tls_used", ip)) {
4409 const tls_directory = coff.dataDirectoryPtr(.TLS);4928 const tls_directory = coff.dataDirectoryPtr(.TLS);
4410 tls_directory.* = .{ .virtual_address = exported_sym.rva, .size = exported_sym.size };4929 tls_directory.* = .{ .virtual_address = exported_sym.rva, .size = exported_sym.value.size };
4411 if (coff.targetEndian() != native_endian)4930 if (coff.targetEndian() != native_endian)
4412 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);4931 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);
4413 }4932 }
...@@ -4492,7 +5011,7 @@ fn updateExportsInner(...@@ -4492,7 +5011,7 @@ fn updateExportsInner(
4492 coff.export_table.export_address_table_si,5011 coff.export_table.export_address_table_si,
4493 @intCast(@sizeOf(std.coff.ExportAddressTableEntry) * gop.index),5012 @intCast(@sizeOf(std.coff.ExportAddressTableEntry) * gop.index),
4494 export_si,5013 export_si,
4495 0,5014 .{ .known = 0 },
4496 .{ .AMD64 = .ADDR32NB },5015 .{ .AMD64 = .ADDR32NB },
4497 );5016 );
4498 } else {5017 } else {
...@@ -4541,6 +5060,14 @@ pub fn printNode(...@@ -4541,6 +5060,14 @@ pub fn printNode(
4541 .image_section => |si| try w.print("({s})", .{5060 .image_section => |si| try w.print("({s})", .{
4542 std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0),5061 std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0),
4543 }),5062 }),
5063 .input_section => |isi| {
5064 const ii = isi.input(coff);
5065 try w.print("({f}{f}, {s})", .{
5066 ii.path(coff).fmtEscapeString(),
5067 fmtArchiveNameString(ii.archiveName(coff)),
5068 isi.symbol(coff).get(coff).section_number.name(coff).toSlice(coff),
5069 });
5070 },
4544 .import_lookup_table,5071 .import_lookup_table,
4545 .import_address_table,5072 .import_address_table,
4546 .import_hint_name_table,5073 .import_hint_name_table,