| ... | ... | @@ -19,6 +19,7 @@ const Value = @import("../Value.zig"); |
| 19 | 19 | const Zcu = @import("../Zcu.zig"); |
| 20 | 20 | const ModuleDefinition = @import("../libs/mingw/def.zig").ModuleDefinition; |
| 21 | 21 | const implib = @import("../libs/mingw/implib.zig"); |
| 22 | const Path = std.Build.Cache.Path; |
| 22 | 23 | |
| 23 | 24 | base: link.File, |
| 24 | 25 | mf: MappedFile, |
| ... | ... | @@ -35,16 +36,19 @@ inputs: std.ArrayHashMapUnmanaged(std.Build.Cache.Path, void, std.Build.Cache.Pa |
| 35 | 36 | input_archives: std.ArrayList(InputArchive), |
| 36 | 37 | input_archive_members: std.ArrayList(InputArchive.Member), |
| 37 | 38 | input_archive_symbols: std.ArrayList(InputArchive.Member.Symbol), |
| 38 | | input_archive_symbol_indices: std.AutoArrayHashMapUnmanaged(String, struct { |
| 39 | | first: InputArchive.Member.Symbol.Index, |
| 40 | | last: InputArchive.Member.Symbol.Index, |
| 41 | | }), |
| 39 | input_archive_symbol_indices: std.AutoArrayHashMapUnmanaged(String, InputArchive.SearchList), |
| 42 | 40 | pending_input: ?InputArchive.Member.Index, |
| 41 | pending_default_libs: std.ArrayList(struct { |
| 42 | path: []const u8, |
| 43 | ioi: InputObject.Index, |
| 44 | }), |
| 45 | alternate_names: std.AutoArrayHashMapUnmanaged(String, String), |
| 43 | 46 | input_objects: std.ArrayList(InputObject), |
| 44 | 47 | input_symbols: std.ArrayList(Symbol.Index), |
| 45 | 48 | input_sections: std.ArrayList(Node.InputSection), |
| 46 | 49 | input_section_pending_index: u32, |
| 47 | 50 | inputs_complete: bool, |
| 51 | exports_complete: bool, |
| 48 | 52 | strings: std.HashMapUnmanaged( |
| 49 | 53 | u32, |
| 50 | 54 | void, |
| ... | ... | @@ -58,6 +62,8 @@ object_section_table: std.array_hash_map.Auto(String, Symbol.Index), |
| 58 | 62 | symbols: std.ArrayList(Symbol), |
| 59 | 63 | globals: std.array_hash_map.Auto(GlobalName, Symbol.Index), |
| 60 | 64 | global_pending_index: u32, |
| 65 | late_globals: std.ArrayList(Node.GlobalMapIndex), |
| 66 | late_globals_pending_index: u32, |
| 61 | 67 | navs: std.array_hash_map.Auto(InternPool.Nav.Index, Symbol.Index), |
| 62 | 68 | uavs: std.array_hash_map.Auto(InternPool.Index, Symbol.Index), |
| 63 | 69 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { |
| ... | ... | @@ -73,6 +79,7 @@ synth_prog_node: std.Progress.Node, |
| 73 | 79 | symbol_prog_node: std.Progress.Node, |
| 74 | 80 | member_prog_node: std.Progress.Node, |
| 75 | 81 | input_prog_node: std.Progress.Node, |
| 82 | subsystem: ?std.zig.Subsystem, |
| 76 | 83 | dump_snapshot: bool, |
| 77 | 84 | |
| 78 | 85 | pub const default_file_alignment: u16 = 0x200; |
| ... | ... | @@ -435,6 +442,11 @@ pub const InputArchive = struct { |
| 435 | 442 | }; |
| 436 | 443 | }; |
| 437 | 444 | }; |
| 445 | |
| 446 | pub const SearchList = struct { |
| 447 | first: InputArchive.Member.Symbol.Index, |
| 448 | last: InputArchive.Member.Symbol.Index, |
| 449 | }; |
| 438 | 450 | }; |
| 439 | 451 | |
| 440 | 452 | pub const InputObject = struct { |
| ... | ... | @@ -825,6 +837,23 @@ pub const Section = struct { |
| 825 | 837 | |
| 826 | 838 | pub const GlobalName = struct { name: String, lib_name: String.Optional }; |
| 827 | 839 | |
| 840 | pub const WeakExternalStrat = enum(u2) { |
| 841 | no_library, |
| 842 | library, |
| 843 | alias, |
| 844 | anti_dependency, |
| 845 | |
| 846 | pub fn fromFlag(flag: std.coff.WeakExternalFlag) WeakExternalStrat { |
| 847 | return switch (flag) { |
| 848 | .SEARCH_NOLIBRARY => .no_library, |
| 849 | .SEARCH_LIBRARY => .library, |
| 850 | .SEARCH_ALIAS => .alias, |
| 851 | .ANTI_DEPENDENCY => .anti_dependency, |
| 852 | _ => unreachable, |
| 853 | }; |
| 854 | } |
| 855 | }; |
| 856 | |
| 828 | 857 | pub const Symbol = struct { |
| 829 | 858 | ni: MappedFile.Node.Index, |
| 830 | 859 | rva: u32, |
| ... | ... | @@ -833,7 +862,9 @@ pub const Symbol = struct { |
| 833 | 862 | value_tag: ValueTag, |
| 834 | 863 | type: Symbol.Type, |
| 835 | 864 | dll_storage_class: DllStorageClass, |
| 836 | | _: u10 = 0, |
| 865 | // Only defined for .alias_si and .alias_name |
| 866 | weak_external_strat: WeakExternalStrat, |
| 867 | _: u8 = 0, |
| 837 | 868 | }, |
| 838 | 869 | /// Relocations contained within this symbol |
| 839 | 870 | loc_relocs: Reloc.Index, |
| ... | ... | @@ -859,15 +890,22 @@ pub const Symbol = struct { |
| 859 | 890 | const ValueTag = enum(u2) { |
| 860 | 891 | node_offset, |
| 861 | 892 | alias_si, |
| 893 | alias_name, |
| 862 | 894 | size, |
| 863 | 895 | }; |
| 864 | 896 | |
| 865 | 897 | pub const Value = union(ValueTag) { |
| 866 | | /// The offset of the symbol within it's node |
| 898 | /// The offset of the symbol within its node. Used with symbols that |
| 899 | /// don't create their own nodes: .input_section, .import_address_table |
| 867 | 900 | node_offset: u32, |
| 868 | | /// For undefined globals, this is a weak alias |
| 869 | | /// that can replace this symbol, or .null if none exists |
| 901 | /// This is a weak alias that can replace this symbol |
| 902 | /// Globals only. |
| 870 | 903 | alias_si: Symbol.Index, |
| 904 | /// For weak externals that have an alias that is also an undef |
| 905 | /// external, this is the name of the alias global that should |
| 906 | /// be generated if this symbol is not resolved. |
| 907 | /// Globals only. |
| 908 | alias_name: String, |
| 871 | 909 | /// The symbol size, or 0 if unknown |
| 872 | 910 | size: u32, |
| 873 | 911 | }; |
| ... | ... | @@ -897,10 +935,6 @@ pub const Symbol = struct { |
| 897 | 935 | }; |
| 898 | 936 | } |
| 899 | 937 | |
| 900 | | pub fn weakAlias(sym: *const Symbol) Symbol.Index { |
| 901 | | return if (sym.flags.value_tag == .alias_si) sym.value.alias_si else .null; |
| 902 | | } |
| 903 | | |
| 904 | 938 | pub fn size(sym: *const Symbol) u32 { |
| 905 | 939 | return if (sym.flags.value_tag == .size) sym.value.size else 0; |
| 906 | 940 | } |
| ... | ... | @@ -1465,11 +1499,14 @@ fn create( |
| 1465 | 1499 | .input_archive_symbols = .empty, |
| 1466 | 1500 | .input_archive_symbol_indices = .empty, |
| 1467 | 1501 | .pending_input = null, |
| 1502 | .pending_default_libs = .empty, |
| 1503 | .alternate_names = .empty, |
| 1468 | 1504 | .input_objects = .empty, |
| 1469 | 1505 | .input_symbols = .empty, |
| 1470 | 1506 | .input_sections = .empty, |
| 1471 | 1507 | .input_section_pending_index = 0, |
| 1472 | 1508 | .inputs_complete = false, |
| 1509 | .exports_complete = false, |
| 1473 | 1510 | .strings = .empty, |
| 1474 | 1511 | .string_bytes = .empty, |
| 1475 | 1512 | .section_table = .empty, |
| ... | ... | @@ -1478,6 +1515,8 @@ fn create( |
| 1478 | 1515 | .symbols = .empty, |
| 1479 | 1516 | .globals = .empty, |
| 1480 | 1517 | .global_pending_index = 0, |
| 1518 | .late_globals = .empty, |
| 1519 | .late_globals_pending_index = 0, |
| 1481 | 1520 | .navs = .empty, |
| 1482 | 1521 | .uavs = .empty, |
| 1483 | 1522 | .lazy = .initFill(.{ |
| ... | ... | @@ -1491,6 +1530,7 @@ fn create( |
| 1491 | 1530 | .symbol_prog_node = .none, |
| 1492 | 1531 | .member_prog_node = .none, |
| 1493 | 1532 | .input_prog_node = .none, |
| 1533 | .subsystem = options.subsystem, |
| 1494 | 1534 | .dump_snapshot = options.enable_link_snapshots, |
| 1495 | 1535 | }; |
| 1496 | 1536 | errdefer coff.deinit(); |
| ... | ... | @@ -1533,6 +1573,9 @@ pub fn deinit(coff: *Coff) void { |
| 1533 | 1573 | coff.input_archive_members.deinit(gpa); |
| 1534 | 1574 | coff.input_archive_symbols.deinit(gpa); |
| 1535 | 1575 | coff.input_archive_symbol_indices.deinit(gpa); |
| 1576 | for (coff.pending_default_libs.items) |l| gpa.free(l.path); |
| 1577 | coff.pending_default_libs.deinit(gpa); |
| 1578 | coff.alternate_names.deinit(gpa); |
| 1536 | 1579 | coff.input_objects.deinit(gpa); |
| 1537 | 1580 | coff.input_symbols.deinit(gpa); |
| 1538 | 1581 | coff.input_sections.deinit(gpa); |
| ... | ... | @@ -1543,6 +1586,7 @@ pub fn deinit(coff: *Coff) void { |
| 1543 | 1586 | coff.object_section_table.deinit(gpa); |
| 1544 | 1587 | coff.symbols.deinit(gpa); |
| 1545 | 1588 | coff.globals.deinit(gpa); |
| 1589 | coff.late_globals.deinit(gpa); |
| 1546 | 1590 | coff.navs.deinit(gpa); |
| 1547 | 1591 | coff.uavs.deinit(gpa); |
| 1548 | 1592 | for (&coff.lazy.values) |*lazy| lazy.map.deinit(gpa); |
| ... | ... | @@ -1579,8 +1623,12 @@ fn isObj(coff: *const Coff) bool { |
| 1579 | 1623 | return coff.base.comp.config.output_mode == .Obj; |
| 1580 | 1624 | } |
| 1581 | 1625 | |
| 1582 | | fn zcuSectionParent(coff: *Coff) MappedFile.Node.Index { |
| 1583 | | assert(coff.base.comp.zcu != null); |
| 1626 | fn hasCoffHeader(coff: *const Coff) bool { |
| 1627 | return coff.base.comp.zcu != null or !coff.isArchive(); |
| 1628 | } |
| 1629 | |
| 1630 | fn sectionParent(coff: *Coff) MappedFile.Node.Index { |
| 1631 | assert(coff.hasCoffHeader()); |
| 1584 | 1632 | return if (coff.isArchive()) Node.known.zcu_member else Node.known.file; |
| 1585 | 1633 | } |
| 1586 | 1634 | |
| ... | ... | @@ -1611,7 +1659,7 @@ fn initHeaders( |
| 1611 | 1659 | 0; |
| 1612 | 1660 | |
| 1613 | 1661 | var expected_nodes_len: usize = Node.known_count; |
| 1614 | | if (comp.zcu != null) { |
| 1662 | if (coff.hasCoffHeader()) { |
| 1615 | 1663 | // Sections |
| 1616 | 1664 | expected_nodes_len += 3; |
| 1617 | 1665 | |
| ... | ... | @@ -1663,7 +1711,7 @@ fn initHeaders( |
| 1663 | 1711 | @memcpy(signature_slice, archive_signature); |
| 1664 | 1712 | } |
| 1665 | 1713 | |
| 1666 | | const opt_zcu_coff_parent_ni = if (is_archive) parent: { |
| 1714 | const opt_coff_parent_ni = if (is_archive) parent: { |
| 1667 | 1715 | const initial_member_count = Member.Index.known_count + @intFromBool(comp.zcu != null); |
| 1668 | 1716 | try coff.members.ensureTotalCapacity(gpa, initial_member_count); |
| 1669 | 1717 | |
| ... | ... | @@ -1709,10 +1757,10 @@ fn initHeaders( |
| 1709 | 1757 | if (placeholder_ni == Node.known.zcu_member) break; |
| 1710 | 1758 | } |
| 1711 | 1759 | |
| 1712 | | break :parent if (comp.zcu != null) Node.known.header else null; |
| 1760 | break :parent Node.known.header; |
| 1713 | 1761 | }; |
| 1714 | 1762 | |
| 1715 | | const zcu_coff_parent_ni = opt_zcu_coff_parent_ni orelse { |
| 1763 | const coff_parent_ni = opt_coff_parent_ni orelse { |
| 1716 | 1764 | // If we're not generating any code, no more known nodes are used |
| 1717 | 1765 | while (coff.nodes.len < Node.known_count) { |
| 1718 | 1766 | _ = try coff.mf.addNodeAfter(gpa, Node.known.header, .{}); |
| ... | ... | @@ -1723,7 +1771,7 @@ fn initHeaders( |
| 1723 | 1771 | }; |
| 1724 | 1772 | |
| 1725 | 1773 | const coff_header_ni = Node.known.coff_header; |
| 1726 | | assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1774 | assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ |
| 1727 | 1775 | .size = @sizeOf(std.coff.Header), |
| 1728 | 1776 | .alignment = .@"4", |
| 1729 | 1777 | .fixed = true, |
| ... | ... | @@ -1751,7 +1799,7 @@ fn initHeaders( |
| 1751 | 1799 | } |
| 1752 | 1800 | |
| 1753 | 1801 | const optional_header_ni = Node.known.optional_header; |
| 1754 | | assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1802 | assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ |
| 1755 | 1803 | .size = optional_header_size, |
| 1756 | 1804 | .alignment = .@"4", |
| 1757 | 1805 | .fixed = true, |
| ... | ... | @@ -1863,7 +1911,7 @@ fn initHeaders( |
| 1863 | 1911 | } |
| 1864 | 1912 | |
| 1865 | 1913 | const data_directories_ni = Node.known.data_directories; |
| 1866 | | assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1914 | assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ |
| 1867 | 1915 | .size = data_directories_size, |
| 1868 | 1916 | .alignment = .@"4", |
| 1869 | 1917 | .fixed = true, |
| ... | ... | @@ -1879,7 +1927,7 @@ fn initHeaders( |
| 1879 | 1927 | } |
| 1880 | 1928 | |
| 1881 | 1929 | const section_table_ni = Node.known.section_table; |
| 1882 | | assert(section_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1930 | assert(section_table_ni == try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ |
| 1883 | 1931 | .alignment = .@"4", |
| 1884 | 1932 | .fixed = true, |
| 1885 | 1933 | })); |
| ... | ... | @@ -1889,14 +1937,14 @@ fn initHeaders( |
| 1889 | 1937 | |
| 1890 | 1938 | if (!is_image) { |
| 1891 | 1939 | // TODO: These two nodes could be inside one movable node? |
| 1892 | | coff.symbol_table.ni = try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1940 | coff.symbol_table.ni = try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ |
| 1893 | 1941 | .alignment = .@"2", |
| 1894 | 1942 | .fixed = true, |
| 1895 | 1943 | .moved = true, |
| 1896 | 1944 | }); |
| 1897 | 1945 | coff.nodes.appendAssumeCapacity(.symbol_table); |
| 1898 | 1946 | |
| 1899 | | coff.symbol_table.strings_ni = try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1947 | coff.symbol_table.strings_ni = try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ |
| 1900 | 1948 | .size = @sizeOf(u32), |
| 1901 | 1949 | .fixed = true, |
| 1902 | 1950 | .resized = true, |
| ... | ... | @@ -2030,16 +2078,19 @@ pub fn initBuiltins(coff: *Coff) !void { |
| 2030 | 2078 | const comp = coff.base.comp; |
| 2031 | 2079 | const gpa = comp.gpa; |
| 2032 | 2080 | const target = &comp.root_mod.resolved_target.result; |
| 2081 | if (coff.isImage()) { |
| 2082 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2083 | try coff.globals.ensureUnusedCapacity(gpa, 1); |
| 2084 | |
| 2085 | const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data }); |
| 2086 | const sym = si.get(coff); |
| 2087 | sym.ni = Node.known.header; |
| 2088 | } |
| 2089 | |
| 2033 | 2090 | if (coff.isImage() and target.isMinGW() and comp.config.link_libc) { |
| 2034 | | try coff.symbols.ensureUnusedCapacity(gpa, 5); |
| 2091 | try coff.symbols.ensureUnusedCapacity(gpa, 6); |
| 2035 | 2092 | try coff.globals.ensureUnusedCapacity(gpa, 2); |
| 2036 | | try coff.nodes.ensureUnusedCapacity(gpa, 3); |
| 2037 | | |
| 2038 | | { |
| 2039 | | const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data }); |
| 2040 | | const sym = si.get(coff); |
| 2041 | | sym.ni = Node.known.header; |
| 2042 | | } |
| 2093 | try coff.nodes.ensureUnusedCapacity(gpa, 6); |
| 2043 | 2094 | |
| 2044 | 2095 | const lists: []const struct { global: []const u8, start: String, end: String } = &.{ |
| 2045 | 2096 | .{ .global = "__CTOR_LIST__", .start = .@".ctors", .end = .@".ctors$ZZZ" }, |
| ... | ... | @@ -2083,7 +2134,10 @@ pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void { |
| 2083 | 2134 | prog_node.increaseEstimatedTotalItems(3); |
| 2084 | 2135 | coff.const_prog_node = prog_node.start("Constants", coff.pending_uavs.count()); |
| 2085 | 2136 | coff.synth_prog_node = prog_node.start("Synthetics", count: { |
| 2086 | | var count = coff.globals.count() - coff.global_pending_index; |
| 2137 | var count = |
| 2138 | coff.globals.count() - coff.global_pending_index + |
| 2139 | coff.late_globals.items.len - coff.late_globals_pending_index; |
| 2140 | |
| 2087 | 2141 | for (&coff.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; |
| 2088 | 2142 | break :count count; |
| 2089 | 2143 | }); |
| ... | ... | @@ -2246,7 +2300,7 @@ fn targetStore(coff: *const Coff, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).poi |
| 2246 | 2300 | } |
| 2247 | 2301 | |
| 2248 | 2302 | pub fn headerPtr(coff: *Coff) *std.coff.Header { |
| 2249 | | assert(coff.base.comp.zcu != null); |
| 2303 | assert(coff.hasCoffHeader()); |
| 2250 | 2304 | return @ptrCast(@alignCast(Node.known.coff_header.slice(&coff.mf))); |
| 2251 | 2305 | } |
| 2252 | 2306 | |
| ... | ... | @@ -2405,6 +2459,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { |
| 2405 | 2459 | .value_tag = .size, |
| 2406 | 2460 | .type = .unknown, |
| 2407 | 2461 | .dll_storage_class = .default, |
| 2462 | .weak_external_strat = undefined, |
| 2408 | 2463 | }, |
| 2409 | 2464 | .loc_relocs = .none, |
| 2410 | 2465 | .target_relocs = .none, |
| ... | ... | @@ -2509,7 +2564,6 @@ fn getOrPutGlobalSymbol( |
| 2509 | 2564 | if (!sym_gop.found_existing) { |
| 2510 | 2565 | const si = coff.addSymbolAssumeCapacity(); |
| 2511 | 2566 | const sym = si.get(coff); |
| 2512 | | sym.setValue(.{ .alias_si = .null }); |
| 2513 | 2567 | sym.gmi = .wrap(@intCast(sym_gop.index)); |
| 2514 | 2568 | sym.flags.type = opts.type; |
| 2515 | 2569 | sym.flags.dll_storage_class = opts.dll_storage_class; |
| ... | ... | @@ -2982,7 +3036,7 @@ fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void { |
| 2982 | 3036 | } |
| 2983 | 3037 | |
| 2984 | 3038 | fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !Symbol.Index { |
| 2985 | | assert(coff.base.comp.zcu != null); |
| 3039 | assert(coff.hasCoffHeader()); |
| 2986 | 3040 | |
| 2987 | 3041 | const gpa = coff.base.comp.gpa; |
| 2988 | 3042 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -3000,7 +3054,7 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S |
| 3000 | 3054 | @sizeOf(std.coff.SectionHeader) * section_table_len, |
| 3001 | 3055 | ); |
| 3002 | 3056 | |
| 3003 | | const ni = try coff.mf.addLastChildNode(gpa, coff.zcuSectionParent(), .{ |
| 3057 | const ni = try coff.mf.addLastChildNode(gpa, coff.sectionParent(), .{ |
| 3004 | 3058 | .alignment = coff.mf.flags.block_size, |
| 3005 | 3059 | .moved = true, |
| 3006 | 3060 | .bubbles_moved = false, |
| ... | ... | @@ -3185,7 +3239,7 @@ fn objectSectionMapIndex( |
| 3185 | 3239 | |
| 3186 | 3240 | const object_section_gop = try coff.object_section_table.getOrPut(gpa, name); |
| 3187 | 3241 | const osmi: Node.ObjectSectionMapIndex = @enumFromInt(object_section_gop.index); |
| 3188 | | const sym = if (!object_section_gop.found_existing) sn: { |
| 3242 | const sym = if (!object_section_gop.found_existing) sym: { |
| 3189 | 3243 | try coff.ensureUnusedStringCapacity(name_slice.len); |
| 3190 | 3244 | const parent_name = coff.getOrPutStringAssumeCapacity(coff.objectSectionParentName(name_slice)); |
| 3191 | 3245 | const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, effective_attributes)).symbol(coff); |
| ... | ... | @@ -3222,7 +3276,7 @@ fn objectSectionMapIndex( |
| 3222 | 3276 | assert(sym.loc_relocs == .none); |
| 3223 | 3277 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 3224 | 3278 | coff.nodes.appendAssumeCapacity(.{ .object_section = osmi }); |
| 3225 | | break :sn sym; |
| 3279 | break :sym sym; |
| 3226 | 3280 | } else object_section_gop.value_ptr.get(coff); |
| 3227 | 3281 | |
| 3228 | 3282 | const parent_ni = sym.ni.parent(&coff.mf); |
| ... | ... | @@ -3334,7 +3388,7 @@ pub fn addReloc( |
| 3334 | 3388 | const new_size = new_num_relocations * std.coff.Relocation.sizeOf(); |
| 3335 | 3389 | if (section.relocation_table_ni == .none) { |
| 3336 | 3390 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 3337 | | section.relocation_table_ni = try coff.mf.addLastChildNode(gpa, coff.zcuSectionParent(), .{ |
| 3391 | section.relocation_table_ni = try coff.mf.addLastChildNode(gpa, coff.sectionParent(), .{ |
| 3338 | 3392 | .size = new_size, |
| 3339 | 3393 | .alignment = .@"2", |
| 3340 | 3394 | .moved = true, |
| ... | ... | @@ -3637,13 +3691,6 @@ fn loadObject( |
| 3637 | 3691 | section_i, |
| 3638 | 3692 | section_name_slice, |
| 3639 | 3693 | }); |
| 3640 | | |
| 3641 | | if (section.header.flags.LNK_REMOVE or |
| 3642 | | section.header.flags.MEM_DISCARDABLE) |
| 3643 | | { |
| 3644 | | // TODO: Convert .debug$* sections into PDB |
| 3645 | | continue; |
| 3646 | | } |
| 3647 | 3694 | } |
| 3648 | 3695 | |
| 3649 | 3696 | break :sections sections; |
| ... | ... | @@ -3684,14 +3731,16 @@ fn loadObject( |
| 3684 | 3731 | section: u32, |
| 3685 | 3732 | // Offset within the section |
| 3686 | 3733 | static: u32, |
| 3687 | | // If section is defined, the symbol size. Otherwise offset within the section. |
| 3734 | // If section is undefined, the symbol size. Otherwise offset within the section. |
| 3688 | 3735 | external: u32, |
| 3689 | | // The index of the target symbol of this alias |
| 3736 | // The index of the target symbol of this weak external |
| 3690 | 3737 | weak_external: u32, |
| 3738 | // Trails .weak_external |
| 3739 | weak_external_aux: WeakExternalStrat, |
| 3691 | 3740 | }, |
| 3692 | 3741 | section_number: Symbol.SectionNumber, |
| 3693 | 3742 | si: Symbol.Index, |
| 3694 | | // The index of the weak_external that targest this symbol |
| 3743 | // If a weak external targets this symbol, the index of the weak external |
| 3695 | 3744 | weak_external_psi: PendingSymbolIndex, |
| 3696 | 3745 | }; |
| 3697 | 3746 | |
| ... | ... | @@ -3741,11 +3790,12 @@ fn loadObject( |
| 3741 | 3790 | |
| 3742 | 3791 | const psi: PendingSymbolIndex = .wrap(@intCast(pending_symbols.count())); |
| 3743 | 3792 | const section_number: Symbol.SectionNumber = @enumFromInt(@intFromEnum(symbol.section_number)); |
| 3744 | | const opt_value: ?@FieldType(PendingSymbol, "value") = pending_symbol: switch (symbol.storage_class) { |
| 3793 | |
| 3794 | const values: []const @FieldType(PendingSymbol, "value") = pending_symbols: switch (symbol.storage_class) { |
| 3745 | 3795 | .STATIC, .LABEL => |storage_class| switch (section_number) { |
| 3746 | 3796 | // TODO: Do we need to do anything with @feat.00? |
| 3747 | 3797 | // https://llvm.org/doxygen/namespacellvm_1_1COFF.html#aeffa16735e18df727a173beaf748c392 |
| 3748 | | .UNDEFINED, .DEBUG, .ABSOLUTE => null, |
| 3798 | .UNDEFINED, .DEBUG, .ABSOLUTE => &.{}, |
| 3749 | 3799 | else => |sn| { |
| 3750 | 3800 | const section = &sections[sn.toIndex()]; |
| 3751 | 3801 | |
| ... | ... | @@ -3803,10 +3853,10 @@ fn loadObject( |
| 3803 | 3853 | section.psi = psi; |
| 3804 | 3854 | } |
| 3805 | 3855 | |
| 3806 | | break :pending_symbol if (is_section) |
| 3856 | break :pending_symbols &.{if (is_section) |
| 3807 | 3857 | .{ .section = section.header.size_of_raw_data } |
| 3808 | 3858 | else |
| 3809 | | .{ .static = symbol.value }; |
| 3859 | .{ .static = symbol.value }}; |
| 3810 | 3860 | }, |
| 3811 | 3861 | }, |
| 3812 | 3862 | .WEAK_EXTERNAL => switch (symbol.section_number) { |
| ... | ... | @@ -3830,16 +3880,12 @@ fn loadObject( |
| 3830 | 3880 | .{ weak_external.tag_index, symbol_i }, |
| 3831 | 3881 | ); |
| 3832 | 3882 | |
| 3833 | | break :pending_symbol switch (weak_external.flag) { |
| 3834 | | .SEARCH_NOLIBRARY, |
| 3835 | | .SEARCH_LIBRARY, |
| 3836 | | => return diags.failParse( |
| 3837 | | path, |
| 3838 | | "TODO handle weak external characteristic 0x{x} for symbol 0x{x}", |
| 3839 | | .{ weak_external.flag, symbol_i }, |
| 3840 | | ), |
| 3841 | | .SEARCH_ALIAS => .{ .weak_external = weak_external.tag_index }, |
| 3842 | | else => return diags.failParse( |
| 3883 | break :pending_symbols switch (weak_external.flag) { |
| 3884 | else => |flag| &.{ |
| 3885 | .{ .weak_external = weak_external.tag_index }, |
| 3886 | .{ .weak_external_aux = WeakExternalStrat.fromFlag(flag) }, |
| 3887 | }, |
| 3888 | _ => return diags.failParse( |
| 3843 | 3889 | path, |
| 3844 | 3890 | "encountered unknown weak external characteristic 0x{x} for symbol 0x{x}", |
| 3845 | 3891 | .{ weak_external.flag, symbol_i }, |
| ... | ... | @@ -3853,7 +3899,7 @@ fn loadObject( |
| 3853 | 3899 | ), |
| 3854 | 3900 | }, |
| 3855 | 3901 | .EXTERNAL => switch (section_number) { |
| 3856 | | .UNDEFINED => .{ .external = symbol.value }, |
| 3902 | .UNDEFINED => &.{.{ .external = symbol.value }}, |
| 3857 | 3903 | .ABSOLUTE => return diags.failParse( |
| 3858 | 3904 | path, |
| 3859 | 3905 | "TODO unhandled external absolute symbol 0x{x}: '{s}'", |
| ... | ... | @@ -3864,7 +3910,7 @@ fn loadObject( |
| 3864 | 3910 | "unexpected external symbol 0x{x} in DEBUG section: '{s}'", |
| 3865 | 3911 | .{ symbol_i, name }, |
| 3866 | 3912 | ), |
| 3867 | | else => .{ .external = symbol.value }, |
| 3913 | else => &.{.{ .external = symbol.value }}, |
| 3868 | 3914 | }, |
| 3869 | 3915 | .FILE => { |
| 3870 | 3916 | if (!std.mem.eql(u8, name, ".file")) |
| ... | ... | @@ -3878,7 +3924,7 @@ fn loadObject( |
| 3878 | 3924 | @memcpy(std.mem.asBytes(&file)[0..symbol_size], aux_symbols[0..symbol_size]); |
| 3879 | 3925 | |
| 3880 | 3926 | input.source_name = (try coff.getOrPutString(file.getFileName())).toOptional(); |
| 3881 | | break :pending_symbol null; |
| 3927 | break :pending_symbols &.{}; |
| 3882 | 3928 | }, |
| 3883 | 3929 | else => |storage_class| return diags.failParse( |
| 3884 | 3930 | path, |
| ... | ... | @@ -3887,10 +3933,13 @@ fn loadObject( |
| 3887 | 3933 | ), |
| 3888 | 3934 | }; |
| 3889 | 3935 | |
| 3890 | | if (opt_value) |value| { |
| 3936 | for (values, 0..) |value, i| { |
| 3891 | 3937 | switch (value) { |
| 3892 | 3938 | .section => {}, |
| 3893 | | .static, .external, .weak_external => { |
| 3939 | .static, |
| 3940 | .external, |
| 3941 | .weak_external, |
| 3942 | => { |
| 3894 | 3943 | num_global_symbols += 1; |
| 3895 | 3944 | if (section_number.hasIndex()) { |
| 3896 | 3945 | const section = &sections[section_number.toIndex()]; |
| ... | ... | @@ -3899,10 +3948,11 @@ fn loadObject( |
| 3899 | 3948 | section.comdat_psi = psi; |
| 3900 | 3949 | } |
| 3901 | 3950 | }, |
| 3951 | .weak_external_aux => {}, |
| 3902 | 3952 | } |
| 3903 | 3953 | |
| 3904 | 3954 | const symbol_name = coff.getOrPutStringAssumeCapacity(name); |
| 3905 | | pending_symbols.putAssumeCapacity(symbol_i, .{ |
| 3955 | pending_symbols.putAssumeCapacity(symbol_i + @as(u32, @intCast(i)), .{ |
| 3906 | 3956 | .name = symbol_name, |
| 3907 | 3957 | .value = value, |
| 3908 | 3958 | .section_number = section_number, |
| ... | ... | @@ -3917,6 +3967,7 @@ fn loadObject( |
| 3917 | 3967 | if (section.header.flags.LNK_INFO) { |
| 3918 | 3968 | if (std.mem.eql(u8, &section.header.name, ".drectve")) { |
| 3919 | 3969 | try fr.seekTo(fl.offset + section.header.pointer_to_raw_data); |
| 3970 | // TODO: Don't really want an additional buffer here, but want to limit to size_of_raw_data |
| 3920 | 3971 | var buf: [128]u8 = undefined; |
| 3921 | 3972 | var section_r = r.limited(.limited(section.header.size_of_raw_data), &buf); |
| 3922 | 3973 | while (section_r.interface.takeDelimiter(' ') catch |err| switch (err) { |
| ... | ... | @@ -3926,9 +3977,60 @@ fn loadObject( |
| 3926 | 3977 | // Microsoft tools emit 3 space characters into this section even with /Zl |
| 3927 | 3978 | if (arg.len == 0) continue; |
| 3928 | 3979 | |
| 3929 | | if (std.mem.cutPrefix(u8, arg, "-exclude-symbols:")) |rest| { |
| 3930 | | // TODO: When implementing mingw auto-exports, use this to not export this symbol |
| 3931 | | _ = rest; |
| 3980 | if (std.ascii.startsWithIgnoreCase(arg, "-exclude-symbols:")) { |
| 3981 | // TODO: When implementing mingw auto-exports (if at all?), use this to not export this symbol |
| 3982 | } else if (std.ascii.startsWithIgnoreCase(arg, "/include:")) { |
| 3983 | _ = try coff.globalSymbol(.{ .name = arg["/include:".len..] }); |
| 3984 | } else if (std.ascii.startsWithIgnoreCase(arg, "/alternatename:")) { |
| 3985 | var split = std.mem.splitScalar(u8, arg["/alternatename:".len..], '='); |
| 3986 | const orig = split.first(); |
| 3987 | const alt = split.next() orelse |
| 3988 | return diags.failParse(path, "malformed .drectve argument: '{s}'", .{arg}); |
| 3989 | |
| 3990 | try coff.ensureManyUnusedStringCapacity(2, orig.len + alt.len + 2); |
| 3991 | const orig_str = coff.getOrPutStringAssumeCapacity(orig); |
| 3992 | const alt_str = coff.getOrPutStringAssumeCapacity(alt); |
| 3993 | const gop = try coff.alternate_names.getOrPut(gpa, orig_str); |
| 3994 | if (!gop.found_existing) { |
| 3995 | log.debug("alternateName({s}={s})", .{ orig, alt }); |
| 3996 | gop.value_ptr.* = alt_str; |
| 3997 | } else if (gop.value_ptr.* != alt_str) |
| 3998 | return diags.failParse( |
| 3999 | path, |
| 4000 | "conflicting /alternatename .drectve arguments: first seen as {s}={s}, now seen as {s}={s}", |
| 4001 | .{ orig, gop.value_ptr.toSlice(coff), orig, alt }, |
| 4002 | ); |
| 4003 | } else if (std.ascii.startsWithIgnoreCase(arg, "/guardsym:")) { |
| 4004 | // TODO: https://learn.microsoft.com/en-us/windows/win32/secbp/pe-metadata |
| 4005 | } else if (std.ascii.startsWithIgnoreCase(arg, "/merge:")) { |
| 4006 | var split = std.mem.splitScalar(u8, arg["/merge:".len..], '='); |
| 4007 | const from = split.first(); |
| 4008 | const to = split.next() orelse |
| 4009 | return diags.failParse(path, "malformed .drectve argument: '{s}'", .{arg}); |
| 4010 | |
| 4011 | // TODO: Override the parent selection for generated sections below |
| 4012 | _ = from; |
| 4013 | _ = to; |
| 4014 | } else if (std.ascii.startsWithIgnoreCase(arg, "/disallowlib:")) { |
| 4015 | const lib_name = arg["/disallowlib:".len..]; |
| 4016 | // TODO: Track these and issue error in prelink if any match |
| 4017 | _ = lib_name; |
| 4018 | } else if (std.ascii.startsWithIgnoreCase(arg, "/defaultlib:")) { |
| 4019 | const lib_path = arg["/defaultlib:".len..]; |
| 4020 | const trim = std.mem.trim(u8, lib_path, "\""); |
| 4021 | if (lib_path.len == trim.len or lib_path.len - 2 == trim.len) { |
| 4022 | if (!comp.config.link_libc or comp.libc_installation == null) |
| 4023 | return diags.failParse(path, "encountered /DEFAULTLIB .drectve argument when libc was not available: {s}", .{arg}); |
| 4024 | |
| 4025 | (try coff.pending_default_libs.addOne(gpa)).* = .{ |
| 4026 | .path = try gpa.dupe(u8, lib_path), |
| 4027 | .ioi = ioi, |
| 4028 | }; |
| 4029 | } else return diags.failParse( |
| 4030 | path, |
| 4031 | "malformed /DEFAULTLIB .drectve argument: `{s}`", |
| 4032 | .{arg}, |
| 4033 | ); |
| 3932 | 4034 | } else return diags.failParse(path, "unsupported argument in .drectve section: `{s}`", .{arg}); |
| 3933 | 4035 | } |
| 3934 | 4036 | } |
| ... | ... | @@ -3940,6 +4042,7 @@ fn loadObject( |
| 3940 | 4042 | if (section.header.flags.LNK_REMOVE or |
| 3941 | 4043 | section.header.flags.MEM_DISCARDABLE) |
| 3942 | 4044 | { |
| 4045 | // TODO: Convert .debug$* sections into PDB |
| 3943 | 4046 | section.comdat_result = .skip; |
| 3944 | 4047 | continue; |
| 3945 | 4048 | } |
| ... | ... | @@ -3973,6 +4076,7 @@ fn loadObject( |
| 3973 | 4076 | const symbol = &pending_symbols.values()[psi]; |
| 3974 | 4077 | const si = existing: switch (symbol.value) { |
| 3975 | 4078 | .weak_external => unreachable, |
| 4079 | .weak_external_aux => unreachable, |
| 3976 | 4080 | .static => break :comdat .include, |
| 3977 | 4081 | .section => { |
| 3978 | 4082 | assert(section.comdat_psi == .none); |
| ... | ... | @@ -4145,14 +4249,21 @@ fn loadObject( |
| 4145 | 4249 | } |
| 4146 | 4250 | |
| 4147 | 4251 | for (pending_symbols.values(), pending_symbols.keys(), 0..) |*symbol, index, i| { |
| 4148 | | defer log.debug("addInputSymbol({s}, 0x{x}, {t}=0x{x}, {d}) = {d}@{d}", .{ |
| 4252 | switch (symbol.value) { |
| 4253 | .weak_external_aux => continue, |
| 4254 | else => {}, |
| 4255 | } |
| 4256 | |
| 4257 | defer log.debug("addInputSymbol({s}, 0x{x}, {t}=0x{x}, {d}) = n{d} {d}@{d}", .{ |
| 4149 | 4258 | symbol.name.toSlice(coff), |
| 4150 | 4259 | index, |
| 4151 | 4260 | symbol.value, |
| 4152 | | symbol.section_number, |
| 4153 | 4261 | switch (symbol.value) { |
| 4262 | .weak_external_aux => unreachable, |
| 4154 | 4263 | inline else => |v| v, |
| 4155 | 4264 | }, |
| 4265 | symbol.section_number, |
| 4266 | symbol.si.get(coff).ni, |
| 4156 | 4267 | symbol.si, |
| 4157 | 4268 | symbol.si.get(coff).section_number, |
| 4158 | 4269 | }); |
| ... | ... | @@ -4161,34 +4272,50 @@ fn loadObject( |
| 4161 | 4272 | .UNDEFINED => switch (symbol.value) { |
| 4162 | 4273 | .section, |
| 4163 | 4274 | .static, |
| 4275 | .weak_external_aux, |
| 4164 | 4276 | => unreachable, |
| 4165 | | .external, |
| 4166 | | .weak_external, |
| 4167 | | => |value, tag| { |
| 4277 | .external => { |
| 4278 | if (symbol.weak_external_psi.unwrap()) |weak_external_i| { |
| 4279 | // If the alias itself is an undef external, we need to wait until flushing the weak |
| 4280 | // external global before creating a global for the alias, as another input |
| 4281 | // could still provide the weak external. |
| 4282 | const weak_sym = pending_symbols.values()[weak_external_i].si.get(coff); |
| 4283 | weak_sym.setValue(.{ .alias_name = symbol.name }); |
| 4284 | weak_sym.flags.weak_external_strat = pending_symbols.values()[weak_external_i + 1].value.weak_external_aux; |
| 4285 | } |
| 4286 | |
| 4287 | // Deferred until referenced by a reloc in this object. |
| 4288 | // vcruntime.lib defines symbols like this (ie. memcpy_$fo$) that are not referenced |
| 4289 | continue; |
| 4290 | }, |
| 4291 | .weak_external => |alias_index| { |
| 4168 | 4292 | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); |
| 4169 | 4293 | symbol.si = global_gop.value_ptr.*; |
| 4170 | 4294 | if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { |
| 4171 | 4295 | const sym = symbol.si.get(coff); |
| 4172 | | if (tag == .external) { |
| 4173 | | sym.setValue(.{ .size = @max(sym.size(), value) }); |
| 4296 | const alias = pending_symbols.getPtr(alias_index) orelse |
| 4297 | return diags.failParse( |
| 4298 | path, |
| 4299 | "weak external 0x{x} {s}{f} targets unknown symbol index 0x{x}", |
| 4300 | .{ |
| 4301 | index, |
| 4302 | symbol.name.toSlice(coff), |
| 4303 | fmtMemberNameString(member_name), |
| 4304 | alias_index, |
| 4305 | }, |
| 4306 | ); |
| 4307 | |
| 4308 | if (alias.si == .null and alias_index > index) { |
| 4309 | // Resolve this once we see alias |
| 4310 | alias.weak_external_psi = .wrap(@intCast(i)); |
| 4174 | 4311 | } else { |
| 4175 | | const alias = pending_symbols.getPtr(value) orelse |
| 4176 | | return diags.failParse( |
| 4177 | | path, |
| 4178 | | "weak external 0x{x} {s}{f} targets unknown symbol index 0x{x}", |
| 4179 | | .{ |
| 4180 | | index, |
| 4181 | | symbol.name.toSlice(coff), |
| 4182 | | fmtMemberNameString(member_name), |
| 4183 | | value, |
| 4184 | | }, |
| 4185 | | ); |
| 4186 | | |
| 4187 | | if (alias.si == .null) { |
| 4188 | | alias.weak_external_psi = .wrap(@intCast(i)); |
| 4189 | | } else { |
| 4190 | | sym.setValue(.{ .alias_si = alias.si }); |
| 4191 | | } |
| 4312 | sym.setValue(if (alias.si == .null) .{ |
| 4313 | // See .external branch above |
| 4314 | .alias_name = alias.name, |
| 4315 | } else .{ |
| 4316 | .alias_si = alias.si, |
| 4317 | }); |
| 4318 | sym.flags.weak_external_strat = pending_symbols.values()[i + 1].value.weak_external_aux; |
| 4192 | 4319 | } |
| 4193 | 4320 | } |
| 4194 | 4321 | |
| ... | ... | @@ -4217,13 +4344,17 @@ fn loadObject( |
| 4217 | 4344 | if (global_gop.found_existing and sym.ni != .none) |
| 4218 | 4345 | return coff.failMultipleDefinitions(path, member_name, symbol.name, index, global_gop.value_ptr.*, .none); |
| 4219 | 4346 | }, |
| 4220 | | .weak_external => unreachable, |
| 4347 | .weak_external, |
| 4348 | .weak_external_aux, |
| 4349 | => unreachable, |
| 4221 | 4350 | } |
| 4222 | 4351 | } |
| 4223 | 4352 | |
| 4224 | 4353 | if (symbol.weak_external_psi.unwrap()) |weak_external_i| { |
| 4225 | 4354 | assert(symbol.si != .null); |
| 4226 | | pending_symbols.values()[weak_external_i].si.get(coff).setValue(.{ .alias_si = symbol.si }); |
| 4355 | const weak_sym = pending_symbols.values()[weak_external_i].si.get(coff); |
| 4356 | weak_sym.setValue(.{ .alias_si = symbol.si }); |
| 4357 | weak_sym.flags.weak_external_strat = pending_symbols.values()[weak_external_i + 1].value.weak_external_aux; |
| 4227 | 4358 | } |
| 4228 | 4359 | |
| 4229 | 4360 | if (section.si != symbol.si) { |
| ... | ... | @@ -4237,7 +4368,9 @@ fn loadObject( |
| 4237 | 4368 | .UNDEFINED, .ABSOLUTE, .DEBUG => unreachable, |
| 4238 | 4369 | else => .{ .node_offset = v }, |
| 4239 | 4370 | }, |
| 4240 | | .weak_external => unreachable, |
| 4371 | .weak_external, |
| 4372 | .weak_external_aux, |
| 4373 | => unreachable, |
| 4241 | 4374 | }); |
| 4242 | 4375 | sym.section_number = section.si.get(coff).section_number; |
| 4243 | 4376 | } |
| ... | ... | @@ -4260,14 +4393,34 @@ fn loadObject( |
| 4260 | 4393 | if (target_endian != native_endian) |
| 4261 | 4394 | std.mem.byteSwapAllFields(std.coff.Relocation, &reloc); |
| 4262 | 4395 | |
| 4263 | | // TODO: This error should show member name for lib |
| 4264 | | const symbol = pending_symbols.get(reloc.symbol_table_index) orelse |
| 4396 | const symbol = pending_symbols.getPtr(reloc.symbol_table_index) orelse |
| 4265 | 4397 | return diags.failParse( |
| 4266 | 4398 | path, |
| 4267 | | "relocation 0x{x} in section '{s}'{f} targets invalid symbol index 0x{x}", |
| 4268 | | .{ reloc_i, section.name.toSlice(coff), fmtMemberNameString(member_name), reloc.symbol_table_index }, |
| 4399 | "relocation 0x{x} in section '{s}' of {f}{f} targets invalid symbol index 0x{x}", |
| 4400 | .{ |
| 4401 | reloc_i, |
| 4402 | section.name.toSlice(coff), |
| 4403 | path.fmtEscapeString(), |
| 4404 | fmtMemberNameString(member_name), |
| 4405 | reloc.symbol_table_index, |
| 4406 | }, |
| 4269 | 4407 | ); |
| 4270 | 4408 | |
| 4409 | if (symbol.si == .null) { |
| 4410 | assert(symbol.section_number == .UNDEFINED); |
| 4411 | switch (symbol.value) { |
| 4412 | .external => |size| { |
| 4413 | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); |
| 4414 | symbol.si = global_gop.value_ptr.*; |
| 4415 | if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { |
| 4416 | const sym = symbol.si.get(coff); |
| 4417 | sym.setValue(.{ .size = @max(sym.size(), size) }); |
| 4418 | } |
| 4419 | }, |
| 4420 | else => unreachable, |
| 4421 | } |
| 4422 | } |
| 4423 | |
| 4271 | 4424 | assert(symbol.si != .null); |
| 4272 | 4425 | try coff.addReloc( |
| 4273 | 4426 | section.si, |
| ... | ... | @@ -4299,7 +4452,7 @@ fn loadObject( |
| 4299 | 4452 | var prev_sn: Symbol.SectionNumber = .DEBUG; |
| 4300 | 4453 | var include_section = false; |
| 4301 | 4454 | for (pending_symbols.values()) |symbol| { |
| 4302 | | // The symbol may have not been included, or it's an undefined external |
| 4455 | // The symbol may have not been included, or it's an undefined external / aux |
| 4303 | 4456 | if (symbol.si == .null or symbol.si.get(coff).ni == .none) continue; |
| 4304 | 4457 | |
| 4305 | 4458 | if (prev_sn != symbol.section_number) { |
| ... | ... | @@ -4731,6 +4884,71 @@ pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { |
| 4731 | 4884 | _ = prog_node; |
| 4732 | 4885 | log.debug("prelink()", .{}); |
| 4733 | 4886 | |
| 4887 | if (coff.pending_default_libs.items.len > 0) { |
| 4888 | // Libs provided by /DEFAULTLIB arguments in objects are searched after all other inputs |
| 4889 | const base = coff.base; |
| 4890 | const comp = base.comp; |
| 4891 | const gpa = comp.gpa; |
| 4892 | const arena = comp.arena; |
| 4893 | const target = &comp.root_mod.resolved_target.result; |
| 4894 | |
| 4895 | defer { |
| 4896 | for (coff.pending_default_libs.items) |l| gpa.free(l.path); |
| 4897 | coff.pending_default_libs.clearAndFree(gpa); |
| 4898 | } |
| 4899 | |
| 4900 | assert(comp.config.link_libc); |
| 4901 | const libc_installation = comp.libc_installation.?; |
| 4902 | const all_paths: [3]?[]const u8 = .{ |
| 4903 | libc_installation.crt_dir, |
| 4904 | libc_installation.msvc_lib_dir, |
| 4905 | libc_installation.kernel32_lib_dir, |
| 4906 | }; |
| 4907 | const search_paths = all_paths[0..if (target.abi == .msvc or target.abi == .itanium) 3 else 1]; |
| 4908 | lib: for (coff.pending_default_libs.items) |lib| { |
| 4909 | if (!std.mem.eql(u8, std.fs.path.extension(lib.path), ".lib")) |
| 4910 | return comp.link_diags.failParse( |
| 4911 | lib.ioi.path(coff), |
| 4912 | "/DEFAULTLIB library '{s}' had unexpected extension", |
| 4913 | .{lib.path}, |
| 4914 | ); |
| 4915 | |
| 4916 | log.debug("loadDefaultLib({s}, {f})", .{ lib.path, lib.ioi.path(coff) }); |
| 4917 | for (search_paths) |opt_path| if (opt_path) |search_path| { |
| 4918 | const lib_path = try Path.initCwd(search_path).join(arena, lib.path); |
| 4919 | const archive = link.openObject(comp.io, lib_path, false, false) catch |err| switch (err) { |
| 4920 | error.FileNotFound => { |
| 4921 | arena.free(lib_path.sub_path); |
| 4922 | continue; |
| 4923 | }, |
| 4924 | else => |e| return comp.link_diags.failParse( |
| 4925 | lib.ioi.path(coff), |
| 4926 | "error opening /DEFAULTLIB library '{s}': {t}", |
| 4927 | .{ lib.path, e }, |
| 4928 | ), |
| 4929 | }; |
| 4930 | errdefer archive.file.close(comp.io); |
| 4931 | |
| 4932 | coff.loadInput(.{ .archive = archive }) catch |err| switch (err) { |
| 4933 | error.LinkFailure => return, |
| 4934 | else => |e| return comp.link_diags.failParse( |
| 4935 | lib.ioi.path(coff), |
| 4936 | "error loading /DEFAULTLIB library '{s}': {t}", |
| 4937 | .{ lib.path, e }, |
| 4938 | ), |
| 4939 | }; |
| 4940 | |
| 4941 | break :lib; |
| 4942 | }; |
| 4943 | |
| 4944 | return comp.link_diags.failParse( |
| 4945 | lib.ioi.path(coff), |
| 4946 | "/DEFAULTLIB library '{s}' was not found", |
| 4947 | .{lib.path}, |
| 4948 | ); |
| 4949 | } |
| 4950 | } |
| 4951 | |
| 4734 | 4952 | coff.inputs_complete = true; |
| 4735 | 4953 | } |
| 4736 | 4954 | |
| ... | ... | @@ -5143,6 +5361,11 @@ pub fn flush( |
| 5143 | 5361 | ) !void { |
| 5144 | 5362 | _ = arena; |
| 5145 | 5363 | _ = prog_node; |
| 5364 | |
| 5365 | // TODO: When https://github.com/ziglang/zig/issues/23617 is in, |
| 5366 | // this should be set after updateExports instead |
| 5367 | coff.exports_complete = true; |
| 5368 | |
| 5146 | 5369 | while (try coff.idle(tid)) {} |
| 5147 | 5370 | |
| 5148 | 5371 | if (coff.isImage()) |
| ... | ... | @@ -5221,6 +5444,22 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5221 | 5444 | }) coff.global_pending_index += 1; |
| 5222 | 5445 | break :task; |
| 5223 | 5446 | } |
| 5447 | if (coff.exports_complete and coff.late_globals_pending_index < coff.late_globals.items.len) { |
| 5448 | const gmi: Node.GlobalMapIndex = coff.late_globals.items[coff.late_globals_pending_index]; |
| 5449 | const sub_prog_node = coff.synth_prog_node.start( |
| 5450 | gmi.globalName(coff).name.toSlice(coff), |
| 5451 | 0, |
| 5452 | ); |
| 5453 | defer sub_prog_node.end(); |
| 5454 | if (coff.flushGlobal(gmi) catch |err| switch (err) { |
| 5455 | error.OutOfMemory => |e| return e, |
| 5456 | else => |e| return comp.link_diags.fail( |
| 5457 | "linker failed to lower constant: {t}", |
| 5458 | .{e}, |
| 5459 | ), |
| 5460 | }) coff.late_globals_pending_index += 1; |
| 5461 | break :task; |
| 5462 | } |
| 5224 | 5463 | var lazy_it = coff.lazy.iterator(); |
| 5225 | 5464 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { |
| 5226 | 5465 | const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid }; |
| ... | ... | @@ -5357,6 +5596,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5357 | 5596 | if (coff.pending_uavs.count() > 0) return true; |
| 5358 | 5597 | if (coff.pending_input != null) return true; |
| 5359 | 5598 | if (coff.inputs_complete and coff.globals.count() > coff.global_pending_index) return true; |
| 5599 | if (coff.exports_complete and coff.late_globals.items.len > coff.late_globals_pending_index) return true; |
| 5360 | 5600 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 5361 | 5601 | if (coff.symbol_table.pending.count() > 0) return true; |
| 5362 | 5602 | if (coff.input_sections.items.len > coff.input_section_pending_index) return true; |
| ... | ... | @@ -5504,10 +5744,11 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5504 | 5744 | const gn = gmi.globalName(coff); |
| 5505 | 5745 | const si = gmi.symbol(coff); |
| 5506 | 5746 | const sym = si.get(coff); |
| 5747 | const is_late = gmi.unwrap().? < coff.global_pending_index; |
| 5507 | 5748 | |
| 5508 | 5749 | log.debug( |
| 5509 | | "flushGlobal({s}, {?s}) = {d} ({d})", |
| 5510 | | .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), si, sym.ni }, |
| 5750 | "flushGlobal({s}, {?s}, {}) = {d} ({d})", |
| 5751 | .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), is_late, si, sym.ni }, |
| 5511 | 5752 | ); |
| 5512 | 5753 | |
| 5513 | 5754 | if (!coff.isImage()) { |
| ... | ... | @@ -5521,16 +5762,6 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5521 | 5762 | return true; |
| 5522 | 5763 | } |
| 5523 | 5764 | |
| 5524 | | // TODO: Only do this if actually referenced? Might have to do on-demand? |
| 5525 | | { |
| 5526 | | // Resolve unresolved .WEAK_EXTERNAL symbols to their aliases |
| 5527 | | const alias_si = sym.weakAlias(); |
| 5528 | | if (alias_si != .null) { |
| 5529 | | try coff.aliasGlobal(gmi, alias_si); |
| 5530 | | return true; |
| 5531 | | } |
| 5532 | | } |
| 5533 | | |
| 5534 | 5765 | const Import = struct { |
| 5535 | 5766 | lib_name: String, |
| 5536 | 5767 | name: String.Optional, |
| ... | ... | @@ -5555,9 +5786,41 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5555 | 5786 | break :name .{ coff.getOrPutStringAssumeCapacity(name), true }; |
| 5556 | 5787 | }; |
| 5557 | 5788 | |
| 5558 | | // TODO: Try to search for __imp_ even when !is_imp, we want to not use thunks if we can |
| 5789 | const opt_alt_search_name = coff.alternate_names.get(search_name); |
| 5790 | const search_libs = if (is_late) switch (sym.flags.value_tag) { |
| 5791 | .alias_si, .alias_name => switch (sym.flags.weak_external_strat) { |
| 5792 | .no_library => false, |
| 5793 | .library, |
| 5794 | .alias, |
| 5795 | => true, |
| 5796 | .anti_dependency => return comp.link_diags.fail( |
| 5797 | // TODO: Figure out what the purpose of this is |
| 5798 | "TODO support anti_dependency weak external: {s}", |
| 5799 | .{gn.name.toSlice(coff)}, |
| 5800 | ), |
| 5801 | }, |
| 5802 | else => true, |
| 5803 | } else search_libs: { |
| 5804 | if (switch (sym.flags.value_tag) { |
| 5805 | .alias_si, .alias_name => true, |
| 5806 | else => opt_alt_search_name != null, |
| 5807 | }) { |
| 5808 | // We need to wait until all exports are known before resolving these |
| 5809 | coff.synth_prog_node.increaseEstimatedTotalItems(1); |
| 5810 | (try coff.late_globals.addOne(gpa)).* = gmi; |
| 5811 | return true; |
| 5812 | } |
| 5813 | |
| 5814 | break :search_libs true; |
| 5815 | }; |
| 5816 | |
| 5817 | const opt_indices_lists: []const ?InputArchive.SearchList = if (search_libs) &.{ |
| 5818 | coff.input_archive_symbol_indices.get(search_name), |
| 5819 | if (opt_alt_search_name) |alt| coff.input_archive_symbol_indices.get(alt) else null, |
| 5820 | } else &.{}; |
| 5559 | 5821 | |
| 5560 | | if (coff.input_archive_symbol_indices.get(search_name)) |indices_list| { |
| 5822 | for (opt_indices_lists) |opt_indices_list| { |
| 5823 | const indices_list = opt_indices_list orelse continue; |
| 5561 | 5824 | var iter: InputArchive.Member.Symbol.Index = indices_list.first; |
| 5562 | 5825 | while (true) { |
| 5563 | 5826 | const archive_sym = &coff.input_archive_symbols.items[@intFromEnum(iter)]; |
| ... | ... | @@ -5631,6 +5894,32 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5631 | 5894 | } |
| 5632 | 5895 | } |
| 5633 | 5896 | |
| 5897 | switch (sym.flags.value_tag) { |
| 5898 | .alias_si => { |
| 5899 | assert(is_late); |
| 5900 | try coff.aliasGlobal(gmi, sym.value.alias_si); |
| 5901 | return true; |
| 5902 | }, |
| 5903 | .alias_name => { |
| 5904 | assert(is_late); |
| 5905 | // Convert an unresolved weak external that itself refers to an undef external |
| 5906 | // into a (possibly new) global, so it can be resolved separately. |
| 5907 | const alias_gop = try coff.getOrPutGlobalSymbol(.{ .name = sym.value.alias_name.toSlice(coff) }); |
| 5908 | try coff.aliasGlobal(gmi, alias_gop.value_ptr.*); |
| 5909 | return true; |
| 5910 | }, |
| 5911 | else => {}, |
| 5912 | } |
| 5913 | |
| 5914 | // If there was an object that had the alternate name, we've attempted to load it |
| 5915 | if (opt_alt_search_name) |alt_search_name| { |
| 5916 | assert(is_late); |
| 5917 | if (coff.globals.get(.{ .name = alt_search_name, .lib_name = .none })) |alias_si| { |
| 5918 | try coff.aliasGlobal(gmi, alias_si); |
| 5919 | return true; |
| 5920 | } |
| 5921 | } |
| 5922 | |
| 5634 | 5923 | // Allow importing symbols with no implib entry, if a lib_name was specified. |
| 5635 | 5924 | // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification, |
| 5636 | 5925 | // which are not in the implib. |