| ... | ... | @@ -753,6 +753,10 @@ pub const String = enum(u32) { |
| 753 | 753 | @".text" = 20, |
| 754 | 754 | @".tls$" = 26, |
| 755 | 755 | @".edata" = 32, |
| 756 | @".ctors" = 39, |
| 757 | @".ctors$ZZZ" = 46, |
| 758 | @".dtors" = 57, |
| 759 | @".dtors$ZZZ" = 64, |
| 756 | 760 | _, |
| 757 | 761 | |
| 758 | 762 | pub const Optional = enum(u32) { |
| ... | ... | @@ -761,6 +765,8 @@ pub const String = enum(u32) { |
| 761 | 765 | @".text" = @intFromEnum(String.@".text"), |
| 762 | 766 | @".tls$" = @intFromEnum(String.@".tls$"), |
| 763 | 767 | @".edata" = @intFromEnum(String.@".edata"), |
| 768 | @".dtors" = @intFromEnum(String.@".dtors"), |
| 769 | @".dtors$ZZZ" = @intFromEnum(String.@".dtors$ZZZ"), |
| 764 | 770 | none = std.math.maxInt(u32), |
| 765 | 771 | _, |
| 766 | 772 | |
| ... | ... | @@ -1506,6 +1512,7 @@ fn create( |
| 1506 | 1512 | section_align, |
| 1507 | 1513 | std.fs.path.basename(path.sub_path), |
| 1508 | 1514 | ); |
| 1515 | try coff.initBuiltins(); |
| 1509 | 1516 | return coff; |
| 1510 | 1517 | } |
| 1511 | 1518 | |
| ... | ... | @@ -2017,15 +2024,58 @@ fn initHeaders( |
| 2017 | 2024 | .{ .read = true, .write = !is_image }, |
| 2018 | 2025 | ); |
| 2019 | 2026 | } |
| 2027 | } |
| 2020 | 2028 | |
| 2021 | | // Linker-supplied symbols |
| 2022 | | { |
| 2023 | | const target = &comp.root_mod.resolved_target.result; |
| 2024 | | if (is_image and target.isMinGW()) { |
| 2029 | pub fn initBuiltins(coff: *Coff) !void { |
| 2030 | const comp = coff.base.comp; |
| 2031 | const gpa = comp.gpa; |
| 2032 | const target = &comp.root_mod.resolved_target.result; |
| 2033 | if (coff.isImage() and target.isMinGW() and comp.config.link_libc) { |
| 2034 | try coff.symbols.ensureUnusedCapacity(gpa, 5); |
| 2035 | try coff.globals.ensureUnusedCapacity(gpa, 2); |
| 2036 | try coff.nodes.ensureUnusedCapacity(gpa, 3); |
| 2037 | |
| 2038 | { |
| 2025 | 2039 | const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data }); |
| 2026 | 2040 | const sym = si.get(coff); |
| 2027 | 2041 | sym.ni = Node.known.header; |
| 2028 | 2042 | } |
| 2043 | |
| 2044 | const lists: []const struct { global: []const u8, start: String, end: String } = &.{ |
| 2045 | .{ .global = "__CTOR_LIST__", .start = .@".ctors", .end = .@".ctors$ZZZ" }, |
| 2046 | .{ .global = "__DTOR_LIST__", .start = .@".dtors", .end = .@".dtors$ZZZ" }, |
| 2047 | }; |
| 2048 | |
| 2049 | for (lists) |list| { |
| 2050 | const addr_info = coff.targetAddrInfo(); |
| 2051 | const start_osmi = try coff.objectSectionMapIndex(list.start, addr_info.alignment, .{ .read = true }); |
| 2052 | const end_osmi = try coff.objectSectionMapIndex(list.end, addr_info.alignment, .{ .read = true }); |
| 2053 | |
| 2054 | const start_sym = start_osmi.symbol(coff).get(coff); |
| 2055 | try start_sym.ni.resize(&coff.mf, gpa, addr_info.size); |
| 2056 | const start_slice = start_sym.ni.slice(&coff.mf); |
| 2057 | switch (addr_info.magic) { |
| 2058 | _ => unreachable, |
| 2059 | inline .PE32, .@"PE32+" => |t| { |
| 2060 | const addr: *TargetAddr(t) = @ptrCast(@alignCast(start_slice)); |
| 2061 | // For __CTOR_LIST__ -1 indicates that the list is null terminated. |
| 2062 | // For __DTOR_LIST__, this value is ignored. |
| 2063 | coff.targetStore(addr, std.math.maxInt(TargetAddr(t))); |
| 2064 | }, |
| 2065 | } |
| 2066 | |
| 2067 | // Any .(c|d)tor$(.*) input sections will merge in between these sections |
| 2068 | // TODO: is it guaranteed that there will be no padding between those nodes? |
| 2069 | |
| 2070 | const end_sym = end_osmi.symbol(coff).get(coff); |
| 2071 | try end_sym.ni.resize(&coff.mf, gpa, addr_info.size); |
| 2072 | @memset(end_sym.ni.slice(&coff.mf), 0); |
| 2073 | |
| 2074 | const list_si = try coff.globalSymbol(.{ .name = list.global, .type = .data }); |
| 2075 | const list_sym = list_si.get(coff); |
| 2076 | list_sym.ni = start_sym.ni; |
| 2077 | list_sym.section_number = start_sym.section_number; |
| 2078 | } |
| 2029 | 2079 | } |
| 2030 | 2080 | } |
| 2031 | 2081 | |
| ... | ... | @@ -2146,6 +2196,28 @@ fn computeSymbolSectionOffset(coff: *Coff, sym: *const Symbol) u32 { |
| 2146 | 2196 | pub inline fn targetEndian(_: *const Coff) std.lang.Endian { |
| 2147 | 2197 | return .little; |
| 2148 | 2198 | } |
| 2199 | |
| 2200 | fn targetAddrInfo(coff: *Coff) struct { |
| 2201 | size: u64, |
| 2202 | alignment: std.mem.Alignment, |
| 2203 | magic: std.coff.OptionalHeader.Magic, |
| 2204 | } { |
| 2205 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); |
| 2206 | switch (magic) { |
| 2207 | _ => unreachable, |
| 2208 | .PE32 => return .{ .size = 4, .alignment = .@"4", .magic = magic }, |
| 2209 | .@"PE32+" => return .{ .size = 8, .alignment = .@"8", .magic = magic }, |
| 2210 | } |
| 2211 | } |
| 2212 | |
| 2213 | fn TargetAddr(comptime magic: std.coff.OptionalHeader.Magic) type { |
| 2214 | return switch (magic) { |
| 2215 | _ => comptime unreachable, |
| 2216 | .PE32 => u32, |
| 2217 | .@"PE32+" => u64, |
| 2218 | }; |
| 2219 | } |
| 2220 | |
| 2149 | 2221 | fn targetLoad(coff: *const Coff, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { |
| 2150 | 2222 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; |
| 2151 | 2223 | return switch (@typeInfo(Child)) { |
| ... | ... | @@ -4072,7 +4144,19 @@ fn loadObject( |
| 4072 | 4144 | coff.synth_prog_node.increaseEstimatedTotalItems(1); |
| 4073 | 4145 | } |
| 4074 | 4146 | |
| 4075 | | for (pending_symbols.values(), pending_symbols.keys(), 0..) |*symbol, index, psi| { |
| 4147 | for (pending_symbols.values(), pending_symbols.keys(), 0..) |*symbol, index, i| { |
| 4148 | defer log.debug("addInputSymbol({s}, 0x{x}, {t}=0x{x}, {d}) = {d}@{d}", .{ |
| 4149 | symbol.name.toSlice(coff), |
| 4150 | index, |
| 4151 | symbol.value, |
| 4152 | symbol.section_number, |
| 4153 | switch (symbol.value) { |
| 4154 | inline else => |v| v, |
| 4155 | }, |
| 4156 | symbol.si, |
| 4157 | symbol.si.get(coff).section_number, |
| 4158 | }); |
| 4159 | |
| 4076 | 4160 | const section = switch (symbol.section_number) { |
| 4077 | 4161 | .UNDEFINED => switch (symbol.value) { |
| 4078 | 4162 | .section, |
| ... | ... | @@ -4101,7 +4185,7 @@ fn loadObject( |
| 4101 | 4185 | ); |
| 4102 | 4186 | |
| 4103 | 4187 | if (alias.si == .null) { |
| 4104 | | alias.weak_external_psi = .wrap(@intCast(psi)); |
| 4188 | alias.weak_external_psi = .wrap(@intCast(i)); |
| 4105 | 4189 | } else { |
| 4106 | 4190 | sym.setValue(.{ .alias_si = alias.si }); |
| 4107 | 4191 | } |
| ... | ... | @@ -4137,9 +4221,9 @@ fn loadObject( |
| 4137 | 4221 | } |
| 4138 | 4222 | } |
| 4139 | 4223 | |
| 4140 | | if (symbol.weak_external_psi.unwrap()) |i| { |
| 4224 | if (symbol.weak_external_psi.unwrap()) |weak_external_i| { |
| 4141 | 4225 | assert(symbol.si != .null); |
| 4142 | | pending_symbols.values()[i].si.get(coff).value = .{ .alias_si = symbol.si }; |
| 4226 | pending_symbols.values()[weak_external_i].si.get(coff).setValue(.{ .alias_si = symbol.si }); |
| 4143 | 4227 | } |
| 4144 | 4228 | |
| 4145 | 4229 | if (section.si != symbol.si) { |
| ... | ... | @@ -4157,17 +4241,6 @@ fn loadObject( |
| 4157 | 4241 | }); |
| 4158 | 4242 | sym.section_number = section.si.get(coff).section_number; |
| 4159 | 4243 | } |
| 4160 | | |
| 4161 | | log.debug("addInputSymbol({s}, 0x{x}, {t}=0x{x}) = {d}@{d}", .{ |
| 4162 | | symbol.name.toSlice(coff), |
| 4163 | | index, |
| 4164 | | symbol.value, |
| 4165 | | switch (symbol.value) { |
| 4166 | | inline else => |v| v, |
| 4167 | | }, |
| 4168 | | symbol.si, |
| 4169 | | section.si.get(coff).section_number, |
| 4170 | | }); |
| 4171 | 4244 | } |
| 4172 | 4245 | |
| 4173 | 4246 | const relocation_size = std.coff.Relocation.sizeOf(); |
| ... | ... | @@ -4979,11 +5052,11 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 4979 | 5052 | |
| 4980 | 5053 | var start_i: usize = 0; |
| 4981 | 5054 | var num_unique_references: usize = 1; |
| 4982 | | for (undef_indices.items[0..], 0..) |reloc_i, i| { |
| 5055 | for (0..undef_indices.items.len) |i| { |
| 4983 | 5056 | const target = coff.relocs.items[undef_indices.items[start_i]].target; |
| 4984 | | if (target != coff.relocs.items[reloc_i].target or i == undef_indices.items.len - 1) { |
| 5057 | if (i == undef_indices.items.len - 1 or target != coff.relocs.items[undef_indices.items[i + 1]].target) { |
| 4985 | 5058 | defer { |
| 4986 | | start_i = i; |
| 5059 | start_i = i + 1; |
| 4987 | 5060 | num_unique_references = 1; |
| 4988 | 5061 | } |
| 4989 | 5062 | |
| ... | ... | @@ -4995,7 +5068,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 4995 | 5068 | try err.addMsg("undefined symbol: {s}", .{target_sym.gmi.globalName(coff).name.toSlice(coff)}); |
| 4996 | 5069 | |
| 4997 | 5070 | var prev_loc_si: Symbol.Index = .null; |
| 4998 | | for (undef_indices.items[start_i..][0..@max(1, i - start_i)]) |reference_i| { |
| 5071 | for (undef_indices.items[start_i .. i + 1]) |reference_i| { |
| 4999 | 5072 | if (err.note_slot == num_full_notes) break; |
| 5000 | 5073 | |
| 5001 | 5074 | const loc_si = coff.relocs.items[reference_i].loc; |
| ... | ... | @@ -5007,7 +5080,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 5007 | 5080 | .input_section => |isi| { |
| 5008 | 5081 | const other_ioi = isi.input(coff); |
| 5009 | 5082 | if (loc_sym.gmi == .none) { |
| 5010 | | // TODO: We could report the name here if we interned it in loadObject |
| 5083 | // TODO: We could report non-global names here if we intern them in loadObject |
| 5011 | 5084 | err.addNote("referenced by input '{f}{f}'", .{ |
| 5012 | 5085 | other_ioi.path(coff).fmtEscapeString(), |
| 5013 | 5086 | fmtMemberNameString(other_ioi.memberName(coff)), |
| ... | ... | @@ -5022,8 +5095,6 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 5022 | 5095 | }, |
| 5023 | 5096 | .import_thunk => |gmi| err.addNote("referenced by import thunk for '{s}'", .{ |
| 5024 | 5097 | gmi.globalName(coff).name.toSlice(coff), |
| 5025 | | // TODO: This won't always have a ZCU |
| 5026 | | //comp.zcu.?.root_mod.fully_qualified_name, |
| 5027 | 5098 | }), |
| 5028 | 5099 | inline .nav, |
| 5029 | 5100 | .uav, |
| ... | ... | @@ -5583,12 +5654,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5583 | 5654 | try coff.symbols.ensureUnusedCapacity(gpa, 1); |
| 5584 | 5655 | |
| 5585 | 5656 | const target_endian = coff.targetEndian(); |
| 5586 | | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); |
| 5587 | | const addr_size: u64, const addr_align: std.mem.Alignment = switch (magic) { |
| 5588 | | _ => unreachable, |
| 5589 | | .PE32 => .{ 4, .@"4" }, |
| 5590 | | .@"PE32+" => .{ 8, .@"8" }, |
| 5591 | | }; |
| 5657 | const addr_info = coff.targetAddrInfo(); |
| 5592 | 5658 | const gop = try coff.import_table.entries.getOrPutAdapted( |
| 5593 | 5659 | gpa, |
| 5594 | 5660 | lib_name, |
| ... | ... | @@ -5606,13 +5672,13 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5606 | 5672 | import_hint_name_align.forward(lib_name.len + ".dll".len + 1); |
| 5607 | 5673 | const idata_section_ni = coff.import_table.ni.parent(&coff.mf); |
| 5608 | 5674 | const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ |
| 5609 | | .size = addr_size * 2, |
| 5610 | | .alignment = addr_align, |
| 5675 | .size = addr_info.size * 2, |
| 5676 | .alignment = addr_info.alignment, |
| 5611 | 5677 | .moved = true, |
| 5612 | 5678 | }); |
| 5613 | 5679 | const import_address_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ |
| 5614 | | .size = addr_size * 2, |
| 5615 | | .alignment = addr_align, |
| 5680 | .size = addr_info.size * 2, |
| 5681 | .alignment = addr_info.alignment, |
| 5616 | 5682 | .moved = true, |
| 5617 | 5683 | }); |
| 5618 | 5684 | const import_address_table_si = coff.addSymbolAssumeCapacity(); |
| ... | ... | @@ -5677,7 +5743,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5677 | 5743 | iat_symbol_gop.value_ptr.* = import_symbol_index; |
| 5678 | 5744 | |
| 5679 | 5745 | gop.value_ptr.len = import_symbol_index + 1; |
| 5680 | | const new_symbol_table_size = addr_size * (import_symbol_index + 2); |
| 5746 | const new_symbol_table_size = addr_info.size * (import_symbol_index + 2); |
| 5681 | 5747 | |
| 5682 | 5748 | const opt_name = import.name.toSlice(coff); |
| 5683 | 5749 | const opt_import_hint_name_index = if (opt_name) |name| blk: { |
| ... | ... | @@ -5704,7 +5770,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5704 | 5770 | |
| 5705 | 5771 | const import_lookup_slice = gop.value_ptr.import_lookup_table_ni.slice(&coff.mf); |
| 5706 | 5772 | const import_address_slice = import_address_table_ni.slice(&coff.mf); |
| 5707 | | switch (magic) { |
| 5773 | switch (addr_info.magic) { |
| 5708 | 5774 | _ => unreachable, |
| 5709 | 5775 | inline .PE32, .@"PE32+" => |ct_magic| { |
| 5710 | 5776 | const Payload = packed union(u31) { |
| ... | ... | @@ -5749,7 +5815,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5749 | 5815 | } |
| 5750 | 5816 | |
| 5751 | 5817 | assert(sym.loc_relocs == .none); |
| 5752 | | const iat_offset: u32 = @intCast(addr_size * iat_symbol_gop.value_ptr.*); |
| 5818 | const iat_offset: u32 = @intCast(addr_info.size * iat_symbol_gop.value_ptr.*); |
| 5753 | 5819 | switch (import.kind) { |
| 5754 | 5820 | .iat_ptr => { |
| 5755 | 5821 | const iat_sym = gop.value_ptr.import_address_table_si.get(coff); |
| ... | ... | @@ -5960,11 +6026,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 5960 | 6026 | switch (magic) { |
| 5961 | 6027 | _ => unreachable, |
| 5962 | 6028 | inline .PE32, .@"PE32+" => |ct_magic| { |
| 5963 | | const Addr = switch (ct_magic) { |
| 5964 | | _ => comptime unreachable, |
| 5965 | | .PE32 => u32, |
| 5966 | | .@"PE32+" => u64, |
| 5967 | | }; |
| 6029 | const Addr = TargetAddr(ct_magic); |
| 5968 | 6030 | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); |
| 5969 | 6031 | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); |
| 5970 | 6032 | const rva = std.mem.nativeTo( |