authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-28 14:13:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-28 14:13:39+02:00
logdb877df8eb1831891fc1f3cb6dab1503868b5732
treef23e2edcc7cfafaf09b05228b1f67f74afc3ae78
parentfb3345e346d26cfac01e45e3662385c587ec3462

coff: move import table definition into a separate ImportTable.zig module


4 files changed, 186 insertions(+), 131 deletions(-)

CMakeLists.txt+1
......@@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES
583583 "${CMAKE_SOURCE_DIR}/src/link/C.zig"
584584 "${CMAKE_SOURCE_DIR}/src/link/Coff.zig"
585585 "${CMAKE_SOURCE_DIR}/src/link/Coff/Atom.zig"
586 "${CMAKE_SOURCE_DIR}/src/link/Coff/ImportTable.zig"
586587 "${CMAKE_SOURCE_DIR}/src/link/Coff/Object.zig"
587588 "${CMAKE_SOURCE_DIR}/src/link/Coff/lld.zig"
588589 "${CMAKE_SOURCE_DIR}/src/link/Elf.zig"
src/link/Coff.zig+45-129
......@@ -1,36 +1,7 @@
1const Coff = @This();
2
3const std = @import("std");
4const build_options = @import("build_options");
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");
1//! The main driver of the COFF linker.
2//! Currently uses our own implementation for the incremental linker, and falls back to
3//! LLD for traditional linking (linking relocatable object files).
4//! LLD is also the default linker for LLVM.
345
356/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
367llvm_object: ?*LlvmObject = null,
......@@ -160,92 +131,6 @@ const Section = struct {
160131 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
161132};
162133
163/// Represents an import table in the .idata section where each contained pointer
164/// is to a symbol from the same DLL.
165///
166/// The layout of .idata section is as follows:
167///
168/// --- ADDR1 : IAT (all import tables concatenated together)
169/// ptr
170/// ptr
171/// 0 sentinel
172/// ptr
173/// 0 sentinel
174/// --- ADDR2: headers
175/// ImportDirectoryEntry header
176/// ImportDirectoryEntry header
177/// sentinel
178/// --- ADDR2: lookup tables
179/// Lookup table
180/// 0 sentinel
181/// Lookup table
182/// 0 sentinel
183/// --- ADDR3: name hint tables
184/// hint-symname
185/// hint-symname
186/// --- ADDR4: DLL names
187/// DLL#1 name
188/// DLL#2 name
189/// --- END
190const ImportTable = struct {
191 entries: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
192 free_list: std.ArrayListUnmanaged(u32) = .{},
193 lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
194 index: u8,
195
196 const ITable = @This();
197
198 fn deinit(itab: *ITable, allocator: Allocator) void {
199 itab.entries.deinit(allocator);
200 itab.free_list.deinit(allocator);
201 itab.lookup.deinit(allocator);
202 }
203
204 fn size(itab: ITable) u32 {
205 return @intCast(u32, itab.entries.items.len) * @sizeOf(u64);
206 }
207
208 fn addImport(itab: *ITable, allocator: Allocator, target: SymbolWithLoc) !u32 {
209 try itab.entries.ensureUnusedCapacity(allocator, 1);
210 const index: u32 = blk: {
211 if (itab.free_list.popOrNull()) |index| {
212 log.debug(" (reusing import entry index {d})", .{index});
213 break :blk index;
214 } else {
215 log.debug(" (allocating import entry at index {d})", .{itab.entries.items.len});
216 const index = @intCast(u32, itab.entries.items.len);
217 _ = itab.entries.addOneAssumeCapacity();
218 break :blk index;
219 }
220 };
221 itab.entries.items[index] = target;
222 try itab.lookup.putNoClobber(allocator, target, index);
223 return index;
224 }
225
226 fn getBaseAddress(itab: *const ITable, coff_file: *const Coff) u32 {
227 const header = coff_file.sections.items(.header)[coff_file.idata_section_index.?];
228 var addr = header.virtual_address;
229 for (coff_file.import_tables.values(), 0..) |other_itab, i| {
230 if (itab.index == i) break;
231 addr += @intCast(u32, other_itab.entries.items.len * @sizeOf(u64)) + 8;
232 }
233 return addr;
234 }
235
236 pub fn getImportAddress(itab: *const ITable, coff_file: *const Coff, target: SymbolWithLoc) ?u32 {
237 const index = itab.lookup.get(target) orelse return null;
238 const base_vaddr = itab.getBaseAddress(coff_file);
239 return base_vaddr + index * @sizeOf(u64);
240 }
241
242 pub fn write(itab: ITable, writer: anytype) !void {
243 for (itab.entries.items) |_| {
244 try writer.writeIntLittle(u64, 0);
245 }
246 }
247};
248
249134const DeclMetadata = struct {
250135 atom: Atom.Index,
251136 section: u16,
......@@ -1527,7 +1412,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
15271412 const res = try self.import_tables.getOrPut(gpa, sym.value);
15281413 const itable = res.value_ptr;
15291414 if (!res.found_existing) {
1530 itable.* = .{ .index = @intCast(u8, self.import_tables.values().len - 1) };
1415 itable.* = .{};
15311416 }
15321417 if (itable.lookup.contains(global)) continue;
15331418 // TODO: we could technically write the pointer placeholder for to-be-bound import here,
......@@ -2367,15 +2252,46 @@ fn logSections(self: *Coff) void {
23672252fn logImportTables(self: *const Coff) void {
23682253 log.debug("import tables:", .{});
23692254 for (self.import_tables.keys(), 0..) |off, i| {
2370 const lib_name = self.temp_strtab.getAssumeExists(off);
23712255 const itable = self.import_tables.values()[i];
2372 log.debug("IAT({s}) @{x}:", .{ lib_name, itable.getBaseAddress(self) });
2373 for (itable.entries.items, 0..) |entry, j| {
2374 log.debug(" {d}@{?x} => {s}", .{
2375 j,
2376 itable.getImportAddress(self, entry),
2377 self.getSymbolName(entry),
2378 });
2379 }
2256 log.debug("{}", .{itable.fmtDebug(.{
2257 .coff_file = self,
2258 .index = i,
2259 .name_off = off,
2260 })});
23802261 }
23812262}
2263
2264const Coff = @This();
2265
2266const std = @import("std");
2267const build_options = @import("build_options");
2268const builtin = @import("builtin");
2269const assert = std.debug.assert;
2270const coff = std.coff;
2271const fmt = std.fmt;
2272const log = std.log.scoped(.link);
2273const math = std.math;
2274const mem = std.mem;
2275
2276const Allocator = std.mem.Allocator;
2277
2278const codegen = @import("../codegen.zig");
2279const link = @import("../link.zig");
2280const lld = @import("Coff/lld.zig");
2281const trace = @import("../tracy.zig").trace;
2282
2283const Air = @import("../Air.zig");
2284pub const Atom = @import("Coff/Atom.zig");
2285const Compilation = @import("../Compilation.zig");
2286const ImportTable = @import("Coff/ImportTable.zig");
2287const Liveness = @import("../Liveness.zig");
2288const LlvmObject = @import("../codegen/llvm.zig").Object;
2289const Module = @import("../Module.zig");
2290const Object = @import("Coff/Object.zig");
2291const Relocation = @import("Coff/Relocation.zig");
2292const StringTable = @import("strtab.zig").StringTable;
2293const TypedValue = @import("../TypedValue.zig");
2294
2295pub const base_tag: link.File.Tag = .coff;
2296
2297const 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+7-2
......@@ -61,8 +61,13 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
6161
6262 .import, .import_page, .import_pageoff => {
6363 const sym = coff_file.getSymbol(self.target);
64 const itab = coff_file.import_tables.get(sym.value) orelse return null;
65 return itab.getImportAddress(coff_file, 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 });
6671 },
6772 }
6873}