| ... | @@ -1,36 +1,7 @@ | ... | @@ -1,36 +1,7 @@ |
| 1 | const Coff = @This(); | 1 | //! The main driver of the COFF linker. |
| 2 | | 2 | //! Currently uses our own implementation for the incremental linker, and falls back to |
| 3 | const std = @import("std"); | 3 | //! LLD for traditional linking (linking relocatable object files). |
| 4 | const build_options = @import("build_options"); | 4 | //! LLD is also the default linker for LLVM. |
| 5 | const builtin = @import("builtin"); | | |
| 6 | const assert = std.debug.assert; | | |
| 7 | const coff = std.coff; | | |
| 8 | const fmt = std.fmt; | | |
| 9 | const log = std.log.scoped(.link); | | |
| 10 | const math = std.math; | | |
| 11 | const mem = std.mem; | | |
| 12 | | | |
| 13 | const Allocator = std.mem.Allocator; | | |
| 14 | | | |
| 15 | const codegen = @import("../codegen.zig"); | | |
| 16 | const link = @import("../link.zig"); | | |
| 17 | const lld = @import("Coff/lld.zig"); | | |
| 18 | const trace = @import("../tracy.zig").trace; | | |
| 19 | | | |
| 20 | const Air = @import("../Air.zig"); | | |
| 21 | pub const Atom = @import("Coff/Atom.zig"); | | |
| 22 | const Compilation = @import("../Compilation.zig"); | | |
| 23 | const Liveness = @import("../Liveness.zig"); | | |
| 24 | const LlvmObject = @import("../codegen/llvm.zig").Object; | | |
| 25 | const Module = @import("../Module.zig"); | | |
| 26 | const Object = @import("Coff/Object.zig"); | | |
| 27 | const Relocation = @import("Coff/Relocation.zig"); | | |
| 28 | const StringTable = @import("strtab.zig").StringTable; | | |
| 29 | const TypedValue = @import("../TypedValue.zig"); | | |
| 30 | | | |
| 31 | pub const base_tag: link.File.Tag = .coff; | | |
| 32 | | | |
| 33 | const msdos_stub = @embedFile("msdos-stub.bin"); | | |
| 34 | | 5 | |
| 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. |
| 36 | llvm_object: ?*LlvmObject = null, | 7 | llvm_object: ?*LlvmObject = null, |
| ... | @@ -160,92 +131,6 @@ const Section = struct { | ... | @@ -160,92 +131,6 @@ const Section = struct { |
| 160 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, | 131 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 161 | }; | 132 | }; |
| 162 | | 133 | |
| 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 | | |
| 190 | const 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 | | | |
| 249 | const DeclMetadata = struct { | 134 | const DeclMetadata = struct { |
| 250 | atom: Atom.Index, | 135 | atom: Atom.Index, |
| 251 | section: u16, | 136 | section: u16, |
| ... | @@ -1527,7 +1412,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -1527,7 +1412,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1527 | const res = try self.import_tables.getOrPut(gpa, sym.value); | 1412 | const res = try self.import_tables.getOrPut(gpa, sym.value); |
| 1528 | const itable = res.value_ptr; | 1413 | const itable = res.value_ptr; |
| 1529 | if (!res.found_existing) { | 1414 | if (!res.found_existing) { |
| 1530 | itable.* = .{ .index = @intCast(u8, self.import_tables.values().len - 1) }; | 1415 | itable.* = .{}; |
| 1531 | } | 1416 | } |
| 1532 | if (itable.lookup.contains(global)) continue; | 1417 | if (itable.lookup.contains(global)) continue; |
| 1533 | // TODO: we could technically write the pointer placeholder for to-be-bound import here, | 1418 | // TODO: we could technically write the pointer placeholder for to-be-bound import here, |
| ... | @@ -2367,15 +2252,46 @@ fn logSections(self: *Coff) void { | ... | @@ -2367,15 +2252,46 @@ fn logSections(self: *Coff) void { |
| 2367 | fn logImportTables(self: *const Coff) void { | 2252 | fn logImportTables(self: *const Coff) void { |
| 2368 | log.debug("import tables:", .{}); | 2253 | log.debug("import tables:", .{}); |
| 2369 | for (self.import_tables.keys(), 0..) |off, i| { | 2254 | for (self.import_tables.keys(), 0..) |off, i| { |
| 2370 | const lib_name = self.temp_strtab.getAssumeExists(off); | | |
| 2371 | const itable = self.import_tables.values()[i]; | 2255 | const itable = self.import_tables.values()[i]; |
| 2372 | log.debug("IAT({s}) @{x}:", .{ lib_name, itable.getBaseAddress(self) }); | 2256 | log.debug("{}", .{itable.fmtDebug(.{ |
| 2373 | for (itable.entries.items, 0..) |entry, j| { | 2257 | .coff_file = self, |
| 2374 | log.debug(" {d}@{?x} => {s}", .{ | 2258 | .index = i, |
| 2375 | j, | 2259 | .name_off = off, |
| 2376 | itable.getImportAddress(self, entry), | 2260 | })}); |
| 2377 | self.getSymbolName(entry), | | |
| 2378 | }); | | |
| 2379 | } | | |
| 2380 | } | 2261 | } |
| 2381 | } | 2262 | } |
| | 2263 | |
| | 2264 | const Coff = @This(); |
| | 2265 | |
| | 2266 | const std = @import("std"); |
| | 2267 | const build_options = @import("build_options"); |
| | 2268 | const builtin = @import("builtin"); |
| | 2269 | const assert = std.debug.assert; |
| | 2270 | const coff = std.coff; |
| | 2271 | const fmt = std.fmt; |
| | 2272 | const log = std.log.scoped(.link); |
| | 2273 | const math = std.math; |
| | 2274 | const mem = std.mem; |
| | 2275 | |
| | 2276 | const Allocator = std.mem.Allocator; |
| | 2277 | |
| | 2278 | const codegen = @import("../codegen.zig"); |
| | 2279 | const link = @import("../link.zig"); |
| | 2280 | const lld = @import("Coff/lld.zig"); |
| | 2281 | const trace = @import("../tracy.zig").trace; |
| | 2282 | |
| | 2283 | const Air = @import("../Air.zig"); |
| | 2284 | pub const Atom = @import("Coff/Atom.zig"); |
| | 2285 | const Compilation = @import("../Compilation.zig"); |
| | 2286 | const ImportTable = @import("Coff/ImportTable.zig"); |
| | 2287 | const Liveness = @import("../Liveness.zig"); |
| | 2288 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| | 2289 | const Module = @import("../Module.zig"); |
| | 2290 | const Object = @import("Coff/Object.zig"); |
| | 2291 | const Relocation = @import("Coff/Relocation.zig"); |
| | 2292 | const StringTable = @import("strtab.zig").StringTable; |
| | 2293 | const TypedValue = @import("../TypedValue.zig"); |
| | 2294 | |
| | 2295 | pub const base_tag: link.File.Tag = .coff; |
| | 2296 | |
| | 2297 | const msdos_stub = @embedFile("msdos-stub.bin"); |