| ... | ... | @@ -84,6 +84,8 @@ pub const default_size_of_heap_commit: u32 = 0x1000; |
| 84 | 84 | pub const archive_signature = "!<arch>\n"; |
| 85 | 85 | pub const archive_end_of_header = "`\n"; |
| 86 | 86 | |
| 87 | pub const imp_prefix = "__imp_"; |
| 88 | |
| 87 | 89 | /// This is the start of a Portable Executable (PE) file. |
| 88 | 90 | /// It starts with a MS-DOS header followed by a MS-DOS stub program. |
| 89 | 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 | 205 | pseudo_section: PseudoSectionMapIndex, |
| 204 | 206 | object_section: ObjectSectionMapIndex, |
| 205 | 207 | input_section: InputSection.Index, |
| 206 | | global: GlobalMapIndex, |
| 208 | import_thunk: GlobalMapIndex, // TODO: Rename to import_thunk |
| 207 | 209 | nav: NavMapIndex, |
| 208 | 210 | uav: UavMapIndex, |
| 209 | 211 | lazy_code: LazyMapRef.Index(.code), |
| ... | ... | @@ -255,10 +257,6 @@ pub const Node = union(enum) { |
| 255 | 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 | 260 | pub fn symbol(gmi: GlobalMapIndex, coff: *const Coff) Symbol.Index { |
| 263 | 261 | return coff.globals.values()[gmi.unwrap().?]; |
| 264 | 262 | } |
| ... | ... | @@ -707,6 +705,12 @@ pub const ExportTable = struct { |
| 707 | 705 | pub const ImportTable = struct { |
| 708 | 706 | ni: MappedFile.Node.Index, |
| 709 | 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 | 715 | pub const Entry = struct { |
| 712 | 716 | import_lookup_table_ni: MappedFile.Node.Index, |
| ... | ... | @@ -815,17 +819,20 @@ pub const Section = struct { |
| 815 | 819 | |
| 816 | 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 | 828 | pub const Symbol = struct { |
| 819 | 829 | ni: MappedFile.Node.Index, |
| 820 | 830 | rva: u32, |
| 821 | | value: union(enum) { |
| 822 | | /// For .ni == .input_section, this is the offset of this symbol within the input section |
| 823 | | input_offset: u32, |
| 824 | | /// For .ni == none and .gmi != .none, this is a weak alias |
| 825 | | /// that should replace this symbol, or .null if none exists |
| 826 | | alias_si: Symbol.Index, |
| 827 | | /// Otherwise, this is the symbol size if known |
| 828 | | size: u32, |
| 831 | value: std.meta.BareUnion(Symbol.Value), |
| 832 | flags: packed struct(u16) { |
| 833 | value_tag: ValueTag, |
| 834 | dll_storage_class: DllStorageClass, |
| 835 | _: u12 = 0, |
| 829 | 836 | }, |
| 830 | 837 | /// Relocations contained within this symbol |
| 831 | 838 | loc_relocs: Reloc.Index, |
| ... | ... | @@ -836,6 +843,55 @@ pub const Symbol = struct { |
| 836 | 843 | sti: SymbolTable.Index, |
| 837 | 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 | 895 | pub const SectionNumber = enum(i16) { |
| 840 | 896 | UNDEFINED = 0, |
| 841 | 897 | ABSOLUTE = -1, |
| ... | ... | @@ -847,10 +903,7 @@ pub const Symbol = struct { |
| 847 | 903 | } |
| 848 | 904 | |
| 849 | 905 | fn hasIndex(sn: SectionNumber) bool { |
| 850 | | return switch (sn) { |
| 851 | | .UNDEFINED, .ABSOLUTE, .DEBUG => false, |
| 852 | | else => true, |
| 853 | | }; |
| 906 | return @intFromEnum(sn) > 0; |
| 854 | 907 | } |
| 855 | 908 | |
| 856 | 909 | pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index { |
| ... | ... | @@ -902,11 +955,7 @@ pub const Symbol = struct { |
| 902 | 955 | |
| 903 | 956 | pub fn flushMoved(si: Symbol.Index, coff: *Coff) void { |
| 904 | 957 | const sym = si.get(coff); |
| 905 | | sym.rva = coff.computeNodeRva(sym.ni); |
| 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 | | } |
| 958 | sym.rva = coff.computeNodeRva(sym.ni) + sym.nodeOffset(coff); |
| 910 | 959 | si.applyLocationRelocs(coff); |
| 911 | 960 | si.applyTargetRelocs(coff); |
| 912 | 961 | } |
| ... | ... | @@ -967,7 +1016,7 @@ pub const Symbol = struct { |
| 967 | 1016 | }; |
| 968 | 1017 | |
| 969 | 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 | 1428 | .import_table = .{ |
| 1380 | 1429 | .ni = .none, |
| 1381 | 1430 | .entries = .empty, |
| 1431 | .iat_symbol_indices = .empty, |
| 1382 | 1432 | }, |
| 1383 | 1433 | .export_table = .{ |
| 1384 | 1434 | .ni = .none, |
| ... | ... | @@ -1460,6 +1510,7 @@ pub fn deinit(coff: *Coff) void { |
| 1460 | 1510 | coff.lib_string_table.deinit(gpa); |
| 1461 | 1511 | coff.long_names_table.entries.deinit(gpa); |
| 1462 | 1512 | coff.import_table.entries.deinit(gpa); |
| 1513 | coff.import_table.iat_symbol_indices.deinit(gpa); |
| 1463 | 1514 | coff.export_table.entries.deinit(gpa); |
| 1464 | 1515 | coff.symbol_table.strings.deinit(gpa); |
| 1465 | 1516 | coff.symbol_table.pending.deinit(gpa); |
| ... | ... | @@ -1840,16 +1891,7 @@ fn initHeaders( |
| 1840 | 1891 | } |
| 1841 | 1892 | |
| 1842 | 1893 | try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count); |
| 1843 | | coff.symbols.addOneAssumeCapacity().* = .{ |
| 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 | | }; |
| 1894 | assert(coff.addSymbolAssumeCapacity() == .null); |
| 1853 | 1895 | assert(try coff.addSection(.@".data", .{ |
| 1854 | 1896 | .CNT_INITIALIZED_DATA = true, |
| 1855 | 1897 | .MEM_READ = true, |
| ... | ... | @@ -2057,7 +2099,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { |
| 2057 | 2099 | ), |
| 2058 | 2100 | inline .pseudo_section, |
| 2059 | 2101 | .object_section, |
| 2060 | | .global, |
| 2102 | .import_thunk, |
| 2061 | 2103 | .nav, |
| 2062 | 2104 | .uav, |
| 2063 | 2105 | .lazy_code, |
| ... | ... | @@ -2070,10 +2112,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { |
| 2070 | 2112 | return @intCast(parent_rva + offset); |
| 2071 | 2113 | } |
| 2072 | 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) |
| 2074 | | sym.value.input_offset |
| 2075 | | else |
| 2076 | | 0; |
| 2115 | var section_offset: u32 = sym.nodeOffset(coff); |
| 2077 | 2116 | var parent_ni = sym.ni; |
| 2078 | 2117 | while (true) { |
| 2079 | 2118 | const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf); |
| ... | ... | @@ -2273,6 +2312,10 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { |
| 2273 | 2312 | .ni = .none, |
| 2274 | 2313 | .rva = 0, |
| 2275 | 2314 | .value = .{ .size = 0 }, |
| 2315 | .flags = .{ |
| 2316 | .value_tag = .size, |
| 2317 | .dll_storage_class = .default, |
| 2318 | }, |
| 2276 | 2319 | .loc_relocs = .none, |
| 2277 | 2320 | .target_relocs = .none, |
| 2278 | 2321 | .section_number = .UNDEFINED, |
| ... | ... | @@ -2357,8 +2400,9 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 2357 | 2400 | } |
| 2358 | 2401 | |
| 2359 | 2402 | const GlobalOptions = struct { |
| 2360 | | name: []const u8, // TODO: Union with String |
| 2403 | name: []const u8, |
| 2361 | 2404 | lib_name: ?[]const u8 = null, |
| 2405 | dll_storage_class: DllStorageClass = .default, |
| 2362 | 2406 | }; |
| 2363 | 2407 | |
| 2364 | 2408 | fn getOrPutGlobalSymbol( |
| ... | ... | @@ -2373,7 +2417,10 @@ fn getOrPutGlobalSymbol( |
| 2373 | 2417 | }); |
| 2374 | 2418 | if (!sym_gop.found_existing) { |
| 2375 | 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 | 2424 | sym_gop.value_ptr.* = si; |
| 2378 | 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 | 2493 | if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(.{ |
| 2447 | 2494 | .name = @"extern".name.toSlice(ip), |
| 2448 | 2495 | .lib_name = @"extern".lib_name.toSlice(ip), |
| 2496 | .dll_storage_class = if (@"extern".is_dll_import) .dllimport else .default, |
| 2449 | 2497 | }); |
| 2450 | 2498 | const nmi = try coff.navMapIndex(zcu, nav_index); |
| 2451 | 2499 | return nmi.symbol(coff); |
| ... | ... | @@ -2774,7 +2822,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void |
| 2774 | 2822 | }; |
| 2775 | 2823 | |
| 2776 | 2824 | coff.targetStore(&entry.value, switch (sym.section_number) { |
| 2777 | | .UNDEFINED => sym.value.size, |
| 2825 | .UNDEFINED => sym.size(), |
| 2778 | 2826 | .ABSOLUTE, |
| 2779 | 2827 | .DEBUG, |
| 2780 | 2828 | => unreachable, |
| ... | ... | @@ -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 | 2838 | fn flushInputMember(coff: *Coff, iami: InputArchive.Member.Index) !void { |
| ... | ... | @@ -3838,7 +3886,10 @@ fn loadObject( |
| 3838 | 3886 | .name = symbol.name.toSlice(coff), |
| 3839 | 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 | 3893 | symbol.si = global_gop.value_ptr.*; |
| 3843 | 3894 | break :comdat .include; |
| 3844 | 3895 | } |
| ... | ... | @@ -4003,9 +4054,7 @@ fn loadObject( |
| 4003 | 4054 | if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { |
| 4004 | 4055 | const sym = symbol.si.get(coff); |
| 4005 | 4056 | if (tag == .external) { |
| 4006 | | // TOOD: Is it valid to encounter multiple external definitions with different sizes? |
| 4007 | | assert(sym.value == .size); |
| 4008 | | sym.value = .{ .size = @max(sym.value.size, value) }; |
| 4057 | sym.setValue(.{ .size = @max(sym.size(), value) }); |
| 4009 | 4058 | } else { |
| 4010 | 4059 | const alias = pending_symbols.getPtr(value) orelse |
| 4011 | 4060 | return diags.failParse( |
| ... | ... | @@ -4022,7 +4071,7 @@ fn loadObject( |
| 4022 | 4071 | if (alias.si == .null) { |
| 4023 | 4072 | alias.weak_external_psi = .wrap(@intCast(psi)); |
| 4024 | 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 | 4112 | |
| 4064 | 4113 | if (section.si != symbol.si) { |
| 4065 | 4114 | const sym = symbol.si.get(coff); |
| 4115 | assert(sym.ni == .none); |
| 4066 | 4116 | sym.ni = section.si.get(coff).ni; |
| 4067 | | sym.value = switch (symbol.value) { |
| 4117 | sym.setValue(switch (symbol.value) { |
| 4068 | 4118 | .section => |v| .{ .size = v }, |
| 4069 | | .static => |v| .{ .input_offset = v }, |
| 4119 | .static => |v| .{ .node_offset = v }, |
| 4070 | 4120 | .external => |v| switch (symbol.section_number) { |
| 4071 | 4121 | .UNDEFINED, .ABSOLUTE, .DEBUG => unreachable, |
| 4072 | | else => .{ .input_offset = v }, |
| 4122 | else => .{ .node_offset = v }, |
| 4073 | 4123 | }, |
| 4074 | 4124 | .weak_external => unreachable, |
| 4075 | | }; |
| 4125 | }); |
| 4076 | 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 | 4130 | symbol.name.toSlice(coff), |
| 4081 | 4131 | index, |
| 4082 | 4132 | symbol.value, |
| ... | ... | @@ -4141,20 +4191,21 @@ fn loadObject( |
| 4141 | 4191 | pending_symbols.sortUnstable(SortContext{ .v = pending_symbols.values() }); |
| 4142 | 4192 | |
| 4143 | 4193 | try coff.input_symbols.ensureUnusedCapacity(gpa, num_included_symbols + num_included_sections); |
| 4144 | | var prev_sn: Symbol.SectionNumber = .UNDEFINED; |
| 4145 | | var include_section = true; |
| 4194 | var prev_sn: Symbol.SectionNumber = .DEBUG; |
| 4195 | var include_section = false; |
| 4146 | 4196 | for (pending_symbols.values()) |symbol| { |
| 4147 | 4197 | // The symbol may have not been included, or it's an undefined external |
| 4148 | 4198 | if (symbol.si == .null or symbol.si.get(coff).ni == .none) continue; |
| 4149 | 4199 | |
| 4150 | 4200 | if (prev_sn != symbol.section_number) { |
| 4151 | 4201 | prev_sn = symbol.section_number; |
| 4152 | | |
| 4153 | | const section = &sections[symbol.section_number.toIndex()]; |
| 4154 | | include_section = section.comdat_result == .include; |
| 4155 | | if (include_section) { |
| 4156 | | const isi = coff.getNode(section.si.get(coff).ni).input_section; |
| 4157 | | isi.inputSection(coff).first_li = @enumFromInt(coff.input_symbols.items.len); |
| 4202 | if (symbol.section_number.hasIndex()) { |
| 4203 | const section = &sections[symbol.section_number.toIndex()]; |
| 4204 | include_section = section.comdat_result == .include; |
| 4205 | if (include_section) { |
| 4206 | const isi = coff.getNode(section.si.get(coff).ni).input_section; |
| 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 | 4380 | var pos = fr.logicalPos(); |
| 4330 | 4381 | const size = try fr.getSize(); |
| 4331 | 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 | 4384 | const header = try r.takeStruct(std.coff.ArchiveMemberHeader, target_endian); |
| 4334 | 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 | 4405 | |
| 4355 | 4406 | const num_members = try r.takeInt(u32, target_endian); |
| 4356 | 4407 | pos = fr.logicalPos(); |
| 4357 | | if (pos + num_members * 4 > member_end) |
| 4408 | if (pos + num_members * @sizeOf(u32) > member_end) |
| 4358 | 4409 | return diags.failParse(path, "invalid member count 0x{x} in second linker member", .{num_members}); |
| 4359 | 4410 | |
| 4360 | 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 | 4417 | |
| 4367 | 4418 | const num_symbols = try r.takeInt(u32, target_endian); |
| 4368 | 4419 | pos = fr.logicalPos(); |
| 4369 | | if (pos + num_symbols * 2 > member_end) |
| 4420 | if (pos + num_symbols * @sizeOf(u16) > member_end) |
| 4370 | 4421 | return diags.failParse(path, "invalid symbol count 0x{x} in second linker member", .{num_symbols}); |
| 4371 | 4422 | |
| 4372 | 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 | 4583 | }; |
| 4533 | 4584 | } else { |
| 4534 | 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 | 4589 | return diags.failParse(path, "machine mismatch in member header '{s}': expected {t}, found {t}", .{ |
| 4537 | 4590 | res.name, |
| 4538 | 4591 | expected_machine, |
| ... | ... | @@ -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 | 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 | 4996 | inline .nav, |
| 4943 | 4997 | .uav, |
| ... | ... | @@ -5099,7 +5153,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5099 | 5153 | if (sym.ni != .none) |
| 5100 | 5154 | coff.getNode(sym.ni) |
| 5101 | 5155 | else |
| 5102 | | .{ .global = pending_si.key.get(coff).gmi }, |
| 5156 | .{ .import_thunk = pending_si.key.get(coff).gmi }, |
| 5103 | 5157 | ); |
| 5104 | 5158 | defer sub_prog_node.end(); |
| 5105 | 5159 | coff.flushSymbolTableEntry( |
| ... | ... | @@ -5229,7 +5283,7 @@ fn idleProgNode( |
| 5229 | 5283 | coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff), |
| 5230 | 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 | 5287 | .nav => |nmi| { |
| 5234 | 5288 | const ip = &coff.base.comp.zcu.?.intern_pool; |
| 5235 | 5289 | break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip); |
| ... | ... | @@ -5306,10 +5360,45 @@ fn flushUav( |
| 5306 | 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 | 5398 | fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5310 | 5399 | const comp = coff.base.comp; |
| 5311 | 5400 | const gpa = comp.gpa; |
| 5312 | | const gn = gmi.globalNameMutable(coff); |
| 5401 | const gn = gmi.globalName(coff); |
| 5313 | 5402 | const si = gmi.symbol(coff); |
| 5314 | 5403 | const sym = si.get(coff); |
| 5315 | 5404 | |
| ... | ... | @@ -5329,112 +5418,102 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5329 | 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 | 5430 | const Import = struct { |
| 5333 | 5431 | lib_name: String, |
| 5334 | | ref: union(enum) { |
| 5335 | | name: struct { |
| 5336 | | str: []const u8, |
| 5337 | | hint: ?u16, |
| 5338 | | }, |
| 5339 | | ordinal: u16, |
| 5432 | name: String.Optional, |
| 5433 | ordinal_hint: u16, |
| 5434 | kind: enum { |
| 5435 | iat_ptr, |
| 5436 | thunk, |
| 5340 | 5437 | }, |
| 5341 | 5438 | }; |
| 5342 | 5439 | |
| 5343 | | const opt_import: ?Import = if (gn.lib_name == .none and sym.ni == .none) import: { |
| 5344 | | switch (sym.value) { |
| 5345 | | .alias_si => |alias_si| { |
| 5346 | | assert(sym.section_number == .UNDEFINED); |
| 5347 | | assert(sym.loc_relocs == .none); |
| 5348 | | |
| 5349 | | const alias_sym = alias_si.get(coff); |
| 5350 | | var ri = sym.target_relocs; |
| 5351 | | while (ri != .none) { |
| 5352 | | const reloc = ri.get(coff); |
| 5353 | | assert(reloc.target == si); |
| 5354 | | reloc.target = alias_si; |
| 5355 | | if (reloc.next == .none) { |
| 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 | | } |
| 5440 | const opt_import: ?Import = if (sym.ni == .none) import: { |
| 5441 | const global_name = gn.name.toSlice(coff); |
| 5442 | const imp_match = std.mem.startsWith(u8, global_name, imp_prefix); |
| 5443 | |
| 5444 | // Globals may have the __imp_ prefix already if they are undef externals from another input. |
| 5445 | const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport) |
| 5446 | .{ gn.name, imp_match } |
| 5447 | else name: { |
| 5448 | try coff.ensureUnusedStringCapacity(imp_prefix.len + global_name.len); |
| 5449 | const name = try std.fmt.allocPrint(gpa, imp_prefix ++ "{s}", .{global_name}); |
| 5450 | defer gpa.free(name); |
| 5451 | break :name .{ coff.getOrPutStringAssumeCapacity(name), true }; |
| 5452 | }; |
| 5376 | 5453 | |
| 5377 | | if (coff.input_archive_symbol_indices.get(gmi.globalName(coff).name)) |index| { |
| 5378 | | var iter: InputArchive.Member.Symbol.Index = index.first; |
| 5454 | if (coff.input_archive_symbol_indices.get(search_name)) |indices_list| { |
| 5455 | var iter: InputArchive.Member.Symbol.Index = indices_list.first; |
| 5379 | 5456 | while (true) { |
| 5380 | 5457 | const archive_sym = &coff.input_archive_symbols.items[@intFromEnum(iter)]; |
| 5381 | 5458 | const member = &coff.input_archive_members.items[@intFromEnum(archive_sym.iami)]; |
| 5382 | | if (!member.flags.is_loaded) { |
| 5383 | | switch (member.content) { |
| 5384 | | .import => |import| switch (import.type) { |
| 5385 | | .CODE, |
| 5386 | | .DATA, |
| 5387 | | => { |
| 5388 | | defer member.flags.is_loaded = true; |
| 5389 | | // gn.lib_name = import.lib_name.toOptional(); |
| 5390 | | // try coff.globals.setKey(gpa, gmi.unwrap().?, gn.*); |
| 5391 | | |
| 5392 | | // Switch this global to an import |
| 5393 | | switch (import.name_type) { |
| 5394 | | .NAME, |
| 5395 | | .NAME_NOPREFIX, |
| 5396 | | .NAME_UNDECORATE, |
| 5397 | | => |tag| { |
| 5398 | | var name: []const u8 = import.symbol_name.toSlice(coff); |
| 5399 | | if (!(std.mem.eql(u8, name, gn.name.toSlice(coff)))) |
| 5400 | | return comp.link_diags.fail("import '{s}' has mismatched symbol name: '{s}'", .{ |
| 5401 | | import.symbol_name.toSlice(coff), |
| 5402 | | gn.name.toSlice(coff), |
| 5403 | | }); |
| 5404 | | |
| 5405 | | name = if (tag == .NAME) name else name: { |
| 5406 | | name = std.mem.trimStart(u8, name, "?@_"); |
| 5407 | | if (tag == .NAME_UNDECORATE) |
| 5408 | | name = std.mem.sliceTo(name, '@'); |
| 5409 | | break :name name; |
| 5410 | | }; |
| 5411 | | |
| 5412 | | break :import .{ |
| 5413 | | .lib_name = import.lib_name, |
| 5414 | | .ref = .{ |
| 5415 | | .name = .{ |
| 5416 | | .str = name, |
| 5417 | | .hint = import.import_ordinal_hint, |
| 5418 | | }, |
| 5419 | | }, |
| 5420 | | }; |
| 5421 | | }, |
| 5422 | | .ORDINAL => break :import .{ |
| 5423 | | .lib_name = import.lib_name, |
| 5424 | | .ref = .{ .ordinal = import.import_ordinal_hint }, |
| 5425 | | }, |
| 5426 | | else => |t| return comp.link_diags.fail("TODO handle name_type {t}", .{t}), |
| 5427 | | } |
| 5459 | member: switch (member.content) { |
| 5460 | .object => if (!member.flags.is_loaded) { |
| 5461 | if (gn.lib_name.unwrap()) |lib_name| |
| 5462 | if (!std.mem.eql(u8, lib_name.toSlice(coff), member.iai.path(coff).stem())) |
| 5463 | break :member; |
| 5464 | |
| 5465 | // Try loading the input member and then retry. |
| 5466 | // This could still be a member containing imports |
| 5467 | // that use the older non-IMPORT_HEADER method. |
| 5468 | coff.pending_input = archive_sym.iami; |
| 5469 | return false; |
| 5470 | }, |
| 5471 | .import => |import| { |
| 5472 | if (gn.lib_name.unwrap()) |lib_name| |
| 5473 | if (import.lib_name != lib_name) |
| 5474 | break :member; |
| 5475 | |
| 5476 | const name: String.Optional = name: switch (import.name_type) { |
| 5477 | .NAME, |
| 5478 | .NAME_NOPREFIX, |
| 5479 | .NAME_UNDECORATE, |
| 5480 | => |tag| { |
| 5481 | const symbol_name: []const u8 = import.symbol_name.toSlice(coff); |
| 5482 | const end_match = std.mem.endsWith(u8, global_name, symbol_name); |
| 5483 | const len_delta = global_name.len -% symbol_name.len; |
| 5484 | if (!end_match or |
| 5485 | (!imp_match and len_delta != 0) or |
| 5486 | (imp_match and len_delta != imp_prefix.len)) |
| 5487 | return comp.link_diags.fail( |
| 5488 | "global '{s}' has mismatched symbol name in import header: '{s}'", |
| 5489 | .{ |
| 5490 | gn.name.toSlice(coff), |
| 5491 | import.symbol_name.toSlice(coff), |
| 5492 | }, |
| 5493 | ); |
| 5494 | |
| 5495 | const name = if (tag == .NAME) import.symbol_name else undecorated: { |
| 5496 | var imp_name = std.mem.trimStart(u8, symbol_name, "?@_"); |
| 5497 | if (tag == .NAME_UNDECORATE) |
| 5498 | imp_name = std.mem.sliceTo(imp_name, '@'); |
| 5499 | |
| 5500 | try coff.ensureUnusedStringCapacity(imp_name.len); |
| 5501 | break :undecorated coff.getOrPutStringAssumeCapacity(imp_name); |
| 5502 | }; |
| 5503 | |
| 5504 | break :name name.toOptional(); |
| 5428 | 5505 | }, |
| 5429 | | .CONST => return comp.link_diags.fail("TODO handle import type CONST", .{}), |
| 5430 | | else => |t| return comp.link_diags.fail("invalid import type: {d}", .{t}), |
| 5431 | | }, |
| 5432 | | .object => { |
| 5433 | | // Try loading the input member and then retry |
| 5434 | | coff.pending_input = archive_sym.iami; |
| 5435 | | return false; |
| 5436 | | }, |
| 5437 | | } |
| 5506 | .ORDINAL => break :name .none, |
| 5507 | else => |t| return comp.link_diags.fail("TODO handle name_type {t}", .{t}), |
| 5508 | }; |
| 5509 | |
| 5510 | break :import .{ |
| 5511 | .lib_name = import.lib_name, |
| 5512 | .name = name, |
| 5513 | .ordinal_hint = import.import_ordinal_hint, |
| 5514 | .kind = if (import.type == .CODE and !is_imp) .thunk else .iat_ptr, |
| 5515 | }; |
| 5516 | }, |
| 5438 | 5517 | } |
| 5439 | 5518 | |
| 5440 | 5519 | if (archive_sym.next == iter) break; |
| ... | ... | @@ -5442,28 +5521,20 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5442 | 5521 | } |
| 5443 | 5522 | } |
| 5444 | 5523 | |
| 5445 | | break :import null; |
| 5446 | | } else if (gn.lib_name.unwrap()) |lib_name| .{ |
| 5447 | | .lib_name = lib_name, |
| 5448 | | .ref = .{ |
| 5449 | | .name = .{ |
| 5450 | | .str = gn.name.toSlice(coff), |
| 5451 | | .hint = null, |
| 5452 | | }, |
| 5453 | | }, |
| 5524 | // Allow importing symbols with no implib entry, if a lib_name was specified. |
| 5525 | // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification, |
| 5526 | // which are not in the implib. |
| 5527 | break :import if (gn.lib_name.unwrap()) |lib_name| .{ |
| 5528 | .lib_name = lib_name, |
| 5529 | .name = gn.name.toOptional(), |
| 5530 | .ordinal_hint = 0, |
| 5531 | .kind = .iat_ptr, |
| 5532 | } else null; |
| 5454 | 5533 | } else null; |
| 5455 | 5534 | |
| 5456 | 5535 | if (opt_import) |import| { |
| 5457 | 5536 | assert(sym.ni == .none); |
| 5458 | 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 | 5539 | try coff.nodes.ensureUnusedCapacity(gpa, 4); |
| 5469 | 5540 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -5547,76 +5618,138 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5547 | 5618 | if (target_endian != native_endian) |
| 5548 | 5619 | std.mem.byteSwapAllFields([2]std.coff.ImportDirectoryEntry, import_directory_entries); |
| 5549 | 5620 | } |
| 5550 | | const import_symbol_index = gop.value_ptr.len; |
| 5551 | | gop.value_ptr.len = import_symbol_index + 1; |
| 5552 | | const new_symbol_table_size = addr_size * (import_symbol_index + 2); |
| 5553 | | const import_hint_name_index = gop.value_ptr.hint_name_len; |
| 5554 | | gop.value_ptr.hint_name_len = @intCast( |
| 5555 | | import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1), |
| 5621 | |
| 5622 | log.debug( |
| 5623 | "flushGlobalImport({s}, {?s}, {d}, {s})", |
| 5624 | .{ gn.name.toSlice(coff), import.name.toSlice(coff), import.ordinal_hint, lib_name }, |
| 5556 | 5625 | ); |
| 5557 | | try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); |
| 5558 | | const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); |
| 5559 | | try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); |
| 5560 | | try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); |
| 5561 | | const import_lookup_slice = gop.value_ptr.import_lookup_table_ni.slice(&coff.mf); |
| 5562 | | const import_address_slice = import_address_table_ni.slice(&coff.mf); |
| 5563 | | const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf); |
| 5564 | | @memset(import_hint_name_slice[import_hint_name_index..][0..2], 0); |
| 5565 | | @memcpy(import_hint_name_slice[import_hint_name_index + 2 ..][0..name.len], name); |
| 5566 | | @memset(import_hint_name_slice[import_hint_name_index + 2 + name.len ..], 0); |
| 5567 | | const import_hint_name_rva = |
| 5568 | | coff.computeNodeRva(gop.value_ptr.import_hint_name_table_ni) + import_hint_name_index; |
| 5569 | | switch (magic) { |
| 5570 | | _ => unreachable, |
| 5571 | | inline .PE32, .@"PE32+" => |ct_magic| { |
| 5572 | | const Addr = switch (ct_magic) { |
| 5573 | | _ => comptime unreachable, |
| 5574 | | .PE32 => u32, |
| 5575 | | .@"PE32+" => u64, |
| 5576 | | }; |
| 5577 | | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); |
| 5578 | | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); |
| 5579 | | const import_hint_name_rvas: [2]Addr = .{ |
| 5580 | | std.mem.nativeTo(Addr, @intCast(import_hint_name_rva), target_endian), |
| 5581 | | std.mem.nativeTo(Addr, 0, target_endian), |
| 5582 | | }; |
| 5583 | | import_lookup_table[import_symbol_index..][0..2].* = import_hint_name_rvas; |
| 5584 | | import_address_table[import_symbol_index..][0..2].* = import_hint_name_rvas; |
| 5585 | | }, |
| 5626 | |
| 5627 | const iat_symbol_gop = try coff.import_table.iat_symbol_indices.getOrPut(gpa, .{ |
| 5628 | .iti = @enumFromInt(gop.index), |
| 5629 | .name = import.name, |
| 5630 | .ordinal_hint = import.ordinal_hint, |
| 5631 | }); |
| 5632 | if (!iat_symbol_gop.found_existing) { |
| 5633 | const import_symbol_index = gop.value_ptr.len; |
| 5634 | iat_symbol_gop.value_ptr.* = import_symbol_index; |
| 5635 | |
| 5636 | gop.value_ptr.len = import_symbol_index + 1; |
| 5637 | const new_symbol_table_size = addr_size * (import_symbol_index + 2); |
| 5638 | |
| 5639 | const opt_name = import.name.toSlice(coff); |
| 5640 | const opt_import_hint_name_index = if (opt_name) |name| blk: { |
| 5641 | const import_hint_name_index = gop.value_ptr.hint_name_len; |
| 5642 | gop.value_ptr.hint_name_len = @intCast( |
| 5643 | import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1), |
| 5644 | ); |
| 5645 | break :blk import_hint_name_index; |
| 5646 | } else null; |
| 5647 | |
| 5648 | try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); |
| 5649 | const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); |
| 5650 | try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); |
| 5651 | try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); |
| 5652 | |
| 5653 | const import_hint_name_rva = if (opt_import_hint_name_index) |import_hint_name_index| blk: { |
| 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 | 5708 | assert(sym.loc_relocs == .none); |
| 5589 | | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 5590 | | switch (coff.targetLoad(&coff.headerPtr().machine)) { |
| 5591 | | else => |tag| @panic(@tagName(tag)), |
| 5592 | | .AMD64 => { |
| 5593 | | const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; |
| 5594 | | const target = &comp.root_mod.resolved_target.result; |
| 5595 | | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ |
| 5596 | | .alignment = switch (comp.root_mod.optimize_mode) { |
| 5597 | | .Debug, |
| 5598 | | .ReleaseSafe, |
| 5599 | | .ReleaseFast, |
| 5600 | | => target_util.defaultFunctionAlignment(target), |
| 5601 | | .ReleaseSmall => target_util.minFunctionAlignment(target), |
| 5602 | | }.toStdMem(), |
| 5603 | | .size = init.len, |
| 5604 | | }); |
| 5605 | | @memcpy(ni.slice(&coff.mf)[0..init.len], &init); |
| 5606 | | sym.ni = ni; |
| 5607 | | sym.value.size = init.len; |
| 5608 | | try coff.addReloc( |
| 5609 | | si, |
| 5610 | | init.len - 4, |
| 5611 | | gop.value_ptr.import_address_table_si, |
| 5612 | | .{ .known = @intCast(addr_size * import_symbol_index) }, |
| 5613 | | .{ .AMD64 = .REL32 }, |
| 5614 | | ); |
| 5709 | const iat_offset: u32 = @intCast(addr_size * iat_symbol_gop.value_ptr.*); |
| 5710 | switch (import.kind) { |
| 5711 | .iat_ptr => { |
| 5712 | const iat_sym = gop.value_ptr.import_address_table_si.get(coff); |
| 5713 | sym.section_number = iat_sym.section_number; |
| 5714 | sym.ni = iat_sym.ni; |
| 5715 | sym.setValue(.{ .node_offset = iat_offset }); |
| 5716 | si.flushMoved(coff); |
| 5717 | }, |
| 5718 | .thunk => { |
| 5719 | sym.section_number = Symbol.Index.text.get(coff).section_number; |
| 5720 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 5721 | switch (coff.targetLoad(&coff.headerPtr().machine)) { |
| 5722 | else => |tag| @panic(@tagName(tag)), |
| 5723 | .AMD64 => { |
| 5724 | const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; |
| 5725 | const target = &comp.root_mod.resolved_target.result; |
| 5726 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ |
| 5727 | .alignment = switch (comp.root_mod.optimize_mode) { |
| 5728 | .Debug, |
| 5729 | .ReleaseSafe, |
| 5730 | .ReleaseFast, |
| 5731 | => target_util.defaultFunctionAlignment(target), |
| 5732 | .ReleaseSmall => target_util.minFunctionAlignment(target), |
| 5733 | }.toStdMem(), |
| 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 | 5755 | return true; |
| ... | ... | @@ -5845,7 +5978,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 5845 | 5978 | }, |
| 5846 | 5979 | inline .pseudo_section, |
| 5847 | 5980 | .object_section, |
| 5848 | | .global, |
| 5981 | .import_thunk, |
| 5849 | 5982 | .nav, |
| 5850 | 5983 | .uav, |
| 5851 | 5984 | .lazy_code, |
| ... | ... | @@ -5980,7 +6113,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 5980 | 6113 | |
| 5981 | 6114 | smi.symbol(coff).get(coff).value.size = @intCast(size); |
| 5982 | 6115 | }, |
| 5983 | | .global, |
| 6116 | .import_thunk, |
| 5984 | 6117 | .nav, |
| 5985 | 6118 | .uav, |
| 5986 | 6119 | .lazy_code, |
| ... | ... | @@ -6148,7 +6281,7 @@ fn updateExportsInner( |
| 6148 | 6281 | const export_sym = export_si.get(coff); |
| 6149 | 6282 | export_sym.ni = exported_ni; |
| 6150 | 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 | 6285 | export_sym.section_number = exported_sym.section_number; |
| 6153 | 6286 | defer export_si.applyTargetRelocs(coff); |
| 6154 | 6287 | |
| ... | ... | @@ -6308,7 +6441,7 @@ pub fn printNode( |
| 6308 | 6441 | inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{ |
| 6309 | 6442 | smi.name(coff).toSlice(coff), |
| 6310 | 6443 | }), |
| 6311 | | .global => |gmi| { |
| 6444 | .import_thunk => |gmi| { |
| 6312 | 6445 | const gn = gmi.globalName(coff); |
| 6313 | 6446 | try w.writeByte('('); |
| 6314 | 6447 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); |