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:22:42-04:00
log2be291c98773e25d4a47e5c35744084627d11f15
tree1e158424790d793bf7e08f8b4589e7675313301a
parenta22ca5d4169406576776436a9bec5c500bc3f2d4

Coff: fixup extern code imports

- Add a type flag to Symbol so that we can select between a thunk or IAT ptr - Library name comparisons are now case insensitive

1 files changed, 41 insertions(+), 19 deletions(-)

src/link/Coff.zig+41-19
...@@ -819,20 +819,15 @@ pub const Section = struct {...@@ -819,20 +819,15 @@ pub const Section = struct {
819819
820pub const GlobalName = struct { name: String, lib_name: String.Optional };820pub const GlobalName = struct { name: String, lib_name: String.Optional };
821821
822pub const DllStorageClass = enum(u2) {
823 default,
824 dllimport,
825 dllexport,
826};
827
828pub const Symbol = struct {822pub const Symbol = struct {
829 ni: MappedFile.Node.Index,823 ni: MappedFile.Node.Index,
830 rva: u32,824 rva: u32,
831 value: std.meta.BareUnion(Symbol.Value),825 value: std.meta.BareUnion(Symbol.Value),
832 flags: packed struct(u16) {826 flags: packed struct(u16) {
833 value_tag: ValueTag,827 value_tag: ValueTag,
828 type: Symbol.Type,
834 dll_storage_class: DllStorageClass,829 dll_storage_class: DllStorageClass,
835 _: u12 = 0,830 _: u10 = 0,
836 },831 },
837 /// Relocations contained within this symbol832 /// Relocations contained within this symbol
838 loc_relocs: Reloc.Index,833 loc_relocs: Reloc.Index,
...@@ -843,6 +838,18 @@ pub const Symbol = struct {...@@ -843,6 +838,18 @@ pub const Symbol = struct {
843 sti: SymbolTable.Index,838 sti: SymbolTable.Index,
844 gmi: Node.GlobalMapIndex,839 gmi: Node.GlobalMapIndex,
845840
841 pub const DllStorageClass = enum(u2) {
842 default,
843 dllimport,
844 dllexport,
845 };
846
847 pub const Type = enum(u2) {
848 unknown,
849 code,
850 data,
851 };
852
846 const ValueTag = enum(u2) {853 const ValueTag = enum(u2) {
847 node_offset,854 node_offset,
848 alias_si,855 alias_si,
...@@ -2314,6 +2321,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {...@@ -2314,6 +2321,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
2314 .value = .{ .size = 0 },2321 .value = .{ .size = 0 },
2315 .flags = .{2322 .flags = .{
2316 .value_tag = .size,2323 .value_tag = .size,
2324 .type = .unknown,
2317 .dll_storage_class = .default,2325 .dll_storage_class = .default,
2318 },2326 },
2319 .loc_relocs = .none,2327 .loc_relocs = .none,
...@@ -2401,8 +2409,9 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {...@@ -2401,8 +2409,9 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {
24012409
2402const GlobalOptions = struct {2410const GlobalOptions = struct {
2403 name: []const u8,2411 name: []const u8,
2412 type: Symbol.Type = .unknown,
2404 lib_name: ?[]const u8 = null,2413 lib_name: ?[]const u8 = null,
2405 dll_storage_class: DllStorageClass = .default,2414 dll_storage_class: Symbol.DllStorageClass = .default,
2406};2415};
24072416
2408fn getOrPutGlobalSymbol(2417fn getOrPutGlobalSymbol(
...@@ -2420,6 +2429,7 @@ fn getOrPutGlobalSymbol(...@@ -2420,6 +2429,7 @@ fn getOrPutGlobalSymbol(
2420 const sym = si.get(coff);2429 const sym = si.get(coff);
2421 sym.setValue(.{ .alias_si = .null });2430 sym.setValue(.{ .alias_si = .null });
2422 sym.gmi = .wrap(@intCast(sym_gop.index));2431 sym.gmi = .wrap(@intCast(sym_gop.index));
2432 sym.flags.type = opts.type;
2423 sym.flags.dll_storage_class = opts.dll_storage_class;2433 sym.flags.dll_storage_class = opts.dll_storage_class;
2424 sym_gop.value_ptr.* = si;2434 sym_gop.value_ptr.* = si;
2425 coff.synth_prog_node.increaseEstimatedTotalItems(1);2435 coff.synth_prog_node.increaseEstimatedTotalItems(1);
...@@ -2493,6 +2503,8 @@ pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbo...@@ -2493,6 +2503,8 @@ pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbo
2493 if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(.{2503 if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(.{
2494 .name = @"extern".name.toSlice(ip),2504 .name = @"extern".name.toSlice(ip),
2495 .lib_name = @"extern".lib_name.toSlice(ip),2505 .lib_name = @"extern".lib_name.toSlice(ip),
2506 // TODO: Threadlocal as well?
2507 .type = if (ip.isFunctionType(nav.resolved.?.type)) .code else .data,
2496 .dll_storage_class = if (@"extern".is_dll_import) .dllimport else .default,2508 .dll_storage_class = if (@"extern".is_dll_import) .dllimport else .default,
2497 });2509 });
2498 const nmi = try coff.navMapIndex(zcu, nav_index);2510 const nmi = try coff.navMapIndex(zcu, nav_index);
...@@ -3881,7 +3893,7 @@ fn loadObject(...@@ -3881,7 +3893,7 @@ fn loadObject(
3881 else3893 else
3882 break :comdat .include;3894 break :comdat .include;
3883 },3895 },
3884 else => {3896 .external => {
3885 const global_gop = try coff.getOrPutGlobalSymbol(.{3897 const global_gop = try coff.getOrPutGlobalSymbol(.{
3886 .name = symbol.name.toSlice(coff),3898 .name = symbol.name.toSlice(coff),
3887 .lib_name = null,3899 .lib_name = null,
...@@ -5451,6 +5463,8 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -5451,6 +5463,8 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
5451 break :name .{ coff.getOrPutStringAssumeCapacity(name), true };5463 break :name .{ coff.getOrPutStringAssumeCapacity(name), true };
5452 };5464 };
54535465
5466 // TODO: Try to search for __imp_ even when !is_imp, we want to not use thunks if we can
5467
5454 if (coff.input_archive_symbol_indices.get(search_name)) |indices_list| {5468 if (coff.input_archive_symbol_indices.get(search_name)) |indices_list| {
5455 var iter: InputArchive.Member.Symbol.Index = indices_list.first;5469 var iter: InputArchive.Member.Symbol.Index = indices_list.first;
5456 while (true) {5470 while (true) {
...@@ -5459,8 +5473,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -5459,8 +5473,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
5459 member: switch (member.content) {5473 member: switch (member.content) {
5460 .object => if (!member.flags.is_loaded) {5474 .object => if (!member.flags.is_loaded) {
5461 if (gn.lib_name.unwrap()) |lib_name|5475 if (gn.lib_name.unwrap()) |lib_name|
5462 if (!std.mem.eql(u8, lib_name.toSlice(coff), member.iai.path(coff).stem()))5476 if (!std.ascii.eqlIgnoreCase(
5463 break :member;5477 lib_name.toSlice(coff),
5478 member.iai.path(coff).stem(),
5479 )) break :member;
54645480
5465 // Try loading the input member and then retry.5481 // Try loading the input member and then retry.
5466 // This could still be a member containing imports5482 // This could still be a member containing imports
...@@ -5470,8 +5486,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -5470,8 +5486,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
5470 },5486 },
5471 .import => |import| {5487 .import => |import| {
5472 if (gn.lib_name.unwrap()) |lib_name|5488 if (gn.lib_name.unwrap()) |lib_name|
5473 if (import.lib_name != lib_name)5489 if (!std.ascii.eqlIgnoreCase(
5474 break :member;5490 import.lib_name.toSlice(coff),
5491 lib_name.toSlice(coff),
5492 )) break :member;
54755493
5476 const name: String.Optional = name: switch (import.name_type) {5494 const name: String.Optional = name: switch (import.name_type) {
5477 .NAME,5495 .NAME,
...@@ -5524,12 +5542,16 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -5524,12 +5542,16 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
5524 // Allow importing symbols with no implib entry, if a lib_name was specified.5542 // Allow importing symbols with no implib entry, if a lib_name was specified.
5525 // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification,5543 // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification,
5526 // which are not in the implib.5544 // which are not in the implib.
5527 break :import if (gn.lib_name.unwrap()) |lib_name| .{5545 if (sym.flags.type != .unknown) {
5528 .lib_name = lib_name,5546 if (gn.lib_name.unwrap()) |lib_name| break :import .{
5529 .name = gn.name.toOptional(),5547 .lib_name = lib_name,
5530 .ordinal_hint = 0,5548 .name = gn.name.toOptional(),
5531 .kind = .iat_ptr,5549 .ordinal_hint = 0,
5532 } else null;5550 .kind = if (sym.flags.type == .code) .thunk else .iat_ptr,
5551 };
5552 }
5553
5554 break :import null;
5533 } else null;5555 } else null;
55345556
5535 if (opt_import) |import| {5557 if (opt_import) |import| {