| ... | @@ -84,6 +84,8 @@ pub const default_size_of_heap_commit: u32 = 0x1000; | ... | @@ -84,6 +84,8 @@ pub const default_size_of_heap_commit: u32 = 0x1000; |
| 84 | pub const archive_signature = "!<arch>\n"; | 84 | pub const archive_signature = "!<arch>\n"; |
| 85 | pub const archive_end_of_header = "`\n"; | 85 | pub const archive_end_of_header = "`\n"; |
| 86 | | 86 | |
| | 87 | pub const imp_prefix = "__imp_"; |
| | 88 | |
| 87 | /// This is the start of a Portable Executable (PE) file. | 89 | /// This is the start of a Portable Executable (PE) file. |
| 88 | /// It starts with a MS-DOS header followed by a MS-DOS stub program. | 90 | /// It starts with a MS-DOS header followed by a MS-DOS stub program. |
| 89 | /// This data does not change so we include it as follows in all binaries. | 91 | /// This data does not change so we include it as follows in all binaries. |
| ... | @@ -203,7 +205,7 @@ pub const Node = union(enum) { | ... | @@ -203,7 +205,7 @@ pub const Node = union(enum) { |
| 203 | pseudo_section: PseudoSectionMapIndex, | 205 | pseudo_section: PseudoSectionMapIndex, |
| 204 | object_section: ObjectSectionMapIndex, | 206 | object_section: ObjectSectionMapIndex, |
| 205 | input_section: InputSection.Index, | 207 | input_section: InputSection.Index, |
| 206 | global: GlobalMapIndex, | 208 | import_thunk: GlobalMapIndex, // TODO: Rename to import_thunk |
| 207 | nav: NavMapIndex, | 209 | nav: NavMapIndex, |
| 208 | uav: UavMapIndex, | 210 | uav: UavMapIndex, |
| 209 | lazy_code: LazyMapRef.Index(.code), | 211 | lazy_code: LazyMapRef.Index(.code), |
| ... | @@ -255,10 +257,6 @@ pub const Node = union(enum) { | ... | @@ -255,10 +257,6 @@ pub const Node = union(enum) { |
| 255 | return coff.globals.keys()[gmi.unwrap().?]; | 257 | return coff.globals.keys()[gmi.unwrap().?]; |
| 256 | } | 258 | } |
| 257 | | 259 | |
| 258 | pub fn globalNameMutable(gmi: GlobalMapIndex, coff: *Coff) *GlobalName { | | |
| 259 | return &coff.globals.keys()[gmi.unwrap().?]; | | |
| 260 | } | | |
| 261 | | | |
| 262 | pub fn symbol(gmi: GlobalMapIndex, coff: *const Coff) Symbol.Index { | 260 | pub fn symbol(gmi: GlobalMapIndex, coff: *const Coff) Symbol.Index { |
| 263 | return coff.globals.values()[gmi.unwrap().?]; | 261 | return coff.globals.values()[gmi.unwrap().?]; |
| 264 | } | 262 | } |
| ... | @@ -707,6 +705,12 @@ pub const ExportTable = struct { | ... | @@ -707,6 +705,12 @@ pub const ExportTable = struct { |
| 707 | pub const ImportTable = struct { | 705 | pub const ImportTable = struct { |
| 708 | ni: MappedFile.Node.Index, | 706 | ni: MappedFile.Node.Index, |
| 709 | entries: std.array_hash_map.Auto(void, Entry), | 707 | entries: std.array_hash_map.Auto(void, Entry), |
| | 708 | iat_symbol_indices: std.AutoArrayHashMapUnmanaged(struct { |
| | 709 | iti: ImportTable.Index, |
| | 710 | name: String.Optional, |
| | 711 | // If name == .none this is the ordinal, otherwise the hint |
| | 712 | ordinal_hint: u16, |
| | 713 | }, u32), |
| 710 | | 714 | |
| 711 | pub const Entry = struct { | 715 | pub const Entry = struct { |
| 712 | import_lookup_table_ni: MappedFile.Node.Index, | 716 | import_lookup_table_ni: MappedFile.Node.Index, |
| ... | @@ -815,17 +819,20 @@ pub const Section = struct { | ... | @@ -815,17 +819,20 @@ pub const Section = struct { |
| 815 | | 819 | |
| 816 | pub const GlobalName = struct { name: String, lib_name: String.Optional }; | 820 | pub const GlobalName = struct { name: String, lib_name: String.Optional }; |
| 817 | | 821 | |
| | 822 | pub const DllStorageClass = enum(u2) { |
| | 823 | default, |
| | 824 | dllimport, |
| | 825 | dllexport, |
| | 826 | }; |
| | 827 | |
| 818 | pub const Symbol = struct { | 828 | pub const Symbol = struct { |
| 819 | ni: MappedFile.Node.Index, | 829 | ni: MappedFile.Node.Index, |
| 820 | rva: u32, | 830 | rva: u32, |
| 821 | value: union(enum) { | 831 | value: std.meta.BareUnion(Symbol.Value), |
| 822 | /// For .ni == .input_section, this is the offset of this symbol within the input section | 832 | flags: packed struct(u16) { |
| 823 | input_offset: u32, | 833 | value_tag: ValueTag, |
| 824 | /// For .ni == none and .gmi != .none, this is a weak alias | 834 | dll_storage_class: DllStorageClass, |
| 825 | /// that should replace this symbol, or .null if none exists | 835 | _: u12 = 0, |
| 826 | alias_si: Symbol.Index, | | |
| 827 | /// Otherwise, this is the symbol size if known | | |
| 828 | size: u32, | | |
| 829 | }, | 836 | }, |
| 830 | /// Relocations contained within this symbol | 837 | /// Relocations contained within this symbol |
| 831 | loc_relocs: Reloc.Index, | 838 | loc_relocs: Reloc.Index, |
| ... | @@ -836,6 +843,55 @@ pub const Symbol = struct { | ... | @@ -836,6 +843,55 @@ pub const Symbol = struct { |
| 836 | sti: SymbolTable.Index, | 843 | sti: SymbolTable.Index, |
| 837 | gmi: Node.GlobalMapIndex, | 844 | gmi: Node.GlobalMapIndex, |
| 838 | | 845 | |
| | 846 | const ValueTag = enum(u2) { |
| | 847 | node_offset, |
| | 848 | alias_si, |
| | 849 | size, |
| | 850 | }; |
| | 851 | |
| | 852 | pub const Value = union(ValueTag) { |
| | 853 | /// The offset of the symbol within it's node |
| | 854 | node_offset: u32, |
| | 855 | /// For undefined globals, this is a weak alias |
| | 856 | /// that can replace this symbol, or .null if none exists |
| | 857 | alias_si: Symbol.Index, |
| | 858 | /// The symbol size, or 0 if unknown |
| | 859 | size: u32, |
| | 860 | }; |
| | 861 | |
| | 862 | pub fn setValue(sym: *Symbol, value: Symbol.Value) void { |
| | 863 | sym.flags.value_tag = std.meta.activeTag(value); |
| | 864 | sym.value = switch (sym.flags.value_tag) { |
| | 865 | inline else => |t| @unionInit( |
| | 866 | @FieldType(Symbol, "value"), |
| | 867 | @tagName(t), |
| | 868 | @field(value, @tagName(t)), |
| | 869 | ), |
| | 870 | }; |
| | 871 | } |
| | 872 | |
| | 873 | pub fn nodeOffset(sym: *const Symbol, coff: *Coff) u32 { |
| | 874 | return switch (sym.flags.value_tag) { |
| | 875 | .node_offset => offset: { |
| | 876 | assert(switch (coff.getNode(sym.ni)) { |
| | 877 | // Separate nodes are not created for these entries per-symbol |
| | 878 | .input_section, .import_address_table => true, |
| | 879 | else => false, |
| | 880 | }); |
| | 881 | break :offset sym.value.node_offset; |
| | 882 | }, |
| | 883 | else => 0, |
| | 884 | }; |
| | 885 | } |
| | 886 | |
| | 887 | pub fn weakAlias(sym: *const Symbol) Symbol.Index { |
| | 888 | return if (sym.flags.value_tag == .alias_si) sym.value.alias_si else .null; |
| | 889 | } |
| | 890 | |
| | 891 | pub fn size(sym: *const Symbol) u32 { |
| | 892 | return if (sym.flags.value_tag == .size) sym.value.size else 0; |
| | 893 | } |
| | 894 | |
| 839 | pub const SectionNumber = enum(i16) { | 895 | pub const SectionNumber = enum(i16) { |
| 840 | UNDEFINED = 0, | 896 | UNDEFINED = 0, |
| 841 | ABSOLUTE = -1, | 897 | ABSOLUTE = -1, |
| ... | @@ -847,10 +903,7 @@ pub const Symbol = struct { | ... | @@ -847,10 +903,7 @@ pub const Symbol = struct { |
| 847 | } | 903 | } |
| 848 | | 904 | |
| 849 | fn hasIndex(sn: SectionNumber) bool { | 905 | fn hasIndex(sn: SectionNumber) bool { |
| 850 | return switch (sn) { | 906 | return @intFromEnum(sn) > 0; |
| 851 | .UNDEFINED, .ABSOLUTE, .DEBUG => false, | | |
| 852 | else => true, | | |
| 853 | }; | | |
| 854 | } | 907 | } |
| 855 | | 908 | |
| 856 | pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index { | 909 | pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index { |
| ... | @@ -902,11 +955,7 @@ pub const Symbol = struct { | ... | @@ -902,11 +955,7 @@ pub const Symbol = struct { |
| 902 | | 955 | |
| 903 | pub fn flushMoved(si: Symbol.Index, coff: *Coff) void { | 956 | pub fn flushMoved(si: Symbol.Index, coff: *Coff) void { |
| 904 | const sym = si.get(coff); | 957 | const sym = si.get(coff); |
| 905 | sym.rva = coff.computeNodeRva(sym.ni); | 958 | sym.rva = coff.computeNodeRva(sym.ni) + sym.nodeOffset(coff); |
| 906 | if (sym.gmi != .none and coff.getNode(sym.ni) == .input_section) { | | |
| 907 | // Symbols in input sections share a ni with their section | | |
| 908 | sym.rva += sym.value.input_offset; | | |
| 909 | } | | |
| 910 | si.applyLocationRelocs(coff); | 959 | si.applyLocationRelocs(coff); |
| 911 | si.applyTargetRelocs(coff); | 960 | si.applyTargetRelocs(coff); |
| 912 | } | 961 | } |
| ... | @@ -967,7 +1016,7 @@ pub const Symbol = struct { | ... | @@ -967,7 +1016,7 @@ pub const Symbol = struct { |
| 967 | }; | 1016 | }; |
| 968 | | 1017 | |
| 969 | comptime { | 1018 | comptime { |
| 970 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 36); | 1019 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 32); |
| 971 | } | 1020 | } |
| 972 | }; | 1021 | }; |
| 973 | | 1022 | |
| ... | @@ -1379,6 +1428,7 @@ fn create( | ... | @@ -1379,6 +1428,7 @@ fn create( |
| 1379 | .import_table = .{ | 1428 | .import_table = .{ |
| 1380 | .ni = .none, | 1429 | .ni = .none, |
| 1381 | .entries = .empty, | 1430 | .entries = .empty, |
| | 1431 | .iat_symbol_indices = .empty, |
| 1382 | }, | 1432 | }, |
| 1383 | .export_table = .{ | 1433 | .export_table = .{ |
| 1384 | .ni = .none, | 1434 | .ni = .none, |
| ... | @@ -1460,6 +1510,7 @@ pub fn deinit(coff: *Coff) void { | ... | @@ -1460,6 +1510,7 @@ pub fn deinit(coff: *Coff) void { |
| 1460 | coff.lib_string_table.deinit(gpa); | 1510 | coff.lib_string_table.deinit(gpa); |
| 1461 | coff.long_names_table.entries.deinit(gpa); | 1511 | coff.long_names_table.entries.deinit(gpa); |
| 1462 | coff.import_table.entries.deinit(gpa); | 1512 | coff.import_table.entries.deinit(gpa); |
| | 1513 | coff.import_table.iat_symbol_indices.deinit(gpa); |
| 1463 | coff.export_table.entries.deinit(gpa); | 1514 | coff.export_table.entries.deinit(gpa); |
| 1464 | coff.symbol_table.strings.deinit(gpa); | 1515 | coff.symbol_table.strings.deinit(gpa); |
| 1465 | coff.symbol_table.pending.deinit(gpa); | 1516 | coff.symbol_table.pending.deinit(gpa); |
| ... | @@ -1840,16 +1891,7 @@ fn initHeaders( | ... | @@ -1840,16 +1891,7 @@ fn initHeaders( |
| 1840 | } | 1891 | } |
| 1841 | | 1892 | |
| 1842 | try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count); | 1893 | try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count); |
| 1843 | coff.symbols.addOneAssumeCapacity().* = .{ | 1894 | assert(coff.addSymbolAssumeCapacity() == .null); |
| 1844 | .ni = .none, | | |
| 1845 | .rva = 0, | | |
| 1846 | .value = .{ .size = 0 }, | | |
| 1847 | .loc_relocs = .none, | | |
| 1848 | .target_relocs = .none, | | |
| 1849 | .section_number = .UNDEFINED, | | |
| 1850 | .sti = .none, | | |
| 1851 | .gmi = .none, | | |
| 1852 | }; | | |
| 1853 | assert(try coff.addSection(.@".data", .{ | 1895 | assert(try coff.addSection(.@".data", .{ |
| 1854 | .CNT_INITIALIZED_DATA = true, | 1896 | .CNT_INITIALIZED_DATA = true, |
| 1855 | .MEM_READ = true, | 1897 | .MEM_READ = true, |
| ... | @@ -2057,7 +2099,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { | ... | @@ -2057,7 +2099,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { |
| 2057 | ), | 2099 | ), |
| 2058 | inline .pseudo_section, | 2100 | inline .pseudo_section, |
| 2059 | .object_section, | 2101 | .object_section, |
| 2060 | .global, | 2102 | .import_thunk, |
| 2061 | .nav, | 2103 | .nav, |
| 2062 | .uav, | 2104 | .uav, |
| 2063 | .lazy_code, | 2105 | .lazy_code, |
| ... | @@ -2070,10 +2112,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { | ... | @@ -2070,10 +2112,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { |
| 2070 | return @intCast(parent_rva + offset); | 2112 | return @intCast(parent_rva + offset); |
| 2071 | } | 2113 | } |
| 2072 | fn computeSymbolSectionOffset(coff: *Coff, sym: *const Symbol) u32 { | 2114 | fn computeSymbolSectionOffset(coff: *Coff, sym: *const Symbol) u32 { |
| 2073 | var section_offset: u32 = if (sym.gmi != .none and coff.getNode(sym.ni) == .input_section) | 2115 | var section_offset: u32 = sym.nodeOffset(coff); |
| 2074 | sym.value.input_offset | | |
| 2075 | else | | |
| 2076 | 0; | | |
| 2077 | var parent_ni = sym.ni; | 2116 | var parent_ni = sym.ni; |
| 2078 | while (true) { | 2117 | while (true) { |
| 2079 | const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf); | 2118 | const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf); |
| ... | @@ -2273,6 +2312,10 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { | ... | @@ -2273,6 +2312,10 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { |
| 2273 | .ni = .none, | 2312 | .ni = .none, |
| 2274 | .rva = 0, | 2313 | .rva = 0, |
| 2275 | .value = .{ .size = 0 }, | 2314 | .value = .{ .size = 0 }, |
| | 2315 | .flags = .{ |
| | 2316 | .value_tag = .size, |
| | 2317 | .dll_storage_class = .default, |
| | 2318 | }, |
| 2276 | .loc_relocs = .none, | 2319 | .loc_relocs = .none, |
| 2277 | .target_relocs = .none, | 2320 | .target_relocs = .none, |
| 2278 | .section_number = .UNDEFINED, | 2321 | .section_number = .UNDEFINED, |
| ... | @@ -2357,8 +2400,9 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { | ... | @@ -2357,8 +2400,9 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 2357 | } | 2400 | } |
| 2358 | | 2401 | |
| 2359 | const GlobalOptions = struct { | 2402 | const GlobalOptions = struct { |
| 2360 | name: []const u8, // TODO: Union with String | 2403 | name: []const u8, |
| 2361 | lib_name: ?[]const u8 = null, | 2404 | lib_name: ?[]const u8 = null, |
| | 2405 | dll_storage_class: DllStorageClass = .default, |
| 2362 | }; | 2406 | }; |
| 2363 | | 2407 | |
| 2364 | fn getOrPutGlobalSymbol( | 2408 | fn getOrPutGlobalSymbol( |
| ... | @@ -2373,7 +2417,10 @@ fn getOrPutGlobalSymbol( | ... | @@ -2373,7 +2417,10 @@ fn getOrPutGlobalSymbol( |
| 2373 | }); | 2417 | }); |
| 2374 | if (!sym_gop.found_existing) { | 2418 | if (!sym_gop.found_existing) { |
| 2375 | const si = coff.addSymbolAssumeCapacity(); | 2419 | const si = coff.addSymbolAssumeCapacity(); |
| 2376 | si.get(coff).gmi = .wrap(@intCast(sym_gop.index)); | 2420 | const sym = si.get(coff); |
| | 2421 | sym.setValue(.{ .alias_si = .null }); |
| | 2422 | sym.gmi = .wrap(@intCast(sym_gop.index)); |
| | 2423 | sym.flags.dll_storage_class = opts.dll_storage_class; |
| 2377 | sym_gop.value_ptr.* = si; | 2424 | sym_gop.value_ptr.* = si; |
| 2378 | coff.synth_prog_node.increaseEstimatedTotalItems(1); | 2425 | coff.synth_prog_node.increaseEstimatedTotalItems(1); |
| 2379 | | 2426 | |
| ... | @@ -2446,6 +2493,7 @@ pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbo | ... | @@ -2446,6 +2493,7 @@ pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbo |
| 2446 | if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(.{ | 2493 | if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(.{ |
| 2447 | .name = @"extern".name.toSlice(ip), | 2494 | .name = @"extern".name.toSlice(ip), |
| 2448 | .lib_name = @"extern".lib_name.toSlice(ip), | 2495 | .lib_name = @"extern".lib_name.toSlice(ip), |
| | 2496 | .dll_storage_class = if (@"extern".is_dll_import) .dllimport else .default, |
| 2449 | }); | 2497 | }); |
| 2450 | const nmi = try coff.navMapIndex(zcu, nav_index); | 2498 | const nmi = try coff.navMapIndex(zcu, nav_index); |
| 2451 | return nmi.symbol(coff); | 2499 | return nmi.symbol(coff); |
| ... | @@ -2774,7 +2822,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void | ... | @@ -2774,7 +2822,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void |
| 2774 | }; | 2822 | }; |
| 2775 | | 2823 | |
| 2776 | coff.targetStore(&entry.value, switch (sym.section_number) { | 2824 | coff.targetStore(&entry.value, switch (sym.section_number) { |
| 2777 | .UNDEFINED => sym.value.size, | 2825 | .UNDEFINED => sym.size(), |
| 2778 | .ABSOLUTE, | 2826 | .ABSOLUTE, |
| 2779 | .DEBUG, | 2827 | .DEBUG, |
| 2780 | => unreachable, | 2828 | => unreachable, |
| ... | @@ -2784,7 +2832,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void | ... | @@ -2784,7 +2832,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void |
| 2784 | }, | 2832 | }, |
| 2785 | }); | 2833 | }); |
| 2786 | | 2834 | |
| 2787 | log.debug("updateSymbolTableEntry({d}) = {d}", .{ si, sym.sti }); | 2835 | log.debug("flushSymbolTableEntry({d}) = {d}", .{ si, sym.sti }); |
| 2788 | } | 2836 | } |
| 2789 | | 2837 | |
| 2790 | fn flushInputMember(coff: *Coff, iami: InputArchive.Member.Index) !void { | 2838 | fn flushInputMember(coff: *Coff, iami: InputArchive.Member.Index) !void { |
| ... | @@ -3838,7 +3886,10 @@ fn loadObject( | ... | @@ -3838,7 +3886,10 @@ fn loadObject( |
| 3838 | .name = symbol.name.toSlice(coff), | 3886 | .name = symbol.name.toSlice(coff), |
| 3839 | .lib_name = null, | 3887 | .lib_name = null, |
| 3840 | }); | 3888 | }); |
| 3841 | if (!global_gop.found_existing) { | 3889 | |
| | 3890 | // TODO: What if the same symbol defined twice in this obj? |
| | 3891 | // TODO: Would need to mark this global as pending, or notice it later when .ni != none |
| | 3892 | if (!global_gop.found_existing or global_gop.value_ptr.get(coff).ni == .none) { |
| 3842 | symbol.si = global_gop.value_ptr.*; | 3893 | symbol.si = global_gop.value_ptr.*; |
| 3843 | break :comdat .include; | 3894 | break :comdat .include; |
| 3844 | } | 3895 | } |
| ... | @@ -4003,9 +4054,7 @@ fn loadObject( | ... | @@ -4003,9 +4054,7 @@ fn loadObject( |
| 4003 | if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { | 4054 | if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { |
| 4004 | const sym = symbol.si.get(coff); | 4055 | const sym = symbol.si.get(coff); |
| 4005 | if (tag == .external) { | 4056 | if (tag == .external) { |
| 4006 | // TOOD: Is it valid to encounter multiple external definitions with different sizes? | 4057 | sym.setValue(.{ .size = @max(sym.size(), value) }); |
| 4007 | assert(sym.value == .size); | | |
| 4008 | sym.value = .{ .size = @max(sym.value.size, value) }; | | |
| 4009 | } else { | 4058 | } else { |
| 4010 | const alias = pending_symbols.getPtr(value) orelse | 4059 | const alias = pending_symbols.getPtr(value) orelse |
| 4011 | return diags.failParse( | 4060 | return diags.failParse( |
| ... | @@ -4022,7 +4071,7 @@ fn loadObject( | ... | @@ -4022,7 +4071,7 @@ fn loadObject( |
| 4022 | if (alias.si == .null) { | 4071 | if (alias.si == .null) { |
| 4023 | alias.weak_external_psi = .wrap(@intCast(psi)); | 4072 | alias.weak_external_psi = .wrap(@intCast(psi)); |
| 4024 | } else { | 4073 | } else { |
| 4025 | sym.value = .{ .alias_si = alias.si }; | 4074 | sym.setValue(.{ .alias_si = alias.si }); |
| 4026 | } | 4075 | } |
| 4027 | } | 4076 | } |
| 4028 | } | 4077 | } |
| ... | @@ -4063,20 +4112,21 @@ fn loadObject( | ... | @@ -4063,20 +4112,21 @@ fn loadObject( |
| 4063 | | 4112 | |
| 4064 | if (section.si != symbol.si) { | 4113 | if (section.si != symbol.si) { |
| 4065 | const sym = symbol.si.get(coff); | 4114 | const sym = symbol.si.get(coff); |
| | 4115 | assert(sym.ni == .none); |
| 4066 | sym.ni = section.si.get(coff).ni; | 4116 | sym.ni = section.si.get(coff).ni; |
| 4067 | sym.value = switch (symbol.value) { | 4117 | sym.setValue(switch (symbol.value) { |
| 4068 | .section => |v| .{ .size = v }, | 4118 | .section => |v| .{ .size = v }, |
| 4069 | .static => |v| .{ .input_offset = v }, | 4119 | .static => |v| .{ .node_offset = v }, |
| 4070 | .external => |v| switch (symbol.section_number) { | 4120 | .external => |v| switch (symbol.section_number) { |
| 4071 | .UNDEFINED, .ABSOLUTE, .DEBUG => unreachable, | 4121 | .UNDEFINED, .ABSOLUTE, .DEBUG => unreachable, |
| 4072 | else => .{ .input_offset = v }, | 4122 | else => .{ .node_offset = v }, |
| 4073 | }, | 4123 | }, |
| 4074 | .weak_external => unreachable, | 4124 | .weak_external => unreachable, |
| 4075 | }; | 4125 | }); |
| 4076 | sym.section_number = symbol.section_number; | 4126 | sym.section_number = symbol.section_number; |
| 4077 | } | 4127 | } |
| 4078 | | 4128 | |
| 4079 | defer log.debug("addInputSymbol({s}, 0x{x}, {t}=0x{x}) = {d}@{d}", .{ | 4129 | log.debug("addInputSymbol({s}, 0x{x}, {t}=0x{x}) = {d}@{d}", .{ |
| 4080 | symbol.name.toSlice(coff), | 4130 | symbol.name.toSlice(coff), |
| 4081 | index, | 4131 | index, |
| 4082 | symbol.value, | 4132 | symbol.value, |
| ... | @@ -4141,20 +4191,21 @@ fn loadObject( | ... | @@ -4141,20 +4191,21 @@ fn loadObject( |
| 4141 | pending_symbols.sortUnstable(SortContext{ .v = pending_symbols.values() }); | 4191 | pending_symbols.sortUnstable(SortContext{ .v = pending_symbols.values() }); |
| 4142 | | 4192 | |
| 4143 | try coff.input_symbols.ensureUnusedCapacity(gpa, num_included_symbols + num_included_sections); | 4193 | try coff.input_symbols.ensureUnusedCapacity(gpa, num_included_symbols + num_included_sections); |
| 4144 | var prev_sn: Symbol.SectionNumber = .UNDEFINED; | 4194 | var prev_sn: Symbol.SectionNumber = .DEBUG; |
| 4145 | var include_section = true; | 4195 | var include_section = false; |
| 4146 | for (pending_symbols.values()) |symbol| { | 4196 | for (pending_symbols.values()) |symbol| { |
| 4147 | // The symbol may have not been included, or it's an undefined external | 4197 | // The symbol may have not been included, or it's an undefined external |
| 4148 | if (symbol.si == .null or symbol.si.get(coff).ni == .none) continue; | 4198 | if (symbol.si == .null or symbol.si.get(coff).ni == .none) continue; |
| 4149 | | 4199 | |
| 4150 | if (prev_sn != symbol.section_number) { | 4200 | if (prev_sn != symbol.section_number) { |
| 4151 | prev_sn = symbol.section_number; | 4201 | prev_sn = symbol.section_number; |
| 4152 | | 4202 | if (symbol.section_number.hasIndex()) { |
| 4153 | const section = &sections[symbol.section_number.toIndex()]; | 4203 | const section = &sections[symbol.section_number.toIndex()]; |
| 4154 | include_section = section.comdat_result == .include; | 4204 | include_section = section.comdat_result == .include; |
| 4155 | if (include_section) { | 4205 | if (include_section) { |
| 4156 | const isi = coff.getNode(section.si.get(coff).ni).input_section; | 4206 | const isi = coff.getNode(section.si.get(coff).ni).input_section; |
| 4157 | isi.inputSection(coff).first_li = @enumFromInt(coff.input_symbols.items.len); | 4207 | isi.inputSection(coff).first_li = @enumFromInt(coff.input_symbols.items.len); |
| | 4208 | } |
| 4158 | } | 4209 | } |
| 4159 | } | 4210 | } |
| 4160 | | 4211 | |
| ... | @@ -4329,7 +4380,7 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo | ... | @@ -4329,7 +4380,7 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo |
| 4329 | var pos = fr.logicalPos(); | 4380 | var pos = fr.logicalPos(); |
| 4330 | const size = try fr.getSize(); | 4381 | const size = try fr.getSize(); |
| 4331 | while (pos < size) : (pos = fr.logicalPos()) { | 4382 | while (pos < size) : (pos = fr.logicalPos()) { |
| 4332 | if ((pos & 1) != 0) r.toss(1); | 4383 | if ((pos & 1) != 0) try r.discardAll(1); |
| 4333 | const header = try r.takeStruct(std.coff.ArchiveMemberHeader, target_endian); | 4384 | const header = try r.takeStruct(std.coff.ArchiveMemberHeader, target_endian); |
| 4334 | const res = try parseArchiveMemberHeader(diags, path, &header, opt_longnames); | 4385 | const res = try parseArchiveMemberHeader(diags, path, &header, opt_longnames); |
| 4335 | | 4386 | |
| ... | @@ -4354,7 +4405,7 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo | ... | @@ -4354,7 +4405,7 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo |
| 4354 | | 4405 | |
| 4355 | const num_members = try r.takeInt(u32, target_endian); | 4406 | const num_members = try r.takeInt(u32, target_endian); |
| 4356 | pos = fr.logicalPos(); | 4407 | pos = fr.logicalPos(); |
| 4357 | if (pos + num_members * 4 > member_end) | 4408 | if (pos + num_members * @sizeOf(u32) > member_end) |
| 4358 | return diags.failParse(path, "invalid member count 0x{x} in second linker member", .{num_members}); | 4409 | return diags.failParse(path, "invalid member count 0x{x} in second linker member", .{num_members}); |
| 4359 | | 4410 | |
| 4360 | try members.ensureTotalCapacity(gpa, num_members); | 4411 | try members.ensureTotalCapacity(gpa, num_members); |
| ... | @@ -4366,7 +4417,7 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo | ... | @@ -4366,7 +4417,7 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo |
| 4366 | | 4417 | |
| 4367 | const num_symbols = try r.takeInt(u32, target_endian); | 4418 | const num_symbols = try r.takeInt(u32, target_endian); |
| 4368 | pos = fr.logicalPos(); | 4419 | pos = fr.logicalPos(); |
| 4369 | if (pos + num_symbols * 2 > member_end) | 4420 | if (pos + num_symbols * @sizeOf(u16) > member_end) |
| 4370 | return diags.failParse(path, "invalid symbol count 0x{x} in second linker member", .{num_symbols}); | 4421 | return diags.failParse(path, "invalid symbol count 0x{x} in second linker member", .{num_symbols}); |
| 4371 | | 4422 | |
| 4372 | try symbol_member_indices.ensureTotalCapacity(gpa, num_symbols); | 4423 | try symbol_member_indices.ensureTotalCapacity(gpa, num_symbols); |
| ... | @@ -4532,7 +4583,9 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo | ... | @@ -4532,7 +4583,9 @@ fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !vo |
| 4532 | }; | 4583 | }; |
| 4533 | } else { | 4584 | } else { |
| 4534 | member.content.object.size = res.size; | 4585 | member.content.object.size = res.size; |
| 4535 | if (machine != expected_machine) { | 4586 | // TODO: If .UNKNOWN assert later that it contains no non-undef symbols? |
| | 4587 | // Microsoft's CRT contains members that set .UNKNOWN but do have symbols |
| | 4588 | if (machine != expected_machine and machine != .UNKNOWN) { |
| 4536 | return diags.failParse(path, "machine mismatch in member header '{s}': expected {t}, found {t}", .{ | 4589 | return diags.failParse(path, "machine mismatch in member header '{s}': expected {t}, found {t}", .{ |
| 4537 | res.name, | 4590 | res.name, |
| 4538 | expected_machine, | 4591 | expected_machine, |
| ... | @@ -4935,9 +4988,10 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { | ... | @@ -4935,9 +4988,10 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 4935 | }); | 4988 | }); |
| 4936 | } | 4989 | } |
| 4937 | }, | 4990 | }, |
| 4938 | .global => |gmi| err.addNote("referenced by '{s}' in module '{s}'", .{ | 4991 | .import_thunk => |gmi| err.addNote("referenced by import thunk for '{s}'", .{ |
| 4939 | gmi.globalName(coff).name.toSlice(coff), | 4992 | gmi.globalName(coff).name.toSlice(coff), |
| 4940 | comp.zcu.?.root_mod.fully_qualified_name, | 4993 | // TODO: This won't always have a ZCU |
| | 4994 | //comp.zcu.?.root_mod.fully_qualified_name, |
| 4941 | }), | 4995 | }), |
| 4942 | inline .nav, | 4996 | inline .nav, |
| 4943 | .uav, | 4997 | .uav, |
| ... | @@ -5099,7 +5153,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ... | @@ -5099,7 +5153,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5099 | if (sym.ni != .none) | 5153 | if (sym.ni != .none) |
| 5100 | coff.getNode(sym.ni) | 5154 | coff.getNode(sym.ni) |
| 5101 | else | 5155 | else |
| 5102 | .{ .global = pending_si.key.get(coff).gmi }, | 5156 | .{ .import_thunk = pending_si.key.get(coff).gmi }, |
| 5103 | ); | 5157 | ); |
| 5104 | defer sub_prog_node.end(); | 5158 | defer sub_prog_node.end(); |
| 5105 | coff.flushSymbolTableEntry( | 5159 | coff.flushSymbolTableEntry( |
| ... | @@ -5229,7 +5283,7 @@ fn idleProgNode( | ... | @@ -5229,7 +5283,7 @@ fn idleProgNode( |
| 5229 | coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff), | 5283 | coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff), |
| 5230 | }) catch &name; | 5284 | }) catch &name; |
| 5231 | }, | 5285 | }, |
| 5232 | .global => |gmi| gmi.globalName(coff).name.toSlice(coff), | 5286 | .import_thunk => |gmi| gmi.globalName(coff).name.toSlice(coff), |
| 5233 | .nav => |nmi| { | 5287 | .nav => |nmi| { |
| 5234 | const ip = &coff.base.comp.zcu.?.intern_pool; | 5288 | const ip = &coff.base.comp.zcu.?.intern_pool; |
| 5235 | break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip); | 5289 | break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip); |
| ... | @@ -5306,10 +5360,45 @@ fn flushUav( | ... | @@ -5306,10 +5360,45 @@ fn flushUav( |
| 5306 | si.applyLocationRelocs(coff); | 5360 | si.applyLocationRelocs(coff); |
| 5307 | } | 5361 | } |
| 5308 | | 5362 | |
| | 5363 | fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !void { |
| | 5364 | const gn = gmi.globalName(coff); |
| | 5365 | const si = gmi.symbol(coff); |
| | 5366 | const sym = si.get(coff); |
| | 5367 | assert(sym.section_number == .UNDEFINED); |
| | 5368 | assert(sym.loc_relocs == .none); |
| | 5369 | |
| | 5370 | const alias_sym = alias_si.get(coff); |
| | 5371 | var ri = sym.target_relocs; |
| | 5372 | while (ri != .none) { |
| | 5373 | const reloc = ri.get(coff); |
| | 5374 | assert(reloc.target == si); |
| | 5375 | reloc.target = alias_si; |
| | 5376 | if (reloc.next == .none) { |
| | 5377 | reloc.next = alias_sym.target_relocs; |
| | 5378 | if (alias_sym.target_relocs != .none) |
| | 5379 | alias_sym.target_relocs.get(coff).prev = ri; |
| | 5380 | } |
| | 5381 | ri = reloc.next; |
| | 5382 | } |
| | 5383 | |
| | 5384 | sym.target_relocs = .none; |
| | 5385 | sym.gmi = alias_sym.gmi; |
| | 5386 | coff.globals.values()[gmi.unwrap().?] = alias_si; |
| | 5387 | alias_si.applyTargetRelocs(coff); |
| | 5388 | |
| | 5389 | log.debug("aliasGlobal({s}, {?s}) {d}->{d} ({?s})", .{ |
| | 5390 | gn.name.toSlice(coff), |
| | 5391 | gn.lib_name.toSlice(coff), |
| | 5392 | si, |
| | 5393 | alias_si, |
| | 5394 | if (alias_sym.gmi != .none) alias_sym.gmi.globalName(coff).name.toSlice(coff) else null, |
| | 5395 | }); |
| | 5396 | } |
| | 5397 | |
| 5309 | fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | 5398 | fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5310 | const comp = coff.base.comp; | 5399 | const comp = coff.base.comp; |
| 5311 | const gpa = comp.gpa; | 5400 | const gpa = comp.gpa; |
| 5312 | const gn = gmi.globalNameMutable(coff); | 5401 | const gn = gmi.globalName(coff); |
| 5313 | const si = gmi.symbol(coff); | 5402 | const si = gmi.symbol(coff); |
| 5314 | const sym = si.get(coff); | 5403 | const sym = si.get(coff); |
| 5315 | | 5404 | |
| ... | @@ -5329,112 +5418,102 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -5329,112 +5418,102 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5329 | return true; | 5418 | return true; |
| 5330 | } | 5419 | } |
| 5331 | | 5420 | |
| | 5421 | { |
| | 5422 | // Resolve unresolved .WEAK_EXTERNAL symbols to their aliases |
| | 5423 | const alias_si = sym.weakAlias(); |
| | 5424 | if (alias_si != .null) { |
| | 5425 | try coff.aliasGlobal(gmi, alias_si); |
| | 5426 | return true; |
| | 5427 | } |
| | 5428 | } |
| | 5429 | |
| 5332 | const Import = struct { | 5430 | const Import = struct { |
| 5333 | lib_name: String, | 5431 | lib_name: String, |
| 5334 | ref: union(enum) { | 5432 | name: String.Optional, |
| 5335 | name: struct { | 5433 | ordinal_hint: u16, |
| 5336 | str: []const u8, | 5434 | kind: enum { |
| 5337 | hint: ?u16, | 5435 | iat_ptr, |
| 5338 | }, | 5436 | thunk, |
| 5339 | ordinal: u16, | | |
| 5340 | }, | 5437 | }, |
| 5341 | }; | 5438 | }; |
| 5342 | | 5439 | |
| 5343 | const opt_import: ?Import = if (gn.lib_name == .none and sym.ni == .none) import: { | 5440 | const opt_import: ?Import = if (sym.ni == .none) import: { |
| 5344 | switch (sym.value) { | 5441 | const global_name = gn.name.toSlice(coff); |
| 5345 | .alias_si => |alias_si| { | 5442 | const imp_match = std.mem.startsWith(u8, global_name, imp_prefix); |
| 5346 | assert(sym.section_number == .UNDEFINED); | 5443 | |
| 5347 | assert(sym.loc_relocs == .none); | 5444 | // Globals may have the __imp_ prefix already if they are undef externals from another input. |
| 5348 | | 5445 | const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport) |
| 5349 | const alias_sym = alias_si.get(coff); | 5446 | .{ gn.name, imp_match } |
| 5350 | var ri = sym.target_relocs; | 5447 | else name: { |
| 5351 | while (ri != .none) { | 5448 | try coff.ensureUnusedStringCapacity(imp_prefix.len + global_name.len); |
| 5352 | const reloc = ri.get(coff); | 5449 | const name = try std.fmt.allocPrint(gpa, imp_prefix ++ "{s}", .{global_name}); |
| 5353 | assert(reloc.target == si); | 5450 | defer gpa.free(name); |
| 5354 | reloc.target = alias_si; | 5451 | break :name .{ coff.getOrPutStringAssumeCapacity(name), true }; |
| 5355 | if (reloc.next == .none) { | 5452 | }; |
| 5356 | reloc.next = alias_sym.target_relocs; | | |
| 5357 | if (alias_sym.target_relocs != .none) | | |
| 5358 | alias_sym.target_relocs.get(coff).prev = ri; | | |
| 5359 | } | | |
| 5360 | ri = reloc.next; | | |
| 5361 | } | | |
| 5362 | | | |
| 5363 | sym.target_relocs = .none; | | |
| 5364 | coff.globals.values()[gmi.unwrap().?] = alias_si; | | |
| 5365 | alias_si.applyTargetRelocs(coff); | | |
| 5366 | | | |
| 5367 | log.debug( | | |
| 5368 | "flushGlobal({s}, null) alias {d}->{d}", | | |
| 5369 | .{ gmi.globalName(coff).name.toSlice(coff), si, alias_si }, | | |
| 5370 | ); | | |
| 5371 | return true; | | |
| 5372 | }, | | |
| 5373 | .size => {}, | | |
| 5374 | .input_offset => unreachable, | | |
| 5375 | } | | |
| 5376 | | 5453 | |
| 5377 | if (coff.input_archive_symbol_indices.get(gmi.globalName(coff).name)) |index| { | 5454 | if (coff.input_archive_symbol_indices.get(search_name)) |indices_list| { |
| 5378 | var iter: InputArchive.Member.Symbol.Index = index.first; | 5455 | var iter: InputArchive.Member.Symbol.Index = indices_list.first; |
| 5379 | while (true) { | 5456 | while (true) { |
| 5380 | const archive_sym = &coff.input_archive_symbols.items[@intFromEnum(iter)]; | 5457 | const archive_sym = &coff.input_archive_symbols.items[@intFromEnum(iter)]; |
| 5381 | const member = &coff.input_archive_members.items[@intFromEnum(archive_sym.iami)]; | 5458 | const member = &coff.input_archive_members.items[@intFromEnum(archive_sym.iami)]; |
| 5382 | if (!member.flags.is_loaded) { | 5459 | member: switch (member.content) { |
| 5383 | switch (member.content) { | 5460 | .object => if (!member.flags.is_loaded) { |
| 5384 | .import => |import| switch (import.type) { | 5461 | if (gn.lib_name.unwrap()) |lib_name| |
| 5385 | .CODE, | 5462 | if (!std.mem.eql(u8, lib_name.toSlice(coff), member.iai.path(coff).stem())) |
| 5386 | .DATA, | 5463 | break :member; |
| 5387 | => { | 5464 | |
| 5388 | defer member.flags.is_loaded = true; | 5465 | // Try loading the input member and then retry. |
| 5389 | // gn.lib_name = import.lib_name.toOptional(); | 5466 | // This could still be a member containing imports |
| 5390 | // try coff.globals.setKey(gpa, gmi.unwrap().?, gn.*); | 5467 | // that use the older non-IMPORT_HEADER method. |
| 5391 | | 5468 | coff.pending_input = archive_sym.iami; |
| 5392 | // Switch this global to an import | 5469 | return false; |
| 5393 | switch (import.name_type) { | 5470 | }, |
| 5394 | .NAME, | 5471 | .import => |import| { |
| 5395 | .NAME_NOPREFIX, | 5472 | if (gn.lib_name.unwrap()) |lib_name| |
| 5396 | .NAME_UNDECORATE, | 5473 | if (import.lib_name != lib_name) |
| 5397 | => |tag| { | 5474 | break :member; |
| 5398 | var name: []const u8 = import.symbol_name.toSlice(coff); | 5475 | |
| 5399 | if (!(std.mem.eql(u8, name, gn.name.toSlice(coff)))) | 5476 | const name: String.Optional = name: switch (import.name_type) { |
| 5400 | return comp.link_diags.fail("import '{s}' has mismatched symbol name: '{s}'", .{ | 5477 | .NAME, |
| 5401 | import.symbol_name.toSlice(coff), | 5478 | .NAME_NOPREFIX, |
| 5402 | gn.name.toSlice(coff), | 5479 | .NAME_UNDECORATE, |
| 5403 | }); | 5480 | => |tag| { |
| 5404 | | 5481 | const symbol_name: []const u8 = import.symbol_name.toSlice(coff); |
| 5405 | name = if (tag == .NAME) name else name: { | 5482 | const end_match = std.mem.endsWith(u8, global_name, symbol_name); |
| 5406 | name = std.mem.trimStart(u8, name, "?@_"); | 5483 | const len_delta = global_name.len -% symbol_name.len; |
| 5407 | if (tag == .NAME_UNDECORATE) | 5484 | if (!end_match or |
| 5408 | name = std.mem.sliceTo(name, '@'); | 5485 | (!imp_match and len_delta != 0) or |
| 5409 | break :name name; | 5486 | (imp_match and len_delta != imp_prefix.len)) |
| 5410 | }; | 5487 | return comp.link_diags.fail( |
| 5411 | | 5488 | "global '{s}' has mismatched symbol name in import header: '{s}'", |
| 5412 | break :import .{ | 5489 | .{ |
| 5413 | .lib_name = import.lib_name, | 5490 | gn.name.toSlice(coff), |
| 5414 | .ref = .{ | 5491 | import.symbol_name.toSlice(coff), |
| 5415 | .name = .{ | 5492 | }, |
| 5416 | .str = name, | 5493 | ); |
| 5417 | .hint = import.import_ordinal_hint, | 5494 | |
| 5418 | }, | 5495 | const name = if (tag == .NAME) import.symbol_name else undecorated: { |
| 5419 | }, | 5496 | var imp_name = std.mem.trimStart(u8, symbol_name, "?@_"); |
| 5420 | }; | 5497 | if (tag == .NAME_UNDECORATE) |
| 5421 | }, | 5498 | imp_name = std.mem.sliceTo(imp_name, '@'); |
| 5422 | .ORDINAL => break :import .{ | 5499 | |
| 5423 | .lib_name = import.lib_name, | 5500 | try coff.ensureUnusedStringCapacity(imp_name.len); |
| 5424 | .ref = .{ .ordinal = import.import_ordinal_hint }, | 5501 | break :undecorated coff.getOrPutStringAssumeCapacity(imp_name); |
| 5425 | }, | 5502 | }; |
| 5426 | else => |t| return comp.link_diags.fail("TODO handle name_type {t}", .{t}), | 5503 | |
| 5427 | } | 5504 | break :name name.toOptional(); |
| 5428 | }, | 5505 | }, |
| 5429 | .CONST => return comp.link_diags.fail("TODO handle import type CONST", .{}), | 5506 | .ORDINAL => break :name .none, |
| 5430 | else => |t| return comp.link_diags.fail("invalid import type: {d}", .{t}), | 5507 | else => |t| return comp.link_diags.fail("TODO handle name_type {t}", .{t}), |
| 5431 | }, | 5508 | }; |
| 5432 | .object => { | 5509 | |
| 5433 | // Try loading the input member and then retry | 5510 | break :import .{ |
| 5434 | coff.pending_input = archive_sym.iami; | 5511 | .lib_name = import.lib_name, |
| 5435 | return false; | 5512 | .name = name, |
| 5436 | }, | 5513 | .ordinal_hint = import.import_ordinal_hint, |
| 5437 | } | 5514 | .kind = if (import.type == .CODE and !is_imp) .thunk else .iat_ptr, |
| | 5515 | }; |
| | 5516 | }, |
| 5438 | } | 5517 | } |
| 5439 | | 5518 | |
| 5440 | if (archive_sym.next == iter) break; | 5519 | if (archive_sym.next == iter) break; |
| ... | @@ -5442,28 +5521,20 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -5442,28 +5521,20 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5442 | } | 5521 | } |
| 5443 | } | 5522 | } |
| 5444 | | 5523 | |
| 5445 | break :import null; | 5524 | // Allow importing symbols with no implib entry, if a lib_name was specified. |
| 5446 | } else if (gn.lib_name.unwrap()) |lib_name| .{ | 5525 | // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification, |
| 5447 | .lib_name = lib_name, | 5526 | // which are not in the implib. |
| 5448 | .ref = .{ | 5527 | break :import if (gn.lib_name.unwrap()) |lib_name| .{ |
| 5449 | .name = .{ | 5528 | .lib_name = lib_name, |
| 5450 | .str = gn.name.toSlice(coff), | 5529 | .name = gn.name.toOptional(), |
| 5451 | .hint = null, | 5530 | .ordinal_hint = 0, |
| 5452 | }, | 5531 | .kind = .iat_ptr, |
| 5453 | }, | 5532 | } else null; |
| 5454 | } else null; | 5533 | } else null; |
| 5455 | | 5534 | |
| 5456 | if (opt_import) |import| { | 5535 | if (opt_import) |import| { |
| 5457 | assert(sym.ni == .none); | 5536 | assert(sym.ni == .none); |
| 5458 | const lib_name = import.lib_name.toSlice(coff); | 5537 | const lib_name = import.lib_name.toSlice(coff); |
| 5459 | const name = switch (import.ref) { | | |
| 5460 | .name => |n| n.str, | | |
| 5461 | .ordinal => return comp.link_diags.fail("TODO handle imports via ordinal", .{}), | | |
| 5462 | }; | | |
| 5463 | | | |
| 5464 | log.debug("flushGlobalImport({s}, {s})", .{ name, lib_name }); | | |
| 5465 | | | |
| 5466 | // TODO: Handle hint | | |
| 5467 | | 5538 | |
| 5468 | try coff.nodes.ensureUnusedCapacity(gpa, 4); | 5539 | try coff.nodes.ensureUnusedCapacity(gpa, 4); |
| 5469 | try coff.symbols.ensureUnusedCapacity(gpa, 1); | 5540 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -5547,76 +5618,138 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -5547,76 +5618,138 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5547 | if (target_endian != native_endian) | 5618 | if (target_endian != native_endian) |
| 5548 | std.mem.byteSwapAllFields([2]std.coff.ImportDirectoryEntry, import_directory_entries); | 5619 | std.mem.byteSwapAllFields([2]std.coff.ImportDirectoryEntry, import_directory_entries); |
| 5549 | } | 5620 | } |
| 5550 | const import_symbol_index = gop.value_ptr.len; | 5621 | |
| 5551 | gop.value_ptr.len = import_symbol_index + 1; | 5622 | log.debug( |
| 5552 | const new_symbol_table_size = addr_size * (import_symbol_index + 2); | 5623 | "flushGlobalImport({s}, {?s}, {d}, {s})", |
| 5553 | const import_hint_name_index = gop.value_ptr.hint_name_len; | 5624 | .{ gn.name.toSlice(coff), import.name.toSlice(coff), import.ordinal_hint, lib_name }, |
| 5554 | gop.value_ptr.hint_name_len = @intCast( | | |
| 5555 | import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1), | | |
| 5556 | ); | 5625 | ); |
| 5557 | try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); | 5626 | |
| 5558 | const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); | 5627 | const iat_symbol_gop = try coff.import_table.iat_symbol_indices.getOrPut(gpa, .{ |
| 5559 | try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); | 5628 | .iti = @enumFromInt(gop.index), |
| 5560 | try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); | 5629 | .name = import.name, |
| 5561 | const import_lookup_slice = gop.value_ptr.import_lookup_table_ni.slice(&coff.mf); | 5630 | .ordinal_hint = import.ordinal_hint, |
| 5562 | const import_address_slice = import_address_table_ni.slice(&coff.mf); | 5631 | }); |
| 5563 | const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf); | 5632 | if (!iat_symbol_gop.found_existing) { |
| 5564 | @memset(import_hint_name_slice[import_hint_name_index..][0..2], 0); | 5633 | const import_symbol_index = gop.value_ptr.len; |
| 5565 | @memcpy(import_hint_name_slice[import_hint_name_index + 2 ..][0..name.len], name); | 5634 | iat_symbol_gop.value_ptr.* = import_symbol_index; |
| 5566 | @memset(import_hint_name_slice[import_hint_name_index + 2 + name.len ..], 0); | 5635 | |
| 5567 | const import_hint_name_rva = | 5636 | gop.value_ptr.len = import_symbol_index + 1; |
| 5568 | coff.computeNodeRva(gop.value_ptr.import_hint_name_table_ni) + import_hint_name_index; | 5637 | const new_symbol_table_size = addr_size * (import_symbol_index + 2); |
| 5569 | switch (magic) { | 5638 | |
| 5570 | _ => unreachable, | 5639 | const opt_name = import.name.toSlice(coff); |
| 5571 | inline .PE32, .@"PE32+" => |ct_magic| { | 5640 | const opt_import_hint_name_index = if (opt_name) |name| blk: { |
| 5572 | const Addr = switch (ct_magic) { | 5641 | const import_hint_name_index = gop.value_ptr.hint_name_len; |
| 5573 | _ => comptime unreachable, | 5642 | gop.value_ptr.hint_name_len = @intCast( |
| 5574 | .PE32 => u32, | 5643 | import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1), |
| 5575 | .@"PE32+" => u64, | 5644 | ); |
| 5576 | }; | 5645 | break :blk import_hint_name_index; |
| 5577 | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); | 5646 | } else null; |
| 5578 | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); | 5647 | |
| 5579 | const import_hint_name_rvas: [2]Addr = .{ | 5648 | try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); |
| 5580 | std.mem.nativeTo(Addr, @intCast(import_hint_name_rva), target_endian), | 5649 | const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); |
| 5581 | std.mem.nativeTo(Addr, 0, target_endian), | 5650 | try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); |
| 5582 | }; | 5651 | try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); |
| 5583 | import_lookup_table[import_symbol_index..][0..2].* = import_hint_name_rvas; | 5652 | |
| 5584 | import_address_table[import_symbol_index..][0..2].* = import_hint_name_rvas; | 5653 | const import_hint_name_rva = if (opt_import_hint_name_index) |import_hint_name_index| blk: { |
| 5585 | }, | 5654 | const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf); |
| | 5655 | const ordinal_hint: *u16 = @ptrCast(@alignCast(import_hint_name_slice[import_hint_name_index..][0..2])); |
| | 5656 | ordinal_hint.* = std.mem.nativeTo(u16, import.ordinal_hint, target_endian); |
| | 5657 | @memcpy(import_hint_name_slice[import_hint_name_index + 2 ..][0..opt_name.?.len], opt_name.?); |
| | 5658 | @memset(import_hint_name_slice[import_hint_name_index + 2 + opt_name.?.len ..], 0); |
| | 5659 | break :blk coff.computeNodeRva(gop.value_ptr.import_hint_name_table_ni) + import_hint_name_index; |
| | 5660 | } else 0; |
| | 5661 | |
| | 5662 | const import_lookup_slice = gop.value_ptr.import_lookup_table_ni.slice(&coff.mf); |
| | 5663 | const import_address_slice = import_address_table_ni.slice(&coff.mf); |
| | 5664 | switch (magic) { |
| | 5665 | _ => unreachable, |
| | 5666 | inline .PE32, .@"PE32+" => |ct_magic| { |
| | 5667 | const Payload = packed union(u31) { |
| | 5668 | ordinal: packed struct(u31) { |
| | 5669 | ordinal: u16, |
| | 5670 | _: u15 = 0, |
| | 5671 | }, |
| | 5672 | hint_name_rva: u31, |
| | 5673 | }; |
| | 5674 | |
| | 5675 | const Entry = switch (ct_magic) { |
| | 5676 | _ => comptime unreachable, |
| | 5677 | .PE32 => packed struct(u32) { |
| | 5678 | payload: Payload, |
| | 5679 | is_ordinal: bool, |
| | 5680 | }, |
| | 5681 | .@"PE32+" => packed struct(u64) { |
| | 5682 | payload: Payload, |
| | 5683 | _: u32 = 0, |
| | 5684 | is_ordinal: bool, |
| | 5685 | }, |
| | 5686 | }; |
| | 5687 | const import_lookup_table: []Entry = @ptrCast(@alignCast(import_lookup_slice)); |
| | 5688 | const import_address_table: []Entry = @ptrCast(@alignCast(import_address_slice)); |
| | 5689 | const import_hint_name_rvas: [2]Entry = .{ |
| | 5690 | .{ |
| | 5691 | .payload = if (import.name == .none) |
| | 5692 | .{ .ordinal = .{ .ordinal = import.ordinal_hint } } |
| | 5693 | else |
| | 5694 | .{ .hint_name_rva = @intCast(import_hint_name_rva) }, |
| | 5695 | .is_ordinal = import.name == .none, |
| | 5696 | }, |
| | 5697 | @bitCast(@as(@typeInfo(Entry).@"struct".backing_integer.?, 0)), |
| | 5698 | }; |
| | 5699 | if (native_endian != target_endian) |
| | 5700 | for (import_hint_name_rvas) |*v| std.mem.byteSwapAllFields(Entry, v); |
| | 5701 | |
| | 5702 | import_lookup_table[import_symbol_index..][0..2].* = import_hint_name_rvas; |
| | 5703 | import_address_table[import_symbol_index..][0..2].* = import_hint_name_rvas; |
| | 5704 | }, |
| | 5705 | } |
| 5586 | } | 5706 | } |
| 5587 | sym.section_number = Symbol.Index.text.get(coff).section_number; | 5707 | |
| 5588 | assert(sym.loc_relocs == .none); | 5708 | assert(sym.loc_relocs == .none); |
| 5589 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | 5709 | const iat_offset: u32 = @intCast(addr_size * iat_symbol_gop.value_ptr.*); |
| 5590 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | 5710 | switch (import.kind) { |
| 5591 | else => |tag| @panic(@tagName(tag)), | 5711 | .iat_ptr => { |
| 5592 | .AMD64 => { | 5712 | const iat_sym = gop.value_ptr.import_address_table_si.get(coff); |
| 5593 | const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; | 5713 | sym.section_number = iat_sym.section_number; |
| 5594 | const target = &comp.root_mod.resolved_target.result; | 5714 | sym.ni = iat_sym.ni; |
| 5595 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ | 5715 | sym.setValue(.{ .node_offset = iat_offset }); |
| 5596 | .alignment = switch (comp.root_mod.optimize_mode) { | 5716 | si.flushMoved(coff); |
| 5597 | .Debug, | 5717 | }, |
| 5598 | .ReleaseSafe, | 5718 | .thunk => { |
| 5599 | .ReleaseFast, | 5719 | sym.section_number = Symbol.Index.text.get(coff).section_number; |
| 5600 | => target_util.defaultFunctionAlignment(target), | 5720 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 5601 | .ReleaseSmall => target_util.minFunctionAlignment(target), | 5721 | switch (coff.targetLoad(&coff.headerPtr().machine)) { |
| 5602 | }.toStdMem(), | 5722 | else => |tag| @panic(@tagName(tag)), |
| 5603 | .size = init.len, | 5723 | .AMD64 => { |
| 5604 | }); | 5724 | const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; |
| 5605 | @memcpy(ni.slice(&coff.mf)[0..init.len], &init); | 5725 | const target = &comp.root_mod.resolved_target.result; |
| 5606 | sym.ni = ni; | 5726 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ |
| 5607 | sym.value.size = init.len; | 5727 | .alignment = switch (comp.root_mod.optimize_mode) { |
| 5608 | try coff.addReloc( | 5728 | .Debug, |
| 5609 | si, | 5729 | .ReleaseSafe, |
| 5610 | init.len - 4, | 5730 | .ReleaseFast, |
| 5611 | gop.value_ptr.import_address_table_si, | 5731 | => target_util.defaultFunctionAlignment(target), |
| 5612 | .{ .known = @intCast(addr_size * import_symbol_index) }, | 5732 | .ReleaseSmall => target_util.minFunctionAlignment(target), |
| 5613 | .{ .AMD64 = .REL32 }, | 5733 | }.toStdMem(), |
| 5614 | ); | 5734 | .size = init.len, |
| | 5735 | }); |
| | 5736 | @memcpy(ni.slice(&coff.mf)[0..init.len], &init); |
| | 5737 | sym.ni = ni; |
| | 5738 | sym.setValue(.{ .size = init.len }); |
| | 5739 | try coff.addReloc( |
| | 5740 | si, |
| | 5741 | init.len - 4, |
| | 5742 | gop.value_ptr.import_address_table_si, |
| | 5743 | .{ .known = iat_offset }, |
| | 5744 | .{ .AMD64 = .REL32 }, |
| | 5745 | ); |
| | 5746 | }, |
| | 5747 | } |
| | 5748 | coff.nodes.appendAssumeCapacity(.{ .import_thunk = gmi }); |
| | 5749 | sym.rva = coff.computeNodeRva(sym.ni); |
| | 5750 | si.applyLocationRelocs(coff); |
| 5615 | }, | 5751 | }, |
| 5616 | } | 5752 | } |
| 5617 | coff.nodes.appendAssumeCapacity(.{ .global = gmi }); | | |
| 5618 | sym.rva = coff.computeNodeRva(sym.ni); | | |
| 5619 | si.applyLocationRelocs(coff); | | |
| 5620 | } | 5753 | } |
| 5621 | | 5754 | |
| 5622 | return true; | 5755 | return true; |
| ... | @@ -5845,7 +5978,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -5845,7 +5978,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 5845 | }, | 5978 | }, |
| 5846 | inline .pseudo_section, | 5979 | inline .pseudo_section, |
| 5847 | .object_section, | 5980 | .object_section, |
| 5848 | .global, | 5981 | .import_thunk, |
| 5849 | .nav, | 5982 | .nav, |
| 5850 | .uav, | 5983 | .uav, |
| 5851 | .lazy_code, | 5984 | .lazy_code, |
| ... | @@ -5980,7 +6113,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -5980,7 +6113,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 5980 | | 6113 | |
| 5981 | smi.symbol(coff).get(coff).value.size = @intCast(size); | 6114 | smi.symbol(coff).get(coff).value.size = @intCast(size); |
| 5982 | }, | 6115 | }, |
| 5983 | .global, | 6116 | .import_thunk, |
| 5984 | .nav, | 6117 | .nav, |
| 5985 | .uav, | 6118 | .uav, |
| 5986 | .lazy_code, | 6119 | .lazy_code, |
| ... | @@ -6148,7 +6281,7 @@ fn updateExportsInner( | ... | @@ -6148,7 +6281,7 @@ fn updateExportsInner( |
| 6148 | const export_sym = export_si.get(coff); | 6281 | const export_sym = export_si.get(coff); |
| 6149 | export_sym.ni = exported_ni; | 6282 | export_sym.ni = exported_ni; |
| 6150 | export_sym.rva = exported_sym.rva; | 6283 | export_sym.rva = exported_sym.rva; |
| 6151 | export_sym.value.size = exported_sym.value.size; | 6284 | export_sym.setValue(.{ .size = exported_sym.value.size }); |
| 6152 | export_sym.section_number = exported_sym.section_number; | 6285 | export_sym.section_number = exported_sym.section_number; |
| 6153 | defer export_si.applyTargetRelocs(coff); | 6286 | defer export_si.applyTargetRelocs(coff); |
| 6154 | | 6287 | |
| ... | @@ -6308,7 +6441,7 @@ pub fn printNode( | ... | @@ -6308,7 +6441,7 @@ pub fn printNode( |
| 6308 | inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{ | 6441 | inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{ |
| 6309 | smi.name(coff).toSlice(coff), | 6442 | smi.name(coff).toSlice(coff), |
| 6310 | }), | 6443 | }), |
| 6311 | .global => |gmi| { | 6444 | .import_thunk => |gmi| { |
| 6312 | const gn = gmi.globalName(coff); | 6445 | const gn = gmi.globalName(coff); |
| 6313 | try w.writeByte('('); | 6446 | try w.writeByte('('); |
| 6314 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); | 6447 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); |