aboutsummaryrefslogtreecommitdiff
path: root/src/link/Coff/ImportTable.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-03-28 14:13:39 +0200
committerJakub Konka <kubkon@jakubkonka.com>2023-03-28 14:13:39 +0200
commitdb877df8eb1831891fc1f3cb6dab1503868b5732 (patch)
treef23e2edcc7cfafaf09b05228b1f67f74afc3ae78 /src/link/Coff/ImportTable.zig
parentfb3345e346d26cfac01e45e3662385c587ec3462 (diff)
downloadzig-db877df8eb1831891fc1f3cb6dab1503868b5732.tar.gz
zig-db877df8eb1831891fc1f3cb6dab1503868b5732.zip
coff: move import table definition into a separate ImportTable.zig module
Diffstat (limited to 'src/link/Coff/ImportTable.zig')
-rw-r--r--src/link/Coff/ImportTable.zig133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/link/Coff/ImportTable.zig b/src/link/Coff/ImportTable.zig
new file mode 100644
index 0000000000..ba58af2fe0
--- /dev/null
+++ b/src/link/Coff/ImportTable.zig
@@ -0,0 +1,133 @@
+//! Represents an import table in the .idata section where each contained pointer
+//! is to a symbol from the same DLL.
+//!
+//! The layout of .idata section is as follows:
+//!
+//! --- ADDR1 : IAT (all import tables concatenated together)
+//! ptr
+//! ptr
+//! 0 sentinel
+//! ptr
+//! 0 sentinel
+//! --- ADDR2: headers
+//! ImportDirectoryEntry header
+//! ImportDirectoryEntry header
+//! sentinel
+//! --- ADDR2: lookup tables
+//! Lookup table
+//! 0 sentinel
+//! Lookup table
+//! 0 sentinel
+//! --- ADDR3: name hint tables
+//! hint-symname
+//! hint-symname
+//! --- ADDR4: DLL names
+//! DLL#1 name
+//! DLL#2 name
+//! --- END
+
+entries: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
+free_list: std.ArrayListUnmanaged(u32) = .{},
+lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
+
+pub fn deinit(itab: *ImportTable, allocator: Allocator) void {
+ itab.entries.deinit(allocator);
+ itab.free_list.deinit(allocator);
+ itab.lookup.deinit(allocator);
+}
+
+/// Size of the import table does not include the sentinel.
+pub fn size(itab: ImportTable) u32 {
+ return @intCast(u32, itab.entries.items.len) * @sizeOf(u64);
+}
+
+pub fn addImport(itab: *ImportTable, allocator: Allocator, target: SymbolWithLoc) !ImportIndex {
+ try itab.entries.ensureUnusedCapacity(allocator, 1);
+ const index: u32 = blk: {
+ if (itab.free_list.popOrNull()) |index| {
+ log.debug(" (reusing import entry index {d})", .{index});
+ break :blk index;
+ } else {
+ log.debug(" (allocating import entry at index {d})", .{itab.entries.items.len});
+ const index = @intCast(u32, itab.entries.items.len);
+ _ = itab.entries.addOneAssumeCapacity();
+ break :blk index;
+ }
+ };
+ itab.entries.items[index] = target;
+ try itab.lookup.putNoClobber(allocator, target, index);
+ return index;
+}
+
+const Context = struct {
+ coff_file: *const Coff,
+ /// Index of this ImportTable in a global list of all tables.
+ /// This is required in order to calculate the base vaddr of this ImportTable.
+ index: usize,
+ /// Offset into the string interning table of the DLL this ImportTable corresponds to.
+ name_off: u32,
+};
+
+fn getBaseAddress(ctx: Context) u32 {
+ const header = ctx.coff_file.sections.items(.header)[ctx.coff_file.idata_section_index.?];
+ var addr = header.virtual_address;
+ for (ctx.coff_file.import_tables.values(), 0..) |other_itab, i| {
+ if (ctx.index == i) break;
+ addr += @intCast(u32, other_itab.entries.items.len * @sizeOf(u64)) + 8;
+ }
+ return addr;
+}
+
+pub fn getImportAddress(itab: *const ImportTable, target: SymbolWithLoc, ctx: Context) ?u32 {
+ const index = itab.lookup.get(target) orelse return null;
+ const base_vaddr = getBaseAddress(ctx);
+ return base_vaddr + index * @sizeOf(u64);
+}
+
+const FormatContext = struct {
+ itab: ImportTable,
+ ctx: Context,
+};
+
+fn fmt(
+ fmt_ctx: FormatContext,
+ comptime unused_format_string: []const u8,
+ options: std.fmt.FormatOptions,
+ writer: anytype,
+) @TypeOf(writer).Error!void {
+ _ = options;
+ comptime assert(unused_format_string.len == 0);
+ const lib_name = fmt_ctx.ctx.coff_file.temp_strtab.getAssumeExists(fmt_ctx.ctx.name_off);
+ const base_vaddr = getBaseAddress(fmt_ctx.ctx);
+ try writer.print("IAT({s}.dll) @{x}:", .{ lib_name, base_vaddr });
+ for (fmt_ctx.itab.entries.items, 0..) |entry, i| {
+ try writer.print("\n {d}@{?x} => {s}", .{
+ i,
+ fmt_ctx.itab.getImportAddress(entry, fmt_ctx.ctx),
+ fmt_ctx.ctx.coff_file.getSymbolName(entry),
+ });
+ }
+}
+
+fn format(itab: ImportTable, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
+ _ = itab;
+ _ = unused_format_string;
+ _ = options;
+ _ = writer;
+ @compileError("do not format ImportTable directly; use itab.fmtDebug()");
+}
+
+pub fn fmtDebug(itab: ImportTable, ctx: Context) std.fmt.Formatter(fmt) {
+ return .{ .data = .{ .itab = itab, .ctx = ctx } };
+}
+
+const ImportIndex = u32;
+const ImportTable = @This();
+
+const std = @import("std");
+const assert = std.debug.assert;
+const log = std.log.scoped(.link);
+
+const Allocator = std.mem.Allocator;
+const Coff = @import("../Coff.zig");
+const SymbolWithLoc = Coff.SymbolWithLoc;