| ... | ... | @@ -334,7 +334,10 @@ pub const Member = struct { |
| 334 | 334 | kind: Kind, |
| 335 | 335 | header_ni: MappedFile.Node.Index, |
| 336 | 336 | content_ni: MappedFile.Node.Index, |
| 337 | | first_linker_indices: std.AutoArrayHashMapUnmanaged(Symbol.Index, FirstLinkerIndex), |
| 337 | first_linker_indices: std.AutoArrayHashMapUnmanaged(struct { |
| 338 | mi: Member.Index, |
| 339 | name: String, |
| 340 | }, FirstLinkerIndex), |
| 338 | 341 | |
| 339 | 342 | pub const Kind = enum { |
| 340 | 343 | first_linker, |
| ... | ... | @@ -670,7 +673,7 @@ pub const Symbol = struct { |
| 670 | 673 | section_number: SectionNumber, |
| 671 | 674 | sti: SymbolTable.Index, |
| 672 | 675 | gmi: Node.GlobalMapIndex, |
| 673 | | unused1: u16 = 0, |
| 676 | unused0: u16 = 0, |
| 674 | 677 | |
| 675 | 678 | pub const SectionNumber = enum(i16) { |
| 676 | 679 | UNDEFINED = 0, |
| ... | ... | @@ -1319,8 +1322,11 @@ fn initHeaders( |
| 1319 | 1322 | break :parent zcu_member.content_ni; |
| 1320 | 1323 | } |
| 1321 | 1324 | |
| 1322 | | assert(Node.known.zcu_member_header == try coff.mf.addLastChildNode(gpa, Node.known.file, .{})); |
| 1323 | | assert(Node.known.zcu_member == try coff.mf.addLastChildNode(gpa, Node.known.file, .{})); |
| 1325 | // These placeholder nodes are placed before the first member - if there are |
| 1326 | // no other members then the last linker member (longnames) needs to expand |
| 1327 | // to fill the padding at the end of the file. |
| 1328 | assert(Node.known.zcu_member_header == try coff.mf.addNodeAfter(gpa, Node.known.header, .{})); |
| 1329 | assert(Node.known.zcu_member == try coff.mf.addNodeAfter(gpa, Node.known.header, .{})); |
| 1324 | 1330 | coff.nodes.appendAssumeCapacity(.placeholder); |
| 1325 | 1331 | coff.nodes.appendAssumeCapacity(.placeholder); |
| 1326 | 1332 | |
| ... | ... | @@ -1339,7 +1345,7 @@ fn initHeaders( |
| 1339 | 1345 | const zcu_coff_parent_ni = opt_zcu_coff_parent_ni orelse { |
| 1340 | 1346 | // If we're not generating any code, no more known nodes are used |
| 1341 | 1347 | while (coff.nodes.len < Node.known_count) { |
| 1342 | | _ = try coff.mf.addLastChildNode(gpa, Node.known.file, .{}); |
| 1348 | _ = try coff.mf.addNodeAfter(gpa, Node.known.header, .{}); |
| 1343 | 1349 | coff.nodes.appendAssumeCapacity(.placeholder); |
| 1344 | 1350 | } |
| 1345 | 1351 | |
| ... | ... | @@ -1976,11 +1982,20 @@ fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional { |
| 1976 | 1982 | return (try coff.getOrPutString(string orelse return .none)).toOptional(); |
| 1977 | 1983 | } |
| 1978 | 1984 | |
| 1985 | /// `len` does not include null terminators |
| 1979 | 1986 | fn ensureUnusedStringCapacity(coff: *Coff, len: usize) !void { |
| 1980 | 1987 | const gpa = coff.base.comp.gpa; |
| 1981 | 1988 | try coff.strings.ensureUnusedCapacityContext(gpa, 1, .{ .bytes = &coff.string_bytes }); |
| 1982 | 1989 | try coff.string_bytes.ensureUnusedCapacity(gpa, len + 1); |
| 1983 | 1990 | } |
| 1991 | |
| 1992 | /// `total_len` includes null terminators |
| 1993 | fn ensureManyUnusedStringCapacity(coff: *Coff, num_strings: u32, total_len: usize) !void { |
| 1994 | const gpa = coff.base.comp.gpa; |
| 1995 | try coff.strings.ensureUnusedCapacityContext(gpa, num_strings, .{ .bytes = &coff.string_bytes }); |
| 1996 | try coff.string_bytes.ensureUnusedCapacity(gpa, total_len + num_strings); |
| 1997 | } |
| 1998 | |
| 1984 | 1999 | fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 1985 | 2000 | const gop = coff.strings.getOrPutAssumeCapacityAdapted( |
| 1986 | 2001 | string, |
| ... | ... | @@ -1995,10 +2010,15 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 1995 | 2010 | return @enumFromInt(gop.key_ptr.*); |
| 1996 | 2011 | } |
| 1997 | 2012 | |
| 1998 | | pub fn globalSymbol(coff: *Coff, opts: struct { |
| 2013 | const GlobalOptions = struct { |
| 1999 | 2014 | name: []const u8, |
| 2000 | 2015 | lib_name: ?[]const u8 = null, |
| 2001 | | }) !Symbol.Index { |
| 2016 | }; |
| 2017 | |
| 2018 | fn getOrPutGlobalSymbol( |
| 2019 | coff: *Coff, |
| 2020 | opts: GlobalOptions, |
| 2021 | ) !std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index).GetOrPutResult { |
| 2002 | 2022 | const gpa = coff.base.comp.gpa; |
| 2003 | 2023 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2004 | 2024 | const sym_gop = try coff.globals.getOrPut(gpa, .{ |
| ... | ... | @@ -2012,7 +2032,11 @@ pub fn globalSymbol(coff: *Coff, opts: struct { |
| 2012 | 2032 | coff.synth_prog_node.increaseEstimatedTotalItems(1); |
| 2013 | 2033 | } |
| 2014 | 2034 | |
| 2015 | | return sym_gop.value_ptr.*; |
| 2035 | return sym_gop; |
| 2036 | } |
| 2037 | |
| 2038 | pub fn globalSymbol(coff: *Coff, opts: GlobalOptions) !Symbol.Index { |
| 2039 | return (try coff.getOrPutGlobalSymbol(opts)).value_ptr.*; |
| 2016 | 2040 | } |
| 2017 | 2041 | |
| 2018 | 2042 | pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void { |
| ... | ... | @@ -2225,22 +2249,14 @@ fn appendMemberSymbolString( |
| 2225 | 2249 | name_slice[name.len] = 0; |
| 2226 | 2250 | } |
| 2227 | 2251 | |
| 2228 | | fn ensureMemberSymbol( |
| 2229 | | coff: *Coff, |
| 2230 | | name: String, |
| 2231 | | mi: Member.Index, |
| 2232 | | si: Symbol.Index, |
| 2233 | | ) !void { |
| 2252 | fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void { |
| 2234 | 2253 | const gpa = coff.base.comp.gpa; |
| 2235 | 2254 | const member = mi.get(coff); |
| 2236 | 2255 | assert(member.kind == .coff); |
| 2237 | 2256 | |
| 2238 | | const gop = try member.first_linker_indices.getOrPut(gpa, si); |
| 2257 | const gop = try member.first_linker_indices.getOrPut(gpa, .{ .mi = mi, .name = name }); |
| 2239 | 2258 | if (gop.found_existing) return; |
| 2240 | 2259 | |
| 2241 | | // TODO: Detect duplicate names (ie. a name used by a symbol in another member, |
| 2242 | | // not the zcu since those already go through globals) |
| 2243 | | |
| 2244 | 2260 | const mfli: Member.FirstLinkerIndex = blk: { |
| 2245 | 2261 | const num_symbols_ptr = coff.firstLinkerMemberNumSymbolsPtr(); |
| 2246 | 2262 | const num_symbols = std.mem.toNative(u32, num_symbols_ptr.*, .big); |
| ... | ... | @@ -2276,14 +2292,15 @@ fn ensureMemberSymbol( |
| 2276 | 2292 | const new_header_size = old_header_size + @sizeOf(u16); |
| 2277 | 2293 | try Node.known.second_linker_member.resize(&coff.mf, gpa, new_header_size + new_string_table_size); |
| 2278 | 2294 | |
| 2279 | | const needs_sort = if (coff.lib_string_table.items.len > 0) |
| 2295 | const old_needs_sort = coff.pending_members.get(Member.Index.second) != null; |
| 2296 | const needs_sort = old_needs_sort or (if (coff.lib_string_table.items.len > 0) |
| 2280 | 2297 | std.mem.lessThan( |
| 2281 | 2298 | u8, |
| 2282 | 2299 | name_slice, |
| 2283 | 2300 | coff.lib_string_table.items[coff.lib_string_table.items.len - 1].toSlice(coff), |
| 2284 | 2301 | ) |
| 2285 | 2302 | else |
| 2286 | | false; |
| 2303 | false); |
| 2287 | 2304 | |
| 2288 | 2305 | try coff.lib_string_table.append(gpa, name); |
| 2289 | 2306 | |
| ... | ... | @@ -2291,13 +2308,13 @@ fn ensureMemberSymbol( |
| 2291 | 2308 | const num_symbols_ptr: *u32 = @ptrCast(@alignCast(slice[@sizeOf(u32) + num_members * @sizeOf(u32) ..])); |
| 2292 | 2309 | coff.targetStore(num_symbols_ptr, @intFromEnum(mfli) + 1); |
| 2293 | 2310 | |
| 2294 | | if (needs_sort) { |
| 2295 | | // The entire string table is rebuilt in flushMember after sorting |
| 2296 | | coff.pending_members.putAssumeCapacity(Member.Index.second, {}); |
| 2297 | | } else { |
| 2311 | if (!needs_sort) { |
| 2298 | 2312 | @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); |
| 2299 | 2313 | @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice[0..name_slice.len]); |
| 2300 | 2314 | slice[new_header_size + coff.lib_string_len + name_slice.len] = 0; |
| 2315 | } else if (!old_needs_sort) { |
| 2316 | // The entire string table is rebuilt in flushMember after sorting |
| 2317 | coff.pending_members.putAssumeCapacity(Member.Index.second, {}); |
| 2301 | 2318 | } |
| 2302 | 2319 | |
| 2303 | 2320 | // Indices in this table are 1-based |
| ... | ... | @@ -2708,16 +2725,216 @@ pub fn addReloc( |
| 2708 | 2725 | target.target_relocs = ri; |
| 2709 | 2726 | } |
| 2710 | 2727 | |
| 2711 | | pub fn loadInput(coff: *Coff, input: link.Input) void { |
| 2712 | | _ = coff; |
| 2728 | pub fn loadInput(coff: *Coff, input: link.Input) (Io.File.Reader.SizeError || |
| 2729 | Io.File.Reader.Error || MappedFile.Error || error{ WriteFailed, EndOfStream, BadMagic, LinkFailure })!void { |
| 2730 | const io = coff.base.comp.io; |
| 2731 | var buf: [4096]u8 = undefined; |
| 2713 | 2732 | switch (input) { |
| 2714 | | .dso_exact => unreachable, |
| 2715 | | inline else => |i, tag| { |
| 2716 | | log.debug("loadInput({s}: {f})", .{ @tagName(tag), i.path.fmtEscapeString() }); |
| 2733 | .object => |object| { |
| 2734 | var fr = object.file.reader(io, &buf); |
| 2735 | coff.loadObject(object.path, null, &fr, .{ |
| 2736 | .offset = fr.logicalPos(), |
| 2737 | .size = try fr.getSize(), |
| 2738 | }) catch |err| switch (err) { |
| 2739 | error.ReadFailed => return fr.err.?, |
| 2740 | else => |e| return e, |
| 2741 | }; |
| 2717 | 2742 | }, |
| 2743 | .archive => |archive| { |
| 2744 | var fr = archive.file.reader(io, &buf); |
| 2745 | coff.loadArchive(archive.path, &fr) catch |err| switch (err) { |
| 2746 | error.ReadFailed => return fr.err.?, |
| 2747 | else => |e| return e, |
| 2748 | }; |
| 2749 | }, |
| 2750 | .res => |res| { |
| 2751 | var fr = res.file.reader(io, &buf); |
| 2752 | coff.loadRes(res.path, &fr) catch |err| switch (err) { |
| 2753 | error.ReadFailed => return fr.err.?, |
| 2754 | else => |e| return e, |
| 2755 | }; |
| 2756 | }, |
| 2757 | .dso => |dso| { |
| 2758 | var fr = dso.file.reader(io, &buf); |
| 2759 | coff.loadDll(dso.path, &fr) catch |err| switch (err) { |
| 2760 | error.ReadFailed => return fr.err.?, |
| 2761 | else => |e| return e, |
| 2762 | }; |
| 2763 | }, |
| 2764 | .dso_exact => unreachable, |
| 2718 | 2765 | } |
| 2719 | 2766 | } |
| 2720 | 2767 | |
| 2768 | fn fmtArchiveNameString(archiveName: ?[]const u8) std.fmt.Alt(?[]const u8, archiveNameStringEscape) { |
| 2769 | return .{ .data = archiveName }; |
| 2770 | } |
| 2771 | fn archiveNameStringEscape(archiveName: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 2772 | try w.print("({f})", .{std.zig.fmtString(archiveName orelse return)}); |
| 2773 | } |
| 2774 | |
| 2775 | fn loadObject( |
| 2776 | coff: *Coff, |
| 2777 | path: std.Build.Cache.Path, |
| 2778 | archive_name: ?[]const u8, |
| 2779 | fr: *Io.File.Reader, |
| 2780 | fl: MappedFile.Node.FileLocation, |
| 2781 | ) !void { |
| 2782 | const comp = coff.base.comp; |
| 2783 | const gpa = comp.gpa; |
| 2784 | const diags = &comp.link_diags; |
| 2785 | const r = &fr.interface; |
| 2786 | const target = &comp.root_mod.resolved_target.result; |
| 2787 | const target_endian = coff.targetEndian(); |
| 2788 | const is_archive = coff.isArchive(); |
| 2789 | |
| 2790 | log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtArchiveNameString(archive_name) }); |
| 2791 | const header = try r.peekStruct(std.coff.Header, coff.targetEndian()); |
| 2792 | if (header.machine != target.toCoffMachine()) |
| 2793 | return diags.failParse(path, "machine mismatch: expected {t}, found {t}", .{ |
| 2794 | target.toCoffMachine(), |
| 2795 | header.machine, |
| 2796 | }); |
| 2797 | if (header.number_of_sections == 0) return; |
| 2798 | if (@sizeOf(std.coff.Header) + header.number_of_sections * @sizeOf(std.coff.SectionHeader) > fl.size) |
| 2799 | return diags.failParse(path, "invalid section table", .{}); |
| 2800 | const unexpected_flags: []const std.meta.FieldEnum(std.coff.Header.Flags) = &.{ |
| 2801 | .RELOCS_STRIPPED, |
| 2802 | .EXECUTABLE_IMAGE, |
| 2803 | .AGGRESSIVE_WS_TRIM, |
| 2804 | .RESERVED, |
| 2805 | .BYTES_REVERSED_LO, |
| 2806 | .DLL, |
| 2807 | .BYTES_REVERSED_HI, |
| 2808 | }; |
| 2809 | inline for (unexpected_flags) |flag| |
| 2810 | if (@field(header.flags, @tagName(flag))) |
| 2811 | return diags.failParse(path, "unexpected flag set: {t}", .{flag}); |
| 2812 | |
| 2813 | if (header.size_of_optional_header != 0) |
| 2814 | return diags.failParse(path, "unexpected optional header", .{}); |
| 2815 | |
| 2816 | const symbol_table_len = header.number_of_symbols * std.coff.Symbol.sizeOf(); |
| 2817 | const symbol_table_end = header.pointer_to_symbol_table + symbol_table_len; |
| 2818 | // String table length (which includes the length field) immediately trails the symbol table |
| 2819 | if (symbol_table_end + @sizeOf(u32) > fl.size) |
| 2820 | return diags.failParse(path, "bad symbol table location", .{}); |
| 2821 | |
| 2822 | try fr.seekTo(fl.offset + symbol_table_end); |
| 2823 | const string_table_len = try r.peekInt(u32, target_endian); |
| 2824 | if (string_table_len < @sizeOf(u32) or |
| 2825 | symbol_table_end + string_table_len > fl.size) |
| 2826 | return diags.failParse(path, "bad string table", .{}); |
| 2827 | |
| 2828 | const string_table = string_table: { |
| 2829 | const string_table = try gpa.alloc(u8, string_table_len); |
| 2830 | errdefer gpa.free(string_table); |
| 2831 | try r.readSliceAll(string_table); |
| 2832 | break :string_table string_table; |
| 2833 | }; |
| 2834 | defer gpa.free(string_table); |
| 2835 | |
| 2836 | try coff.ensureManyUnusedStringCapacity( |
| 2837 | header.number_of_symbols, |
| 2838 | string_table_len - @sizeOf(u32), |
| 2839 | ); |
| 2840 | |
| 2841 | const mi = if (is_archive) mi: { |
| 2842 | try coff.nodes.ensureUnusedCapacity(gpa, 2); |
| 2843 | try coff.members.ensureUnusedCapacity(gpa, 1); |
| 2844 | |
| 2845 | const mi = try coff.addMemberAssumeCapacity(.coff, fl.size); |
| 2846 | const member = mi.get(coff); |
| 2847 | try member.initHeader(coff, path.sub_path, header.time_date_stamp); |
| 2848 | |
| 2849 | { |
| 2850 | var nw: MappedFile.Node.Writer = undefined; |
| 2851 | member.content_ni.writer(&coff.mf, gpa, &nw); |
| 2852 | defer nw.deinit(); |
| 2853 | |
| 2854 | try fr.seekTo(fl.offset); |
| 2855 | try r.streamExact(&nw.interface, fl.size); |
| 2856 | } |
| 2857 | |
| 2858 | break :mi mi; |
| 2859 | } else undefined; |
| 2860 | |
| 2861 | try fr.seekTo(fl.offset + header.pointer_to_symbol_table); |
| 2862 | const symbol_size = std.coff.Symbol.sizeOf(); |
| 2863 | |
| 2864 | var symbol_ix: u32 = 0; |
| 2865 | while (symbol_ix < header.number_of_symbols) { |
| 2866 | const symbol: *align(2) std.coff.Symbol = @ptrCast(@alignCast(try r.take(symbol_size))); |
| 2867 | defer { |
| 2868 | r.toss(symbol.number_of_aux_symbols * symbol_size); |
| 2869 | symbol_ix += symbol.number_of_aux_symbols + 1; |
| 2870 | } |
| 2871 | |
| 2872 | switch (symbol.section_number) { |
| 2873 | .UNDEFINED, .ABSOLUTE, .DEBUG => continue, |
| 2874 | else => switch (symbol.storage_class) { |
| 2875 | .STATIC => if (symbol.value == 0) continue, |
| 2876 | .EXTERNAL => {}, |
| 2877 | else => continue, |
| 2878 | }, |
| 2879 | } |
| 2880 | |
| 2881 | const name = std.mem.sliceTo(if (std.mem.eql(u8, symbol.name[0..4], "\x00\x00\x00\x00")) name: { |
| 2882 | const index = std.mem.readInt(u32, symbol.name[4..], target_endian); |
| 2883 | if (index >= string_table.len) |
| 2884 | return diags.failParse(path, "bad string offset for symbol {d}", .{symbol_ix}); |
| 2885 | break :name string_table[index..]; |
| 2886 | } else &symbol.name, 0); |
| 2887 | |
| 2888 | if (is_archive) { |
| 2889 | try coff.ensureMemberSymbol(mi, coff.getOrPutStringAssumeCapacity(name)); |
| 2890 | continue; |
| 2891 | } |
| 2892 | |
| 2893 | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = name }); |
| 2894 | if (global_gop.found_existing) |
| 2895 | return diags.failParse(path, "multiple definitions of '{s}'", .{name}); |
| 2896 | } |
| 2897 | } |
| 2898 | |
| 2899 | fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2900 | const comp = coff.base.comp; |
| 2901 | const gpa = comp.gpa; |
| 2902 | const diags = &comp.link_diags; |
| 2903 | const r = &fr.interface; |
| 2904 | |
| 2905 | log.debug("loadArchive({f})", .{path.fmtEscapeString()}); |
| 2906 | |
| 2907 | _ = gpa; |
| 2908 | _ = diags; |
| 2909 | _ = r; |
| 2910 | } |
| 2911 | |
| 2912 | fn loadRes(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2913 | const comp = coff.base.comp; |
| 2914 | const gpa = comp.gpa; |
| 2915 | const diags = &comp.link_diags; |
| 2916 | const r = &fr.interface; |
| 2917 | |
| 2918 | log.debug("loadRes({f})", .{path.fmtEscapeString()}); |
| 2919 | |
| 2920 | _ = gpa; |
| 2921 | _ = diags; |
| 2922 | _ = r; |
| 2923 | } |
| 2924 | |
| 2925 | fn loadDll(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2926 | const comp = coff.base.comp; |
| 2927 | const gpa = comp.gpa; |
| 2928 | const diags = &comp.link_diags; |
| 2929 | const r = &fr.interface; |
| 2930 | |
| 2931 | log.debug("loadDll({f})", .{path.fmtEscapeString()}); |
| 2932 | |
| 2933 | _ = gpa; |
| 2934 | _ = diags; |
| 2935 | _ = r; |
| 2936 | } |
| 2937 | |
| 2721 | 2938 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { |
| 2722 | 2939 | _ = coff; |
| 2723 | 2940 | _ = prog_node; |
| ... | ... | @@ -3074,7 +3291,6 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 3074 | 3291 | break :task; |
| 3075 | 3292 | } |
| 3076 | 3293 | if (coff.global_pending_index < coff.globals.count()) { |
| 3077 | | const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid }; |
| 3078 | 3294 | const gmi: Node.GlobalMapIndex = .wrap(coff.global_pending_index); |
| 3079 | 3295 | coff.global_pending_index += 1; |
| 3080 | 3296 | const sub_prog_node = coff.synth_prog_node.start( |
| ... | ... | @@ -3082,7 +3298,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 3082 | 3298 | 0, |
| 3083 | 3299 | ); |
| 3084 | 3300 | defer sub_prog_node.end(); |
| 3085 | | coff.flushGlobal(pt, gmi) catch |err| switch (err) { |
| 3301 | coff.flushGlobal(gmi) catch |err| switch (err) { |
| 3086 | 3302 | else => |e| return e, |
| 3087 | 3303 | error.MappedFileIo => return comp.link_diags.fail( |
| 3088 | 3304 | "linker failed to lower constant: {t}", |
| ... | ... | @@ -3301,22 +3517,19 @@ fn flushUav( |
| 3301 | 3517 | si.applyLocationRelocs(coff); |
| 3302 | 3518 | } |
| 3303 | 3519 | |
| 3304 | | fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { |
| 3305 | | const zcu = pt.zcu; |
| 3306 | | const comp = zcu.comp; |
| 3307 | | const gpa = zcu.gpa; |
| 3520 | fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !void { |
| 3521 | const comp = coff.base.comp; |
| 3522 | const gpa = comp.gpa; |
| 3308 | 3523 | const gn = gmi.globalName(coff); |
| 3309 | 3524 | log.debug("flushGlobal({s}, {?s}) = {d}", .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), gmi.symbol(coff) }); |
| 3310 | 3525 | |
| 3311 | 3526 | if (!coff.isImage()) { |
| 3312 | 3527 | const si = gmi.symbol(coff); |
| 3313 | 3528 | try coff.pendingSymbolTableEntry(si); |
| 3314 | | |
| 3315 | 3529 | if (coff.isArchive() and si.get(coff).ni != .none) |
| 3316 | 3530 | try coff.ensureMemberSymbol( |
| 3317 | | gn.name, |
| 3318 | 3531 | coff.getNode(Node.known.zcu_member).archive_member, |
| 3319 | | si, |
| 3532 | gn.name, |
| 3320 | 3533 | ); |
| 3321 | 3534 | |
| 3322 | 3535 | return; |
| ... | ... | @@ -3715,6 +3928,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 3715 | 3928 | .file => { |
| 3716 | 3929 | if (coff.isArchive() and coff.members.items.len > 0) { |
| 3717 | 3930 | const last_member = coff.members.items[coff.members.items.len - 1]; |
| 3931 | // See .archive_member branch for reasoning |
| 3718 | 3932 | assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni); |
| 3719 | 3933 | try coff.flushResized(last_member.content_ni); |
| 3720 | 3934 | } |
| ... | ... | @@ -3867,6 +4081,8 @@ fn flushMember(coff: *Coff, mi: Member.Index) !void { |
| 3867 | 4081 | } |
| 3868 | 4082 | }; |
| 3869 | 4083 | |
| 4084 | // TODO: Does this sort need to also sort by linker input order (if names equal)? |
| 4085 | |
| 3870 | 4086 | std.sort.pdqContext(0, coff.lib_string_table.items.len, Context{ |
| 3871 | 4087 | .coff = coff, |
| 3872 | 4088 | .indices = coff.secondLinkerMemberIndicesSlice(), |