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...@@ -592,11 +592,6 @@ set(ZIG_STAGE2_SOURCES
592 src/link.zig592 src/link.zig
593 src/link/C.zig593 src/link/C.zig
594 src/link/Coff.zig594 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
600 src/link/Dwarf.zig595 src/link/Dwarf.zig
601 src/link/Elf.zig596 src/link/Elf.zig
602 src/link/Elf/Archive.zig597 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 {...@@ -942,7 +942,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
942 .load_memory_import => coff_file.getGlobalByIndex(data.sym_index),942 .load_memory_import => coff_file.getGlobalByIndex(data.sym_index),
943 else => unreachable,943 else => unreachable,
944 };944 };
945 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{945 try coff_file.addRelocation(atom_index, .{
946 .target = target,946 .target = target,
947 .offset = offset,947 .offset = offset,
948 .addend = 0,948 .addend = 0,
...@@ -959,7 +959,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -959,7 +959,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
959 else => unreachable,959 else => unreachable,
960 },960 },
961 });961 });
962 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{962 try coff_file.addRelocation(atom_index, .{
963 .target = target,963 .target = target,
964 .offset = offset + 4,964 .offset = offset + 4,
965 .addend = 0,965 .addend = 0,
src/arch/x86_64/Emit.zig+2-2
...@@ -132,7 +132,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -132,7 +132,7 @@ pub fn emitMir(emit: *Emit) Error!void {
132 coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index)132 coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index)
133 else133 else
134 link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null };134 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, .{
136 .type = .direct,136 .type = .direct,
137 .target = target,137 .target = target,
138 .offset = end_offset - 4,138 .offset = end_offset - 4,
...@@ -230,7 +230,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -230,7 +230,7 @@ pub fn emitMir(emit: *Emit) Error!void {
230 coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index)230 coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index)
231 else231 else
232 link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null };232 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, .{
234 .type = switch (lowered_relocs[0].target) {234 .type = switch (lowered_relocs[0].target) {
235 .linker_got => .got,235 .linker_got => .got,
236 .linker_direct => .direct,236 .linker_direct => .direct,
src/link/Coff.zig+1632-645
...@@ -26,10 +26,8 @@ repro: bool,...@@ -26,10 +26,8 @@ repro: bool,
26ptr_width: PtrWidth,26ptr_width: PtrWidth,
27page_size: u32,27page_size: u32,
2828
29objects: std.ArrayListUnmanaged(Object) = .empty,
30
31sections: std.MultiArrayList(Section) = .{},29sections: std.MultiArrayList(Section) = .{},
32data_directories: [coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory,30data_directories: [coff_util.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff_util.ImageDataDirectory,
3331
34text_section_index: ?u16 = null,32text_section_index: ?u16 = null,
35got_section_index: ?u16 = null,33got_section_index: ?u16 = null,
...@@ -38,7 +36,7 @@ data_section_index: ?u16 = null,...@@ -38,7 +36,7 @@ data_section_index: ?u16 = null,
38reloc_section_index: ?u16 = null,36reloc_section_index: ?u16 = null,
39idata_section_index: ?u16 = null,37idata_section_index: ?u16 = null,
4038
41locals: std.ArrayListUnmanaged(coff.Symbol) = .empty,39locals: std.ArrayListUnmanaged(coff_util.Symbol) = .empty,
42globals: std.ArrayListUnmanaged(SymbolWithLoc) = .empty,40globals: std.ArrayListUnmanaged(SymbolWithLoc) = .empty,
43resolver: std.StringHashMapUnmanaged(u32) = .empty,41resolver: std.StringHashMapUnmanaged(u32) = .empty,
44unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .empty,42unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .empty,
...@@ -112,7 +110,7 @@ const default_size_of_heap_reserve: u32 = 0x100000;...@@ -112,7 +110,7 @@ const default_size_of_heap_reserve: u32 = 0x100000;
112const default_size_of_heap_commit: u32 = 0x1000;110const default_size_of_heap_commit: u32 = 0x1000;
113111
114const Section = struct {112const Section = struct {
115 header: coff.SectionHeader,113 header: coff_util.SectionHeader,
116114
117 last_atom_index: ?Atom.Index = null,115 last_atom_index: ?Atom.Index = null,
118116
...@@ -154,9 +152,9 @@ const AvMetadata = struct {...@@ -154,9 +152,9 @@ const AvMetadata = struct {
154 m.exports.deinit(allocator);152 m.exports.deinit(allocator);
155 }153 }
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 {
158 for (m.exports.items) |exp| {156 for (m.exports.items) |exp| {
159 if (mem.eql(u8, name, coff_file.getSymbolName(.{157 if (mem.eql(u8, name, coff.getSymbolName(.{
160 .sym_index = exp,158 .sym_index = exp,
161 .file = null,159 .file = null,
162 }))) return exp;160 }))) return exp;
...@@ -164,9 +162,9 @@ const AvMetadata = struct {...@@ -164,9 +162,9 @@ const AvMetadata = struct {
164 return null;162 return null;
165 }163 }
166164
167 fn getExportPtr(m: *AvMetadata, coff_file: *Coff, name: []const u8) ?*u32 {165 fn getExportPtr(m: *AvMetadata, coff: *Coff, name: []const u8) ?*u32 {
168 for (m.exports.items) |*exp| {166 for (m.exports.items) |*exp| {
169 if (mem.eql(u8, name, coff_file.getSymbolName(.{167 if (mem.eql(u8, name, coff.getSymbolName(.{
170 .sym_index = exp.*,168 .sym_index = exp.*,
171 .file = null,169 .file = null,
172 }))) return exp;170 }))) return exp;
...@@ -247,10 +245,10 @@ pub fn createEmpty(...@@ -247,10 +245,10 @@ pub fn createEmpty(
247 const zcu_object_sub_path = if (!use_lld and !use_llvm)245 const zcu_object_sub_path = if (!use_lld and !use_llvm)
248 null246 null
249 else247 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);250 const coff = try arena.create(Coff);
253 self.* = .{251 coff.* = .{
254 .base = .{252 .base = .{
255 .tag = .coff,253 .tag = .coff,
256 .comp = comp,254 .comp = comp,
...@@ -267,10 +265,10 @@ pub fn createEmpty(...@@ -267,10 +265,10 @@ pub fn createEmpty(
267 .ptr_width = ptr_width,265 .ptr_width = ptr_width,
268 .page_size = page_size,266 .page_size = page_size,
269267
270 .data_directories = [1]coff.ImageDataDirectory{.{268 .data_directories = [1]coff_util.ImageDataDirectory{.{
271 .virtual_address = 0,269 .virtual_address = 0,
272 .size = 0,270 .size = 0,
273 }} ** coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES,271 }} ** coff_util.IMAGE_NUMBEROF_DIRECTORY_ENTRIES,
274272
275 .image_base = options.image_base orelse switch (output_mode) {273 .image_base = options.image_base orelse switch (output_mode) {
276 .Exe => switch (target.cpu.arch) {274 .Exe => switch (target.cpu.arch) {
...@@ -305,35 +303,35 @@ pub fn createEmpty(...@@ -305,35 +303,35 @@ pub fn createEmpty(
305 .repro = options.repro,303 .repro = options.repro,
306 };304 };
307 if (use_llvm and comp.config.have_zcu) {305 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);
309 }307 }
310 errdefer self.base.destroy();308 errdefer coff.base.destroy();
311309
312 if (use_lld and (use_llvm or !comp.config.have_zcu)) {310 if (use_lld and (use_llvm or !comp.config.have_zcu)) {
313 // LLVM emits the object file (if any); LLD links it into the final product.311 // LLVM emits the object file (if any); LLD links it into the final product.
314 return self;312 return coff;
315 }313 }
316314
317 // What path should this COFF linker code output to?315 // What path should this COFF linker code output to?
318 // If using LLD to link, this code should produce an object file so that it316 // If using LLD to link, this code should produce an object file so that it
319 // can be passed to LLD.317 // can be passed to LLD.
320 const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path;318 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, .{
322 .truncate = true,320 .truncate = true,
323 .read = true,321 .read = true,
324 .mode = link.File.determineMode(use_lld, output_mode, link_mode),322 .mode = link.File.determineMode(use_lld, output_mode, link_mode),
325 });323 });
326324
327 assert(self.llvm_object == null);325 assert(coff.llvm_object == null);
328 const gpa = comp.gpa;326 const gpa = comp.gpa;
329327
330 try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));328 try coff.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));
331 self.strtab.buffer.appendNTimesAssumeCapacity(0, @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
335 // Index 0 is always a null symbol.333 // Index 0 is always a null symbol.
336 try self.locals.append(gpa, .{334 try coff.locals.append(gpa, .{
337 .name = [_]u8{0} ** 8,335 .name = [_]u8{0} ** 8,
338 .value = 0,336 .value = 0,
339 .section_number = .UNDEFINED,337 .section_number = .UNDEFINED,
...@@ -342,61 +340,61 @@ pub fn createEmpty(...@@ -342,61 +340,61 @@ pub fn createEmpty(
342 .number_of_aux_symbols = 0,340 .number_of_aux_symbols = 0,
343 });341 });
344342
345 if (self.text_section_index == null) {343 if (coff.text_section_index == null) {
346 const file_size: u32 = @intCast(options.program_code_size_hint);344 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, .{
348 .CNT_CODE = 1,346 .CNT_CODE = 1,
349 .MEM_EXECUTE = 1,347 .MEM_EXECUTE = 1,
350 .MEM_READ = 1,348 .MEM_READ = 1,
351 });349 });
352 }350 }
353351
354 if (self.got_section_index == null) {352 if (coff.got_section_index == null) {
355 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size();353 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
356 self.got_section_index = try self.allocateSection(".got", file_size, .{354 coff.got_section_index = try coff.allocateSection(".got", file_size, .{
357 .CNT_INITIALIZED_DATA = 1,355 .CNT_INITIALIZED_DATA = 1,
358 .MEM_READ = 1,356 .MEM_READ = 1,
359 });357 });
360 }358 }
361359
362 if (self.rdata_section_index == null) {360 if (coff.rdata_section_index == null) {
363 const file_size: u32 = self.page_size;361 const file_size: u32 = coff.page_size;
364 self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{362 coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{
365 .CNT_INITIALIZED_DATA = 1,363 .CNT_INITIALIZED_DATA = 1,
366 .MEM_READ = 1,364 .MEM_READ = 1,
367 });365 });
368 }366 }
369367
370 if (self.data_section_index == null) {368 if (coff.data_section_index == null) {
371 const file_size: u32 = self.page_size;369 const file_size: u32 = coff.page_size;
372 self.data_section_index = try self.allocateSection(".data", file_size, .{370 coff.data_section_index = try coff.allocateSection(".data", file_size, .{
373 .CNT_INITIALIZED_DATA = 1,371 .CNT_INITIALIZED_DATA = 1,
374 .MEM_READ = 1,372 .MEM_READ = 1,
375 .MEM_WRITE = 1,373 .MEM_WRITE = 1,
376 });374 });
377 }375 }
378376
379 if (self.idata_section_index == null) {377 if (coff.idata_section_index == null) {
380 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size();378 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
381 self.idata_section_index = try self.allocateSection(".idata", file_size, .{379 coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{
382 .CNT_INITIALIZED_DATA = 1,380 .CNT_INITIALIZED_DATA = 1,
383 .MEM_READ = 1,381 .MEM_READ = 1,
384 });382 });
385 }383 }
386384
387 if (self.reloc_section_index == null) {385 if (coff.reloc_section_index == null) {
388 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff.BaseRelocation);386 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation);
389 self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{387 coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{
390 .CNT_INITIALIZED_DATA = 1,388 .CNT_INITIALIZED_DATA = 1,
391 .MEM_DISCARDABLE = 1,389 .MEM_DISCARDABLE = 1,
392 .MEM_READ = 1,390 .MEM_READ = 1,
393 });391 });
394 }392 }
395393
396 if (self.strtab_offset == null) {394 if (coff.strtab_offset == null) {
397 const file_size = @as(u32, @intCast(self.strtab.buffer.items.len));395 const file_size = @as(u32, @intCast(coff.strtab.buffer.items.len));
398 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here396 coff.strtab_offset = coff.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 });397 log.debug("found strtab free space 0x{x} to 0x{x}", .{ coff.strtab_offset.?, coff.strtab_offset.? + file_size });
400 }398 }
401399
402 {400 {
...@@ -405,15 +403,15 @@ pub fn createEmpty(...@@ -405,15 +403,15 @@ pub fn createEmpty(
405 // offset + it's filesize.403 // offset + it's filesize.
406 // TODO I don't like this here one bit404 // TODO I don't like this here one bit
407 var max_file_offset: u64 = 0;405 var max_file_offset: u64 = 0;
408 for (self.sections.items(.header)) |header| {406 for (coff.sections.items(.header)) |header| {
409 if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) {407 if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) {
410 max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data;408 max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data;
411 }409 }
412 }410 }
413 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);411 try coff.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);
414 }412 }
415413
416 return self;414 return coff;
417}415}
418416
419pub fn open(417pub fn open(
...@@ -427,85 +425,80 @@ pub fn open(...@@ -427,85 +425,80 @@ pub fn open(
427 return createEmpty(arena, comp, emit, options);425 return createEmpty(arena, comp, emit, options);
428}426}
429427
430pub fn deinit(self: *Coff) void {428pub fn deinit(coff: *Coff) void {
431 const gpa = self.base.comp.gpa;429 const gpa = coff.base.comp.gpa;
432
433 if (self.llvm_object) |llvm_object| llvm_object.deinit();
434430
435 for (self.objects.items) |*object| {431 if (coff.llvm_object) |llvm_object| llvm_object.deinit();
436 object.deinit(gpa);
437 }
438 self.objects.deinit(gpa);
439432
440 for (self.sections.items(.free_list)) |*free_list| {433 for (coff.sections.items(.free_list)) |*free_list| {
441 free_list.deinit(gpa);434 free_list.deinit(gpa);
442 }435 }
443 self.sections.deinit(gpa);436 coff.sections.deinit(gpa);
444437
445 self.atoms.deinit(gpa);438 coff.atoms.deinit(gpa);
446 self.locals.deinit(gpa);439 coff.locals.deinit(gpa);
447 self.globals.deinit(gpa);440 coff.globals.deinit(gpa);
448441
449 {442 {
450 var it = self.resolver.keyIterator();443 var it = coff.resolver.keyIterator();
451 while (it.next()) |key_ptr| {444 while (it.next()) |key_ptr| {
452 gpa.free(key_ptr.*);445 gpa.free(key_ptr.*);
453 }446 }
454 self.resolver.deinit(gpa);447 coff.resolver.deinit(gpa);
455 }448 }
456449
457 self.unresolved.deinit(gpa);450 coff.unresolved.deinit(gpa);
458 self.locals_free_list.deinit(gpa);451 coff.locals_free_list.deinit(gpa);
459 self.globals_free_list.deinit(gpa);452 coff.globals_free_list.deinit(gpa);
460 self.strtab.deinit(gpa);453 coff.strtab.deinit(gpa);
461 self.temp_strtab.deinit(gpa);454 coff.temp_strtab.deinit(gpa);
462 self.got_table.deinit(gpa);455 coff.got_table.deinit(gpa);
463456
464 for (self.import_tables.values()) |*itab| {457 for (coff.import_tables.values()) |*itab| {
465 itab.deinit(gpa);458 itab.deinit(gpa);
466 }459 }
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| {
472 metadata.deinit(gpa);465 metadata.deinit(gpa);
473 }466 }
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
478 {471 {
479 var it = self.uavs.iterator();472 var it = coff.uavs.iterator();
480 while (it.next()) |entry| {473 while (it.next()) |entry| {
481 entry.value_ptr.exports.deinit(gpa);474 entry.value_ptr.exports.deinit(gpa);
482 }475 }
483 self.uavs.deinit(gpa);476 coff.uavs.deinit(gpa);
484 }477 }
485478
486 for (self.relocs.values()) |*relocs| {479 for (coff.relocs.values()) |*relocs| {
487 relocs.deinit(gpa);480 relocs.deinit(gpa);
488 }481 }
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| {
492 relocs.deinit(gpa);485 relocs.deinit(gpa);
493 }486 }
494 self.base_relocs.deinit(gpa);487 coff.base_relocs.deinit(gpa);
495}488}
496489
497fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.SectionHeaderFlags) !u16 {490fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeaderFlags) !u16 {
498 const index = @as(u16, @intCast(self.sections.slice().len));491 const index = @as(u16, @intCast(coff.sections.slice().len));
499 const off = self.findFreeSpace(size, default_file_alignment);492 const off = coff.findFreeSpace(size, default_file_alignment);
500 // Memory is always allocated in sequence493 // Memory is always allocated in sequence
501 // TODO: investigate if we can allocate .text last; this way it would never need to grow in memory!494 // TODO: investigate if we can allocate .text last; this way it would never need to grow in memory!
502 const vaddr = blk: {495 const vaddr = blk: {
503 if (index == 0) break :blk self.page_size;496 if (index == 0) break :blk coff.page_size;
504 const prev_header = self.sections.items(.header)[index - 1];497 const prev_header = coff.sections.items(.header)[index - 1];
505 break :blk mem.alignForward(u32, prev_header.virtual_address + prev_header.virtual_size, self.page_size);498 break :blk mem.alignForward(u32, prev_header.virtual_address + prev_header.virtual_size, coff.page_size);
506 };499 };
507 // We commit more memory than needed upfront so that we don't have to reallocate too soon.500 // 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;
509 log.debug("found {s} free space 0x{x} to 0x{x} (0x{x} - 0x{x})", .{502 log.debug("found {s} free space 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
510 name,503 name,
511 off,504 off,
...@@ -513,7 +506,7 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section...@@ -513,7 +506,7 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section
513 vaddr,506 vaddr,
514 vaddr + size,507 vaddr + size,
515 });508 });
516 var header = coff.SectionHeader{509 var header = coff_util.SectionHeader{
517 .name = undefined,510 .name = undefined,
518 .virtual_size = memsz,511 .virtual_size = memsz,
519 .virtual_address = vaddr,512 .virtual_address = vaddr,
...@@ -525,32 +518,32 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section...@@ -525,32 +518,32 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section
525 .number_of_linenumbers = 0,518 .number_of_linenumbers = 0,
526 .flags = flags,519 .flags = flags,
527 };520 };
528 const gpa = self.base.comp.gpa;521 const gpa = coff.base.comp.gpa;
529 try self.setSectionName(&header, name);522 try coff.setSectionName(&header, name);
530 try self.sections.append(gpa, .{ .header = header });523 try coff.sections.append(gpa, .{ .header = header });
531 return index;524 return index;
532}525}
533526
534fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void {527fn growSection(coff: *Coff, sect_id: u32, needed_size: u32) !void {
535 const header = &self.sections.items(.header)[sect_id];528 const header = &coff.sections.items(.header)[sect_id];
536 const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id];529 const maybe_last_atom_index = coff.sections.items(.last_atom_index)[sect_id];
537 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);530 const sect_capacity = coff.allocatedSize(header.pointer_to_raw_data);
538531
539 if (needed_size > sect_capacity) {532 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);
541 const current_size = if (maybe_last_atom_index) |last_atom_index| blk: {534 const current_size = if (maybe_last_atom_index) |last_atom_index| blk: {
542 const last_atom = self.getAtom(last_atom_index);535 const last_atom = coff.getAtom(last_atom_index);
543 const sym = last_atom.getSymbol(self);536 const sym = last_atom.getSymbol(coff);
544 break :blk (sym.value + last_atom.size) - header.virtual_address;537 break :blk (sym.value + last_atom.size) - header.virtual_address;
545 } else 0;538 } else 0;
546 log.debug("moving {s} from 0x{x} to 0x{x}", .{539 log.debug("moving {s} from 0x{x} to 0x{x}", .{
547 self.getSectionName(header),540 coff.getSectionName(header),
548 header.pointer_to_raw_data,541 header.pointer_to_raw_data,
549 new_offset,542 new_offset,
550 });543 });
551 const amt = try self.base.file.?.copyRangeAll(544 const amt = try coff.base.file.?.copyRangeAll(
552 header.pointer_to_raw_data,545 header.pointer_to_raw_data,
553 self.base.file.?,546 coff.base.file.?,
554 new_offset,547 new_offset,
555 current_size,548 current_size,
556 );549 );
...@@ -558,35 +551,35 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void {...@@ -558,35 +551,35 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void {
558 header.pointer_to_raw_data = new_offset;551 header.pointer_to_raw_data = new_offset;
559 }552 }
560553
561 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);554 const sect_vm_capacity = coff.allocatedVirtualSize(header.virtual_address);
562 if (needed_size > sect_vm_capacity) {555 if (needed_size > sect_vm_capacity) {
563 self.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size);556 coff.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size);
564 try self.growSectionVirtualMemory(sect_id, needed_size);557 try coff.growSectionVirtualMemory(sect_id, needed_size);
565 }558 }
566559
567 header.virtual_size = @max(header.virtual_size, needed_size);560 header.virtual_size = @max(header.virtual_size, needed_size);
568 header.size_of_raw_data = needed_size;561 header.size_of_raw_data = needed_size;
569}562}
570563
571fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void {564fn growSectionVirtualMemory(coff: *Coff, sect_id: u32, needed_size: u32) !void {
572 const header = &self.sections.items(.header)[sect_id];565 const header = &coff.sections.items(.header)[sect_id];
573 const increased_size = padToIdeal(needed_size);566 const increased_size = padToIdeal(needed_size);
574 const old_aligned_end = header.virtual_address + mem.alignForward(u32, header.virtual_size, self.page_size);567 const old_aligned_end = header.virtual_address + mem.alignForward(u32, header.virtual_size, coff.page_size);
575 const new_aligned_end = header.virtual_address + mem.alignForward(u32, increased_size, self.page_size);568 const new_aligned_end = header.virtual_address + mem.alignForward(u32, increased_size, coff.page_size);
576 const diff = new_aligned_end - old_aligned_end;569 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.
580 // This is required by the loader anyhow as far as I can tell.573 // 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| {574 for (coff.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];575 const maybe_last_atom_index = coff.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id];
583 next_header.virtual_address += diff;576 next_header.virtual_address += diff;
584577
585 if (maybe_last_atom_index) |last_atom_index| {578 if (maybe_last_atom_index) |last_atom_index| {
586 var atom_index = last_atom_index;579 var atom_index = last_atom_index;
587 while (true) {580 while (true) {
588 const atom = self.getAtom(atom_index);581 const atom = coff.getAtom(atom_index);
589 const sym = atom.getSymbolPtr(self);582 const sym = atom.getSymbolPtr(coff);
590 sym.value += diff;583 sym.value += diff;
591584
592 if (atom.prev_index) |prev_index| {585 if (atom.prev_index) |prev_index| {
...@@ -599,15 +592,15 @@ fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void {...@@ -599,15 +592,15 @@ fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void {
599 header.virtual_size = increased_size;592 header.virtual_size = increased_size;
600}593}
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 {
603 const tracy = trace(@src());596 const tracy = trace(@src());
604 defer tracy.end();597 defer tracy.end();
605598
606 const atom = self.getAtom(atom_index);599 const atom = coff.getAtom(atom_index);
607 const sect_id = @intFromEnum(atom.getSymbol(self).section_number) - 1;600 const sect_id = @intFromEnum(atom.getSymbol(coff).section_number) - 1;
608 const header = &self.sections.items(.header)[sect_id];601 const header = &coff.sections.items(.header)[sect_id];
609 const free_list = &self.sections.items(.free_list)[sect_id];602 const free_list = &coff.sections.items(.free_list)[sect_id];
610 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];603 const maybe_last_atom_index = &coff.sections.items(.last_atom_index)[sect_id];
611 const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size;604 const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size;
612605
613 // We use these to indicate our intention to update metadata, placing the new atom,606 // 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...@@ -624,11 +617,11 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
624 var i: usize = 0;617 var i: usize = 0;
625 while (i < free_list.items.len) {618 while (i < free_list.items.len) {
626 const big_atom_index = free_list.items[i];619 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);
628 // We now have a pointer to a live atom that has too much capacity.621 // We now have a pointer to a live atom that has too much capacity.
629 // Is it enough that we could fit this new atom?622 // Is it enough that we could fit this new atom?
630 const sym = big_atom.getSymbol(self);623 const sym = big_atom.getSymbol(coff);
631 const capacity = big_atom.capacity(self);624 const capacity = big_atom.capacity(coff);
632 const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity;625 const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity;
633 const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity;626 const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity;
634 const capacity_end_vaddr = sym.value + capacity;627 const capacity_end_vaddr = sym.value + capacity;
...@@ -638,7 +631,7 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme...@@ -638,7 +631,7 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
638 // Additional bookkeeping here to notice if this free list node631 // Additional bookkeeping here to notice if this free list node
639 // should be deleted because the atom that it points to has grown to take up632 // should be deleted because the atom that it points to has grown to take up
640 // more of the extra capacity.633 // more of the extra capacity.
641 if (!big_atom.freeListEligible(self)) {634 if (!big_atom.freeListEligible(coff)) {
642 _ = free_list.swapRemove(i);635 _ = free_list.swapRemove(i);
643 } else {636 } else {
644 i += 1;637 i += 1;
...@@ -658,8 +651,8 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme...@@ -658,8 +651,8 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
658 }651 }
659 break :blk new_start_vaddr;652 break :blk new_start_vaddr;
660 } else if (maybe_last_atom_index.*) |last_index| {653 } else if (maybe_last_atom_index.*) |last_index| {
661 const last = self.getAtom(last_index);654 const last = coff.getAtom(last_index);
662 const last_symbol = last.getSymbol(self);655 const last_symbol = last.getSymbol(coff);
663 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;656 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
664 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;657 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;
665 const new_start_vaddr = mem.alignForward(u32, ideal_capacity_end_vaddr, alignment);658 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...@@ -671,33 +664,33 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
671 };664 };
672665
673 const expand_section = if (atom_placement) |placement_index|666 const expand_section = if (atom_placement) |placement_index|
674 self.getAtom(placement_index).next_index == null667 coff.getAtom(placement_index).next_index == null
675 else668 else
676 true;669 true;
677 if (expand_section) {670 if (expand_section) {
678 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;671 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);
680 maybe_last_atom_index.* = atom_index;673 maybe_last_atom_index.* = atom_index;
681 }674 }
682 self.getAtomPtr(atom_index).size = new_atom_size;675 coff.getAtomPtr(atom_index).size = new_atom_size;
683676
684 if (atom.prev_index) |prev_index| {677 if (atom.prev_index) |prev_index| {
685 const prev = self.getAtomPtr(prev_index);678 const prev = coff.getAtomPtr(prev_index);
686 prev.next_index = atom.next_index;679 prev.next_index = atom.next_index;
687 }680 }
688 if (atom.next_index) |next_index| {681 if (atom.next_index) |next_index| {
689 const next = self.getAtomPtr(next_index);682 const next = coff.getAtomPtr(next_index);
690 next.prev_index = atom.prev_index;683 next.prev_index = atom.prev_index;
691 }684 }
692685
693 if (atom_placement) |big_atom_index| {686 if (atom_placement) |big_atom_index| {
694 const big_atom = self.getAtomPtr(big_atom_index);687 const big_atom = coff.getAtomPtr(big_atom_index);
695 const atom_ptr = self.getAtomPtr(atom_index);688 const atom_ptr = coff.getAtomPtr(atom_index);
696 atom_ptr.prev_index = big_atom_index;689 atom_ptr.prev_index = big_atom_index;
697 atom_ptr.next_index = big_atom.next_index;690 atom_ptr.next_index = big_atom.next_index;
698 big_atom.next_index = atom_index;691 big_atom.next_index = atom_index;
699 } else {692 } else {
700 const atom_ptr = self.getAtomPtr(atom_index);693 const atom_ptr = coff.getAtomPtr(atom_index);
701 atom_ptr.prev_index = null;694 atom_ptr.prev_index = null;
702 atom_ptr.next_index = null;695 atom_ptr.next_index = null;
703 }696 }
...@@ -708,23 +701,23 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme...@@ -708,23 +701,23 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
708 return vaddr;701 return vaddr;
709}702}
710703
711pub fn allocateSymbol(self: *Coff) !u32 {704pub fn allocateSymbol(coff: *Coff) !u32 {
712 const gpa = self.base.comp.gpa;705 const gpa = coff.base.comp.gpa;
713 try self.locals.ensureUnusedCapacity(gpa, 1);706 try coff.locals.ensureUnusedCapacity(gpa, 1);
714707
715 const index = blk: {708 const index = blk: {
716 if (self.locals_free_list.popOrNull()) |index| {709 if (coff.locals_free_list.popOrNull()) |index| {
717 log.debug(" (reusing symbol index {d})", .{index});710 log.debug(" (reusing symbol index {d})", .{index});
718 break :blk index;711 break :blk index;
719 } else {712 } else {
720 log.debug(" (allocating symbol index {d})", .{self.locals.items.len});713 log.debug(" (allocating symbol index {d})", .{coff.locals.items.len});
721 const index = @as(u32, @intCast(self.locals.items.len));714 const index = @as(u32, @intCast(coff.locals.items.len));
722 _ = self.locals.addOneAssumeCapacity();715 _ = coff.locals.addOneAssumeCapacity();
723 break :blk index;716 break :blk index;
724 }717 }
725 };718 };
726719
727 self.locals.items[index] = .{720 coff.locals.items[index] = .{
728 .name = [_]u8{0} ** 8,721 .name = [_]u8{0} ** 8,
729 .value = 0,722 .value = 0,
730 .section_number = .UNDEFINED,723 .section_number = .UNDEFINED,
...@@ -736,23 +729,23 @@ pub fn allocateSymbol(self: *Coff) !u32 {...@@ -736,23 +729,23 @@ pub fn allocateSymbol(self: *Coff) !u32 {
736 return index;729 return index;
737}730}
738731
739fn allocateGlobal(self: *Coff) !u32 {732fn allocateGlobal(coff: *Coff) !u32 {
740 const gpa = self.base.comp.gpa;733 const gpa = coff.base.comp.gpa;
741 try self.globals.ensureUnusedCapacity(gpa, 1);734 try coff.globals.ensureUnusedCapacity(gpa, 1);
742735
743 const index = blk: {736 const index = blk: {
744 if (self.globals_free_list.popOrNull()) |index| {737 if (coff.globals_free_list.popOrNull()) |index| {
745 log.debug(" (reusing global index {d})", .{index});738 log.debug(" (reusing global index {d})", .{index});
746 break :blk index;739 break :blk index;
747 } else {740 } else {
748 log.debug(" (allocating global index {d})", .{self.globals.items.len});741 log.debug(" (allocating global index {d})", .{coff.globals.items.len});
749 const index = @as(u32, @intCast(self.globals.items.len));742 const index = @as(u32, @intCast(coff.globals.items.len));
750 _ = self.globals.addOneAssumeCapacity();743 _ = coff.globals.addOneAssumeCapacity();
751 break :blk index;744 break :blk index;
752 }745 }
753 };746 };
754747
755 self.globals.items[index] = .{748 coff.globals.items[index] = .{
756 .sym_index = 0,749 .sym_index = 0,
757 .file = null,750 .file = null,
758 };751 };
...@@ -760,21 +753,21 @@ fn allocateGlobal(self: *Coff) !u32 {...@@ -760,21 +753,21 @@ fn allocateGlobal(self: *Coff) !u32 {
760 return index;753 return index;
761}754}
762755
763fn addGotEntry(self: *Coff, target: SymbolWithLoc) !void {756fn addGotEntry(coff: *Coff, target: SymbolWithLoc) !void {
764 const gpa = self.base.comp.gpa;757 const gpa = coff.base.comp.gpa;
765 if (self.got_table.lookup.contains(target)) return;758 if (coff.got_table.lookup.contains(target)) return;
766 const got_index = try self.got_table.allocateEntry(gpa, target);759 const got_index = try coff.got_table.allocateEntry(gpa, target);
767 try self.writeOffsetTableEntry(got_index);760 try coff.writeOffsetTableEntry(got_index);
768 self.got_table_count_dirty = true;761 coff.got_table_count_dirty = true;
769 self.markRelocsDirtyByTarget(target);762 coff.markRelocsDirtyByTarget(target);
770}763}
771764
772pub fn createAtom(self: *Coff) !Atom.Index {765pub fn createAtom(coff: *Coff) !Atom.Index {
773 const gpa = self.base.comp.gpa;766 const gpa = coff.base.comp.gpa;
774 const atom_index = @as(Atom.Index, @intCast(self.atoms.items.len));767 const atom_index = @as(Atom.Index, @intCast(coff.atoms.items.len));
775 const atom = try self.atoms.addOne(gpa);768 const atom = try coff.atoms.addOne(gpa);
776 const sym_index = try self.allocateSymbol();769 const sym_index = try coff.allocateSymbol();
777 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);770 try coff.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
778 atom.* = .{771 atom.* = .{
779 .sym_index = sym_index,772 .sym_index = sym_index,
780 .file = null,773 .file = null,
...@@ -786,36 +779,36 @@ pub fn createAtom(self: *Coff) !Atom.Index {...@@ -786,36 +779,36 @@ pub fn createAtom(self: *Coff) !Atom.Index {
786 return atom_index;779 return atom_index;
787}780}
788781
789fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {782fn growAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
790 const atom = self.getAtom(atom_index);783 const atom = coff.getAtom(atom_index);
791 const sym = atom.getSymbol(self);784 const sym = atom.getSymbol(coff);
792 const align_ok = mem.alignBackward(u32, sym.value, alignment) == sym.value;785 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);
794 if (!need_realloc) return sym.value;787 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);
796}789}
797790
798fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void {791fn shrinkAtom(coff: *Coff, atom_index: Atom.Index, new_block_size: u32) void {
799 _ = self;792 _ = coff;
800 _ = atom_index;793 _ = atom_index;
801 _ = new_block_size;794 _ = new_block_size;
802 // TODO check the new capacity, and if it crosses the size threshold into a big enough795 // TODO check the new capacity, and if it crosses the size threshold into a big enough
803 // capacity, insert a free list node for it.796 // capacity, insert a free list node for it.
804}797}
805798
806fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {799fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8) !void {
807 const atom = self.getAtom(atom_index);800 const atom = coff.getAtom(atom_index);
808 const sym = atom.getSymbol(self);801 const sym = atom.getSymbol(coff);
809 const section = self.sections.get(@intFromEnum(sym.section_number) - 1);802 const section = coff.sections.get(@intFromEnum(sym.section_number) - 1);
810 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;803 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
811804
812 log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{805 log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{
813 atom.getName(self),806 atom.getName(coff),
814 file_offset,807 file_offset,
815 file_offset + code.len,808 file_offset + code.len,
816 });809 });
817810
818 const gpa = self.base.comp.gpa;811 const gpa = coff.base.comp.gpa;
819812
820 // Gather relocs which can be resolved.813 // Gather relocs which can be resolved.
821 // We need to do this as we will be applying different slide values depending814 // 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 {...@@ -825,22 +818,22 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
825 var relocs = std.ArrayList(*Relocation).init(gpa);818 var relocs = std.ArrayList(*Relocation).init(gpa);
826 defer relocs.deinit();819 defer relocs.deinit();
827820
828 if (self.relocs.getPtr(atom_index)) |rels| {821 if (coff.relocs.getPtr(atom_index)) |rels| {
829 try relocs.ensureTotalCapacityPrecise(rels.items.len);822 try relocs.ensureTotalCapacityPrecise(rels.items.len);
830 for (rels.items) |*reloc| {823 for (rels.items) |*reloc| {
831 if (reloc.isResolvable(self) and reloc.dirty) {824 if (reloc.isResolvable(coff) and reloc.dirty) {
832 relocs.appendAssumeCapacity(reloc);825 relocs.appendAssumeCapacity(reloc);
833 }826 }
834 }827 }
835 }828 }
836829
837 if (is_hot_update_compatible) {830 if (is_hot_update_compatible) {
838 if (self.base.child_pid) |handle| {831 if (coff.base.child_pid) |handle| {
839 const slide = @intFromPtr(self.hot_state.loaded_base_address.?);832 const slide = @intFromPtr(coff.hot_state.loaded_base_address.?);
840833
841 const mem_code = try gpa.dupe(u8, code);834 const mem_code = try gpa.dupe(u8, code);
842 defer gpa.free(mem_code);835 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
845 const vaddr = sym.value + slide;838 const vaddr = sym.value + slide;
846 const pvaddr = @as(*anyopaque, @ptrFromInt(vaddr));839 const pvaddr = @as(*anyopaque, @ptrFromInt(vaddr));
...@@ -863,8 +856,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {...@@ -863,8 +856,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
863 }856 }
864 }857 }
865858
866 self.resolveRelocs(atom_index, relocs.items, code, self.image_base);859 coff.resolveRelocs(atom_index, relocs.items, code, coff.image_base);
867 try self.base.file.?.pwriteAll(code, file_offset);860 try coff.base.file.?.pwriteAll(code, file_offset);
868861
869 // Now we can mark the relocs as resolved.862 // Now we can mark the relocs as resolved.
870 while (relocs.popOrNull()) |reloc| {863 while (relocs.popOrNull()) |reloc| {
...@@ -893,46 +886,46 @@ fn writeMem(handle: std.process.Child.Id, pvaddr: std.os.windows.LPVOID, code: [...@@ -893,46 +886,46 @@ fn writeMem(handle: std.process.Child.Id, pvaddr: std.os.windows.LPVOID, code: [
893 if (amt != code.len) return error.InputOutput;886 if (amt != code.len) return error.InputOutput;
894}887}
895888
896fn writeOffsetTableEntry(self: *Coff, index: usize) !void {889fn writeOffsetTableEntry(coff: *Coff, index: usize) !void {
897 const sect_id = self.got_section_index.?;890 const sect_id = coff.got_section_index.?;
898891
899 if (self.got_table_count_dirty) {892 if (coff.got_table_count_dirty) {
900 const needed_size = @as(u32, @intCast(self.got_table.entries.items.len * self.ptr_width.size()));893 const needed_size = @as(u32, @intCast(coff.got_table.entries.items.len * coff.ptr_width.size()));
901 try self.growSection(sect_id, needed_size);894 try coff.growSection(sect_id, needed_size);
902 self.got_table_count_dirty = false;895 coff.got_table_count_dirty = false;
903 }896 }
904897
905 const header = &self.sections.items(.header)[sect_id];898 const header = &coff.sections.items(.header)[sect_id];
906 const entry = self.got_table.entries.items[index];899 const entry = coff.got_table.entries.items[index];
907 const entry_value = self.getSymbol(entry).value;900 const entry_value = coff.getSymbol(entry).value;
908 const entry_offset = index * self.ptr_width.size();901 const entry_offset = index * coff.ptr_width.size();
909 const file_offset = header.pointer_to_raw_data + entry_offset;902 const file_offset = header.pointer_to_raw_data + entry_offset;
910 const vmaddr = header.virtual_address + entry_offset;903 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) {
915 .p32 => {908 .p32 => {
916 var buf: [4]u8 = undefined;909 var buf: [4]u8 = undefined;
917 mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + self.image_base)), .little);910 mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + coff.image_base)), .little);
918 try self.base.file.?.pwriteAll(&buf, file_offset);911 try coff.base.file.?.pwriteAll(&buf, file_offset);
919 },912 },
920 .p64 => {913 .p64 => {
921 var buf: [8]u8 = undefined;914 var buf: [8]u8 = undefined;
922 mem.writeInt(u64, &buf, entry_value + self.image_base, .little);915 mem.writeInt(u64, &buf, entry_value + coff.image_base, .little);
923 try self.base.file.?.pwriteAll(&buf, file_offset);916 try coff.base.file.?.pwriteAll(&buf, file_offset);
924 },917 },
925 }918 }
926919
927 if (is_hot_update_compatible) {920 if (is_hot_update_compatible) {
928 if (self.base.child_pid) |handle| {921 if (coff.base.child_pid) |handle| {
929 const gpa = self.base.comp.gpa;922 const gpa = coff.base.comp.gpa;
930 const slide = @intFromPtr(self.hot_state.loaded_base_address.?);923 const slide = @intFromPtr(coff.hot_state.loaded_base_address.?);
931 const actual_vmaddr = vmaddr + slide;924 const actual_vmaddr = vmaddr + slide;
932 const pvaddr = @as(*anyopaque, @ptrFromInt(actual_vmaddr));925 const pvaddr = @as(*anyopaque, @ptrFromInt(actual_vmaddr));
933 log.debug("writing GOT entry to memory at address {x}", .{actual_vmaddr});926 log.debug("writing GOT entry to memory at address {x}", .{actual_vmaddr});
934 if (build_options.enable_logging) {927 if (build_options.enable_logging) {
935 switch (self.ptr_width) {928 switch (coff.ptr_width) {
936 .p32 => {929 .p32 => {
937 var buf: [4]u8 = undefined;930 var buf: [4]u8 = undefined;
938 try debugMem(gpa, handle, pvaddr, &buf);931 try debugMem(gpa, handle, pvaddr, &buf);
...@@ -944,7 +937,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {...@@ -944,7 +937,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
944 }937 }
945 }938 }
946939
947 switch (self.ptr_width) {940 switch (coff.ptr_width) {
948 .p32 => {941 .p32 => {
949 var buf: [4]u8 = undefined;942 var buf: [4]u8 = undefined;
950 mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + slide)), .little);943 mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + slide)), .little);
...@@ -964,9 +957,9 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {...@@ -964,9 +957,9 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
964 }957 }
965}958}
966959
967fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {960fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void {
968 // TODO: reverse-lookup might come in handy here961 // TODO: reverse-lookup might come in handy here
969 for (self.relocs.values()) |*relocs| {962 for (coff.relocs.values()) |*relocs| {
970 for (relocs.items) |*reloc| {963 for (relocs.items) |*reloc| {
971 if (!reloc.target.eql(target)) continue;964 if (!reloc.target.eql(target)) continue;
972 reloc.dirty = true;965 reloc.dirty = true;
...@@ -974,71 +967,71 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {...@@ -974,71 +967,71 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {
974 }967 }
975}968}
976969
977fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {970fn markRelocsDirtyByAddress(coff: *Coff, addr: u32) void {
978 const got_moved = blk: {971 const got_moved = blk: {
979 const sect_id = self.got_section_index orelse break :blk false;972 const sect_id = coff.got_section_index orelse break :blk false;
980 break :blk self.sections.items(.header)[sect_id].virtual_address >= addr;973 break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr;
981 };974 };
982975
983 // TODO: dirty relocations targeting import table if that got moved in memory976 // 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| {
986 for (relocs.items) |*reloc| {979 for (relocs.items) |*reloc| {
987 if (reloc.isGotIndirection()) {980 if (reloc.isGotIndirection()) {
988 reloc.dirty = reloc.dirty or got_moved;981 reloc.dirty = reloc.dirty or got_moved;
989 } else {982 } else {
990 const target_vaddr = reloc.getTargetAddress(self) orelse continue;983 const target_vaddr = reloc.getTargetAddress(coff) orelse continue;
991 if (target_vaddr >= addr) reloc.dirty = true;984 if (target_vaddr >= addr) reloc.dirty = true;
992 }985 }
993 }986 }
994 }987 }
995988
996 // TODO: dirty only really affected GOT cells989 // TODO: dirty only really affected GOT cells
997 for (self.got_table.entries.items) |entry| {990 for (coff.got_table.entries.items) |entry| {
998 const target_addr = self.getSymbol(entry).value;991 const target_addr = coff.getSymbol(entry).value;
999 if (target_addr >= addr) {992 if (target_addr >= addr) {
1000 self.got_table_contents_dirty = true;993 coff.got_table_contents_dirty = true;
1001 break;994 break;
1002 }995 }
1003 }996 }
1004}997}
1005998
1006fn resolveRelocs(self: *Coff, atom_index: Atom.Index, relocs: []*const Relocation, code: []u8, image_base: u64) void {999fn resolveRelocs(coff: *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)});1000 log.debug("relocating '{s}'", .{coff.getAtom(atom_index).getName(coff)});
1008 for (relocs) |reloc| {1001 for (relocs) |reloc| {
1009 reloc.resolve(atom_index, code, image_base, self);1002 reloc.resolve(atom_index, code, image_base, coff);
1010 }1003 }
1011}1004}
10121005
1013pub fn ptraceAttach(self: *Coff, handle: std.process.Child.Id) !void {1006pub fn ptraceAttach(coff: *Coff, handle: std.process.Child.Id) !void {
1014 if (!is_hot_update_compatible) return;1007 if (!is_hot_update_compatible) return;
10151008
1016 log.debug("attaching to process with handle {*}", .{handle});1009 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| {
1018 log.warn("failed to get base address for the process with error: {s}", .{@errorName(err)});1011 log.warn("failed to get base address for the process with error: {s}", .{@errorName(err)});
1019 return;1012 return;
1020 };1013 };
1021}1014}
10221015
1023pub fn ptraceDetach(self: *Coff, handle: std.process.Child.Id) void {1016pub fn ptraceDetach(coff: *Coff, handle: std.process.Child.Id) void {
1024 if (!is_hot_update_compatible) return;1017 if (!is_hot_update_compatible) return;
10251018
1026 log.debug("detaching from process with handle {*}", .{handle});1019 log.debug("detaching from process with handle {*}", .{handle});
1027 self.hot_state.loaded_base_address = null;1020 coff.hot_state.loaded_base_address = null;
1028}1021}
10291022
1030fn freeAtom(self: *Coff, atom_index: Atom.Index) void {1023fn freeAtom(coff: *Coff, atom_index: Atom.Index) void {
1031 log.debug("freeAtom {d}", .{atom_index});1024 log.debug("freeAtom {d}", .{atom_index});
10321025
1033 const gpa = self.base.comp.gpa;1026 const gpa = coff.base.comp.gpa;
10341027
1035 // Remove any relocs and base relocs associated with this Atom1028 // 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);1031 const atom = coff.getAtom(atom_index);
1039 const sym = atom.getSymbol(self);1032 const sym = atom.getSymbol(coff);
1040 const sect_id = @intFromEnum(sym.section_number) - 1;1033 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];
1042 var already_have_free_list_node = false;1035 var already_have_free_list_node = false;
1043 {1036 {
1044 var i: usize = 0;1037 var i: usize = 0;
...@@ -1055,7 +1048,7 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void {...@@ -1055,7 +1048,7 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
1055 }1048 }
1056 }1049 }
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];
1059 if (maybe_last_atom_index.*) |last_atom_index| {1052 if (maybe_last_atom_index.*) |last_atom_index| {
1060 if (last_atom_index == atom_index) {1053 if (last_atom_index == atom_index) {
1061 if (atom.prev_index) |prev_index| {1054 if (atom.prev_index) |prev_index| {
...@@ -1068,42 +1061,42 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void {...@@ -1068,42 +1061,42 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
1068 }1061 }
10691062
1070 if (atom.prev_index) |prev_index| {1063 if (atom.prev_index) |prev_index| {
1071 const prev = self.getAtomPtr(prev_index);1064 const prev = coff.getAtomPtr(prev_index);
1072 prev.next_index = atom.next_index;1065 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)) {
1075 // The free list is heuristics, it doesn't have to be perfect, so we can1068 // The free list is heuristics, it doesn't have to be perfect, so we can
1076 // ignore the OOM here.1069 // ignore the OOM here.
1077 free_list.append(gpa, prev_index) catch {};1070 free_list.append(gpa, prev_index) catch {};
1078 }1071 }
1079 } else {1072 } else {
1080 self.getAtomPtr(atom_index).prev_index = null;1073 coff.getAtomPtr(atom_index).prev_index = null;
1081 }1074 }
10821075
1083 if (atom.next_index) |next_index| {1076 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;
1085 } else {1078 } else {
1086 self.getAtomPtr(atom_index).next_index = null;1079 coff.getAtomPtr(atom_index).next_index = null;
1087 }1080 }
10881081
1089 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.1082 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
1090 const sym_index = atom.getSymbolIndex().?;1083 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
1093 // Try freeing GOT atom if this decl had one1086 // 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;1089 coff.locals.items[sym_index].section_number = .UNDEFINED;
1097 _ = self.atom_by_index_table.remove(sym_index);1090 _ = coff.atom_by_index_table.remove(sym_index);
1098 log.debug(" adding local symbol index {d} to free list", .{sym_index});1091 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;
1100}1093}
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 {
1103 if (build_options.skip_non_native and builtin.object_format != .coff) {1096 if (build_options.skip_non_native and builtin.object_format != .coff) {
1104 @panic("Attempted to compile for object format that was disabled by build configuration");1097 @panic("Attempted to compile for object format that was disabled by build configuration");
1105 }1098 }
1106 if (self.llvm_object) |llvm_object| {1099 if (coff.llvm_object) |llvm_object| {
1107 return llvm_object.updateFunc(pt, func_index, air, liveness);1100 return llvm_object.updateFunc(pt, func_index, air, liveness);
1108 }1101 }
1109 const tracy = trace(@src());1102 const tracy = trace(@src());
...@@ -1113,14 +1106,14 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,...@@ -1113,14 +1106,14 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
1113 const gpa = zcu.gpa;1106 const gpa = zcu.gpa;
1114 const func = zcu.funcInfo(func_index);1107 const func = zcu.funcInfo(func_index);
11151108
1116 const atom_index = try self.getOrCreateAtomForNav(func.owner_nav);1109 const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav);
1117 Atom.freeRelocations(self, atom_index);1110 coff.freeRelocations(atom_index);
11181111
1119 var code_buffer = std.ArrayList(u8).init(gpa);1112 var code_buffer = std.ArrayList(u8).init(gpa);
1120 defer code_buffer.deinit();1113 defer code_buffer.deinit();
11211114
1122 const res = try codegen.generateFunction(1115 const res = try codegen.generateFunction(
1123 &self.base,1116 &coff.base,
1124 pt,1117 pt,
1125 zcu.navSrcLoc(func.owner_nav),1118 zcu.navSrcLoc(func.owner_nav),
1126 func_index,1119 func_index,
...@@ -1137,7 +1130,7 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,...@@ -1137,7 +1130,7 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
1137 },1130 },
1138 };1131 };
11391132
1140 try self.updateNavCode(pt, func.owner_nav, code, .FUNCTION);1133 try coff.updateNavCode(pt, func.owner_nav, code, .FUNCTION);
11411134
1142 // Exports will be updated by `Zcu.processExports` after the update.1135 // Exports will be updated by `Zcu.processExports` after the update.
1143}1136}
...@@ -1148,7 +1141,7 @@ const LowerConstResult = union(enum) {...@@ -1148,7 +1141,7 @@ const LowerConstResult = union(enum) {
1148};1141};
11491142
1150fn lowerConst(1143fn lowerConst(
1151 self: *Coff,1144 coff: *Coff,
1152 pt: Zcu.PerThread,1145 pt: Zcu.PerThread,
1153 name: []const u8,1146 name: []const u8,
1154 val: Value,1147 val: Value,
...@@ -1156,50 +1149,50 @@ fn lowerConst(...@@ -1156,50 +1149,50 @@ fn lowerConst(
1156 sect_id: u16,1149 sect_id: u16,
1157 src_loc: Zcu.LazySrcLoc,1150 src_loc: Zcu.LazySrcLoc,
1158) !LowerConstResult {1151) !LowerConstResult {
1159 const gpa = self.base.comp.gpa;1152 const gpa = coff.base.comp.gpa;
11601153
1161 var code_buffer = std.ArrayList(u8).init(gpa);1154 var code_buffer = std.ArrayList(u8).init(gpa);
1162 defer code_buffer.deinit();1155 defer code_buffer.deinit();
11631156
1164 const atom_index = try self.createAtom();1157 const atom_index = try coff.createAtom();
1165 const sym = self.getAtom(atom_index).getSymbolPtr(self);1158 const sym = coff.getAtom(atom_index).getSymbolPtr(coff);
1166 try self.setSymbolName(sym, name);1159 try coff.setSymbolName(sym, name);
1167 sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1));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, .{1162 const res = try codegen.generateSymbol(&coff.base, pt, src_loc, val, &code_buffer, .{
1170 .atom_index = self.getAtom(atom_index).getSymbolIndex().?,1163 .atom_index = coff.getAtom(atom_index).getSymbolIndex().?,
1171 });1164 });
1172 const code = switch (res) {1165 const code = switch (res) {
1173 .ok => code_buffer.items,1166 .ok => code_buffer.items,
1174 .fail => |em| return .{ .fail = em },1167 .fail => |em| return .{ .fail = em },
1175 };1168 };
11761169
1177 const atom = self.getAtomPtr(atom_index);1170 const atom = coff.getAtomPtr(atom_index);
1178 atom.size = @as(u32, @intCast(code.len));1171 atom.size = @as(u32, @intCast(code.len));
1179 atom.getSymbolPtr(self).value = try self.allocateAtom(1172 atom.getSymbolPtr(coff).value = try coff.allocateAtom(
1180 atom_index,1173 atom_index,
1181 atom.size,1174 atom.size,
1182 @intCast(required_alignment.toByteUnits().?),1175 @intCast(required_alignment.toByteUnits().?),
1183 );1176 );
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 });
1187 log.debug(" (required alignment 0x{x})", .{required_alignment});1180 log.debug(" (required alignment 0x{x})", .{required_alignment});
11881181
1189 try self.writeAtom(atom_index, code);1182 try coff.writeAtom(atom_index, code);
11901183
1191 return .{ .ok = atom_index };1184 return .{ .ok = atom_index };
1192}1185}
11931186
1194pub fn updateNav(1187pub fn updateNav(
1195 self: *Coff,1188 coff: *Coff,
1196 pt: Zcu.PerThread,1189 pt: Zcu.PerThread,
1197 nav_index: InternPool.Nav.Index,1190 nav_index: InternPool.Nav.Index,
1198) link.File.UpdateNavError!void {1191) link.File.UpdateNavError!void {
1199 if (build_options.skip_non_native and builtin.object_format != .coff) {1192 if (build_options.skip_non_native and builtin.object_format != .coff) {
1200 @panic("Attempted to compile for object format that was disabled by build configuration");1193 @panic("Attempted to compile for object format that was disabled by build configuration");
1201 }1194 }
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);
1203 const tracy = trace(@src());1196 const tracy = trace(@src());
1204 defer tracy.end();1197 defer tracy.end();
12051198
...@@ -1217,23 +1210,23 @@ pub fn updateNav(...@@ -1217,23 +1210,23 @@ pub fn updateNav(
1217 // TODO make this part of getGlobalSymbol1210 // TODO make this part of getGlobalSymbol
1218 const name = nav.name.toSlice(ip);1211 const name = nav.name.toSlice(ip);
1219 const lib_name = @"extern".lib_name.toSlice(ip);1212 const lib_name = @"extern".lib_name.toSlice(ip);
1220 const global_index = try self.getGlobalSymbol(name, lib_name);1213 const global_index = try coff.getGlobalSymbol(name, lib_name);
1221 try self.need_got_table.put(gpa, global_index, {});1214 try coff.need_got_table.put(gpa, global_index, {});
1222 return;1215 return;
1223 },1216 },
1224 else => nav_val,1217 else => nav_val,
1225 };1218 };
12261219
1227 if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {1220 if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
1228 const atom_index = try self.getOrCreateAtomForNav(nav_index);1221 const atom_index = try coff.getOrCreateAtomForNav(nav_index);
1229 Atom.freeRelocations(self, atom_index);1222 coff.freeRelocations(atom_index);
1230 const atom = self.getAtom(atom_index);1223 const atom = coff.getAtom(atom_index);
12311224
1232 var code_buffer = std.ArrayList(u8).init(gpa);1225 var code_buffer = std.ArrayList(u8).init(gpa);
1233 defer code_buffer.deinit();1226 defer code_buffer.deinit();
12341227
1235 const res = try codegen.generateSymbol(1228 const res = try codegen.generateSymbol(
1236 &self.base,1229 &coff.base,
1237 pt,1230 pt,
1238 zcu.navSrcLoc(nav_index),1231 zcu.navSrcLoc(nav_index),
1239 nav_init,1232 nav_init,
...@@ -1248,14 +1241,14 @@ pub fn updateNav(...@@ -1248,14 +1241,14 @@ pub fn updateNav(
1248 },1241 },
1249 };1242 };
12501243
1251 try self.updateNavCode(pt, nav_index, code, .NULL);1244 try coff.updateNavCode(pt, nav_index, code, .NULL);
1252 }1245 }
12531246
1254 // Exports will be updated by `Zcu.processExports` after the update.1247 // Exports will be updated by `Zcu.processExports` after the update.
1255}1248}
12561249
1257fn updateLazySymbolAtom(1250fn updateLazySymbolAtom(
1258 self: *Coff,1251 coff: *Coff,
1259 pt: Zcu.PerThread,1252 pt: Zcu.PerThread,
1260 sym: link.File.LazySymbol,1253 sym: link.File.LazySymbol,
1261 atom_index: Atom.Index,1254 atom_index: Atom.Index,
...@@ -1268,18 +1261,18 @@ fn updateLazySymbolAtom(...@@ -1268,18 +1261,18 @@ fn updateLazySymbolAtom(
1268 var code_buffer = std.ArrayList(u8).init(gpa);1261 var code_buffer = std.ArrayList(u8).init(gpa);
1269 defer code_buffer.deinit();1262 defer code_buffer.deinit();
12701263
1271 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{1264 const name = try allocPrint(gpa, "__lazy_{s}_{}", .{
1272 @tagName(sym.kind),1265 @tagName(sym.kind),
1273 Type.fromInterned(sym.ty).fmt(pt),1266 Type.fromInterned(sym.ty).fmt(pt),
1274 });1267 });
1275 defer gpa.free(name);1268 defer gpa.free(name);
12761269
1277 const atom = self.getAtomPtr(atom_index);1270 const atom = coff.getAtomPtr(atom_index);
1278 const local_sym_index = atom.getSymbolIndex().?;1271 const local_sym_index = atom.getSymbolIndex().?;
12791272
1280 const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded;1273 const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded;
1281 const res = try codegen.generateLazySymbol(1274 const res = try codegen.generateLazySymbol(
1282 &self.base,1275 &coff.base,
1283 pt,1276 pt,
1284 src,1277 src,
1285 sym,1278 sym,
...@@ -1297,13 +1290,13 @@ fn updateLazySymbolAtom(...@@ -1297,13 +1290,13 @@ fn updateLazySymbolAtom(
1297 };1290 };
12981291
1299 const code_len: u32 = @intCast(code.len);1292 const code_len: u32 = @intCast(code.len);
1300 const symbol = atom.getSymbolPtr(self);1293 const symbol = atom.getSymbolPtr(coff);
1301 try self.setSymbolName(symbol, name);1294 try coff.setSymbolName(symbol, name);
1302 symbol.section_number = @enumFromInt(section_index + 1);1295 symbol.section_number = @enumFromInt(section_index + 1);
1303 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };1296 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));1298 const vaddr = try coff.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
1306 errdefer self.freeAtom(atom_index);1299 errdefer coff.freeAtom(atom_index);
13071300
1308 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });1301 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
1309 log.debug(" (required alignment 0x{x})", .{required_alignment});1302 log.debug(" (required alignment 0x{x})", .{required_alignment});
...@@ -1311,52 +1304,52 @@ fn updateLazySymbolAtom(...@@ -1311,52 +1304,52 @@ fn updateLazySymbolAtom(
1311 atom.size = code_len;1304 atom.size = code_len;
1312 symbol.value = vaddr;1305 symbol.value = vaddr;
13131306
1314 try self.addGotEntry(.{ .sym_index = local_sym_index });1307 try coff.addGotEntry(.{ .sym_index = local_sym_index });
1315 try self.writeAtom(atom_index, code);1308 try coff.writeAtom(atom_index, code);
1316}1309}
13171310
1318pub fn getOrCreateAtomForLazySymbol(1311pub fn getOrCreateAtomForLazySymbol(
1319 self: *Coff,1312 coff: *Coff,
1320 pt: Zcu.PerThread,1313 pt: Zcu.PerThread,
1321 lazy_sym: link.File.LazySymbol,1314 lazy_sym: link.File.LazySymbol,
1322) !Atom.Index {1315) !Atom.Index {
1323 const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);1316 const gop = try coff.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);
1324 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();1317 errdefer _ = if (!gop.found_existing) coff.lazy_syms.pop();
1325 if (!gop.found_existing) gop.value_ptr.* = .{};1318 if (!gop.found_existing) gop.value_ptr.* = .{};
1326 const atom_ptr, const state_ptr = switch (lazy_sym.kind) {1319 const atom_ptr, const state_ptr = switch (lazy_sym.kind) {
1327 .code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state },1320 .code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state },
1328 .const_data => .{ &gop.value_ptr.rdata_atom, &gop.value_ptr.rdata_state },1321 .const_data => .{ &gop.value_ptr.rdata_atom, &gop.value_ptr.rdata_state },
1329 };1322 };
1330 switch (state_ptr.*) {1323 switch (state_ptr.*) {
1331 .unused => atom_ptr.* = try self.createAtom(),1324 .unused => atom_ptr.* = try coff.createAtom(),
1332 .pending_flush => return atom_ptr.*,1325 .pending_flush => return atom_ptr.*,
1333 .flushed => {},1326 .flushed => {},
1334 }1327 }
1335 state_ptr.* = .pending_flush;1328 state_ptr.* = .pending_flush;
1336 const atom = atom_ptr.*;1329 const atom = atom_ptr.*;
1337 // anyerror needs to be deferred until flushModule1330 // 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) {1331 if (lazy_sym.ty != .anyerror_type) try coff.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) {
1339 .code => self.text_section_index.?,1332 .code => coff.text_section_index.?,
1340 .const_data => self.rdata_section_index.?,1333 .const_data => coff.rdata_section_index.?,
1341 });1334 });
1342 return atom;1335 return atom;
1343}1336}
13441337
1345pub fn getOrCreateAtomForNav(self: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index {1338pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index {
1346 const gpa = self.base.comp.gpa;1339 const gpa = coff.base.comp.gpa;
1347 const gop = try self.navs.getOrPut(gpa, nav_index);1340 const gop = try coff.navs.getOrPut(gpa, nav_index);
1348 if (!gop.found_existing) {1341 if (!gop.found_existing) {
1349 gop.value_ptr.* = .{1342 gop.value_ptr.* = .{
1350 .atom = try self.createAtom(),1343 .atom = try coff.createAtom(),
1351 .section = self.getNavOutputSection(nav_index),1344 .section = coff.getNavOutputSection(nav_index),
1352 .exports = .{},1345 .exports = .{},
1353 };1346 };
1354 }1347 }
1355 return gop.value_ptr.atom;1348 return gop.value_ptr.atom;
1356}1349}
13571350
1358fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {1351fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 {
1359 const zcu = self.base.comp.zcu.?;1352 const zcu = coff.base.comp.zcu.?;
1360 const ip = &zcu.intern_pool;1353 const ip = &zcu.intern_pool;
1361 const nav = ip.getNav(nav_index);1354 const nav = ip.getNav(nav_index);
1362 const ty = Type.fromInterned(nav.typeOf(ip));1355 const ty = Type.fromInterned(nav.typeOf(ip));
...@@ -1365,17 +1358,17 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {...@@ -1365,17 +1358,17 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {
1365 const index: u16 = blk: {1358 const index: u16 = blk: {
1366 if (val.isUndefDeep(zcu)) {1359 if (val.isUndefDeep(zcu)) {
1367 // TODO in release-fast and release-small, we should put undef in .bss1360 // 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.?;
1369 }1362 }
13701363
1371 switch (zig_ty) {1364 switch (zig_ty) {
1372 // TODO: what if this is a function pointer?1365 // TODO: what if this is a function pointer?
1373 .@"fn" => break :blk self.text_section_index.?,1366 .@"fn" => break :blk coff.text_section_index.?,
1374 else => {1367 else => {
1375 if (val.getVariable(zcu)) |_| {1368 if (val.getVariable(zcu)) |_| {
1376 break :blk self.data_section_index.?;1369 break :blk coff.data_section_index.?;
1377 }1370 }
1378 break :blk self.rdata_section_index.?;1371 break :blk coff.rdata_section_index.?;
1379 },1372 },
1380 }1373 }
1381 };1374 };
...@@ -1383,11 +1376,11 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {...@@ -1383,11 +1376,11 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 {
1383}1376}
13841377
1385fn updateNavCode(1378fn updateNavCode(
1386 self: *Coff,1379 coff: *Coff,
1387 pt: Zcu.PerThread,1380 pt: Zcu.PerThread,
1388 nav_index: InternPool.Nav.Index,1381 nav_index: InternPool.Nav.Index,
1389 code: []u8,1382 code: []u8,
1390 complex_type: coff.ComplexType,1383 complex_type: coff_util.ComplexType,
1391) !void {1384) !void {
1392 const zcu = pt.zcu;1385 const zcu = pt.zcu;
1393 const ip = &zcu.intern_pool;1386 const ip = &zcu.intern_pool;
...@@ -1399,70 +1392,70 @@ fn updateNavCode(...@@ -1399,70 +1392,70 @@ fn updateNavCode(
1399 target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),1392 target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
1400 );1393 );
14011394
1402 const nav_metadata = self.navs.get(nav_index).?;1395 const nav_metadata = coff.navs.get(nav_index).?;
1403 const atom_index = nav_metadata.atom;1396 const atom_index = nav_metadata.atom;
1404 const atom = self.getAtom(atom_index);1397 const atom = coff.getAtom(atom_index);
1405 const sym_index = atom.getSymbolIndex().?;1398 const sym_index = atom.getSymbolIndex().?;
1406 const sect_index = nav_metadata.section;1399 const sect_index = nav_metadata.section;
1407 const code_len = @as(u32, @intCast(code.len));1400 const code_len = @as(u32, @intCast(code.len));
14081401
1409 if (atom.size != 0) {1402 if (atom.size != 0) {
1410 const sym = atom.getSymbolPtr(self);1403 const sym = atom.getSymbolPtr(coff);
1411 try self.setSymbolName(sym, nav.fqn.toSlice(ip));1404 try coff.setSymbolName(sym, nav.fqn.toSlice(ip));
1412 sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1));1405 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_index + 1));
1413 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };1406 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
14141407
1415 const capacity = atom.capacity(self);1408 const capacity = atom.capacity(coff);
1416 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);1409 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
1417 if (need_realloc) {1410 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));
1419 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr });1412 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr });
1420 log.debug(" (required alignment 0x{x}", .{required_alignment});1413 log.debug(" (required alignment 0x{x}", .{required_alignment});
14211414
1422 if (vaddr != sym.value) {1415 if (vaddr != sym.value) {
1423 sym.value = vaddr;1416 sym.value = vaddr;
1424 log.debug(" (updating GOT entry)", .{});1417 log.debug(" (updating GOT entry)", .{});
1425 const got_entry_index = self.got_table.lookup.get(.{ .sym_index = sym_index }).?;1418 const got_entry_index = coff.got_table.lookup.get(.{ .sym_index = sym_index }).?;
1426 try self.writeOffsetTableEntry(got_entry_index);1419 try coff.writeOffsetTableEntry(got_entry_index);
1427 self.markRelocsDirtyByTarget(.{ .sym_index = sym_index });1420 coff.markRelocsDirtyByTarget(.{ .sym_index = sym_index });
1428 }1421 }
1429 } else if (code_len < atom.size) {1422 } else if (code_len < atom.size) {
1430 self.shrinkAtom(atom_index, code_len);1423 coff.shrinkAtom(atom_index, code_len);
1431 }1424 }
1432 self.getAtomPtr(atom_index).size = code_len;1425 coff.getAtomPtr(atom_index).size = code_len;
1433 } else {1426 } else {
1434 const sym = atom.getSymbolPtr(self);1427 const sym = atom.getSymbolPtr(coff);
1435 try self.setSymbolName(sym, nav.fqn.toSlice(ip));1428 try coff.setSymbolName(sym, nav.fqn.toSlice(ip));
1436 sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1));1429 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_index + 1));
1437 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };1430 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));1432 const vaddr = try coff.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
1440 errdefer self.freeAtom(atom_index);1433 errdefer coff.freeAtom(atom_index);
1441 log.debug("allocated atom for {} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr });1434 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;
1443 sym.value = vaddr;1436 sym.value = vaddr;
14441437
1445 try self.addGotEntry(.{ .sym_index = sym_index });1438 try coff.addGotEntry(.{ .sym_index = sym_index });
1446 }1439 }
14471440
1448 try self.writeAtom(atom_index, code);1441 try coff.writeAtom(atom_index, code);
1449}1442}
14501443
1451pub fn freeNav(self: *Coff, nav_index: InternPool.NavIndex) void {1444pub fn freeNav(coff: *Coff, nav_index: InternPool.NavIndex) void {
1452 if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index);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;
1455 log.debug("freeDecl 0x{x}", .{nav_index});1448 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| {
1458 var kv = const_kv;1451 var kv = const_kv;
1459 self.freeAtom(kv.value.atom);1452 coff.freeAtom(kv.value.atom);
1460 kv.value.exports.deinit(gpa);1453 kv.value.exports.deinit(gpa);
1461 }1454 }
1462}1455}
14631456
1464pub fn updateExports(1457pub fn updateExports(
1465 self: *Coff,1458 coff: *Coff,
1466 pt: Zcu.PerThread,1459 pt: Zcu.PerThread,
1467 exported: Zcu.Exported,1460 exported: Zcu.Exported,
1468 export_indices: []const u32,1461 export_indices: []const u32,
...@@ -1473,7 +1466,7 @@ pub fn updateExports(...@@ -1473,7 +1466,7 @@ pub fn updateExports(
14731466
1474 const zcu = pt.zcu;1467 const zcu = pt.zcu;
1475 const ip = &zcu.intern_pool;1468 const ip = &zcu.intern_pool;
1476 const comp = self.base.comp;1469 const comp = coff.base.comp;
1477 const target = comp.root_mod.resolved_target.result;1470 const target = comp.root_mod.resolved_target.result;
14781471
1479 if (comp.config.use_llvm) {1472 if (comp.config.use_llvm) {
...@@ -1513,18 +1506,18 @@ pub fn updateExports(...@@ -1513,18 +1506,18 @@ pub fn updateExports(
1513 }1506 }
1514 }1507 }
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
1518 const gpa = comp.gpa;1511 const gpa = comp.gpa;
15191512
1520 const metadata = switch (exported) {1513 const metadata = switch (exported) {
1521 .nav => |nav| blk: {1514 .nav => |nav| blk: {
1522 _ = try self.getOrCreateAtomForNav(nav);1515 _ = try coff.getOrCreateAtomForNav(nav);
1523 break :blk self.navs.getPtr(nav).?;1516 break :blk coff.navs.getPtr(nav).?;
1524 },1517 },
1525 .uav => |uav| self.uavs.getPtr(uav) orelse blk: {1518 .uav => |uav| coff.uavs.getPtr(uav) orelse blk: {
1526 const first_exp = zcu.all_exports.items[export_indices[0]];1519 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);
1528 switch (res) {1521 switch (res) {
1529 .mcv => {},1522 .mcv => {},
1530 .fail => |em| {1523 .fail => |em| {
...@@ -1535,11 +1528,11 @@ pub fn updateExports(...@@ -1535,11 +1528,11 @@ pub fn updateExports(
1535 return;1528 return;
1536 },1529 },
1537 }1530 }
1538 break :blk self.uavs.getPtr(uav).?;1531 break :blk coff.uavs.getPtr(uav).?;
1539 },1532 },
1540 };1533 };
1541 const atom_index = metadata.atom;1534 const atom_index = metadata.atom;
1542 const atom = self.getAtom(atom_index);1535 const atom = coff.getAtom(atom_index);
15431536
1544 for (export_indices) |export_idx| {1537 for (export_indices) |export_idx| {
1545 const exp = zcu.all_exports.items[export_idx];1538 const exp = zcu.all_exports.items[export_idx];
...@@ -1568,27 +1561,27 @@ pub fn updateExports(...@@ -1568,27 +1561,27 @@ pub fn updateExports(
1568 }1561 }
15691562
1570 const exp_name = exp.opts.name.toSlice(&zcu.intern_pool);1563 const exp_name = exp.opts.name.toSlice(&zcu.intern_pool);
1571 const sym_index = metadata.getExport(self, exp_name) orelse blk: {1564 const sym_index = metadata.getExport(coff, exp_name) orelse blk: {
1572 const sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: {1565 const sym_index = if (coff.getGlobalIndex(exp_name)) |global_index| ind: {
1573 const global = self.globals.items[global_index];1566 const global = coff.globals.items[global_index];
1574 // TODO this is just plain wrong as it all should happen in a single `resolveSymbols`1567 // TODO this is just plain wrong as it all should happen in a single `resolveSymbols`
1575 // pass. This will go away once we abstact away Zig's incremental compilation into1568 // pass. This will go away once we abstact away Zig's incremental compilation into
1576 // its own module.1569 // its own module.
1577 if (global.file == null and self.getSymbol(global).section_number == .UNDEFINED) {1570 if (global.file == null and coff.getSymbol(global).section_number == .UNDEFINED) {
1578 _ = self.unresolved.swapRemove(global_index);1571 _ = coff.unresolved.swapRemove(global_index);
1579 break :ind global.sym_index;1572 break :ind global.sym_index;
1580 }1573 }
1581 break :ind try self.allocateSymbol();1574 break :ind try coff.allocateSymbol();
1582 } else try self.allocateSymbol();1575 } else try coff.allocateSymbol();
1583 try metadata.exports.append(gpa, sym_index);1576 try metadata.exports.append(gpa, sym_index);
1584 break :blk sym_index;1577 break :blk sym_index;
1585 };1578 };
1586 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };1579 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1587 const sym = self.getSymbolPtr(sym_loc);1580 const sym = coff.getSymbolPtr(sym_loc);
1588 try self.setSymbolName(sym, exp_name);1581 try coff.setSymbolName(sym, exp_name);
1589 sym.value = atom.getSymbol(self).value;1582 sym.value = atom.getSymbol(coff).value;
1590 sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1));1583 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1));
1591 sym.type = atom.getSymbol(self).type;1584 sym.type = atom.getSymbol(coff).type;
15921585
1593 switch (exp.opts.linkage) {1586 switch (exp.opts.linkage) {
1594 .strong => {1587 .strong => {
...@@ -1599,27 +1592,27 @@ pub fn updateExports(...@@ -1599,27 +1592,27 @@ pub fn updateExports(
1599 else => unreachable,1592 else => unreachable,
1600 }1593 }
16011594
1602 try self.resolveGlobalSymbol(sym_loc);1595 try coff.resolveGlobalSymbol(sym_loc);
1603 }1596 }
1604}1597}
16051598
1606pub fn deleteExport(1599pub fn deleteExport(
1607 self: *Coff,1600 coff: *Coff,
1608 exported: Zcu.Exported,1601 exported: Zcu.Exported,
1609 name: InternPool.NullTerminatedString,1602 name: InternPool.NullTerminatedString,
1610) void {1603) void {
1611 if (self.llvm_object) |_| return;1604 if (coff.llvm_object) |_| return;
1612 const metadata = switch (exported) {1605 const metadata = switch (exported) {
1613 .nav => |nav| self.navs.getPtr(nav),1606 .nav => |nav| coff.navs.getPtr(nav),
1614 .uav => |uav| self.uavs.getPtr(uav),1607 .uav => |uav| coff.uavs.getPtr(uav),
1615 } orelse return;1608 } orelse return;
1616 const zcu = self.base.comp.zcu.?;1609 const zcu = coff.base.comp.zcu.?;
1617 const name_slice = name.toSlice(&zcu.intern_pool);1610 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;
1621 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };1614 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
1622 const sym = self.getSymbolPtr(sym_loc);1615 const sym = coff.getSymbolPtr(sym_loc);
1623 log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)});1616 log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)});
1624 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);1617 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
1625 sym.* = .{1618 sym.* = .{
...@@ -1630,12 +1623,12 @@ pub fn deleteExport(...@@ -1630,12 +1623,12 @@ pub fn deleteExport(
1630 .storage_class = .NULL,1623 .storage_class = .NULL,
1631 .number_of_aux_symbols = 0,1624 .number_of_aux_symbols = 0,
1632 };1625 };
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| {
1636 defer gpa.free(entry.key);1629 defer gpa.free(entry.key);
1637 self.globals_free_list.append(gpa, entry.value) catch {};1630 coff.globals_free_list.append(gpa, entry.value) catch {};
1638 self.globals.items[entry.value] = .{1631 coff.globals.items[entry.value] = .{
1639 .sym_index = 0,1632 .sym_index = 0,
1640 .file = null,1633 .file = null,
1641 };1634 };
...@@ -1644,16 +1637,16 @@ pub fn deleteExport(...@@ -1644,16 +1637,16 @@ pub fn deleteExport(
1644 sym_index.* = 0;1637 sym_index.* = 0;
1645}1638}
16461639
1647fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {1640fn resolveGlobalSymbol(coff: *Coff, current: SymbolWithLoc) !void {
1648 const gpa = self.base.comp.gpa;1641 const gpa = coff.base.comp.gpa;
1649 const sym = self.getSymbol(current);1642 const sym = coff.getSymbol(current);
1650 const sym_name = self.getSymbolName(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);
1653 if (!gop.found_existing) {1646 if (!gop.found_existing) {
1654 gop.value_ptr.* = current;1647 gop.value_ptr.* = current;
1655 if (sym.section_number == .UNDEFINED) {1648 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);
1657 }1650 }
1658 return;1651 return;
1659 }1652 }
...@@ -1662,33 +1655,560 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {...@@ -1662,33 +1655,560 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
16621655
1663 if (sym.section_number == .UNDEFINED) return;1656 if (sym.section_number == .UNDEFINED) return;
16641657
1665 _ = self.unresolved.swapRemove(self.getGlobalIndex(sym_name).?);1658 _ = coff.unresolved.swapRemove(coff.getGlobalIndex(sym_name).?);
16661659
1667 gop.value_ptr.* = current;1660 gop.value_ptr.* = current;
1668}1661}
16691662
1670pub fn flush(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {1663pub fn flush(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
1671 const comp = self.base.comp;1664 const comp = coff.base.comp;
1672 const use_lld = build_options.have_llvm and comp.config.use_lld;1665 const use_lld = build_options.have_llvm and comp.config.use_lld;
1673 if (use_lld) {1666 if (use_lld) {
1674 return lld.linkWithLLD(self, arena, tid, prog_node);1667 return coff.linkWithLLD(arena, tid, prog_node);
1675 }1668 }
1676 switch (comp.config.output_mode) {1669 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),
1678 .Lib => return error.TODOImplementWritingLibFiles,1671 .Lib => return error.TODOImplementWritingLibFiles,
1679 }1672 }
1680}1673}
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
1683 const tracy = trace(@src());1678 const tracy = trace(@src());
1684 defer tracy.end();1679 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;
1687 const gpa = comp.gpa;2207 const gpa = comp.gpa;
1688 const diags = &comp.link_diags;2208 const diags = &comp.link_diags;
16892209
1690 if (self.llvm_object) |llvm_object| {2210 if (coff.llvm_object) |llvm_object| {
1691 try self.base.emitLlvmObject(arena, llvm_object, prog_node);2211 try coff.base.emitLlvmObject(arena, llvm_object, prog_node);
1692 return;2212 return;
1693 }2213 }
16942214
...@@ -1700,46 +2220,46 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -1700,46 +2220,46 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
1700 .tid = tid,2220 .tid = tid,
1701 };2221 };
17022222
1703 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {2223 if (coff.lazy_syms.getPtr(.anyerror_type)) |metadata| {
1704 // Most lazy symbols can be updated on first use, but2224 // Most lazy symbols can be updated on first use, but
1705 // anyerror needs to wait for everything to be flushed.2225 // 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(
1707 pt,2227 pt,
1708 .{ .kind = .code, .ty = .anyerror_type },2228 .{ .kind = .code, .ty = .anyerror_type },
1709 metadata.text_atom,2229 metadata.text_atom,
1710 self.text_section_index.?,2230 coff.text_section_index.?,
1711 ) catch |err| return switch (err) {2231 ) catch |err| return switch (err) {
1712 error.CodegenFail => error.FlushFailure,2232 error.CodegenFail => error.FlushFailure,
1713 else => |e| e,2233 else => |e| e,
1714 };2234 };
1715 if (metadata.rdata_state != .unused) self.updateLazySymbolAtom(2235 if (metadata.rdata_state != .unused) coff.updateLazySymbolAtom(
1716 pt,2236 pt,
1717 .{ .kind = .const_data, .ty = .anyerror_type },2237 .{ .kind = .const_data, .ty = .anyerror_type },
1718 metadata.rdata_atom,2238 metadata.rdata_atom,
1719 self.rdata_section_index.?,2239 coff.rdata_section_index.?,
1720 ) catch |err| return switch (err) {2240 ) catch |err| return switch (err) {
1721 error.CodegenFail => error.FlushFailure,2241 error.CodegenFail => error.FlushFailure,
1722 else => |e| e,2242 else => |e| e,
1723 };2243 };
1724 }2244 }
1725 for (self.lazy_syms.values()) |*metadata| {2245 for (coff.lazy_syms.values()) |*metadata| {
1726 if (metadata.text_state != .unused) metadata.text_state = .flushed;2246 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1727 if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;2247 if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;
1728 }2248 }
17292249
1730 {2250 {
1731 var it = self.need_got_table.iterator();2251 var it = coff.need_got_table.iterator();
1732 while (it.next()) |entry| {2252 while (it.next()) |entry| {
1733 const global = self.globals.items[entry.key_ptr.*];2253 const global = coff.globals.items[entry.key_ptr.*];
1734 try self.addGotEntry(global);2254 try coff.addGotEntry(global);
1735 }2255 }
1736 }2256 }
17372257
1738 while (self.unresolved.popOrNull()) |entry| {2258 while (coff.unresolved.popOrNull()) |entry| {
1739 assert(entry.value);2259 assert(entry.value);
1740 const global = self.globals.items[entry.key];2260 const global = coff.globals.items[entry.key];
1741 const sym = self.getSymbol(global);2261 const sym = coff.getSymbol(global);
1742 const res = try self.import_tables.getOrPut(gpa, sym.value);2262 const res = try coff.import_tables.getOrPut(gpa, sym.value);
1743 const itable = res.value_ptr;2263 const itable = res.value_ptr;
1744 if (!res.found_existing) {2264 if (!res.found_existing) {
1745 itable.* = .{};2265 itable.* = .{};
...@@ -1748,21 +2268,21 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -1748,21 +2268,21 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
1748 // TODO: we could technically write the pointer placeholder for to-be-bound import here,2268 // TODO: we could technically write the pointer placeholder for to-be-bound import here,
1749 // but since this happens in flush, there is currently no point.2269 // but since this happens in flush, there is currently no point.
1750 _ = try itable.addImport(gpa, global);2270 _ = try itable.addImport(gpa, global);
1751 self.imports_count_dirty = true;2271 coff.imports_count_dirty = true;
1752 }2272 }
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| {
1757 const needs_update = for (relocs.items) |reloc| {2277 const needs_update = for (relocs.items) |reloc| {
1758 if (reloc.dirty) break true;2278 if (reloc.dirty) break true;
1759 } else false;2279 } else false;
17602280
1761 if (!needs_update) continue;2281 if (!needs_update) continue;
17622282
1763 const atom = self.getAtom(atom_index);2283 const atom = coff.getAtom(atom_index);
1764 const sym = atom.getSymbol(self);2284 const sym = atom.getSymbol(coff);
1765 const section = self.sections.get(@intFromEnum(sym.section_number) - 1).header;2285 const section = coff.sections.get(@intFromEnum(sym.section_number) - 1).header;
1766 const file_offset = section.pointer_to_raw_data + sym.value - section.virtual_address;2286 const file_offset = section.pointer_to_raw_data + sym.value - section.virtual_address;
17672287
1768 var code = std.ArrayList(u8).init(gpa);2288 var code = std.ArrayList(u8).init(gpa);
...@@ -1770,70 +2290,70 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -1770,70 +2290,70 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
1770 try code.resize(math.cast(usize, atom.size) orelse return error.Overflow);2290 try code.resize(math.cast(usize, atom.size) orelse return error.Overflow);
1771 assert(atom.size > 0);2291 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);
1774 if (amt != code.items.len) return error.InputOutput;2294 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);
1777 }2297 }
17782298
1779 // Update GOT if it got moved in memory.2299 // Update GOT if it got moved in memory.
1780 if (self.got_table_contents_dirty) {2300 if (coff.got_table_contents_dirty) {
1781 for (self.got_table.entries.items, 0..) |entry, i| {2301 for (coff.got_table.entries.items, 0..) |entry, i| {
1782 if (!self.got_table.lookup.contains(entry)) continue;2302 if (!coff.got_table.lookup.contains(entry)) continue;
1783 // TODO: write all in one go rather than incrementally.2303 // TODO: write all in one go rather than incrementally.
1784 try self.writeOffsetTableEntry(i);2304 try coff.writeOffsetTableEntry(i);
1785 }2305 }
1786 self.got_table_contents_dirty = false;2306 coff.got_table_contents_dirty = false;
1787 }2307 }
17882308
1789 try self.writeBaseRelocations();2309 try coff.writeBaseRelocations();
17902310
1791 if (self.getEntryPoint()) |entry_sym_loc| {2311 if (coff.getEntryPoint()) |entry_sym_loc| {
1792 self.entry_addr = self.getSymbol(entry_sym_loc).value;2312 coff.entry_addr = coff.getSymbol(entry_sym_loc).value;
1793 }2313 }
17942314
1795 if (build_options.enable_logging) {2315 if (build_options.enable_logging) {
1796 self.logSymtab();2316 coff.logSymtab();
1797 self.logImportTables();2317 coff.logImportTables();
1798 }2318 }
17992319
1800 try self.writeStrtab();2320 try coff.writeStrtab();
1801 try self.writeDataDirectoriesHeaders();2321 try coff.writeDataDirectoriesHeaders();
1802 try self.writeSectionHeaders();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) {
1805 log.debug("flushing. no_entry_point_found = true\n", .{});2325 log.debug("flushing. no_entry_point_found = true\n", .{});
1806 diags.flags.no_entry_point_found = true;2326 diags.flags.no_entry_point_found = true;
1807 } else {2327 } else {
1808 log.debug("flushing. no_entry_point_found = false\n", .{});2328 log.debug("flushing. no_entry_point_found = false\n", .{});
1809 diags.flags.no_entry_point_found = false;2329 diags.flags.no_entry_point_found = false;
1810 try self.writeHeader();2330 try coff.writeHeader();
1811 }2331 }
18122332
1813 assert(!self.imports_count_dirty);2333 assert(!coff.imports_count_dirty);
1814}2334}
18152335
1816pub fn getNavVAddr(2336pub fn getNavVAddr(
1817 self: *Coff,2337 coff: *Coff,
1818 pt: Zcu.PerThread,2338 pt: Zcu.PerThread,
1819 nav_index: InternPool.Nav.Index,2339 nav_index: InternPool.Nav.Index,
1820 reloc_info: link.File.RelocInfo,2340 reloc_info: link.File.RelocInfo,
1821) !u64 {2341) !u64 {
1822 assert(self.llvm_object == null);2342 assert(coff.llvm_object == null);
1823 const zcu = pt.zcu;2343 const zcu = pt.zcu;
1824 const ip = &zcu.intern_pool;2344 const ip = &zcu.intern_pool;
1825 const nav = ip.getNav(nav_index);2345 const nav = ip.getNav(nav_index);
1826 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });2346 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
1827 const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {2347 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)),2348 .@"extern" => |@"extern"| try coff.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)),
1829 else => self.getAtom(try self.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,2349 else => coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,
1830 };2350 };
1831 const atom_index = self.getAtomIndexForSymbol(.{2351 const atom_index = coff.getAtomIndexForSymbol(.{
1832 .sym_index = reloc_info.parent.atom_index,2352 .sym_index = reloc_info.parent.atom_index,
1833 .file = null,2353 .file = null,
1834 }).?;2354 }).?;
1835 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };2355 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1836 try Atom.addRelocation(self, atom_index, .{2356 try coff.addRelocation(atom_index, .{
1837 .type = .direct,2357 .type = .direct,
1838 .target = target,2358 .target = target,
1839 .offset = @as(u32, @intCast(reloc_info.offset)),2359 .offset = @as(u32, @intCast(reloc_info.offset)),
...@@ -1841,13 +2361,13 @@ pub fn getNavVAddr(...@@ -1841,13 +2361,13 @@ pub fn getNavVAddr(
1841 .pcrel = false,2361 .pcrel = false,
1842 .length = 3,2362 .length = 3,
1843 });2363 });
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
1846 return 0;2366 return 0;
1847}2367}
18482368
1849pub fn lowerUav(2369pub fn lowerUav(
1850 self: *Coff,2370 coff: *Coff,
1851 pt: Zcu.PerThread,2371 pt: Zcu.PerThread,
1852 uav: InternPool.Index,2372 uav: InternPool.Index,
1853 explicit_alignment: InternPool.Alignment,2373 explicit_alignment: InternPool.Alignment,
...@@ -1860,9 +2380,9 @@ pub fn lowerUav(...@@ -1860,9 +2380,9 @@ pub fn lowerUav(
1860 .none => val.typeOf(zcu).abiAlignment(zcu),2380 .none => val.typeOf(zcu).abiAlignment(zcu),
1861 else => explicit_alignment,2381 else => explicit_alignment,
1862 };2382 };
1863 if (self.uavs.get(uav)) |metadata| {2383 if (coff.uavs.get(uav)) |metadata| {
1864 const atom = self.getAtom(metadata.atom);2384 const atom = coff.getAtom(metadata.atom);
1865 const existing_addr = atom.getSymbol(self).value;2385 const existing_addr = atom.getSymbol(coff).value;
1866 if (uav_alignment.check(existing_addr))2386 if (uav_alignment.check(existing_addr))
1867 return .{ .mcv = .{ .load_direct = atom.getSymbolIndex().? } };2387 return .{ .mcv = .{ .load_direct = atom.getSymbolIndex().? } };
1868 }2388 }
...@@ -1871,12 +2391,12 @@ pub fn lowerUav(...@@ -1871,12 +2391,12 @@ pub fn lowerUav(
1871 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{2391 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
1872 @intFromEnum(uav),2392 @intFromEnum(uav),
1873 }) catch unreachable;2393 }) catch unreachable;
1874 const res = self.lowerConst(2394 const res = coff.lowerConst(
1875 pt,2395 pt,
1876 name,2396 name,
1877 val,2397 val,
1878 uav_alignment,2398 uav_alignment,
1879 self.rdata_section_index.?,2399 coff.rdata_section_index.?,
1880 src_loc,2400 src_loc,
1881 ) catch |err| switch (err) {2401 ) catch |err| switch (err) {
1882 error.OutOfMemory => return error.OutOfMemory,2402 error.OutOfMemory => return error.OutOfMemory,
...@@ -1891,30 +2411,30 @@ pub fn lowerUav(...@@ -1891,30 +2411,30 @@ pub fn lowerUav(
1891 .ok => |atom_index| atom_index,2411 .ok => |atom_index| atom_index,
1892 .fail => |em| return .{ .fail = em },2412 .fail => |em| return .{ .fail = em },
1893 };2413 };
1894 try self.uavs.put(gpa, uav, .{2414 try coff.uavs.put(gpa, uav, .{
1895 .atom = atom_index,2415 .atom = atom_index,
1896 .section = self.rdata_section_index.?,2416 .section = coff.rdata_section_index.?,
1897 });2417 });
1898 return .{ .mcv = .{2418 return .{ .mcv = .{
1899 .load_direct = self.getAtom(atom_index).getSymbolIndex().?,2419 .load_direct = coff.getAtom(atom_index).getSymbolIndex().?,
1900 } };2420 } };
1901}2421}
19022422
1903pub fn getUavVAddr(2423pub fn getUavVAddr(
1904 self: *Coff,2424 coff: *Coff,
1905 uav: InternPool.Index,2425 uav: InternPool.Index,
1906 reloc_info: link.File.RelocInfo,2426 reloc_info: link.File.RelocInfo,
1907) !u64 {2427) !u64 {
1908 assert(self.llvm_object == null);2428 assert(coff.llvm_object == null);
19092429
1910 const this_atom_index = self.uavs.get(uav).?.atom;2430 const this_atom_index = coff.uavs.get(uav).?.atom;
1911 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;2431 const sym_index = coff.getAtom(this_atom_index).getSymbolIndex().?;
1912 const atom_index = self.getAtomIndexForSymbol(.{2432 const atom_index = coff.getAtomIndexForSymbol(.{
1913 .sym_index = reloc_info.parent.atom_index,2433 .sym_index = reloc_info.parent.atom_index,
1914 .file = null,2434 .file = null,
1915 }).?;2435 }).?;
1916 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };2436 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1917 try Atom.addRelocation(self, atom_index, .{2437 try coff.addRelocation(atom_index, .{
1918 .type = .direct,2438 .type = .direct,
1919 .target = target,2439 .target = target,
1920 .offset = @as(u32, @intCast(reloc_info.offset)),2440 .offset = @as(u32, @intCast(reloc_info.offset)),
...@@ -1922,41 +2442,41 @@ pub fn getUavVAddr(...@@ -1922,41 +2442,41 @@ pub fn getUavVAddr(
1922 .pcrel = false,2442 .pcrel = false,
1923 .length = 3,2443 .length = 3,
1924 });2444 });
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
1927 return 0;2447 return 0;
1928}2448}
19292449
1930pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 {2450pub fn getGlobalSymbol(coff: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 {
1931 const gop = try self.getOrPutGlobalPtr(name);2451 const gop = try coff.getOrPutGlobalPtr(name);
1932 const global_index = self.getGlobalIndex(name).?;2452 const global_index = coff.getGlobalIndex(name).?;
19332453
1934 if (gop.found_existing) {2454 if (gop.found_existing) {
1935 return global_index;2455 return global_index;
1936 }2456 }
19372457
1938 const sym_index = try self.allocateSymbol();2458 const sym_index = try coff.allocateSymbol();
1939 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };2459 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1940 gop.value_ptr.* = sym_loc;2460 gop.value_ptr.* = sym_loc;
19412461
1942 const gpa = self.base.comp.gpa;2462 const gpa = coff.base.comp.gpa;
1943 const sym = self.getSymbolPtr(sym_loc);2463 const sym = coff.getSymbolPtr(sym_loc);
1944 try self.setSymbolName(sym, name);2464 try coff.setSymbolName(sym, name);
1945 sym.storage_class = .EXTERNAL;2465 sym.storage_class = .EXTERNAL;
19462466
1947 if (lib_name_name) |lib_name| {2467 if (lib_name_name) |lib_name| {
1948 // We repurpose the 'value' of the Symbol struct to store an offset into2468 // We repurpose the 'value' of the Symbol struct to store an offset into
1949 // temporary string table where we will store the library name hint.2469 // 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);
1951 }2471 }
19522472
1953 try self.unresolved.putNoClobber(gpa, global_index, true);2473 try coff.unresolved.putNoClobber(gpa, global_index, true);
19542474
1955 return global_index;2475 return global_index;
1956}2476}
19572477
1958pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {2478pub fn updateDeclLineNumber(coff: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
1959 _ = self;2479 _ = coff;
1960 _ = pt;2480 _ = pt;
1961 _ = decl_index;2481 _ = decl_index;
1962 log.debug("TODO implement updateDeclLineNumber", .{});2482 log.debug("TODO implement updateDeclLineNumber", .{});
...@@ -1965,10 +2485,10 @@ pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPo...@@ -1965,10 +2485,10 @@ pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPo
1965/// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table2485/// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table
1966/// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do2486/// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do
1967/// incremental updates and writes into the table instead of doing it all at once2487/// incremental updates and writes into the table instead of doing it all at once
1968fn writeBaseRelocations(self: *Coff) !void {2488fn writeBaseRelocations(coff: *Coff) !void {
1969 const gpa = self.base.comp.gpa;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);
1972 defer {2492 defer {
1973 var it = page_table.valueIterator();2493 var it = page_table.valueIterator();
1974 while (it.next()) |inner| {2494 while (it.next()) |inner| {
...@@ -1978,19 +2498,19 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1978,19 +2498,19 @@ fn writeBaseRelocations(self: *Coff) !void {
1978 }2498 }
19792499
1980 {2500 {
1981 var it = self.base_relocs.iterator();2501 var it = coff.base_relocs.iterator();
1982 while (it.next()) |entry| {2502 while (it.next()) |entry| {
1983 const atom_index = entry.key_ptr.*;2503 const atom_index = entry.key_ptr.*;
1984 const atom = self.getAtom(atom_index);2504 const atom = coff.getAtom(atom_index);
1985 const sym = atom.getSymbol(self);2505 const sym = atom.getSymbol(coff);
1986 const offsets = entry.value_ptr.*;2506 const offsets = entry.value_ptr.*;
19872507
1988 for (offsets.items) |offset| {2508 for (offsets.items) |offset| {
1989 const rva = sym.value + offset;2509 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);
1991 const gop = try page_table.getOrPut(page);2511 const gop = try page_table.getOrPut(page);
1992 if (!gop.found_existing) {2512 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);
1994 }2514 }
1995 try gop.value_ptr.append(.{2515 try gop.value_ptr.append(.{
1996 .offset = @as(u12, @intCast(rva - page)),2516 .offset = @as(u12, @intCast(rva - page)),
...@@ -2000,18 +2520,18 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -2000,18 +2520,18 @@ fn writeBaseRelocations(self: *Coff) !void {
2000 }2520 }
20012521
2002 {2522 {
2003 const header = &self.sections.items(.header)[self.got_section_index.?];2523 const header = &coff.sections.items(.header)[coff.got_section_index.?];
2004 for (self.got_table.entries.items, 0..) |entry, index| {2524 for (coff.got_table.entries.items, 0..) |entry, index| {
2005 if (!self.got_table.lookup.contains(entry)) continue;2525 if (!coff.got_table.lookup.contains(entry)) continue;
20062526
2007 const sym = self.getSymbol(entry);2527 const sym = coff.getSymbol(entry);
2008 if (sym.section_number == .UNDEFINED) continue;2528 if (sym.section_number == .UNDEFINED) continue;
20092529
2010 const rva = @as(u32, @intCast(header.virtual_address + index * self.ptr_width.size()));2530 const rva = @as(u32, @intCast(header.virtual_address + index * coff.ptr_width.size()));
2011 const page = mem.alignBackward(u32, rva, self.page_size);2531 const page = mem.alignBackward(u32, rva, coff.page_size);
2012 const gop = try page_table.getOrPut(page);2532 const gop = try page_table.getOrPut(page);
2013 if (!gop.found_existing) {2533 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);
2015 }2535 }
2016 try gop.value_ptr.append(.{2536 try gop.value_ptr.append(.{
2017 .offset = @as(u12, @intCast(rva - page)),2537 .offset = @as(u12, @intCast(rva - page)),
...@@ -2040,7 +2560,7 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -2040,7 +2560,7 @@ fn writeBaseRelocations(self: *Coff) !void {
2040 // Pad to required 4byte alignment2560 // Pad to required 4byte alignment
2041 if (!mem.isAlignedGeneric(2561 if (!mem.isAlignedGeneric(
2042 usize,2562 usize,
2043 entries.items.len * @sizeOf(coff.BaseRelocation),2563 entries.items.len * @sizeOf(coff_util.BaseRelocation),
2044 @sizeOf(u32),2564 @sizeOf(u32),
2045 )) {2565 )) {
2046 try entries.append(.{2566 try entries.append(.{
...@@ -2051,58 +2571,58 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -2051,58 +2571,58 @@ fn writeBaseRelocations(self: *Coff) !void {
20512571
2052 const block_size = @as(2572 const block_size = @as(
2053 u32,2573 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)),
2055 );2575 );
2056 try buffer.ensureUnusedCapacity(block_size);2576 try buffer.ensureUnusedCapacity(block_size);
2057 buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{2577 buffer.appendSliceAssumeCapacity(mem.asBytes(&coff_util.BaseRelocationDirectoryEntry{
2058 .page_rva = page,2578 .page_rva = page,
2059 .block_size = block_size,2579 .block_size = block_size,
2060 }));2580 }));
2061 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entries.items));2581 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entries.items));
2062 }2582 }
20632583
2064 const header = &self.sections.items(.header)[self.reloc_section_index.?];2584 const header = &coff.sections.items(.header)[coff.reloc_section_index.?];
2065 const needed_size = @as(u32, @intCast(buffer.items.len));2585 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)] = .{
2071 .virtual_address = header.virtual_address,2591 .virtual_address = header.virtual_address,
2072 .size = needed_size,2592 .size = needed_size,
2073 };2593 };
2074}2594}
20752595
2076fn writeImportTables(self: *Coff) !void {2596fn writeImportTables(coff: *Coff) !void {
2077 if (self.idata_section_index == null) return;2597 if (coff.idata_section_index == null) return;
2078 if (!self.imports_count_dirty) return;2598 if (!coff.imports_count_dirty) return;
20792599
2080 const gpa = self.base.comp.gpa;2600 const gpa = coff.base.comp.gpa;
20812601
2082 const ext = ".dll";2602 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
2085 // Calculate needed size2605 // Calculate needed size
2086 var iat_size: u32 = 0;2606 var iat_size: u32 = 0;
2087 var dir_table_size: u32 = @sizeOf(coff.ImportDirectoryEntry); // sentinel2607 var dir_table_size: u32 = @sizeOf(coff_util.ImportDirectoryEntry); // sentinel
2088 var lookup_table_size: u32 = 0;2608 var lookup_table_size: u32 = 0;
2089 var names_table_size: u32 = 0;2609 var names_table_size: u32 = 0;
2090 var dll_names_size: u32 = 0;2610 var dll_names_size: u32 = 0;
2091 for (self.import_tables.keys(), 0..) |off, i| {2611 for (coff.import_tables.keys(), 0..) |off, i| {
2092 const lib_name = self.temp_strtab.getAssumeExists(off);2612 const lib_name = coff.temp_strtab.getAssumeExists(off);
2093 const itable = self.import_tables.values()[i];2613 const itable = coff.import_tables.values()[i];
2094 iat_size += itable.size() + 8;2614 iat_size += itable.size() + 8;
2095 dir_table_size += @sizeOf(coff.ImportDirectoryEntry);2615 dir_table_size += @sizeOf(coff_util.ImportDirectoryEntry);
2096 lookup_table_size += @as(u32, @intCast(itable.entries.items.len + 1)) * @sizeOf(coff.ImportLookupEntry64.ByName);2616 lookup_table_size += @as(u32, @intCast(itable.entries.items.len + 1)) * @sizeOf(coff_util.ImportLookupEntry64.ByName);
2097 for (itable.entries.items) |entry| {2617 for (itable.entries.items) |entry| {
2098 const sym_name = self.getSymbolName(entry);2618 const sym_name = coff.getSymbolName(entry);
2099 names_table_size += 2 + mem.alignForward(u32, @as(u32, @intCast(sym_name.len + 1)), 2);2619 names_table_size += 2 + mem.alignForward(u32, @as(u32, @intCast(sym_name.len + 1)), 2);
2100 }2620 }
2101 dll_names_size += @as(u32, @intCast(lib_name.len + ext.len + 1));2621 dll_names_size += @as(u32, @intCast(lib_name.len + ext.len + 1));
2102 }2622 }
21032623
2104 const needed_size = iat_size + dir_table_size + lookup_table_size + names_table_size + dll_names_size;2624 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
2107 // Do the actual writes2627 // Do the actual writes
2108 var buffer = std.ArrayList(u8).init(gpa);2628 var buffer = std.ArrayList(u8).init(gpa);
...@@ -2110,41 +2630,41 @@ fn writeImportTables(self: *Coff) !void {...@@ -2110,41 +2630,41 @@ fn writeImportTables(self: *Coff) !void {
2110 try buffer.ensureTotalCapacityPrecise(needed_size);2630 try buffer.ensureTotalCapacityPrecise(needed_size);
2111 buffer.resize(needed_size) catch unreachable;2631 buffer.resize(needed_size) catch unreachable;
21122632
2113 const dir_header_size = @sizeOf(coff.ImportDirectoryEntry);2633 const dir_header_size = @sizeOf(coff_util.ImportDirectoryEntry);
2114 const lookup_entry_size = @sizeOf(coff.ImportLookupEntry64.ByName);2634 const lookup_entry_size = @sizeOf(coff_util.ImportLookupEntry64.ByName);
21152635
2116 var iat_offset: u32 = 0;2636 var iat_offset: u32 = 0;
2117 var dir_table_offset = iat_size;2637 var dir_table_offset = iat_size;
2118 var lookup_table_offset = dir_table_offset + dir_table_size;2638 var lookup_table_offset = dir_table_offset + dir_table_size;
2119 var names_table_offset = lookup_table_offset + lookup_table_size;2639 var names_table_offset = lookup_table_offset + lookup_table_size;
2120 var dll_names_offset = names_table_offset + names_table_size;2640 var dll_names_offset = names_table_offset + names_table_size;
2121 for (self.import_tables.keys(), 0..) |off, i| {2641 for (coff.import_tables.keys(), 0..) |off, i| {
2122 const lib_name = self.temp_strtab.getAssumeExists(off);2642 const lib_name = coff.temp_strtab.getAssumeExists(off);
2123 const itable = self.import_tables.values()[i];2643 const itable = coff.import_tables.values()[i];
21242644
2125 // Lookup table header2645 // Lookup table header
2126 const lookup_header = coff.ImportDirectoryEntry{2646 const lookup_header = coff_util.ImportDirectoryEntry{
2127 .import_lookup_table_rva = header.virtual_address + lookup_table_offset,2647 .import_lookup_table_rva = header.virtual_address + lookup_table_offset,
2128 .time_date_stamp = 0,2648 .time_date_stamp = 0,
2129 .forwarder_chain = 0,2649 .forwarder_chain = 0,
2130 .name_rva = header.virtual_address + dll_names_offset,2650 .name_rva = header.virtual_address + dll_names_offset,
2131 .import_address_table_rva = header.virtual_address + iat_offset,2651 .import_address_table_rva = header.virtual_address + iat_offset,
2132 };2652 };
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));
2134 dir_table_offset += dir_header_size;2654 dir_table_offset += dir_header_size;
21352655
2136 for (itable.entries.items) |entry| {2656 for (itable.entries.items) |entry| {
2137 const import_name = self.getSymbolName(entry);2657 const import_name = coff.getSymbolName(entry);
21382658
2139 // IAT and lookup table entry2659 // 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)) };
2141 @memcpy(2661 @memcpy(
2142 buffer.items[iat_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)],2662 buffer.items[iat_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)],
2143 mem.asBytes(&lookup),2663 mem.asBytes(&lookup),
2144 );2664 );
2145 iat_offset += lookup_entry_size;2665 iat_offset += lookup_entry_size;
2146 @memcpy(2666 @memcpy(
2147 buffer.items[lookup_table_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)],2667 buffer.items[lookup_table_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)],
2148 mem.asBytes(&lookup),2668 mem.asBytes(&lookup),
2149 );2669 );
2150 lookup_table_offset += lookup_entry_size;2670 lookup_table_offset += lookup_entry_size;
...@@ -2168,8 +2688,8 @@ fn writeImportTables(self: *Coff) !void {...@@ -2168,8 +2688,8 @@ fn writeImportTables(self: *Coff) !void {
21682688
2169 // Lookup table sentinel2689 // Lookup table sentinel
2170 @memcpy(2690 @memcpy(
2171 buffer.items[lookup_table_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)],2691 buffer.items[lookup_table_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)],
2172 mem.asBytes(&coff.ImportLookupEntry64.ByName{ .name_table_rva = 0 }),2692 mem.asBytes(&coff_util.ImportLookupEntry64.ByName{ .name_table_rva = 0 }),
2173 );2693 );
2174 lookup_table_offset += lookup_entry_size;2694 lookup_table_offset += lookup_entry_size;
21752695
...@@ -2183,7 +2703,7 @@ fn writeImportTables(self: *Coff) !void {...@@ -2183,7 +2703,7 @@ fn writeImportTables(self: *Coff) !void {
2183 }2703 }
21842704
2185 // Sentinel2705 // Sentinel
2186 const lookup_header = coff.ImportDirectoryEntry{2706 const lookup_header = coff_util.ImportDirectoryEntry{
2187 .import_lookup_table_rva = 0,2707 .import_lookup_table_rva = 0,
2188 .time_date_stamp = 0,2708 .time_date_stamp = 0,
2189 .forwarder_chain = 0,2709 .forwarder_chain = 0,
...@@ -2191,93 +2711,93 @@ fn writeImportTables(self: *Coff) !void {...@@ -2191,93 +2711,93 @@ fn writeImportTables(self: *Coff) !void {
2191 .import_address_table_rva = 0,2711 .import_address_table_rva = 0,
2192 };2712 };
2193 @memcpy(2713 @memcpy(
2194 buffer.items[dir_table_offset..][0..@sizeOf(coff.ImportDirectoryEntry)],2714 buffer.items[dir_table_offset..][0..@sizeOf(coff_util.ImportDirectoryEntry)],
2195 mem.asBytes(&lookup_header),2715 mem.asBytes(&lookup_header),
2196 );2716 );
2197 dir_table_offset += dir_header_size;2717 dir_table_offset += dir_header_size;
21982718
2199 assert(dll_names_offset == needed_size);2719 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)] = .{
2204 .virtual_address = header.virtual_address + iat_size,2724 .virtual_address = header.virtual_address + iat_size,
2205 .size = dir_table_size,2725 .size = dir_table_size,
2206 };2726 };
2207 self.data_directories[@intFromEnum(coff.DirectoryEntry.IAT)] = .{2727 coff.data_directories[@intFromEnum(coff_util.DirectoryEntry.IAT)] = .{
2208 .virtual_address = header.virtual_address,2728 .virtual_address = header.virtual_address,
2209 .size = iat_size,2729 .size = iat_size,
2210 };2730 };
22112731
2212 self.imports_count_dirty = false;2732 coff.imports_count_dirty = false;
2213}2733}
22142734
2215fn writeStrtab(self: *Coff) !void {2735fn writeStrtab(coff: *Coff) !void {
2216 if (self.strtab_offset == null) return;2736 if (coff.strtab_offset == null) return;
22172737
2218 const allocated_size = self.allocatedSize(self.strtab_offset.?);2738 const allocated_size = coff.allocatedSize(coff.strtab_offset.?);
2219 const needed_size = @as(u32, @intCast(self.strtab.buffer.items.len));2739 const needed_size = @as(u32, @intCast(coff.strtab.buffer.items.len));
22202740
2221 if (needed_size > allocated_size) {2741 if (needed_size > allocated_size) {
2222 self.strtab_offset = null;2742 coff.strtab_offset = null;
2223 self.strtab_offset = @as(u32, @intCast(self.findFreeSpace(needed_size, @alignOf(u32))));2743 coff.strtab_offset = @as(u32, @intCast(coff.findFreeSpace(needed_size, @alignOf(u32))));
2224 }2744 }
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;
2229 var buffer = std.ArrayList(u8).init(gpa);2749 var buffer = std.ArrayList(u8).init(gpa);
2230 defer buffer.deinit();2750 defer buffer.deinit();
2231 try buffer.ensureTotalCapacityPrecise(needed_size);2751 try buffer.ensureTotalCapacityPrecise(needed_size);
2232 buffer.appendSliceAssumeCapacity(self.strtab.buffer.items);2752 buffer.appendSliceAssumeCapacity(coff.strtab.buffer.items);
2233 // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead2753 // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead
2234 // we write the length of the strtab to a temporary buffer that goes to file.2754 // 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.?);
2238}2758}
22392759
2240fn writeSectionHeaders(self: *Coff) !void {2760fn writeSectionHeaders(coff: *Coff) !void {
2241 const offset = self.getSectionHeadersOffset();2761 const offset = coff.getSectionHeadersOffset();
2242 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items(.header)), offset);2762 try coff.base.file.?.pwriteAll(mem.sliceAsBytes(coff.sections.items(.header)), offset);
2243}2763}
22442764
2245fn writeDataDirectoriesHeaders(self: *Coff) !void {2765fn writeDataDirectoriesHeaders(coff: *Coff) !void {
2246 const offset = self.getDataDirectoryHeadersOffset();2766 const offset = coff.getDataDirectoryHeadersOffset();
2247 try self.base.file.?.pwriteAll(mem.sliceAsBytes(&self.data_directories), offset);2767 try coff.base.file.?.pwriteAll(mem.sliceAsBytes(&coff.data_directories), offset);
2248}2768}
22492769
2250fn writeHeader(self: *Coff) !void {2770fn writeHeader(coff: *Coff) !void {
2251 const target = self.base.comp.root_mod.resolved_target.result;2771 const target = coff.base.comp.root_mod.resolved_target.result;
2252 const gpa = self.base.comp.gpa;2772 const gpa = coff.base.comp.gpa;
2253 var buffer = std.ArrayList(u8).init(gpa);2773 var buffer = std.ArrayList(u8).init(gpa);
2254 defer buffer.deinit();2774 defer buffer.deinit();
2255 const writer = buffer.writer();2775 const writer = buffer.writer();
22562776
2257 try buffer.ensureTotalCapacity(self.getSizeOfHeaders());2777 try buffer.ensureTotalCapacity(coff.getSizeOfHeaders());
2258 writer.writeAll(msdos_stub) catch unreachable;2778 writer.writeAll(msdos_stub) catch unreachable;
2259 mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little);2779 mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little);
22602780
2261 writer.writeAll("PE\x00\x00") catch unreachable;2781 writer.writeAll("PE\x00\x00") catch unreachable;
2262 var flags = coff.CoffHeaderFlags{2782 var flags = coff_util.CoffHeaderFlags{
2263 .EXECUTABLE_IMAGE = 1,2783 .EXECUTABLE_IMAGE = 1,
2264 .DEBUG_STRIPPED = 1, // TODO2784 .DEBUG_STRIPPED = 1, // TODO
2265 };2785 };
2266 switch (self.ptr_width) {2786 switch (coff.ptr_width) {
2267 .p32 => flags.@"32BIT_MACHINE" = 1,2787 .p32 => flags.@"32BIT_MACHINE" = 1,
2268 .p64 => flags.LARGE_ADDRESS_AWARE = 1,2788 .p64 => flags.LARGE_ADDRESS_AWARE = 1,
2269 }2789 }
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) {
2271 flags.DLL = 1;2791 flags.DLL = 1;
2272 }2792 }
22732793
2274 const timestamp = if (self.repro) 0 else std.time.timestamp();2794 const timestamp = if (coff.repro) 0 else std.time.timestamp();
2275 const size_of_optional_header = @as(u16, @intCast(self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize()));2795 const size_of_optional_header = @as(u16, @intCast(coff.getOptionalHeaderSize() + coff.getDataDirectoryHeadersSize()));
2276 var coff_header = coff.CoffHeader{2796 var coff_header = coff_util.CoffHeader{
2277 .machine = target.toCoffMachine(),2797 .machine = target.toCoffMachine(),
2278 .number_of_sections = @as(u16, @intCast(self.sections.slice().len)), // TODO what if we prune a section2798 .number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section
2279 .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))),2799 .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,
2281 .number_of_symbols = 0,2801 .number_of_symbols = 0,
2282 .size_of_optional_header = size_of_optional_header,2802 .size_of_optional_header = size_of_optional_header,
2283 .flags = flags,2803 .flags = flags,
...@@ -2285,22 +2805,22 @@ fn writeHeader(self: *Coff) !void {...@@ -2285,22 +2805,22 @@ fn writeHeader(self: *Coff) !void {
22852805
2286 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;2806 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
22872807
2288 const dll_flags: coff.DllFlags = .{2808 const dll_flags: coff_util.DllFlags = .{
2289 .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all?2809 .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all?
2290 .DYNAMIC_BASE = 1,2810 .DYNAMIC_BASE = 1,
2291 .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app2811 .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app
2292 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention2812 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention
2293 };2813 };
2294 const subsystem: coff.Subsystem = .WINDOWS_CUI;2814 const subsystem: coff_util.Subsystem = .WINDOWS_CUI;
2295 const size_of_image: u32 = self.getSizeOfImage();2815 const size_of_image: u32 = coff.getSizeOfImage();
2296 const size_of_headers: u32 = mem.alignForward(u32, self.getSizeOfHeaders(), default_file_alignment);2816 const size_of_headers: u32 = mem.alignForward(u32, coff.getSizeOfHeaders(), default_file_alignment);
2297 const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address;2817 const base_of_code = coff.sections.get(coff.text_section_index.?).header.virtual_address;
2298 const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address;2818 const base_of_data = coff.sections.get(coff.data_section_index.?).header.virtual_address;
22992819
2300 var size_of_code: u32 = 0;2820 var size_of_code: u32 = 0;
2301 var size_of_initialized_data: u32 = 0;2821 var size_of_initialized_data: u32 = 0;
2302 var size_of_uninitialized_data: u32 = 0;2822 var size_of_uninitialized_data: u32 = 0;
2303 for (self.sections.items(.header)) |header| {2823 for (coff.sections.items(.header)) |header| {
2304 if (header.flags.CNT_CODE == 1) {2824 if (header.flags.CNT_CODE == 1) {
2305 size_of_code += header.size_of_raw_data;2825 size_of_code += header.size_of_raw_data;
2306 }2826 }
...@@ -2312,27 +2832,27 @@ fn writeHeader(self: *Coff) !void {...@@ -2312,27 +2832,27 @@ fn writeHeader(self: *Coff) !void {
2312 }2832 }
2313 }2833 }
23142834
2315 switch (self.ptr_width) {2835 switch (coff.ptr_width) {
2316 .p32 => {2836 .p32 => {
2317 var opt_header = coff.OptionalHeaderPE32{2837 var opt_header = coff_util.OptionalHeaderPE32{
2318 .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC,2838 .magic = coff_util.IMAGE_NT_OPTIONAL_HDR32_MAGIC,
2319 .major_linker_version = 0,2839 .major_linker_version = 0,
2320 .minor_linker_version = 0,2840 .minor_linker_version = 0,
2321 .size_of_code = size_of_code,2841 .size_of_code = size_of_code,
2322 .size_of_initialized_data = size_of_initialized_data,2842 .size_of_initialized_data = size_of_initialized_data,
2323 .size_of_uninitialized_data = size_of_uninitialized_data,2843 .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,
2325 .base_of_code = base_of_code,2845 .base_of_code = base_of_code,
2326 .base_of_data = base_of_data,2846 .base_of_data = base_of_data,
2327 .image_base = @intCast(self.image_base),2847 .image_base = @intCast(coff.image_base),
2328 .section_alignment = self.page_size,2848 .section_alignment = coff.page_size,
2329 .file_alignment = default_file_alignment,2849 .file_alignment = default_file_alignment,
2330 .major_operating_system_version = 6,2850 .major_operating_system_version = 6,
2331 .minor_operating_system_version = 0,2851 .minor_operating_system_version = 0,
2332 .major_image_version = 0,2852 .major_image_version = 0,
2333 .minor_image_version = 0,2853 .minor_image_version = 0,
2334 .major_subsystem_version = @intCast(self.major_subsystem_version),2854 .major_subsystem_version = @intCast(coff.major_subsystem_version),
2335 .minor_subsystem_version = @intCast(self.minor_subsystem_version),2855 .minor_subsystem_version = @intCast(coff.minor_subsystem_version),
2336 .win32_version_value = 0,2856 .win32_version_value = 0,
2337 .size_of_image = size_of_image,2857 .size_of_image = size_of_image,
2338 .size_of_headers = size_of_headers,2858 .size_of_headers = size_of_headers,
...@@ -2344,29 +2864,29 @@ fn writeHeader(self: *Coff) !void {...@@ -2344,29 +2864,29 @@ fn writeHeader(self: *Coff) !void {
2344 .size_of_heap_reserve = default_size_of_heap_reserve,2864 .size_of_heap_reserve = default_size_of_heap_reserve,
2345 .size_of_heap_commit = default_size_of_heap_commit,2865 .size_of_heap_commit = default_size_of_heap_commit,
2346 .loader_flags = 0,2866 .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),
2348 };2868 };
2349 writer.writeAll(mem.asBytes(&opt_header)) catch unreachable;2869 writer.writeAll(mem.asBytes(&opt_header)) catch unreachable;
2350 },2870 },
2351 .p64 => {2871 .p64 => {
2352 var opt_header = coff.OptionalHeaderPE64{2872 var opt_header = coff_util.OptionalHeaderPE64{
2353 .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC,2873 .magic = coff_util.IMAGE_NT_OPTIONAL_HDR64_MAGIC,
2354 .major_linker_version = 0,2874 .major_linker_version = 0,
2355 .minor_linker_version = 0,2875 .minor_linker_version = 0,
2356 .size_of_code = size_of_code,2876 .size_of_code = size_of_code,
2357 .size_of_initialized_data = size_of_initialized_data,2877 .size_of_initialized_data = size_of_initialized_data,
2358 .size_of_uninitialized_data = size_of_uninitialized_data,2878 .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,
2360 .base_of_code = base_of_code,2880 .base_of_code = base_of_code,
2361 .image_base = self.image_base,2881 .image_base = coff.image_base,
2362 .section_alignment = self.page_size,2882 .section_alignment = coff.page_size,
2363 .file_alignment = default_file_alignment,2883 .file_alignment = default_file_alignment,
2364 .major_operating_system_version = 6,2884 .major_operating_system_version = 6,
2365 .minor_operating_system_version = 0,2885 .minor_operating_system_version = 0,
2366 .major_image_version = 0,2886 .major_image_version = 0,
2367 .minor_image_version = 0,2887 .minor_image_version = 0,
2368 .major_subsystem_version = self.major_subsystem_version,2888 .major_subsystem_version = coff.major_subsystem_version,
2369 .minor_subsystem_version = self.minor_subsystem_version,2889 .minor_subsystem_version = coff.minor_subsystem_version,
2370 .win32_version_value = 0,2890 .win32_version_value = 0,
2371 .size_of_image = size_of_image,2891 .size_of_image = size_of_image,
2372 .size_of_headers = size_of_headers,2892 .size_of_headers = size_of_headers,
...@@ -2378,28 +2898,28 @@ fn writeHeader(self: *Coff) !void {...@@ -2378,28 +2898,28 @@ fn writeHeader(self: *Coff) !void {
2378 .size_of_heap_reserve = default_size_of_heap_reserve,2898 .size_of_heap_reserve = default_size_of_heap_reserve,
2379 .size_of_heap_commit = default_size_of_heap_commit,2899 .size_of_heap_commit = default_size_of_heap_commit,
2380 .loader_flags = 0,2900 .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),
2382 };2902 };
2383 writer.writeAll(mem.asBytes(&opt_header)) catch unreachable;2903 writer.writeAll(mem.asBytes(&opt_header)) catch unreachable;
2384 },2904 },
2385 }2905 }
23862906
2387 try self.base.file.?.pwriteAll(buffer.items, 0);2907 try coff.base.file.?.pwriteAll(buffer.items, 0);
2388}2908}
23892909
2390pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {2910pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2391 return actual_size +| (actual_size / ideal_factor);2911 return actual_size +| (actual_size / ideal_factor);
2392}2912}
23932913
2394fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {2914fn detectAllocCollision(coff: *Coff, start: u32, size: u32) ?u32 {
2395 const headers_size = @max(self.getSizeOfHeaders(), self.page_size);2915 const headers_size = @max(coff.getSizeOfHeaders(), coff.page_size);
2396 if (start < headers_size)2916 if (start < headers_size)
2397 return headers_size;2917 return headers_size;
23982918
2399 const end = start + padToIdeal(size);2919 const end = start + padToIdeal(size);
24002920
2401 if (self.strtab_offset) |off| {2921 if (coff.strtab_offset) |off| {
2402 const tight_size = @as(u32, @intCast(self.strtab.buffer.items.len));2922 const tight_size = @as(u32, @intCast(coff.strtab.buffer.items.len));
2403 const increased_size = padToIdeal(tight_size);2923 const increased_size = padToIdeal(tight_size);
2404 const test_end = off + increased_size;2924 const test_end = off + increased_size;
2405 if (end > off and start < test_end) {2925 if (end > off and start < test_end) {
...@@ -2407,7 +2927,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {...@@ -2407,7 +2927,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
2407 }2927 }
2408 }2928 }
24092929
2410 for (self.sections.items(.header)) |header| {2930 for (coff.sections.items(.header)) |header| {
2411 const tight_size = header.size_of_raw_data;2931 const tight_size = header.size_of_raw_data;
2412 const increased_size = padToIdeal(tight_size);2932 const increased_size = padToIdeal(tight_size);
2413 const test_end = header.pointer_to_raw_data + increased_size;2933 const test_end = header.pointer_to_raw_data + increased_size;
...@@ -2419,86 +2939,86 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {...@@ -2419,86 +2939,86 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
2419 return null;2939 return null;
2420}2940}
24212941
2422fn allocatedSize(self: *Coff, start: u32) u32 {2942fn allocatedSize(coff: *Coff, start: u32) u32 {
2423 if (start == 0)2943 if (start == 0)
2424 return 0;2944 return 0;
2425 var min_pos: u32 = std.math.maxInt(u32);2945 var min_pos: u32 = std.math.maxInt(u32);
2426 if (self.strtab_offset) |off| {2946 if (coff.strtab_offset) |off| {
2427 if (off > start and off < min_pos) min_pos = off;2947 if (off > start and off < min_pos) min_pos = off;
2428 }2948 }
2429 for (self.sections.items(.header)) |header| {2949 for (coff.sections.items(.header)) |header| {
2430 if (header.pointer_to_raw_data <= start) continue;2950 if (header.pointer_to_raw_data <= start) continue;
2431 if (header.pointer_to_raw_data < min_pos) min_pos = header.pointer_to_raw_data;2951 if (header.pointer_to_raw_data < min_pos) min_pos = header.pointer_to_raw_data;
2432 }2952 }
2433 return min_pos - start;2953 return min_pos - start;
2434}2954}
24352955
2436fn findFreeSpace(self: *Coff, object_size: u32, min_alignment: u32) u32 {2956fn findFreeSpace(coff: *Coff, object_size: u32, min_alignment: u32) u32 {
2437 var start: u32 = 0;2957 var start: u32 = 0;
2438 while (self.detectAllocCollision(start, object_size)) |item_end| {2958 while (coff.detectAllocCollision(start, object_size)) |item_end| {
2439 start = mem.alignForward(u32, item_end, min_alignment);2959 start = mem.alignForward(u32, item_end, min_alignment);
2440 }2960 }
2441 return start;2961 return start;
2442}2962}
24432963
2444fn allocatedVirtualSize(self: *Coff, start: u32) u32 {2964fn allocatedVirtualSize(coff: *Coff, start: u32) u32 {
2445 if (start == 0)2965 if (start == 0)
2446 return 0;2966 return 0;
2447 var min_pos: u32 = std.math.maxInt(u32);2967 var min_pos: u32 = std.math.maxInt(u32);
2448 for (self.sections.items(.header)) |header| {2968 for (coff.sections.items(.header)) |header| {
2449 if (header.virtual_address <= start) continue;2969 if (header.virtual_address <= start) continue;
2450 if (header.virtual_address < min_pos) min_pos = header.virtual_address;2970 if (header.virtual_address < min_pos) min_pos = header.virtual_address;
2451 }2971 }
2452 return min_pos - start;2972 return min_pos - start;
2453}2973}
24542974
2455inline fn getSizeOfHeaders(self: Coff) u32 {2975fn getSizeOfHeaders(coff: Coff) u32 {
2456 const msdos_hdr_size = msdos_stub.len + 4;2976 const msdos_hdr_size = msdos_stub.len + 4;
2457 return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() +2977 return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize() +
2458 self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize()));2978 coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize()));
2459}2979}
24602980
2461inline fn getOptionalHeaderSize(self: Coff) u32 {2981fn getOptionalHeaderSize(coff: Coff) u32 {
2462 return switch (self.ptr_width) {2982 return switch (coff.ptr_width) {
2463 .p32 => @as(u32, @intCast(@sizeOf(coff.OptionalHeaderPE32))),2983 .p32 => @as(u32, @intCast(@sizeOf(coff_util.OptionalHeaderPE32))),
2464 .p64 => @as(u32, @intCast(@sizeOf(coff.OptionalHeaderPE64))),2984 .p64 => @as(u32, @intCast(@sizeOf(coff_util.OptionalHeaderPE64))),
2465 };2985 };
2466}2986}
24672987
2468inline fn getDataDirectoryHeadersSize(self: Coff) u32 {2988fn getDataDirectoryHeadersSize(coff: Coff) u32 {
2469 return @as(u32, @intCast(self.data_directories.len * @sizeOf(coff.ImageDataDirectory)));2989 return @as(u32, @intCast(coff.data_directories.len * @sizeOf(coff_util.ImageDataDirectory)));
2470}2990}
24712991
2472inline fn getSectionHeadersSize(self: Coff) u32 {2992fn getSectionHeadersSize(coff: Coff) u32 {
2473 return @as(u32, @intCast(self.sections.slice().len * @sizeOf(coff.SectionHeader)));2993 return @as(u32, @intCast(coff.sections.slice().len * @sizeOf(coff_util.SectionHeader)));
2474}2994}
24752995
2476inline fn getDataDirectoryHeadersOffset(self: Coff) u32 {2996fn getDataDirectoryHeadersOffset(coff: Coff) u32 {
2477 const msdos_hdr_size = msdos_stub.len + 4;2997 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()));
2479}2999}
24803000
2481inline fn getSectionHeadersOffset(self: Coff) u32 {3001fn getSectionHeadersOffset(coff: Coff) u32 {
2482 return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize();3002 return coff.getDataDirectoryHeadersOffset() + coff.getDataDirectoryHeadersSize();
2483}3003}
24843004
2485inline fn getSizeOfImage(self: Coff) u32 {3005fn getSizeOfImage(coff: Coff) u32 {
2486 var image_size: u32 = mem.alignForward(u32, self.getSizeOfHeaders(), self.page_size);3006 var image_size: u32 = mem.alignForward(u32, coff.getSizeOfHeaders(), coff.page_size);
2487 for (self.sections.items(.header)) |header| {3007 for (coff.sections.items(.header)) |header| {
2488 image_size += mem.alignForward(u32, header.virtual_size, self.page_size);3008 image_size += mem.alignForward(u32, header.virtual_size, coff.page_size);
2489 }3009 }
2490 return image_size;3010 return image_size;
2491}3011}
24923012
2493/// Returns symbol location corresponding to the set entrypoint (if any).3013/// Returns symbol location corresponding to the set entrypoint (if any).
2494pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {3014pub fn getEntryPoint(coff: Coff) ?SymbolWithLoc {
2495 const comp = self.base.comp;3015 const comp = coff.base.comp;
24963016
2497 // TODO This is incomplete.3017 // TODO This is incomplete.
2498 // The entry symbol name depends on the subsystem as well as the set of3018 // The entry symbol name depends on the subsystem as well as the set of
2499 // public symbol names from linked objects.3019 // public symbol names from linked objects.
2500 // See LinkerDriver::findDefaultEntry from the LLD project for the flow chart.3020 // 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) {
2502 .disabled => return null,3022 .disabled => return null,
2503 .default => switch (comp.config.output_mode) {3023 .default => switch (comp.config.output_mode) {
2504 .Exe => "wWinMainCRTStartup",3024 .Exe => "wWinMainCRTStartup",
...@@ -2507,51 +3027,51 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {...@@ -2507,51 +3027,51 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
2507 .enabled => "wWinMainCRTStartup",3027 .enabled => "wWinMainCRTStartup",
2508 .named => |name| name,3028 .named => |name| name,
2509 };3029 };
2510 const global_index = self.resolver.get(entry_name) orelse return null;3030 const global_index = coff.resolver.get(entry_name) orelse return null;
2511 return self.globals.items[global_index];3031 return coff.globals.items[global_index];
2512}3032}
25133033
2514/// Returns pointer-to-symbol described by `sym_loc` descriptor.3034/// 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 {
2516 assert(sym_loc.file == null); // TODO linking object files3036 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];
2518}3038}
25193039
2520/// Returns symbol described by `sym_loc` descriptor.3040/// 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 {
2522 assert(sym_loc.file == null); // TODO linking object files3042 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];
2524}3044}
25253045
2526/// Returns name of the symbol described by `sym_loc` descriptor.3046/// 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 {
2528 assert(sym_loc.file == null); // TODO linking object files3048 assert(sym_loc.file == null); // TODO linking object files
2529 const sym = self.getSymbol(sym_loc);3049 const sym = coff.getSymbol(sym_loc);
2530 const offset = sym.getNameOffset() orelse return sym.getName().?;3050 const offset = sym.getNameOffset() orelse return sym.getName().?;
2531 return self.strtab.get(offset).?;3051 return coff.strtab.get(offset).?;
2532}3052}
25333053
2534/// Returns pointer to the global entry for `name` if one exists.3054/// Returns pointer to the global entry for `name` if one exists.
2535pub fn getGlobalPtr(self: *Coff, name: []const u8) ?*SymbolWithLoc {3055pub fn getGlobalPtr(coff: *Coff, name: []const u8) ?*SymbolWithLoc {
2536 const global_index = self.resolver.get(name) orelse return null;3056 const global_index = coff.resolver.get(name) orelse return null;
2537 return &self.globals.items[global_index];3057 return &coff.globals.items[global_index];
2538}3058}
25393059
2540/// Returns the global entry for `name` if one exists.3060/// Returns the global entry for `name` if one exists.
2541pub fn getGlobal(self: *const Coff, name: []const u8) ?SymbolWithLoc {3061pub fn getGlobal(coff: *const Coff, name: []const u8) ?SymbolWithLoc {
2542 const global_index = self.resolver.get(name) orelse return null;3062 const global_index = coff.resolver.get(name) orelse return null;
2543 return self.globals.items[global_index];3063 return coff.globals.items[global_index];
2544}3064}
25453065
2546/// Returns the index of the global entry for `name` if one exists.3066/// Returns the index of the global entry for `name` if one exists.
2547pub fn getGlobalIndex(self: *const Coff, name: []const u8) ?u32 {3067pub fn getGlobalIndex(coff: *const Coff, name: []const u8) ?u32 {
2548 return self.resolver.get(name);3068 return coff.resolver.get(name);
2549}3069}
25503070
2551/// Returns global entry at `index`.3071/// Returns global entry at `index`.
2552pub fn getGlobalByIndex(self: *const Coff, index: u32) SymbolWithLoc {3072pub fn getGlobalByIndex(coff: *const Coff, index: u32) SymbolWithLoc {
2553 assert(index < self.globals.items.len);3073 assert(index < coff.globals.items.len);
2554 return self.globals.items[index];3074 return coff.globals.items[index];
2555}3075}
25563076
2557const GetOrPutGlobalPtrResult = struct {3077const GetOrPutGlobalPtrResult = struct {
...@@ -2567,68 +3087,68 @@ pub const global_symbol_mask: u32 = 0x7fffffff;...@@ -2567,68 +3087,68 @@ pub const global_symbol_mask: u32 = 0x7fffffff;
2567/// Return pointer to the global entry for `name` if one exists.3087/// Return pointer to the global entry for `name` if one exists.
2568/// Puts a new global entry for `name` if one doesn't exist, and3088/// Puts a new global entry for `name` if one doesn't exist, and
2569/// returns a pointer to it.3089/// returns a pointer to it.
2570pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult {3090pub fn getOrPutGlobalPtr(coff: *Coff, name: []const u8) !GetOrPutGlobalPtrResult {
2571 if (self.getGlobalPtr(name)) |ptr| {3091 if (coff.getGlobalPtr(name)) |ptr| {
2572 return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr };3092 return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr };
2573 }3093 }
2574 const gpa = self.base.comp.gpa;3094 const gpa = coff.base.comp.gpa;
2575 const global_index = try self.allocateGlobal();3095 const global_index = try coff.allocateGlobal();
2576 const global_name = try gpa.dupe(u8, name);3096 const global_name = try gpa.dupe(u8, name);
2577 _ = try self.resolver.put(gpa, global_name, global_index);3097 _ = try coff.resolver.put(gpa, global_name, global_index);
2578 const ptr = &self.globals.items[global_index];3098 const ptr = &coff.globals.items[global_index];
2579 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };3099 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
2580}3100}
25813101
2582pub fn getAtom(self: *const Coff, atom_index: Atom.Index) Atom {3102pub fn getAtom(coff: *const Coff, atom_index: Atom.Index) Atom {
2583 assert(atom_index < self.atoms.items.len);3103 assert(atom_index < coff.atoms.items.len);
2584 return self.atoms.items[atom_index];3104 return coff.atoms.items[atom_index];
2585}3105}
25863106
2587pub fn getAtomPtr(self: *Coff, atom_index: Atom.Index) *Atom {3107pub fn getAtomPtr(coff: *Coff, atom_index: Atom.Index) *Atom {
2588 assert(atom_index < self.atoms.items.len);3108 assert(atom_index < coff.atoms.items.len);
2589 return &self.atoms.items[atom_index];3109 return &coff.atoms.items[atom_index];
2590}3110}
25913111
2592/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.3112/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.
2593/// Returns null on failure.3113/// 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 {
2595 assert(sym_loc.file == null); // TODO linking with object files3115 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);
2597}3117}
25983118
2599fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {3119fn setSectionName(coff: *Coff, header: *coff_util.SectionHeader, name: []const u8) !void {
2600 if (name.len <= 8) {3120 if (name.len <= 8) {
2601 @memcpy(header.name[0..name.len], name);3121 @memcpy(header.name[0..name.len], name);
2602 @memset(header.name[name.len..], 0);3122 @memset(header.name[name.len..], 0);
2603 return;3123 return;
2604 }3124 }
2605 const gpa = self.base.comp.gpa;3125 const gpa = coff.base.comp.gpa;
2606 const offset = try self.strtab.insert(gpa, name);3126 const offset = try coff.strtab.insert(gpa, name);
2607 const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable;3127 const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable;
2608 @memset(header.name[name_offset.len..], 0);3128 @memset(header.name[name_offset.len..], 0);
2609}3129}
26103130
2611fn getSectionName(self: *const Coff, header: *const coff.SectionHeader) []const u8 {3131fn getSectionName(coff: *const Coff, header: *const coff_util.SectionHeader) []const u8 {
2612 if (header.getName()) |name| {3132 if (header.getName()) |name| {
2613 return name;3133 return name;
2614 }3134 }
2615 const offset = header.getNameOffset().?;3135 const offset = header.getNameOffset().?;
2616 return self.strtab.get(offset).?;3136 return coff.strtab.get(offset).?;
2617}3137}
26183138
2619fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {3139fn setSymbolName(coff: *Coff, symbol: *coff_util.Symbol, name: []const u8) !void {
2620 if (name.len <= 8) {3140 if (name.len <= 8) {
2621 @memcpy(symbol.name[0..name.len], name);3141 @memcpy(symbol.name[0..name.len], name);
2622 @memset(symbol.name[name.len..], 0);3142 @memset(symbol.name[name.len..], 0);
2623 return;3143 return;
2624 }3144 }
2625 const gpa = self.base.comp.gpa;3145 const gpa = coff.base.comp.gpa;
2626 const offset = try self.strtab.insert(gpa, name);3146 const offset = try coff.strtab.insert(gpa, name);
2627 @memset(symbol.name[0..4], 0);3147 @memset(symbol.name[0..4], 0);
2628 mem.writeInt(u32, symbol.name[4..8], offset, .little);3148 mem.writeInt(u32, symbol.name[4..8], offset, .little);
2629}3149}
26303150
2631fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 {3151fn logSymAttributes(sym: *const coff_util.Symbol, buf: *[4]u8) []const u8 {
2632 @memset(buf[0..4], '_');3152 @memset(buf[0..4], '_');
2633 switch (sym.section_number) {3153 switch (sym.section_number) {
2634 .UNDEFINED => {3154 .UNDEFINED => {
...@@ -2655,12 +3175,12 @@ fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 {...@@ -2655,12 +3175,12 @@ fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 {
2655 return buf[0..];3175 return buf[0..];
2656}3176}
26573177
2658fn logSymtab(self: *Coff) void {3178fn logSymtab(coff: *Coff) void {
2659 var buf: [4]u8 = undefined;3179 var buf: [4]u8 = undefined;
26603180
2661 log.debug("symtab:", .{});3181 log.debug("symtab:", .{});
2662 log.debug(" object(null)", .{});3182 log.debug(" object(null)", .{});
2663 for (self.locals.items, 0..) |*sym, sym_id| {3183 for (coff.locals.items, 0..) |*sym, sym_id| {
2664 const where = if (sym.section_number == .UNDEFINED) "ord" else "sect";3184 const where = if (sym.section_number == .UNDEFINED) "ord" else "sect";
2665 const def_index: u16 = switch (sym.section_number) {3185 const def_index: u16 = switch (sym.section_number) {
2666 .UNDEFINED => 0, // TODO3186 .UNDEFINED => 0, // TODO
...@@ -2670,7 +3190,7 @@ fn logSymtab(self: *Coff) void {...@@ -2670,7 +3190,7 @@ fn logSymtab(self: *Coff) void {
2670 };3190 };
2671 log.debug(" %{d}: {?s} @{x} in {s}({d}), {s}", .{3191 log.debug(" %{d}: {?s} @{x} in {s}({d}), {s}", .{
2672 sym_id,3192 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 }),
2674 sym.value,3194 sym.value,
2675 where,3195 where,
2676 def_index,3196 def_index,
...@@ -2679,20 +3199,20 @@ fn logSymtab(self: *Coff) void {...@@ -2679,20 +3199,20 @@ fn logSymtab(self: *Coff) void {
2679 }3199 }
26803200
2681 log.debug("globals table:", .{});3201 log.debug("globals table:", .{});
2682 for (self.globals.items) |sym_loc| {3202 for (coff.globals.items) |sym_loc| {
2683 const sym_name = self.getSymbolName(sym_loc);3203 const sym_name = coff.getSymbolName(sym_loc);
2684 log.debug(" {s} => %{d} in object({?d})", .{ sym_name, sym_loc.sym_index, sym_loc.file });3204 log.debug(" {s} => %{d} in object({?d})", .{ sym_name, sym_loc.sym_index, sym_loc.file });
2685 }3205 }
26863206
2687 log.debug("GOT entries:", .{});3207 log.debug("GOT entries:", .{});
2688 log.debug("{}", .{self.got_table});3208 log.debug("{}", .{coff.got_table});
2689}3209}
26903210
2691fn logSections(self: *Coff) void {3211fn logSections(coff: *Coff) void {
2692 log.debug("sections:", .{});3212 log.debug("sections:", .{});
2693 for (self.sections.items(.header)) |*header| {3213 for (coff.sections.items(.header)) |*header| {
2694 log.debug(" {s}: VM({x}, {x}) FILE({x}, {x})", .{3214 log.debug(" {s}: VM({x}, {x}) FILE({x}, {x})", .{
2695 self.getSectionName(header),3215 coff.getSectionName(header),
2696 header.virtual_address,3216 header.virtual_address,
2697 header.virtual_address + header.virtual_size,3217 header.virtual_address + header.virtual_size,
2698 header.pointer_to_raw_data,3218 header.pointer_to_raw_data,
...@@ -2701,26 +3221,495 @@ fn logSections(self: *Coff) void {...@@ -2701,26 +3221,495 @@ fn logSections(self: *Coff) void {
2701 }3221 }
2702}3222}
27033223
2704fn logImportTables(self: *const Coff) void {3224fn logImportTables(coff: *const Coff) void {
2705 log.debug("import tables:", .{});3225 log.debug("import tables:", .{});
2706 for (self.import_tables.keys(), 0..) |off, i| {3226 for (coff.import_tables.keys(), 0..) |off, i| {
2707 const itable = self.import_tables.values()[i];3227 const itable = coff.import_tables.values()[i];
2708 log.debug("{}", .{itable.fmtDebug(.{3228 log.debug("{}", .{itable.fmtDebug(.{
2709 .coff_file = self,3229 .coff = coff,
2710 .index = i,3230 .index = i,
2711 .name_off = off,3231 .name_off = off,
2712 })});3232 })});
2713 }3233 }
2714}3234}
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
2716const Coff = @This();3704const Coff = @This();
27173705
2718const std = @import("std");3706const std = @import("std");
2719const build_options = @import("build_options");3707const build_options = @import("build_options");
2720const builtin = @import("builtin");3708const builtin = @import("builtin");
2721const assert = std.debug.assert;3709const assert = std.debug.assert;
2722const coff = std.coff;3710const coff_util = std.coff;
2723const fmt = std.fmt;3711const fmt = std.fmt;
3712const fs = std.fs;
2724const log = std.log.scoped(.link);3713const log = std.log.scoped(.link);
2725const math = std.math;3714const math = std.math;
2726const mem = std.mem;3715const mem = std.mem;
...@@ -2728,23 +3717,21 @@ const mem = std.mem;...@@ -2728,23 +3717,21 @@ const mem = std.mem;
2728const Allocator = std.mem.Allocator;3717const Allocator = std.mem.Allocator;
2729const Path = std.Build.Cache.Path;3718const Path = std.Build.Cache.Path;
2730const Directory = std.Build.Cache.Directory;3719const Directory = std.Build.Cache.Directory;
3720const Cache = std.Build.Cache;
27313721
3722const aarch64_util = @import("../arch/aarch64/bits.zig");
3723const allocPrint = std.fmt.allocPrint;
2732const codegen = @import("../codegen.zig");3724const codegen = @import("../codegen.zig");
2733const link = @import("../link.zig");3725const link = @import("../link.zig");
2734const lld = @import("Coff/lld.zig");
2735const target_util = @import("../target.zig");3726const target_util = @import("../target.zig");
2736const trace = @import("../tracy.zig").trace;3727const trace = @import("../tracy.zig").trace;
27373728
2738const Air = @import("../Air.zig");3729const Air = @import("../Air.zig");
2739pub const Atom = @import("Coff/Atom.zig");
2740const Compilation = @import("../Compilation.zig");3730const Compilation = @import("../Compilation.zig");
2741const ImportTable = @import("Coff/ImportTable.zig");
2742const Liveness = @import("../Liveness.zig");3731const Liveness = @import("../Liveness.zig");
2743const LlvmObject = @import("../codegen/llvm.zig").Object;3732const LlvmObject = @import("../codegen/llvm.zig").Object;
2744const Zcu = @import("../Zcu.zig");3733const Zcu = @import("../Zcu.zig");
2745const InternPool = @import("../InternPool.zig");3734const InternPool = @import("../InternPool.zig");
2746const Object = @import("Coff/Object.zig");
2747const Relocation = @import("Coff/Relocation.zig");
2748const TableSection = @import("table_section.zig").TableSection;3735const TableSection = @import("table_section.zig").TableSection;
2749const StringTable = @import("StringTable.zig");3736const StringTable = @import("StringTable.zig");
2750const Type = @import("../Type.zig");3737const 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}