| ... | @@ -334,7 +334,10 @@ pub const Member = struct { | ... | @@ -334,7 +334,10 @@ pub const Member = struct { |
| 334 | kind: Kind, | 334 | kind: Kind, |
| 335 | header_ni: MappedFile.Node.Index, | 335 | header_ni: MappedFile.Node.Index, |
| 336 | content_ni: MappedFile.Node.Index, | 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 | pub const Kind = enum { | 342 | pub const Kind = enum { |
| 340 | first_linker, | 343 | first_linker, |
| ... | @@ -670,7 +673,7 @@ pub const Symbol = struct { | ... | @@ -670,7 +673,7 @@ pub const Symbol = struct { |
| 670 | section_number: SectionNumber, | 673 | section_number: SectionNumber, |
| 671 | sti: SymbolTable.Index, | 674 | sti: SymbolTable.Index, |
| 672 | gmi: Node.GlobalMapIndex, | 675 | gmi: Node.GlobalMapIndex, |
| 673 | unused1: u16 = 0, | 676 | unused0: u16 = 0, |
| 674 | | 677 | |
| 675 | pub const SectionNumber = enum(i16) { | 678 | pub const SectionNumber = enum(i16) { |
| 676 | UNDEFINED = 0, | 679 | UNDEFINED = 0, |
| ... | @@ -1319,8 +1322,11 @@ fn initHeaders( | ... | @@ -1319,8 +1322,11 @@ fn initHeaders( |
| 1319 | break :parent zcu_member.content_ni; | 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, .{})); | 1325 | // These placeholder nodes are placed before the first member - if there are |
| 1323 | assert(Node.known.zcu_member == try coff.mf.addLastChildNode(gpa, Node.known.file, .{})); | 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 | coff.nodes.appendAssumeCapacity(.placeholder); | 1330 | coff.nodes.appendAssumeCapacity(.placeholder); |
| 1325 | coff.nodes.appendAssumeCapacity(.placeholder); | 1331 | coff.nodes.appendAssumeCapacity(.placeholder); |
| 1326 | | 1332 | |
| ... | @@ -1339,7 +1345,7 @@ fn initHeaders( | ... | @@ -1339,7 +1345,7 @@ fn initHeaders( |
| 1339 | const zcu_coff_parent_ni = opt_zcu_coff_parent_ni orelse { | 1345 | const zcu_coff_parent_ni = opt_zcu_coff_parent_ni orelse { |
| 1340 | // If we're not generating any code, no more known nodes are used | 1346 | // If we're not generating any code, no more known nodes are used |
| 1341 | while (coff.nodes.len < Node.known_count) { | 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 | coff.nodes.appendAssumeCapacity(.placeholder); | 1349 | coff.nodes.appendAssumeCapacity(.placeholder); |
| 1344 | } | 1350 | } |
| 1345 | | 1351 | |
| ... | @@ -1976,11 +1982,20 @@ fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional { | ... | @@ -1976,11 +1982,20 @@ fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional { |
| 1976 | return (try coff.getOrPutString(string orelse return .none)).toOptional(); | 1982 | return (try coff.getOrPutString(string orelse return .none)).toOptional(); |
| 1977 | } | 1983 | } |
| 1978 | | 1984 | |
| | 1985 | /// `len` does not include null terminators |
| 1979 | fn ensureUnusedStringCapacity(coff: *Coff, len: usize) !void { | 1986 | fn ensureUnusedStringCapacity(coff: *Coff, len: usize) !void { |
| 1980 | const gpa = coff.base.comp.gpa; | 1987 | const gpa = coff.base.comp.gpa; |
| 1981 | try coff.strings.ensureUnusedCapacityContext(gpa, 1, .{ .bytes = &coff.string_bytes }); | 1988 | try coff.strings.ensureUnusedCapacityContext(gpa, 1, .{ .bytes = &coff.string_bytes }); |
| 1982 | try coff.string_bytes.ensureUnusedCapacity(gpa, len + 1); | 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 | fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { | 1999 | fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 1985 | const gop = coff.strings.getOrPutAssumeCapacityAdapted( | 2000 | const gop = coff.strings.getOrPutAssumeCapacityAdapted( |
| 1986 | string, | 2001 | string, |
| ... | @@ -1995,10 +2010,15 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { | ... | @@ -1995,10 +2010,15 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 1995 | return @enumFromInt(gop.key_ptr.*); | 2010 | return @enumFromInt(gop.key_ptr.*); |
| 1996 | } | 2011 | } |
| 1997 | | 2012 | |
| 1998 | pub fn globalSymbol(coff: *Coff, opts: struct { | 2013 | const GlobalOptions = struct { |
| 1999 | name: []const u8, | 2014 | name: []const u8, |
| 2000 | lib_name: ?[]const u8 = null, | 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 | const gpa = coff.base.comp.gpa; | 2022 | const gpa = coff.base.comp.gpa; |
| 2003 | try coff.symbols.ensureUnusedCapacity(gpa, 1); | 2023 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2004 | const sym_gop = try coff.globals.getOrPut(gpa, .{ | 2024 | const sym_gop = try coff.globals.getOrPut(gpa, .{ |
| ... | @@ -2012,7 +2032,11 @@ pub fn globalSymbol(coff: *Coff, opts: struct { | ... | @@ -2012,7 +2032,11 @@ pub fn globalSymbol(coff: *Coff, opts: struct { |
| 2012 | coff.synth_prog_node.increaseEstimatedTotalItems(1); | 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 | pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void { | 2042 | pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void { |
| ... | @@ -2225,22 +2249,14 @@ fn appendMemberSymbolString( | ... | @@ -2225,22 +2249,14 @@ fn appendMemberSymbolString( |
| 2225 | name_slice[name.len] = 0; | 2249 | name_slice[name.len] = 0; |
| 2226 | } | 2250 | } |
| 2227 | | 2251 | |
| 2228 | fn ensureMemberSymbol( | 2252 | fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void { |
| 2229 | coff: *Coff, | | |
| 2230 | name: String, | | |
| 2231 | mi: Member.Index, | | |
| 2232 | si: Symbol.Index, | | |
| 2233 | ) !void { | | |
| 2234 | const gpa = coff.base.comp.gpa; | 2253 | const gpa = coff.base.comp.gpa; |
| 2235 | const member = mi.get(coff); | 2254 | const member = mi.get(coff); |
| 2236 | assert(member.kind == .coff); | 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 | if (gop.found_existing) return; | 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 | const mfli: Member.FirstLinkerIndex = blk: { | 2260 | const mfli: Member.FirstLinkerIndex = blk: { |
| 2245 | const num_symbols_ptr = coff.firstLinkerMemberNumSymbolsPtr(); | 2261 | const num_symbols_ptr = coff.firstLinkerMemberNumSymbolsPtr(); |
| 2246 | const num_symbols = std.mem.toNative(u32, num_symbols_ptr.*, .big); | 2262 | const num_symbols = std.mem.toNative(u32, num_symbols_ptr.*, .big); |
| ... | @@ -2276,14 +2292,15 @@ fn ensureMemberSymbol( | ... | @@ -2276,14 +2292,15 @@ fn ensureMemberSymbol( |
| 2276 | const new_header_size = old_header_size + @sizeOf(u16); | 2292 | const new_header_size = old_header_size + @sizeOf(u16); |
| 2277 | try Node.known.second_linker_member.resize(&coff.mf, gpa, new_header_size + new_string_table_size); | 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 | std.mem.lessThan( | 2297 | std.mem.lessThan( |
| 2281 | u8, | 2298 | u8, |
| 2282 | name_slice, | 2299 | name_slice, |
| 2283 | coff.lib_string_table.items[coff.lib_string_table.items.len - 1].toSlice(coff), | 2300 | coff.lib_string_table.items[coff.lib_string_table.items.len - 1].toSlice(coff), |
| 2284 | ) | 2301 | ) |
| 2285 | else | 2302 | else |
| 2286 | false; | 2303 | false); |
| 2287 | | 2304 | |
| 2288 | try coff.lib_string_table.append(gpa, name); | 2305 | try coff.lib_string_table.append(gpa, name); |
| 2289 | | 2306 | |
| ... | @@ -2291,13 +2308,13 @@ fn ensureMemberSymbol( | ... | @@ -2291,13 +2308,13 @@ fn ensureMemberSymbol( |
| 2291 | const num_symbols_ptr: *u32 = @ptrCast(@alignCast(slice[@sizeOf(u32) + num_members * @sizeOf(u32) ..])); | 2308 | const num_symbols_ptr: *u32 = @ptrCast(@alignCast(slice[@sizeOf(u32) + num_members * @sizeOf(u32) ..])); |
| 2292 | coff.targetStore(num_symbols_ptr, @intFromEnum(mfli) + 1); | 2309 | coff.targetStore(num_symbols_ptr, @intFromEnum(mfli) + 1); |
| 2293 | | 2310 | |
| 2294 | if (needs_sort) { | 2311 | if (!needs_sort) { |
| 2295 | // The entire string table is rebuilt in flushMember after sorting | | |
| 2296 | coff.pending_members.putAssumeCapacity(Member.Index.second, {}); | | |
| 2297 | } else { | | |
| 2298 | @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); | 2312 | @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); |
| 2299 | @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice[0..name_slice.len]); | 2313 | @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice[0..name_slice.len]); |
| 2300 | slice[new_header_size + coff.lib_string_len + name_slice.len] = 0; | 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 | // Indices in this table are 1-based | 2320 | // Indices in this table are 1-based |
| ... | @@ -2708,16 +2725,216 @@ pub fn addReloc( | ... | @@ -2708,16 +2725,216 @@ pub fn addReloc( |
| 2708 | target.target_relocs = ri; | 2725 | target.target_relocs = ri; |
| 2709 | } | 2726 | } |
| 2710 | | 2727 | |
| 2711 | pub fn loadInput(coff: *Coff, input: link.Input) void { | 2728 | pub fn loadInput(coff: *Coff, input: link.Input) (Io.File.Reader.SizeError || |
| 2712 | _ = coff; | 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 | switch (input) { | 2732 | switch (input) { |
| 2714 | .dso_exact => unreachable, | 2733 | .object => |object| { |
| 2715 | inline else => |i, tag| { | 2734 | var fr = object.file.reader(io, &buf); |
| 2716 | log.debug("loadInput({s}: {f})", .{ @tagName(tag), i.path.fmtEscapeString() }); | 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 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { | 2938 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { |
| 2722 | _ = coff; | 2939 | _ = coff; |
| 2723 | _ = prog_node; | 2940 | _ = prog_node; |
| ... | @@ -3074,7 +3291,6 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ... | @@ -3074,7 +3291,6 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 3074 | break :task; | 3291 | break :task; |
| 3075 | } | 3292 | } |
| 3076 | if (coff.global_pending_index < coff.globals.count()) { | 3293 | if (coff.global_pending_index < coff.globals.count()) { |
| 3077 | const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid }; | | |
| 3078 | const gmi: Node.GlobalMapIndex = .wrap(coff.global_pending_index); | 3294 | const gmi: Node.GlobalMapIndex = .wrap(coff.global_pending_index); |
| 3079 | coff.global_pending_index += 1; | 3295 | coff.global_pending_index += 1; |
| 3080 | const sub_prog_node = coff.synth_prog_node.start( | 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,7 +3298,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 3082 | 0, | 3298 | 0, |
| 3083 | ); | 3299 | ); |
| 3084 | defer sub_prog_node.end(); | 3300 | defer sub_prog_node.end(); |
| 3085 | coff.flushGlobal(pt, gmi) catch |err| switch (err) { | 3301 | coff.flushGlobal(gmi) catch |err| switch (err) { |
| 3086 | else => |e| return e, | 3302 | else => |e| return e, |
| 3087 | error.MappedFileIo => return comp.link_diags.fail( | 3303 | error.MappedFileIo => return comp.link_diags.fail( |
| 3088 | "linker failed to lower constant: {t}", | 3304 | "linker failed to lower constant: {t}", |
| ... | @@ -3301,22 +3517,19 @@ fn flushUav( | ... | @@ -3301,22 +3517,19 @@ fn flushUav( |
| 3301 | si.applyLocationRelocs(coff); | 3517 | si.applyLocationRelocs(coff); |
| 3302 | } | 3518 | } |
| 3303 | | 3519 | |
| 3304 | fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { | 3520 | fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !void { |
| 3305 | const zcu = pt.zcu; | 3521 | const comp = coff.base.comp; |
| 3306 | const comp = zcu.comp; | 3522 | const gpa = comp.gpa; |
| 3307 | const gpa = zcu.gpa; | | |
| 3308 | const gn = gmi.globalName(coff); | 3523 | const gn = gmi.globalName(coff); |
| 3309 | log.debug("flushGlobal({s}, {?s}) = {d}", .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), gmi.symbol(coff) }); | 3524 | log.debug("flushGlobal({s}, {?s}) = {d}", .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), gmi.symbol(coff) }); |
| 3310 | | 3525 | |
| 3311 | if (!coff.isImage()) { | 3526 | if (!coff.isImage()) { |
| 3312 | const si = gmi.symbol(coff); | 3527 | const si = gmi.symbol(coff); |
| 3313 | try coff.pendingSymbolTableEntry(si); | 3528 | try coff.pendingSymbolTableEntry(si); |
| 3314 | | | |
| 3315 | if (coff.isArchive() and si.get(coff).ni != .none) | 3529 | if (coff.isArchive() and si.get(coff).ni != .none) |
| 3316 | try coff.ensureMemberSymbol( | 3530 | try coff.ensureMemberSymbol( |
| 3317 | gn.name, | | |
| 3318 | coff.getNode(Node.known.zcu_member).archive_member, | 3531 | coff.getNode(Node.known.zcu_member).archive_member, |
| 3319 | si, | 3532 | gn.name, |
| 3320 | ); | 3533 | ); |
| 3321 | | 3534 | |
| 3322 | return; | 3535 | return; |
| ... | @@ -3715,6 +3928,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -3715,6 +3928,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 3715 | .file => { | 3928 | .file => { |
| 3716 | if (coff.isArchive() and coff.members.items.len > 0) { | 3929 | if (coff.isArchive() and coff.members.items.len > 0) { |
| 3717 | const last_member = coff.members.items[coff.members.items.len - 1]; | 3930 | const last_member = coff.members.items[coff.members.items.len - 1]; |
| | 3931 | // See .archive_member branch for reasoning |
| 3718 | assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni); | 3932 | assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni); |
| 3719 | try coff.flushResized(last_member.content_ni); | 3933 | try coff.flushResized(last_member.content_ni); |
| 3720 | } | 3934 | } |
| ... | @@ -3867,6 +4081,8 @@ fn flushMember(coff: *Coff, mi: Member.Index) !void { | ... | @@ -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 | std.sort.pdqContext(0, coff.lib_string_table.items.len, Context{ | 4086 | std.sort.pdqContext(0, coff.lib_string_table.items.len, Context{ |
| 3871 | .coff = coff, | 4087 | .coff = coff, |
| 3872 | .indices = coff.secondLinkerMemberIndicesSlice(), | 4088 | .indices = coff.secondLinkerMemberIndicesSlice(), |