mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
coff: move import table definition into a separate ImportTable.zig module
This commit is contained in:
parent
fb3345e346
commit
db877df8eb
4 changed files with 186 additions and 131 deletions
|
|
@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES
|
||||||
"${CMAKE_SOURCE_DIR}/src/link/C.zig"
|
"${CMAKE_SOURCE_DIR}/src/link/C.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/link/Coff.zig"
|
"${CMAKE_SOURCE_DIR}/src/link/Coff.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/link/Coff/Atom.zig"
|
"${CMAKE_SOURCE_DIR}/src/link/Coff/Atom.zig"
|
||||||
|
"${CMAKE_SOURCE_DIR}/src/link/Coff/ImportTable.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/link/Coff/Object.zig"
|
"${CMAKE_SOURCE_DIR}/src/link/Coff/Object.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/link/Coff/lld.zig"
|
"${CMAKE_SOURCE_DIR}/src/link/Coff/lld.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/link/Elf.zig"
|
"${CMAKE_SOURCE_DIR}/src/link/Elf.zig"
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,7 @@
|
||||||
const Coff = @This();
|
//! The main driver of the COFF linker.
|
||||||
|
//! Currently uses our own implementation for the incremental linker, and falls back to
|
||||||
const std = @import("std");
|
//! LLD for traditional linking (linking relocatable object files).
|
||||||
const build_options = @import("build_options");
|
//! LLD is also the default linker for LLVM.
|
||||||
const builtin = @import("builtin");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const coff = std.coff;
|
|
||||||
const fmt = std.fmt;
|
|
||||||
const log = std.log.scoped(.link);
|
|
||||||
const math = std.math;
|
|
||||||
const mem = std.mem;
|
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const codegen = @import("../codegen.zig");
|
|
||||||
const link = @import("../link.zig");
|
|
||||||
const lld = @import("Coff/lld.zig");
|
|
||||||
const trace = @import("../tracy.zig").trace;
|
|
||||||
|
|
||||||
const Air = @import("../Air.zig");
|
|
||||||
pub const Atom = @import("Coff/Atom.zig");
|
|
||||||
const Compilation = @import("../Compilation.zig");
|
|
||||||
const Liveness = @import("../Liveness.zig");
|
|
||||||
const LlvmObject = @import("../codegen/llvm.zig").Object;
|
|
||||||
const Module = @import("../Module.zig");
|
|
||||||
const Object = @import("Coff/Object.zig");
|
|
||||||
const Relocation = @import("Coff/Relocation.zig");
|
|
||||||
const StringTable = @import("strtab.zig").StringTable;
|
|
||||||
const TypedValue = @import("../TypedValue.zig");
|
|
||||||
|
|
||||||
pub const base_tag: link.File.Tag = .coff;
|
|
||||||
|
|
||||||
const msdos_stub = @embedFile("msdos-stub.bin");
|
|
||||||
|
|
||||||
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
|
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
|
||||||
llvm_object: ?*LlvmObject = null,
|
llvm_object: ?*LlvmObject = null,
|
||||||
|
|
@ -160,92 +131,6 @@ const Section = struct {
|
||||||
free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
|
free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 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
|
|
||||||
const ImportTable = struct {
|
|
||||||
entries: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
|
|
||||||
free_list: std.ArrayListUnmanaged(u32) = .{},
|
|
||||||
lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
|
|
||||||
index: u8,
|
|
||||||
|
|
||||||
const ITable = @This();
|
|
||||||
|
|
||||||
fn deinit(itab: *ITable, allocator: Allocator) void {
|
|
||||||
itab.entries.deinit(allocator);
|
|
||||||
itab.free_list.deinit(allocator);
|
|
||||||
itab.lookup.deinit(allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(itab: ITable) u32 {
|
|
||||||
return @intCast(u32, itab.entries.items.len) * @sizeOf(u64);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn addImport(itab: *ITable, allocator: Allocator, target: SymbolWithLoc) !u32 {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getBaseAddress(itab: *const ITable, coff_file: *const Coff) u32 {
|
|
||||||
const header = coff_file.sections.items(.header)[coff_file.idata_section_index.?];
|
|
||||||
var addr = header.virtual_address;
|
|
||||||
for (coff_file.import_tables.values(), 0..) |other_itab, i| {
|
|
||||||
if (itab.index == i) break;
|
|
||||||
addr += @intCast(u32, other_itab.entries.items.len * @sizeOf(u64)) + 8;
|
|
||||||
}
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getImportAddress(itab: *const ITable, coff_file: *const Coff, target: SymbolWithLoc) ?u32 {
|
|
||||||
const index = itab.lookup.get(target) orelse return null;
|
|
||||||
const base_vaddr = itab.getBaseAddress(coff_file);
|
|
||||||
return base_vaddr + index * @sizeOf(u64);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(itab: ITable, writer: anytype) !void {
|
|
||||||
for (itab.entries.items) |_| {
|
|
||||||
try writer.writeIntLittle(u64, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const DeclMetadata = struct {
|
const DeclMetadata = struct {
|
||||||
atom: Atom.Index,
|
atom: Atom.Index,
|
||||||
section: u16,
|
section: u16,
|
||||||
|
|
@ -1527,7 +1412,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||||
const res = try self.import_tables.getOrPut(gpa, sym.value);
|
const res = try self.import_tables.getOrPut(gpa, sym.value);
|
||||||
const itable = res.value_ptr;
|
const itable = res.value_ptr;
|
||||||
if (!res.found_existing) {
|
if (!res.found_existing) {
|
||||||
itable.* = .{ .index = @intCast(u8, self.import_tables.values().len - 1) };
|
itable.* = .{};
|
||||||
}
|
}
|
||||||
if (itable.lookup.contains(global)) continue;
|
if (itable.lookup.contains(global)) continue;
|
||||||
// TODO: we could technically write the pointer placeholder for to-be-bound import here,
|
// TODO: we could technically write the pointer placeholder for to-be-bound import here,
|
||||||
|
|
@ -2367,15 +2252,46 @@ fn logSections(self: *Coff) void {
|
||||||
fn logImportTables(self: *const Coff) void {
|
fn logImportTables(self: *const Coff) void {
|
||||||
log.debug("import tables:", .{});
|
log.debug("import tables:", .{});
|
||||||
for (self.import_tables.keys(), 0..) |off, i| {
|
for (self.import_tables.keys(), 0..) |off, i| {
|
||||||
const lib_name = self.temp_strtab.getAssumeExists(off);
|
|
||||||
const itable = self.import_tables.values()[i];
|
const itable = self.import_tables.values()[i];
|
||||||
log.debug("IAT({s}) @{x}:", .{ lib_name, itable.getBaseAddress(self) });
|
log.debug("{}", .{itable.fmtDebug(.{
|
||||||
for (itable.entries.items, 0..) |entry, j| {
|
.coff_file = self,
|
||||||
log.debug(" {d}@{?x} => {s}", .{
|
.index = i,
|
||||||
j,
|
.name_off = off,
|
||||||
itable.getImportAddress(self, entry),
|
})});
|
||||||
self.getSymbolName(entry),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Coff = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const build_options = @import("build_options");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const coff = std.coff;
|
||||||
|
const fmt = std.fmt;
|
||||||
|
const log = std.log.scoped(.link);
|
||||||
|
const math = std.math;
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const codegen = @import("../codegen.zig");
|
||||||
|
const link = @import("../link.zig");
|
||||||
|
const lld = @import("Coff/lld.zig");
|
||||||
|
const trace = @import("../tracy.zig").trace;
|
||||||
|
|
||||||
|
const Air = @import("../Air.zig");
|
||||||
|
pub const Atom = @import("Coff/Atom.zig");
|
||||||
|
const Compilation = @import("../Compilation.zig");
|
||||||
|
const ImportTable = @import("Coff/ImportTable.zig");
|
||||||
|
const Liveness = @import("../Liveness.zig");
|
||||||
|
const LlvmObject = @import("../codegen/llvm.zig").Object;
|
||||||
|
const Module = @import("../Module.zig");
|
||||||
|
const Object = @import("Coff/Object.zig");
|
||||||
|
const Relocation = @import("Coff/Relocation.zig");
|
||||||
|
const StringTable = @import("strtab.zig").StringTable;
|
||||||
|
const TypedValue = @import("../TypedValue.zig");
|
||||||
|
|
||||||
|
pub const base_tag: link.File.Tag = .coff;
|
||||||
|
|
||||||
|
const msdos_stub = @embedFile("msdos-stub.bin");
|
||||||
|
|
|
||||||
133
src/link/Coff/ImportTable.zig
Normal file
133
src/link/Coff/ImportTable.zig
Normal file
|
|
@ -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;
|
||||||
|
|
@ -61,8 +61,13 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
|
||||||
|
|
||||||
.import, .import_page, .import_pageoff => {
|
.import, .import_page, .import_pageoff => {
|
||||||
const sym = coff_file.getSymbol(self.target);
|
const sym = coff_file.getSymbol(self.target);
|
||||||
const itab = coff_file.import_tables.get(sym.value) orelse return null;
|
const index = coff_file.import_tables.getIndex(sym.value) orelse return null;
|
||||||
return itab.getImportAddress(coff_file, self.target);
|
const itab = coff_file.import_tables.values()[index];
|
||||||
|
return itab.getImportAddress(self.target, .{
|
||||||
|
.coff_file = coff_file,
|
||||||
|
.index = index,
|
||||||
|
.name_off = sym.value,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue