authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-28 18:28:48+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-28 18:28:48+02:00
log43487eb3ef0933c1da53b917c44ba6070d8e5a21
treecc3af355efe42c4503d866322caed9fad5832961
parent5d63d1115f0f18984ed7c517c2d85224aa4da444
parent1c5f2557894539d7620933324dad48a43a16d0ef
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15102 from ziglang/fix-15075

coff: handle multiple DLLs

11 files changed, 392 insertions(+), 214 deletions(-)

CMakeLists.txt+1
...@@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES...@@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES
583 "${CMAKE_SOURCE_DIR}/src/link/C.zig"583 "${CMAKE_SOURCE_DIR}/src/link/C.zig"
584 "${CMAKE_SOURCE_DIR}/src/link/Coff.zig"584 "${CMAKE_SOURCE_DIR}/src/link/Coff.zig"
585 "${CMAKE_SOURCE_DIR}/src/link/Coff/Atom.zig"585 "${CMAKE_SOURCE_DIR}/src/link/Coff/Atom.zig"
586 "${CMAKE_SOURCE_DIR}/src/link/Coff/ImportTable.zig"
586 "${CMAKE_SOURCE_DIR}/src/link/Coff/Object.zig"587 "${CMAKE_SOURCE_DIR}/src/link/Coff/Object.zig"
587 "${CMAKE_SOURCE_DIR}/src/link/Coff/lld.zig"588 "${CMAKE_SOURCE_DIR}/src/link/Coff/lld.zig"
588 "${CMAKE_SOURCE_DIR}/src/link/Elf.zig"589 "${CMAKE_SOURCE_DIR}/src/link/Elf.zig"
src/arch/aarch64/CodeGen.zig+4-10
...@@ -4318,16 +4318,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4318,16 +4318,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4318 });4318 });
4319 } else if (func_value.castTag(.extern_fn)) |func_payload| {4319 } else if (func_value.castTag(.extern_fn)) |func_payload| {
4320 const extern_fn = func_payload.data;4320 const extern_fn = func_payload.data;
4321 const decl_name = mod.declPtr(extern_fn.owner_decl).name;4321 const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0);
4322 if (extern_fn.lib_name) |lib_name| {4322 const lib_name = mem.sliceTo(extern_fn.lib_name, 0);
4323 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
4324 decl_name,
4325 lib_name,
4326 });
4327 }
4328
4329 if (self.bin_file.cast(link.File.MachO)) |macho_file| {4323 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4330 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));4324 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
4331 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);4325 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4332 const atom_index = macho_file.getAtom(atom).getSymbolIndex().?;4326 const atom_index = macho_file.getAtom(atom).getSymbolIndex().?;
4333 _ = try self.addInst(.{4327 _ = try self.addInst(.{
...@@ -4340,7 +4334,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4340,7 +4334,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4340 },4334 },
4341 });4335 });
4342 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {4336 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4343 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));4337 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
4344 try self.genSetReg(Type.initTag(.u64), .x30, .{4338 try self.genSetReg(Type.initTag(.u64), .x30, .{
4345 .linker_load = .{4339 .linker_load = .{
4346 .type = .import,4340 .type = .import,
src/arch/wasm/CodeGen.zig+1-1
...@@ -6121,7 +6121,7 @@ fn callIntrinsic(...@@ -6121,7 +6121,7 @@ fn callIntrinsic(
6121 args: []const WValue,6121 args: []const WValue,
6122) InnerError!WValue {6122) InnerError!WValue {
6123 assert(param_types.len == args.len);6123 assert(param_types.len == args.len);
6124 const symbol_index = func.bin_file.base.getGlobalSymbol(name) catch |err| {6124 const symbol_index = func.bin_file.base.getGlobalSymbol(name, null) catch |err| {
6125 return func.fail("Could not find or create global symbol '{s}'", .{@errorName(err)});6125 return func.fail("Could not find or create global symbol '{s}'", .{@errorName(err)});
6126 };6126 };
61276127
src/arch/x86_64/CodeGen.zig+4-10
...@@ -5317,16 +5317,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -5317,16 +5317,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
5317 } else unreachable;5317 } else unreachable;
5318 } else if (func_value.castTag(.extern_fn)) |func_payload| {5318 } else if (func_value.castTag(.extern_fn)) |func_payload| {
5319 const extern_fn = func_payload.data;5319 const extern_fn = func_payload.data;
5320 const decl_name = mod.declPtr(extern_fn.owner_decl).name;5320 const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0);
5321 if (extern_fn.lib_name) |lib_name| {5321 const lib_name = mem.sliceTo(extern_fn.lib_name, 0);
5322 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
5323 decl_name,
5324 lib_name,
5325 });
5326 }
5327
5328 if (self.bin_file.cast(link.File.Coff)) |coff_file| {5322 if (self.bin_file.cast(link.File.Coff)) |coff_file| {
5329 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));5323 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
5330 try self.genSetReg(Type.initTag(.usize), .rax, .{5324 try self.genSetReg(Type.initTag(.usize), .rax, .{
5331 .linker_load = .{5325 .linker_load = .{
5332 .type = .import,5326 .type = .import,
...@@ -5335,7 +5329,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -5335,7 +5329,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
5335 });5329 });
5336 try self.asmRegister(.call, .rax);5330 try self.asmRegister(.call, .rax);
5337 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {5331 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
5338 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));5332 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
5339 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);5333 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5340 const atom_index = macho_file.getAtom(atom).getSymbolIndex().?;5334 const atom_index = macho_file.getAtom(atom).getSymbolIndex().?;
5341 _ = try self.addInst(.{5335 _ = try self.addInst(.{
src/link.zig+7-5
...@@ -504,18 +504,20 @@ pub const File = struct {...@@ -504,18 +504,20 @@ pub const File = struct {
504 /// Called from within CodeGen to retrieve the symbol index of a global symbol.504 /// Called from within CodeGen to retrieve the symbol index of a global symbol.
505 /// If no symbol exists yet with this name, a new undefined global symbol will505 /// If no symbol exists yet with this name, a new undefined global symbol will
506 /// be created. This symbol may get resolved once all relocatables are (re-)linked.506 /// be created. This symbol may get resolved once all relocatables are (re-)linked.
507 pub fn getGlobalSymbol(base: *File, name: []const u8) UpdateDeclError!u32 {507 /// Optionally, it is possible to specify where to expect the symbol defined if it
508 /// is an import.
509 pub fn getGlobalSymbol(base: *File, name: []const u8, lib_name: ?[]const u8) UpdateDeclError!u32 {
508 if (build_options.only_c) @compileError("unreachable");510 if (build_options.only_c) @compileError("unreachable");
509 log.debug("getGlobalSymbol '{s}'", .{name});511 log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name });
510 switch (base.tag) {512 switch (base.tag) {
511 // zig fmt: off513 // zig fmt: off
512 .coff => return @fieldParentPtr(Coff, "base", base).getGlobalSymbol(name),514 .coff => return @fieldParentPtr(Coff, "base", base).getGlobalSymbol(name, lib_name),
513 .elf => unreachable,515 .elf => unreachable,
514 .macho => return @fieldParentPtr(MachO, "base", base).getGlobalSymbol(name),516 .macho => return @fieldParentPtr(MachO, "base", base).getGlobalSymbol(name, lib_name),
515 .plan9 => unreachable,517 .plan9 => unreachable,
516 .spirv => unreachable,518 .spirv => unreachable,
517 .c => unreachable,519 .c => unreachable,
518 .wasm => return @fieldParentPtr(Wasm, "base", base).getGlobalSymbol(name),520 .wasm => return @fieldParentPtr(Wasm, "base", base).getGlobalSymbol(name, lib_name),
519 .nvptx => unreachable,521 .nvptx => unreachable,
520 // zig fmt: on522 // zig fmt: on
521 }523 }
src/link/Coff.zig+214-166
...@@ -1,36 +1,7 @@...@@ -1,36 +1,7 @@
1const Coff = @This();1//! The main driver of the COFF linker.
22//! Currently uses our own implementation for the incremental linker, and falls back to
3const std = @import("std");3//! LLD for traditional linking (linking relocatable object files).
4const build_options = @import("build_options");4//! LLD is also the default linker for LLVM.
5const builtin = @import("builtin");
6const assert = std.debug.assert;
7const coff = std.coff;
8const fmt = std.fmt;
9const log = std.log.scoped(.link);
10const math = std.math;
11const mem = std.mem;
12
13const Allocator = std.mem.Allocator;
14
15const codegen = @import("../codegen.zig");
16const link = @import("../link.zig");
17const lld = @import("Coff/lld.zig");
18const trace = @import("../tracy.zig").trace;
19
20const Air = @import("../Air.zig");
21pub const Atom = @import("Coff/Atom.zig");
22const Compilation = @import("../Compilation.zig");
23const Liveness = @import("../Liveness.zig");
24const LlvmObject = @import("../codegen/llvm.zig").Object;
25const Module = @import("../Module.zig");
26const Object = @import("Coff/Object.zig");
27const Relocation = @import("Coff/Relocation.zig");
28const StringTable = @import("strtab.zig").StringTable;
29const TypedValue = @import("../TypedValue.zig");
30
31pub const base_tag: link.File.Tag = .coff;
32
33const msdos_stub = @embedFile("msdos-stub.bin");
345
35/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.6/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
36llvm_object: ?*LlvmObject = null,7llvm_object: ?*LlvmObject = null,
...@@ -64,13 +35,16 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},...@@ -64,13 +35,16 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},
64strtab: StringTable(.strtab) = .{},35strtab: StringTable(.strtab) = .{},
65strtab_offset: ?u32 = null,36strtab_offset: ?u32 = null,
6637
38temp_strtab: StringTable(.temp_strtab) = .{},
39
67got_entries: std.ArrayListUnmanaged(Entry) = .{},40got_entries: std.ArrayListUnmanaged(Entry) = .{},
68got_entries_free_list: std.ArrayListUnmanaged(u32) = .{},41got_entries_free_list: std.ArrayListUnmanaged(u32) = .{},
69got_entries_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},42got_entries_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
7043
71imports: std.ArrayListUnmanaged(Entry) = .{},44/// A table of ImportTables partitioned by the library name.
72imports_free_list: std.ArrayListUnmanaged(u32) = .{},45/// Key is an offset into the interning string table `temp_strtab`.
73imports_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},46import_tables: std.AutoArrayHashMapUnmanaged(u32, ImportTable) = .{},
47imports_count_dirty: bool = true,
7448
75/// Virtual address of the entry point procedure relative to image base.49/// Virtual address of the entry point procedure relative to image base.
76entry_addr: ?u32 = null,50entry_addr: ?u32 = null,
...@@ -309,12 +283,15 @@ pub fn deinit(self: *Coff) void {...@@ -309,12 +283,15 @@ pub fn deinit(self: *Coff) void {
309 self.locals_free_list.deinit(gpa);283 self.locals_free_list.deinit(gpa);
310 self.globals_free_list.deinit(gpa);284 self.globals_free_list.deinit(gpa);
311 self.strtab.deinit(gpa);285 self.strtab.deinit(gpa);
286 self.temp_strtab.deinit(gpa);
312 self.got_entries.deinit(gpa);287 self.got_entries.deinit(gpa);
313 self.got_entries_free_list.deinit(gpa);288 self.got_entries_free_list.deinit(gpa);
314 self.got_entries_table.deinit(gpa);289 self.got_entries_table.deinit(gpa);
315 self.imports.deinit(gpa);290
316 self.imports_free_list.deinit(gpa);291 for (self.import_tables.values()) |*itab| {
317 self.imports_table.deinit(gpa);292 itab.deinit(gpa);
293 }
294 self.import_tables.deinit(gpa);
318295
319 {296 {
320 var it = self.decls.iterator();297 var it = self.decls.iterator();
...@@ -358,6 +335,8 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -358,6 +335,8 @@ fn populateMissingMetadata(self: *Coff) !void {
358 try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));335 try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));
359 self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32));336 self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32));
360337
338 try self.temp_strtab.buffer.append(gpa, 0);
339
361 // Index 0 is always a null symbol.340 // Index 0 is always a null symbol.
362 try self.locals.append(gpa, .{341 try self.locals.append(gpa, .{
363 .name = [_]u8{0} ** 8,342 .name = [_]u8{0} ** 8,
...@@ -725,28 +704,6 @@ pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {...@@ -725,28 +704,6 @@ pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {
725 return index;704 return index;
726}705}
727706
728pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 {
729 const gpa = self.base.allocator;
730 try self.imports.ensureUnusedCapacity(gpa, 1);
731
732 const index: u32 = blk: {
733 if (self.imports_free_list.popOrNull()) |index| {
734 log.debug(" (reusing import entry index {d})", .{index});
735 break :blk index;
736 } else {
737 log.debug(" (allocating import entry at index {d})", .{self.imports.items.len});
738 const index = @intCast(u32, self.imports.items.len);
739 _ = self.imports.addOneAssumeCapacity();
740 break :blk index;
741 }
742 };
743
744 self.imports.items[index] = .{ .target = target, .sym_index = 0 };
745 try self.imports_table.putNoClobber(gpa, target, index);
746
747 return index;
748}
749
750pub fn createAtom(self: *Coff) !Atom.Index {707pub fn createAtom(self: *Coff) !Atom.Index {
751 const gpa = self.base.allocator;708 const gpa = self.base.allocator;
752 const atom_index = @intCast(Atom.Index, self.atoms.items.len);709 const atom_index = @intCast(Atom.Index, self.atoms.items.len);
...@@ -797,21 +754,6 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !Atom.Index {...@@ -797,21 +754,6 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !Atom.Index {
797 return atom_index;754 return atom_index;
798}755}
799756
800fn createImportAtom(self: *Coff) !Atom.Index {
801 const atom_index = try self.createAtom();
802 const atom = self.getAtomPtr(atom_index);
803 atom.size = @sizeOf(u64);
804 atom.alignment = @alignOf(u64);
805
806 const sym = atom.getSymbolPtr(self);
807 sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1);
808 sym.value = try self.allocateAtom(atom_index, atom.size, atom.alignment);
809
810 log.debug("allocated import atom at 0x{x}", .{sym.value});
811
812 return atom_index;
813}
814
815fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {757fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
816 const atom = self.getAtom(atom_index);758 const atom = self.getAtom(atom_index);
817 const sym = atom.getSymbol(self);759 const sym = atom.getSymbol(self);
...@@ -871,10 +813,8 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {...@@ -871,10 +813,8 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
871 var it = self.relocs.valueIterator();813 var it = self.relocs.valueIterator();
872 while (it.next()) |relocs| {814 while (it.next()) |relocs| {
873 for (relocs.items) |*reloc| {815 for (relocs.items) |*reloc| {
874 const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;816 const target_vaddr = reloc.getTargetAddress(self) orelse continue;
875 const target_atom = self.getAtom(target_atom_index);817 if (target_vaddr < addr) continue;
876 const target_sym = target_atom.getSymbol(self);
877 if (target_sym.value < addr) continue;
878 reloc.dirty = true;818 reloc.dirty = true;
879 }819 }
880 }820 }
...@@ -1463,35 +1403,42 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1463,35 +1403,42 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1463 sub_prog_node.activate();1403 sub_prog_node.activate();
1464 defer sub_prog_node.end();1404 defer sub_prog_node.end();
14651405
1406 const gpa = self.base.allocator;
1407
1466 while (self.unresolved.popOrNull()) |entry| {1408 while (self.unresolved.popOrNull()) |entry| {
1467 assert(entry.value); // We only expect imports generated by the incremental linker for now.1409 assert(entry.value); // We only expect imports generated by the incremental linker for now.
1468 const global = self.globals.items[entry.key];1410 const global = self.globals.items[entry.key];
1469 if (self.imports_table.contains(global)) continue;1411 const sym = self.getSymbol(global);
14701412 const res = try self.import_tables.getOrPut(gpa, sym.value);
1471 const import_index = try self.allocateImportEntry(global);1413 const itable = res.value_ptr;
1472 const import_atom_index = try self.createImportAtom();1414 if (!res.found_existing) {
1473 const import_atom = self.getAtom(import_atom_index);1415 itable.* = .{};
1474 self.imports.items[import_index].sym_index = import_atom.getSymbolIndex().?;1416 }
1475 try self.writePtrWidthAtom(import_atom_index);1417 if (itable.lookup.contains(global)) continue;
1476 }1418 // TODO: we could technically write the pointer placeholder for to-be-bound import here,
14771419 // but since this happens in flush, there is currently no point.
1478 if (build_options.enable_logging) {1420 _ = try itable.addImport(gpa, global);
1479 self.logSymtab();1421 self.imports_count_dirty = true;
1480 }1422 }
14811423
1424 try self.writeImportTables();
1482 {1425 {
1483 var it = self.relocs.keyIterator();1426 var it = self.relocs.keyIterator();
1484 while (it.next()) |atom| {1427 while (it.next()) |atom| {
1485 try self.resolveRelocs(atom.*);1428 try self.resolveRelocs(atom.*);
1486 }1429 }
1487 }1430 }
1488 try self.writeImportTable();
1489 try self.writeBaseRelocations();1431 try self.writeBaseRelocations();
14901432
1491 if (self.getEntryPoint()) |entry_sym_loc| {1433 if (self.getEntryPoint()) |entry_sym_loc| {
1492 self.entry_addr = self.getSymbol(entry_sym_loc).value;1434 self.entry_addr = self.getSymbol(entry_sym_loc).value;
1493 }1435 }
14941436
1437 if (build_options.enable_logging) {
1438 self.logSymtab();
1439 self.logImportTables();
1440 }
1441
1495 try self.writeStrtab();1442 try self.writeStrtab();
1496 try self.writeDataDirectoriesHeaders();1443 try self.writeDataDirectoriesHeaders();
1497 try self.writeSectionHeaders();1444 try self.writeSectionHeaders();
...@@ -1504,6 +1451,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1504,6 +1451,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1504 self.error_flags.no_entry_point_found = false;1451 self.error_flags.no_entry_point_found = false;
1505 try self.writeHeader();1452 try self.writeHeader();
1506 }1453 }
1454
1455 assert(!self.imports_count_dirty);
1507}1456}
15081457
1509pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {1458pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
...@@ -1526,7 +1475,7 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link...@@ -1526,7 +1475,7 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link
1526 return 0;1475 return 0;
1527}1476}
15281477
1529pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {1478pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 {
1530 const gop = try self.getOrPutGlobalPtr(name);1479 const gop = try self.getOrPutGlobalPtr(name);
1531 const global_index = self.getGlobalIndex(name).?;1480 const global_index = self.getGlobalIndex(name).?;
15321481
...@@ -1543,6 +1492,12 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {...@@ -1543,6 +1492,12 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
1543 try self.setSymbolName(sym, name);1492 try self.setSymbolName(sym, name);
1544 sym.storage_class = .EXTERNAL;1493 sym.storage_class = .EXTERNAL;
15451494
1495 if (lib_name_name) |lib_name| {
1496 // We repurpose the 'value' of the Symbol struct to store an offset into
1497 // temporary string table where we will store the library name hint.
1498 sym.value = try self.temp_strtab.insert(gpa, lib_name);
1499 }
1500
1546 try self.unresolved.putNoClobber(gpa, global_index, true);1501 try self.unresolved.putNoClobber(gpa, global_index, true);
15471502
1548 return global_index;1503 return global_index;
...@@ -1625,12 +1580,10 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1625,12 +1580,10 @@ fn writeBaseRelocations(self: *Coff) !void {
1625 const needed_size = @intCast(u32, buffer.items.len);1580 const needed_size = @intCast(u32, buffer.items.len);
1626 if (needed_size > sect_capacity) {1581 if (needed_size > sect_capacity) {
1627 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);1582 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
1628 log.debug("writing {s} at 0x{x} to 0x{x} (0x{x} - 0x{x})", .{1583 log.debug("moving {s} from 0x{x} to 0x{x}", .{
1629 self.getSectionName(header),1584 self.getSectionName(header),
1630 header.pointer_to_raw_data,1585 header.pointer_to_raw_data,
1631 header.pointer_to_raw_data + needed_size,
1632 new_offset,1586 new_offset,
1633 new_offset + needed_size,
1634 });1587 });
1635 header.pointer_to_raw_data = new_offset;1588 header.pointer_to_raw_data = new_offset;
16361589
...@@ -1651,88 +1604,144 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1651,88 +1604,144 @@ fn writeBaseRelocations(self: *Coff) !void {
1651 };1604 };
1652}1605}
16531606
1654fn writeImportTable(self: *Coff) !void {1607fn writeImportTables(self: *Coff) !void {
1655 if (self.idata_section_index == null) return;1608 if (self.idata_section_index == null) return;
1609 if (!self.imports_count_dirty) return;
16561610
1657 const gpa = self.base.allocator;1611 const gpa = self.base.allocator;
16581612
1659 const section = self.sections.get(self.idata_section_index.?);1613 const ext = ".dll";
1660 const last_atom_index = section.last_atom_index orelse return;1614 const header = &self.sections.items(.header)[self.idata_section_index.?];
1661 const last_atom = self.getAtom(last_atom_index);1615
1616 // Calculate needed size
1617 var iat_size: u32 = 0;
1618 var dir_table_size: u32 = @sizeOf(coff.ImportDirectoryEntry); // sentinel
1619 var lookup_table_size: u32 = 0;
1620 var names_table_size: u32 = 0;
1621 var dll_names_size: u32 = 0;
1622 for (self.import_tables.keys(), 0..) |off, i| {
1623 const lib_name = self.temp_strtab.getAssumeExists(off);
1624 const itable = self.import_tables.values()[i];
1625 iat_size += itable.size() + 8;
1626 dir_table_size += @sizeOf(coff.ImportDirectoryEntry);
1627 lookup_table_size += @intCast(u32, itable.entries.items.len + 1) * @sizeOf(coff.ImportLookupEntry64.ByName);
1628 for (itable.entries.items) |entry| {
1629 const sym_name = self.getSymbolName(entry);
1630 names_table_size += 2 + mem.alignForwardGeneric(u32, @intCast(u32, sym_name.len + 1), 2);
1631 }
1632 dll_names_size += @intCast(u32, lib_name.len + ext.len + 1);
1633 }
16621634
1663 const iat_rva = section.header.virtual_address;1635 const needed_size = iat_size + dir_table_size + lookup_table_size + names_table_size + dll_names_size;
1664 const iat_size = last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer1636 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
1637 if (needed_size > sect_capacity) {
1638 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
1639 log.debug("moving .idata from 0x{x} to 0x{x}", .{ header.pointer_to_raw_data, new_offset });
1640 header.pointer_to_raw_data = new_offset;
16651641
1666 const dll_name = "KERNEL32.dll";1642 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);
1643 if (needed_size > sect_vm_capacity) {
1644 try self.growSectionVM(self.idata_section_index.?, needed_size);
1645 }
16671646
1668 var import_dir_entry = coff.ImportDirectoryEntry{1647 header.virtual_size = @max(header.virtual_size, needed_size);
1669 .import_lookup_table_rva = @sizeOf(coff.ImportDirectoryEntry) * 2,1648 header.size_of_raw_data = needed_size;
1670 .time_date_stamp = 0,1649 }
1671 .forwarder_chain = 0,
1672 .name_rva = 0,
1673 .import_address_table_rva = iat_rva,
1674 };
16751650
1676 // TODO: we currently assume there's only one (implicit) DLL - ntdll1651 // Do the actual writes
1677 var lookup_table = std.ArrayList(coff.ImportLookupEntry64.ByName).init(gpa);1652 var buffer = std.ArrayList(u8).init(gpa);
1678 defer lookup_table.deinit();1653 defer buffer.deinit();
16791654 try buffer.ensureTotalCapacityPrecise(needed_size);
1680 var names_table = std.ArrayList(u8).init(gpa);1655 buffer.resize(needed_size) catch unreachable;
1681 defer names_table.deinit();1656
16821657 const dir_header_size = @sizeOf(coff.ImportDirectoryEntry);
1683 // TODO: check if import is still valid1658 const lookup_entry_size = @sizeOf(coff.ImportLookupEntry64.ByName);
1684 for (self.imports.items) |entry| {1659
1685 const target_name = self.getSymbolName(entry.target);1660 var iat_offset: u32 = 0;
1686 const start = names_table.items.len;1661 var dir_table_offset = iat_size;
1687 mem.writeIntLittle(u16, try names_table.addManyAsArray(2), 0); // TODO: currently, hint is set to 0 as we haven't yet parsed any DLL1662 var lookup_table_offset = dir_table_offset + dir_table_size;
1688 try names_table.appendSlice(target_name);1663 var names_table_offset = lookup_table_offset + lookup_table_size;
1689 try names_table.append(0);1664 var dll_names_offset = names_table_offset + names_table_size;
1690 const end = names_table.items.len;1665 for (self.import_tables.keys(), 0..) |off, i| {
1691 if (!mem.isAlignedGeneric(usize, end - start, @sizeOf(u16))) {1666 const lib_name = self.temp_strtab.getAssumeExists(off);
1692 try names_table.append(0);1667 const itable = self.import_tables.values()[i];
1668
1669 // Lookup table header
1670 const lookup_header = coff.ImportDirectoryEntry{
1671 .import_lookup_table_rva = header.virtual_address + lookup_table_offset,
1672 .time_date_stamp = 0,
1673 .forwarder_chain = 0,
1674 .name_rva = header.virtual_address + dll_names_offset,
1675 .import_address_table_rva = header.virtual_address + iat_offset,
1676 };
1677 mem.copy(u8, buffer.items[dir_table_offset..], mem.asBytes(&lookup_header));
1678 dir_table_offset += dir_header_size;
1679
1680 for (itable.entries.items) |entry| {
1681 const import_name = self.getSymbolName(entry);
1682
1683 // IAT and lookup table entry
1684 const lookup = coff.ImportLookupEntry64.ByName{ .name_table_rva = @intCast(u31, header.virtual_address + names_table_offset) };
1685 mem.copy(u8, buffer.items[iat_offset..], mem.asBytes(&lookup));
1686 iat_offset += lookup_entry_size;
1687 mem.copy(u8, buffer.items[lookup_table_offset..], mem.asBytes(&lookup));
1688 lookup_table_offset += lookup_entry_size;
1689
1690 // Names table entry
1691 mem.writeIntLittle(u16, buffer.items[names_table_offset..][0..2], 0); // Hint set to 0 until we learn how to parse DLLs
1692 names_table_offset += 2;
1693 mem.copy(u8, buffer.items[names_table_offset..], import_name);
1694 names_table_offset += @intCast(u32, import_name.len);
1695 buffer.items[names_table_offset] = 0;
1696 names_table_offset += 1;
1697 if (!mem.isAlignedGeneric(usize, names_table_offset, @sizeOf(u16))) {
1698 buffer.items[names_table_offset] = 0;
1699 names_table_offset += 1;
1700 }
1693 }1701 }
1694 try lookup_table.append(.{ .name_table_rva = @intCast(u31, start) });
1695 }
1696 try lookup_table.append(.{ .name_table_rva = 0 }); // the sentinel
16971702
1698 const dir_entry_size = @sizeOf(coff.ImportDirectoryEntry) + lookup_table.items.len * @sizeOf(coff.ImportLookupEntry64.ByName) + names_table.items.len + dll_name.len + 1;1703 // IAT sentinel
1699 const needed_size = iat_size + dir_entry_size + @sizeOf(coff.ImportDirectoryEntry);1704 mem.writeIntLittle(u64, buffer.items[iat_offset..][0..lookup_entry_size], 0);
1700 const sect_capacity = self.allocatedSize(section.header.pointer_to_raw_data);1705 iat_offset += 8;
1701 assert(needed_size < sect_capacity); // TODO: implement expanding .idata section
17021706
1703 // Fixup offsets1707 // Lookup table sentinel
1704 const base_rva = iat_rva + iat_size;1708 mem.copy(u8, buffer.items[lookup_table_offset..], mem.asBytes(&coff.ImportLookupEntry64.ByName{ .name_table_rva = 0 }));
1705 import_dir_entry.import_lookup_table_rva += base_rva;1709 lookup_table_offset += lookup_entry_size;
1706 import_dir_entry.name_rva = @intCast(u32, base_rva + dir_entry_size + @sizeOf(coff.ImportDirectoryEntry) - dll_name.len - 1);
17071710
1708 for (lookup_table.items[0 .. lookup_table.items.len - 1]) |*lk| {1711 // DLL name
1709 lk.name_table_rva += @intCast(u31, base_rva + @sizeOf(coff.ImportDirectoryEntry) * 2 + lookup_table.items.len * @sizeOf(coff.ImportLookupEntry64.ByName));1712 mem.copy(u8, buffer.items[dll_names_offset..], lib_name);
1713 dll_names_offset += @intCast(u32, lib_name.len);
1714 mem.copy(u8, buffer.items[dll_names_offset..], ext);
1715 dll_names_offset += @intCast(u32, ext.len);
1716 buffer.items[dll_names_offset] = 0;
1717 dll_names_offset += 1;
1710 }1718 }
17111719
1712 var buffer = std.ArrayList(u8).init(gpa);1720 // Sentinel
1713 defer buffer.deinit();1721 const lookup_header = coff.ImportDirectoryEntry{
1714 try buffer.ensureTotalCapacity(dir_entry_size + @sizeOf(coff.ImportDirectoryEntry));1722 .import_lookup_table_rva = 0,
1715 buffer.appendSliceAssumeCapacity(mem.asBytes(&import_dir_entry));1723 .time_date_stamp = 0,
1716 buffer.appendNTimesAssumeCapacity(0, @sizeOf(coff.ImportDirectoryEntry)); // the sentinel; TODO: I think doing all of the above on bytes directly might be cleaner1724 .forwarder_chain = 0,
1717 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(lookup_table.items));1725 .name_rva = 0,
1718 buffer.appendSliceAssumeCapacity(names_table.items);1726 .import_address_table_rva = 0,
1719 buffer.appendSliceAssumeCapacity(dll_name);1727 };
1720 buffer.appendAssumeCapacity(0);1728 mem.copy(u8, buffer.items[dir_table_offset..], mem.asBytes(&lookup_header));
17211729 dir_table_offset += dir_header_size;
1722 try self.base.file.?.pwriteAll(buffer.items, section.header.pointer_to_raw_data + iat_size);1730
1723 // Override the IAT atoms1731 assert(dll_names_offset == needed_size);
1724 // TODO: we should rewrite only dirtied atoms, but that's for way later1732
1725 try self.base.file.?.pwriteAll(mem.sliceAsBytes(lookup_table.items), section.header.pointer_to_raw_data);1733 try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);
17261734
1727 self.data_directories[@enumToInt(coff.DirectoryEntry.IMPORT)] = .{1735 self.data_directories[@enumToInt(coff.DirectoryEntry.IMPORT)] = .{
1728 .virtual_address = iat_rva + iat_size,1736 .virtual_address = header.virtual_address + iat_size,
1729 .size = @intCast(u32, @sizeOf(coff.ImportDirectoryEntry) * 2),1737 .size = dir_table_size,
1730 };1738 };
1731
1732 self.data_directories[@enumToInt(coff.DirectoryEntry.IAT)] = .{1739 self.data_directories[@enumToInt(coff.DirectoryEntry.IAT)] = .{
1733 .virtual_address = iat_rva,1740 .virtual_address = header.virtual_address,
1734 .size = iat_size,1741 .size = iat_size,
1735 };1742 };
1743
1744 self.imports_count_dirty = false;
1736}1745}
17371746
1738fn writeStrtab(self: *Coff) !void {1747fn writeStrtab(self: *Coff) !void {
...@@ -2121,14 +2130,6 @@ pub fn getGotAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom...@@ -2121,14 +2130,6 @@ pub fn getGotAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom
2121 return self.getAtomIndexForSymbol(.{ .sym_index = got_entry.sym_index, .file = null });2130 return self.getAtomIndexForSymbol(.{ .sym_index = got_entry.sym_index, .file = null });
2122}2131}
21232132
2124/// Returns import atom that references `sym_loc` if one exists.
2125/// Returns null otherwise.
2126pub fn getImportAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
2127 const imports_index = self.imports_table.get(sym_loc) orelse return null;
2128 const imports_entry = self.imports.items[imports_index];
2129 return self.getAtomIndexForSymbol(.{ .sym_index = imports_entry.sym_index, .file = null });
2130}
2131
2132fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {2133fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {
2133 if (name.len <= 8) {2134 if (name.len <= 8) {
2134 mem.copy(u8, &header.name, name);2135 mem.copy(u8, &header.name, name);
...@@ -2249,3 +2250,50 @@ fn logSections(self: *Coff) void {...@@ -2249,3 +2250,50 @@ fn logSections(self: *Coff) void {
2249 });2250 });
2250 }2251 }
2251}2252}
2253
2254fn logImportTables(self: *const Coff) void {
2255 log.debug("import tables:", .{});
2256 for (self.import_tables.keys(), 0..) |off, i| {
2257 const itable = self.import_tables.values()[i];
2258 log.debug("{}", .{itable.fmtDebug(.{
2259 .coff_file = self,
2260 .index = i,
2261 .name_off = off,
2262 })});
2263 }
2264}
2265
2266const Coff = @This();
2267
2268const std = @import("std");
2269const build_options = @import("build_options");
2270const builtin = @import("builtin");
2271const assert = std.debug.assert;
2272const coff = std.coff;
2273const fmt = std.fmt;
2274const log = std.log.scoped(.link);
2275const math = std.math;
2276const mem = std.mem;
2277
2278const Allocator = std.mem.Allocator;
2279
2280const codegen = @import("../codegen.zig");
2281const link = @import("../link.zig");
2282const lld = @import("Coff/lld.zig");
2283const trace = @import("../tracy.zig").trace;
2284
2285const Air = @import("../Air.zig");
2286pub const Atom = @import("Coff/Atom.zig");
2287const Compilation = @import("../Compilation.zig");
2288const ImportTable = @import("Coff/ImportTable.zig");
2289const Liveness = @import("../Liveness.zig");
2290const LlvmObject = @import("../codegen/llvm.zig").Object;
2291const Module = @import("../Module.zig");
2292const Object = @import("Coff/Object.zig");
2293const Relocation = @import("Coff/Relocation.zig");
2294const StringTable = @import("strtab.zig").StringTable;
2295const TypedValue = @import("../TypedValue.zig");
2296
2297pub const base_tag: link.File.Tag = .coff;
2298
2299const msdos_stub = @embedFile("msdos-stub.bin");
src/link/Coff/ImportTable.zig created+133
...@@ -0,0 +1,133 @@
1//! Represents an import table in the .idata section where each contained pointer
2//! is to a symbol from the same DLL.
3//!
4//! The layout of .idata section is as follows:
5//!
6//! --- ADDR1 : IAT (all import tables concatenated together)
7//! ptr
8//! ptr
9//! 0 sentinel
10//! ptr
11//! 0 sentinel
12//! --- ADDR2: headers
13//! ImportDirectoryEntry header
14//! ImportDirectoryEntry header
15//! sentinel
16//! --- ADDR2: lookup tables
17//! Lookup table
18//! 0 sentinel
19//! Lookup table
20//! 0 sentinel
21//! --- ADDR3: name hint tables
22//! hint-symname
23//! hint-symname
24//! --- ADDR4: DLL names
25//! DLL#1 name
26//! DLL#2 name
27//! --- END
28
29entries: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
30free_list: std.ArrayListUnmanaged(u32) = .{},
31lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
32
33pub fn deinit(itab: *ImportTable, allocator: Allocator) void {
34 itab.entries.deinit(allocator);
35 itab.free_list.deinit(allocator);
36 itab.lookup.deinit(allocator);
37}
38
39/// Size of the import table does not include the sentinel.
40pub fn size(itab: ImportTable) u32 {
41 return @intCast(u32, itab.entries.items.len) * @sizeOf(u64);
42}
43
44pub fn addImport(itab: *ImportTable, allocator: Allocator, target: SymbolWithLoc) !ImportIndex {
45 try itab.entries.ensureUnusedCapacity(allocator, 1);
46 const index: u32 = blk: {
47 if (itab.free_list.popOrNull()) |index| {
48 log.debug(" (reusing import entry index {d})", .{index});
49 break :blk index;
50 } else {
51 log.debug(" (allocating import entry at index {d})", .{itab.entries.items.len});
52 const index = @intCast(u32, itab.entries.items.len);
53 _ = itab.entries.addOneAssumeCapacity();
54 break :blk index;
55 }
56 };
57 itab.entries.items[index] = target;
58 try itab.lookup.putNoClobber(allocator, target, index);
59 return index;
60}
61
62const Context = struct {
63 coff_file: *const Coff,
64 /// Index of this ImportTable in a global list of all tables.
65 /// This is required in order to calculate the base vaddr of this ImportTable.
66 index: usize,
67 /// Offset into the string interning table of the DLL this ImportTable corresponds to.
68 name_off: u32,
69};
70
71fn getBaseAddress(ctx: Context) u32 {
72 const header = ctx.coff_file.sections.items(.header)[ctx.coff_file.idata_section_index.?];
73 var addr = header.virtual_address;
74 for (ctx.coff_file.import_tables.values(), 0..) |other_itab, i| {
75 if (ctx.index == i) break;
76 addr += @intCast(u32, other_itab.entries.items.len * @sizeOf(u64)) + 8;
77 }
78 return addr;
79}
80
81pub fn getImportAddress(itab: *const ImportTable, target: SymbolWithLoc, ctx: Context) ?u32 {
82 const index = itab.lookup.get(target) orelse return null;
83 const base_vaddr = getBaseAddress(ctx);
84 return base_vaddr + index * @sizeOf(u64);
85}
86
87const FormatContext = struct {
88 itab: ImportTable,
89 ctx: Context,
90};
91
92fn fmt(
93 fmt_ctx: FormatContext,
94 comptime unused_format_string: []const u8,
95 options: std.fmt.FormatOptions,
96 writer: anytype,
97) @TypeOf(writer).Error!void {
98 _ = options;
99 comptime assert(unused_format_string.len == 0);
100 const lib_name = fmt_ctx.ctx.coff_file.temp_strtab.getAssumeExists(fmt_ctx.ctx.name_off);
101 const base_vaddr = getBaseAddress(fmt_ctx.ctx);
102 try writer.print("IAT({s}.dll) @{x}:", .{ lib_name, base_vaddr });
103 for (fmt_ctx.itab.entries.items, 0..) |entry, i| {
104 try writer.print("\n {d}@{?x} => {s}", .{
105 i,
106 fmt_ctx.itab.getImportAddress(entry, fmt_ctx.ctx),
107 fmt_ctx.ctx.coff_file.getSymbolName(entry),
108 });
109 }
110}
111
112fn format(itab: ImportTable, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
113 _ = itab;
114 _ = unused_format_string;
115 _ = options;
116 _ = writer;
117 @compileError("do not format ImportTable directly; use itab.fmtDebug()");
118}
119
120pub fn fmtDebug(itab: ImportTable, ctx: Context) std.fmt.Formatter(fmt) {
121 return .{ .data = .{ .itab = itab, .ctx = ctx } };
122}
123
124const ImportIndex = u32;
125const ImportTable = @This();
126
127const std = @import("std");
128const assert = std.debug.assert;
129const log = std.log.scoped(.link);
130
131const Allocator = std.mem.Allocator;
132const Coff = @import("../Coff.zig");
133const SymbolWithLoc = Coff.SymbolWithLoc;
src/link/Coff/Relocation.zig+24-19
...@@ -45,23 +45,30 @@ pcrel: bool,...@@ -45,23 +45,30 @@ pcrel: bool,
45length: u2,45length: u2,
46dirty: bool = true,46dirty: bool = true,
4747
48/// Returns an Atom which is the target node of this relocation edge (if any).48/// Returns address of the target if any.
49pub fn getTargetAtomIndex(self: Relocation, coff_file: *const Coff) ?Atom.Index {49pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
50 switch (self.type) {50 switch (self.type) {
51 .got,51 .got, .got_page, .got_pageoff, .direct, .page, .pageoff => {
52 .got_page,52 const maybe_target_atom_index = switch (self.type) {
53 .got_pageoff,53 .got, .got_page, .got_pageoff => coff_file.getGotAtomIndexForSymbol(self.target),
54 => return coff_file.getGotAtomIndexForSymbol(self.target),54 .direct, .page, .pageoff => coff_file.getAtomIndexForSymbol(self.target),
5555 else => unreachable,
56 .direct,56 };
57 .page,57 const target_atom_index = maybe_target_atom_index orelse return null;
58 .pageoff,58 const target_atom = coff_file.getAtom(target_atom_index);
59 => return coff_file.getAtomIndexForSymbol(self.target),59 return target_atom.getSymbol(coff_file).value;
6060 },
61 .import,61
62 .import_page,62 .import, .import_page, .import_pageoff => {
63 .import_pageoff,63 const sym = coff_file.getSymbol(self.target);
64 => return coff_file.getImportAtomIndexForSymbol(self.target),64 const index = coff_file.import_tables.getIndex(sym.value) orelse return null;
65 const itab = coff_file.import_tables.values()[index];
66 return itab.getImportAddress(self.target, .{
67 .coff_file = coff_file,
68 .index = index,
69 .name_off = sym.value,
70 });
71 },
65 }72 }
66}73}
6774
...@@ -73,9 +80,7 @@ pub fn resolve(self: *Relocation, atom_index: Atom.Index, coff_file: *Coff) !voi...@@ -73,9 +80,7 @@ pub fn resolve(self: *Relocation, atom_index: Atom.Index, coff_file: *Coff) !voi
7380
74 const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address;81 const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address;
7582
76 const target_atom_index = self.getTargetAtomIndex(coff_file) orelse return;83 const target_vaddr = self.getTargetAddress(coff_file) orelse return;
77 const target_atom = coff_file.getAtom(target_atom_index);
78 const target_vaddr = target_atom.getSymbol(coff_file).value;
79 const target_vaddr_with_addend = target_vaddr + self.addend;84 const target_vaddr_with_addend = target_vaddr + self.addend;
8085
81 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{86 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{
src/link/MachO.zig+2-1
...@@ -3202,7 +3202,8 @@ fn insertSection(self: *MachO, segment_index: u8, header: macho.section_64) !u8...@@ -3202,7 +3202,8 @@ fn insertSection(self: *MachO, segment_index: u8, header: macho.section_64) !u8
3202 return insertion_index;3202 return insertion_index;
3203}3203}
32043204
3205pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {3205pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {
3206 _ = lib_name;
3206 const gpa = self.base.allocator;3207 const gpa = self.base.allocator;
32073208
3208 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});3209 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
src/link/Wasm.zig+2-1
...@@ -1573,7 +1573,8 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1573,7 +1573,8 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1573/// such as an exported or imported symbol.1573/// such as an exported or imported symbol.
1574/// If the symbol does not yet exist, creates a new one symbol instead1574/// If the symbol does not yet exist, creates a new one symbol instead
1575/// and then returns the index to it.1575/// and then returns the index to it.
1576pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8) !u32 {1576pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 {
1577 _ = lib_name;
1577 const name_index = try wasm.string_table.put(wasm.base.allocator, name);1578 const name_index = try wasm.string_table.put(wasm.base.allocator, name);
1578 const gop = try wasm.globals.getOrPut(wasm.base.allocator, name_index);1579 const gop = try wasm.globals.getOrPut(wasm.base.allocator, name_index);
1579 if (gop.found_existing) {1580 if (gop.found_existing) {
test/tests.zig-1
...@@ -112,7 +112,6 @@ const test_targets = blk: {...@@ -112,7 +112,6 @@ const test_targets = blk: {
112 .os_tag = .windows,112 .os_tag = .windows,
113 .abi = .gnu,113 .abi = .gnu,
114 },114 },
115 .single_threaded = true, // https://github.com/ziglang/zig/issues/15075
116 .backend = .stage2_x86_64,115 .backend = .stage2_x86_64,
117 },116 },
118117