| ... | @@ -31,6 +31,18 @@ long_names_table: LongNamesTable, | ... | @@ -31,6 +31,18 @@ long_names_table: LongNamesTable, |
| 31 | import_table: ImportTable, | 31 | import_table: ImportTable, |
| 32 | export_table: ExportTable, | 32 | export_table: ExportTable, |
| 33 | symbol_table: SymbolTable, | 33 | symbol_table: SymbolTable, |
| | 34 | inputs: 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 | }), |
| | 40 | input_sections: std.ArrayList(struct { |
| | 41 | ii: Node.InputIndex, |
| | 42 | si: Symbol.Index, |
| | 43 | file_location: MappedFile.Node.FileLocation, |
| | 44 | }), |
| | 45 | input_section_pending_index: u32, |
| 34 | strings: std.HashMapUnmanaged( | 46 | strings: 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, |
| 59 | synth_prog_node: std.Progress.Node, | 71 | synth_prog_node: std.Progress.Node, |
| 60 | symbol_prog_node: std.Progress.Node, | 72 | symbol_prog_node: std.Progress.Node, |
| 61 | member_prog_node: std.Progress.Node, | 73 | member_prog_node: std.Progress.Node, |
| | 74 | input_prog_node: std.Progress.Node, |
| 62 | dump_snapshot: bool, | 75 | dump_snapshot: bool, |
| 63 | | 76 | |
| 64 | pub const default_file_alignment: u16 = 0x200; | 77 | pub const default_file_alignment: u16 = 0x200; |
| ... | @@ -185,6 +198,7 @@ pub const Node = union(enum) { | ... | @@ -185,6 +198,7 @@ pub const Node = union(enum) { |
| 185 | | 198 | |
| 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 | }; |
| 268 | | 282 | |
| | 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, |
| 650 | | 704 | |
| 651 | pub const RelocationIndex = enum(u32) { | 705 | pub const RelocationIndex = enum(u16) { |
| 652 | none, | 706 | none, |
| 653 | _, | 707 | _, |
| 654 | | 708 | |
| 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 | } |
| 658 | | 712 | |
| 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 }; |
| 680 | pub const Symbol = struct { | 734 | pub 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 symbol | 743 | /// Relocations contained within this symbol |
| 685 | loc_relocs: Reloc.Index, | 744 | loc_relocs: Reloc.Index, |
| 686 | /// Relocations targeting this symbol | 745 | /// 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 | } |
| 706 | | 765 | |
| | 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 | } |
| 734 | | 797 | |
| | 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 { |
| 761 | | 832 | |
| 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 | } |
| 773 | | 849 | |
| ... | @@ -783,11 +859,16 @@ pub const Symbol = struct { | ... | @@ -783,11 +859,16 @@ pub const Symbol = struct { |
| 783 | | 859 | |
| 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 | }; |
| 793 | | 874 | |
| ... | @@ -797,14 +878,20 @@ pub const Symbol = struct { | ... | @@ -797,14 +878,20 @@ pub const Symbol = struct { |
| 797 | }; | 878 | }; |
| 798 | | 879 | |
| 799 | pub const Reloc = extern struct { | 880 | pub 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 | }, |
| 808 | | 895 | |
| 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 | }; |
| 829 | | 916 | |
| 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 { |
| 836 | | 923 | |
| 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); |
| 839 | | 927 | |
| 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 | } |
| 891 | | 980 | |
| 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 | } |
| 894 | | 1031 | |
| 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 | } |
| 900 | | 1037 | |
| 901 | const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); | 1038 | const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); |
| 902 | | 1039 | 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 | } |
| 1706 | | 1850 | |
| 1707 | pub fn endProgress(coff: *Coff) void { | 1851 | pub 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 | } |
| 1784 | fn computeNodeSectionOffset(coff: *Coff, ni: MappedFile.Node.Index) u32 { | 1930 | fn 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 { |
| 2003 | fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional { | 2152 | fn 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 | } |
| | 2155 | fn 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 | } |
| 2006 | | 2164 | |
| 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 avoid | 2166 | /// 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 | }; |
| 2468 | | 2626 | |
| 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 | }); |
| 2479 | | 2637 | |
| 2480 | log.debug("updateSymbolTableEntry({d}) = {d}", .{ si, sym.sti }); | 2638 | log.debug("updateSymbolTableEntry({d}) = {d}", .{ si, sym.sti }); |
| 2481 | } | 2639 | } |
| 2482 | | 2640 | |
| | 2641 | fn 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 | |
| 2483 | fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !Symbol.Index { | 2662 | fn 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); |
| 2485 | | 2664 | |
| ... | @@ -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 | .text | 2796 | .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_parent | 2807 | 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()); | | |
| 2634 | | 2812 | |
| 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 | |
| | 2839 | fn 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 | |
| 2650 | fn objectSectionMapIndex( | 2849 | fn 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 | } |
| 2710 | | 2916 | |
| 2711 | fn verifyParentSectionAttributes( | 2917 | fn 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; |
| 2719 | | 2926 | |
| 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 | }); |
| 2726 | | 2936 | |
| 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 | } |
| 2734 | | 2948 | |
| 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); |
| 2748 | | 2965 | |
| 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 | }); |
| 2750 | | 2975 | |
| 2751 | try coff.relocs.ensureUnusedCapacity(gpa, 1); | 2976 | try coff.relocs.ensureUnusedCapacity(gpa, 1); |
| 2752 | | 2977 | |
| ... | @@ -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 || |
| 2869 | fn fmtArchiveNameString(archiveName: ?[]const u8) std.fmt.Alt(?[]const u8, archiveNameStringEscape) { | 3097 | fn fmtArchiveNameString(archiveName: ?[]const u8) std.fmt.Alt(?[]const u8, archiveNameStringEscape) { |
| 2870 | return .{ .data = archiveName }; | 3098 | return .{ .data = archiveName }; |
| 2871 | } | 3099 | } |
| | 3100 | |
| 2872 | fn archiveNameStringEscape(archiveName: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { | 3101 | fn 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 | } |
| 2875 | | 3104 | |
| | 3105 | fn 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 | |
| 2876 | fn loadObject( | 3128 | fn 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()); |
| 2891 | | 3143 | |
| 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", .{}); |
| 2929 | | 3182 | |
| | 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( |
| 2942 | | 3205 | |
| 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 | }; |
| 2947 | | 3211 | |
| 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); |
| 2952 | | 3215 | |
| 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); |
| 2958 | | 3223 | |
| 2959 | continue; | 3224 | try fr.seekTo(fl.offset + @sizeOf(std.coff.Header)); |
| 2960 | } | 3225 | for (sections, 0..) |*section, section_i| { |
| 2961 | | 3226 | section.* = .{ |
| 2962 | if (section.header.flags.LNK_REMOVE or | 3227 | .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 PDB | 3230 | }; |
| 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", .{}); | | |
| 2972 | | 3231 | |
| 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) catch | 3234 | 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( |
| 2983 | | 3242 | |
| 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); |
| 2986 | | 3246 | |
| 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 | else | 3252 | }); |
| 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 | } |
| 2996 | | 3290 | |
| 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 | } |
| 2998 | | 3332 | |
| 2999 | // TODO: Decide to merge this section | 3333 | 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 | } |
| 3001 | | 3338 | |
| 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", .{}); |
| 3003 | | 3342 | |
| 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)}); |
| 3005 | | 3344 | |
| | 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 | } |
| 3007 | | 3377 | |
| 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); |
| 3021 | | 3391 | |
| | 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(); |
| 3026 | | 3398 | |
| 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 | } |
| 3030 | | 3403 | |
| 3031 | break :mi mi; | 3404 | break :mi mi; |
| 3032 | } else undefined; | 3405 | } else undefined; |
| 3033 | | 3406 | |
| | 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(); |
| 3036 | | 3411 | |
| | 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 | } |
| 3044 | | 3427 | |
| 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); |
| 3060 | | 3434 | |
| 3061 | // Section numbers are 1-based here | 3435 | 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 | } |
| 3064 | | 3491 | |
| 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 | } |
| 3069 | | 3496 | |
| | 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); |
| 3073 | | 3509 | |
| 3074 | // TODO: Get the sym and set the ni to point to wherever it was copied in the pseudo section | 3510 | 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 | } |
| 3078 | | 3556 | |
| ... | @@ -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 | } |
| 3190 | | 3668 | |
| 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 | } |
| 3324 | | 3802 | |
| ... | @@ -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 | } |
| 3705 | | 4214 | |
| ... | @@ -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 | } |
| 3935 | | 4444 | |
| ... | @@ -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 | } |
| 4230 | | 4749 | |
| 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); |
| 4404 | | 4923 | |
| ... | @@ -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, |