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 {
819819
820820pub const GlobalName = struct { name: String, lib_name: String.Optional };
821821
822pub const DllStorageClass = enum(u2) {
823 default,
824 dllimport,
825 dllexport,
826};
827
828822pub const Symbol = struct {
829823 ni: MappedFile.Node.Index,
830824 rva: u32,
831825 value: std.meta.BareUnion(Symbol.Value),
832826 flags: packed struct(u16) {
833827 value_tag: ValueTag,
828 type: Symbol.Type,
834829 dll_storage_class: DllStorageClass,
835 _: u12 = 0,
830 _: u10 = 0,
836831 },
837832 /// Relocations contained within this symbol
838833 loc_relocs: Reloc.Index,
......@@ -843,6 +838,18 @@ pub const Symbol = struct {
843838 sti: SymbolTable.Index,
844839 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
846853 const ValueTag = enum(u2) {
847854 node_offset,
848855 alias_si,
......@@ -2314,6 +2321,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
23142321 .value = .{ .size = 0 },
23152322 .flags = .{
23162323 .value_tag = .size,
2324 .type = .unknown,
23172325 .dll_storage_class = .default,
23182326 },
23192327 .loc_relocs = .none,
......@@ -2401,8 +2409,9 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {
24012409
24022410const GlobalOptions = struct {
24032411 name: []const u8,
2412 type: Symbol.Type = .unknown,
24042413 lib_name: ?[]const u8 = null,
2405 dll_storage_class: DllStorageClass = .default,
2414 dll_storage_class: Symbol.DllStorageClass = .default,
24062415};
24072416
24082417fn getOrPutGlobalSymbol(
......@@ -2420,6 +2429,7 @@ fn getOrPutGlobalSymbol(
24202429 const sym = si.get(coff);
24212430 sym.setValue(.{ .alias_si = .null });
24222431 sym.gmi = .wrap(@intCast(sym_gop.index));
2432 sym.flags.type = opts.type;
24232433 sym.flags.dll_storage_class = opts.dll_storage_class;
24242434 sym_gop.value_ptr.* = si;
24252435 coff.synth_prog_node.increaseEstimatedTotalItems(1);
......@@ -2493,6 +2503,8 @@ pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbo
24932503 if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(.{
24942504 .name = @"extern".name.toSlice(ip),
24952505 .lib_name = @"extern".lib_name.toSlice(ip),
2506 // TODO: Threadlocal as well?
2507 .type = if (ip.isFunctionType(nav.resolved.?.type)) .code else .data,
24962508 .dll_storage_class = if (@"extern".is_dll_import) .dllimport else .default,
24972509 });
24982510 const nmi = try coff.navMapIndex(zcu, nav_index);
......@@ -3881,7 +3893,7 @@ fn loadObject(
38813893 else
38823894 break :comdat .include;
38833895 },
3884 else => {
3896 .external => {
38853897 const global_gop = try coff.getOrPutGlobalSymbol(.{
38863898 .name = symbol.name.toSlice(coff),
38873899 .lib_name = null,
......@@ -5451,6 +5463,8 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
54515463 break :name .{ coff.getOrPutStringAssumeCapacity(name), true };
54525464 };
54535465
5466 // TODO: Try to search for __imp_ even when !is_imp, we want to not use thunks if we can
5467
54545468 if (coff.input_archive_symbol_indices.get(search_name)) |indices_list| {
54555469 var iter: InputArchive.Member.Symbol.Index = indices_list.first;
54565470 while (true) {
......@@ -5459,8 +5473,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
54595473 member: switch (member.content) {
54605474 .object => if (!member.flags.is_loaded) {
54615475 if (gn.lib_name.unwrap()) |lib_name|
5462 if (!std.mem.eql(u8, lib_name.toSlice(coff), member.iai.path(coff).stem()))
5463 break :member;
5476 if (!std.ascii.eqlIgnoreCase(
5477 lib_name.toSlice(coff),
5478 member.iai.path(coff).stem(),
5479 )) break :member;
54645480
54655481 // Try loading the input member and then retry.
54665482 // This could still be a member containing imports
......@@ -5470,8 +5486,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
54705486 },
54715487 .import => |import| {
54725488 if (gn.lib_name.unwrap()) |lib_name|
5473 if (import.lib_name != lib_name)
5474 break :member;
5489 if (!std.ascii.eqlIgnoreCase(
5490 import.lib_name.toSlice(coff),
5491 lib_name.toSlice(coff),
5492 )) break :member;
54755493
54765494 const name: String.Optional = name: switch (import.name_type) {
54775495 .NAME,
......@@ -5524,12 +5542,16 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
55245542 // Allow importing symbols with no implib entry, if a lib_name was specified.
55255543 // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification,
55265544 // which are not in the implib.
5527 break :import if (gn.lib_name.unwrap()) |lib_name| .{
5528 .lib_name = lib_name,
5529 .name = gn.name.toOptional(),
5530 .ordinal_hint = 0,
5531 .kind = .iat_ptr,
5532 } else null;
5545 if (sym.flags.type != .unknown) {
5546 if (gn.lib_name.unwrap()) |lib_name| break :import .{
5547 .lib_name = lib_name,
5548 .name = gn.name.toOptional(),
5549 .ordinal_hint = 0,
5550 .kind = if (sym.flags.type == .code) .thunk else .iat_ptr,
5551 };
5552 }
5553
5554 break :import null;
55335555 } else null;
55345556
55355557 if (opt_import) |import| {