authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-09-20 02:20:35+02:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-09-20 02:20:35+02:00
log3bfb2999471d921cfdf461c3c12f6caedb45904b
treedfa1f059f7c0b15eb1ec67a57fd331c1ad211b1c
parent1175a3e992fc30361febf3517827a5d0ada49b5b
parent68680bbd00ae43cd25d8c613d666bd1554d67131

Merge pull request 'Coff: Miscellaneous fixes' (#36887) from kcbanner/zig:coff_fixes into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36887

5 files changed, 257 insertions(+), 199 deletions(-)

lib/compiler/objdump.zig+13-11
...@@ -828,19 +828,21 @@ const coff = struct {...@@ -828,19 +828,21 @@ const coff = struct {
828 defer gpa.free(string_table);828 defer gpa.free(string_table);
829829
830 if (d.opts.strings) {830 if (d.opts.strings) {
831 if (d.element(.@"table-header"))831 if (string_table.len > 0) {
832 try w.print(832 if (d.element(.@"table-header"))
833 \\String Table (0x{x} bytes):833 try w.print(
834 \\834 \\String Table (0x{x} bytes):
835 , .{string_table.len});835 \\
836 , .{string_table.len});
836837
837 var sr = Io.Reader.fixed(string_table[@sizeOf(u32)..]);838 var sr = Io.Reader.fixed(string_table[@sizeOf(u32)..]);
838 while (try sr.takeDelimiter(0)) |str| {839 while (try sr.takeDelimiter(0)) |str| {
839 try w.writeAll(str);840 try w.writeAll(str);
840 try w.writeByte('\n');841 try w.writeByte('\n');
841 }842 }
842843
843 if (d.element(.newlines)) try w.writeByte('\n');844 if (d.element(.newlines)) try w.writeByte('\n');
845 } else try w.writeAll("String table not present\n");
844 }846 }
845847
846 var sections: std.ArrayList(Section) = .empty;848 var sections: std.ArrayList(Section) = .empty;
src/Compilation.zig+3-2
...@@ -3528,7 +3528,7 @@ fn emitFromCObject(...@@ -3528,7 +3528,7 @@ fn emitFromCObject(
3528/// Having the file open for writing is problematic as far as executing the3528/// Having the file open for writing is problematic as far as executing the
3529/// binary is concerned. This will remove the write flag, or close the file,3529/// binary is concerned. This will remove the write flag, or close the file,
3530/// or whatever is needed so that it can be executed.3530/// or whatever is needed so that it can be executed.
3531/// After this, one must call` makeFileWritable` before calling `update`.3531/// After this, one must call `makeFileWritable` before calling `update`.
3532pub fn makeBinFileExecutable(comp: *Compilation) !void {3532pub fn makeBinFileExecutable(comp: *Compilation) !void {
3533 if (!dev.env.supports(.make_executable)) return;3533 if (!dev.env.supports(.make_executable)) return;
3534 const lf = comp.bin_file orelse return;3534 const lf = comp.bin_file orelse return;
...@@ -3537,7 +3537,8 @@ pub fn makeBinFileExecutable(comp: *Compilation) !void {...@@ -3537,7 +3537,8 @@ pub fn makeBinFileExecutable(comp: *Compilation) !void {
35373537
3538pub fn makeBinFileWritable(comp: *Compilation) !void {3538pub fn makeBinFileWritable(comp: *Compilation) !void {
3539 const lf = comp.bin_file orelse return;3539 const lf = comp.bin_file orelse return;
3540 return lf.makeWritable();3540 if (lf.canMakeExecutable())
3541 try lf.makeWritable();
3541}3542}
35423543
3543const Header = extern struct {3544const Header = extern struct {
src/link.zig+14-8
...@@ -689,18 +689,24 @@ pub const File = struct {...@@ -689,18 +689,24 @@ pub const File = struct {
689 return macho.reopenDebugInfo();689 return macho.reopenDebugInfo();
690 }690 }
691691
692 pub fn canMakeExecutable(base: *File) bool {
693 const comp = base.comp;
694 return switch (comp.config.output_mode) {
695 .Obj => false,
696 .Lib => switch (comp.config.link_mode) {
697 .static => false,
698 .dynamic => true,
699 },
700 .Exe => true,
701 };
702 }
703
692 pub fn makeExecutable(base: *File) !void {704 pub fn makeExecutable(base: *File) !void {
693 dev.check(.make_executable);705 dev.check(.make_executable);
694 const comp = base.comp;706 const comp = base.comp;
695 const io = comp.io;707 const io = comp.io;
696 switch (comp.config.output_mode) {708 if (!base.canMakeExecutable())
697 .Obj => return,709 return;
698 .Lib => switch (comp.config.link_mode) {
699 .static => return,
700 .dynamic => {},
701 },
702 .Exe => {},
703 }
704 switch (base.tag) {710 switch (base.tag) {
705 .lld => assert(base.file == null),711 .lld => assert(base.file == null),
706 .elf => if (base.file) |f| {712 .elf => if (base.file) |f| {
src/link/Coff.zig+225-170
...@@ -278,7 +278,7 @@ pub const Node = union(enum) {...@@ -278,7 +278,7 @@ pub const Node = union(enum) {
278 return coff.globals.values()[gmi.unwrap().?].si;278 return coff.globals.values()[gmi.unwrap().?].si;
279 }279 }
280280
281 pub fn libName(gmi: GlobalMapIndex, coff: *const Coff) String.Optional {281 pub fn libName(gmi: GlobalMapIndex, coff: *const Coff) ExternLibName {
282 return coff.globals.values()[gmi.unwrap().?].lib_name;282 return coff.globals.values()[gmi.unwrap().?].lib_name;
283 }283 }
284 };284 };
...@@ -647,15 +647,12 @@ pub const SymbolTable = struct {...@@ -647,15 +647,12 @@ pub const SymbolTable = struct {
647 };647 };
648648
649 pub const SymbolName = union(enum) {649 pub const SymbolName = union(enum) {
650 short: []const u8,650 short: [8]u8,
651 long: StringIndex,651 long: StringIndex,
652652
653 pub fn store(name: SymbolName, coff: *const Coff, field: *[8]u8) void {653 pub fn store(name: SymbolName, coff: *const Coff, field: *[8]u8) void {
654 switch (name) {654 switch (name) {
655 .short => |s| {655 .short => |s| field.* = s,
656 @memcpy(field[0..s.len], s);
657 @memset(field[s.len..], 0);
658 },
659 .long => |l| {656 .long => |l| {
660 @memset(field[0..4], 0);657 @memset(field[0..4], 0);
661 std.mem.writePackedInt(u32, field[4..], 0, @backingInt(l), coff.targetEndian());658 std.mem.writePackedInt(u32, field[4..], 0, @backingInt(l), coff.targetEndian());
...@@ -864,7 +861,7 @@ pub const Section = struct {...@@ -864,7 +861,7 @@ pub const Section = struct {
864861
865pub const Global = struct {862pub const Global = struct {
866 si: Symbol.Index,863 si: Symbol.Index,
867 lib_name: String.Optional,864 lib_name: ExternLibName,
868};865};
869866
870pub const WeakExternalStrat = enum(u3) {867pub const WeakExternalStrat = enum(u3) {
...@@ -2263,6 +2260,11 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2263,6 +2260,11 @@ pub fn initBuiltins(coff: *Coff) !void {
2263 }2260 }
22642261
2265 defer coff.flushSectionMerges() catch unreachable;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 if (coff.isImage() and target.isMinGW() and comp.config.link_libc) {2268 if (coff.isImage() and target.isMinGW() and comp.config.link_libc) {
2267 try coff.symbols.ensureUnusedCapacity(gpa, 8);2269 try coff.symbols.ensureUnusedCapacity(gpa, 8);
2268 try coff.globals.ensureUnusedCapacity(gpa, 2);2270 try coff.globals.ensureUnusedCapacity(gpa, 2);
...@@ -2723,29 +2725,42 @@ fn getString(coff: *Coff, string: []const u8) String.Optional {...@@ -2723,29 +2725,42 @@ fn getString(coff: *Coff, string: []const u8) String.Optional {
2723 return .none;2725 return .none;
2724}2726}
27252727
2726/// If the name does not fit in the symbol header, adds it to the symbol table string table.2728/// If the name does not fit within inline storage, adds it to the symbol table string table.
2727/// If the caller knows this name already has a String associated with it, they can avoid2729fn getOrPutSymbolName(coff: *Coff, name: union(enum) {
2728/// a redundant call to `getOrPutString` by specifying `opt_string`.2730 slice: []const u8,
2729/// The lifetime of the return value matches that of `name`.2731 string: String,
2730fn getOrPutSymbolName(coff: *Coff, name: []const u8, opt_string: ?String) !SymbolTable.SymbolName {2732}) !SymbolTable.SymbolName {
2731 assert(!coff.isImage());2733 assert(!coff.isImage());
2732 const gpa = coff.base.comp.gpa;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 };
27332745
2734 return if (name.len > header_name_max_len) name: {
2735 const string = opt_string orelse try coff.getOrPutString(name);
2736 const string_gop = try coff.symbol_table.strings.getOrPut(gpa, string);2746 const string_gop = try coff.symbol_table.strings.getOrPut(gpa, string);
2737 if (!string_gop.found_existing) {2747 if (!string_gop.found_existing) {
2738 const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1];2748 const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1];
2739 string_gop.value_ptr.* = @fromBackingInt(@intCast(string_index));2749 string_gop.value_ptr.* = @fromBackingInt(@intCast(string_index));
27402750
2741 try coff.symbol_table.strings_ni.resizeLeaf(gpa, &coff.mf, string_index + name.len + 1);2751 try coff.symbol_table.strings_ni.resizeLeaf(gpa, &coff.mf, string_index + slice.len + 1);
2742 const slice = coff.symbol_table.strings_ni.slice(&coff.mf);2752 const storage = coff.symbol_table.strings_ni.slice(&coff.mf);
2743 @memcpy(slice[@intCast(string_index)..][0..name.len], name);2753 @memcpy(storage[@intCast(string_index)..][0..slice.len], slice);
2744 slice[@intCast(string_index + name.len)] = 0;2754 storage[@intCast(string_index + slice.len)] = 0;
2745 }2755 }
27462756
2747 break :name .{ .long = string_gop.value_ptr.* };2757 return .{ .long = string_gop.value_ptr.* };
2748 } else .{ .short = name };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}
27502765
2751/// `len` does not include null terminators2766/// `len` does not include null terminators
...@@ -2776,37 +2791,43 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {...@@ -2776,37 +2791,43 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {
2776 return @fromBackingInt(@intCast(gop.key_ptr.*));2791 return @fromBackingInt(@intCast(gop.key_ptr.*));
2777}2792}
27782793
2779const GlobalOptions = struct {2794const ExternLibName = union(enum) {
2780 name: []const u8,2795 // Symbol can be supplied from anywhere
2781 lib_name: ?[]const u8 = null,2796 any,
2782 type: Symbol.Type = .unknown,2797 // Symbol can be supplied by any LibC input
2783 dll_storage_class: Symbol.DllStorageClass = .default,2798 lib_c,
2799 // Symbol must be supplied by a specific input
2800 explicit: String,
2784};2801};
27852802
2803const FmtExternLibName = struct { coff: *Coff, lib_name: ExternLibName };
2804
2805fn fmtExternLibName(coff: *Coff, lib_name: ExternLibName) std.fmt.Alt(FmtExternLibName, formatExternLibName) {
2806 return .{ .data = .{ .coff = coff, .lib_name = lib_name } };
2807}
2808
2809fn 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
2786fn getOrPutGlobalSymbol(2817fn getOrPutGlobalSymbol(
2787 coff: *Coff,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) !std.array_hash_map.Auto(String, Global).GetOrPutResult {2825) !std.array_hash_map.Auto(String, Global).GetOrPutResult {
2790 const comp = coff.base.comp;2826 const comp = coff.base.comp;
2791 const gpa = comp.gpa;2827 const gpa = comp.gpa;
2792 try coff.symbols.ensureUnusedCapacity(gpa, 1);2828 try coff.symbols.ensureUnusedCapacity(gpa, 1);
27932829
2794 const lib_name: String.Optional = if (opts.lib_name) |lib_name| lib_name: {2830 const sym_gop = try coff.globals.getOrPut(gpa, opts.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));
2810 if (!sym_gop.found_existing) {2831 if (!sym_gop.found_existing) {
2811 const si = coff.addSymbolAssumeCapacity();2832 const si = coff.addSymbolAssumeCapacity();
2812 const sym = si.get(coff);2833 const sym = si.get(coff);
...@@ -2815,11 +2836,11 @@ fn getOrPutGlobalSymbol(...@@ -2815,11 +2836,11 @@ fn getOrPutGlobalSymbol(
2815 sym.flags.dll_storage_class = opts.dll_storage_class;2836 sym.flags.dll_storage_class = opts.dll_storage_class;
2816 sym_gop.value_ptr.* = .{2837 sym_gop.value_ptr.* = .{
2817 .si = si,2838 .si = si,
2818 .lib_name = lib_name,2839 .lib_name = opts.lib_name,
2819 };2840 };
2820 coff.synth_prog_node.increaseEstimatedTotalItems(1);2841 coff.synth_prog_node.increaseEstimatedTotalItems(1);
28212842
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 }
28242845
2825 return sym_gop;2846 return sym_gop;
...@@ -2832,8 +2853,36 @@ fn getDefinedGlobal(coff: *Coff, name: []const u8) Symbol.Index {...@@ -2832,8 +2853,36 @@ fn getDefinedGlobal(coff: *Coff, name: []const u8) Symbol.Index {
2832 return .null;2853 return .null;
2833}2854}
28342855
2835pub fn globalSymbol(coff: *Coff, opts: GlobalOptions) !Symbol.Index {2856pub fn globalSymbol(coff: *Coff, opts: struct {
2836 const gop = try coff.getOrPutGlobalSymbol(opts);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 return gop.value_ptr.si;2886 return gop.value_ptr.si;
2838}2887}
28392888
...@@ -3107,7 +3156,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {...@@ -3107,7 +3156,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void {
3107 coff.targetStore(coff.secondLinkerMemberNumSymbolsPtr(), @backingInt(mfli) + 1);3156 coff.targetStore(coff.secondLinkerMemberNumSymbolsPtr(), @backingInt(mfli) + 1);
3108 if (!needs_sort) {3157 if (!needs_sort) {
3109 @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]);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 slice[new_header_size + coff.lib_string_len + name_slice.len] = 0;3160 slice[new_header_size + coff.lib_string_len + name_slice.len] = 0;
3112 } else if (!old_needs_sort) {3161 } else if (!old_needs_sort) {
3113 // The entire string table is rebuilt in flushMember after sorting3162 // The entire string table is rebuilt in flushMember after sorting
...@@ -3136,9 +3185,8 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {...@@ -3136,9 +3185,8 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {
3136 const entry = coff.symbolTableEntryPtr(sti.*) orelse entry: {3185 const entry = coff.symbolTableEntryPtr(sti.*) orelse entry: {
3137 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =3186 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =
3138 if (sym.gmi != .none) blk: {3187 if (sym.gmi != .none) blk: {
3139 const name = sym.gmi.name(coff);
3140 break :blk .{3188 break :blk .{
3141 try coff.getOrPutSymbolName(name.toSlice(coff), name),3189 try coff.getOrPutSymbolName(.{ .string = sym.gmi.name(coff) }),
3142 @intFromBool(sym.flags.weak_external_strat != .none),3190 @intFromBool(sym.flags.weak_external_strat != .none),
3143 if (Symbol.Index.text.get(coff).section_number == sym.section_number)3191 if (Symbol.Index.text.get(coff).section_number == sym.section_number)
3144 .FUNCTION3192 .FUNCTION
...@@ -3147,7 +3195,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {...@@ -3147,7 +3195,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {
3147 };3195 };
3148 } else blk: switch (coff.getNode(sym.ni.unwrap().?)) {3196 } else blk: switch (coff.getNode(sym.ni.unwrap().?)) {
3149 .image_section => .{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 1,3199 1,
3152 .NULL,3200 .NULL,
3153 },3201 },
...@@ -3156,7 +3204,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {...@@ -3156,7 +3204,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {
3156 const ip = &zcu.intern_pool;3204 const ip = &zcu.intern_pool;
3157 const nav = ip.getNav(nmi.navIndex(coff));3205 const nav = ip.getNav(nmi.navIndex(coff));
3158 break :blk .{3206 break :blk .{
3159 try coff.getOrPutSymbolName(nav.fqn.toSlice(ip), null),3207 try coff.getOrPutSymbolName(.{ .slice = nav.fqn.toSlice(ip) }),
3160 0,3208 0,
3161 if (ip.isFunctionType(nav.resolved.?.type)) .FUNCTION else .NULL,3209 if (ip.isFunctionType(nav.resolved.?.type)) .FUNCTION else .NULL,
3162 };3210 };
...@@ -3165,7 +3213,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {...@@ -3165,7 +3213,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {
3165 var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined;3213 var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined;
3166 const name = std.mem.print(&name_buf, "__anon_{d}", .{umi}) catch unreachable;3214 const name = std.mem.print(&name_buf, "__anon_{d}", .{umi}) catch unreachable;
3167 break :blk .{3215 break :blk .{
3168 try coff.getOrPutSymbolName(name, null),3216 try coff.getOrPutSymbolName(.{ .slice = name }),
3169 0,3217 0,
3170 .NULL,3218 .NULL,
3171 };3219 };
...@@ -3179,9 +3227,8 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {...@@ -3179,9 +3227,8 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void {
3179 lazy_sym.kind, mi,3227 lazy_sym.kind, mi,
3180 }) catch unreachable;3228 }) catch unreachable;
31813229
3182 const string = try coff.getOrPutString(name);
3183 break :blk .{3230 break :blk .{
3184 try coff.getOrPutSymbolName(string.toSlice(coff), string),3231 try coff.getOrPutSymbolName(.{ .slice = name }),
3185 0,3232 0,
3186 if (tag == .lazy_code) .FUNCTION else .NULL,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,8 +3459,8 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S
3412 if (coff.targetEndian() != native_endian)3459 if (coff.targetEndian() != native_endian)
3413 std.mem.byteSwapAllFields(std.coff.SectionHeader, section);3460 std.mem.byteSwapAllFields(std.coff.SectionHeader, section);
34143461
3415 const name_slice = name.toSlice(coff);
3416 if (coff.isImage()) {3462 if (coff.isImage()) {
3463 const name_slice = name.toSlice(coff);
3417 @memcpy(section.name[0..name_slice.len], name_slice);3464 @memcpy(section.name[0..name_slice.len], name_slice);
3418 @memset(section.name[name_slice.len..], 0);3465 @memset(section.name[name_slice.len..], 0);
3419 switch (coff.optionalHeaderPtr()) {3466 switch (coff.optionalHeaderPtr()) {
...@@ -3423,7 +3470,7 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S...@@ -3423,7 +3470,7 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S
3423 ),3470 ),
3424 }3471 }
3425 } else {3472 } else {
3426 (try coff.getOrPutSymbolName(name_slice, name)).store(coff, &section.name);3473 (try coff.getOrPutSymbolName(.{ .string = name })).store(coff, &section.name);
3427 try coff.pendingSymbolTableEntry(si);3474 try coff.pendingSymbolTableEntry(si);
3428 }3475 }
34293476
...@@ -3542,21 +3589,26 @@ fn objectSectionMapIndex(...@@ -3542,21 +3589,26 @@ fn objectSectionMapIndex(
3542 attributes: ObjectSectionAttributes,3589 attributes: ObjectSectionAttributes,
3543) !Node.ObjectSectionMapIndex {3590) !Node.ObjectSectionMapIndex {
3544 const gpa = coff.base.comp.gpa;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;
35533592
3554 const object_section_gop = try coff.object_section_table.getOrPut(gpa, name);3593 const object_section_gop = try coff.object_section_table.getOrPut(gpa, name);
3555 const osmi: Node.ObjectSectionMapIndex = @fromBackingInt(@intCast(object_section_gop.index));3594 const osmi: Node.ObjectSectionMapIndex = @fromBackingInt(@intCast(object_section_gop.index));
3556 const sym = if (!object_section_gop.found_existing) sym: {3595 const sym = if (!object_section_gop.found_existing) sym: {
3557 try coff.ensureUnusedStringCapacity(name_slice.len);3596 const name_slice, const parent_name = blk: {
3558 const parent_name = coff.getOrPutStringAssumeCapacity(coff.objectSectionParentName(name_slice));3597 var name_slice = name.toSlice(coff);
3559 const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, effective_attributes)).symbol(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 try coff.nodes.ensureUnusedCapacity(gpa, 1);3612 try coff.nodes.ensureUnusedCapacity(gpa, 1);
3561 try coff.symbols.ensureUnusedCapacity(gpa, 1);3613 try coff.symbols.ensureUnusedCapacity(gpa, 1);
3562 const parent_ni = parent.node(coff);3614 const parent_ni = parent.node(coff);
...@@ -3608,7 +3660,7 @@ fn objectSectionMapIndex(...@@ -3608,7 +3660,7 @@ fn objectSectionMapIndex(
3608 name,3660 name,
3609 .object,3661 .object,
3610 .fromFlags(sym.section_number.header(coff).flags),3662 .fromFlags(sym.section_number.header(coff).flags),
3611 effective_attributes,3663 attributes,
3612 );3664 );
36133665
3614 return osmi;3666 return osmi;
...@@ -4542,7 +4594,7 @@ fn loadObject(...@@ -4542,7 +4594,7 @@ fn loadObject(
4542 },4594 },
4543 .external => {4595 .external => {
4544 const global_gop = try coff.getOrPutGlobalSymbol(.{4596 const global_gop = try coff.getOrPutGlobalSymbol(.{
4545 .name = symbol.name.toSlice(coff),4597 .name = symbol.name,
4546 });4598 });
45474599
4548 // TODO: What if the same symbol is incorrectly defined twice in this obj?4600 // TODO: What if the same symbol is incorrectly defined twice in this obj?
...@@ -4749,7 +4801,7 @@ fn loadObject(...@@ -4749,7 +4801,7 @@ fn loadObject(
4749 continue;4801 continue;
4750 },4802 },
4751 .weak_external => |alias_index| {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 symbol.si = global_gop.value_ptr.si;4805 symbol.si = global_gop.value_ptr.si;
4754 if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) {4806 if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) {
4755 const sym = symbol.si.get(coff);4807 const sym = symbol.si.get(coff);
...@@ -4788,7 +4840,7 @@ fn loadObject(...@@ -4788,7 +4840,7 @@ fn loadObject(
4788 break :sym value;4840 break :sym value;
4789 },4841 },
4790 .external => |value| {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 symbol.si = global_gop.value_ptr.si;4844 symbol.si = global_gop.value_ptr.si;
4793 if (global_gop.found_existing)4845 if (global_gop.found_existing)
4794 return coff.failMultipleDefinitions(4846 return coff.failMultipleDefinitions(
...@@ -4824,7 +4876,7 @@ fn loadObject(...@@ -4824,7 +4876,7 @@ fn loadObject(
4824 },4876 },
4825 .external => {4877 .external => {
4826 assert(index != section.comdat_psi.unwrap());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 symbol.si = global_gop.value_ptr.si;4880 symbol.si = global_gop.value_ptr.si;
48294881
4830 const sym = symbol.si.get(coff);4882 const sym = symbol.si.get(coff);
...@@ -4908,7 +4960,7 @@ fn loadObject(...@@ -4908,7 +4960,7 @@ fn loadObject(
4908 assert(symbol.section_number == .UNDEFINED);4960 assert(symbol.section_number == .UNDEFINED);
4909 switch (symbol.value) {4961 switch (symbol.value) {
4910 .external => |size| {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 symbol.si = global_gop.value_ptr.si;4964 symbol.si = global_gop.value_ptr.si;
4913 if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) {4965 if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) {
4914 const sym = symbol.si.get(coff);4966 const sym = symbol.si.get(coff);
...@@ -5963,12 +6015,12 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -5963,12 +6015,12 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
5963 break :task;6015 break :task;
5964 }6016 }
5965 if (coff.pending_input) |pending_iami| {6017 if (coff.pending_input) |pending_iami| {
5966 const name_slice = pending_iami.member(coff).name.toSlice(coff);
5967 const sub_prog_node = coff.input_prog_node.start(6018 const sub_prog_node = coff.input_prog_node.start(
5968 name_slice,6019 pending_iami.member(coff).name.toSlice(coff),
5969 0,6020 0,
5970 );6021 );
5971 defer sub_prog_node.end();6022 defer sub_prog_node.end();
6023
5972 coff.pending_input = null;6024 coff.pending_input = null;
5973 coff.flushInputMember(pending_iami) catch |err| switch (err) {6025 coff.flushInputMember(pending_iami) catch |err| switch (err) {
5974 error.OutOfMemory => return error.OutOfMemory,6026 error.OutOfMemory => return error.OutOfMemory,
...@@ -5976,7 +6028,7 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -5976,7 +6028,7 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
5976 "linker failed to load archive member '{f}{f}': {t}",6028 "linker failed to load archive member '{f}{f}': {t}",
5977 .{6029 .{
5978 pending_iami.member(coff).iai.path(coff),6030 pending_iami.member(coff).iai.path(coff),
5979 fmtMemberNameString(name_slice),6031 fmtMemberNameString(pending_iami.member(coff).name.toSlice(coff)),
5980 e,6032 e,
5981 },6033 },
5982 ),6034 ),
...@@ -6246,9 +6298,9 @@ fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !v...@@ -6246,9 +6298,9 @@ fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !v
6246 assert(sym.section_number == .UNDEFINED);6298 assert(sym.section_number == .UNDEFINED);
6247 assert(sym.loc_relocs == .none);6299 assert(sym.loc_relocs == .none);
62486300
6249 log.debug("aliasGlobal({s}, {?s}) {d}->{d} ({?s})", .{6301 log.debug("aliasGlobal({s}, {f}) {d}->{d} ({?s})", .{
6250 gmi.name(coff).toSlice(coff),6302 gmi.name(coff).toSlice(coff),
6251 gmi.libName(coff).toSlice(coff),6303 fmtExternLibName(coff, gmi.libName(coff)),
6252 si,6304 si,
6253 alias_si,6305 alias_si,
6254 if (alias_sym.gmi != .none) alias_sym.gmi.name(coff).toSlice(coff) else null,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,10 +6338,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6286 const si = gmi.symbol(coff);6338 const si = gmi.symbol(coff);
62876339
6288 log.debug(6340 log.debug(
6289 "flushGlobal({s}, {?s}) = n{d} {d}@{d}",6341 "flushGlobal({s}, {f}) = n{d} {d}@{d}",
6290 .{6342 .{
6291 name.toSlice(coff),6343 name.toSlice(coff),
6292 gmi.libName(coff).toSlice(coff),6344 fmtExternLibName(coff, gmi.libName(coff)),
6293 si.get(coff).ni,6345 si.get(coff).ni,
6294 si,6346 si,
6295 si.get(coff).section_number,6347 si.get(coff).section_number,
...@@ -6322,16 +6374,18 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6322,16 +6374,18 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
63226374
6323 const import: Import = import: {6375 const import: Import = import: {
6324 const sym = si.get(coff);6376 const sym = si.get(coff);
6325 const name_slice = name.toSlice(coff);6377 const imp_match, const name_len = blk: {
6326 const imp_match = std.mem.startsWith(u8, name_slice, imp_prefix);6378 const name_slice = name.toSlice(coff);
6379 break :blk .{ std.mem.startsWith(u8, name_slice, imp_prefix), name_slice.len };
6380 };
63276381
6328 // Globals may have the __imp_ prefix already if they are undef externals from another input.6382 // Globals may have the __imp_ prefix already if they are undef externals from another input.
6329 assert(sym.flags.dll_storage_class != .dllexport);6383 assert(sym.flags.dll_storage_class != .dllexport);
6330 const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport)6384 const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport)
6331 .{ name, imp_match }6385 .{ name, imp_match }
6332 else name: {6386 else name: {
6333 try coff.ensureUnusedStringCapacity(imp_prefix.len + name_slice.len);6387 try coff.ensureUnusedStringCapacity(imp_prefix.len + name_len);
6334 const imp_name = try gpa.print(imp_prefix ++ "{s}", .{name_slice});6388 const imp_name = try gpa.print(imp_prefix ++ "{s}", .{name.toSlice(coff)});
6335 defer gpa.free(imp_name);6389 defer gpa.free(imp_name);
6336 break :name .{ coff.getOrPutStringAssumeCapacity(imp_name), true };6390 break :name .{ coff.getOrPutStringAssumeCapacity(imp_name), true };
6337 };6391 };
...@@ -6364,68 +6418,73 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6364,68 +6418,73 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6364 while (true) {6418 while (true) {
6365 const archive_sym = &coff.input_archive_symbols.items[@backingInt(iter)];6419 const archive_sym = &coff.input_archive_symbols.items[@backingInt(iter)];
6366 const member = &coff.input_archive_members.items[@backingInt(archive_sym.iami)];6420 const member = &coff.input_archive_members.items[@backingInt(archive_sym.iami)];
6367 member: switch (member.content) {6421 const lib_name_matches = match: switch (gmi.libName(coff)) {
6368 .object => if (!member.flags.is_loaded) {6422 .any => true,
6369 if (gmi.libName(coff).unwrap()) |lib_name|6423 .lib_c => {
6370 if (!std.ascii.eqlIgnoreCase(6424 // TODO: Need a flag to indicate if this member is from a libc archive
6371 lib_name.toSlice(coff),6425 const is_libc_archive = true;
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, '@');
64116426
6412 try coff.ensureUnusedStringCapacity(imp_name.len);6427 break :match is_libc_archive;
6413 break :undecorated coff.getOrPutStringAssumeCapacity(imp_name);6428 },
6414 };6429 .explicit => |lib_name| std.ascii.eqlIgnoreCase(
6430 lib_name.toSlice(coff),
6431 member.iai.path(coff).stem(),
6432 ),
6433 };
64156434
6416 break :name imp_name.toOptional();6435 if (lib_name_matches) {
6417 },6436 switch (member.content) {
6418 .ORDINAL => break :name .none,6437 .object => if (!member.flags.is_loaded) {
6419 else => |t| return comp.link_diags.fail("TODO handle name_type {t}", .{t}),6438 // Try loading the input member and then retry.
6420 };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 };
64216479
6422 break :import .{6480 break :import .{
6423 .lib_name = import.lib_name,6481 .lib_name = import.lib_name,
6424 .name = imp_name,6482 .name = imp_name,
6425 .ordinal_hint = import.import_ordinal_hint,6483 .ordinal_hint = import.import_ordinal_hint,
6426 .kind = if (import.type == .CODE and !is_imp) .thunk else .iat_ptr,6484 .kind = if (import.type == .CODE and !is_imp) .thunk else .iat_ptr,
6427 };6485 };
6428 },6486 },
6487 }
6429 }6488 }
64306489
6431 if (archive_sym.next == iter) break;6490 if (archive_sym.next == iter) break;
...@@ -6442,7 +6501,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6442,7 +6501,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6442 // Convert an unresolved weak external that itself refers to an undef external6501 // Convert an unresolved weak external that itself refers to an undef external
6443 // into a (possibly new) global, so it can be resolved separately.6502 // into a (possibly new) global, so it can be resolved separately.
6444 const alias_gop = try coff.getOrPutGlobalSymbol(.{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 try coff.aliasGlobal(gmi, alias_gop.value_ptr.si);6506 try coff.aliasGlobal(gmi, alias_gop.value_ptr.si);
6448 return true;6507 return true;
...@@ -6462,12 +6521,15 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6462,12 +6521,15 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6462 // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification,6521 // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification,
6463 // which are not in the implib.6522 // which are not in the implib.
6464 if (sym.flags.type != .unknown) {6523 if (sym.flags.type != .unknown) {
6465 if (gmi.libName(coff).unwrap()) |lib_name| break :import .{6524 switch (gmi.libName(coff)) {
6466 .lib_name = lib_name,6525 .explicit => |lib_name| break :import .{
6467 .name = name.toOptional(),6526 .lib_name = lib_name,
6468 .ordinal_hint = 0,6527 .name = name.toOptional(),
6469 .kind = if (sym.flags.type == .code) .thunk else .iat_ptr,6528 .ordinal_hint = 0,
6470 };6529 .kind = if (sym.flags.type == .code) .thunk else .iat_ptr,
6530 },
6531 else => {},
6532 }
6471 }6533 }
64726534
6473 return true;6535 return true;
...@@ -6478,10 +6540,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6478,10 +6540,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
64786540
6479 const target_endian = coff.targetEndian();6541 const target_endian = coff.targetEndian();
6480 const addr_info = coff.targetAddrInfo();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 const gop = try coff.import_table.entries.getOrPutAdapted(6544 const gop = try coff.import_table.entries.getOrPutAdapted(
6483 gpa,6545 gpa,
6484 lib_name,6546 lib_name_slice,
6485 ImportTable.Adapter{ .coff = coff },6547 ImportTable.Adapter{ .coff = coff },
6486 );6548 );
6487 const import_hint_name_align: Alignment = .@"2";6549 const import_hint_name_align: Alignment = .@"2";
...@@ -6493,7 +6555,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6493,7 +6555,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6493 @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2),6555 @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2),
6494 );6556 );
6495 const import_hint_name_table_len =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 const idata_section_ni = coff.import_table.ni.parent(&coff.mf).unwrap().?;6559 const idata_section_ni = coff.import_table.ni.parent(&coff.mf).unwrap().?;
6498 const import_lookup_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{6560 const import_lookup_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{
6499 .size = addr_info.size * 2,6561 .size = addr_info.size * 2,
...@@ -6528,9 +6590,9 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6528,9 +6590,9 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6528 .hint_name_len = @intCast(import_hint_name_table_len),6590 .hint_name_len = @intCast(import_hint_name_table_len),
6529 };6591 };
6530 const import_hint_name_slice = import_hint_name_table_ni.slice(&coff.mf);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);6593 @memcpy(import_hint_name_slice[0..lib_name_slice.len], lib_name_slice);
6532 @memcpy(import_hint_name_slice[lib_name.len..][0..".dll".len], ".dll");6594 @memcpy(import_hint_name_slice[lib_name_slice.len..][0..".dll".len], ".dll");
6533 @memset(import_hint_name_slice[lib_name.len + ".dll".len ..], 0);6595 @memset(import_hint_name_slice[lib_name_slice.len + ".dll".len ..], 0);
6534 coff.nodes.appendAssumeCapacity(.{ .import_lookup_table = @fromBackingInt(@intCast(gop.index)) });6596 coff.nodes.appendAssumeCapacity(.{ .import_lookup_table = @fromBackingInt(@intCast(gop.index)) });
6535 coff.nodes.appendAssumeCapacity(.{ .import_address_table = @fromBackingInt(@intCast(gop.index)) });6597 coff.nodes.appendAssumeCapacity(.{ .import_address_table = @fromBackingInt(@intCast(gop.index)) });
6536 coff.nodes.appendAssumeCapacity(.{ .import_hint_name_table = @fromBackingInt(@intCast(gop.index)) });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,7 +6617,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
65556617
6556 log.debug(6618 log.debug(
6557 "flushGlobalImport({s}, {?s}, {d}, {s})",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 );
65606622
6561 const iat_symbol_gop = try coff.import_table.iat_symbol_indices.getOrPut(gpa, .{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,8 +7724,10 @@ fn fmtGlobalName(coff: *Coff, gmi: Node.GlobalMapIndex) std.fmt.Alt(FmtGlobalNam
7662fn globalNameEscape(data: FmtGlobalName, w: *std.Io.Writer) std.Io.Writer.Error!void {7724fn globalNameEscape(data: FmtGlobalName, w: *std.Io.Writer) std.Io.Writer.Error!void {
7663 if (data.gmi == .none) return;7725 if (data.gmi == .none) return;
7664 try w.writeAll(data.gmi.name(data.coff).toSlice(data.coff));7726 try w.writeAll(data.gmi.name(data.coff).toSlice(data.coff));
7665 if (data.gmi.libName(data.coff).unwrap()) |lib_name|7727 switch (data.gmi.libName(data.coff)) {
7666 try w.print("({s})", .{lib_name.toSlice(data.coff)});7728 .explicit => |lib_name| try w.print(" ({s}.dll)", .{lib_name.toSlice(data.coff)}),
7729 else => {},
7730 }
7667}7731}
76687732
7669fn printNodeName(7733fn printNodeName(
...@@ -7705,12 +7769,7 @@ fn printNodeName(...@@ -7705,12 +7769,7 @@ fn printNodeName(
7705 inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{7769 inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{
7706 smi.name(coff).toSlice(coff),7770 smi.name(coff).toSlice(coff),
7707 }),7771 }),
7708 .import_thunk,7772 .import_thunk => |gmi| try w.print("({f})", .{fmtGlobalName(coff, gmi)}),
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 },
7714 .nav => |nmi| {7773 .nav => |nmi| {
7715 const zcu = coff.base.comp.zcu.?;7774 const zcu = coff.base.comp.zcu.?;
7716 const ip = &zcu.intern_pool;7775 const ip = &zcu.intern_pool;
...@@ -7736,11 +7795,7 @@ fn printNodeName(...@@ -7736,11 +7795,7 @@ fn printNodeName(
7736 }),7795 }),
7737 .builtin => |si| {7796 .builtin => |si| {
7738 const sym = si.get(coff);7797 const sym = si.get(coff);
7739 if (sym.gmi != .none) {7798 if (sym.gmi != .none) try w.print("({f})", .{fmtGlobalName(coff, sym.gmi)});
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 }
7744 },7799 },
7745 }7800 }
7746}7801}
src/main.zig+2-8
...@@ -4440,12 +4440,8 @@ fn serve(...@@ -4440,12 +4440,8 @@ fn serve(
4440 continue;4440 continue;
4441 }4441 }
44424442
4443 if (comp.config.output_mode == .Exe) {4443 try comp.makeBinFileWritable();
4444 try comp.makeBinFileWritable();
4445 }
4446
4447 try comp.update(main_progress_node);4444 try comp.update(main_progress_node);
4448
4449 try comp.makeBinFileExecutable();4445 try comp.makeBinFileExecutable();
4450 try serveUpdateResults(&server, comp);4446 try serveUpdateResults(&server, comp);
4451 },4447 },
...@@ -4476,9 +4472,7 @@ fn serve(...@@ -4476,9 +4472,7 @@ fn serve(
4476 try comp.hotCodeSwap(main_progress_node, pid);4472 try comp.hotCodeSwap(main_progress_node, pid);
4477 try serveUpdateResults(&server, comp);4473 try serveUpdateResults(&server, comp);
4478 } else {4474 } else {
4479 if (comp.config.output_mode == .Exe) {4475 try comp.makeBinFileWritable();
4480 try comp.makeBinFileWritable();
4481 }
4482 try comp.update(main_progress_node);4476 try comp.update(main_progress_node);
4483 try comp.makeBinFileExecutable();4477 try comp.makeBinFileExecutable();
4484 try serveUpdateResults(&server, comp);4478 try serveUpdateResults(&server, comp);