authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:35-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:26:55-04:00
loga2f4459da80937e8ca2a19d6298c90690f7ddfcd
tree35cd3e5b732295255e286609c72794ff6184ecc9
parent8bf109b0b34d1d97a71a447ab4d79a89125a2de2

Coff: entry point detection and IAT fixes

- Track which symbols reference IAT entries, and update them when the IAT moves - Fix IAT flushMoved logic to account for ordinal entries - Select which entry to use based on subsystem / image type - Add errors for undefined / missing entry points - When linking an image without a zcu, pick an entry point based on which main function was exported - Fix up shifting differently aligned nodes when resizing a node

2 files changed, 167 insertions(+), 69 deletions(-)

src/link/Coff.zig+164-66
...@@ -74,12 +74,12 @@ pending_uavs: std.array_hash_map.Auto(Node.UavMapIndex, struct {...@@ -74,12 +74,12 @@ pending_uavs: std.array_hash_map.Auto(Node.UavMapIndex, struct {
74 alignment: InternPool.Alignment,74 alignment: InternPool.Alignment,
75}),75}),
76relocs: std.ArrayList(Reloc),76relocs: std.ArrayList(Reloc),
77entry: Node.GlobalMapIndex,
77const_prog_node: std.Progress.Node,78const_prog_node: std.Progress.Node,
78synth_prog_node: std.Progress.Node,79synth_prog_node: std.Progress.Node,
79symbol_prog_node: std.Progress.Node,80symbol_prog_node: std.Progress.Node,
80member_prog_node: std.Progress.Node,81member_prog_node: std.Progress.Node,
81input_prog_node: std.Progress.Node,82input_prog_node: std.Progress.Node,
82subsystem: ?std.zig.Subsystem,
83dump_snapshot: bool,83dump_snapshot: bool,
8484
85pub const default_file_alignment: u16 = 0x200;85pub const default_file_alignment: u16 = 0x200;
...@@ -728,10 +728,37 @@ pub const ImportTable = struct {...@@ -728,10 +728,37 @@ pub const ImportTable = struct {
728 import_lookup_table_ni: MappedFile.Node.Index,728 import_lookup_table_ni: MappedFile.Node.Index,
729 import_address_table_si: Symbol.Index,729 import_address_table_si: Symbol.Index,
730 import_hint_name_table_ni: MappedFile.Node.Index,730 import_hint_name_table_ni: MappedFile.Node.Index,
731 // All .iat_ptr globals that reference this table.
732 // This is separate from `iat_symbol_indices` because multiple symbols
733 // can reference to the same iat entry, after name demangling.
734 import_address_table_symbols: std.ArrayList(Symbol.Index),
731 len: u32,735 len: u32,
732 hint_name_len: u32,736 hint_name_len: u32,
733 };737 };
734738
739 pub fn TableEntry(comptime magic: std.coff.OptionalHeader.Magic) type {
740 const Payload = packed union(u31) {
741 ordinal: packed struct(u31) {
742 ordinal: u16,
743 _: u15 = 0,
744 },
745 hint_name_rva: u31,
746 };
747
748 return switch (magic) {
749 _ => comptime unreachable,
750 .PE32 => packed struct(u32) {
751 payload: Payload,
752 is_ordinal: bool,
753 },
754 .@"PE32+" => packed struct(u64) {
755 payload: Payload,
756 _: u32 = 0,
757 is_ordinal: bool,
758 },
759 };
760 }
761
735 const Adapter = struct {762 const Adapter = struct {
736 coff: *Coff,763 coff: *Coff,
737764
...@@ -864,7 +891,8 @@ pub const Symbol = struct {...@@ -864,7 +891,8 @@ pub const Symbol = struct {
864 dll_storage_class: DllStorageClass,891 dll_storage_class: DllStorageClass,
865 // Only defined for .alias_si and .alias_name892 // Only defined for .alias_si and .alias_name
866 weak_external_strat: WeakExternalStrat,893 weak_external_strat: WeakExternalStrat,
867 _: u8 = 0,894 is_entry: bool,
895 _: u7 = 0,
868 },896 },
869 /// Relocations contained within this symbol897 /// Relocations contained within this symbol
870 loc_relocs: Reloc.Index,898 loc_relocs: Reloc.Index,
...@@ -1038,7 +1066,15 @@ pub const Symbol = struct {...@@ -1038,7 +1066,15 @@ pub const Symbol = struct {
1038 }1066 }
10391067
1040 pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff) void {1068 pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff) void {
1041 var ri = si.get(coff).target_relocs;1069 const sym = si.get(coff);
1070
1071 // TODO: Would this be better modeled using an actual reloc? Would need a si for the header
1072 if (sym.flags.is_entry) {
1073 log.debug("updateEntryRVA({d}, 0x{x})", .{ si, sym.rva });
1074 coff.optionalHeaderStandardPtr().address_of_entry_point = sym.rva;
1075 }
1076
1077 var ri = sym.target_relocs;
1042 while (ri != .none) {1078 while (ri != .none) {
1043 const reloc = ri.get(coff);1079 const reloc = ri.get(coff);
1044 assert(reloc.target == si);1080 assert(reloc.target == si);
...@@ -1525,12 +1561,12 @@ fn create(...@@ -1525,12 +1561,12 @@ fn create(
1525 }),1561 }),
1526 .pending_uavs = .empty,1562 .pending_uavs = .empty,
1527 .relocs = .empty,1563 .relocs = .empty,
1564 .entry = .none,
1528 .const_prog_node = .none,1565 .const_prog_node = .none,
1529 .synth_prog_node = .none,1566 .synth_prog_node = .none,
1530 .symbol_prog_node = .none,1567 .symbol_prog_node = .none,
1531 .member_prog_node = .none,1568 .member_prog_node = .none,
1532 .input_prog_node = .none,1569 .input_prog_node = .none,
1533 .subsystem = options.subsystem,
1534 .dump_snapshot = options.enable_link_snapshots,1570 .dump_snapshot = options.enable_link_snapshots,
1535 };1571 };
1536 errdefer coff.deinit();1572 errdefer coff.deinit();
...@@ -1549,6 +1585,11 @@ fn create(...@@ -1549,6 +1585,11 @@ fn create(
1549 major_subsystem_version,1585 major_subsystem_version,
1550 minor_subsystem_version,1586 minor_subsystem_version,
1551 magic,1587 magic,
1588 if (options.subsystem) |s| switch (s) {
1589 .console => .WINDOWS_CUI,
1590 .windows => .WINDOWS_GUI,
1591 else => return error.UnsupportedCOFFSubsystem,
1592 } else .WINDOWS_CUI,
1552 section_align,1593 section_align,
1553 std.fs.path.basename(path.sub_path),1594 std.fs.path.basename(path.sub_path),
1554 );1595 );
...@@ -1619,6 +1660,10 @@ fn isArchive(coff: *const Coff) bool {...@@ -1619,6 +1660,10 @@ fn isArchive(coff: *const Coff) bool {
1619 };1660 };
1620}1661}
16211662
1663fn isExe(coff: *const Coff) bool {
1664 return coff.base.comp.config.output_mode == .Exe;
1665}
1666
1622fn isObj(coff: *const Coff) bool {1667fn isObj(coff: *const Coff) bool {
1623 return coff.base.comp.config.output_mode == .Obj;1668 return coff.base.comp.config.output_mode == .Obj;
1624}1669}
...@@ -1639,6 +1684,7 @@ fn initHeaders(...@@ -1639,6 +1684,7 @@ fn initHeaders(
1639 major_subsystem_version: u16,1684 major_subsystem_version: u16,
1640 minor_subsystem_version: u16,1685 minor_subsystem_version: u16,
1641 magic: std.coff.OptionalHeader.Magic,1686 magic: std.coff.OptionalHeader.Magic,
1687 subsystem: std.coff.Subsystem,
1642 section_align: std.mem.Alignment,1688 section_align: std.mem.Alignment,
1643 file_name: []const u8,1689 file_name: []const u8,
1644) !void {1690) !void {
...@@ -1841,7 +1887,7 @@ fn initHeaders(...@@ -1841,7 +1887,7 @@ fn initHeaders(
1841 .size_of_image = 0,1887 .size_of_image = 0,
1842 .size_of_headers = 0,1888 .size_of_headers = 0,
1843 .checksum = 0,1889 .checksum = 0,
1844 .subsystem = .WINDOWS_CUI,1890 .subsystem = subsystem,
1845 .dll_flags = .{1891 .dll_flags = .{
1846 .HIGH_ENTROPY_VA = true,1892 .HIGH_ENTROPY_VA = true,
1847 .DYNAMIC_BASE = true,1893 .DYNAMIC_BASE = true,
...@@ -1890,7 +1936,7 @@ fn initHeaders(...@@ -1890,7 +1936,7 @@ fn initHeaders(
1890 .size_of_image = 0,1936 .size_of_image = 0,
1891 .size_of_headers = 0,1937 .size_of_headers = 0,
1892 .checksum = 0,1938 .checksum = 0,
1893 .subsystem = .WINDOWS_CUI,1939 .subsystem = subsystem,
1894 .dll_flags = .{1940 .dll_flags = .{
1895 .HIGH_ENTROPY_VA = true,1941 .HIGH_ENTROPY_VA = true,
1896 .DYNAMIC_BASE = true,1942 .DYNAMIC_BASE = true,
...@@ -2079,9 +2125,6 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2079,9 +2125,6 @@ pub fn initBuiltins(coff: *Coff) !void {
2079 const gpa = comp.gpa;2125 const gpa = comp.gpa;
2080 const target = &comp.root_mod.resolved_target.result;2126 const target = &comp.root_mod.resolved_target.result;
2081 if (coff.isImage()) {2127 if (coff.isImage()) {
2082 try coff.symbols.ensureUnusedCapacity(gpa, 1);
2083 try coff.globals.ensureUnusedCapacity(gpa, 1);
2084
2085 const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data });2128 const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data });
2086 const sym = si.get(coff);2129 const sym = si.get(coff);
2087 sym.ni = Node.known.header;2130 sym.ni = Node.known.header;
...@@ -2099,8 +2142,16 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2099,8 +2142,16 @@ pub fn initBuiltins(coff: *Coff) !void {
20992142
2100 for (lists) |list| {2143 for (lists) |list| {
2101 const addr_info = coff.targetAddrInfo();2144 const addr_info = coff.targetAddrInfo();
2102 const start_osmi = try coff.objectSectionMapIndex(list.start, addr_info.alignment, .{ .read = true });2145 const start_osmi = try coff.objectSectionMapIndex(
2103 const end_osmi = try coff.objectSectionMapIndex(list.end, addr_info.alignment, .{ .read = true });2146 list.start,
2147 addr_info.alignment,
2148 .{ .read = true },
2149 );
2150 const end_osmi = try coff.objectSectionMapIndex(
2151 list.end,
2152 addr_info.alignment,
2153 .{ .read = true },
2154 );
21042155
2105 const start_sym = start_osmi.symbol(coff).get(coff);2156 const start_sym = start_osmi.symbol(coff).get(coff);
2106 try start_sym.ni.resize(&coff.mf, gpa, addr_info.size);2157 try start_sym.ni.resize(&coff.mf, gpa, addr_info.size);
...@@ -2460,6 +2511,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {...@@ -2460,6 +2511,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
2460 .type = .unknown,2511 .type = .unknown,
2461 .dll_storage_class = .default,2512 .dll_storage_class = .default,
2462 .weak_external_strat = undefined,2513 .weak_external_strat = undefined,
2514 .is_entry = false,
2463 },2515 },
2464 .loc_relocs = .none,2516 .loc_relocs = .none,
2465 .target_relocs = .none,2517 .target_relocs = .none,
...@@ -2482,14 +2534,14 @@ fn getOrPutString(coff: *Coff, string: []const u8) !String {...@@ -2482,14 +2534,14 @@ fn getOrPutString(coff: *Coff, string: []const u8) !String {
2482fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional {2534fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional {
2483 return (try coff.getOrPutString(string orelse return .none)).toOptional();2535 return (try coff.getOrPutString(string orelse return .none)).toOptional();
2484}2536}
2485fn getString(coff: *Coff, string: []const u8) ?String {2537fn getString(coff: *Coff, string: []const u8) String.Optional {
2486 if (coff.strings.getKeyAdapted(2538 if (coff.strings.getKeyAdapted(
2487 string,2539 string,
2488 std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes },2540 std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes },
2489 )) |key|2541 )) |key|
2490 return @enumFromInt(key)2542 return @as(String, @enumFromInt(key)).toOptional()
2491 else2543 else
2492 return null;2544 return .none;
2493}2545}
24942546
2495/// If the name does not fit in the symbol header, adds it to the symbol table string table.2547/// If the name does not fit in the symbol header, adds it to the symbol table string table.
...@@ -4882,12 +4934,13 @@ fn loadDll(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {...@@ -4882,12 +4934,13 @@ fn loadDll(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {
48824934
4883pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void {4935pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void {
4884 _ = prog_node;4936 _ = prog_node;
4937 const base = coff.base;
4938 const comp = base.comp;
4939
4885 log.debug("prelink()", .{});4940 log.debug("prelink()", .{});
48864941
4887 if (coff.pending_default_libs.items.len > 0) {4942 if (coff.pending_default_libs.items.len > 0) {
4888 // Libs provided by /DEFAULTLIB arguments in objects are searched after all other inputs4943 // Libs provided by /DEFAULTLIB arguments in objects are searched after all other inputs
4889 const base = coff.base;
4890 const comp = base.comp;
4891 const gpa = comp.gpa;4944 const gpa = comp.gpa;
4892 const arena = comp.arena;4945 const arena = comp.arena;
4893 const target = &comp.root_mod.resolved_target.result;4946 const target = &comp.root_mod.resolved_target.result;
...@@ -4949,6 +5002,34 @@ pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void {...@@ -4949,6 +5002,34 @@ pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void {
4949 }5002 }
4950 }5003 }
49515004
5005 if (coff.isImage() and comp.config.link_libc) {
5006 const entries: []const struct { ?[]const u8, []const u8 } = if (coff.isExe())
5007 if (comp.zcu == null) switch (coff.optionalHeaderField(.subsystem)) {
5008 .WINDOWS_CUI => &.{
5009 .{ "main", "mainCRTStartup" },
5010 .{ "wmain", "wmainCRTStartup" },
5011 },
5012 .WINDOWS_GUI => &.{
5013 .{ "WinMain", "WinMainCRTStartup" },
5014 .{ "wWinMain", "wWinMainCRTStartup" },
5015 },
5016 else => unreachable,
5017 } else &.{}
5018 else
5019 &.{.{ null, "_DllMainCRTStartup" }};
5020
5021 for (entries) |entry| {
5022 if (entry[0]) |required_name| {
5023 const str = coff.getString(required_name).unwrap() orelse continue;
5024 const si = coff.globals.get(.{ .name = str, .lib_name = .none }) orelse continue;
5025 if (si.get(coff).ni == .none) continue;
5026 }
5027
5028 const si = try coff.globalSymbol(.{ .name = entry[1], .type = .code });
5029 coff.updateEntry(si.get(coff).gmi);
5030 }
5031 }
5032
4952 coff.inputs_complete = true;5033 coff.inputs_complete = true;
4953}5034}
49545035
...@@ -5241,6 +5322,17 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {...@@ -5241,6 +5322,17 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
5241 const gpa = comp.gpa;5322 const gpa = comp.gpa;
5242 const max_notes = 4;5323 const max_notes = 4;
52435324
5325 if (coff.isImage()) {
5326 if (coff.entry == .none)
5327 comp.link_diags.addError("no entry point defined", .{})
5328 else if (coff.entry.symbol(coff).get(coff).ni == .none) {
5329 comp.link_diags.addError(
5330 "no definition for entry point '{s}' found",
5331 .{coff.entry.globalName(coff).name.toSlice(coff)},
5332 );
5333 }
5334 }
5335
5244 var undef_indices: std.ArrayListUnmanaged(u32) = .empty;5336 var undef_indices: std.ArrayListUnmanaged(u32) = .empty;
5245 for (coff.relocs.items, 0..) |reloc, reloc_i| {5337 for (coff.relocs.items, 0..) |reloc, reloc_i| {
5246 const target_sym = reloc.target.get(coff);5338 const target_sym = reloc.target.get(coff);
...@@ -5988,6 +6080,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -5988,6 +6080,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
5988 .import_lookup_table_ni = import_lookup_table_ni,6080 .import_lookup_table_ni = import_lookup_table_ni,
5989 .import_address_table_si = import_address_table_si,6081 .import_address_table_si = import_address_table_si,
5990 .import_hint_name_table_ni = import_hint_name_table_ni,6082 .import_hint_name_table_ni = import_hint_name_table_ni,
6083 .import_address_table_symbols = .empty,
5991 .len = 0,6084 .len = 0,
5992 .hint_name_len = @intCast(import_hint_name_table_len),6085 .hint_name_len = @intCast(import_hint_name_table_len),
5993 };6086 };
...@@ -6034,20 +6127,20 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6034,20 +6127,20 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6034 gop.value_ptr.len = import_symbol_index + 1;6127 gop.value_ptr.len = import_symbol_index + 1;
6035 const new_symbol_table_size = addr_info.size * (import_symbol_index + 2);6128 const new_symbol_table_size = addr_info.size * (import_symbol_index + 2);
60366129
6130 try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size);
6131 const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff);
6132 try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size);
6133
6037 const opt_name = import.name.toSlice(coff);6134 const opt_name = import.name.toSlice(coff);
6038 const opt_import_hint_name_index = if (opt_name) |name| blk: {6135 const opt_import_hint_name_index = if (opt_name) |name| blk: {
6039 const import_hint_name_index = gop.value_ptr.hint_name_len;6136 const import_hint_name_index = gop.value_ptr.hint_name_len;
6040 gop.value_ptr.hint_name_len = @intCast(6137 gop.value_ptr.hint_name_len = @intCast(
6041 import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1),6138 import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1),
6042 );6139 );
6140 try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len);
6043 break :blk import_hint_name_index;6141 break :blk import_hint_name_index;
6044 } else null;6142 } else null;
60456143
6046 try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size);
6047 const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff);
6048 try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size);
6049 try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len);
6050
6051 const import_hint_name_rva = if (opt_import_hint_name_index) |import_hint_name_index| blk: {6144 const import_hint_name_rva = if (opt_import_hint_name_index) |import_hint_name_index| blk: {
6052 const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf);6145 const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf);
6053 const ordinal_hint: *u16 = @ptrCast(@alignCast(import_hint_name_slice[import_hint_name_index..][0..2]));6146 const ordinal_hint: *u16 = @ptrCast(@alignCast(import_hint_name_slice[import_hint_name_index..][0..2]));
...@@ -6062,26 +6155,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6062,26 +6155,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6062 switch (addr_info.magic) {6155 switch (addr_info.magic) {
6063 _ => unreachable,6156 _ => unreachable,
6064 inline .PE32, .@"PE32+" => |ct_magic| {6157 inline .PE32, .@"PE32+" => |ct_magic| {
6065 const Payload = packed union(u31) {6158 const Entry = ImportTable.TableEntry(ct_magic);
6066 ordinal: packed struct(u31) {
6067 ordinal: u16,
6068 _: u15 = 0,
6069 },
6070 hint_name_rva: u31,
6071 };
6072
6073 const Entry = switch (ct_magic) {
6074 _ => comptime unreachable,
6075 .PE32 => packed struct(u32) {
6076 payload: Payload,
6077 is_ordinal: bool,
6078 },
6079 .@"PE32+" => packed struct(u64) {
6080 payload: Payload,
6081 _: u32 = 0,
6082 is_ordinal: bool,
6083 },
6084 };
6085 const import_lookup_table: []Entry = @ptrCast(@alignCast(import_lookup_slice));6159 const import_lookup_table: []Entry = @ptrCast(@alignCast(import_lookup_slice));
6086 const import_address_table: []Entry = @ptrCast(@alignCast(import_address_slice));6160 const import_address_table: []Entry = @ptrCast(@alignCast(import_address_slice));
6087 const import_hint_name_rvas: [2]Entry = .{6161 const import_hint_name_rvas: [2]Entry = .{
...@@ -6112,6 +6186,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6112,6 +6186,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6112 sym.ni = iat_sym.ni;6186 sym.ni = iat_sym.ni;
6113 sym.setValue(.{ .node_offset = iat_offset });6187 sym.setValue(.{ .node_offset = iat_offset });
6114 si.flushMoved(coff);6188 si.flushMoved(coff);
6189 (try gop.value_ptr.import_address_table_symbols.addOne(gpa)).* = si;
6115 },6190 },
6116 .thunk => {6191 .thunk => {
6117 sym.section_number = Symbol.Index.text.get(coff).section_number;6192 sym.section_number = Symbol.Index.text.get(coff).section_number;
...@@ -6281,15 +6356,18 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6281,15 +6356,18 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6281 coff.computeNodeRva(ni),6356 coff.computeNodeRva(ni),
6282 ),6357 ),
6283 .import_address_table => |import_index| {6358 .import_address_table => |import_index| {
6284 const import_address_table_si = import_index.get(coff).import_address_table_si;6359 const entry = import_index.get(coff);
6360 const import_address_table_si = entry.import_address_table_si;
6285 import_address_table_si.flushMoved(coff);6361 import_address_table_si.flushMoved(coff);
6286 coff.targetStore(6362 coff.targetStore(
6287 &coff.importDirectoryEntryPtr(import_index).import_address_table_rva,6363 &coff.importDirectoryEntryPtr(import_index).import_address_table_rva,
6288 import_address_table_si.get(coff).rva,6364 import_address_table_si.get(coff).rva,
6289 );6365 );
6366
6367 for (entry.import_address_table_symbols.items) |iat_ptr_si|
6368 iat_ptr_si.flushMoved(coff);
6290 },6369 },
6291 .import_hint_name_table => |import_index| {6370 .import_hint_name_table => |import_index| {
6292 const target_endian = coff.targetEndian();
6293 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);6371 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);
6294 const import_hint_name_rva = coff.computeNodeRva(ni);6372 const import_hint_name_rva = coff.computeNodeRva(ni);
6295 coff.targetStore(6373 coff.targetStore(
...@@ -6302,32 +6380,36 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6302,32 +6380,36 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6302 import_entry.import_address_table_si.node(coff).slice(&coff.mf);6380 import_entry.import_address_table_si.node(coff).slice(&coff.mf);
6303 const import_hint_name_slice = ni.slice(&coff.mf);6381 const import_hint_name_slice = ni.slice(&coff.mf);
6304 const import_hint_name_align = ni.alignment(&coff.mf);6382 const import_hint_name_align = ni.alignment(&coff.mf);
6383
6305 var import_hint_name_index: u32 = 0;6384 var import_hint_name_index: u32 = 0;
6306 for (0..import_entry.len) |import_symbol_index| {6385 for (0..import_entry.len) |import_symbol_index| {
6307 import_hint_name_index = @intCast(import_hint_name_align.forward(
6308 std.mem.indexOfScalarPos(
6309 u8,
6310 import_hint_name_slice,
6311 import_hint_name_index,
6312 0,
6313 ).? + 1,
6314 ));
6315 switch (magic) {6386 switch (magic) {
6316 _ => unreachable,6387 _ => unreachable,
6317 inline .PE32, .@"PE32+" => |ct_magic| {6388 inline .PE32, .@"PE32+" => |ct_magic| {
6318 const Addr = TargetAddr(ct_magic);6389 const Entry = ImportTable.TableEntry(ct_magic);
6319 const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice));6390 const import_lookup_table: []Entry = @ptrCast(@alignCast(import_lookup_slice));
6320 const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice));6391 const import_address_table: []Entry = @ptrCast(@alignCast(import_address_slice));
6321 const rva = std.mem.nativeTo(6392
6322 Addr,6393 var entry = coff.targetLoad(&import_lookup_table[import_symbol_index]);
6323 import_hint_name_rva + import_hint_name_index,6394 if (entry.is_ordinal)
6324 target_endian,6395 continue;
6325 );6396
6326 import_lookup_table[import_symbol_index] = rva;6397 import_hint_name_index = @intCast(import_hint_name_align.forward(
6327 import_address_table[import_symbol_index] = rva;6398 std.mem.indexOfScalarPos(
6399 u8,
6400 import_hint_name_slice,
6401 import_hint_name_index,
6402 0,
6403 ).? + 1,
6404 ));
6405
6406 entry.payload.hint_name_rva = @intCast(import_hint_name_rva + import_hint_name_index);
6407 import_hint_name_index += 2;
6408
6409 coff.targetStore(&import_lookup_table[import_symbol_index], entry);
6410 coff.targetStore(&import_address_table[import_symbol_index], entry);
6328 },6411 },
6329 }6412 }
6330 import_hint_name_index += 2;
6331 }6413 }
6332 },6414 },
6333 .export_directory_table => {6415 .export_directory_table => {
...@@ -6679,14 +6761,16 @@ fn updateExportsInner(...@@ -6679,14 +6761,16 @@ fn updateExportsInner(
6679 export_sym.section_number = exported_sym.section_number;6761 export_sym.section_number = exported_sym.section_number;
6680 defer export_si.applyTargetRelocs(coff);6762 defer export_si.applyTargetRelocs(coff);
66816763
6682 if (isImage(coff)) {6764 if (coff.isImage()) {
6683 if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) {6765 if (@"export".opts.name.eqlSlice("_tls_used", ip)) {
6684 coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva;
6685 } else if (@"export".opts.name.eqlSlice("_tls_used", ip)) {
6686 const tls_directory = coff.dataDirectoryPtr(.TLS);6766 const tls_directory = coff.dataDirectoryPtr(.TLS);
6687 tls_directory.* = .{ .virtual_address = exported_sym.rva, .size = exported_sym.value.size };6767 tls_directory.* = .{ .virtual_address = exported_sym.rva, .size = exported_sym.value.size };
6688 if (coff.targetEndian() != native_endian)6768 if (coff.targetEndian() != native_endian)
6689 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);6769 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);
6770 } else if ((coff.isExe() and @"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) or
6771 (!coff.isExe() and @"export".opts.name.eqlSlice("_DllMainCRTStartup", ip)))
6772 {
6773 coff.updateEntry(export_sym.gmi);
6690 }6774 }
6691 } else continue;6775 } else continue;
66926776
...@@ -6780,6 +6864,20 @@ fn updateExportsInner(...@@ -6780,6 +6864,20 @@ fn updateExportsInner(
6780 }6864 }
6781}6865}
67826866
6867/// Caller ensures that `applyTargetRelocs` will be called on `si` eventually
6868fn updateEntry(coff: *Coff, gmi: Node.GlobalMapIndex) void {
6869 const si = gmi.symbol(coff);
6870 log.debug("updateEntry({s}, {d})", .{ gmi.globalName(coff).name.toSlice(coff), si });
6871
6872 if (coff.entry != .none)
6873 coff.entry.symbol(coff).get(coff).flags.is_entry = false;
6874
6875 // TODO: Should we detect the subsystem like link.exe does (if not explicitly set) based on entry name?
6876
6877 coff.entry = gmi;
6878 si.get(coff).flags.is_entry = true;
6879}
6880
6783pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void {6881pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void {
6784 _ = coff;6882 _ = coff;
6785 _ = exported;6883 _ = exported;
src/link/MappedFile.zig+3-3
...@@ -756,7 +756,6 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested...@@ -756,7 +756,6 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
756 const node = ni.get(mf);756 const node = ni.get(mf);
757 const old_offset, const old_size = node.location().resolve(mf);757 const old_offset, const old_size = node.location().resolve(mf);
758 const new_size = node.flags.alignment.forward(@intCast(requested_size));758 const new_size = node.flags.alignment.forward(@intCast(requested_size));
759 //if (new_size <= old_size) return;
760759
761 // Resize the entire file760 // Resize the entire file
762 if (ni == Node.Index.root) {761 if (ni == Node.Index.root) {
...@@ -917,8 +916,9 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested...@@ -917,8 +916,9 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
917 if (new_last_fixed_offset + last_fixed_size <= old_first_floating_offset)916 if (new_last_fixed_offset + last_fixed_size <= old_first_floating_offset)
918 break :make_space;917 break :make_space;
919 assert(direction == .forward);918 assert(direction == .forward);
919 const shift_alignment = first_floating.flags.alignment.max(last_fixed.flags.alignment);
920 if (first_floating.flags.fixed) {920 if (first_floating.flags.fixed) {
921 shift = first_floating.flags.alignment.forward(@intCast(921 shift = shift_alignment.forward(@intCast(
922 @max(shift, first_floating_size),922 @max(shift, first_floating_size),
923 ));923 ));
924924
...@@ -930,7 +930,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested...@@ -930,7 +930,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
930 // Move the found floating node to make space for preceding fixed nodes930 // Move the found floating node to make space for preceding fixed nodes
931 const last = parent.last.get(mf);931 const last = parent.last.get(mf);
932 const last_offset, const last_size = last.location().resolve(mf);932 const last_offset, const last_size = last.location().resolve(mf);
933 const new_first_floating_offset = first_floating.flags.alignment.forward(933 const new_first_floating_offset = shift_alignment.forward(
934 @intCast(@max(new_last_fixed_offset + last_fixed_size, last_offset + last_size)),934 @intCast(@max(new_last_fixed_offset + last_fixed_size, last_offset + last_size)),
935 );935 );
936 const new_parent_size = new_first_floating_offset + first_floating_size;936 const new_parent_size = new_first_floating_offset + first_floating_size;