| ... | ... | @@ -278,7 +278,7 @@ pub const Node = union(enum) { |
| 278 | 278 | return coff.globals.values()[gmi.unwrap().?].si; |
| 279 | 279 | } |
| 280 | 280 | |
| 281 | | pub fn libName(gmi: GlobalMapIndex, coff: *const Coff) String.Optional { |
| 281 | pub fn libName(gmi: GlobalMapIndex, coff: *const Coff) ExternLibName { |
| 282 | 282 | return coff.globals.values()[gmi.unwrap().?].lib_name; |
| 283 | 283 | } |
| 284 | 284 | }; |
| ... | ... | @@ -647,15 +647,12 @@ pub const SymbolTable = struct { |
| 647 | 647 | }; |
| 648 | 648 | |
| 649 | 649 | pub const SymbolName = union(enum) { |
| 650 | | short: []const u8, |
| 650 | short: [8]u8, |
| 651 | 651 | long: StringIndex, |
| 652 | 652 | |
| 653 | 653 | pub fn store(name: SymbolName, coff: *const Coff, field: *[8]u8) void { |
| 654 | 654 | switch (name) { |
| 655 | | .short => |s| { |
| 656 | | @memcpy(field[0..s.len], s); |
| 657 | | @memset(field[s.len..], 0); |
| 658 | | }, |
| 655 | .short => |s| field.* = s, |
| 659 | 656 | .long => |l| { |
| 660 | 657 | @memset(field[0..4], 0); |
| 661 | 658 | std.mem.writePackedInt(u32, field[4..], 0, @backingInt(l), coff.targetEndian()); |
| ... | ... | @@ -864,7 +861,7 @@ pub const Section = struct { |
| 864 | 861 | |
| 865 | 862 | pub const Global = struct { |
| 866 | 863 | si: Symbol.Index, |
| 867 | | lib_name: String.Optional, |
| 864 | lib_name: ExternLibName, |
| 868 | 865 | }; |
| 869 | 866 | |
| 870 | 867 | pub const WeakExternalStrat = enum(u3) { |
| ... | ... | @@ -2263,6 +2260,11 @@ pub fn initBuiltins(coff: *Coff) !void { |
| 2263 | 2260 | } |
| 2264 | 2261 | |
| 2265 | 2262 | defer coff.flushSectionMerges() catch unreachable; |
| 2263 | if (coff.isImage()) { |
| 2264 | // In images, the .tls section is a read-only template |
| 2265 | try coff.section_merges.put(gpa, .@".tls", .@".rdata"); |
| 2266 | } |
| 2267 | |
| 2266 | 2268 | if (coff.isImage() and target.isMinGW() and comp.config.link_libc) { |
| 2267 | 2269 | try coff.symbols.ensureUnusedCapacity(gpa, 8); |
| 2268 | 2270 | try coff.globals.ensureUnusedCapacity(gpa, 2); |
| ... | ... | @@ -2723,29 +2725,42 @@ fn getString(coff: *Coff, string: []const u8) String.Optional { |
| 2723 | 2725 | return .none; |
| 2724 | 2726 | } |
| 2725 | 2727 | |
| 2726 | | /// If the name does not fit in the symbol header, adds it to the symbol table string table. |
| 2727 | | /// If the caller knows this name already has a String associated with it, they can avoid |
| 2728 | | /// a redundant call to `getOrPutString` by specifying `opt_string`. |
| 2729 | | /// The lifetime of the return value matches that of `name`. |
| 2730 | | fn getOrPutSymbolName(coff: *Coff, name: []const u8, opt_string: ?String) !SymbolTable.SymbolName { |
| 2728 | /// If the name does not fit within inline storage, adds it to the symbol table string table. |
| 2729 | fn getOrPutSymbolName(coff: *Coff, name: union(enum) { |
| 2730 | slice: []const u8, |
| 2731 | string: String, |
| 2732 | }) !SymbolTable.SymbolName { |
| 2731 | 2733 | assert(!coff.isImage()); |
| 2732 | 2734 | const gpa = coff.base.comp.gpa; |
| 2735 | const slice = switch (name) { |
| 2736 | .slice => |s| s, |
| 2737 | .string => |s| s.toSlice(coff), |
| 2738 | }; |
| 2739 | |
| 2740 | if (slice.len > header_name_max_len) { |
| 2741 | const string = switch (name) { |
| 2742 | .slice => |s| try coff.getOrPutString(s), |
| 2743 | .string => |s| s, |
| 2744 | }; |
| 2733 | 2745 | |
| 2734 | | return if (name.len > header_name_max_len) name: { |
| 2735 | | const string = opt_string orelse try coff.getOrPutString(name); |
| 2736 | 2746 | const string_gop = try coff.symbol_table.strings.getOrPut(gpa, string); |
| 2737 | 2747 | if (!string_gop.found_existing) { |
| 2738 | 2748 | const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1]; |
| 2739 | 2749 | string_gop.value_ptr.* = @fromBackingInt(@intCast(string_index)); |
| 2740 | 2750 | |
| 2741 | | try coff.symbol_table.strings_ni.resizeLeaf(gpa, &coff.mf, string_index + name.len + 1); |
| 2742 | | const slice = coff.symbol_table.strings_ni.slice(&coff.mf); |
| 2743 | | @memcpy(slice[@intCast(string_index)..][0..name.len], name); |
| 2744 | | slice[@intCast(string_index + name.len)] = 0; |
| 2751 | try coff.symbol_table.strings_ni.resizeLeaf(gpa, &coff.mf, string_index + slice.len + 1); |
| 2752 | const storage = coff.symbol_table.strings_ni.slice(&coff.mf); |
| 2753 | @memcpy(storage[@intCast(string_index)..][0..slice.len], slice); |
| 2754 | storage[@intCast(string_index + slice.len)] = 0; |
| 2745 | 2755 | } |
| 2746 | 2756 | |
| 2747 | | break :name .{ .long = string_gop.value_ptr.* }; |
| 2748 | | } else .{ .short = name }; |
| 2757 | return .{ .long = string_gop.value_ptr.* }; |
| 2758 | } else { |
| 2759 | var symbol_name: SymbolTable.SymbolName = .{ .short = undefined }; |
| 2760 | @memcpy(symbol_name.short[0..slice.len], slice); |
| 2761 | @memset(symbol_name.short[slice.len..], 0); |
| 2762 | return symbol_name; |
| 2763 | } |
| 2749 | 2764 | } |
| 2750 | 2765 | |
| 2751 | 2766 | /// `len` does not include null terminators |
| ... | ... | @@ -2776,37 +2791,43 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 2776 | 2791 | return @fromBackingInt(@intCast(gop.key_ptr.*)); |
| 2777 | 2792 | } |
| 2778 | 2793 | |
| 2779 | | const GlobalOptions = struct { |
| 2780 | | name: []const u8, |
| 2781 | | lib_name: ?[]const u8 = null, |
| 2782 | | type: Symbol.Type = .unknown, |
| 2783 | | dll_storage_class: Symbol.DllStorageClass = .default, |
| 2794 | const ExternLibName = union(enum) { |
| 2795 | // Symbol can be supplied from anywhere |
| 2796 | any, |
| 2797 | // Symbol can be supplied by any LibC input |
| 2798 | lib_c, |
| 2799 | // Symbol must be supplied by a specific input |
| 2800 | explicit: String, |
| 2784 | 2801 | }; |
| 2785 | 2802 | |
| 2803 | const FmtExternLibName = struct { coff: *Coff, lib_name: ExternLibName }; |
| 2804 | |
| 2805 | fn fmtExternLibName(coff: *Coff, lib_name: ExternLibName) std.fmt.Alt(FmtExternLibName, formatExternLibName) { |
| 2806 | return .{ .data = .{ .coff = coff, .lib_name = lib_name } }; |
| 2807 | } |
| 2808 | |
| 2809 | fn formatExternLibName(data: FmtExternLibName, w: *Io.Writer) Io.Writer.Error!void { |
| 2810 | try w.writeAll(switch (data.lib_name) { |
| 2811 | .any => "*", |
| 2812 | .lib_c => "c", |
| 2813 | .explicit => |str| str.toSlice(data.coff), |
| 2814 | }); |
| 2815 | } |
| 2816 | |
| 2786 | 2817 | fn getOrPutGlobalSymbol( |
| 2787 | 2818 | coff: *Coff, |
| 2788 | | opts: GlobalOptions, |
| 2819 | opts: struct { |
| 2820 | name: String, |
| 2821 | lib_name: ExternLibName = .any, |
| 2822 | type: Symbol.Type = .unknown, |
| 2823 | dll_storage_class: Symbol.DllStorageClass = .default, |
| 2824 | }, |
| 2789 | 2825 | ) !std.array_hash_map.Auto(String, Global).GetOrPutResult { |
| 2790 | 2826 | const comp = coff.base.comp; |
| 2791 | 2827 | const gpa = comp.gpa; |
| 2792 | 2828 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 2793 | 2829 | |
| 2794 | | const lib_name: String.Optional = if (opts.lib_name) |lib_name| lib_name: { |
| 2795 | | const is_libc = std.zig.target.isLibCLibName(&comp.root_mod.resolved_target.result, lib_name); |
| 2796 | | if (is_libc) { |
| 2797 | | // This is guaranteed by Sema.handleExternLibName |
| 2798 | | if (!comp.config.link_libc) unreachable; |
| 2799 | | |
| 2800 | | // TODO: The user has requested this symbol come from libc, but this logic allows |
| 2801 | | // it to come from anywhere. We need to know what inputs are libc inputs, |
| 2802 | | // and set a flag to only search them for this symbol. |
| 2803 | | break :lib_name .none; |
| 2804 | | } |
| 2805 | | |
| 2806 | | break :lib_name (try coff.getOrPutString(lib_name)).toOptional(); |
| 2807 | | } else .none; |
| 2808 | | |
| 2809 | | const sym_gop = try coff.globals.getOrPut(gpa, try coff.getOrPutString(opts.name)); |
| 2830 | const sym_gop = try coff.globals.getOrPut(gpa, opts.name); |
| 2810 | 2831 | if (!sym_gop.found_existing) { |
| 2811 | 2832 | const si = coff.addSymbolAssumeCapacity(); |
| 2812 | 2833 | const sym = si.get(coff); |
| ... | ... | @@ -2815,11 +2836,11 @@ fn getOrPutGlobalSymbol( |
| 2815 | 2836 | sym.flags.dll_storage_class = opts.dll_storage_class; |
| 2816 | 2837 | sym_gop.value_ptr.* = .{ |
| 2817 | 2838 | .si = si, |
| 2818 | | .lib_name = lib_name, |
| 2839 | .lib_name = opts.lib_name, |
| 2819 | 2840 | }; |
| 2820 | 2841 | coff.synth_prog_node.increaseEstimatedTotalItems(1); |
| 2821 | 2842 | |
| 2822 | | log.debug("globalSymbol({s}, {?s}) = {d}", .{ opts.name, opts.lib_name, si }); |
| 2843 | log.debug("globalSymbol({s}, {f}) = {d}", .{ opts.name.toSlice(coff), fmtExternLibName(coff, opts.lib_name), si }); |
| 2823 | 2844 | } |
| 2824 | 2845 | |
| 2825 | 2846 | return sym_gop; |
| ... | ... | @@ -2832,8 +2853,36 @@ fn getDefinedGlobal(coff: *Coff, name: []const u8) Symbol.Index { |
| 2832 | 2853 | return .null; |
| 2833 | 2854 | } |
| 2834 | 2855 | |
| 2835 | | pub fn globalSymbol(coff: *Coff, opts: GlobalOptions) !Symbol.Index { |
| 2836 | | const gop = try coff.getOrPutGlobalSymbol(opts); |
| 2856 | pub fn globalSymbol(coff: *Coff, opts: struct { |
| 2857 | name: []const u8, |
| 2858 | lib_name: ?[]const u8 = null, |
| 2859 | type: Symbol.Type = .unknown, |
| 2860 | dll_storage_class: Symbol.DllStorageClass = .default, |
| 2861 | }) !Symbol.Index { |
| 2862 | const comp = coff.base.comp; |
| 2863 | const lib_name: ExternLibName = if (opts.lib_name) |lib_name| lib_name: { |
| 2864 | const is_libc = std.zig.target.isLibCLibName( |
| 2865 | &comp.root_mod.resolved_target.result, |
| 2866 | lib_name, |
| 2867 | ); |
| 2868 | |
| 2869 | if (is_libc) { |
| 2870 | // This is guaranteed by Sema.handleExternLibName |
| 2871 | if (!comp.config.link_libc) unreachable; |
| 2872 | break :lib_name .lib_c; |
| 2873 | } |
| 2874 | |
| 2875 | try coff.ensureManyUnusedStringCapacity(2, opts.name.len + lib_name.len + 2); |
| 2876 | break :lib_name .{ .explicit = coff.getOrPutStringAssumeCapacity(lib_name) }; |
| 2877 | } else .any; |
| 2878 | |
| 2879 | try coff.ensureUnusedStringCapacity(opts.name.len); |
| 2880 | const gop = try coff.getOrPutGlobalSymbol(.{ |
| 2881 | .name = coff.getOrPutStringAssumeCapacity(opts.name), |
| 2882 | .lib_name = lib_name, |
| 2883 | .type = opts.type, |
| 2884 | .dll_storage_class = opts.dll_storage_class, |
| 2885 | }); |
| 2837 | 2886 | return gop.value_ptr.si; |
| 2838 | 2887 | } |
| 2839 | 2888 | |
| ... | ... | @@ -3107,7 +3156,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void { |
| 3107 | 3156 | coff.targetStore(coff.secondLinkerMemberNumSymbolsPtr(), @backingInt(mfli) + 1); |
| 3108 | 3157 | if (!needs_sort) { |
| 3109 | 3158 | @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); |
| 3110 | | @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice[0..name_slice.len]); |
| 3159 | @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice); |
| 3111 | 3160 | slice[new_header_size + coff.lib_string_len + name_slice.len] = 0; |
| 3112 | 3161 | } else if (!old_needs_sort) { |
| 3113 | 3162 | // The entire string table is rebuilt in flushMember after sorting |
| ... | ... | @@ -3136,9 +3185,8 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void { |
| 3136 | 3185 | const entry = coff.symbolTableEntryPtr(sti.*) orelse entry: { |
| 3137 | 3186 | const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType = |
| 3138 | 3187 | if (sym.gmi != .none) blk: { |
| 3139 | | const name = sym.gmi.name(coff); |
| 3140 | 3188 | break :blk .{ |
| 3141 | | try coff.getOrPutSymbolName(name.toSlice(coff), name), |
| 3189 | try coff.getOrPutSymbolName(.{ .string = sym.gmi.name(coff) }), |
| 3142 | 3190 | @intFromBool(sym.flags.weak_external_strat != .none), |
| 3143 | 3191 | if (Symbol.Index.text.get(coff).section_number == sym.section_number) |
| 3144 | 3192 | .FUNCTION |
| ... | ... | @@ -3147,7 +3195,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void { |
| 3147 | 3195 | }; |
| 3148 | 3196 | } else blk: switch (coff.getNode(sym.ni.unwrap().?)) { |
| 3149 | 3197 | .image_section => .{ |
| 3150 | | try coff.getOrPutSymbolName(&sym.section_number.header(coff).name, null), |
| 3198 | try coff.getOrPutSymbolName(.{ .slice = &sym.section_number.header(coff).name }), |
| 3151 | 3199 | 1, |
| 3152 | 3200 | .NULL, |
| 3153 | 3201 | }, |
| ... | ... | @@ -3156,7 +3204,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void { |
| 3156 | 3204 | const ip = &zcu.intern_pool; |
| 3157 | 3205 | const nav = ip.getNav(nmi.navIndex(coff)); |
| 3158 | 3206 | break :blk .{ |
| 3159 | | try coff.getOrPutSymbolName(nav.fqn.toSlice(ip), null), |
| 3207 | try coff.getOrPutSymbolName(.{ .slice = nav.fqn.toSlice(ip) }), |
| 3160 | 3208 | 0, |
| 3161 | 3209 | if (ip.isFunctionType(nav.resolved.?.type)) .FUNCTION else .NULL, |
| 3162 | 3210 | }; |
| ... | ... | @@ -3165,7 +3213,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void { |
| 3165 | 3213 | var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined; |
| 3166 | 3214 | const name = std.mem.print(&name_buf, "__anon_{d}", .{umi}) catch unreachable; |
| 3167 | 3215 | break :blk .{ |
| 3168 | | try coff.getOrPutSymbolName(name, null), |
| 3216 | try coff.getOrPutSymbolName(.{ .slice = name }), |
| 3169 | 3217 | 0, |
| 3170 | 3218 | .NULL, |
| 3171 | 3219 | }; |
| ... | ... | @@ -3179,9 +3227,8 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void { |
| 3179 | 3227 | lazy_sym.kind, mi, |
| 3180 | 3228 | }) catch unreachable; |
| 3181 | 3229 | |
| 3182 | | const string = try coff.getOrPutString(name); |
| 3183 | 3230 | break :blk .{ |
| 3184 | | try coff.getOrPutSymbolName(string.toSlice(coff), string), |
| 3231 | try coff.getOrPutSymbolName(.{ .slice = name }), |
| 3185 | 3232 | 0, |
| 3186 | 3233 | if (tag == .lazy_code) .FUNCTION else .NULL, |
| 3187 | 3234 | }; |
| ... | ... | @@ -3412,8 +3459,8 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S |
| 3412 | 3459 | if (coff.targetEndian() != native_endian) |
| 3413 | 3460 | std.mem.byteSwapAllFields(std.coff.SectionHeader, section); |
| 3414 | 3461 | |
| 3415 | | const name_slice = name.toSlice(coff); |
| 3416 | 3462 | if (coff.isImage()) { |
| 3463 | const name_slice = name.toSlice(coff); |
| 3417 | 3464 | @memcpy(section.name[0..name_slice.len], name_slice); |
| 3418 | 3465 | @memset(section.name[name_slice.len..], 0); |
| 3419 | 3466 | switch (coff.optionalHeaderPtr()) { |
| ... | ... | @@ -3423,7 +3470,7 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S |
| 3423 | 3470 | ), |
| 3424 | 3471 | } |
| 3425 | 3472 | } else { |
| 3426 | | (try coff.getOrPutSymbolName(name_slice, name)).store(coff, &section.name); |
| 3473 | (try coff.getOrPutSymbolName(.{ .string = name })).store(coff, &section.name); |
| 3427 | 3474 | try coff.pendingSymbolTableEntry(si); |
| 3428 | 3475 | } |
| 3429 | 3476 | |
| ... | ... | @@ -3542,21 +3589,26 @@ fn objectSectionMapIndex( |
| 3542 | 3589 | attributes: ObjectSectionAttributes, |
| 3543 | 3590 | ) !Node.ObjectSectionMapIndex { |
| 3544 | 3591 | const gpa = coff.base.comp.gpa; |
| 3545 | | const name_slice = name.toSlice(coff); |
| 3546 | | // TODO: Should this be a section merge instead? |
| 3547 | | const effective_attributes = if (coff.isImage() and std.mem.startsWith(u8, name_slice, ".tls")) attr: { |
| 3548 | | // In images, the .tls section is a read-only template |
| 3549 | | var attr = attributes; |
| 3550 | | attr.write = false; |
| 3551 | | break :attr attr; |
| 3552 | | } else attributes; |
| 3553 | 3592 | |
| 3554 | 3593 | const object_section_gop = try coff.object_section_table.getOrPut(gpa, name); |
| 3555 | 3594 | const osmi: Node.ObjectSectionMapIndex = @fromBackingInt(@intCast(object_section_gop.index)); |
| 3556 | 3595 | const sym = if (!object_section_gop.found_existing) sym: { |
| 3557 | | try coff.ensureUnusedStringCapacity(name_slice.len); |
| 3558 | | const parent_name = coff.getOrPutStringAssumeCapacity(coff.objectSectionParentName(name_slice)); |
| 3559 | | const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, effective_attributes)).symbol(coff); |
| 3596 | const name_slice, const parent_name = blk: { |
| 3597 | var name_slice = name.toSlice(coff); |
| 3598 | const parent_name_slice = coff.objectSectionParentName(name_slice); |
| 3599 | const parent_name = if (parent_name_slice.len < name_slice.len) parent_name: { |
| 3600 | try coff.ensureUnusedStringCapacity(parent_name_slice.len); |
| 3601 | name_slice = name.toSlice(coff); |
| 3602 | break :parent_name coff.getOrPutStringAssumeCapacity(name_slice[0..parent_name_slice.len]); |
| 3603 | } else name; |
| 3604 | |
| 3605 | break :blk .{ name_slice, parent_name }; |
| 3606 | }; |
| 3607 | |
| 3608 | coff.string_bytes.lockPointers(); |
| 3609 | defer coff.string_bytes.unlockPointers(); |
| 3610 | |
| 3611 | const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, attributes)).symbol(coff); |
| 3560 | 3612 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 3561 | 3613 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 3562 | 3614 | const parent_ni = parent.node(coff); |
| ... | ... | @@ -3608,7 +3660,7 @@ fn objectSectionMapIndex( |
| 3608 | 3660 | name, |
| 3609 | 3661 | .object, |
| 3610 | 3662 | .fromFlags(sym.section_number.header(coff).flags), |
| 3611 | | effective_attributes, |
| 3663 | attributes, |
| 3612 | 3664 | ); |
| 3613 | 3665 | |
| 3614 | 3666 | return osmi; |
| ... | ... | @@ -4542,7 +4594,7 @@ fn loadObject( |
| 4542 | 4594 | }, |
| 4543 | 4595 | .external => { |
| 4544 | 4596 | const global_gop = try coff.getOrPutGlobalSymbol(.{ |
| 4545 | | .name = symbol.name.toSlice(coff), |
| 4597 | .name = symbol.name, |
| 4546 | 4598 | }); |
| 4547 | 4599 | |
| 4548 | 4600 | // TODO: What if the same symbol is incorrectly defined twice in this obj? |
| ... | ... | @@ -4749,7 +4801,7 @@ fn loadObject( |
| 4749 | 4801 | continue; |
| 4750 | 4802 | }, |
| 4751 | 4803 | .weak_external => |alias_index| { |
| 4752 | | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); |
| 4804 | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name }); |
| 4753 | 4805 | symbol.si = global_gop.value_ptr.si; |
| 4754 | 4806 | if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { |
| 4755 | 4807 | const sym = symbol.si.get(coff); |
| ... | ... | @@ -4788,7 +4840,7 @@ fn loadObject( |
| 4788 | 4840 | break :sym value; |
| 4789 | 4841 | }, |
| 4790 | 4842 | .external => |value| { |
| 4791 | | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); |
| 4843 | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name }); |
| 4792 | 4844 | symbol.si = global_gop.value_ptr.si; |
| 4793 | 4845 | if (global_gop.found_existing) |
| 4794 | 4846 | return coff.failMultipleDefinitions( |
| ... | ... | @@ -4824,7 +4876,7 @@ fn loadObject( |
| 4824 | 4876 | }, |
| 4825 | 4877 | .external => { |
| 4826 | 4878 | assert(index != section.comdat_psi.unwrap()); |
| 4827 | | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); |
| 4879 | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name }); |
| 4828 | 4880 | symbol.si = global_gop.value_ptr.si; |
| 4829 | 4881 | |
| 4830 | 4882 | const sym = symbol.si.get(coff); |
| ... | ... | @@ -4908,7 +4960,7 @@ fn loadObject( |
| 4908 | 4960 | assert(symbol.section_number == .UNDEFINED); |
| 4909 | 4961 | switch (symbol.value) { |
| 4910 | 4962 | .external => |size| { |
| 4911 | | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); |
| 4963 | const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name }); |
| 4912 | 4964 | symbol.si = global_gop.value_ptr.si; |
| 4913 | 4965 | if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { |
| 4914 | 4966 | const sym = symbol.si.get(coff); |
| ... | ... | @@ -5963,12 +6015,12 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5963 | 6015 | break :task; |
| 5964 | 6016 | } |
| 5965 | 6017 | if (coff.pending_input) |pending_iami| { |
| 5966 | | const name_slice = pending_iami.member(coff).name.toSlice(coff); |
| 5967 | 6018 | const sub_prog_node = coff.input_prog_node.start( |
| 5968 | | name_slice, |
| 6019 | pending_iami.member(coff).name.toSlice(coff), |
| 5969 | 6020 | 0, |
| 5970 | 6021 | ); |
| 5971 | 6022 | defer sub_prog_node.end(); |
| 6023 | |
| 5972 | 6024 | coff.pending_input = null; |
| 5973 | 6025 | coff.flushInputMember(pending_iami) catch |err| switch (err) { |
| 5974 | 6026 | error.OutOfMemory => return error.OutOfMemory, |
| ... | ... | @@ -5976,7 +6028,7 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5976 | 6028 | "linker failed to load archive member '{f}{f}': {t}", |
| 5977 | 6029 | .{ |
| 5978 | 6030 | pending_iami.member(coff).iai.path(coff), |
| 5979 | | fmtMemberNameString(name_slice), |
| 6031 | fmtMemberNameString(pending_iami.member(coff).name.toSlice(coff)), |
| 5980 | 6032 | e, |
| 5981 | 6033 | }, |
| 5982 | 6034 | ), |
| ... | ... | @@ -6246,9 +6298,9 @@ fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !v |
| 6246 | 6298 | assert(sym.section_number == .UNDEFINED); |
| 6247 | 6299 | assert(sym.loc_relocs == .none); |
| 6248 | 6300 | |
| 6249 | | log.debug("aliasGlobal({s}, {?s}) {d}->{d} ({?s})", .{ |
| 6301 | log.debug("aliasGlobal({s}, {f}) {d}->{d} ({?s})", .{ |
| 6250 | 6302 | gmi.name(coff).toSlice(coff), |
| 6251 | | gmi.libName(coff).toSlice(coff), |
| 6303 | fmtExternLibName(coff, gmi.libName(coff)), |
| 6252 | 6304 | si, |
| 6253 | 6305 | alias_si, |
| 6254 | 6306 | if (alias_sym.gmi != .none) alias_sym.gmi.name(coff).toSlice(coff) else null, |
| ... | ... | @@ -6286,10 +6338,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6286 | 6338 | const si = gmi.symbol(coff); |
| 6287 | 6339 | |
| 6288 | 6340 | log.debug( |
| 6289 | | "flushGlobal({s}, {?s}) = n{d} {d}@{d}", |
| 6341 | "flushGlobal({s}, {f}) = n{d} {d}@{d}", |
| 6290 | 6342 | .{ |
| 6291 | 6343 | name.toSlice(coff), |
| 6292 | | gmi.libName(coff).toSlice(coff), |
| 6344 | fmtExternLibName(coff, gmi.libName(coff)), |
| 6293 | 6345 | si.get(coff).ni, |
| 6294 | 6346 | si, |
| 6295 | 6347 | si.get(coff).section_number, |
| ... | ... | @@ -6322,16 +6374,18 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6322 | 6374 | |
| 6323 | 6375 | const import: Import = import: { |
| 6324 | 6376 | const sym = si.get(coff); |
| 6325 | | const name_slice = name.toSlice(coff); |
| 6326 | | const imp_match = std.mem.startsWith(u8, name_slice, imp_prefix); |
| 6377 | const imp_match, const name_len = blk: { |
| 6378 | const name_slice = name.toSlice(coff); |
| 6379 | break :blk .{ std.mem.startsWith(u8, name_slice, imp_prefix), name_slice.len }; |
| 6380 | }; |
| 6327 | 6381 | |
| 6328 | 6382 | // Globals may have the __imp_ prefix already if they are undef externals from another input. |
| 6329 | 6383 | assert(sym.flags.dll_storage_class != .dllexport); |
| 6330 | 6384 | const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport) |
| 6331 | 6385 | .{ name, imp_match } |
| 6332 | 6386 | else name: { |
| 6333 | | try coff.ensureUnusedStringCapacity(imp_prefix.len + name_slice.len); |
| 6334 | | const imp_name = try gpa.print(imp_prefix ++ "{s}", .{name_slice}); |
| 6387 | try coff.ensureUnusedStringCapacity(imp_prefix.len + name_len); |
| 6388 | const imp_name = try gpa.print(imp_prefix ++ "{s}", .{name.toSlice(coff)}); |
| 6335 | 6389 | defer gpa.free(imp_name); |
| 6336 | 6390 | break :name .{ coff.getOrPutStringAssumeCapacity(imp_name), true }; |
| 6337 | 6391 | }; |
| ... | ... | @@ -6364,68 +6418,73 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6364 | 6418 | while (true) { |
| 6365 | 6419 | const archive_sym = &coff.input_archive_symbols.items[@backingInt(iter)]; |
| 6366 | 6420 | const member = &coff.input_archive_members.items[@backingInt(archive_sym.iami)]; |
| 6367 | | member: switch (member.content) { |
| 6368 | | .object => if (!member.flags.is_loaded) { |
| 6369 | | if (gmi.libName(coff).unwrap()) |lib_name| |
| 6370 | | if (!std.ascii.eqlIgnoreCase( |
| 6371 | | lib_name.toSlice(coff), |
| 6372 | | member.iai.path(coff).stem(), |
| 6373 | | )) break :member; |
| 6374 | | |
| 6375 | | // Try loading the input member and then retry. |
| 6376 | | // This could still be a member containing imports |
| 6377 | | // that use the older non-IMPORT_HEADER method. |
| 6378 | | coff.pending_input = archive_sym.iami; |
| 6379 | | return false; |
| 6380 | | }, |
| 6381 | | .import => |import| { |
| 6382 | | if (gmi.libName(coff).unwrap()) |lib_name| |
| 6383 | | if (!std.ascii.eqlIgnoreCase( |
| 6384 | | import.lib_name.toSlice(coff), |
| 6385 | | lib_name.toSlice(coff), |
| 6386 | | )) break :member; |
| 6387 | | |
| 6388 | | const imp_name: String.Optional = name: switch (import.name_type) { |
| 6389 | | .NAME, |
| 6390 | | .NAME_NOPREFIX, |
| 6391 | | .NAME_UNDECORATE, |
| 6392 | | => |tag| { |
| 6393 | | const symbol_name: []const u8 = import.symbol_name.toSlice(coff); |
| 6394 | | const end_match = std.mem.endsWith(u8, name_slice, symbol_name); |
| 6395 | | const len_delta = name_slice.len -% symbol_name.len; |
| 6396 | | if (!end_match or |
| 6397 | | (!imp_match and len_delta != 0) or |
| 6398 | | (imp_match and len_delta != imp_prefix.len)) |
| 6399 | | return comp.link_diags.fail( |
| 6400 | | "global '{s}' has mismatched symbol name in import header: '{s}'", |
| 6401 | | .{ |
| 6402 | | name.toSlice(coff), |
| 6403 | | import.symbol_name.toSlice(coff), |
| 6404 | | }, |
| 6405 | | ); |
| 6406 | | |
| 6407 | | const imp_name = if (tag == .NAME) import.symbol_name else undecorated: { |
| 6408 | | var imp_name = std.mem.trimStart(u8, symbol_name, "?@_"); |
| 6409 | | if (tag == .NAME_UNDECORATE) |
| 6410 | | imp_name = std.mem.sliceTo(imp_name, '@'); |
| 6421 | const lib_name_matches = match: switch (gmi.libName(coff)) { |
| 6422 | .any => true, |
| 6423 | .lib_c => { |
| 6424 | // TODO: Need a flag to indicate if this member is from a libc archive |
| 6425 | const is_libc_archive = true; |
| 6411 | 6426 | |
| 6412 | | try coff.ensureUnusedStringCapacity(imp_name.len); |
| 6413 | | break :undecorated coff.getOrPutStringAssumeCapacity(imp_name); |
| 6414 | | }; |
| 6427 | break :match is_libc_archive; |
| 6428 | }, |
| 6429 | .explicit => |lib_name| std.ascii.eqlIgnoreCase( |
| 6430 | lib_name.toSlice(coff), |
| 6431 | member.iai.path(coff).stem(), |
| 6432 | ), |
| 6433 | }; |
| 6415 | 6434 | |
| 6416 | | break :name imp_name.toOptional(); |
| 6417 | | }, |
| 6418 | | .ORDINAL => break :name .none, |
| 6419 | | else => |t| return comp.link_diags.fail("TODO handle name_type {t}", .{t}), |
| 6420 | | }; |
| 6435 | if (lib_name_matches) { |
| 6436 | switch (member.content) { |
| 6437 | .object => if (!member.flags.is_loaded) { |
| 6438 | // Try loading the input member and then retry. |
| 6439 | // This could still be a member containing imports |
| 6440 | // that use the older non-IMPORT_HEADER method. |
| 6441 | coff.pending_input = archive_sym.iami; |
| 6442 | return false; |
| 6443 | }, |
| 6444 | .import => |import| { |
| 6445 | const imp_name: String.Optional = name: switch (import.name_type) { |
| 6446 | .NAME, |
| 6447 | .NAME_NOPREFIX, |
| 6448 | .NAME_UNDECORATE, |
| 6449 | => |tag| { |
| 6450 | const symbol_name: []const u8 = import.symbol_name.toSlice(coff); |
| 6451 | const name_slice = name.toSlice(coff); |
| 6452 | const end_match = std.mem.endsWith(u8, name_slice, symbol_name); |
| 6453 | const len_delta = name_slice.len -% symbol_name.len; |
| 6454 | if (!end_match or |
| 6455 | (!imp_match and len_delta != 0) or |
| 6456 | (imp_match and len_delta != imp_prefix.len)) |
| 6457 | return comp.link_diags.fail( |
| 6458 | "global '{s}' has mismatched symbol name in import header: '{s}'", |
| 6459 | .{ |
| 6460 | name.toSlice(coff), |
| 6461 | import.symbol_name.toSlice(coff), |
| 6462 | }, |
| 6463 | ); |
| 6464 | |
| 6465 | const imp_name = if (tag == .NAME) import.symbol_name else undecorated: { |
| 6466 | var imp_name = std.mem.trimStart(u8, symbol_name, "?@_"); |
| 6467 | if (tag == .NAME_UNDECORATE) |
| 6468 | imp_name = std.mem.sliceTo(imp_name, '@'); |
| 6469 | |
| 6470 | try coff.ensureUnusedStringCapacity(imp_name.len); |
| 6471 | break :undecorated coff.getOrPutStringAssumeCapacity(imp_name); |
| 6472 | }; |
| 6473 | |
| 6474 | break :name imp_name.toOptional(); |
| 6475 | }, |
| 6476 | .ORDINAL => break :name .none, |
| 6477 | else => |t| return comp.link_diags.fail("TODO handle name_type {t}", .{t}), |
| 6478 | }; |
| 6421 | 6479 | |
| 6422 | | break :import .{ |
| 6423 | | .lib_name = import.lib_name, |
| 6424 | | .name = imp_name, |
| 6425 | | .ordinal_hint = import.import_ordinal_hint, |
| 6426 | | .kind = if (import.type == .CODE and !is_imp) .thunk else .iat_ptr, |
| 6427 | | }; |
| 6428 | | }, |
| 6480 | break :import .{ |
| 6481 | .lib_name = import.lib_name, |
| 6482 | .name = imp_name, |
| 6483 | .ordinal_hint = import.import_ordinal_hint, |
| 6484 | .kind = if (import.type == .CODE and !is_imp) .thunk else .iat_ptr, |
| 6485 | }; |
| 6486 | }, |
| 6487 | } |
| 6429 | 6488 | } |
| 6430 | 6489 | |
| 6431 | 6490 | if (archive_sym.next == iter) break; |
| ... | ... | @@ -6442,7 +6501,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6442 | 6501 | // Convert an unresolved weak external that itself refers to an undef external |
| 6443 | 6502 | // into a (possibly new) global, so it can be resolved separately. |
| 6444 | 6503 | const alias_gop = try coff.getOrPutGlobalSymbol(.{ |
| 6445 | | .name = sym.value.weak_alias_name.toSlice(coff), |
| 6504 | .name = sym.value.weak_alias_name, |
| 6446 | 6505 | }); |
| 6447 | 6506 | try coff.aliasGlobal(gmi, alias_gop.value_ptr.si); |
| 6448 | 6507 | return true; |
| ... | ... | @@ -6462,12 +6521,15 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6462 | 6521 | // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification, |
| 6463 | 6522 | // which are not in the implib. |
| 6464 | 6523 | if (sym.flags.type != .unknown) { |
| 6465 | | if (gmi.libName(coff).unwrap()) |lib_name| break :import .{ |
| 6466 | | .lib_name = lib_name, |
| 6467 | | .name = name.toOptional(), |
| 6468 | | .ordinal_hint = 0, |
| 6469 | | .kind = if (sym.flags.type == .code) .thunk else .iat_ptr, |
| 6470 | | }; |
| 6524 | switch (gmi.libName(coff)) { |
| 6525 | .explicit => |lib_name| break :import .{ |
| 6526 | .lib_name = lib_name, |
| 6527 | .name = name.toOptional(), |
| 6528 | .ordinal_hint = 0, |
| 6529 | .kind = if (sym.flags.type == .code) .thunk else .iat_ptr, |
| 6530 | }, |
| 6531 | else => {}, |
| 6532 | } |
| 6471 | 6533 | } |
| 6472 | 6534 | |
| 6473 | 6535 | return true; |
| ... | ... | @@ -6478,10 +6540,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6478 | 6540 | |
| 6479 | 6541 | const target_endian = coff.targetEndian(); |
| 6480 | 6542 | const addr_info = coff.targetAddrInfo(); |
| 6481 | | const lib_name = import.lib_name.toSlice(coff); |
| 6543 | const lib_name_slice = import.lib_name.toSlice(coff); |
| 6482 | 6544 | const gop = try coff.import_table.entries.getOrPutAdapted( |
| 6483 | 6545 | gpa, |
| 6484 | | lib_name, |
| 6546 | lib_name_slice, |
| 6485 | 6547 | ImportTable.Adapter{ .coff = coff }, |
| 6486 | 6548 | ); |
| 6487 | 6549 | const import_hint_name_align: Alignment = .@"2"; |
| ... | ... | @@ -6493,7 +6555,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6493 | 6555 | @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2), |
| 6494 | 6556 | ); |
| 6495 | 6557 | const import_hint_name_table_len = |
| 6496 | | import_hint_name_align.forward(lib_name.len + ".dll".len + 1); |
| 6558 | import_hint_name_align.forward(lib_name_slice.len + ".dll".len + 1); |
| 6497 | 6559 | const idata_section_ni = coff.import_table.ni.parent(&coff.mf).unwrap().?; |
| 6498 | 6560 | const import_lookup_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{ |
| 6499 | 6561 | .size = addr_info.size * 2, |
| ... | ... | @@ -6528,9 +6590,9 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6528 | 6590 | .hint_name_len = @intCast(import_hint_name_table_len), |
| 6529 | 6591 | }; |
| 6530 | 6592 | const import_hint_name_slice = import_hint_name_table_ni.slice(&coff.mf); |
| 6531 | | @memcpy(import_hint_name_slice[0..lib_name.len], lib_name); |
| 6532 | | @memcpy(import_hint_name_slice[lib_name.len..][0..".dll".len], ".dll"); |
| 6533 | | @memset(import_hint_name_slice[lib_name.len + ".dll".len ..], 0); |
| 6593 | @memcpy(import_hint_name_slice[0..lib_name_slice.len], lib_name_slice); |
| 6594 | @memcpy(import_hint_name_slice[lib_name_slice.len..][0..".dll".len], ".dll"); |
| 6595 | @memset(import_hint_name_slice[lib_name_slice.len + ".dll".len ..], 0); |
| 6534 | 6596 | coff.nodes.appendAssumeCapacity(.{ .import_lookup_table = @fromBackingInt(@intCast(gop.index)) }); |
| 6535 | 6597 | coff.nodes.appendAssumeCapacity(.{ .import_address_table = @fromBackingInt(@intCast(gop.index)) }); |
| 6536 | 6598 | coff.nodes.appendAssumeCapacity(.{ .import_hint_name_table = @fromBackingInt(@intCast(gop.index)) }); |
| ... | ... | @@ -6555,7 +6617,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6555 | 6617 | |
| 6556 | 6618 | log.debug( |
| 6557 | 6619 | "flushGlobalImport({s}, {?s}, {d}, {s})", |
| 6558 | | .{ name.toSlice(coff), import.name.toSlice(coff), import.ordinal_hint, lib_name }, |
| 6620 | .{ name.toSlice(coff), import.name.toSlice(coff), import.ordinal_hint, lib_name_slice }, |
| 6559 | 6621 | ); |
| 6560 | 6622 | |
| 6561 | 6623 | const iat_symbol_gop = try coff.import_table.iat_symbol_indices.getOrPut(gpa, .{ |
| ... | ... | @@ -7662,8 +7724,10 @@ fn fmtGlobalName(coff: *Coff, gmi: Node.GlobalMapIndex) std.fmt.Alt(FmtGlobalNam |
| 7662 | 7724 | fn globalNameEscape(data: FmtGlobalName, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 7663 | 7725 | if (data.gmi == .none) return; |
| 7664 | 7726 | try w.writeAll(data.gmi.name(data.coff).toSlice(data.coff)); |
| 7665 | | if (data.gmi.libName(data.coff).unwrap()) |lib_name| |
| 7666 | | try w.print("({s})", .{lib_name.toSlice(data.coff)}); |
| 7727 | switch (data.gmi.libName(data.coff)) { |
| 7728 | .explicit => |lib_name| try w.print(" ({s}.dll)", .{lib_name.toSlice(data.coff)}), |
| 7729 | else => {}, |
| 7730 | } |
| 7667 | 7731 | } |
| 7668 | 7732 | |
| 7669 | 7733 | fn printNodeName( |
| ... | ... | @@ -7705,12 +7769,7 @@ fn printNodeName( |
| 7705 | 7769 | inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{ |
| 7706 | 7770 | smi.name(coff).toSlice(coff), |
| 7707 | 7771 | }), |
| 7708 | | .import_thunk, |
| 7709 | | => |gmi| { |
| 7710 | | try w.writeByte('('); |
| 7711 | | if (gmi.libName(coff).toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); |
| 7712 | | try w.print("{s})", .{gmi.name(coff).toSlice(coff)}); |
| 7713 | | }, |
| 7772 | .import_thunk => |gmi| try w.print("({f})", .{fmtGlobalName(coff, gmi)}), |
| 7714 | 7773 | .nav => |nmi| { |
| 7715 | 7774 | const zcu = coff.base.comp.zcu.?; |
| 7716 | 7775 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -7736,11 +7795,7 @@ fn printNodeName( |
| 7736 | 7795 | }), |
| 7737 | 7796 | .builtin => |si| { |
| 7738 | 7797 | const sym = si.get(coff); |
| 7739 | | if (sym.gmi != .none) { |
| 7740 | | try w.writeByte('('); |
| 7741 | | if (sym.gmi.libName(coff).toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); |
| 7742 | | try w.print("{s})", .{sym.gmi.name(coff).toSlice(coff)}); |
| 7743 | | } |
| 7798 | if (sym.gmi != .none) try w.print("({f})", .{fmtGlobalName(coff, sym.gmi)}); |
| 7744 | 7799 | }, |
| 7745 | 7800 | } |
| 7746 | 7801 | } |