authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-10-24 15:50:02+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-24 13:50:02+00:00
log56996a2809421a7dfbb74f7533d40faf6c1482e3
tree32aad14d943bb8b9ace2daccd980d6b3e99e5949
parent9ffee5abed1e57ceb24e0c8e20aa2fd8c242ca38
signaturebadge-check Signed by PGP key B5690EEEBB952194

link/Coff: simplify file structure by collapsing all files into Coff.zig (#21761)

* coff: collapse Coff/lld.zig logic into Coff.zig * coff: rename std.coff uses to coff_util * coff: rename self to coff for *Coff references * coff: collapse Coff/Atom.zig logic into Coff.zig * coff: collapse Coff/Relocation.zig logic into Coff.zig * coff: collapse Coff/ImportTable.zig logic into Coff.zig * coff: remove unused Coff/Object.zig * link/Coff: fix rebase gone wrong

9 files changed, 1636 insertions(+), 1708 deletions(-)

CMakeLists.txt-5
......@@ -592,11 +592,6 @@ set(ZIG_STAGE2_SOURCES
592592 src/link.zig
593593 src/link/C.zig
594594 src/link/Coff.zig
595 src/link/Coff/Atom.zig
596 src/link/Coff/ImportTable.zig
597 src/link/Coff/Object.zig
598 src/link/Coff/Relocation.zig
599 src/link/Coff/lld.zig
600595 src/link/Dwarf.zig
601596 src/link/Elf.zig
602597 src/link/Elf/Archive.zig
src/arch/aarch64/Emit.zig+2-2
......@@ -942,7 +942,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
942942 .load_memory_import => coff_file.getGlobalByIndex(data.sym_index),
943943 else => unreachable,
944944 };
945 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
945 try coff_file.addRelocation(atom_index, .{
946946 .target = target,
947947 .offset = offset,
948948 .addend = 0,
......@@ -959,7 +959,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
959959 else => unreachable,
960960 },
961961 });
962 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
962 try coff_file.addRelocation(atom_index, .{
963963 .target = target,
964964 .offset = offset + 4,
965965 .addend = 0,
src/arch/x86_64/Emit.zig+2-2
......@@ -132,7 +132,7 @@ pub fn emitMir(emit: *Emit) Error!void {
132132 coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index)
133133 else
134134 link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null };
135 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
135 try coff_file.addRelocation(atom_index, .{
136136 .type = .direct,
137137 .target = target,
138138 .offset = end_offset - 4,
......@@ -230,7 +230,7 @@ pub fn emitMir(emit: *Emit) Error!void {
230230 coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index)
231231 else
232232 link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null };
233 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
233 try coff_file.addRelocation(atom_index, .{
234234 .type = switch (lowered_relocs[0].target) {
235235 .linker_got => .got,
236236 .linker_direct => .direct,
src/link/Coff.zig+1632-645
......@@ -26,10 +26,8 @@ repro: bool,
2626ptr_width: PtrWidth,
2727page_size: u32,
2828
29objects: std.ArrayListUnmanaged(Object) = .empty,
30
3129sections: std.MultiArrayList(Section) = .{},
32data_directories: [coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory,
30data_directories: [coff_util.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff_util.ImageDataDirectory,
3331
3432text_section_index: ?u16 = null,
3533got_section_index: ?u16 = null,
......@@ -38,7 +36,7 @@ data_section_index: ?u16 = null,
3836reloc_section_index: ?u16 = null,
3937idata_section_index: ?u16 = null,
4038
41locals: std.ArrayListUnmanaged(coff.Symbol) = .empty,
39locals: std.ArrayListUnmanaged(coff_util.Symbol) = .empty,
4240globals: std.ArrayListUnmanaged(SymbolWithLoc) = .empty,
4341resolver: std.StringHashMapUnmanaged(u32) = .empty,
4442unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .empty,
......@@ -112,7 +110,7 @@ const default_size_of_heap_reserve: u32 = 0x100000;
112110const default_size_of_heap_commit: u32 = 0x1000;
113111
114112const Section = struct {
115 header: coff.SectionHeader,
113 header: coff_util.SectionHeader,
116114
117115 last_atom_index: ?Atom.Index = null,
118116
......@@ -154,9 +152,9 @@ const AvMetadata = struct {
154152 m.exports.deinit(allocator);
155153 }
156154
157 fn getExport(m: AvMetadata, coff_file: *const Coff, name: []const u8) ?u32 {
155 fn getExport(m: AvMetadata, coff: *const Coff, name: []const u8) ?u32 {
158156 for (m.exports.items) |exp| {
159 if (mem.eql(u8, name, coff_file.getSymbolName(.{
157 if (mem.eql(u8, name, coff.getSymbolName(.{
160158 .sym_index = exp,
161159 .file = null,
162160 }))) return exp;
......@@ -164,9 +162,9 @@ const AvMetadata = struct {
164162 return null;
165163 }
166164
167 fn getExportPtr(m: *AvMetadata, coff_file: *Coff, name: []const u8) ?*u32 {
165 fn getExportPtr(m: *AvMetadata, coff: *Coff, name: []const u8) ?*u32 {
168166 for (m.exports.items) |*exp| {
169 if (mem.eql(u8, name, coff_file.getSymbolName(.{
167 if (mem.eql(u8, name, coff.getSymbolName(.{
170168 .sym_index = exp.*,
171169 .file = null,
172170 }))) return exp;
......@@ -247,10 +245,10 @@ pub fn createEmpty(
247245 const zcu_object_sub_path = if (!use_lld and !use_llvm)
248246 null
249247 else
250 try std.fmt.allocPrint(arena, "{s}.obj", .{emit.sub_path});
248 try allocPrint(arena, "{s}.obj", .{emit.sub_path});
251249
252 const self = try arena.create(Coff);
253 self.* = .{
250 const coff = try arena.create(Coff);
251 coff.* = .{
254252 .base = .{
255253 .tag = .coff,
256254 .comp = comp,
......@@ -267,10 +265,10 @@ pub fn createEmpty(
267265 .ptr_width = ptr_width,
268266 .page_size = page_size,
269267
270 .data_directories = [1]coff.ImageDataDirectory{.{
268 .data_directories = [1]coff_util.ImageDataDirectory{.{
271269 .virtual_address = 0,
272270 .size = 0,
273 }} ** coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES,
271 }} ** coff_util.IMAGE_NUMBEROF_DIRECTORY_ENTRIES,
274272
275273 .image_base = options.image_base orelse switch (output_mode) {
276274 .Exe => switch (target.cpu.arch) {
......@@ -305,35 +303,35 @@ pub fn createEmpty(
305303 .repro = options.repro,
306304 };
307305 if (use_llvm and comp.config.have_zcu) {
308 self.llvm_object = try LlvmObject.create(arena, comp);
306 coff.llvm_object = try LlvmObject.create(arena, comp);
309307 }
310 errdefer self.base.destroy();
308 errdefer coff.base.destroy();
311309
312310 if (use_lld and (use_llvm or !comp.config.have_zcu)) {
313311 // LLVM emits the object file (if any); LLD links it into the final product.
314 return self;
312 return coff;
315313 }
316314
317315 // What path should this COFF linker code output to?
318316 // If using LLD to link, this code should produce an object file so that it
319317 // can be passed to LLD.
320318 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;
321 self.base.file = try emit.root_dir.handle.createFile(sub_path, .{
319 coff.base.file = try emit.root_dir.handle.createFile(sub_path, .{
322320 .truncate = true,
323321 .read = true,
324322 .mode = link.File.determineMode(use_lld, output_mode, link_mode),
325323 });
326324
327 assert(self.llvm_object == null);
325 assert(coff.llvm_object == null);
328326 const gpa = comp.gpa;
329327
330 try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));
331 self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32));
328 try coff.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));
329 coff.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32));
332330
333 try self.temp_strtab.buffer.append(gpa, 0);
331 try coff.temp_strtab.buffer.append(gpa, 0);
334332
335333 // Index 0 is always a null symbol.
336 try self.locals.append(gpa, .{
334 try coff.locals.append(gpa, .{
337335 .name = [_]u8{0} ** 8,
338336 .value = 0,
339337 .section_number = .UNDEFINED,
......@@ -342,61 +340,61 @@ pub fn createEmpty(
342340 .number_of_aux_symbols = 0,
343341 });
344342
345 if (self.text_section_index == null) {
343 if (coff.text_section_index == null) {
346344 const file_size: u32 = @intCast(options.program_code_size_hint);
347 self.text_section_index = try self.allocateSection(".text", file_size, .{
345 coff.text_section_index = try coff.allocateSection(".text", file_size, .{
348346 .CNT_CODE = 1,
349347 .MEM_EXECUTE = 1,
350348 .MEM_READ = 1,
351349 });
352350 }
353351
354 if (self.got_section_index == null) {
355 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size();
356 self.got_section_index = try self.allocateSection(".got", file_size, .{
352 if (coff.got_section_index == null) {
353 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
354 coff.got_section_index = try coff.allocateSection(".got", file_size, .{
357355 .CNT_INITIALIZED_DATA = 1,
358356 .MEM_READ = 1,
359357 });
360358 }
361359
362 if (self.rdata_section_index == null) {
363 const file_size: u32 = self.page_size;
364 self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{
360 if (coff.rdata_section_index == null) {
361 const file_size: u32 = coff.page_size;
362 coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{
365363 .CNT_INITIALIZED_DATA = 1,
366364 .MEM_READ = 1,
367365 });
368366 }
369367
370 if (self.data_section_index == null) {
371 const file_size: u32 = self.page_size;
372 self.data_section_index = try self.allocateSection(".data", file_size, .{
368 if (coff.data_section_index == null) {
369 const file_size: u32 = coff.page_size;
370 coff.data_section_index = try coff.allocateSection(".data", file_size, .{
373371 .CNT_INITIALIZED_DATA = 1,
374372 .MEM_READ = 1,
375373 .MEM_WRITE = 1,
376374 });
377375 }
378376
379 if (self.idata_section_index == null) {
380 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size();
381 self.idata_section_index = try self.allocateSection(".idata", file_size, .{
377 if (coff.idata_section_index == null) {
378 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
379 coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{
382380 .CNT_INITIALIZED_DATA = 1,
383381 .MEM_READ = 1,
384382 });
385383 }
386384
387 if (self.reloc_section_index == null) {
388 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff.BaseRelocation);
389 self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{
385 if (coff.reloc_section_index == null) {
386 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation);
387 coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{
390388 .CNT_INITIALIZED_DATA = 1,
391389 .MEM_DISCARDABLE = 1,
392390 .MEM_READ = 1,
393391 });
394392 }
395393
396 if (self.strtab_offset == null) {
397 const file_size = @as(u32, @intCast(self.strtab.buffer.items.len));
398 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here
399 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });
394 if (coff.strtab_offset == null) {
395 const file_size = @as(u32, @intCast(coff.strtab.buffer.items.len));
396 coff.strtab_offset = coff.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here
397 log.debug("found strtab free space 0x{x} to 0x{x}", .{ coff.strtab_offset.?, coff.strtab_offset.? + file_size });
400398 }
401399
402400 {
......@@ -405,15 +403,15 @@ pub fn createEmpty(
405403 // offset + it's filesize.
406404 // TODO I don't like this here one bit
407405 var max_file_offset: u64 = 0;
408 for (self.sections.items(.header)) |header| {
406 for (coff.sections.items(.header)) |header| {
409407 if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) {
410408 max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data;
411409 }
412410 }
413 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);
411 try coff.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);
414412 }
415413
416 return self;
414 return coff;
417415}
418416
419417pub fn open(
......@@ -427,85 +425,80 @@ pub fn open(
427425 return createEmpty(arena, comp, emit, options);
428426}
429427
430pub fn deinit(self: *Coff) void {
431 const gpa = self.base.comp.gpa;
432
433 if (self.llvm_object) |llvm_object| llvm_object.deinit();
428pub fn deinit(coff: *Coff) void {
429 const gpa = coff.base.comp.gpa;
434430
435 for (self.objects.items) |*object| {
436 object.deinit(gpa);
437 }
438 self.objects.deinit(gpa);
431 if (coff.llvm_object) |llvm_object| llvm_object.deinit();
439432
440 for (self.sections.items(.free_list)) |*free_list| {
433 for (coff.sections.items(.free_list)) |*free_list| {
441434 free_list.deinit(gpa);
442435 }
443 self.sections.deinit(gpa);
436 coff.sections.deinit(gpa);
444437
445 self.atoms.deinit(gpa);
446 self.locals.deinit(gpa);
447 self.globals.deinit(gpa);
438 coff.atoms.deinit(gpa);
439 coff.locals.deinit(gpa);
440 coff.globals.deinit(gpa);
448441
449442 {
450 var it = self.resolver.keyIterator();
443 var it = coff.resolver.keyIterator();
451444 while (it.next()) |key_ptr| {
452445 gpa.free(key_ptr.*);
453446 }
454 self.resolver.deinit(gpa);
447 coff.resolver.deinit(gpa);
455448 }
456449
457 self.unresolved.deinit(gpa);
458 self.locals_free_list.deinit(gpa);
459 self.globals_free_list.deinit(gpa);
460 self.strtab.deinit(gpa);
461 self.temp_strtab.deinit(gpa);
462 self.got_table.deinit(gpa);
450 coff.unresolved.deinit(gpa);
451 coff.locals_free_list.deinit(gpa);
452 coff.globals_free_list.deinit(gpa);
453 coff.strtab.deinit(gpa);
454 coff.temp_strtab.deinit(gpa);
455 coff.got_table.deinit(gpa);
463456
464 for (self.import_tables.values()) |*itab| {
457 for (coff.import_tables.values()) |*itab| {
465458 itab.deinit(gpa);
466459 }
467 self.import_tables.deinit(gpa);
460 coff.import_tables.deinit(gpa);
468461
469 self.lazy_syms.deinit(gpa);
462 coff.lazy_syms.deinit(gpa);
470463
471 for (self.navs.values()) |*metadata| {
464 for (coff.navs.values()) |*metadata| {
472465 metadata.deinit(gpa);
473466 }
474 self.navs.deinit(gpa);
467 coff.navs.deinit(gpa);
475468
476 self.atom_by_index_table.deinit(gpa);
469 coff.atom_by_index_table.deinit(gpa);
477470
478471 {
479 var it = self.uavs.iterator();
472 var it = coff.uavs.iterator();
480473 while (it.next()) |entry| {
481474 entry.value_ptr.exports.deinit(gpa);
482475 }
483 self.uavs.deinit(gpa);
476 coff.uavs.deinit(gpa);
484477 }
485478
486 for (self.relocs.values()) |*relocs| {
479 for (coff.relocs.values()) |*relocs| {
487480 relocs.deinit(gpa);
488481 }
489 self.relocs.deinit(gpa);
482 coff.relocs.deinit(gpa);
490483
491 for (self.base_relocs.values()) |*relocs| {
484 for (coff.base_relocs.values()) |*relocs| {
492485 relocs.deinit(gpa);
493486 }
494 self.base_relocs.deinit(gpa);
487 coff.base_relocs.deinit(gpa);
495488}
496489
497fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.SectionHeaderFlags) !u16 {
498 const index = @as(u16, @intCast(self.sections.slice().len));
499 const off = self.findFreeSpace(size, default_file_alignment);
490fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeaderFlags) !u16 {
491 const index = @as(u16, @intCast(coff.sections.slice().len));
492 const off = coff.findFreeSpace(size, default_file_alignment);
500493 // Memory is always allocated in sequence
501494 // TODO: investigate if we can allocate .text last; this way it would never need to grow in memory!
502495 const vaddr = blk: {
503 if (index == 0) break :blk self.page_size;
504 const prev_header = self.sections.items(.header)[index - 1];
505 break :blk mem.alignForward(u32, prev_header.virtual_address + prev_header.virtual_size, self.page_size);
496 if (index == 0) break :blk coff.page_size;
497 const prev_header = coff.sections.items(.header)[index - 1];
498 break :blk mem.alignForward(u32, prev_header.virtual_address + prev_header.virtual_size, coff.page_size);
506499 };
507500 // We commit more memory than needed upfront so that we don't have to reallocate too soon.
508 const memsz = mem.alignForward(u32, size, self.page_size) * 100;
501 const memsz = mem.alignForward(u32, size, coff.page_size) * 100;
509502 log.debug("found {s} free space 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
510503 name,
511504 off,
......@@ -513,7 +506,7 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section
513506 vaddr,
514507 vaddr + size,
515508 });
516 var header = coff.SectionHeader{
509 var header = coff_util.SectionHeader{
517510 .name = undefined,
518511 .virtual_size = memsz,
519512 .virtual_address = vaddr,
......@@ -525,32 +518,32 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section
525518 .number_of_linenumbers = 0,
526519 .flags = flags,
527520 };
528 const gpa = self.base.comp.gpa;
529 try self.setSectionName(&header, name);
530 try self.sections.append(gpa, .{ .header = header });
521 const gpa = coff.base.comp.gpa;
522 try coff.setSectionName(&header, name);
523 try coff.sections.append(gpa, .{ .header = header });
531524 return index;
532525}
533526
534fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void {
535 const header = &self.sections.items(.header)[sect_id];
536 const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id];
537 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
527fn growSection(coff: *Coff, sect_id: u32, needed_size: u32) !void {
528 const header = &coff.sections.items(.header)[sect_id];
529 const maybe_last_atom_index = coff.sections.items(.last_atom_index)[sect_id];
530 const sect_capacity = coff.allocatedSize(header.pointer_to_raw_data);
538531
539532 if (needed_size > sect_capacity) {
540 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
533 const new_offset = coff.findFreeSpace(needed_size, default_file_alignment);
541534 const current_size = if (maybe_last_atom_index) |last_atom_index| blk: {
542 const last_atom = self.getAtom(last_atom_index);
543 const sym = last_atom.getSymbol(self);
535 const last_atom = coff.getAtom(last_atom_index);
536 const sym = last_atom.getSymbol(coff);
544537 break :blk (sym.value + last_atom.size) - header.virtual_address;
545538 } else 0;
546539 log.debug("moving {s} from 0x{x} to 0x{x}", .{
547 self.getSectionName(header),
540 coff.getSectionName(header),
548541 header.pointer_to_raw_data,
549542 new_offset,
550543 });
551 const amt = try self.base.file.?.copyRangeAll(
544 const amt = try coff.base.file.?.copyRangeAll(
552545 header.pointer_to_raw_data,
553 self.base.file.?,
546 coff.base.file.?,
554547 new_offset,
555548 current_size,
556549 );
......@@ -558,35 +551,35 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void {
558551 header.pointer_to_raw_data = new_offset;
559552 }
560553
561 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);
554 const sect_vm_capacity = coff.allocatedVirtualSize(header.virtual_address);
562555 if (needed_size > sect_vm_capacity) {
563 self.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size);
564 try self.growSectionVirtualMemory(sect_id, needed_size);
556 coff.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size);
557 try coff.growSectionVirtualMemory(sect_id, needed_size);
565558 }
566559
567560 header.virtual_size = @max(header.virtual_size, needed_size);
568561 header.size_of_raw_data = needed_size;
569562}
570563
571fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void {
572 const header = &self.sections.items(.header)[sect_id];
564fn growSectionVirtualMemory(coff: *Coff, sect_id: u32, needed_size: u32) !void {
565 const header = &coff.sections.items(.header)[sect_id];
573566 const increased_size = padToIdeal(needed_size);
574 const old_aligned_end = header.virtual_address + mem.alignForward(u32, header.virtual_size, self.page_size);
575 const new_aligned_end = header.virtual_address + mem.alignForward(u32, increased_size, self.page_size);
567 const old_aligned_end = header.virtual_address + mem.alignForward(u32, header.virtual_size, coff.page_size);
568 const new_aligned_end = header.virtual_address + mem.alignForward(u32, increased_size, coff.page_size);
576569 const diff = new_aligned_end - old_aligned_end;
577 log.debug("growing {s} in virtual memory by {x}", .{ self.getSectionName(header), diff });
570 log.debug("growing {s} in virtual memory by {x}", .{ coff.getSectionName(header), diff });
578571
579 // TODO: enforce order by increasing VM addresses in self.sections container.
572 // TODO: enforce order by increasing VM addresses in coff.sections container.
580573 // This is required by the loader anyhow as far as I can tell.
581 for (self.sections.items(.header)[sect_id + 1 ..], 0..) |*next_header, next_sect_id| {
582 const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id];
574 for (coff.sections.items(.header)[sect_id + 1 ..], 0..) |*next_header, next_sect_id| {
575 const maybe_last_atom_index = coff.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id];
583576 next_header.virtual_address += diff;
584577
585578 if (maybe_last_atom_index) |last_atom_index| {
586579 var atom_index = last_atom_index;
587580 while (true) {
588 const atom = self.getAtom(atom_index);
589 const sym = atom.getSymbolPtr(self);
581 const atom = coff.getAtom(atom_index);
582 const sym = atom.getSymbolPtr(coff);
590583 sym.value += diff;
591584
592585 if (atom.prev_index) |prev_index| {
......@@ -599,15 +592,15 @@ fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void {
599592 header.virtual_size = increased_size;
600593}
601594
602fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
595fn allocateAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
603596 const tracy = trace(@src());
604597 defer tracy.end();
605598
606 const atom = self.getAtom(atom_index);
607 const sect_id = @intFromEnum(atom.getSymbol(self).section_number) - 1;
608 const header = &self.sections.items(.header)[sect_id];
609 const free_list = &self.sections.items(.free_list)[sect_id];
610 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
599 const atom = coff.getAtom(atom_index);
600 const sect_id = @intFromEnum(atom.getSymbol(coff).section_number) - 1;
601 const header = &coff.sections.items(.header)[sect_id];
602 const free_list = &coff.sections.items(.free_list)[sect_id];
603 const maybe_last_atom_index = &coff.sections.items(.last_atom_index)[sect_id];
611604 const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size;
612605
613606 // We use these to indicate our intention to update metadata, placing the new atom,
......@@ -624,11 +617,11 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
624617 var i: usize = 0;
625618 while (i < free_list.items.len) {
626619 const big_atom_index = free_list.items[i];
627 const big_atom = self.getAtom(big_atom_index);
620 const big_atom = coff.getAtom(big_atom_index);
628621 // We now have a pointer to a live atom that has too much capacity.
629622 // Is it enough that we could fit this new atom?
630 const sym = big_atom.getSymbol(self);
631 const capacity = big_atom.capacity(self);
623 const sym = big_atom.getSymbol(coff);
624 const capacity = big_atom.capacity(coff);
632625 const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity;
633626 const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity;
634627 const capacity_end_vaddr = sym.value + capacity;
......@@ -638,7 +631,7 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
638631 // Additional bookkeeping here to notice if this free list node
639632 // should be deleted because the atom that it points to has grown to take up
640633 // more of the extra capacity.
641 if (!big_atom.freeListEligible(self)) {
634 if (!big_atom.freeListEligible(coff)) {
642635 _ = free_list.swapRemove(i);
643636 } else {
644637 i += 1;
......@@ -658,8 +651,8 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
658651 }
659652 break :blk new_start_vaddr;
660653 } else if (maybe_last_atom_index.*) |last_index| {
661 const last = self.getAtom(last_index);
662 const last_symbol = last.getSymbol(self);
654 const last = coff.getAtom(last_index);
655 const last_symbol = last.getSymbol(coff);
663656 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
664657 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;
665658 const new_start_vaddr = mem.alignForward(u32, ideal_capacity_end_vaddr, alignment);
......@@ -671,33 +664,33 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
671664 };
672665
673666 const expand_section = if (atom_placement) |placement_index|
674 self.getAtom(placement_index).next_index == null
667 coff.getAtom(placement_index).next_index == null
675668 else
676669 true;
677670 if (expand_section) {
678671 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;
679 try self.growSection(sect_id, needed_size);
672 try coff.growSection(sect_id, needed_size);
680673 maybe_last_atom_index.* = atom_index;
681674 }
682 self.getAtomPtr(atom_index).size = new_atom_size;
675 coff.getAtomPtr(atom_index).size = new_atom_size;
683676
684677 if (atom.prev_index) |prev_index| {
685 const prev = self.getAtomPtr(prev_index);
678 const prev = coff.getAtomPtr(prev_index);
686679 prev.next_index = atom.next_index;
687680 }
688681 if (atom.next_index) |next_index| {
689 const next = self.getAtomPtr(next_index);
682 const next = coff.getAtomPtr(next_index);
690683 next.prev_index = atom.prev_index;
691684 }
692685
693686 if (atom_placement) |big_atom_index| {
694 const big_atom = self.getAtomPtr(big_atom_index);
695 const atom_ptr = self.getAtomPtr(atom_index);
687 const big_atom = coff.getAtomPtr(big_atom_index);
688 const atom_ptr = coff.getAtomPtr(atom_index);
696689 atom_ptr.prev_index = big_atom_index;
697690 atom_ptr.next_index = big_atom.next_index;
698691 big_atom.next_index = atom_index;
699692 } else {
700 const atom_ptr = self.getAtomPtr(atom_index);
693 const atom_ptr = coff.getAtomPtr(atom_index);
701694 atom_ptr.prev_index = null;
702695 atom_ptr.next_index = null;
703696 }
......@@ -708,23 +701,23 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
708701 return vaddr;
709702}
710703
711pub fn allocateSymbol(self: *Coff) !u32 {
712 const gpa = self.base.comp.gpa;
713 try self.locals.ensureUnusedCapacity(gpa, 1);
704pub fn allocateSymbol(coff: *Coff) !u32 {
705 const gpa = coff.base.comp.gpa;
706 try coff.locals.ensureUnusedCapacity(gpa, 1);
714707
715708 const index = blk: {
716 if (self.locals_free_list.popOrNull()) |index| {
709 if (coff.locals_free_list.popOrNull()) |index| {
717710 log.debug(" (reusing symbol index {d})", .{index});
718711 break :blk index;
719712 } else {
720 log.debug(" (allocating symbol index {d})", .{self.locals.items.len});
721 const index = @as(u32, @intCast(self.locals.items.len));
722 _ = self.locals.addOneAssumeCapacity();
713 log.debug(" (allocating symbol index {d})", .{coff.locals.items.len});
714 const index = @as(u32, @intCast(coff.locals.items.len));
715 _ = coff.locals.addOneAssumeCapacity();
723716 break :blk index;
724717 }
725718 };
726719
727 self.locals.items[index] = .{
720 coff.locals.items[index] = .{
728721 .name = [_]u8{0} ** 8,
729722 .value = 0,
730723 .section_number = .UNDEFINED,
......@@ -736,23 +729,23 @@ pub fn allocateSymbol(self: *Coff) !u32 {
736729 return index;
737730}
738731
739fn allocateGlobal(self: *Coff) !u32 {
740 const gpa = self.base.comp.gpa;
741 try self.globals.ensureUnusedCapacity(gpa, 1);
732fn allocateGlobal(coff: *Coff) !u32 {
733 const gpa = coff.base.comp.gpa;
734 try coff.globals.ensureUnusedCapacity(gpa, 1);
742735
743736 const index = blk: {
744 if (self.globals_free_list.popOrNull()) |index| {
737 if (coff.globals_free_list.popOrNull()) |index| {
745738 log.debug(" (reusing global index {d})", .{index});
746739 break :blk index;
747740 } else {
748 log.debug(" (allocating global index {d})", .{self.globals.items.len});
749 const index = @as(u32, @intCast(self.globals.items.len));
750 _ = self.globals.addOneAssumeCapacity();
741 log.debug(" (allocating global index {d})", .{coff.globals.items.len});
742 const index = @as(u32, @intCast(coff.globals.items.len));
743 _ = coff.globals.addOneAssumeCapacity();
751744 break :blk index;
752745 }
753746 };
754747
755 self.globals.items[index] = .{
748 coff.globals.items[index] = .{
756749 .sym_index = 0,
757750 .file = null,
758751 };
......@@ -760,21 +753,21 @@ fn allocateGlobal(self: *Coff) !u32 {
760753 return index;
761754}
762755
763fn addGotEntry(self: *Coff, target: SymbolWithLoc) !void {
764 const gpa = self.base.comp.gpa;
765 if (self.got_table.lookup.contains(target)) return;
766 const got_index = try self.got_table.allocateEntry(gpa, target);
767 try self.writeOffsetTableEntry(got_index);
768 self.got_table_count_dirty = true;
769 self.markRelocsDirtyByTarget(target);
756fn addGotEntry(coff: *Coff, target: SymbolWithLoc) !void {
757 const gpa = coff.base.comp.gpa;
758 if (coff.got_table.lookup.contains(target)) return;
759 const got_index = try coff.got_table.allocateEntry(gpa, target);
760 try coff.writeOffsetTableEntry(got_index);
761 coff.got_table_count_dirty = true;
762 coff.markRelocsDirtyByTarget(target);
770763}
771764
772pub fn createAtom(self: *Coff) !Atom.Index {
773 const gpa = self.base.comp.gpa;
774 const atom_index = @as(Atom.Index, @intCast(self.atoms.items.len));
775 const atom = try self.atoms.addOne(gpa);
776 const sym_index = try self.allocateSymbol();
777 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
765pub fn createAtom(coff: *Coff) !Atom.Index {
766 const gpa = coff.base.comp.gpa;
767 const atom_index = @as(Atom.Index, @intCast(coff.atoms.items.len));
768 const atom = try coff.atoms.addOne(gpa);
769 const sym_index = try coff.allocateSymbol();
770 try coff.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
778771 atom.* = .{
779772 .sym_index = sym_index,
780773 .file = null,
......@@ -786,36 +779,36 @@ pub fn createAtom(self: *Coff) !Atom.Index {
786779 return atom_index;
787780}
788781
789fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
790 const atom = self.getAtom(atom_index);
791 const sym = atom.getSymbol(self);
782fn growAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
783 const atom = coff.getAtom(atom_index);
784 const sym = atom.getSymbol(coff);
792785 const align_ok = mem.alignBackward(u32, sym.value, alignment) == sym.value;
793 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
786 const need_realloc = !align_ok or new_atom_size > atom.capacity(coff);
794787 if (!need_realloc) return sym.value;
795 return self.allocateAtom(atom_index, new_atom_size, alignment);
788 return coff.allocateAtom(atom_index, new_atom_size, alignment);
796789}
797790
798fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void {
799 _ = self;
791fn shrinkAtom(coff: *Coff, atom_index: Atom.Index, new_block_size: u32) void {
792 _ = coff;
800793 _ = atom_index;
801794 _ = new_block_size;
802795 // TODO check the new capacity, and if it crosses the size threshold into a big enough
803796 // capacity, insert a free list node for it.
804797}
805798
806fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
807 const atom = self.getAtom(atom_index);
808 const sym = atom.getSymbol(self);
809 const section = self.sections.get(@intFromEnum(sym.section_number) - 1);
799fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8) !void {
800 const atom = coff.getAtom(atom_index);
801 const sym = atom.getSymbol(coff);
802 const section = coff.sections.get(@intFromEnum(sym.section_number) - 1);
810803 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
811804
812805 log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{
813 atom.getName(self),
806 atom.getName(coff),
814807 file_offset,
815808 file_offset + code.len,
816809 });
817810
818 const gpa = self.base.comp.gpa;
811 const gpa = coff.base.comp.gpa;
819812
820813 // Gather relocs which can be resolved.
821814 // We need to do this as we will be applying different slide values depending
......@@ -825,22 +818,22 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
825818 var relocs = std.ArrayList(*Relocation).init(gpa);
826819 defer relocs.deinit();
827820
828 if (self.relocs.getPtr(atom_index)) |rels| {
821 if (coff.relocs.getPtr(atom_index)) |rels| {
829822 try relocs.ensureTotalCapacityPrecise(rels.items.len);
830823 for (rels.items) |*reloc| {
831 if (reloc.isResolvable(self) and reloc.dirty) {
824 if (reloc.isResolvable(coff) and reloc.dirty) {
832825 relocs.appendAssumeCapacity(reloc);
833826 }
834827 }
835828 }
836829
837830 if (is_hot_update_compatible) {
838 if (self.base.child_pid) |handle| {
839 const slide = @intFromPtr(self.hot_state.loaded_base_address.?);
831 if (coff.base.child_pid) |handle| {
832 const slide = @intFromPtr(coff.hot_state.loaded_base_address.?);
840833
841834 const mem_code = try gpa.dupe(u8, code);
842835 defer gpa.free(mem_code);
843 self.resolveRelocs(atom_index, relocs.items, mem_code, slide);
836 coff.resolveRelocs(atom_index, relocs.items, mem_code, slide);
844837
845838 const vaddr = sym.value + slide;
846839 const pvaddr = @as(*anyopaque, @ptrFromInt(vaddr));
......@@ -863,8 +856,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
863856 }
864857 }
865858
866 self.resolveRelocs(atom_index, relocs.items, code, self.image_base);
867 try self.base.file.?.pwriteAll(code, file_offset);
859 coff.resolveRelocs(atom_index, relocs.items, code, coff.image_base);
860 try coff.base.file.?.pwriteAll(code, file_offset);
868861
869862 // Now we can mark the relocs as resolved.
870863 while (relocs.popOrNull()) |reloc| {
......@@ -893,46 +886,46 @@ fn writeMem(handle: std.process.Child.Id, pvaddr: std.os.windows.LPVOID, code: [
893886 if (amt != code.len) return error.InputOutput;
894887}
895888
896fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
897 const sect_id = self.got_section_index.?;
889fn writeOffsetTableEntry(coff: *Coff, index: usize) !void {
890 const sect_id = coff.got_section_index.?;
898891
899 if (self.got_table_count_dirty) {
900 const needed_size = @as(u32, @intCast(self.got_table.entries.items.len * self.ptr_width.size()));
901 try self.growSection(sect_id, needed_size);
902 self.got_table_count_dirty = false;
892 if (coff.got_table_count_dirty) {
893 const needed_size = @as(u32, @intCast(coff.got_table.entries.items.len * coff.ptr_width.size()));
894 try coff.growSection(sect_id, needed_size);
895 coff.got_table_count_dirty = false;
903896 }
904897
905 const header = &self.sections.items(.header)[sect_id];
906 const entry = self.got_table.entries.items[index];
907 const entry_value = self.getSymbol(entry).value;
908 const entry_offset = index * self.ptr_width.size();
898 const header = &coff.sections.items(.header)[sect_id];
899 const entry = coff.got_table.entries.items[index];
900 const entry_value = coff.getSymbol(entry).value;
901 const entry_offset = index * coff.ptr_width.size();
909902 const file_offset = header.pointer_to_raw_data + entry_offset;
910903 const vmaddr = header.virtual_address + entry_offset;
911904
912 log.debug("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value + self.image_base });
905 log.debug("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value + coff.image_base });
913906
914 switch (self.ptr_width) {
907 switch (coff.ptr_width) {
915908 .p32 => {
916909 var buf: [4]u8 = undefined;
917 mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + self.image_base)), .little);
918 try self.base.file.?.pwriteAll(&buf, file_offset);
910 mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + coff.image_base)), .little);
911 try coff.base.file.?.pwriteAll(&buf, file_offset);
919912 },
920913 .p64 => {
921914 var buf: [8]u8 = undefined;
922 mem.writeInt(u64, &buf, entry_value + self.image_base, .little);
923 try self.base.file.?.pwriteAll(&buf, file_offset);
915 mem.writeInt(u64, &buf, entry_value + coff.image_base, .little);
916 try coff.base.file.?.pwriteAll(&buf, file_offset);
924917 },
925918 }
926919
927920 if (is_hot_update_compatible) {
928 if (self.base.child_pid) |handle| {
929 const gpa = self.base.comp.gpa;
930 const slide = @intFromPtr(self.hot_state.loaded_base_address.?);
921 if (coff.base.child_pid) |handle| {
922 const gpa = coff.base.comp.gpa;
923 const slide = @intFromPtr(coff.hot_state.loaded_base_address.?);
931924 const actual_vmaddr = vmaddr + slide;
932925 const pvaddr = @as(*anyopaque, @ptrFromInt(actual_vmaddr));
933926 log.debug("writing GOT entry to memory at address {x}", .{actual_vmaddr});
934927 if (build_options.enable_logging) {
935 switch (self.ptr_width) {
928 switch (coff.ptr_width) {
936929 .p32 => {
937930 var buf: [4]u8 = undefined;
938931 try debugMem(gpa, handle, pvaddr, &buf);
......@@ -944,7 +937,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
944937 }
945938 }
946939
947 switch (self.ptr_width) {
940 switch (coff.ptr_width) {
948941 .p32 => {
949942 var buf: [4]u8 = undefined;
950943 mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + slide)), .little);
......@@ -964,9 +957,9 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
964957 }
965958}
966959
967fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {
960fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void {
968961 // TODO: reverse-lookup might come in handy here
969 for (self.relocs.values()) |*relocs| {
962 for (coff.relocs.values()) |*relocs| {
970963 for (relocs.items) |*reloc| {
971964 if (!reloc.target.eql(target)) continue;
972965 reloc.dirty = true;
......@@ -974,71 +967,71 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {
974967 }
975968}
976969
977fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
970fn markRelocsDirtyByAddress(coff: *Coff, addr: u32) void {
978971 const got_moved = blk: {
979 const sect_id = self.got_section_index orelse break :blk false;
980 break :blk self.sections.items(.header)[sect_id].virtual_address >= addr;
972 const sect_id = coff.got_section_index orelse break :blk false;
973 break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr;
981974 };
982975
983976 // TODO: dirty relocations targeting import table if that got moved in memory
984977
985 for (self.relocs.values()) |*relocs| {
978 for (coff.relocs.values()) |*relocs| {
986979 for (relocs.items) |*reloc| {
987980 if (reloc.isGotIndirection()) {
988981 reloc.dirty = reloc.dirty or got_moved;
989982 } else {
990 const target_vaddr = reloc.getTargetAddress(self) orelse continue;
983 const target_vaddr = reloc.getTargetAddress(coff) orelse continue;
991984 if (target_vaddr >= addr) reloc.dirty = true;
992985 }
993986 }
994987 }
995988
996989 // TODO: dirty only really affected GOT cells
997 for (self.got_table.entries.items) |entry| {
998 const target_addr = self.getSymbol(entry).value;
990 for (coff.got_table.entries.items) |entry| {
991 const target_addr = coff.getSymbol(entry).value;
999992 if (target_addr >= addr) {
1000 self.got_table_contents_dirty = true;
993 coff.got_table_contents_dirty = true;
1001994 break;
1002995 }
1003996 }
1004997}
1005998
1006fn resolveRelocs(self: *Coff, atom_index: Atom.Index, relocs: []*const Relocation, code: []u8, image_base: u64) void {
1007 log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)});
999fn resolveRelocs(coff: *Coff, atom_index: Atom.Index, relocs: []*const Relocation, code: []u8, image_base: u64) void {
1000 log.debug("relocating '{s}'", .{coff.getAtom(atom_index).getName(coff)});
10081001 for (relocs) |reloc| {
1009 reloc.resolve(atom_index, code, image_base, self);
1002 reloc.resolve(atom_index, code, image_base, coff);
10101003 }
10111004}
10121005
1013pub fn ptraceAttach(self: *Coff, handle: std.process.Child.Id) !void {
1006pub fn ptraceAttach(coff: *Coff, handle: std.process.Child.Id) !void {
10141007 if (!is_hot_update_compatible) return;
10151008
10161009 log.debug("attaching to process with handle {*}", .{handle});
1017 self.hot_state.loaded_base_address = std.os.windows.ProcessBaseAddress(handle) catch |err| {
1010 coff.hot_state.loaded_base_address = std.os.windows.ProcessBaseAddress(handle) catch |err| {
10181011 log.warn("failed to get base address for the process with error: {s}", .{@errorName(err)});
10191012 return;
10201013 };
10211014}
10221015
1023pub fn ptraceDetach(self: *Coff, handle: std.process.Child.Id) void {
1016pub fn ptraceDetach(coff: *Coff, handle: std.process.Child.Id) void {
10241017 if (!is_hot_update_compatible) return;
10251018
10261019 log.debug("detaching from process with handle {*}", .{handle});
1027 self.hot_state.loaded_base_address = null;
1020 coff.hot_state.loaded_base_address = null;
10281021}
10291022
1030fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
1023fn freeAtom(coff: *Coff, atom_index: Atom.Index) void {
10311024 log.debug("freeAtom {d}", .{atom_index});
10321025
1033 const gpa = self.base.comp.gpa;
1026 const gpa = coff.base.comp.gpa;
10341027
10351028 // Remove any relocs and base relocs associated with this Atom
1036 Atom.freeRelocations(self, atom_index);
1029 coff.freeRelocations(atom_index);
10371030
1038 const atom = self.getAtom(atom_index);
1039 const sym = atom.getSymbol(self);
1031 const atom = coff.getAtom(atom_index);
1032 const sym = atom.getSymbol(coff);
10401033 const sect_id = @intFromEnum(sym.section_number) - 1;
1041 const free_list = &self.sections.items(.free_list)[sect_id];
1034 const free_list = &coff.sections.items(.free_list)[sect_id];
10421035 var already_have_free_list_node = false;
10431036 {
10441037 var i: usize = 0;
......@@ -1055,7 +1048,7 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
10551048 }
10561049 }
10571050
1058 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
1051 const maybe_last_atom_index = &coff.sections.items(.last_atom_index)[sect_id];
10591052 if (maybe_last_atom_index.*) |last_atom_index| {
10601053 if (last_atom_index == atom_index) {
10611054 if (atom.prev_index) |prev_index| {
......@@ -1068,42 +1061,42 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
10681061 }
10691062
10701063 if (atom.prev_index) |prev_index| {
1071 const prev = self.getAtomPtr(prev_index);
1064 const prev = coff.getAtomPtr(prev_index);
10721065 prev.next_index = atom.next_index;
10731066
1074 if (!already_have_free_list_node and prev.*.freeListEligible(self)) {
1067 if (!already_have_free_list_node and prev.*.freeListEligible(coff)) {
10751068 // The free list is heuristics, it doesn't have to be perfect, so we can
10761069 // ignore the OOM here.
10771070 free_list.append(gpa, prev_index) catch {};
10781071 }
10791072 } else {
1080 self.getAtomPtr(atom_index).prev_index = null;
1073 coff.getAtomPtr(atom_index).prev_index = null;
10811074 }
10821075
10831076 if (atom.next_index) |next_index| {
1084 self.getAtomPtr(next_index).prev_index = atom.prev_index;
1077 coff.getAtomPtr(next_index).prev_index = atom.prev_index;
10851078 } else {
1086 self.getAtomPtr(atom_index).next_index = null;
1079 coff.getAtomPtr(atom_index).next_index = null;
10871080 }
10881081
10891082 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
10901083 const sym_index = atom.getSymbolIndex().?;
1091 self.locals_free_list.append(gpa, sym_index) catch {};
1084 coff.locals_free_list.append(gpa, sym_index) catch {};
10921085
10931086 // Try freeing GOT atom if this decl had one
1094 self.got_table.freeEntry(gpa, .{ .sym_index = sym_index });
1087 coff.got_table.freeEntry(gpa, .{ .sym_index = sym_index });
10951088
1096 self.locals.items[sym_index].section_number = .UNDEFINED;
1097 _ = self.atom_by_index_table.remove(sym_index);
1089 coff.locals.items[sym_index].section_number = .UNDEFINED;
1090 _ = coff.atom_by_index_table.remove(sym_index);
10981091 log.debug(" adding local symbol index {d} to free list", .{sym_index});
1099 self.getAtomPtr(atom_index).sym_index = 0;
1092 coff.getAtomPtr(atom_index).sym_index = 0;
11001093}
11011094
1102pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
1095pub fn updateFunc(coff: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
11031096 if (build_options.skip_non_native and builtin.object_format != .coff) {
11041097 @panic("Attempted to compile for object format that was disabled by build configuration");
11051098 }
1106 if (self.llvm_object) |llvm_object| {
1099 if (coff.llvm_object) |llvm_object| {
11071100 return llvm_object.updateFunc(pt, func_index, air, liveness);
11081101 }
11091102 const tracy = trace(@src());
......@@ -1113,14 +1106,14 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
11131106 const gpa = zcu.gpa;
11141107 const func = zcu.funcInfo(func_index);
11151108
1116 const atom_index = try self.getOrCreateAtomForNav(func.owner_nav);
1117 Atom.freeRelocations(self, atom_index);
1109 const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav);
1110 coff.freeRelocations(atom_index);
11181111
11191112 var code_buffer = std.ArrayList(u8).init(gpa);
11201113 defer code_buffer.deinit();
11211114
11221115 const res = try codegen.generateFunction(
1123 &self.base,
1116 &coff.base,
11241117 pt,
11251118 zcu.navSrcLoc(func.owner_nav),
11261119 func_index,
......@@ -1137,7 +1130,7 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
11371130 },
11381131 };
11391132
1140 try self.updateNavCode(pt, func.owner_nav, code, .FUNCTION);
1133 try coff.updateNavCode(pt, func.owner_nav, code, .FUNCTION);
11411134
11421135 // Exports will be updated by `Zcu.processExports` after the update.
11431136}
......@@ -1148,7 +1141,7 @@ const LowerConstResult = union(enum) {
11481141};
11491142
11501143fn lowerConst(
1151 self: *Coff,
1144 coff: *Coff,
11521145 pt: Zcu.PerThread,
11531146 name: []const u8,
11541147 val: Value,
......@@ -1156,50 +1149,50 @@ fn lowerConst(
11561149 sect_id: u16,
11571150 src_loc: Zcu.LazySrcLoc,
11581151) !LowerConstResult {
1159 const gpa = self.base.comp.gpa;
1152 const gpa = coff.base.comp.gpa;
11601153
11611154 var code_buffer = std.ArrayList(u8).init(gpa);
11621155 defer code_buffer.deinit();
11631156
1164 const atom_index = try self.createAtom();
1165 const sym = self.getAtom(atom_index).getSymbolPtr(self);
1166 try self.setSymbolName(sym, name);
1167 sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1));
1157 const atom_index = try coff.createAtom();
1158 const sym = coff.getAtom(atom_index).getSymbolPtr(coff);
1159 try coff.setSymbolName(sym, name);
1160 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_id + 1));
11681161
1169 const res = try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .{
1170 .atom_index = self.getAtom(atom_index).getSymbolIndex().?,
1162 const res = try codegen.generateSymbol(&coff.base, pt, src_loc, val, &code_buffer, .{
1163 .atom_index = coff.getAtom(atom_index).getSymbolIndex().?,
11711164 });
11721165 const code = switch (res) {
11731166 .ok => code_buffer.items,
11741167 .fail => |em| return .{ .fail = em },
11751168 };
11761169
1177 const atom = self.getAtomPtr(atom_index);
1170 const atom = coff.getAtomPtr(atom_index);
11781171 atom.size = @as(u32, @intCast(code.len));
1179 atom.getSymbolPtr(self).value = try self.allocateAtom(
1172 atom.getSymbolPtr(coff).value = try coff.allocateAtom(
11801173 atom_index,
11811174 atom.size,
11821175 @intCast(required_alignment.toByteUnits().?),
11831176 );
1184 errdefer self.freeAtom(atom_index);
1177 errdefer coff.freeAtom(atom_index);
11851178
1186 log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(self).value });
1179 log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(coff).value });
11871180 log.debug(" (required alignment 0x{x})", .{required_alignment});
11881181
1189 try self.writeAtom(atom_index, code);
1182 try coff.writeAtom(atom_index, code);
11901183
11911184 return .{ .ok = atom_index };
11921185}
11931186
11941187pub fn updateNav(
1195 self: *Coff,
1188 coff: *Coff,
11961189 pt: Zcu.PerThread,
11971190 nav_index: InternPool.Nav.Index,
11981191) link.File.UpdateNavError!void {
11991192 if (build_options.skip_non_native and builtin.object_format != .coff) {
12001193 @panic("Attempted to compile for object format that was disabled by build configuration");
12011194 }
1202 if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index);
1195 if (coff.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index);
12031196 const tracy = trace(@src());
12041197 defer tracy.end();
12051198
......@@ -1217,23 +1210,23 @@ pub fn updateNav(
12171210 // TODO make this part of getGlobalSymbol
12181211 const name = nav.name.toSlice(ip);
12191212 const lib_name = @"extern".lib_name.toSlice(ip);
1220 const global_index = try self.getGlobalSymbol(name, lib_name);
1221 try self.need_got_table.put(gpa, global_index, {});
1213 const global_index = try coff.getGlobalSymbol(name, lib_name);
1214 try coff.need_got_table.put(gpa, global_index, {});
12221215 return;
12231216 },
12241217 else => nav_val,
12251218 };
12261219
12271220 if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
1228 const atom_index = try self.getOrCreateAtomForNav(nav_index);
1229 Atom.freeRelocations(self, atom_index);
1230 const atom = self.getAtom(atom_index);
1221 const atom_index = try coff.getOrCreateAtomForNav(nav_index);
1222 coff.freeRelocations(atom_index);
1223 const atom = coff.getAtom(atom_index);
12311224
12321225 var code_buffer = std.ArrayList(u8).init(gpa);
12331226 defer code_buffer.deinit();
12341227
12351228 const res = try codegen.generateSymbol(
1236 &self.base,
1229 &coff.base,
12371230 pt,
12381231 zcu.navSrcLoc(nav_index),
12391232 nav_init,
......@@ -1248,14 +1241,14 @@ pub fn updateNav(
12481241 },
12491242 };
12501243
1251 try self.updateNavCode(pt, nav_index, code, .NULL);
1244 try coff.updateNavCode(pt, nav_index, code, .NULL);
12521245 }
12531246
12541247 // Exports will be updated by `Zcu.processExports` after the update.
12551248}
12561249
12571250fn updateLazySymbolAtom(
1258 self: *Coff,
1251 coff: *Coff,
12591252 pt: Zcu.PerThread,
12601253 sym: link.File.LazySymbol,
12611254 atom_index: Atom.Index,
......@@ -1268,18 +1261,18 @@ fn updateLazySymbolAtom(
12681261 var code_buffer = std.ArrayList(u8).init(gpa);
12691262 defer code_buffer.deinit();
12701263
1271 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1264 const name = try allocPrint(gpa, "__lazy_{s}_{}", .{
12721265 @tagName(sym.kind),
12731266 Type.fromInterned(sym.ty).fmt(pt),
12741267 });
12751268 defer gpa.free(name);
12761269
1277 const atom = self.getAtomPtr(atom_index);
1270 const atom = coff.getAtomPtr(atom_index);
12781271 const local_sym_index = atom.getSymbolIndex().?;
12791272
12801273 const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded;
12811274 const res = try codegen.generateLazySymbol(
1282 &self.base,
1275 &coff.base,
12831276 pt,
12841277 src,
12851278 sym,
......@@ -1297,13 +1290,13 @@ fn updateLazySymbolAtom(
12971290 };
12981291
12991292 const code_len: u32 = @intCast(code.len);
1300 const symbol = atom.getSymbolPtr(self);
1301 try self.setSymbolName(symbol, name);
1293 const symbol = atom.getSymbolPtr(coff);
1294 try coff.setSymbolName(symbol, name);
13021295 symbol.section_number = @enumFromInt(section_index + 1);
13031296 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
13041297
1305 const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
1306 errdefer self.freeAtom(atom_index);
1298 const vaddr = try coff.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
1299 errdefer coff.freeAtom(atom_index);
13071300
13081301 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
13091302 log.debug(" (required alignment 0x{x})", .{required_alignment});
......@@ -1311,52 +1304,52 @@ fn updateLazySymbolAtom(
13111304 atom.size = code_len;
13121305 symbol.value = vaddr;
13131306
1314 try self.addGotEntry(.{ .sym_index = local_sym_index });
1315 try self.writeAtom(atom_index, code);
1307 try coff.addGotEntry(.{ .sym_index = local_sym_index });
1308 try coff.writeAtom(atom_index, code);
13161309}
13171310
13181311pub fn getOrCreateAtomForLazySymbol(
1319 self: *Coff,
1312 coff: *Coff,
13201313 pt: Zcu.PerThread,
13211314 lazy_sym: link.File.LazySymbol,
13221315) !Atom.Index {
1323 const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);
1324 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
1316 const gop = try coff.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);
1317 errdefer _ = if (!gop.found_existing) coff.lazy_syms.pop();
13251318 if (!gop.found_existing) gop.value_ptr.* = .{};
13261319 const atom_ptr, const state_ptr = switch (lazy_sym.kind) {
13271320 .code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state },
13281321 .const_data => .{ &gop.value_ptr.rdata_atom, &gop.value_ptr.rdata_state },
13291322 };
13301323 switch (state_ptr.*) {
1331 .unused => atom_ptr.* = try self.createAtom(),
1324 .unused => atom_ptr.* = try coff.createAtom(),
13321325 .pending_flush => return atom_ptr.*,
13331326 .flushed => {},
13341327 }
13351328 state_ptr.* = .pending_flush;
13361329 const atom = atom_ptr.*;
13371330 // anyerror needs to be deferred until flushModule
1338 if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) {
1339 .code => self.text_section_index.?,
1340 .const_data => self.rdata_section_index.?,
1331 if (lazy_sym.ty != .anyerror_type) try coff.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) {
1332 .code => coff.text_section_index.?,
1333 .const_data => coff.rdata_section_index.?,
13411334 });
13421335 return atom;
13431336}
13441337
1345pub fn getOrCreateAtomForNav(self: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index {
1346 const gpa = self.base.comp.gpa;
1347 const gop = try self.navs.getOrPut(gpa, nav_index);
1338pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index {
1339 const gpa = coff.base.comp.gpa;
1340 const gop = try coff.navs.getOrPut(gpa, nav_index);
13481341 if (!gop.found_existing) {
13491342 gop.value_ptr.* = .{
1350 .atom = try self.createAtom(),
1351 .section = self.getNavOutputSection(nav_index),
1343 .atom = try coff.createAtom(),
1344 .section = coff.getNavOutputSection(nav_index),
13521345 .exports = .{},
13531346 };
13541347 }
13551348 return gop.value_ptr.atom;
13561349}
13571350
1358fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {
1359 const zcu = self.base.comp.zcu.?;
1351fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 {
1352 const zcu = coff.base.comp.zcu.?;
13601353 const ip = &zcu.intern_pool;
13611354 const nav = ip.getNav(nav_index);
13621355 const ty = Type.fromInterned(nav.typeOf(ip));
......@@ -1365,17 +1358,17 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {
13651358 const index: u16 = blk: {
13661359 if (val.isUndefDeep(zcu)) {
13671360 // TODO in release-fast and release-small, we should put undef in .bss
1368 break :blk self.data_section_index.?;
1361 break :blk coff.data_section_index.?;
13691362 }
13701363
13711364 switch (zig_ty) {
13721365 // TODO: what if this is a function pointer?
1373 .@"fn" => break :blk self.text_section_index.?,
1366 .@"fn" => break :blk coff.text_section_index.?,
13741367 else => {
13751368 if (val.getVariable(zcu)) |_| {
1376 break :blk self.data_section_index.?;
1369 break :blk coff.data_section_index.?;
13771370 }
1378 break :blk self.rdata_section_index.?;
1371 break :blk coff.rdata_section_index.?;
13791372 },
13801373 }
13811374 };
......@@ -1383,11 +1376,11 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {
13831376}
13841377
13851378fn updateNavCode(
1386 self: *Coff,
1379 coff: *Coff,
13871380 pt: Zcu.PerThread,
13881381 nav_index: InternPool.Nav.Index,
13891382 code: []u8,
1390 complex_type: coff.ComplexType,
1383 complex_type: coff_util.ComplexType,
13911384) !void {
13921385 const zcu = pt.zcu;
13931386 const ip = &zcu.intern_pool;
......@@ -1399,70 +1392,70 @@ fn updateNavCode(
13991392 target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
14001393 );
14011394
1402 const nav_metadata = self.navs.get(nav_index).?;
1395 const nav_metadata = coff.navs.get(nav_index).?;
14031396 const atom_index = nav_metadata.atom;
1404 const atom = self.getAtom(atom_index);
1397 const atom = coff.getAtom(atom_index);
14051398 const sym_index = atom.getSymbolIndex().?;
14061399 const sect_index = nav_metadata.section;
14071400 const code_len = @as(u32, @intCast(code.len));
14081401
14091402 if (atom.size != 0) {
1410 const sym = atom.getSymbolPtr(self);
1411 try self.setSymbolName(sym, nav.fqn.toSlice(ip));
1412 sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1));
1403 const sym = atom.getSymbolPtr(coff);
1404 try coff.setSymbolName(sym, nav.fqn.toSlice(ip));
1405 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_index + 1));
14131406 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
14141407
1415 const capacity = atom.capacity(self);
1408 const capacity = atom.capacity(coff);
14161409 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
14171410 if (need_realloc) {
1418 const vaddr = try self.growAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
1411 const vaddr = try coff.growAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
14191412 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr });
14201413 log.debug(" (required alignment 0x{x}", .{required_alignment});
14211414
14221415 if (vaddr != sym.value) {
14231416 sym.value = vaddr;
14241417 log.debug(" (updating GOT entry)", .{});
1425 const got_entry_index = self.got_table.lookup.get(.{ .sym_index = sym_index }).?;
1426 try self.writeOffsetTableEntry(got_entry_index);
1427 self.markRelocsDirtyByTarget(.{ .sym_index = sym_index });
1418 const got_entry_index = coff.got_table.lookup.get(.{ .sym_index = sym_index }).?;
1419 try coff.writeOffsetTableEntry(got_entry_index);
1420 coff.markRelocsDirtyByTarget(.{ .sym_index = sym_index });
14281421 }
14291422 } else if (code_len < atom.size) {
1430 self.shrinkAtom(atom_index, code_len);
1423 coff.shrinkAtom(atom_index, code_len);
14311424 }
1432 self.getAtomPtr(atom_index).size = code_len;
1425 coff.getAtomPtr(atom_index).size = code_len;
14331426 } else {
1434 const sym = atom.getSymbolPtr(self);
1435 try self.setSymbolName(sym, nav.fqn.toSlice(ip));
1436 sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1));
1427 const sym = atom.getSymbolPtr(coff);
1428 try coff.setSymbolName(sym, nav.fqn.toSlice(ip));
1429 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_index + 1));
14371430 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
14381431
1439 const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
1440 errdefer self.freeAtom(atom_index);
1432 const vaddr = try coff.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
1433 errdefer coff.freeAtom(atom_index);
14411434 log.debug("allocated atom for {} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr });
1442 self.getAtomPtr(atom_index).size = code_len;
1435 coff.getAtomPtr(atom_index).size = code_len;
14431436 sym.value = vaddr;
14441437
1445 try self.addGotEntry(.{ .sym_index = sym_index });
1438 try coff.addGotEntry(.{ .sym_index = sym_index });
14461439 }
14471440
1448 try self.writeAtom(atom_index, code);
1441 try coff.writeAtom(atom_index, code);
14491442}
14501443
1451pub fn freeNav(self: *Coff, nav_index: InternPool.NavIndex) void {
1452 if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index);
1444pub fn freeNav(coff: *Coff, nav_index: InternPool.NavIndex) void {
1445 if (coff.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index);
14531446
1454 const gpa = self.base.comp.gpa;
1447 const gpa = coff.base.comp.gpa;
14551448 log.debug("freeDecl 0x{x}", .{nav_index});
14561449
1457 if (self.decls.fetchOrderedRemove(nav_index)) |const_kv| {
1450 if (coff.decls.fetchOrderedRemove(nav_index)) |const_kv| {
14581451 var kv = const_kv;
1459 self.freeAtom(kv.value.atom);
1452 coff.freeAtom(kv.value.atom);
14601453 kv.value.exports.deinit(gpa);
14611454 }
14621455}
14631456
14641457pub fn updateExports(
1465 self: *Coff,
1458 coff: *Coff,
14661459 pt: Zcu.PerThread,
14671460 exported: Zcu.Exported,
14681461 export_indices: []const u32,
......@@ -1473,7 +1466,7 @@ pub fn updateExports(
14731466
14741467 const zcu = pt.zcu;
14751468 const ip = &zcu.intern_pool;
1476 const comp = self.base.comp;
1469 const comp = coff.base.comp;
14771470 const target = comp.root_mod.resolved_target.result;
14781471
14791472 if (comp.config.use_llvm) {
......@@ -1513,18 +1506,18 @@ pub fn updateExports(
15131506 }
15141507 }
15151508
1516 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices);
1509 if (coff.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices);
15171510
15181511 const gpa = comp.gpa;
15191512
15201513 const metadata = switch (exported) {
15211514 .nav => |nav| blk: {
1522 _ = try self.getOrCreateAtomForNav(nav);
1523 break :blk self.navs.getPtr(nav).?;
1515 _ = try coff.getOrCreateAtomForNav(nav);
1516 break :blk coff.navs.getPtr(nav).?;
15241517 },
1525 .uav => |uav| self.uavs.getPtr(uav) orelse blk: {
1518 .uav => |uav| coff.uavs.getPtr(uav) orelse blk: {
15261519 const first_exp = zcu.all_exports.items[export_indices[0]];
1527 const res = try self.lowerUav(pt, uav, .none, first_exp.src);
1520 const res = try coff.lowerUav(pt, uav, .none, first_exp.src);
15281521 switch (res) {
15291522 .mcv => {},
15301523 .fail => |em| {
......@@ -1535,11 +1528,11 @@ pub fn updateExports(
15351528 return;
15361529 },
15371530 }
1538 break :blk self.uavs.getPtr(uav).?;
1531 break :blk coff.uavs.getPtr(uav).?;
15391532 },
15401533 };
15411534 const atom_index = metadata.atom;
1542 const atom = self.getAtom(atom_index);
1535 const atom = coff.getAtom(atom_index);
15431536
15441537 for (export_indices) |export_idx| {
15451538 const exp = zcu.all_exports.items[export_idx];
......@@ -1568,27 +1561,27 @@ pub fn updateExports(
15681561 }
15691562
15701563 const exp_name = exp.opts.name.toSlice(&zcu.intern_pool);
1571 const sym_index = metadata.getExport(self, exp_name) orelse blk: {
1572 const sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: {
1573 const global = self.globals.items[global_index];
1564 const sym_index = metadata.getExport(coff, exp_name) orelse blk: {
1565 const sym_index = if (coff.getGlobalIndex(exp_name)) |global_index| ind: {
1566 const global = coff.globals.items[global_index];
15741567 // TODO this is just plain wrong as it all should happen in a single `resolveSymbols`
15751568 // pass. This will go away once we abstact away Zig's incremental compilation into
15761569 // its own module.
1577 if (global.file == null and self.getSymbol(global).section_number == .UNDEFINED) {
1578 _ = self.unresolved.swapRemove(global_index);
1570 if (global.file == null and coff.getSymbol(global).section_number == .UNDEFINED) {
1571 _ = coff.unresolved.swapRemove(global_index);
15791572 break :ind global.sym_index;
15801573 }
1581 break :ind try self.allocateSymbol();
1582 } else try self.allocateSymbol();
1574 break :ind try coff.allocateSymbol();
1575 } else try coff.allocateSymbol();
15831576 try metadata.exports.append(gpa, sym_index);
15841577 break :blk sym_index;
15851578 };
15861579 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1587 const sym = self.getSymbolPtr(sym_loc);
1588 try self.setSymbolName(sym, exp_name);
1589 sym.value = atom.getSymbol(self).value;
1590 sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1));
1591 sym.type = atom.getSymbol(self).type;
1580 const sym = coff.getSymbolPtr(sym_loc);
1581 try coff.setSymbolName(sym, exp_name);
1582 sym.value = atom.getSymbol(coff).value;
1583 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1));
1584 sym.type = atom.getSymbol(coff).type;
15921585
15931586 switch (exp.opts.linkage) {
15941587 .strong => {
......@@ -1599,27 +1592,27 @@ pub fn updateExports(
15991592 else => unreachable,
16001593 }
16011594
1602 try self.resolveGlobalSymbol(sym_loc);
1595 try coff.resolveGlobalSymbol(sym_loc);
16031596 }
16041597}
16051598
16061599pub fn deleteExport(
1607 self: *Coff,
1600 coff: *Coff,
16081601 exported: Zcu.Exported,
16091602 name: InternPool.NullTerminatedString,
16101603) void {
1611 if (self.llvm_object) |_| return;
1604 if (coff.llvm_object) |_| return;
16121605 const metadata = switch (exported) {
1613 .nav => |nav| self.navs.getPtr(nav),
1614 .uav => |uav| self.uavs.getPtr(uav),
1606 .nav => |nav| coff.navs.getPtr(nav),
1607 .uav => |uav| coff.uavs.getPtr(uav),
16151608 } orelse return;
1616 const zcu = self.base.comp.zcu.?;
1609 const zcu = coff.base.comp.zcu.?;
16171610 const name_slice = name.toSlice(&zcu.intern_pool);
1618 const sym_index = metadata.getExportPtr(self, name_slice) orelse return;
1611 const sym_index = metadata.getExportPtr(coff, name_slice) orelse return;
16191612
1620 const gpa = self.base.comp.gpa;
1613 const gpa = coff.base.comp.gpa;
16211614 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
1622 const sym = self.getSymbolPtr(sym_loc);
1615 const sym = coff.getSymbolPtr(sym_loc);
16231616 log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)});
16241617 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
16251618 sym.* = .{
......@@ -1630,12 +1623,12 @@ pub fn deleteExport(
16301623 .storage_class = .NULL,
16311624 .number_of_aux_symbols = 0,
16321625 };
1633 self.locals_free_list.append(gpa, sym_index.*) catch {};
1626 coff.locals_free_list.append(gpa, sym_index.*) catch {};
16341627
1635 if (self.resolver.fetchRemove(name_slice)) |entry| {
1628 if (coff.resolver.fetchRemove(name_slice)) |entry| {
16361629 defer gpa.free(entry.key);
1637 self.globals_free_list.append(gpa, entry.value) catch {};
1638 self.globals.items[entry.value] = .{
1630 coff.globals_free_list.append(gpa, entry.value) catch {};
1631 coff.globals.items[entry.value] = .{
16391632 .sym_index = 0,
16401633 .file = null,
16411634 };
......@@ -1644,16 +1637,16 @@ pub fn deleteExport(
16441637 sym_index.* = 0;
16451638}
16461639
1647fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
1648 const gpa = self.base.comp.gpa;
1649 const sym = self.getSymbol(current);
1650 const sym_name = self.getSymbolName(current);
1640fn resolveGlobalSymbol(coff: *Coff, current: SymbolWithLoc) !void {
1641 const gpa = coff.base.comp.gpa;
1642 const sym = coff.getSymbol(current);
1643 const sym_name = coff.getSymbolName(current);
16511644
1652 const gop = try self.getOrPutGlobalPtr(sym_name);
1645 const gop = try coff.getOrPutGlobalPtr(sym_name);
16531646 if (!gop.found_existing) {
16541647 gop.value_ptr.* = current;
16551648 if (sym.section_number == .UNDEFINED) {
1656 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, false);
1649 try coff.unresolved.putNoClobber(gpa, coff.getGlobalIndex(sym_name).?, false);
16571650 }
16581651 return;
16591652 }
......@@ -1662,33 +1655,560 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
16621655
16631656 if (sym.section_number == .UNDEFINED) return;
16641657
1665 _ = self.unresolved.swapRemove(self.getGlobalIndex(sym_name).?);
1658 _ = coff.unresolved.swapRemove(coff.getGlobalIndex(sym_name).?);
16661659
16671660 gop.value_ptr.* = current;
16681661}
16691662
1670pub fn flush(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
1671 const comp = self.base.comp;
1663pub fn flush(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
1664 const comp = coff.base.comp;
16721665 const use_lld = build_options.have_llvm and comp.config.use_lld;
16731666 if (use_lld) {
1674 return lld.linkWithLLD(self, arena, tid, prog_node);
1667 return coff.linkWithLLD(arena, tid, prog_node);
16751668 }
16761669 switch (comp.config.output_mode) {
1677 .Exe, .Obj => return self.flushModule(arena, tid, prog_node),
1670 .Exe, .Obj => return coff.flushModule(arena, tid, prog_node),
16781671 .Lib => return error.TODOImplementWritingLibFiles,
16791672 }
16801673}
16811674
1682pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
1675fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
1676 dev.check(.lld_linker);
1677
16831678 const tracy = trace(@src());
16841679 defer tracy.end();
16851680
1686 const comp = self.base.comp;
1681 const comp = coff.base.comp;
1682 const gpa = comp.gpa;
1683
1684 const directory = coff.base.emit.root_dir; // Just an alias to make it shorter to type.
1685 const full_out_path = try directory.join(arena, &[_][]const u8{coff.base.emit.sub_path});
1686
1687 // If there is no Zig code to compile, then we should skip flushing the output file because it
1688 // will not be part of the linker line anyway.
1689 const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: {
1690 try coff.flushModule(arena, tid, prog_node);
1691
1692 if (fs.path.dirname(full_out_path)) |dirname| {
1693 break :blk try fs.path.join(arena, &.{ dirname, coff.base.zcu_object_sub_path.? });
1694 } else {
1695 break :blk coff.base.zcu_object_sub_path.?;
1696 }
1697 } else null;
1698
1699 const sub_prog_node = prog_node.start("LLD Link", 0);
1700 defer sub_prog_node.end();
1701
1702 const is_lib = comp.config.output_mode == .Lib;
1703 const is_dyn_lib = comp.config.link_mode == .dynamic and is_lib;
1704 const is_exe_or_dyn_lib = is_dyn_lib or comp.config.output_mode == .Exe;
1705 const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib;
1706 const target = comp.root_mod.resolved_target.result;
1707 const optimize_mode = comp.root_mod.optimize_mode;
1708 const entry_name: ?[]const u8 = switch (coff.entry) {
1709 // This logic isn't quite right for disabled or enabled. No point in fixing it
1710 // when the goal is to eliminate dependency on LLD anyway.
1711 // https://github.com/ziglang/zig/issues/17751
1712 .disabled, .default, .enabled => null,
1713 .named => |name| name,
1714 };
1715
1716 // See link/Elf.zig for comments on how this mechanism works.
1717 const id_symlink_basename = "lld.id";
1718
1719 var man: Cache.Manifest = undefined;
1720 defer if (!coff.base.disable_lld_caching) man.deinit();
1721
1722 var digest: [Cache.hex_digest_len]u8 = undefined;
1723
1724 if (!coff.base.disable_lld_caching) {
1725 man = comp.cache_parent.obtain();
1726 coff.base.releaseLock();
1727
1728 comptime assert(Compilation.link_hash_implementation_version == 14);
1729
1730 try link.hashInputs(&man, comp.link_inputs);
1731 for (comp.c_object_table.keys()) |key| {
1732 _ = try man.addFilePath(key.status.success.object_path, null);
1733 }
1734 for (comp.win32_resource_table.keys()) |key| {
1735 _ = try man.addFile(key.status.success.res_path, null);
1736 }
1737 try man.addOptionalFile(module_obj_path);
1738 man.hash.addOptionalBytes(entry_name);
1739 man.hash.add(coff.base.stack_size);
1740 man.hash.add(coff.image_base);
1741 {
1742 // TODO remove this, libraries must instead be resolved by the frontend.
1743 for (coff.lib_directories) |lib_directory| man.hash.addOptionalBytes(lib_directory.path);
1744 }
1745 man.hash.add(comp.skip_linker_dependencies);
1746 if (comp.config.link_libc) {
1747 man.hash.add(comp.libc_installation != null);
1748 if (comp.libc_installation) |libc_installation| {
1749 man.hash.addBytes(libc_installation.crt_dir.?);
1750 if (target.abi == .msvc or target.abi == .itanium) {
1751 man.hash.addBytes(libc_installation.msvc_lib_dir.?);
1752 man.hash.addBytes(libc_installation.kernel32_lib_dir.?);
1753 }
1754 }
1755 }
1756 man.hash.addListOfBytes(comp.windows_libs.keys());
1757 man.hash.addListOfBytes(comp.force_undefined_symbols.keys());
1758 man.hash.addOptional(coff.subsystem);
1759 man.hash.add(comp.config.is_test);
1760 man.hash.add(coff.tsaware);
1761 man.hash.add(coff.nxcompat);
1762 man.hash.add(coff.dynamicbase);
1763 man.hash.add(coff.base.allow_shlib_undefined);
1764 // strip does not need to go into the linker hash because it is part of the hash namespace
1765 man.hash.add(coff.major_subsystem_version);
1766 man.hash.add(coff.minor_subsystem_version);
1767 man.hash.add(coff.repro);
1768 man.hash.addOptional(comp.version);
1769 try man.addOptionalFile(coff.module_definition_file);
1770
1771 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
1772 _ = try man.hit();
1773 digest = man.final();
1774 var prev_digest_buf: [digest.len]u8 = undefined;
1775 const prev_digest: []u8 = Cache.readSmallFile(
1776 directory.handle,
1777 id_symlink_basename,
1778 &prev_digest_buf,
1779 ) catch |err| blk: {
1780 log.debug("COFF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
1781 // Handle this as a cache miss.
1782 break :blk prev_digest_buf[0..0];
1783 };
1784 if (mem.eql(u8, prev_digest, &digest)) {
1785 log.debug("COFF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
1786 // Hot diggity dog! The output binary is already there.
1787 coff.base.lock = man.toOwnedLock();
1788 return;
1789 }
1790 log.debug("COFF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
1791
1792 // We are about to change the output file to be different, so we invalidate the build hash now.
1793 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
1794 error.FileNotFound => {},
1795 else => |e| return e,
1796 };
1797 }
1798
1799 if (comp.config.output_mode == .Obj) {
1800 // LLD's COFF driver does not support the equivalent of `-r` so we do a simple file copy
1801 // here. TODO: think carefully about how we can avoid this redundant operation when doing
1802 // build-obj. See also the corresponding TODO in linkAsArchive.
1803 const the_object_path = blk: {
1804 if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path;
1805
1806 if (comp.c_object_table.count() != 0)
1807 break :blk comp.c_object_table.keys()[0].status.success.object_path;
1808
1809 if (module_obj_path) |p|
1810 break :blk Path.initCwd(p);
1811
1812 // TODO I think this is unreachable. Audit this situation when solving the above TODO
1813 // regarding eliding redundant object -> object transformations.
1814 return error.NoObjectsToLink;
1815 };
1816 try std.fs.Dir.copyFile(
1817 the_object_path.root_dir.handle,
1818 the_object_path.sub_path,
1819 directory.handle,
1820 coff.base.emit.sub_path,
1821 .{},
1822 );
1823 } else {
1824 // Create an LLD command line and invoke it.
1825 var argv = std.ArrayList([]const u8).init(gpa);
1826 defer argv.deinit();
1827 // We will invoke ourselves as a child process to gain access to LLD.
1828 // This is necessary because LLD does not behave properly as a library -
1829 // it calls exit() and does not reset all global data between invocations.
1830 const linker_command = "lld-link";
1831 try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command });
1832
1833 try argv.append("-ERRORLIMIT:0");
1834 try argv.append("-NOLOGO");
1835 if (comp.config.debug_format != .strip) {
1836 try argv.append("-DEBUG");
1837
1838 const out_ext = std.fs.path.extension(full_out_path);
1839 const out_pdb = coff.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{
1840 full_out_path[0 .. full_out_path.len - out_ext.len],
1841 });
1842 const out_pdb_basename = std.fs.path.basename(out_pdb);
1843
1844 try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb}));
1845 try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb_basename}));
1846 }
1847 if (comp.version) |version| {
1848 try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));
1849 }
1850 if (comp.config.lto) {
1851 switch (optimize_mode) {
1852 .Debug => {},
1853 .ReleaseSmall => try argv.append("-OPT:lldlto=2"),
1854 .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"),
1855 }
1856 }
1857 if (comp.config.output_mode == .Exe) {
1858 try argv.append(try allocPrint(arena, "-STACK:{d}", .{coff.base.stack_size}));
1859 }
1860 try argv.append(try allocPrint(arena, "-BASE:{d}", .{coff.image_base}));
1861
1862 if (target.cpu.arch == .x86) {
1863 try argv.append("-MACHINE:X86");
1864 } else if (target.cpu.arch == .x86_64) {
1865 try argv.append("-MACHINE:X64");
1866 } else if (target.cpu.arch.isARM()) {
1867 if (target.ptrBitWidth() == 32) {
1868 try argv.append("-MACHINE:ARM");
1869 } else {
1870 try argv.append("-MACHINE:ARM64");
1871 }
1872 }
1873
1874 for (comp.force_undefined_symbols.keys()) |symbol| {
1875 try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol}));
1876 }
1877
1878 if (is_dyn_lib) {
1879 try argv.append("-DLL");
1880 }
1881
1882 if (entry_name) |name| {
1883 try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{name}));
1884 }
1885
1886 if (coff.repro) {
1887 try argv.append("-BREPRO");
1888 }
1889
1890 if (coff.tsaware) {
1891 try argv.append("-tsaware");
1892 }
1893 if (coff.nxcompat) {
1894 try argv.append("-nxcompat");
1895 }
1896 if (!coff.dynamicbase) {
1897 try argv.append("-dynamicbase:NO");
1898 }
1899 if (coff.base.allow_shlib_undefined) {
1900 try argv.append("-FORCE:UNRESOLVED");
1901 }
1902
1903 try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
1904
1905 if (comp.implib_emit) |emit| {
1906 const implib_out_path = try emit.root_dir.join(arena, &[_][]const u8{emit.sub_path});
1907 try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path}));
1908 }
1909
1910 if (comp.config.link_libc) {
1911 if (comp.libc_installation) |libc_installation| {
1912 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?}));
1913
1914 if (target.abi == .msvc or target.abi == .itanium) {
1915 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.msvc_lib_dir.?}));
1916 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.kernel32_lib_dir.?}));
1917 }
1918 }
1919 }
1920
1921 for (coff.lib_directories) |lib_directory| {
1922 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_directory.path orelse "."}));
1923 }
1924
1925 try argv.ensureUnusedCapacity(comp.link_inputs.len);
1926 for (comp.link_inputs) |link_input| switch (link_input) {
1927 .dso_exact => unreachable, // not applicable to PE/COFF
1928 inline .dso, .res => |x| {
1929 argv.appendAssumeCapacity(try x.path.toString(arena));
1930 },
1931 .object, .archive => |obj| {
1932 if (obj.must_link) {
1933 argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{}", .{@as(Path, obj.path)}));
1934 } else {
1935 argv.appendAssumeCapacity(try obj.path.toString(arena));
1936 }
1937 },
1938 };
1939
1940 for (comp.c_object_table.keys()) |key| {
1941 try argv.append(try key.status.success.object_path.toString(arena));
1942 }
1943
1944 for (comp.win32_resource_table.keys()) |key| {
1945 try argv.append(key.status.success.res_path);
1946 }
1947
1948 if (module_obj_path) |p| {
1949 try argv.append(p);
1950 }
1951
1952 if (coff.module_definition_file) |def| {
1953 try argv.append(try allocPrint(arena, "-DEF:{s}", .{def}));
1954 }
1955
1956 const resolved_subsystem: ?std.Target.SubSystem = blk: {
1957 if (coff.subsystem) |explicit| break :blk explicit;
1958 switch (target.os.tag) {
1959 .windows => {
1960 if (comp.zcu) |module| {
1961 if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib)
1962 break :blk null;
1963 if (module.stage1_flags.have_c_main or comp.config.is_test or
1964 module.stage1_flags.have_winmain_crt_startup or
1965 module.stage1_flags.have_wwinmain_crt_startup)
1966 {
1967 break :blk .Console;
1968 }
1969 if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain)
1970 break :blk .Windows;
1971 }
1972 },
1973 .uefi => break :blk .EfiApplication,
1974 else => {},
1975 }
1976 break :blk null;
1977 };
1978
1979 const Mode = enum { uefi, win32 };
1980 const mode: Mode = mode: {
1981 if (resolved_subsystem) |subsystem| {
1982 const subsystem_suffix = try allocPrint(arena, ",{d}.{d}", .{
1983 coff.major_subsystem_version, coff.minor_subsystem_version,
1984 });
1985
1986 switch (subsystem) {
1987 .Console => {
1988 try argv.append(try allocPrint(arena, "-SUBSYSTEM:console{s}", .{
1989 subsystem_suffix,
1990 }));
1991 break :mode .win32;
1992 },
1993 .EfiApplication => {
1994 try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_application{s}", .{
1995 subsystem_suffix,
1996 }));
1997 break :mode .uefi;
1998 },
1999 .EfiBootServiceDriver => {
2000 try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_boot_service_driver{s}", .{
2001 subsystem_suffix,
2002 }));
2003 break :mode .uefi;
2004 },
2005 .EfiRom => {
2006 try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_rom{s}", .{
2007 subsystem_suffix,
2008 }));
2009 break :mode .uefi;
2010 },
2011 .EfiRuntimeDriver => {
2012 try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_runtime_driver{s}", .{
2013 subsystem_suffix,
2014 }));
2015 break :mode .uefi;
2016 },
2017 .Native => {
2018 try argv.append(try allocPrint(arena, "-SUBSYSTEM:native{s}", .{
2019 subsystem_suffix,
2020 }));
2021 break :mode .win32;
2022 },
2023 .Posix => {
2024 try argv.append(try allocPrint(arena, "-SUBSYSTEM:posix{s}", .{
2025 subsystem_suffix,
2026 }));
2027 break :mode .win32;
2028 },
2029 .Windows => {
2030 try argv.append(try allocPrint(arena, "-SUBSYSTEM:windows{s}", .{
2031 subsystem_suffix,
2032 }));
2033 break :mode .win32;
2034 },
2035 }
2036 } else if (target.os.tag == .uefi) {
2037 break :mode .uefi;
2038 } else {
2039 break :mode .win32;
2040 }
2041 };
2042
2043 switch (mode) {
2044 .uefi => try argv.appendSlice(&[_][]const u8{
2045 "-BASE:0",
2046 "-ENTRY:EfiMain",
2047 "-OPT:REF",
2048 "-SAFESEH:NO",
2049 "-MERGE:.rdata=.data",
2050 "-NODEFAULTLIB",
2051 "-SECTION:.xdata,D",
2052 }),
2053 .win32 => {
2054 if (link_in_crt) {
2055 if (target.abi.isGnu()) {
2056 try argv.append("-lldmingw");
2057
2058 if (target.cpu.arch == .x86) {
2059 try argv.append("-ALTERNATENAME:__image_base__=___ImageBase");
2060 } else {
2061 try argv.append("-ALTERNATENAME:__image_base__=__ImageBase");
2062 }
2063
2064 if (is_dyn_lib) {
2065 try argv.append(try comp.crtFileAsString(arena, "dllcrt2.obj"));
2066 if (target.cpu.arch == .x86) {
2067 try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12");
2068 } else {
2069 try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup");
2070 }
2071 } else {
2072 try argv.append(try comp.crtFileAsString(arena, "crt2.obj"));
2073 }
2074
2075 try argv.append(try comp.crtFileAsString(arena, "mingw32.lib"));
2076 } else {
2077 const lib_str = switch (comp.config.link_mode) {
2078 .dynamic => "",
2079 .static => "lib",
2080 };
2081 const d_str = switch (optimize_mode) {
2082 .Debug => "d",
2083 else => "",
2084 };
2085 switch (comp.config.link_mode) {
2086 .static => try argv.append(try allocPrint(arena, "libcmt{s}.lib", .{d_str})),
2087 .dynamic => try argv.append(try allocPrint(arena, "msvcrt{s}.lib", .{d_str})),
2088 }
2089
2090 try argv.append(try allocPrint(arena, "{s}vcruntime{s}.lib", .{ lib_str, d_str }));
2091 try argv.append(try allocPrint(arena, "{s}ucrt{s}.lib", .{ lib_str, d_str }));
2092
2093 //Visual C++ 2015 Conformance Changes
2094 //https://msdn.microsoft.com/en-us/library/bb531344.aspx
2095 try argv.append("legacy_stdio_definitions.lib");
2096
2097 // msvcrt depends on kernel32 and ntdll
2098 try argv.append("kernel32.lib");
2099 try argv.append("ntdll.lib");
2100 }
2101 } else {
2102 try argv.append("-NODEFAULTLIB");
2103 if (!is_lib and entry_name == null) {
2104 if (comp.zcu) |module| {
2105 if (module.stage1_flags.have_winmain_crt_startup) {
2106 try argv.append("-ENTRY:WinMainCRTStartup");
2107 } else {
2108 try argv.append("-ENTRY:wWinMainCRTStartup");
2109 }
2110 } else {
2111 try argv.append("-ENTRY:wWinMainCRTStartup");
2112 }
2113 }
2114 }
2115 },
2116 }
2117
2118 // libc++ dep
2119 if (comp.config.link_libcpp) {
2120 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
2121 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
2122 }
2123
2124 // libunwind dep
2125 if (comp.config.link_libunwind) {
2126 try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
2127 }
2128
2129 if (comp.config.any_fuzz) {
2130 try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
2131 }
2132
2133 if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) {
2134 if (!comp.config.link_libc) {
2135 if (comp.libc_static_lib) |lib| {
2136 try argv.append(try lib.full_object_path.toString(arena));
2137 }
2138 }
2139 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but
2140 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
2141 if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena));
2142 if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena));
2143 }
2144
2145 try argv.ensureUnusedCapacity(comp.windows_libs.count());
2146 for (comp.windows_libs.keys()) |key| {
2147 const lib_basename = try allocPrint(arena, "{s}.lib", .{key});
2148 if (comp.crt_files.get(lib_basename)) |crt_file| {
2149 argv.appendAssumeCapacity(try crt_file.full_object_path.toString(arena));
2150 continue;
2151 }
2152 if (try findLib(arena, lib_basename, coff.lib_directories)) |full_path| {
2153 argv.appendAssumeCapacity(full_path);
2154 continue;
2155 }
2156 if (target.abi.isGnu()) {
2157 const fallback_name = try allocPrint(arena, "lib{s}.dll.a", .{key});
2158 if (try findLib(arena, fallback_name, coff.lib_directories)) |full_path| {
2159 argv.appendAssumeCapacity(full_path);
2160 continue;
2161 }
2162 }
2163 if (target.abi == .msvc or target.abi == .itanium) {
2164 argv.appendAssumeCapacity(lib_basename);
2165 continue;
2166 }
2167
2168 log.err("DLL import library for -l{s} not found", .{key});
2169 return error.DllImportLibraryNotFound;
2170 }
2171
2172 try link.spawnLld(comp, arena, argv.items);
2173 }
2174
2175 if (!coff.base.disable_lld_caching) {
2176 // Update the file with the digest. If it fails we can continue; it only
2177 // means that the next invocation will have an unnecessary cache miss.
2178 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
2179 log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)});
2180 };
2181 // Again failure here only means an unnecessary cache miss.
2182 man.writeManifest() catch |err| {
2183 log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)});
2184 };
2185 // We hang on to this lock so that the output file path can be used without
2186 // other processes clobbering it.
2187 coff.base.lock = man.toOwnedLock();
2188 }
2189}
2190
2191fn findLib(arena: Allocator, name: []const u8, lib_directories: []const Directory) !?[]const u8 {
2192 for (lib_directories) |lib_directory| {
2193 lib_directory.handle.access(name, .{}) catch |err| switch (err) {
2194 error.FileNotFound => continue,
2195 else => |e| return e,
2196 };
2197 return try lib_directory.join(arena, &.{name});
2198 }
2199 return null;
2200}
2201
2202pub fn flushModule(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
2203 const tracy = trace(@src());
2204 defer tracy.end();
2205
2206 const comp = coff.base.comp;
16872207 const gpa = comp.gpa;
16882208 const diags = &comp.link_diags;
16892209
1690 if (self.llvm_object) |llvm_object| {
1691 try self.base.emitLlvmObject(arena, llvm_object, prog_node);
2210 if (coff.llvm_object) |llvm_object| {
2211 try coff.base.emitLlvmObject(arena, llvm_object, prog_node);
16922212 return;
16932213 }
16942214
......@@ -1700,46 +2220,46 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
17002220 .tid = tid,
17012221 };
17022222
1703 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
2223 if (coff.lazy_syms.getPtr(.anyerror_type)) |metadata| {
17042224 // Most lazy symbols can be updated on first use, but
17052225 // anyerror needs to wait for everything to be flushed.
1706 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
2226 if (metadata.text_state != .unused) coff.updateLazySymbolAtom(
17072227 pt,
17082228 .{ .kind = .code, .ty = .anyerror_type },
17092229 metadata.text_atom,
1710 self.text_section_index.?,
2230 coff.text_section_index.?,
17112231 ) catch |err| return switch (err) {
17122232 error.CodegenFail => error.FlushFailure,
17132233 else => |e| e,
17142234 };
1715 if (metadata.rdata_state != .unused) self.updateLazySymbolAtom(
2235 if (metadata.rdata_state != .unused) coff.updateLazySymbolAtom(
17162236 pt,
17172237 .{ .kind = .const_data, .ty = .anyerror_type },
17182238 metadata.rdata_atom,
1719 self.rdata_section_index.?,
2239 coff.rdata_section_index.?,
17202240 ) catch |err| return switch (err) {
17212241 error.CodegenFail => error.FlushFailure,
17222242 else => |e| e,
17232243 };
17242244 }
1725 for (self.lazy_syms.values()) |*metadata| {
2245 for (coff.lazy_syms.values()) |*metadata| {
17262246 if (metadata.text_state != .unused) metadata.text_state = .flushed;
17272247 if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;
17282248 }
17292249
17302250 {
1731 var it = self.need_got_table.iterator();
2251 var it = coff.need_got_table.iterator();
17322252 while (it.next()) |entry| {
1733 const global = self.globals.items[entry.key_ptr.*];
1734 try self.addGotEntry(global);
2253 const global = coff.globals.items[entry.key_ptr.*];
2254 try coff.addGotEntry(global);
17352255 }
17362256 }
17372257
1738 while (self.unresolved.popOrNull()) |entry| {
2258 while (coff.unresolved.popOrNull()) |entry| {
17392259 assert(entry.value);
1740 const global = self.globals.items[entry.key];
1741 const sym = self.getSymbol(global);
1742 const res = try self.import_tables.getOrPut(gpa, sym.value);
2260 const global = coff.globals.items[entry.key];
2261 const sym = coff.getSymbol(global);
2262 const res = try coff.import_tables.getOrPut(gpa, sym.value);
17432263 const itable = res.value_ptr;
17442264 if (!res.found_existing) {
17452265 itable.* = .{};
......@@ -1748,21 +2268,21 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
17482268 // TODO: we could technically write the pointer placeholder for to-be-bound import here,
17492269 // but since this happens in flush, there is currently no point.
17502270 _ = try itable.addImport(gpa, global);
1751 self.imports_count_dirty = true;
2271 coff.imports_count_dirty = true;
17522272 }
17532273
1754 try self.writeImportTables();
2274 try coff.writeImportTables();
17552275
1756 for (self.relocs.keys(), self.relocs.values()) |atom_index, relocs| {
2276 for (coff.relocs.keys(), coff.relocs.values()) |atom_index, relocs| {
17572277 const needs_update = for (relocs.items) |reloc| {
17582278 if (reloc.dirty) break true;
17592279 } else false;
17602280
17612281 if (!needs_update) continue;
17622282
1763 const atom = self.getAtom(atom_index);
1764 const sym = atom.getSymbol(self);
1765 const section = self.sections.get(@intFromEnum(sym.section_number) - 1).header;
2283 const atom = coff.getAtom(atom_index);
2284 const sym = atom.getSymbol(coff);
2285 const section = coff.sections.get(@intFromEnum(sym.section_number) - 1).header;
17662286 const file_offset = section.pointer_to_raw_data + sym.value - section.virtual_address;
17672287
17682288 var code = std.ArrayList(u8).init(gpa);
......@@ -1770,70 +2290,70 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
17702290 try code.resize(math.cast(usize, atom.size) orelse return error.Overflow);
17712291 assert(atom.size > 0);
17722292
1773 const amt = try self.base.file.?.preadAll(code.items, file_offset);
2293 const amt = try coff.base.file.?.preadAll(code.items, file_offset);
17742294 if (amt != code.items.len) return error.InputOutput;
17752295
1776 try self.writeAtom(atom_index, code.items);
2296 try coff.writeAtom(atom_index, code.items);
17772297 }
17782298
17792299 // Update GOT if it got moved in memory.
1780 if (self.got_table_contents_dirty) {
1781 for (self.got_table.entries.items, 0..) |entry, i| {
1782 if (!self.got_table.lookup.contains(entry)) continue;
2300 if (coff.got_table_contents_dirty) {
2301 for (coff.got_table.entries.items, 0..) |entry, i| {
2302 if (!coff.got_table.lookup.contains(entry)) continue;
17832303 // TODO: write all in one go rather than incrementally.
1784 try self.writeOffsetTableEntry(i);
2304 try coff.writeOffsetTableEntry(i);
17852305 }
1786 self.got_table_contents_dirty = false;
2306 coff.got_table_contents_dirty = false;
17872307 }
17882308
1789 try self.writeBaseRelocations();
2309 try coff.writeBaseRelocations();
17902310
1791 if (self.getEntryPoint()) |entry_sym_loc| {
1792 self.entry_addr = self.getSymbol(entry_sym_loc).value;
2311 if (coff.getEntryPoint()) |entry_sym_loc| {
2312 coff.entry_addr = coff.getSymbol(entry_sym_loc).value;
17932313 }
17942314
17952315 if (build_options.enable_logging) {
1796 self.logSymtab();
1797 self.logImportTables();
2316 coff.logSymtab();
2317 coff.logImportTables();
17982318 }
17992319
1800 try self.writeStrtab();
1801 try self.writeDataDirectoriesHeaders();
1802 try self.writeSectionHeaders();
2320 try coff.writeStrtab();
2321 try coff.writeDataDirectoriesHeaders();
2322 try coff.writeSectionHeaders();
18032323
1804 if (self.entry_addr == null and comp.config.output_mode == .Exe) {
2324 if (coff.entry_addr == null and comp.config.output_mode == .Exe) {
18052325 log.debug("flushing. no_entry_point_found = true\n", .{});
18062326 diags.flags.no_entry_point_found = true;
18072327 } else {
18082328 log.debug("flushing. no_entry_point_found = false\n", .{});
18092329 diags.flags.no_entry_point_found = false;
1810 try self.writeHeader();
2330 try coff.writeHeader();
18112331 }
18122332
1813 assert(!self.imports_count_dirty);
2333 assert(!coff.imports_count_dirty);
18142334}
18152335
18162336pub fn getNavVAddr(
1817 self: *Coff,
2337 coff: *Coff,
18182338 pt: Zcu.PerThread,
18192339 nav_index: InternPool.Nav.Index,
18202340 reloc_info: link.File.RelocInfo,
18212341) !u64 {
1822 assert(self.llvm_object == null);
2342 assert(coff.llvm_object == null);
18232343 const zcu = pt.zcu;
18242344 const ip = &zcu.intern_pool;
18252345 const nav = ip.getNav(nav_index);
18262346 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
18272347 const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
1828 .@"extern" => |@"extern"| try self.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)),
1829 else => self.getAtom(try self.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,
2348 .@"extern" => |@"extern"| try coff.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)),
2349 else => coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,
18302350 };
1831 const atom_index = self.getAtomIndexForSymbol(.{
2351 const atom_index = coff.getAtomIndexForSymbol(.{
18322352 .sym_index = reloc_info.parent.atom_index,
18332353 .file = null,
18342354 }).?;
18352355 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1836 try Atom.addRelocation(self, atom_index, .{
2356 try coff.addRelocation(atom_index, .{
18372357 .type = .direct,
18382358 .target = target,
18392359 .offset = @as(u32, @intCast(reloc_info.offset)),
......@@ -1841,13 +2361,13 @@ pub fn getNavVAddr(
18412361 .pcrel = false,
18422362 .length = 3,
18432363 });
1844 try Atom.addBaseRelocation(self, atom_index, @as(u32, @intCast(reloc_info.offset)));
2364 try coff.addBaseRelocation(atom_index, @as(u32, @intCast(reloc_info.offset)));
18452365
18462366 return 0;
18472367}
18482368
18492369pub fn lowerUav(
1850 self: *Coff,
2370 coff: *Coff,
18512371 pt: Zcu.PerThread,
18522372 uav: InternPool.Index,
18532373 explicit_alignment: InternPool.Alignment,
......@@ -1860,9 +2380,9 @@ pub fn lowerUav(
18602380 .none => val.typeOf(zcu).abiAlignment(zcu),
18612381 else => explicit_alignment,
18622382 };
1863 if (self.uavs.get(uav)) |metadata| {
1864 const atom = self.getAtom(metadata.atom);
1865 const existing_addr = atom.getSymbol(self).value;
2383 if (coff.uavs.get(uav)) |metadata| {
2384 const atom = coff.getAtom(metadata.atom);
2385 const existing_addr = atom.getSymbol(coff).value;
18662386 if (uav_alignment.check(existing_addr))
18672387 return .{ .mcv = .{ .load_direct = atom.getSymbolIndex().? } };
18682388 }
......@@ -1871,12 +2391,12 @@ pub fn lowerUav(
18712391 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
18722392 @intFromEnum(uav),
18732393 }) catch unreachable;
1874 const res = self.lowerConst(
2394 const res = coff.lowerConst(
18752395 pt,
18762396 name,
18772397 val,
18782398 uav_alignment,
1879 self.rdata_section_index.?,
2399 coff.rdata_section_index.?,
18802400 src_loc,
18812401 ) catch |err| switch (err) {
18822402 error.OutOfMemory => return error.OutOfMemory,
......@@ -1891,30 +2411,30 @@ pub fn lowerUav(
18912411 .ok => |atom_index| atom_index,
18922412 .fail => |em| return .{ .fail = em },
18932413 };
1894 try self.uavs.put(gpa, uav, .{
2414 try coff.uavs.put(gpa, uav, .{
18952415 .atom = atom_index,
1896 .section = self.rdata_section_index.?,
2416 .section = coff.rdata_section_index.?,
18972417 });
18982418 return .{ .mcv = .{
1899 .load_direct = self.getAtom(atom_index).getSymbolIndex().?,
2419 .load_direct = coff.getAtom(atom_index).getSymbolIndex().?,
19002420 } };
19012421}
19022422
19032423pub fn getUavVAddr(
1904 self: *Coff,
2424 coff: *Coff,
19052425 uav: InternPool.Index,
19062426 reloc_info: link.File.RelocInfo,
19072427) !u64 {
1908 assert(self.llvm_object == null);
2428 assert(coff.llvm_object == null);
19092429
1910 const this_atom_index = self.uavs.get(uav).?.atom;
1911 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
1912 const atom_index = self.getAtomIndexForSymbol(.{
2430 const this_atom_index = coff.uavs.get(uav).?.atom;
2431 const sym_index = coff.getAtom(this_atom_index).getSymbolIndex().?;
2432 const atom_index = coff.getAtomIndexForSymbol(.{
19132433 .sym_index = reloc_info.parent.atom_index,
19142434 .file = null,
19152435 }).?;
19162436 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1917 try Atom.addRelocation(self, atom_index, .{
2437 try coff.addRelocation(atom_index, .{
19182438 .type = .direct,
19192439 .target = target,
19202440 .offset = @as(u32, @intCast(reloc_info.offset)),
......@@ -1922,41 +2442,41 @@ pub fn getUavVAddr(
19222442 .pcrel = false,
19232443 .length = 3,
19242444 });
1925 try Atom.addBaseRelocation(self, atom_index, @as(u32, @intCast(reloc_info.offset)));
2445 try coff.addBaseRelocation(atom_index, @as(u32, @intCast(reloc_info.offset)));
19262446
19272447 return 0;
19282448}
19292449
1930pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 {
1931 const gop = try self.getOrPutGlobalPtr(name);
1932 const global_index = self.getGlobalIndex(name).?;
2450pub fn getGlobalSymbol(coff: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 {
2451 const gop = try coff.getOrPutGlobalPtr(name);
2452 const global_index = coff.getGlobalIndex(name).?;
19332453
19342454 if (gop.found_existing) {
19352455 return global_index;
19362456 }
19372457
1938 const sym_index = try self.allocateSymbol();
2458 const sym_index = try coff.allocateSymbol();
19392459 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
19402460 gop.value_ptr.* = sym_loc;
19412461
1942 const gpa = self.base.comp.gpa;
1943 const sym = self.getSymbolPtr(sym_loc);
1944 try self.setSymbolName(sym, name);
2462 const gpa = coff.base.comp.gpa;
2463 const sym = coff.getSymbolPtr(sym_loc);
2464 try coff.setSymbolName(sym, name);
19452465 sym.storage_class = .EXTERNAL;
19462466
19472467 if (lib_name_name) |lib_name| {
19482468 // We repurpose the 'value' of the Symbol struct to store an offset into
19492469 // temporary string table where we will store the library name hint.
1950 sym.value = try self.temp_strtab.insert(gpa, lib_name);
2470 sym.value = try coff.temp_strtab.insert(gpa, lib_name);
19512471 }
19522472
1953 try self.unresolved.putNoClobber(gpa, global_index, true);
2473 try coff.unresolved.putNoClobber(gpa, global_index, true);
19542474
19552475 return global_index;
19562476}
19572477
1958pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
1959 _ = self;
2478pub fn updateDeclLineNumber(coff: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
2479 _ = coff;
19602480 _ = pt;
19612481 _ = decl_index;
19622482 log.debug("TODO implement updateDeclLineNumber", .{});
......@@ -1965,10 +2485,10 @@ pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPo
19652485/// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table
19662486/// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do
19672487/// incremental updates and writes into the table instead of doing it all at once
1968fn writeBaseRelocations(self: *Coff) !void {
1969 const gpa = self.base.comp.gpa;
2488fn writeBaseRelocations(coff: *Coff) !void {
2489 const gpa = coff.base.comp.gpa;
19702490
1971 var page_table = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa);
2491 var page_table = std.AutoHashMap(u32, std.ArrayList(coff_util.BaseRelocation)).init(gpa);
19722492 defer {
19732493 var it = page_table.valueIterator();
19742494 while (it.next()) |inner| {
......@@ -1978,19 +2498,19 @@ fn writeBaseRelocations(self: *Coff) !void {
19782498 }
19792499
19802500 {
1981 var it = self.base_relocs.iterator();
2501 var it = coff.base_relocs.iterator();
19822502 while (it.next()) |entry| {
19832503 const atom_index = entry.key_ptr.*;
1984 const atom = self.getAtom(atom_index);
1985 const sym = atom.getSymbol(self);
2504 const atom = coff.getAtom(atom_index);
2505 const sym = atom.getSymbol(coff);
19862506 const offsets = entry.value_ptr.*;
19872507
19882508 for (offsets.items) |offset| {
19892509 const rva = sym.value + offset;
1990 const page = mem.alignBackward(u32, rva, self.page_size);
2510 const page = mem.alignBackward(u32, rva, coff.page_size);
19912511 const gop = try page_table.getOrPut(page);
19922512 if (!gop.found_existing) {
1993 gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
2513 gop.value_ptr.* = std.ArrayList(coff_util.BaseRelocation).init(gpa);
19942514 }
19952515 try gop.value_ptr.append(.{
19962516 .offset = @as(u12, @intCast(rva - page)),
......@@ -2000,18 +2520,18 @@ fn writeBaseRelocations(self: *Coff) !void {
20002520 }
20012521
20022522 {
2003 const header = &self.sections.items(.header)[self.got_section_index.?];
2004 for (self.got_table.entries.items, 0..) |entry, index| {
2005 if (!self.got_table.lookup.contains(entry)) continue;
2523 const header = &coff.sections.items(.header)[coff.got_section_index.?];
2524 for (coff.got_table.entries.items, 0..) |entry, index| {
2525 if (!coff.got_table.lookup.contains(entry)) continue;
20062526
2007 const sym = self.getSymbol(entry);
2527 const sym = coff.getSymbol(entry);
20082528 if (sym.section_number == .UNDEFINED) continue;
20092529
2010 const rva = @as(u32, @intCast(header.virtual_address + index * self.ptr_width.size()));
2011 const page = mem.alignBackward(u32, rva, self.page_size);
2530 const rva = @as(u32, @intCast(header.virtual_address + index * coff.ptr_width.size()));
2531 const page = mem.alignBackward(u32, rva, coff.page_size);
20122532 const gop = try page_table.getOrPut(page);
20132533 if (!gop.found_existing) {
2014 gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
2534 gop.value_ptr.* = std.ArrayList(coff_util.BaseRelocation).init(gpa);
20152535 }
20162536 try gop.value_ptr.append(.{
20172537 .offset = @as(u12, @intCast(rva - page)),
......@@ -2040,7 +2560,7 @@ fn writeBaseRelocations(self: *Coff) !void {
20402560 // Pad to required 4byte alignment
20412561 if (!mem.isAlignedGeneric(
20422562 usize,
2043 entries.items.len * @sizeOf(coff.BaseRelocation),
2563 entries.items.len * @sizeOf(coff_util.BaseRelocation),
20442564 @sizeOf(u32),
20452565 )) {
20462566 try entries.append(.{
......@@ -2051,58 +2571,58 @@ fn writeBaseRelocations(self: *Coff) !void {
20512571
20522572 const block_size = @as(
20532573 u32,
2054 @intCast(entries.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry)),
2574 @intCast(entries.items.len * @sizeOf(coff_util.BaseRelocation) + @sizeOf(coff_util.BaseRelocationDirectoryEntry)),
20552575 );
20562576 try buffer.ensureUnusedCapacity(block_size);
2057 buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{
2577 buffer.appendSliceAssumeCapacity(mem.asBytes(&coff_util.BaseRelocationDirectoryEntry{
20582578 .page_rva = page,
20592579 .block_size = block_size,
20602580 }));
20612581 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entries.items));
20622582 }
20632583
2064 const header = &self.sections.items(.header)[self.reloc_section_index.?];
2584 const header = &coff.sections.items(.header)[coff.reloc_section_index.?];
20652585 const needed_size = @as(u32, @intCast(buffer.items.len));
2066 try self.growSection(self.reloc_section_index.?, needed_size);
2586 try coff.growSection(coff.reloc_section_index.?, needed_size);
20672587
2068 try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);
2588 try coff.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);
20692589
2070 self.data_directories[@intFromEnum(coff.DirectoryEntry.BASERELOC)] = .{
2590 coff.data_directories[@intFromEnum(coff_util.DirectoryEntry.BASERELOC)] = .{
20712591 .virtual_address = header.virtual_address,
20722592 .size = needed_size,
20732593 };
20742594}
20752595
2076fn writeImportTables(self: *Coff) !void {
2077 if (self.idata_section_index == null) return;
2078 if (!self.imports_count_dirty) return;
2596fn writeImportTables(coff: *Coff) !void {
2597 if (coff.idata_section_index == null) return;
2598 if (!coff.imports_count_dirty) return;
20792599
2080 const gpa = self.base.comp.gpa;
2600 const gpa = coff.base.comp.gpa;
20812601
20822602 const ext = ".dll";
2083 const header = &self.sections.items(.header)[self.idata_section_index.?];
2603 const header = &coff.sections.items(.header)[coff.idata_section_index.?];
20842604
20852605 // Calculate needed size
20862606 var iat_size: u32 = 0;
2087 var dir_table_size: u32 = @sizeOf(coff.ImportDirectoryEntry); // sentinel
2607 var dir_table_size: u32 = @sizeOf(coff_util.ImportDirectoryEntry); // sentinel
20882608 var lookup_table_size: u32 = 0;
20892609 var names_table_size: u32 = 0;
20902610 var dll_names_size: u32 = 0;
2091 for (self.import_tables.keys(), 0..) |off, i| {
2092 const lib_name = self.temp_strtab.getAssumeExists(off);
2093 const itable = self.import_tables.values()[i];
2611 for (coff.import_tables.keys(), 0..) |off, i| {
2612 const lib_name = coff.temp_strtab.getAssumeExists(off);
2613 const itable = coff.import_tables.values()[i];
20942614 iat_size += itable.size() + 8;
2095 dir_table_size += @sizeOf(coff.ImportDirectoryEntry);
2096 lookup_table_size += @as(u32, @intCast(itable.entries.items.len + 1)) * @sizeOf(coff.ImportLookupEntry64.ByName);
2615 dir_table_size += @sizeOf(coff_util.ImportDirectoryEntry);
2616 lookup_table_size += @as(u32, @intCast(itable.entries.items.len + 1)) * @sizeOf(coff_util.ImportLookupEntry64.ByName);
20972617 for (itable.entries.items) |entry| {
2098 const sym_name = self.getSymbolName(entry);
2618 const sym_name = coff.getSymbolName(entry);
20992619 names_table_size += 2 + mem.alignForward(u32, @as(u32, @intCast(sym_name.len + 1)), 2);
21002620 }
21012621 dll_names_size += @as(u32, @intCast(lib_name.len + ext.len + 1));
21022622 }
21032623
21042624 const needed_size = iat_size + dir_table_size + lookup_table_size + names_table_size + dll_names_size;
2105 try self.growSection(self.idata_section_index.?, needed_size);
2625 try coff.growSection(coff.idata_section_index.?, needed_size);
21062626
21072627 // Do the actual writes
21082628 var buffer = std.ArrayList(u8).init(gpa);
......@@ -2110,41 +2630,41 @@ fn writeImportTables(self: *Coff) !void {
21102630 try buffer.ensureTotalCapacityPrecise(needed_size);
21112631 buffer.resize(needed_size) catch unreachable;
21122632
2113 const dir_header_size = @sizeOf(coff.ImportDirectoryEntry);
2114 const lookup_entry_size = @sizeOf(coff.ImportLookupEntry64.ByName);
2633 const dir_header_size = @sizeOf(coff_util.ImportDirectoryEntry);
2634 const lookup_entry_size = @sizeOf(coff_util.ImportLookupEntry64.ByName);
21152635
21162636 var iat_offset: u32 = 0;
21172637 var dir_table_offset = iat_size;
21182638 var lookup_table_offset = dir_table_offset + dir_table_size;
21192639 var names_table_offset = lookup_table_offset + lookup_table_size;
21202640 var dll_names_offset = names_table_offset + names_table_size;
2121 for (self.import_tables.keys(), 0..) |off, i| {
2122 const lib_name = self.temp_strtab.getAssumeExists(off);
2123 const itable = self.import_tables.values()[i];
2641 for (coff.import_tables.keys(), 0..) |off, i| {
2642 const lib_name = coff.temp_strtab.getAssumeExists(off);
2643 const itable = coff.import_tables.values()[i];
21242644
21252645 // Lookup table header
2126 const lookup_header = coff.ImportDirectoryEntry{
2646 const lookup_header = coff_util.ImportDirectoryEntry{
21272647 .import_lookup_table_rva = header.virtual_address + lookup_table_offset,
21282648 .time_date_stamp = 0,
21292649 .forwarder_chain = 0,
21302650 .name_rva = header.virtual_address + dll_names_offset,
21312651 .import_address_table_rva = header.virtual_address + iat_offset,
21322652 };
2133 @memcpy(buffer.items[dir_table_offset..][0..@sizeOf(coff.ImportDirectoryEntry)], mem.asBytes(&lookup_header));
2653 @memcpy(buffer.items[dir_table_offset..][0..@sizeOf(coff_util.ImportDirectoryEntry)], mem.asBytes(&lookup_header));
21342654 dir_table_offset += dir_header_size;
21352655
21362656 for (itable.entries.items) |entry| {
2137 const import_name = self.getSymbolName(entry);
2657 const import_name = coff.getSymbolName(entry);
21382658
21392659 // IAT and lookup table entry
2140 const lookup = coff.ImportLookupEntry64.ByName{ .name_table_rva = @as(u31, @intCast(header.virtual_address + names_table_offset)) };
2660 const lookup = coff_util.ImportLookupEntry64.ByName{ .name_table_rva = @as(u31, @intCast(header.virtual_address + names_table_offset)) };
21412661 @memcpy(
2142 buffer.items[iat_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)],
2662 buffer.items[iat_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)],
21432663 mem.asBytes(&lookup),
21442664 );
21452665 iat_offset += lookup_entry_size;
21462666 @memcpy(
2147 buffer.items[lookup_table_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)],
2667 buffer.items[lookup_table_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)],
21482668 mem.asBytes(&lookup),
21492669 );
21502670 lookup_table_offset += lookup_entry_size;
......@@ -2168,8 +2688,8 @@ fn writeImportTables(self: *Coff) !void {
21682688
21692689 // Lookup table sentinel
21702690 @memcpy(
2171 buffer.items[lookup_table_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)],
2172 mem.asBytes(&coff.ImportLookupEntry64.ByName{ .name_table_rva = 0 }),
2691 buffer.items[lookup_table_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)],
2692 mem.asBytes(&coff_util.ImportLookupEntry64.ByName{ .name_table_rva = 0 }),
21732693 );
21742694 lookup_table_offset += lookup_entry_size;
21752695
......@@ -2183,7 +2703,7 @@ fn writeImportTables(self: *Coff) !void {
21832703 }
21842704
21852705 // Sentinel
2186 const lookup_header = coff.ImportDirectoryEntry{
2706 const lookup_header = coff_util.ImportDirectoryEntry{
21872707 .import_lookup_table_rva = 0,
21882708 .time_date_stamp = 0,
21892709 .forwarder_chain = 0,
......@@ -2191,93 +2711,93 @@ fn writeImportTables(self: *Coff) !void {
21912711 .import_address_table_rva = 0,
21922712 };
21932713 @memcpy(
2194 buffer.items[dir_table_offset..][0..@sizeOf(coff.ImportDirectoryEntry)],
2714 buffer.items[dir_table_offset..][0..@sizeOf(coff_util.ImportDirectoryEntry)],
21952715 mem.asBytes(&lookup_header),
21962716 );
21972717 dir_table_offset += dir_header_size;
21982718
21992719 assert(dll_names_offset == needed_size);
22002720
2201 try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);
2721 try coff.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);
22022722
2203 self.data_directories[@intFromEnum(coff.DirectoryEntry.IMPORT)] = .{
2723 coff.data_directories[@intFromEnum(coff_util.DirectoryEntry.IMPORT)] = .{
22042724 .virtual_address = header.virtual_address + iat_size,
22052725 .size = dir_table_size,
22062726 };
2207 self.data_directories[@intFromEnum(coff.DirectoryEntry.IAT)] = .{
2727 coff.data_directories[@intFromEnum(coff_util.DirectoryEntry.IAT)] = .{
22082728 .virtual_address = header.virtual_address,
22092729 .size = iat_size,
22102730 };
22112731
2212 self.imports_count_dirty = false;
2732 coff.imports_count_dirty = false;
22132733}
22142734
2215fn writeStrtab(self: *Coff) !void {
2216 if (self.strtab_offset == null) return;
2735fn writeStrtab(coff: *Coff) !void {
2736 if (coff.strtab_offset == null) return;
22172737
2218 const allocated_size = self.allocatedSize(self.strtab_offset.?);
2219 const needed_size = @as(u32, @intCast(self.strtab.buffer.items.len));
2738 const allocated_size = coff.allocatedSize(coff.strtab_offset.?);
2739 const needed_size = @as(u32, @intCast(coff.strtab.buffer.items.len));
22202740
22212741 if (needed_size > allocated_size) {
2222 self.strtab_offset = null;
2223 self.strtab_offset = @as(u32, @intCast(self.findFreeSpace(needed_size, @alignOf(u32))));
2742 coff.strtab_offset = null;
2743 coff.strtab_offset = @as(u32, @intCast(coff.findFreeSpace(needed_size, @alignOf(u32))));
22242744 }
22252745
2226 log.debug("writing strtab from 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + needed_size });
2746 log.debug("writing strtab from 0x{x} to 0x{x}", .{ coff.strtab_offset.?, coff.strtab_offset.? + needed_size });
22272747
2228 const gpa = self.base.comp.gpa;
2748 const gpa = coff.base.comp.gpa;
22292749 var buffer = std.ArrayList(u8).init(gpa);
22302750 defer buffer.deinit();
22312751 try buffer.ensureTotalCapacityPrecise(needed_size);
2232 buffer.appendSliceAssumeCapacity(self.strtab.buffer.items);
2752 buffer.appendSliceAssumeCapacity(coff.strtab.buffer.items);
22332753 // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead
22342754 // we write the length of the strtab to a temporary buffer that goes to file.
2235 mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(self.strtab.buffer.items.len)), .little);
2755 mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(coff.strtab.buffer.items.len)), .little);
22362756
2237 try self.base.file.?.pwriteAll(buffer.items, self.strtab_offset.?);
2757 try coff.base.file.?.pwriteAll(buffer.items, coff.strtab_offset.?);
22382758}
22392759
2240fn writeSectionHeaders(self: *Coff) !void {
2241 const offset = self.getSectionHeadersOffset();
2242 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items(.header)), offset);
2760fn writeSectionHeaders(coff: *Coff) !void {
2761 const offset = coff.getSectionHeadersOffset();
2762 try coff.base.file.?.pwriteAll(mem.sliceAsBytes(coff.sections.items(.header)), offset);
22432763}
22442764
2245fn writeDataDirectoriesHeaders(self: *Coff) !void {
2246 const offset = self.getDataDirectoryHeadersOffset();
2247 try self.base.file.?.pwriteAll(mem.sliceAsBytes(&self.data_directories), offset);
2765fn writeDataDirectoriesHeaders(coff: *Coff) !void {
2766 const offset = coff.getDataDirectoryHeadersOffset();
2767 try coff.base.file.?.pwriteAll(mem.sliceAsBytes(&coff.data_directories), offset);
22482768}
22492769
2250fn writeHeader(self: *Coff) !void {
2251 const target = self.base.comp.root_mod.resolved_target.result;
2252 const gpa = self.base.comp.gpa;
2770fn writeHeader(coff: *Coff) !void {
2771 const target = coff.base.comp.root_mod.resolved_target.result;
2772 const gpa = coff.base.comp.gpa;
22532773 var buffer = std.ArrayList(u8).init(gpa);
22542774 defer buffer.deinit();
22552775 const writer = buffer.writer();
22562776
2257 try buffer.ensureTotalCapacity(self.getSizeOfHeaders());
2777 try buffer.ensureTotalCapacity(coff.getSizeOfHeaders());
22582778 writer.writeAll(msdos_stub) catch unreachable;
22592779 mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little);
22602780
22612781 writer.writeAll("PE\x00\x00") catch unreachable;
2262 var flags = coff.CoffHeaderFlags{
2782 var flags = coff_util.CoffHeaderFlags{
22632783 .EXECUTABLE_IMAGE = 1,
22642784 .DEBUG_STRIPPED = 1, // TODO
22652785 };
2266 switch (self.ptr_width) {
2786 switch (coff.ptr_width) {
22672787 .p32 => flags.@"32BIT_MACHINE" = 1,
22682788 .p64 => flags.LARGE_ADDRESS_AWARE = 1,
22692789 }
2270 if (self.base.comp.config.output_mode == .Lib and self.base.comp.config.link_mode == .dynamic) {
2790 if (coff.base.comp.config.output_mode == .Lib and coff.base.comp.config.link_mode == .dynamic) {
22712791 flags.DLL = 1;
22722792 }
22732793
2274 const timestamp = if (self.repro) 0 else std.time.timestamp();
2275 const size_of_optional_header = @as(u16, @intCast(self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize()));
2276 var coff_header = coff.CoffHeader{
2794 const timestamp = if (coff.repro) 0 else std.time.timestamp();
2795 const size_of_optional_header = @as(u16, @intCast(coff.getOptionalHeaderSize() + coff.getDataDirectoryHeadersSize()));
2796 var coff_header = coff_util.CoffHeader{
22772797 .machine = target.toCoffMachine(),
2278 .number_of_sections = @as(u16, @intCast(self.sections.slice().len)), // TODO what if we prune a section
2798 .number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section
22792799 .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))),
2280 .pointer_to_symbol_table = self.strtab_offset orelse 0,
2800 .pointer_to_symbol_table = coff.strtab_offset orelse 0,
22812801 .number_of_symbols = 0,
22822802 .size_of_optional_header = size_of_optional_header,
22832803 .flags = flags,
......@@ -2285,22 +2805,22 @@ fn writeHeader(self: *Coff) !void {
22852805
22862806 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
22872807
2288 const dll_flags: coff.DllFlags = .{
2808 const dll_flags: coff_util.DllFlags = .{
22892809 .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all?
22902810 .DYNAMIC_BASE = 1,
22912811 .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app
22922812 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention
22932813 };
2294 const subsystem: coff.Subsystem = .WINDOWS_CUI;
2295 const size_of_image: u32 = self.getSizeOfImage();
2296 const size_of_headers: u32 = mem.alignForward(u32, self.getSizeOfHeaders(), default_file_alignment);
2297 const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address;
2298 const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address;
2814 const subsystem: coff_util.Subsystem = .WINDOWS_CUI;
2815 const size_of_image: u32 = coff.getSizeOfImage();
2816 const size_of_headers: u32 = mem.alignForward(u32, coff.getSizeOfHeaders(), default_file_alignment);
2817 const base_of_code = coff.sections.get(coff.text_section_index.?).header.virtual_address;
2818 const base_of_data = coff.sections.get(coff.data_section_index.?).header.virtual_address;
22992819
23002820 var size_of_code: u32 = 0;
23012821 var size_of_initialized_data: u32 = 0;
23022822 var size_of_uninitialized_data: u32 = 0;
2303 for (self.sections.items(.header)) |header| {
2823 for (coff.sections.items(.header)) |header| {
23042824 if (header.flags.CNT_CODE == 1) {
23052825 size_of_code += header.size_of_raw_data;
23062826 }
......@@ -2312,27 +2832,27 @@ fn writeHeader(self: *Coff) !void {
23122832 }
23132833 }
23142834
2315 switch (self.ptr_width) {
2835 switch (coff.ptr_width) {
23162836 .p32 => {
2317 var opt_header = coff.OptionalHeaderPE32{
2318 .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC,
2837 var opt_header = coff_util.OptionalHeaderPE32{
2838 .magic = coff_util.IMAGE_NT_OPTIONAL_HDR32_MAGIC,
23192839 .major_linker_version = 0,
23202840 .minor_linker_version = 0,
23212841 .size_of_code = size_of_code,
23222842 .size_of_initialized_data = size_of_initialized_data,
23232843 .size_of_uninitialized_data = size_of_uninitialized_data,
2324 .address_of_entry_point = self.entry_addr orelse 0,
2844 .address_of_entry_point = coff.entry_addr orelse 0,
23252845 .base_of_code = base_of_code,
23262846 .base_of_data = base_of_data,
2327 .image_base = @intCast(self.image_base),
2328 .section_alignment = self.page_size,
2847 .image_base = @intCast(coff.image_base),
2848 .section_alignment = coff.page_size,
23292849 .file_alignment = default_file_alignment,
23302850 .major_operating_system_version = 6,
23312851 .minor_operating_system_version = 0,
23322852 .major_image_version = 0,
23332853 .minor_image_version = 0,
2334 .major_subsystem_version = @intCast(self.major_subsystem_version),
2335 .minor_subsystem_version = @intCast(self.minor_subsystem_version),
2854 .major_subsystem_version = @intCast(coff.major_subsystem_version),
2855 .minor_subsystem_version = @intCast(coff.minor_subsystem_version),
23362856 .win32_version_value = 0,
23372857 .size_of_image = size_of_image,
23382858 .size_of_headers = size_of_headers,
......@@ -2344,29 +2864,29 @@ fn writeHeader(self: *Coff) !void {
23442864 .size_of_heap_reserve = default_size_of_heap_reserve,
23452865 .size_of_heap_commit = default_size_of_heap_commit,
23462866 .loader_flags = 0,
2347 .number_of_rva_and_sizes = @intCast(self.data_directories.len),
2867 .number_of_rva_and_sizes = @intCast(coff.data_directories.len),
23482868 };
23492869 writer.writeAll(mem.asBytes(&opt_header)) catch unreachable;
23502870 },
23512871 .p64 => {
2352 var opt_header = coff.OptionalHeaderPE64{
2353 .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC,
2872 var opt_header = coff_util.OptionalHeaderPE64{
2873 .magic = coff_util.IMAGE_NT_OPTIONAL_HDR64_MAGIC,
23542874 .major_linker_version = 0,
23552875 .minor_linker_version = 0,
23562876 .size_of_code = size_of_code,
23572877 .size_of_initialized_data = size_of_initialized_data,
23582878 .size_of_uninitialized_data = size_of_uninitialized_data,
2359 .address_of_entry_point = self.entry_addr orelse 0,
2879 .address_of_entry_point = coff.entry_addr orelse 0,
23602880 .base_of_code = base_of_code,
2361 .image_base = self.image_base,
2362 .section_alignment = self.page_size,
2881 .image_base = coff.image_base,
2882 .section_alignment = coff.page_size,
23632883 .file_alignment = default_file_alignment,
23642884 .major_operating_system_version = 6,
23652885 .minor_operating_system_version = 0,
23662886 .major_image_version = 0,
23672887 .minor_image_version = 0,
2368 .major_subsystem_version = self.major_subsystem_version,
2369 .minor_subsystem_version = self.minor_subsystem_version,
2888 .major_subsystem_version = coff.major_subsystem_version,
2889 .minor_subsystem_version = coff.minor_subsystem_version,
23702890 .win32_version_value = 0,
23712891 .size_of_image = size_of_image,
23722892 .size_of_headers = size_of_headers,
......@@ -2378,28 +2898,28 @@ fn writeHeader(self: *Coff) !void {
23782898 .size_of_heap_reserve = default_size_of_heap_reserve,
23792899 .size_of_heap_commit = default_size_of_heap_commit,
23802900 .loader_flags = 0,
2381 .number_of_rva_and_sizes = @intCast(self.data_directories.len),
2901 .number_of_rva_and_sizes = @intCast(coff.data_directories.len),
23822902 };
23832903 writer.writeAll(mem.asBytes(&opt_header)) catch unreachable;
23842904 },
23852905 }
23862906
2387 try self.base.file.?.pwriteAll(buffer.items, 0);
2907 try coff.base.file.?.pwriteAll(buffer.items, 0);
23882908}
23892909
23902910pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
23912911 return actual_size +| (actual_size / ideal_factor);
23922912}
23932913
2394fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
2395 const headers_size = @max(self.getSizeOfHeaders(), self.page_size);
2914fn detectAllocCollision(coff: *Coff, start: u32, size: u32) ?u32 {
2915 const headers_size = @max(coff.getSizeOfHeaders(), coff.page_size);
23962916 if (start < headers_size)
23972917 return headers_size;
23982918
23992919 const end = start + padToIdeal(size);
24002920
2401 if (self.strtab_offset) |off| {
2402 const tight_size = @as(u32, @intCast(self.strtab.buffer.items.len));
2921 if (coff.strtab_offset) |off| {
2922 const tight_size = @as(u32, @intCast(coff.strtab.buffer.items.len));
24032923 const increased_size = padToIdeal(tight_size);
24042924 const test_end = off + increased_size;
24052925 if (end > off and start < test_end) {
......@@ -2407,7 +2927,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
24072927 }
24082928 }
24092929
2410 for (self.sections.items(.header)) |header| {
2930 for (coff.sections.items(.header)) |header| {
24112931 const tight_size = header.size_of_raw_data;
24122932 const increased_size = padToIdeal(tight_size);
24132933 const test_end = header.pointer_to_raw_data + increased_size;
......@@ -2419,86 +2939,86 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
24192939 return null;
24202940}
24212941
2422fn allocatedSize(self: *Coff, start: u32) u32 {
2942fn allocatedSize(coff: *Coff, start: u32) u32 {
24232943 if (start == 0)
24242944 return 0;
24252945 var min_pos: u32 = std.math.maxInt(u32);
2426 if (self.strtab_offset) |off| {
2946 if (coff.strtab_offset) |off| {
24272947 if (off > start and off < min_pos) min_pos = off;
24282948 }
2429 for (self.sections.items(.header)) |header| {
2949 for (coff.sections.items(.header)) |header| {
24302950 if (header.pointer_to_raw_data <= start) continue;
24312951 if (header.pointer_to_raw_data < min_pos) min_pos = header.pointer_to_raw_data;
24322952 }
24332953 return min_pos - start;
24342954}
24352955
2436fn findFreeSpace(self: *Coff, object_size: u32, min_alignment: u32) u32 {
2956fn findFreeSpace(coff: *Coff, object_size: u32, min_alignment: u32) u32 {
24372957 var start: u32 = 0;
2438 while (self.detectAllocCollision(start, object_size)) |item_end| {
2958 while (coff.detectAllocCollision(start, object_size)) |item_end| {
24392959 start = mem.alignForward(u32, item_end, min_alignment);
24402960 }
24412961 return start;
24422962}
24432963
2444fn allocatedVirtualSize(self: *Coff, start: u32) u32 {
2964fn allocatedVirtualSize(coff: *Coff, start: u32) u32 {
24452965 if (start == 0)
24462966 return 0;
24472967 var min_pos: u32 = std.math.maxInt(u32);
2448 for (self.sections.items(.header)) |header| {
2968 for (coff.sections.items(.header)) |header| {
24492969 if (header.virtual_address <= start) continue;
24502970 if (header.virtual_address < min_pos) min_pos = header.virtual_address;
24512971 }
24522972 return min_pos - start;
24532973}
24542974
2455inline fn getSizeOfHeaders(self: Coff) u32 {
2975fn getSizeOfHeaders(coff: Coff) u32 {
24562976 const msdos_hdr_size = msdos_stub.len + 4;
2457 return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() +
2458 self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize()));
2977 return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize() +
2978 coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize()));
24592979}
24602980
2461inline fn getOptionalHeaderSize(self: Coff) u32 {
2462 return switch (self.ptr_width) {
2463 .p32 => @as(u32, @intCast(@sizeOf(coff.OptionalHeaderPE32))),
2464 .p64 => @as(u32, @intCast(@sizeOf(coff.OptionalHeaderPE64))),
2981fn getOptionalHeaderSize(coff: Coff) u32 {
2982 return switch (coff.ptr_width) {
2983 .p32 => @as(u32, @intCast(@sizeOf(coff_util.OptionalHeaderPE32))),
2984 .p64 => @as(u32, @intCast(@sizeOf(coff_util.OptionalHeaderPE64))),
24652985 };
24662986}
24672987
2468inline fn getDataDirectoryHeadersSize(self: Coff) u32 {
2469 return @as(u32, @intCast(self.data_directories.len * @sizeOf(coff.ImageDataDirectory)));
2988fn getDataDirectoryHeadersSize(coff: Coff) u32 {
2989 return @as(u32, @intCast(coff.data_directories.len * @sizeOf(coff_util.ImageDataDirectory)));
24702990}
24712991
2472inline fn getSectionHeadersSize(self: Coff) u32 {
2473 return @as(u32, @intCast(self.sections.slice().len * @sizeOf(coff.SectionHeader)));
2992fn getSectionHeadersSize(coff: Coff) u32 {
2993 return @as(u32, @intCast(coff.sections.slice().len * @sizeOf(coff_util.SectionHeader)));
24742994}
24752995
2476inline fn getDataDirectoryHeadersOffset(self: Coff) u32 {
2996fn getDataDirectoryHeadersOffset(coff: Coff) u32 {
24772997 const msdos_hdr_size = msdos_stub.len + 4;
2478 return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize()));
2998 return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize()));
24792999}
24803000
2481inline fn getSectionHeadersOffset(self: Coff) u32 {
2482 return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize();
3001fn getSectionHeadersOffset(coff: Coff) u32 {
3002 return coff.getDataDirectoryHeadersOffset() + coff.getDataDirectoryHeadersSize();
24833003}
24843004
2485inline fn getSizeOfImage(self: Coff) u32 {
2486 var image_size: u32 = mem.alignForward(u32, self.getSizeOfHeaders(), self.page_size);
2487 for (self.sections.items(.header)) |header| {
2488 image_size += mem.alignForward(u32, header.virtual_size, self.page_size);
3005fn getSizeOfImage(coff: Coff) u32 {
3006 var image_size: u32 = mem.alignForward(u32, coff.getSizeOfHeaders(), coff.page_size);
3007 for (coff.sections.items(.header)) |header| {
3008 image_size += mem.alignForward(u32, header.virtual_size, coff.page_size);
24893009 }
24903010 return image_size;
24913011}
24923012
24933013/// Returns symbol location corresponding to the set entrypoint (if any).
2494pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
2495 const comp = self.base.comp;
3014pub fn getEntryPoint(coff: Coff) ?SymbolWithLoc {
3015 const comp = coff.base.comp;
24963016
24973017 // TODO This is incomplete.
24983018 // The entry symbol name depends on the subsystem as well as the set of
24993019 // public symbol names from linked objects.
25003020 // See LinkerDriver::findDefaultEntry from the LLD project for the flow chart.
2501 const entry_name = switch (self.entry) {
3021 const entry_name = switch (coff.entry) {
25023022 .disabled => return null,
25033023 .default => switch (comp.config.output_mode) {
25043024 .Exe => "wWinMainCRTStartup",
......@@ -2507,51 +3027,51 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
25073027 .enabled => "wWinMainCRTStartup",
25083028 .named => |name| name,
25093029 };
2510 const global_index = self.resolver.get(entry_name) orelse return null;
2511 return self.globals.items[global_index];
3030 const global_index = coff.resolver.get(entry_name) orelse return null;
3031 return coff.globals.items[global_index];
25123032}
25133033
25143034/// Returns pointer-to-symbol described by `sym_loc` descriptor.
2515pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol {
3035pub fn getSymbolPtr(coff: *Coff, sym_loc: SymbolWithLoc) *coff_util.Symbol {
25163036 assert(sym_loc.file == null); // TODO linking object files
2517 return &self.locals.items[sym_loc.sym_index];
3037 return &coff.locals.items[sym_loc.sym_index];
25183038}
25193039
25203040/// Returns symbol described by `sym_loc` descriptor.
2521pub fn getSymbol(self: *const Coff, sym_loc: SymbolWithLoc) *const coff.Symbol {
3041pub fn getSymbol(coff: *const Coff, sym_loc: SymbolWithLoc) *const coff_util.Symbol {
25223042 assert(sym_loc.file == null); // TODO linking object files
2523 return &self.locals.items[sym_loc.sym_index];
3043 return &coff.locals.items[sym_loc.sym_index];
25243044}
25253045
25263046/// Returns name of the symbol described by `sym_loc` descriptor.
2527pub fn getSymbolName(self: *const Coff, sym_loc: SymbolWithLoc) []const u8 {
3047pub fn getSymbolName(coff: *const Coff, sym_loc: SymbolWithLoc) []const u8 {
25283048 assert(sym_loc.file == null); // TODO linking object files
2529 const sym = self.getSymbol(sym_loc);
3049 const sym = coff.getSymbol(sym_loc);
25303050 const offset = sym.getNameOffset() orelse return sym.getName().?;
2531 return self.strtab.get(offset).?;
3051 return coff.strtab.get(offset).?;
25323052}
25333053
25343054/// Returns pointer to the global entry for `name` if one exists.
2535pub fn getGlobalPtr(self: *Coff, name: []const u8) ?*SymbolWithLoc {
2536 const global_index = self.resolver.get(name) orelse return null;
2537 return &self.globals.items[global_index];
3055pub fn getGlobalPtr(coff: *Coff, name: []const u8) ?*SymbolWithLoc {
3056 const global_index = coff.resolver.get(name) orelse return null;
3057 return &coff.globals.items[global_index];
25383058}
25393059
25403060/// Returns the global entry for `name` if one exists.
2541pub fn getGlobal(self: *const Coff, name: []const u8) ?SymbolWithLoc {
2542 const global_index = self.resolver.get(name) orelse return null;
2543 return self.globals.items[global_index];
3061pub fn getGlobal(coff: *const Coff, name: []const u8) ?SymbolWithLoc {
3062 const global_index = coff.resolver.get(name) orelse return null;
3063 return coff.globals.items[global_index];
25443064}
25453065
25463066/// Returns the index of the global entry for `name` if one exists.
2547pub fn getGlobalIndex(self: *const Coff, name: []const u8) ?u32 {
2548 return self.resolver.get(name);
3067pub fn getGlobalIndex(coff: *const Coff, name: []const u8) ?u32 {
3068 return coff.resolver.get(name);
25493069}
25503070
25513071/// Returns global entry at `index`.
2552pub fn getGlobalByIndex(self: *const Coff, index: u32) SymbolWithLoc {
2553 assert(index < self.globals.items.len);
2554 return self.globals.items[index];
3072pub fn getGlobalByIndex(coff: *const Coff, index: u32) SymbolWithLoc {
3073 assert(index < coff.globals.items.len);
3074 return coff.globals.items[index];
25553075}
25563076
25573077const GetOrPutGlobalPtrResult = struct {
......@@ -2567,68 +3087,68 @@ pub const global_symbol_mask: u32 = 0x7fffffff;
25673087/// Return pointer to the global entry for `name` if one exists.
25683088/// Puts a new global entry for `name` if one doesn't exist, and
25693089/// returns a pointer to it.
2570pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult {
2571 if (self.getGlobalPtr(name)) |ptr| {
3090pub fn getOrPutGlobalPtr(coff: *Coff, name: []const u8) !GetOrPutGlobalPtrResult {
3091 if (coff.getGlobalPtr(name)) |ptr| {
25723092 return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr };
25733093 }
2574 const gpa = self.base.comp.gpa;
2575 const global_index = try self.allocateGlobal();
3094 const gpa = coff.base.comp.gpa;
3095 const global_index = try coff.allocateGlobal();
25763096 const global_name = try gpa.dupe(u8, name);
2577 _ = try self.resolver.put(gpa, global_name, global_index);
2578 const ptr = &self.globals.items[global_index];
3097 _ = try coff.resolver.put(gpa, global_name, global_index);
3098 const ptr = &coff.globals.items[global_index];
25793099 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
25803100}
25813101
2582pub fn getAtom(self: *const Coff, atom_index: Atom.Index) Atom {
2583 assert(atom_index < self.atoms.items.len);
2584 return self.atoms.items[atom_index];
3102pub fn getAtom(coff: *const Coff, atom_index: Atom.Index) Atom {
3103 assert(atom_index < coff.atoms.items.len);
3104 return coff.atoms.items[atom_index];
25853105}
25863106
2587pub fn getAtomPtr(self: *Coff, atom_index: Atom.Index) *Atom {
2588 assert(atom_index < self.atoms.items.len);
2589 return &self.atoms.items[atom_index];
3107pub fn getAtomPtr(coff: *Coff, atom_index: Atom.Index) *Atom {
3108 assert(atom_index < coff.atoms.items.len);
3109 return &coff.atoms.items[atom_index];
25903110}
25913111
25923112/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.
25933113/// Returns null on failure.
2594pub fn getAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
3114pub fn getAtomIndexForSymbol(coff: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
25953115 assert(sym_loc.file == null); // TODO linking with object files
2596 return self.atom_by_index_table.get(sym_loc.sym_index);
3116 return coff.atom_by_index_table.get(sym_loc.sym_index);
25973117}
25983118
2599fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {
3119fn setSectionName(coff: *Coff, header: *coff_util.SectionHeader, name: []const u8) !void {
26003120 if (name.len <= 8) {
26013121 @memcpy(header.name[0..name.len], name);
26023122 @memset(header.name[name.len..], 0);
26033123 return;
26043124 }
2605 const gpa = self.base.comp.gpa;
2606 const offset = try self.strtab.insert(gpa, name);
3125 const gpa = coff.base.comp.gpa;
3126 const offset = try coff.strtab.insert(gpa, name);
26073127 const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable;
26083128 @memset(header.name[name_offset.len..], 0);
26093129}
26103130
2611fn getSectionName(self: *const Coff, header: *const coff.SectionHeader) []const u8 {
3131fn getSectionName(coff: *const Coff, header: *const coff_util.SectionHeader) []const u8 {
26123132 if (header.getName()) |name| {
26133133 return name;
26143134 }
26153135 const offset = header.getNameOffset().?;
2616 return self.strtab.get(offset).?;
3136 return coff.strtab.get(offset).?;
26173137}
26183138
2619fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {
3139fn setSymbolName(coff: *Coff, symbol: *coff_util.Symbol, name: []const u8) !void {
26203140 if (name.len <= 8) {
26213141 @memcpy(symbol.name[0..name.len], name);
26223142 @memset(symbol.name[name.len..], 0);
26233143 return;
26243144 }
2625 const gpa = self.base.comp.gpa;
2626 const offset = try self.strtab.insert(gpa, name);
3145 const gpa = coff.base.comp.gpa;
3146 const offset = try coff.strtab.insert(gpa, name);
26273147 @memset(symbol.name[0..4], 0);
26283148 mem.writeInt(u32, symbol.name[4..8], offset, .little);
26293149}
26303150
2631fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 {
3151fn logSymAttributes(sym: *const coff_util.Symbol, buf: *[4]u8) []const u8 {
26323152 @memset(buf[0..4], '_');
26333153 switch (sym.section_number) {
26343154 .UNDEFINED => {
......@@ -2655,12 +3175,12 @@ fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 {
26553175 return buf[0..];
26563176}
26573177
2658fn logSymtab(self: *Coff) void {
3178fn logSymtab(coff: *Coff) void {
26593179 var buf: [4]u8 = undefined;
26603180
26613181 log.debug("symtab:", .{});
26623182 log.debug(" object(null)", .{});
2663 for (self.locals.items, 0..) |*sym, sym_id| {
3183 for (coff.locals.items, 0..) |*sym, sym_id| {
26643184 const where = if (sym.section_number == .UNDEFINED) "ord" else "sect";
26653185 const def_index: u16 = switch (sym.section_number) {
26663186 .UNDEFINED => 0, // TODO
......@@ -2670,7 +3190,7 @@ fn logSymtab(self: *Coff) void {
26703190 };
26713191 log.debug(" %{d}: {?s} @{x} in {s}({d}), {s}", .{
26723192 sym_id,
2673 self.getSymbolName(.{ .sym_index = @as(u32, @intCast(sym_id)), .file = null }),
3193 coff.getSymbolName(.{ .sym_index = @as(u32, @intCast(sym_id)), .file = null }),
26743194 sym.value,
26753195 where,
26763196 def_index,
......@@ -2679,20 +3199,20 @@ fn logSymtab(self: *Coff) void {
26793199 }
26803200
26813201 log.debug("globals table:", .{});
2682 for (self.globals.items) |sym_loc| {
2683 const sym_name = self.getSymbolName(sym_loc);
3202 for (coff.globals.items) |sym_loc| {
3203 const sym_name = coff.getSymbolName(sym_loc);
26843204 log.debug(" {s} => %{d} in object({?d})", .{ sym_name, sym_loc.sym_index, sym_loc.file });
26853205 }
26863206
26873207 log.debug("GOT entries:", .{});
2688 log.debug("{}", .{self.got_table});
3208 log.debug("{}", .{coff.got_table});
26893209}
26903210
2691fn logSections(self: *Coff) void {
3211fn logSections(coff: *Coff) void {
26923212 log.debug("sections:", .{});
2693 for (self.sections.items(.header)) |*header| {
3213 for (coff.sections.items(.header)) |*header| {
26943214 log.debug(" {s}: VM({x}, {x}) FILE({x}, {x})", .{
2695 self.getSectionName(header),
3215 coff.getSectionName(header),
26963216 header.virtual_address,
26973217 header.virtual_address + header.virtual_size,
26983218 header.pointer_to_raw_data,
......@@ -2701,26 +3221,495 @@ fn logSections(self: *Coff) void {
27013221 }
27023222}
27033223
2704fn logImportTables(self: *const Coff) void {
3224fn logImportTables(coff: *const Coff) void {
27053225 log.debug("import tables:", .{});
2706 for (self.import_tables.keys(), 0..) |off, i| {
2707 const itable = self.import_tables.values()[i];
3226 for (coff.import_tables.keys(), 0..) |off, i| {
3227 const itable = coff.import_tables.values()[i];
27083228 log.debug("{}", .{itable.fmtDebug(.{
2709 .coff_file = self,
3229 .coff = coff,
27103230 .index = i,
27113231 .name_off = off,
27123232 })});
27133233 }
27143234}
27153235
3236pub const Atom = struct {
3237 /// Each decl always gets a local symbol with the fully qualified name.
3238 /// The vaddr and size are found here directly.
3239 /// The file offset is found by computing the vaddr offset from the section vaddr
3240 /// the symbol references, and adding that to the file offset of the section.
3241 /// If this field is 0, it means the codegen size = 0 and there is no symbol or
3242 /// offset table entry.
3243 sym_index: u32,
3244
3245 /// null means symbol defined by Zig source.
3246 file: ?u32,
3247
3248 /// Size of the atom
3249 size: u32,
3250
3251 /// Points to the previous and next neighbors, based on the `text_offset`.
3252 /// This can be used to find, for example, the capacity of this `Atom`.
3253 prev_index: ?Index,
3254 next_index: ?Index,
3255
3256 const Index = u32;
3257
3258 pub fn getSymbolIndex(atom: Atom) ?u32 {
3259 if (atom.sym_index == 0) return null;
3260 return atom.sym_index;
3261 }
3262
3263 /// Returns symbol referencing this atom.
3264 fn getSymbol(atom: Atom, coff: *const Coff) *const coff_util.Symbol {
3265 const sym_index = atom.getSymbolIndex().?;
3266 return coff.getSymbol(.{
3267 .sym_index = sym_index,
3268 .file = atom.file,
3269 });
3270 }
3271
3272 /// Returns pointer-to-symbol referencing this atom.
3273 fn getSymbolPtr(atom: Atom, coff: *Coff) *coff_util.Symbol {
3274 const sym_index = atom.getSymbolIndex().?;
3275 return coff.getSymbolPtr(.{
3276 .sym_index = sym_index,
3277 .file = atom.file,
3278 });
3279 }
3280
3281 fn getSymbolWithLoc(atom: Atom) SymbolWithLoc {
3282 const sym_index = atom.getSymbolIndex().?;
3283 return .{ .sym_index = sym_index, .file = atom.file };
3284 }
3285
3286 /// Returns the name of this atom.
3287 fn getName(atom: Atom, coff: *const Coff) []const u8 {
3288 const sym_index = atom.getSymbolIndex().?;
3289 return coff.getSymbolName(.{
3290 .sym_index = sym_index,
3291 .file = atom.file,
3292 });
3293 }
3294
3295 /// Returns how much room there is to grow in virtual address space.
3296 fn capacity(atom: Atom, coff: *const Coff) u32 {
3297 const atom_sym = atom.getSymbol(coff);
3298 if (atom.next_index) |next_index| {
3299 const next = coff.getAtom(next_index);
3300 const next_sym = next.getSymbol(coff);
3301 return next_sym.value - atom_sym.value;
3302 } else {
3303 // We are the last atom.
3304 // The capacity is limited only by virtual address space.
3305 return std.math.maxInt(u32) - atom_sym.value;
3306 }
3307 }
3308
3309 fn freeListEligible(atom: Atom, coff: *const Coff) bool {
3310 // No need to keep a free list node for the last atom.
3311 const next_index = atom.next_index orelse return false;
3312 const next = coff.getAtom(next_index);
3313 const atom_sym = atom.getSymbol(coff);
3314 const next_sym = next.getSymbol(coff);
3315 const cap = next_sym.value - atom_sym.value;
3316 const ideal_cap = padToIdeal(atom.size);
3317 if (cap <= ideal_cap) return false;
3318 const surplus = cap - ideal_cap;
3319 return surplus >= min_text_capacity;
3320 }
3321};
3322
3323pub const Relocation = struct {
3324 type: enum {
3325 // x86, x86_64
3326 /// RIP-relative displacement to a GOT pointer
3327 got,
3328 /// RIP-relative displacement to an import pointer
3329 import,
3330
3331 // aarch64
3332 /// PC-relative distance to target page in GOT section
3333 got_page,
3334 /// Offset to a GOT pointer relative to the start of a page in GOT section
3335 got_pageoff,
3336 /// PC-relative distance to target page in a section (e.g., .rdata)
3337 page,
3338 /// Offset to a pointer relative to the start of a page in a section (e.g., .rdata)
3339 pageoff,
3340 /// PC-relative distance to target page in a import section
3341 import_page,
3342 /// Offset to a pointer relative to the start of a page in an import section (e.g., .rdata)
3343 import_pageoff,
3344
3345 // common
3346 /// Absolute pointer value
3347 direct,
3348 },
3349 target: SymbolWithLoc,
3350 offset: u32,
3351 addend: u32,
3352 pcrel: bool,
3353 length: u2,
3354 dirty: bool = true,
3355
3356 /// Returns true if and only if the reloc can be resolved.
3357 fn isResolvable(reloc: Relocation, coff: *Coff) bool {
3358 _ = reloc.getTargetAddress(coff) orelse return false;
3359 return true;
3360 }
3361
3362 fn isGotIndirection(reloc: Relocation) bool {
3363 return switch (reloc.type) {
3364 .got, .got_page, .got_pageoff => true,
3365 else => false,
3366 };
3367 }
3368
3369 /// Returns address of the target if any.
3370 fn getTargetAddress(reloc: Relocation, coff: *const Coff) ?u32 {
3371 switch (reloc.type) {
3372 .got, .got_page, .got_pageoff => {
3373 const got_index = coff.got_table.lookup.get(reloc.target) orelse return null;
3374 const header = coff.sections.items(.header)[coff.got_section_index.?];
3375 return header.virtual_address + got_index * coff.ptr_width.size();
3376 },
3377 .import, .import_page, .import_pageoff => {
3378 const sym = coff.getSymbol(reloc.target);
3379 const index = coff.import_tables.getIndex(sym.value) orelse return null;
3380 const itab = coff.import_tables.values()[index];
3381 return itab.getImportAddress(reloc.target, .{
3382 .coff = coff,
3383 .index = index,
3384 .name_off = sym.value,
3385 });
3386 },
3387 else => {
3388 const target_atom_index = coff.getAtomIndexForSymbol(reloc.target) orelse return null;
3389 const target_atom = coff.getAtom(target_atom_index);
3390 return target_atom.getSymbol(coff).value;
3391 },
3392 }
3393 }
3394
3395 fn resolve(reloc: Relocation, atom_index: Atom.Index, code: []u8, image_base: u64, coff: *Coff) void {
3396 const atom = coff.getAtom(atom_index);
3397 const source_sym = atom.getSymbol(coff);
3398 const source_vaddr = source_sym.value + reloc.offset;
3399
3400 const target_vaddr = reloc.getTargetAddress(coff).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().
3401 const target_vaddr_with_addend = target_vaddr + reloc.addend;
3402
3403 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) ", .{
3404 source_vaddr,
3405 target_vaddr_with_addend,
3406 coff.getSymbolName(reloc.target),
3407 @tagName(reloc.type),
3408 });
3409
3410 const ctx: Context = .{
3411 .source_vaddr = source_vaddr,
3412 .target_vaddr = target_vaddr_with_addend,
3413 .image_base = image_base,
3414 .code = code,
3415 .ptr_width = coff.ptr_width,
3416 };
3417
3418 const target = coff.base.comp.root_mod.resolved_target.result;
3419 switch (target.cpu.arch) {
3420 .aarch64 => reloc.resolveAarch64(ctx),
3421 .x86, .x86_64 => reloc.resolveX86(ctx),
3422 else => unreachable, // unhandled target architecture
3423 }
3424 }
3425
3426 const Context = struct {
3427 source_vaddr: u32,
3428 target_vaddr: u32,
3429 image_base: u64,
3430 code: []u8,
3431 ptr_width: PtrWidth,
3432 };
3433
3434 fn resolveAarch64(reloc: Relocation, ctx: Context) void {
3435 var buffer = ctx.code[reloc.offset..];
3436 switch (reloc.type) {
3437 .got_page, .import_page, .page => {
3438 const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12));
3439 const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12));
3440 const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page))));
3441 var inst = aarch64_util.Instruction{
3442 .pc_relative_address = mem.bytesToValue(std.meta.TagPayload(
3443 aarch64_util.Instruction,
3444 aarch64_util.Instruction.pc_relative_address,
3445 ), buffer[0..4]),
3446 };
3447 inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
3448 inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
3449 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
3450 },
3451 .got_pageoff, .import_pageoff, .pageoff => {
3452 assert(!reloc.pcrel);
3453
3454 const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr))));
3455 if (isArithmeticOp(buffer[0..4])) {
3456 var inst = aarch64_util.Instruction{
3457 .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
3458 aarch64_util.Instruction,
3459 aarch64_util.Instruction.add_subtract_immediate,
3460 ), buffer[0..4]),
3461 };
3462 inst.add_subtract_immediate.imm12 = narrowed;
3463 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
3464 } else {
3465 var inst = aarch64_util.Instruction{
3466 .load_store_register = mem.bytesToValue(std.meta.TagPayload(
3467 aarch64_util.Instruction,
3468 aarch64_util.Instruction.load_store_register,
3469 ), buffer[0..4]),
3470 };
3471 const offset: u12 = blk: {
3472 if (inst.load_store_register.size == 0) {
3473 if (inst.load_store_register.v == 1) {
3474 // 128-bit SIMD is scaled by 16.
3475 break :blk @divExact(narrowed, 16);
3476 }
3477 // Otherwise, 8-bit SIMD or ldrb.
3478 break :blk narrowed;
3479 } else {
3480 const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable;
3481 break :blk @divExact(narrowed, denom);
3482 }
3483 };
3484 inst.load_store_register.offset = offset;
3485 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
3486 }
3487 },
3488 .direct => {
3489 assert(!reloc.pcrel);
3490 switch (reloc.length) {
3491 2 => mem.writeInt(
3492 u32,
3493 buffer[0..4],
3494 @as(u32, @truncate(ctx.target_vaddr + ctx.image_base)),
3495 .little,
3496 ),
3497 3 => mem.writeInt(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base, .little),
3498 else => unreachable,
3499 }
3500 },
3501
3502 .got => unreachable,
3503 .import => unreachable,
3504 }
3505 }
3506
3507 fn resolveX86(reloc: Relocation, ctx: Context) void {
3508 var buffer = ctx.code[reloc.offset..];
3509 switch (reloc.type) {
3510 .got_page => unreachable,
3511 .got_pageoff => unreachable,
3512 .page => unreachable,
3513 .pageoff => unreachable,
3514 .import_page => unreachable,
3515 .import_pageoff => unreachable,
3516
3517 .got, .import => {
3518 assert(reloc.pcrel);
3519 const disp = @as(i32, @intCast(ctx.target_vaddr)) - @as(i32, @intCast(ctx.source_vaddr)) - 4;
3520 mem.writeInt(i32, buffer[0..4], disp, .little);
3521 },
3522 .direct => {
3523 if (reloc.pcrel) {
3524 const disp = @as(i32, @intCast(ctx.target_vaddr)) - @as(i32, @intCast(ctx.source_vaddr)) - 4;
3525 mem.writeInt(i32, buffer[0..4], disp, .little);
3526 } else switch (ctx.ptr_width) {
3527 .p32 => mem.writeInt(u32, buffer[0..4], @as(u32, @intCast(ctx.target_vaddr + ctx.image_base)), .little),
3528 .p64 => switch (reloc.length) {
3529 2 => mem.writeInt(u32, buffer[0..4], @as(u32, @truncate(ctx.target_vaddr + ctx.image_base)), .little),
3530 3 => mem.writeInt(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base, .little),
3531 else => unreachable,
3532 },
3533 }
3534 },
3535 }
3536 }
3537
3538 fn isArithmeticOp(inst: *const [4]u8) bool {
3539 const group_decode = @as(u5, @truncate(inst[3]));
3540 return ((group_decode >> 2) == 4);
3541 }
3542};
3543
3544pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void {
3545 const comp = coff.base.comp;
3546 const gpa = comp.gpa;
3547 log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.type), reloc.target.sym_index });
3548 const gop = try coff.relocs.getOrPut(gpa, atom_index);
3549 if (!gop.found_existing) {
3550 gop.value_ptr.* = .{};
3551 }
3552 try gop.value_ptr.append(gpa, reloc);
3553}
3554
3555fn addBaseRelocation(coff: *Coff, atom_index: Atom.Index, offset: u32) !void {
3556 const comp = coff.base.comp;
3557 const gpa = comp.gpa;
3558 log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{
3559 offset,
3560 coff.getAtom(atom_index).getSymbolIndex().?,
3561 });
3562 const gop = try coff.base_relocs.getOrPut(gpa, atom_index);
3563 if (!gop.found_existing) {
3564 gop.value_ptr.* = .{};
3565 }
3566 try gop.value_ptr.append(gpa, offset);
3567}
3568
3569fn freeRelocations(coff: *Coff, atom_index: Atom.Index) void {
3570 const comp = coff.base.comp;
3571 const gpa = comp.gpa;
3572 var removed_relocs = coff.relocs.fetchOrderedRemove(atom_index);
3573 if (removed_relocs) |*relocs| relocs.value.deinit(gpa);
3574 var removed_base_relocs = coff.base_relocs.fetchOrderedRemove(atom_index);
3575 if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(gpa);
3576}
3577
3578/// Represents an import table in the .idata section where each contained pointer
3579/// is to a symbol from the same DLL.
3580///
3581/// The layout of .idata section is as follows:
3582///
3583/// --- ADDR1 : IAT (all import tables concatenated together)
3584/// ptr
3585/// ptr
3586/// 0 sentinel
3587/// ptr
3588/// 0 sentinel
3589/// --- ADDR2: headers
3590/// ImportDirectoryEntry header
3591/// ImportDirectoryEntry header
3592/// sentinel
3593/// --- ADDR2: lookup tables
3594/// Lookup table
3595/// 0 sentinel
3596/// Lookup table
3597/// 0 sentinel
3598/// --- ADDR3: name hint tables
3599/// hint-symname
3600/// hint-symname
3601/// --- ADDR4: DLL names
3602/// DLL#1 name
3603/// DLL#2 name
3604/// --- END
3605const ImportTable = struct {
3606 entries: std.ArrayListUnmanaged(SymbolWithLoc) = .empty,
3607 free_list: std.ArrayListUnmanaged(u32) = .empty,
3608 lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .empty,
3609
3610 fn deinit(itab: *ImportTable, allocator: Allocator) void {
3611 itab.entries.deinit(allocator);
3612 itab.free_list.deinit(allocator);
3613 itab.lookup.deinit(allocator);
3614 }
3615
3616 /// Size of the import table does not include the sentinel.
3617 fn size(itab: ImportTable) u32 {
3618 return @as(u32, @intCast(itab.entries.items.len)) * @sizeOf(u64);
3619 }
3620
3621 fn addImport(itab: *ImportTable, allocator: Allocator, target: SymbolWithLoc) !ImportIndex {
3622 try itab.entries.ensureUnusedCapacity(allocator, 1);
3623 const index: u32 = blk: {
3624 if (itab.free_list.popOrNull()) |index| {
3625 log.debug(" (reusing import entry index {d})", .{index});
3626 break :blk index;
3627 } else {
3628 log.debug(" (allocating import entry at index {d})", .{itab.entries.items.len});
3629 const index = @as(u32, @intCast(itab.entries.items.len));
3630 _ = itab.entries.addOneAssumeCapacity();
3631 break :blk index;
3632 }
3633 };
3634 itab.entries.items[index] = target;
3635 try itab.lookup.putNoClobber(allocator, target, index);
3636 return index;
3637 }
3638
3639 const Context = struct {
3640 coff: *const Coff,
3641 /// Index of this ImportTable in a global list of all tables.
3642 /// This is required in order to calculate the base vaddr of this ImportTable.
3643 index: usize,
3644 /// Offset into the string interning table of the DLL this ImportTable corresponds to.
3645 name_off: u32,
3646 };
3647
3648 fn getBaseAddress(ctx: Context) u32 {
3649 const header = ctx.coff.sections.items(.header)[ctx.coff.idata_section_index.?];
3650 var addr = header.virtual_address;
3651 for (ctx.coff.import_tables.values(), 0..) |other_itab, i| {
3652 if (ctx.index == i) break;
3653 addr += @as(u32, @intCast(other_itab.entries.items.len * @sizeOf(u64))) + 8;
3654 }
3655 return addr;
3656 }
3657
3658 fn getImportAddress(itab: *const ImportTable, target: SymbolWithLoc, ctx: Context) ?u32 {
3659 const index = itab.lookup.get(target) orelse return null;
3660 const base_vaddr = getBaseAddress(ctx);
3661 return base_vaddr + index * @sizeOf(u64);
3662 }
3663
3664 const FormatContext = struct {
3665 itab: ImportTable,
3666 ctx: Context,
3667 };
3668
3669 fn format(itab: ImportTable, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
3670 _ = itab;
3671 _ = unused_format_string;
3672 _ = options;
3673 _ = writer;
3674 @compileError("do not format ImportTable directly; use itab.fmtDebug()");
3675 }
3676
3677 fn format2(
3678 fmt_ctx: FormatContext,
3679 comptime unused_format_string: []const u8,
3680 options: fmt.FormatOptions,
3681 writer: anytype,
3682 ) @TypeOf(writer).Error!void {
3683 _ = options;
3684 comptime assert(unused_format_string.len == 0);
3685 const lib_name = fmt_ctx.ctx.coff.temp_strtab.getAssumeExists(fmt_ctx.ctx.name_off);
3686 const base_vaddr = getBaseAddress(fmt_ctx.ctx);
3687 try writer.print("IAT({s}.dll) @{x}:", .{ lib_name, base_vaddr });
3688 for (fmt_ctx.itab.entries.items, 0..) |entry, i| {
3689 try writer.print("\n {d}@{?x} => {s}", .{
3690 i,
3691 fmt_ctx.itab.getImportAddress(entry, fmt_ctx.ctx),
3692 fmt_ctx.ctx.coff.getSymbolName(entry),
3693 });
3694 }
3695 }
3696
3697 fn fmtDebug(itab: ImportTable, ctx: Context) fmt.Formatter(format2) {
3698 return .{ .data = .{ .itab = itab, .ctx = ctx } };
3699 }
3700
3701 const ImportIndex = u32;
3702};
3703
27163704const Coff = @This();
27173705
27183706const std = @import("std");
27193707const build_options = @import("build_options");
27203708const builtin = @import("builtin");
27213709const assert = std.debug.assert;
2722const coff = std.coff;
3710const coff_util = std.coff;
27233711const fmt = std.fmt;
3712const fs = std.fs;
27243713const log = std.log.scoped(.link);
27253714const math = std.math;
27263715const mem = std.mem;
......@@ -2728,23 +3717,21 @@ const mem = std.mem;
27283717const Allocator = std.mem.Allocator;
27293718const Path = std.Build.Cache.Path;
27303719const Directory = std.Build.Cache.Directory;
3720const Cache = std.Build.Cache;
27313721
3722const aarch64_util = @import("../arch/aarch64/bits.zig");
3723const allocPrint = std.fmt.allocPrint;
27323724const codegen = @import("../codegen.zig");
27333725const link = @import("../link.zig");
2734const lld = @import("Coff/lld.zig");
27353726const target_util = @import("../target.zig");
27363727const trace = @import("../tracy.zig").trace;
27373728
27383729const Air = @import("../Air.zig");
2739pub const Atom = @import("Coff/Atom.zig");
27403730const Compilation = @import("../Compilation.zig");
2741const ImportTable = @import("Coff/ImportTable.zig");
27423731const Liveness = @import("../Liveness.zig");
27433732const LlvmObject = @import("../codegen/llvm.zig").Object;
27443733const Zcu = @import("../Zcu.zig");
27453734const InternPool = @import("../InternPool.zig");
2746const Object = @import("Coff/Object.zig");
2747const Relocation = @import("Coff/Relocation.zig");
27483735const TableSection = @import("table_section.zig").TableSection;
27493736const StringTable = @import("StringTable.zig");
27503737const Type = @import("../Type.zig");
src/link/Coff/Atom.zig deleted-128
......@@ -1,128 +0,0 @@
1const Atom = @This();
2
3const std = @import("std");
4const coff = std.coff;
5const log = std.log.scoped(.link);
6
7const Coff = @import("../Coff.zig");
8const Relocation = @import("Relocation.zig");
9const SymbolWithLoc = Coff.SymbolWithLoc;
10
11/// Each decl always gets a local symbol with the fully qualified name.
12/// The vaddr and size are found here directly.
13/// The file offset is found by computing the vaddr offset from the section vaddr
14/// the symbol references, and adding that to the file offset of the section.
15/// If this field is 0, it means the codegen size = 0 and there is no symbol or
16/// offset table entry.
17sym_index: u32,
18
19/// null means symbol defined by Zig source.
20file: ?u32,
21
22/// Size of the atom
23size: u32,
24
25/// Points to the previous and next neighbors, based on the `text_offset`.
26/// This can be used to find, for example, the capacity of this `Atom`.
27prev_index: ?Index,
28next_index: ?Index,
29
30pub const Index = u32;
31
32pub fn getSymbolIndex(self: Atom) ?u32 {
33 if (self.sym_index == 0) return null;
34 return self.sym_index;
35}
36
37/// Returns symbol referencing this atom.
38pub fn getSymbol(self: Atom, coff_file: *const Coff) *const coff.Symbol {
39 const sym_index = self.getSymbolIndex().?;
40 return coff_file.getSymbol(.{
41 .sym_index = sym_index,
42 .file = self.file,
43 });
44}
45
46/// Returns pointer-to-symbol referencing this atom.
47pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol {
48 const sym_index = self.getSymbolIndex().?;
49 return coff_file.getSymbolPtr(.{
50 .sym_index = sym_index,
51 .file = self.file,
52 });
53}
54
55pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {
56 const sym_index = self.getSymbolIndex().?;
57 return .{ .sym_index = sym_index, .file = self.file };
58}
59
60/// Returns the name of this atom.
61pub fn getName(self: Atom, coff_file: *const Coff) []const u8 {
62 const sym_index = self.getSymbolIndex().?;
63 return coff_file.getSymbolName(.{
64 .sym_index = sym_index,
65 .file = self.file,
66 });
67}
68
69/// Returns how much room there is to grow in virtual address space.
70pub fn capacity(self: Atom, coff_file: *const Coff) u32 {
71 const self_sym = self.getSymbol(coff_file);
72 if (self.next_index) |next_index| {
73 const next = coff_file.getAtom(next_index);
74 const next_sym = next.getSymbol(coff_file);
75 return next_sym.value - self_sym.value;
76 } else {
77 // We are the last atom.
78 // The capacity is limited only by virtual address space.
79 return std.math.maxInt(u32) - self_sym.value;
80 }
81}
82
83pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
84 // No need to keep a free list node for the last atom.
85 const next_index = self.next_index orelse return false;
86 const next = coff_file.getAtom(next_index);
87 const self_sym = self.getSymbol(coff_file);
88 const next_sym = next.getSymbol(coff_file);
89 const cap = next_sym.value - self_sym.value;
90 const ideal_cap = Coff.padToIdeal(self.size);
91 if (cap <= ideal_cap) return false;
92 const surplus = cap - ideal_cap;
93 return surplus >= Coff.min_text_capacity;
94}
95
96pub fn addRelocation(coff_file: *Coff, atom_index: Index, reloc: Relocation) !void {
97 const comp = coff_file.base.comp;
98 const gpa = comp.gpa;
99 log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.type), reloc.target.sym_index });
100 const gop = try coff_file.relocs.getOrPut(gpa, atom_index);
101 if (!gop.found_existing) {
102 gop.value_ptr.* = .{};
103 }
104 try gop.value_ptr.append(gpa, reloc);
105}
106
107pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void {
108 const comp = coff_file.base.comp;
109 const gpa = comp.gpa;
110 log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{
111 offset,
112 coff_file.getAtom(atom_index).getSymbolIndex().?,
113 });
114 const gop = try coff_file.base_relocs.getOrPut(gpa, atom_index);
115 if (!gop.found_existing) {
116 gop.value_ptr.* = .{};
117 }
118 try gop.value_ptr.append(gpa, offset);
119}
120
121pub fn freeRelocations(coff_file: *Coff, atom_index: Index) void {
122 const comp = coff_file.base.comp;
123 const gpa = comp.gpa;
124 var removed_relocs = coff_file.relocs.fetchOrderedRemove(atom_index);
125 if (removed_relocs) |*relocs| relocs.value.deinit(gpa);
126 var removed_base_relocs = coff_file.base_relocs.fetchOrderedRemove(atom_index);
127 if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(gpa);
128}
src/link/Coff/ImportTable.zig deleted-133
......@@ -1,133 +0,0 @@
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) = .empty,
30free_list: std.ArrayListUnmanaged(u32) = .empty,
31lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .empty,
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 @as(u32, @intCast(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 = @as(u32, @intCast(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 += @as(u32, @intCast(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
124pub const 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/Object.zig deleted-12
......@@ -1,12 +0,0 @@
1const Object = @This();
2
3const std = @import("std");
4const mem = std.mem;
5
6const Allocator = mem.Allocator;
7
8name: []const u8,
9
10pub fn deinit(self: *Object, gpa: Allocator) void {
11 gpa.free(self.name);
12}
src/link/Coff/Relocation.zig deleted-233
......@@ -1,233 +0,0 @@
1const Relocation = @This();
2
3const std = @import("std");
4const assert = std.debug.assert;
5const log = std.log.scoped(.link);
6const math = std.math;
7const mem = std.mem;
8const meta = std.meta;
9
10const aarch64 = @import("../../arch/aarch64/bits.zig");
11
12const Atom = @import("Atom.zig");
13const Coff = @import("../Coff.zig");
14const SymbolWithLoc = Coff.SymbolWithLoc;
15
16type: enum {
17 // x86, x86_64
18 /// RIP-relative displacement to a GOT pointer
19 got,
20 /// RIP-relative displacement to an import pointer
21 import,
22
23 // aarch64
24 /// PC-relative distance to target page in GOT section
25 got_page,
26 /// Offset to a GOT pointer relative to the start of a page in GOT section
27 got_pageoff,
28 /// PC-relative distance to target page in a section (e.g., .rdata)
29 page,
30 /// Offset to a pointer relative to the start of a page in a section (e.g., .rdata)
31 pageoff,
32 /// PC-relative distance to target page in a import section
33 import_page,
34 /// Offset to a pointer relative to the start of a page in an import section (e.g., .rdata)
35 import_pageoff,
36
37 // common
38 /// Absolute pointer value
39 direct,
40},
41target: SymbolWithLoc,
42offset: u32,
43addend: u32,
44pcrel: bool,
45length: u2,
46dirty: bool = true,
47
48/// Returns true if and only if the reloc can be resolved.
49pub fn isResolvable(self: Relocation, coff_file: *Coff) bool {
50 _ = self.getTargetAddress(coff_file) orelse return false;
51 return true;
52}
53
54pub fn isGotIndirection(self: Relocation) bool {
55 return switch (self.type) {
56 .got, .got_page, .got_pageoff => true,
57 else => false,
58 };
59}
60
61/// Returns address of the target if any.
62pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
63 switch (self.type) {
64 .got, .got_page, .got_pageoff => {
65 const got_index = coff_file.got_table.lookup.get(self.target) orelse return null;
66 const header = coff_file.sections.items(.header)[coff_file.got_section_index.?];
67 return header.virtual_address + got_index * coff_file.ptr_width.size();
68 },
69 .import, .import_page, .import_pageoff => {
70 const sym = coff_file.getSymbol(self.target);
71 const index = coff_file.import_tables.getIndex(sym.value) orelse return null;
72 const itab = coff_file.import_tables.values()[index];
73 return itab.getImportAddress(self.target, .{
74 .coff_file = coff_file,
75 .index = index,
76 .name_off = sym.value,
77 });
78 },
79 else => {
80 const target_atom_index = coff_file.getAtomIndexForSymbol(self.target) orelse return null;
81 const target_atom = coff_file.getAtom(target_atom_index);
82 return target_atom.getSymbol(coff_file).value;
83 },
84 }
85}
86
87pub fn resolve(self: Relocation, atom_index: Atom.Index, code: []u8, image_base: u64, coff_file: *Coff) void {
88 const atom = coff_file.getAtom(atom_index);
89 const source_sym = atom.getSymbol(coff_file);
90 const source_vaddr = source_sym.value + self.offset;
91
92 const target_vaddr = self.getTargetAddress(coff_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().
93 const target_vaddr_with_addend = target_vaddr + self.addend;
94
95 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) ", .{
96 source_vaddr,
97 target_vaddr_with_addend,
98 coff_file.getSymbolName(self.target),
99 @tagName(self.type),
100 });
101
102 const ctx: Context = .{
103 .source_vaddr = source_vaddr,
104 .target_vaddr = target_vaddr_with_addend,
105 .image_base = image_base,
106 .code = code,
107 .ptr_width = coff_file.ptr_width,
108 };
109
110 const target = coff_file.base.comp.root_mod.resolved_target.result;
111 switch (target.cpu.arch) {
112 .aarch64 => self.resolveAarch64(ctx),
113 .x86, .x86_64 => self.resolveX86(ctx),
114 else => unreachable, // unhandled target architecture
115 }
116}
117
118const Context = struct {
119 source_vaddr: u32,
120 target_vaddr: u32,
121 image_base: u64,
122 code: []u8,
123 ptr_width: Coff.PtrWidth,
124};
125
126fn resolveAarch64(self: Relocation, ctx: Context) void {
127 var buffer = ctx.code[self.offset..];
128 switch (self.type) {
129 .got_page, .import_page, .page => {
130 const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12));
131 const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12));
132 const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page))));
133 var inst = aarch64.Instruction{
134 .pc_relative_address = mem.bytesToValue(meta.TagPayload(
135 aarch64.Instruction,
136 aarch64.Instruction.pc_relative_address,
137 ), buffer[0..4]),
138 };
139 inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
140 inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
141 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
142 },
143 .got_pageoff, .import_pageoff, .pageoff => {
144 assert(!self.pcrel);
145
146 const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr))));
147 if (isArithmeticOp(buffer[0..4])) {
148 var inst = aarch64.Instruction{
149 .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(
150 aarch64.Instruction,
151 aarch64.Instruction.add_subtract_immediate,
152 ), buffer[0..4]),
153 };
154 inst.add_subtract_immediate.imm12 = narrowed;
155 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
156 } else {
157 var inst = aarch64.Instruction{
158 .load_store_register = mem.bytesToValue(meta.TagPayload(
159 aarch64.Instruction,
160 aarch64.Instruction.load_store_register,
161 ), buffer[0..4]),
162 };
163 const offset: u12 = blk: {
164 if (inst.load_store_register.size == 0) {
165 if (inst.load_store_register.v == 1) {
166 // 128-bit SIMD is scaled by 16.
167 break :blk @divExact(narrowed, 16);
168 }
169 // Otherwise, 8-bit SIMD or ldrb.
170 break :blk narrowed;
171 } else {
172 const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable;
173 break :blk @divExact(narrowed, denom);
174 }
175 };
176 inst.load_store_register.offset = offset;
177 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
178 }
179 },
180 .direct => {
181 assert(!self.pcrel);
182 switch (self.length) {
183 2 => mem.writeInt(
184 u32,
185 buffer[0..4],
186 @as(u32, @truncate(ctx.target_vaddr + ctx.image_base)),
187 .little,
188 ),
189 3 => mem.writeInt(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base, .little),
190 else => unreachable,
191 }
192 },
193
194 .got => unreachable,
195 .import => unreachable,
196 }
197}
198
199fn resolveX86(self: Relocation, ctx: Context) void {
200 var buffer = ctx.code[self.offset..];
201 switch (self.type) {
202 .got_page => unreachable,
203 .got_pageoff => unreachable,
204 .page => unreachable,
205 .pageoff => unreachable,
206 .import_page => unreachable,
207 .import_pageoff => unreachable,
208
209 .got, .import => {
210 assert(self.pcrel);
211 const disp = @as(i32, @intCast(ctx.target_vaddr)) - @as(i32, @intCast(ctx.source_vaddr)) - 4;
212 mem.writeInt(i32, buffer[0..4], disp, .little);
213 },
214 .direct => {
215 if (self.pcrel) {
216 const disp = @as(i32, @intCast(ctx.target_vaddr)) - @as(i32, @intCast(ctx.source_vaddr)) - 4;
217 mem.writeInt(i32, buffer[0..4], disp, .little);
218 } else switch (ctx.ptr_width) {
219 .p32 => mem.writeInt(u32, buffer[0..4], @as(u32, @intCast(ctx.target_vaddr + ctx.image_base)), .little),
220 .p64 => switch (self.length) {
221 2 => mem.writeInt(u32, buffer[0..4], @as(u32, @truncate(ctx.target_vaddr + ctx.image_base)), .little),
222 3 => mem.writeInt(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base, .little),
223 else => unreachable,
224 },
225 }
226 },
227 }
228}
229
230inline fn isArithmeticOp(inst: *const [4]u8) bool {
231 const group_decode = @as(u5, @truncate(inst[3]));
232 return ((group_decode >> 2) == 4);
233}
src/link/Coff/lld.zig deleted-548
......@@ -1,548 +0,0 @@
1const std = @import("std");
2const build_options = @import("build_options");
3const allocPrint = std.fmt.allocPrint;
4const assert = std.debug.assert;
5const dev = @import("../../dev.zig");
6const fs = std.fs;
7const log = std.log.scoped(.link);
8const mem = std.mem;
9const Cache = std.Build.Cache;
10const Path = std.Build.Cache.Path;
11const Directory = std.Build.Cache.Directory;
12
13const mingw = @import("../../mingw.zig");
14const link = @import("../../link.zig");
15const trace = @import("../../tracy.zig").trace;
16
17const Allocator = mem.Allocator;
18
19const Coff = @import("../Coff.zig");
20const Compilation = @import("../../Compilation.zig");
21const Zcu = @import("../../Zcu.zig");
22
23pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
24 dev.check(.lld_linker);
25
26 const tracy = trace(@src());
27 defer tracy.end();
28
29 const comp = self.base.comp;
30 const gpa = comp.gpa;
31
32 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
33 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
34
35 // If there is no Zig code to compile, then we should skip flushing the output file because it
36 // will not be part of the linker line anyway.
37 const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: {
38 try self.flushModule(arena, tid, prog_node);
39
40 if (fs.path.dirname(full_out_path)) |dirname| {
41 break :blk try fs.path.join(arena, &.{ dirname, self.base.zcu_object_sub_path.? });
42 } else {
43 break :blk self.base.zcu_object_sub_path.?;
44 }
45 } else null;
46
47 const sub_prog_node = prog_node.start("LLD Link", 0);
48 defer sub_prog_node.end();
49
50 const is_lib = comp.config.output_mode == .Lib;
51 const is_dyn_lib = comp.config.link_mode == .dynamic and is_lib;
52 const is_exe_or_dyn_lib = is_dyn_lib or comp.config.output_mode == .Exe;
53 const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib;
54 const target = comp.root_mod.resolved_target.result;
55 const optimize_mode = comp.root_mod.optimize_mode;
56 const entry_name: ?[]const u8 = switch (self.entry) {
57 // This logic isn't quite right for disabled or enabled. No point in fixing it
58 // when the goal is to eliminate dependency on LLD anyway.
59 // https://github.com/ziglang/zig/issues/17751
60 .disabled, .default, .enabled => null,
61 .named => |name| name,
62 };
63
64 // See link/Elf.zig for comments on how this mechanism works.
65 const id_symlink_basename = "lld.id";
66
67 var man: Cache.Manifest = undefined;
68 defer if (!self.base.disable_lld_caching) man.deinit();
69
70 var digest: [Cache.hex_digest_len]u8 = undefined;
71
72 if (!self.base.disable_lld_caching) {
73 man = comp.cache_parent.obtain();
74 self.base.releaseLock();
75
76 comptime assert(Compilation.link_hash_implementation_version == 14);
77
78 try link.hashInputs(&man, comp.link_inputs);
79 for (comp.c_object_table.keys()) |key| {
80 _ = try man.addFilePath(key.status.success.object_path, null);
81 }
82 for (comp.win32_resource_table.keys()) |key| {
83 _ = try man.addFile(key.status.success.res_path, null);
84 }
85 try man.addOptionalFile(module_obj_path);
86 man.hash.addOptionalBytes(entry_name);
87 man.hash.add(self.base.stack_size);
88 man.hash.add(self.image_base);
89 {
90 // TODO remove this, libraries must instead be resolved by the frontend.
91 for (self.lib_directories) |lib_directory| man.hash.addOptionalBytes(lib_directory.path);
92 }
93 man.hash.add(comp.skip_linker_dependencies);
94 if (comp.config.link_libc) {
95 man.hash.add(comp.libc_installation != null);
96 if (comp.libc_installation) |libc_installation| {
97 man.hash.addBytes(libc_installation.crt_dir.?);
98 if (target.abi == .msvc or target.abi == .itanium) {
99 man.hash.addBytes(libc_installation.msvc_lib_dir.?);
100 man.hash.addBytes(libc_installation.kernel32_lib_dir.?);
101 }
102 }
103 }
104 man.hash.addListOfBytes(comp.windows_libs.keys());
105 man.hash.addListOfBytes(comp.force_undefined_symbols.keys());
106 man.hash.addOptional(self.subsystem);
107 man.hash.add(comp.config.is_test);
108 man.hash.add(self.tsaware);
109 man.hash.add(self.nxcompat);
110 man.hash.add(self.dynamicbase);
111 man.hash.add(self.base.allow_shlib_undefined);
112 // strip does not need to go into the linker hash because it is part of the hash namespace
113 man.hash.add(self.major_subsystem_version);
114 man.hash.add(self.minor_subsystem_version);
115 man.hash.add(self.repro);
116 man.hash.addOptional(comp.version);
117 try man.addOptionalFile(self.module_definition_file);
118
119 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
120 _ = try man.hit();
121 digest = man.final();
122 var prev_digest_buf: [digest.len]u8 = undefined;
123 const prev_digest: []u8 = Cache.readSmallFile(
124 directory.handle,
125 id_symlink_basename,
126 &prev_digest_buf,
127 ) catch |err| blk: {
128 log.debug("COFF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
129 // Handle this as a cache miss.
130 break :blk prev_digest_buf[0..0];
131 };
132 if (mem.eql(u8, prev_digest, &digest)) {
133 log.debug("COFF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
134 // Hot diggity dog! The output binary is already there.
135 self.base.lock = man.toOwnedLock();
136 return;
137 }
138 log.debug("COFF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
139
140 // We are about to change the output file to be different, so we invalidate the build hash now.
141 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
142 error.FileNotFound => {},
143 else => |e| return e,
144 };
145 }
146
147 if (comp.config.output_mode == .Obj) {
148 // LLD's COFF driver does not support the equivalent of `-r` so we do a simple file copy
149 // here. TODO: think carefully about how we can avoid this redundant operation when doing
150 // build-obj. See also the corresponding TODO in linkAsArchive.
151 const the_object_path = blk: {
152 if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path;
153
154 if (comp.c_object_table.count() != 0)
155 break :blk comp.c_object_table.keys()[0].status.success.object_path;
156
157 if (module_obj_path) |p|
158 break :blk Path.initCwd(p);
159
160 // TODO I think this is unreachable. Audit this situation when solving the above TODO
161 // regarding eliding redundant object -> object transformations.
162 return error.NoObjectsToLink;
163 };
164 try std.fs.Dir.copyFile(
165 the_object_path.root_dir.handle,
166 the_object_path.sub_path,
167 directory.handle,
168 self.base.emit.sub_path,
169 .{},
170 );
171 } else {
172 // Create an LLD command line and invoke it.
173 var argv = std.ArrayList([]const u8).init(gpa);
174 defer argv.deinit();
175 // We will invoke ourselves as a child process to gain access to LLD.
176 // This is necessary because LLD does not behave properly as a library -
177 // it calls exit() and does not reset all global data between invocations.
178 const linker_command = "lld-link";
179 try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command });
180
181 try argv.append("-ERRORLIMIT:0");
182 try argv.append("-NOLOGO");
183 if (comp.config.debug_format != .strip) {
184 try argv.append("-DEBUG");
185
186 const out_ext = std.fs.path.extension(full_out_path);
187 const out_pdb = self.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{
188 full_out_path[0 .. full_out_path.len - out_ext.len],
189 });
190 const out_pdb_basename = std.fs.path.basename(out_pdb);
191
192 try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb}));
193 try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb_basename}));
194 }
195 if (comp.version) |version| {
196 try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));
197 }
198 if (comp.config.lto) {
199 switch (optimize_mode) {
200 .Debug => {},
201 .ReleaseSmall => try argv.append("-OPT:lldlto=2"),
202 .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"),
203 }
204 }
205 if (comp.config.output_mode == .Exe) {
206 try argv.append(try allocPrint(arena, "-STACK:{d}", .{self.base.stack_size}));
207 }
208 try argv.append(try std.fmt.allocPrint(arena, "-BASE:{d}", .{self.image_base}));
209
210 if (target.cpu.arch == .x86) {
211 try argv.append("-MACHINE:X86");
212 } else if (target.cpu.arch == .x86_64) {
213 try argv.append("-MACHINE:X64");
214 } else if (target.cpu.arch.isARM()) {
215 if (target.ptrBitWidth() == 32) {
216 try argv.append("-MACHINE:ARM");
217 } else {
218 try argv.append("-MACHINE:ARM64");
219 }
220 }
221
222 for (comp.force_undefined_symbols.keys()) |symbol| {
223 try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol}));
224 }
225
226 if (is_dyn_lib) {
227 try argv.append("-DLL");
228 }
229
230 if (entry_name) |name| {
231 try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{name}));
232 }
233
234 if (self.repro) {
235 try argv.append("-BREPRO");
236 }
237
238 if (self.tsaware) {
239 try argv.append("-tsaware");
240 }
241 if (self.nxcompat) {
242 try argv.append("-nxcompat");
243 }
244 if (!self.dynamicbase) {
245 try argv.append("-dynamicbase:NO");
246 }
247 if (self.base.allow_shlib_undefined) {
248 try argv.append("-FORCE:UNRESOLVED");
249 }
250
251 try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
252
253 if (comp.implib_emit) |emit| {
254 const implib_out_path = try emit.root_dir.join(arena, &[_][]const u8{emit.sub_path});
255 try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path}));
256 }
257
258 if (comp.config.link_libc) {
259 if (comp.libc_installation) |libc_installation| {
260 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?}));
261
262 if (target.abi == .msvc or target.abi == .itanium) {
263 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.msvc_lib_dir.?}));
264 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.kernel32_lib_dir.?}));
265 }
266 }
267 }
268
269 for (self.lib_directories) |lib_directory| {
270 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_directory.path orelse "."}));
271 }
272
273 try argv.ensureUnusedCapacity(comp.link_inputs.len);
274 for (comp.link_inputs) |link_input| switch (link_input) {
275 .dso_exact => unreachable, // not applicable to PE/COFF
276 inline .dso, .res => |x| {
277 argv.appendAssumeCapacity(try x.path.toString(arena));
278 },
279 .object, .archive => |obj| {
280 if (obj.must_link) {
281 argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{}", .{@as(Path, obj.path)}));
282 } else {
283 argv.appendAssumeCapacity(try obj.path.toString(arena));
284 }
285 },
286 };
287
288 for (comp.c_object_table.keys()) |key| {
289 try argv.append(try key.status.success.object_path.toString(arena));
290 }
291
292 for (comp.win32_resource_table.keys()) |key| {
293 try argv.append(key.status.success.res_path);
294 }
295
296 if (module_obj_path) |p| {
297 try argv.append(p);
298 }
299
300 if (self.module_definition_file) |def| {
301 try argv.append(try allocPrint(arena, "-DEF:{s}", .{def}));
302 }
303
304 const resolved_subsystem: ?std.Target.SubSystem = blk: {
305 if (self.subsystem) |explicit| break :blk explicit;
306 switch (target.os.tag) {
307 .windows => {
308 if (comp.zcu) |module| {
309 if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib)
310 break :blk null;
311 if (module.stage1_flags.have_c_main or comp.config.is_test or
312 module.stage1_flags.have_winmain_crt_startup or
313 module.stage1_flags.have_wwinmain_crt_startup)
314 {
315 break :blk .Console;
316 }
317 if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain)
318 break :blk .Windows;
319 }
320 },
321 .uefi => break :blk .EfiApplication,
322 else => {},
323 }
324 break :blk null;
325 };
326
327 const Mode = enum { uefi, win32 };
328 const mode: Mode = mode: {
329 if (resolved_subsystem) |subsystem| {
330 const subsystem_suffix = try allocPrint(arena, ",{d}.{d}", .{
331 self.major_subsystem_version, self.minor_subsystem_version,
332 });
333
334 switch (subsystem) {
335 .Console => {
336 try argv.append(try allocPrint(arena, "-SUBSYSTEM:console{s}", .{
337 subsystem_suffix,
338 }));
339 break :mode .win32;
340 },
341 .EfiApplication => {
342 try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_application{s}", .{
343 subsystem_suffix,
344 }));
345 break :mode .uefi;
346 },
347 .EfiBootServiceDriver => {
348 try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_boot_service_driver{s}", .{
349 subsystem_suffix,
350 }));
351 break :mode .uefi;
352 },
353 .EfiRom => {
354 try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_rom{s}", .{
355 subsystem_suffix,
356 }));
357 break :mode .uefi;
358 },
359 .EfiRuntimeDriver => {
360 try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_runtime_driver{s}", .{
361 subsystem_suffix,
362 }));
363 break :mode .uefi;
364 },
365 .Native => {
366 try argv.append(try allocPrint(arena, "-SUBSYSTEM:native{s}", .{
367 subsystem_suffix,
368 }));
369 break :mode .win32;
370 },
371 .Posix => {
372 try argv.append(try allocPrint(arena, "-SUBSYSTEM:posix{s}", .{
373 subsystem_suffix,
374 }));
375 break :mode .win32;
376 },
377 .Windows => {
378 try argv.append(try allocPrint(arena, "-SUBSYSTEM:windows{s}", .{
379 subsystem_suffix,
380 }));
381 break :mode .win32;
382 },
383 }
384 } else if (target.os.tag == .uefi) {
385 break :mode .uefi;
386 } else {
387 break :mode .win32;
388 }
389 };
390
391 switch (mode) {
392 .uefi => try argv.appendSlice(&[_][]const u8{
393 "-BASE:0",
394 "-ENTRY:EfiMain",
395 "-OPT:REF",
396 "-SAFESEH:NO",
397 "-MERGE:.rdata=.data",
398 "-NODEFAULTLIB",
399 "-SECTION:.xdata,D",
400 }),
401 .win32 => {
402 if (link_in_crt) {
403 if (target.abi.isGnu()) {
404 try argv.append("-lldmingw");
405
406 if (target.cpu.arch == .x86) {
407 try argv.append("-ALTERNATENAME:__image_base__=___ImageBase");
408 } else {
409 try argv.append("-ALTERNATENAME:__image_base__=__ImageBase");
410 }
411
412 if (is_dyn_lib) {
413 try argv.append(try comp.crtFileAsString(arena, "dllcrt2.obj"));
414 if (target.cpu.arch == .x86) {
415 try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12");
416 } else {
417 try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup");
418 }
419 } else {
420 try argv.append(try comp.crtFileAsString(arena, "crt2.obj"));
421 }
422
423 try argv.append(try comp.crtFileAsString(arena, "mingw32.lib"));
424 } else {
425 const lib_str = switch (comp.config.link_mode) {
426 .dynamic => "",
427 .static => "lib",
428 };
429 const d_str = switch (optimize_mode) {
430 .Debug => "d",
431 else => "",
432 };
433 switch (comp.config.link_mode) {
434 .static => try argv.append(try allocPrint(arena, "libcmt{s}.lib", .{d_str})),
435 .dynamic => try argv.append(try allocPrint(arena, "msvcrt{s}.lib", .{d_str})),
436 }
437
438 try argv.append(try allocPrint(arena, "{s}vcruntime{s}.lib", .{ lib_str, d_str }));
439 try argv.append(try allocPrint(arena, "{s}ucrt{s}.lib", .{ lib_str, d_str }));
440
441 //Visual C++ 2015 Conformance Changes
442 //https://msdn.microsoft.com/en-us/library/bb531344.aspx
443 try argv.append("legacy_stdio_definitions.lib");
444
445 // msvcrt depends on kernel32 and ntdll
446 try argv.append("kernel32.lib");
447 try argv.append("ntdll.lib");
448 }
449 } else {
450 try argv.append("-NODEFAULTLIB");
451 if (!is_lib and entry_name == null) {
452 if (comp.zcu) |module| {
453 if (module.stage1_flags.have_winmain_crt_startup) {
454 try argv.append("-ENTRY:WinMainCRTStartup");
455 } else {
456 try argv.append("-ENTRY:wWinMainCRTStartup");
457 }
458 } else {
459 try argv.append("-ENTRY:wWinMainCRTStartup");
460 }
461 }
462 }
463 },
464 }
465
466 // libc++ dep
467 if (comp.config.link_libcpp) {
468 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
469 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
470 }
471
472 // libunwind dep
473 if (comp.config.link_libunwind) {
474 try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
475 }
476
477 if (comp.config.any_fuzz) {
478 try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
479 }
480
481 if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) {
482 if (!comp.config.link_libc) {
483 if (comp.libc_static_lib) |lib| {
484 try argv.append(try lib.full_object_path.toString(arena));
485 }
486 }
487 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but
488 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
489 if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena));
490 if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena));
491 }
492
493 try argv.ensureUnusedCapacity(comp.windows_libs.count());
494 for (comp.windows_libs.keys()) |key| {
495 const lib_basename = try allocPrint(arena, "{s}.lib", .{key});
496 if (comp.crt_files.get(lib_basename)) |crt_file| {
497 argv.appendAssumeCapacity(try crt_file.full_object_path.toString(arena));
498 continue;
499 }
500 if (try findLib(arena, lib_basename, self.lib_directories)) |full_path| {
501 argv.appendAssumeCapacity(full_path);
502 continue;
503 }
504 if (target.abi.isGnu()) {
505 const fallback_name = try allocPrint(arena, "lib{s}.dll.a", .{key});
506 if (try findLib(arena, fallback_name, self.lib_directories)) |full_path| {
507 argv.appendAssumeCapacity(full_path);
508 continue;
509 }
510 }
511 if (target.abi == .msvc or target.abi == .itanium) {
512 argv.appendAssumeCapacity(lib_basename);
513 continue;
514 }
515
516 log.err("DLL import library for -l{s} not found", .{key});
517 return error.DllImportLibraryNotFound;
518 }
519
520 try link.spawnLld(comp, arena, argv.items);
521 }
522
523 if (!self.base.disable_lld_caching) {
524 // Update the file with the digest. If it fails we can continue; it only
525 // means that the next invocation will have an unnecessary cache miss.
526 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
527 log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)});
528 };
529 // Again failure here only means an unnecessary cache miss.
530 man.writeManifest() catch |err| {
531 log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)});
532 };
533 // We hang on to this lock so that the output file path can be used without
534 // other processes clobbering it.
535 self.base.lock = man.toOwnedLock();
536 }
537}
538
539fn findLib(arena: Allocator, name: []const u8, lib_directories: []const Directory) !?[]const u8 {
540 for (lib_directories) |lib_directory| {
541 lib_directory.handle.access(name, .{}) catch |err| switch (err) {
542 error.FileNotFound => continue,
543 else => |e| return e,
544 };
545 return try lib_directory.join(arena, &.{name});
546 }
547 return null;
548}