authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-28 16:10:02+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 10:42:21+02:00
loge5b8a1ac27367402c703a25774bc228499cfeb37
tree673ac4cad74ecb4dd3cfabd295870fe2ffed49db
parent2a994ba4a713f0bd469265ea3c55e335048d4c91

coff: allocate and write atoms to file


2 files changed, 347 insertions(+), 112 deletions(-)

src/link/Coff.zig+334-109
......@@ -23,6 +23,7 @@ const Compilation = @import("../Compilation.zig");
2323const Liveness = @import("../Liveness.zig");
2424const LlvmObject = @import("../codegen/llvm.zig").Object;
2525const Module = @import("../Module.zig");
26const Object = @import("Coff/Object.zig");
2627const StringTable = @import("strtab.zig").StringTable;
2728const TypedValue = @import("../TypedValue.zig");
2829
......@@ -39,6 +40,8 @@ error_flags: link.File.ErrorFlags = .{},
3940ptr_width: PtrWidth,
4041page_size: u32,
4142
43objects: std.ArrayListUnmanaged(Object) = .{},
44
4245sections: std.MultiArrayList(Section) = .{},
4346data_directories: [16]coff.ImageDataDirectory,
4447
......@@ -185,6 +188,11 @@ pub fn deinit(self: *Coff) void {
185188 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
186189 }
187190
191 for (self.objects.items) |*object| {
192 object.deinit(gpa);
193 }
194 self.objects.deinit(gpa);
195
188196 for (self.sections.items(.free_list)) |*free_list| {
189197 free_list.deinit(gpa);
190198 }
......@@ -211,15 +219,15 @@ fn populateMissingMetadata(self: *Coff) !void {
211219
212220 if (self.text_section_index == null) {
213221 self.text_section_index = @intCast(u16, self.sections.slice().len);
214 const file_size = self.base.options.program_code_size_hint;
222 const file_size = @intCast(u32, self.base.options.program_code_size_hint);
215223 const off = self.findFreeSpace(file_size, self.page_size); // TODO we are over-aligning in file; we should track both in file and in memory pointers
216224 log.debug("found .text free space 0x{x} to 0x{x}", .{ off, off + file_size });
217225 var header = coff.SectionHeader{
218226 .name = undefined,
219 .virtual_size = @intCast(u32, file_size),
220 .virtual_address = @intCast(u32, off),
221 .size_of_raw_data = @intCast(u32, file_size),
222 .pointer_to_raw_data = @intCast(u32, off),
227 .virtual_size = file_size,
228 .virtual_address = off,
229 .size_of_raw_data = file_size,
230 .pointer_to_raw_data = off,
223231 .pointer_to_relocations = 0,
224232 .pointer_to_linenumbers = 0,
225233 .number_of_relocations = 0,
......@@ -236,15 +244,15 @@ fn populateMissingMetadata(self: *Coff) !void {
236244
237245 if (self.pdata_section_index == null) {
238246 self.pdata_section_index = @intCast(u16, self.sections.slice().len);
239 const file_size = self.base.options.symbol_count_hint;
247 const file_size = @intCast(u32, self.base.options.symbol_count_hint);
240248 const off = self.findFreeSpace(file_size, self.page_size);
241249 log.debug("found .pdata free space 0x{x} to 0x{x}", .{ off, off + file_size });
242250 var header = coff.SectionHeader{
243251 .name = undefined,
244 .virtual_size = @intCast(u32, file_size),
245 .virtual_address = @intCast(u32, off),
246 .size_of_raw_data = @intCast(u32, file_size),
247 .pointer_to_raw_data = @intCast(u32, off),
252 .virtual_size = file_size,
253 .virtual_address = off,
254 .size_of_raw_data = file_size,
255 .pointer_to_raw_data = off,
248256 .pointer_to_relocations = 0,
249257 .pointer_to_linenumbers = 0,
250258 .number_of_relocations = 0,
......@@ -260,15 +268,15 @@ fn populateMissingMetadata(self: *Coff) !void {
260268
261269 if (self.rdata_section_index == null) {
262270 self.rdata_section_index = @intCast(u16, self.sections.slice().len);
263 const file_size = 1024;
271 const file_size: u32 = 1024;
264272 const off = self.findFreeSpace(file_size, self.page_size);
265273 log.debug("found .rdata free space 0x{x} to 0x{x}", .{ off, off + file_size });
266274 var header = coff.SectionHeader{
267275 .name = undefined,
268 .virtual_size = @intCast(u32, file_size),
269 .virtual_address = @intCast(u32, off),
270 .size_of_raw_data = @intCast(u32, file_size),
271 .pointer_to_raw_data = @intCast(u32, off),
276 .virtual_size = file_size,
277 .virtual_address = off,
278 .size_of_raw_data = file_size,
279 .pointer_to_raw_data = off,
272280 .pointer_to_relocations = 0,
273281 .pointer_to_linenumbers = 0,
274282 .number_of_relocations = 0,
......@@ -284,15 +292,15 @@ fn populateMissingMetadata(self: *Coff) !void {
284292
285293 if (self.data_section_index == null) {
286294 self.data_section_index = @intCast(u16, self.sections.slice().len);
287 const file_size = 1024;
295 const file_size: u32 = 1024;
288296 const off = self.findFreeSpace(file_size, self.page_size);
289297 log.debug("found .data free space 0x{x} to 0x{x}", .{ off, off + file_size });
290298 var header = coff.SectionHeader{
291299 .name = undefined,
292 .virtual_size = @intCast(u32, file_size),
293 .virtual_address = @intCast(u32, off),
294 .size_of_raw_data = @intCast(u32, file_size),
295 .pointer_to_raw_data = @intCast(u32, off),
300 .virtual_size = file_size,
301 .virtual_address = off,
302 .size_of_raw_data = file_size,
303 .pointer_to_raw_data = off,
296304 .pointer_to_relocations = 0,
297305 .pointer_to_linenumbers = 0,
298306 .number_of_relocations = 0,
......@@ -309,7 +317,7 @@ fn populateMissingMetadata(self: *Coff) !void {
309317
310318 if (self.strtab_offset == null) {
311319 try self.strtab.buffer.append(gpa, 0);
312 self.strtab_offset = @intCast(u32, self.findFreeSpace(self.strtab.len(), 1));
320 self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1);
313321 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + self.strtab.len() });
314322 }
315323
......@@ -334,7 +342,7 @@ pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {
334342 try self.decls.putNoClobber(gpa, decl_index, null);
335343}
336344
337fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, sect_id: u16) !u64 {
345fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 {
338346 const tracy = trace(@src());
339347 defer tracy.end();
340348
......@@ -362,10 +370,10 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, se
362370 const sym = big_atom.getSymbol(self);
363371 const capacity = big_atom.capacity(self);
364372 const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity;
365 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;
366 const capacity_end_vaddr = sym.n_value + capacity;
373 const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity;
374 const capacity_end_vaddr = sym.value + capacity;
367375 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
368 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
376 const new_start_vaddr = mem.alignBackwardGeneric(u32, new_start_vaddr_unaligned, alignment);
369377 if (new_start_vaddr < ideal_capacity_end_vaddr) {
370378 // Additional bookkeeping here to notice if this free list node
371379 // should be deleted because the atom that it points to has grown to take up
......@@ -392,23 +400,30 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, se
392400 } else if (maybe_last_atom.*) |last| {
393401 const last_symbol = last.getSymbol(self);
394402 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
395 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
396 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
403 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;
404 const new_start_vaddr = mem.alignForwardGeneric(u32, ideal_capacity_end_vaddr, alignment);
397405 atom_placement = last;
398406 break :blk new_start_vaddr;
399407 } else {
400 break :blk mem.alignForwardGeneric(u64, header.addr, alignment);
408 break :blk mem.alignForwardGeneric(u32, header.virtual_address, alignment);
401409 }
402410 };
403411
404412 const expand_section = atom_placement == null or atom_placement.?.next == null;
405413 if (expand_section) {
406 @panic("TODO expand section in allocateAtom");
414 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
415 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;
416 if (needed_size > sect_capacity) {
417 @panic("TODO move section");
418 }
419 maybe_last_atom.* = atom;
420 header.virtual_size = needed_size;
421 header.size_of_raw_data = needed_size;
407422 }
408423
409 if (header.getAlignment() < alignment) {
410 header.setAlignment(alignment);
411 }
424 // if (header.getAlignment().? < alignment) {
425 // header.setAlignment(alignment);
426 // }
412427 atom.size = new_atom_size;
413428 atom.alignment = alignment;
414429
......@@ -465,30 +480,39 @@ fn allocateSymbol(self: *Coff) !u32 {
465480pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {
466481 const gpa = self.base.allocator;
467482 try self.got_entries.ensureUnusedCapacity(gpa, 1);
468 if (self.got_entries_free_list.popOrNull()) |index| {
469 log.debug(" (reusing GOT entry index {d})", .{index});
470 if (self.got_entries.getIndex(target)) |existing| {
471 assert(existing == index);
483 const index: u32 = blk: {
484 if (self.got_entries_free_list.popOrNull()) |index| {
485 log.debug(" (reusing GOT entry index {d})", .{index});
486 if (self.got_entries.getIndex(target)) |existing| {
487 assert(existing == index);
488 }
489 break :blk index;
490 } else {
491 log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.keys().len});
492 const index = @intCast(u32, self.got_entries.keys().len);
493 self.got_entries.putAssumeCapacityNoClobber(target, 0);
494 break :blk index;
472495 }
473 self.got_entries.keys()[index] = target;
474 return index;
475 } else {
476 log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.keys().len});
477 const index = @intCast(u32, self.got_entries.keys().len);
478 try self.got_entries.putAssumeCapacityNoClobber(target, 0);
479 return index;
480 }
496 };
497 self.got_entries.keys()[index] = target;
498 return index;
499}
500
501fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
502 _ = self;
503 _ = target;
504 @panic("TODO createGotAtom");
481505}
482506
483fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, sect_id: u16) !u64 {
507fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 {
484508 const sym = atom.getSymbol(self);
485 const align_ok = mem.alignBackwardGeneric(u64, sym.value, alignment) == sym.value;
509 const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value;
486510 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
487511 if (!need_realloc) return sym.value;
488512 return self.allocateAtom(atom, new_atom_size, alignment, sect_id);
489513}
490514
491fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u64, sect_id: u16) void {
515fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u32, sect_id: u16) void {
492516 _ = self;
493517 _ = atom;
494518 _ = new_block_size;
......@@ -497,6 +521,22 @@ fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u64, sect_id: u16) void
497521 // capacity, insert a free list node for it.
498522}
499523
524fn writeAtom(self: *Coff, atom: *Atom, code: []const u8, sect_id: u16) !void {
525 const section = self.sections.get(sect_id);
526 const sym = atom.getSymbol(self);
527 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
528 try self.resolveRelocs(atom, code);
529 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
530 try self.base.file.?.pwriteAll(code, file_offset);
531}
532
533fn resolveRelocs(self: *Coff, atom: *Atom, code: []const u8) !void {
534 _ = self;
535 _ = atom;
536 _ = code;
537 log.debug("TODO resolveRelocs", .{});
538}
539
500540fn freeAtom(self: *Coff, atom: *Atom, sect_id: u16) void {
501541 log.debug("freeAtom {*}", .{atom});
502542
......@@ -583,8 +623,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
583623 },
584624 };
585625
586 const sym = try self.updateDeclCode(decl_index, code);
587 log.debug("updated decl code has sym {}", .{sym});
626 try self.updateDeclCode(decl_index, code);
588627
589628 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
590629 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
......@@ -640,20 +679,104 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
640679 },
641680 };
642681
643 const sym = try self.updateDeclCode(decl_index, code);
644 log.debug("updated decl code for {}", .{sym});
682 try self.updateDeclCode(decl_index, code);
645683
646684 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
647685 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
648686 return self.updateDeclExports(module, decl_index, decl_exports);
649687}
650688
651fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) !*coff.Symbol {
652 _ = self;
653 _ = decl_index;
654 _ = code;
655 log.debug("TODO updateDeclCode", .{});
656 return &self.locals.items[0];
689fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 {
690 const ty = decl.ty;
691 const zig_ty = ty.zigTypeTag();
692 const val = decl.val;
693 const index: u16 = blk: {
694 if (val.isUndefDeep()) {
695 // TODO in release-fast and release-small, we should put undef in .bss
696 break :blk self.data_section_index.?;
697 }
698
699 switch (zig_ty) {
700 .Fn => break :blk self.text_section_index.?,
701 else => {
702 if (val.castTag(.variable)) |_| {
703 break :blk self.data_section_index.?;
704 }
705 break :blk self.rdata_section_index.?;
706 },
707 }
708 };
709 return index;
710}
711
712fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) !void {
713 const gpa = self.base.allocator;
714 const mod = self.base.options.module.?;
715 const decl = mod.declPtr(decl_index);
716
717 const decl_name = try decl.getFullyQualifiedName(mod);
718 defer gpa.free(decl_name);
719
720 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
721 const required_alignment = decl.getAlignment(self.base.options.target);
722
723 const decl_ptr = self.decls.getPtr(decl_index).?;
724 if (decl_ptr.* == null) {
725 decl_ptr.* = self.getDeclOutputSection(decl);
726 }
727 const sect_index = decl_ptr.*.?;
728
729 const code_len = @intCast(u32, code.len);
730 const atom = &decl.link.coff;
731 assert(atom.sym_index != 0); // Caller forgot to allocateDeclIndexes()
732 if (atom.size != 0) {
733 const sym = atom.getSymbolPtr(self);
734 const capacity = atom.capacity(self);
735 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
736
737 if (need_realloc) {
738 const vaddr = try self.growAtom(atom, code_len, required_alignment, sect_index);
739 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });
740 log.debug(" (required alignment 0x{x}", .{required_alignment});
741
742 if (vaddr != sym.value) {
743 sym.value = vaddr;
744 log.debug(" (updating GOT entry)", .{});
745 var buffer: [@sizeOf(u64)]u8 = undefined;
746 const got_atom = self.getGotAtomForSymbol(.{ .sym_index = atom.sym_index, .file = null }).?;
747 try self.writeAtom(got_atom, &buffer, self.pdata_section_index.?);
748 }
749 } else if (code_len < atom.size) {
750 self.shrinkAtom(atom, code_len, sect_index);
751 }
752 atom.size = code_len;
753 try self.setSymbolName(sym, decl_name);
754 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
755 sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
756 sym.storage_class = .NULL;
757 } else {
758 const sym = atom.getSymbolPtr(self);
759 try self.setSymbolName(sym, decl_name);
760 const vaddr = try self.allocateAtom(atom, code_len, required_alignment, sect_index);
761 errdefer self.freeAtom(atom, sect_index);
762
763 log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr });
764
765 atom.size = code_len;
766 sym.value = vaddr;
767 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
768 sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
769 sym.storage_class = .NULL;
770
771 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };
772 _ = try self.allocateGotEntry(got_target);
773 const got_atom = try self.createGotAtom(got_target);
774
775 var buffer: [@sizeOf(u64)]u8 = undefined;
776 try self.writeAtom(got_atom, &buffer, self.pdata_section_index.?);
777 }
778
779 try self.writeAtom(atom, code, sect_index);
657780}
658781
659782pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
......@@ -701,40 +824,142 @@ pub fn updateDeclExports(
701824 @panic("Attempted to compile for object format that was disabled by build configuration");
702825 }
703826
704 // Even in the case of LLVM, we need to notice certain exported symbols in order to
705 // detect the default subsystem.
827 if (build_options.have_llvm) {
828 // Even in the case of LLVM, we need to notice certain exported symbols in order to
829 // detect the default subsystem.
830 for (exports) |exp| {
831 const exported_decl = module.declPtr(exp.exported_decl);
832 if (exported_decl.getFunction() == null) continue;
833 const winapi_cc = switch (self.base.options.target.cpu.arch) {
834 .i386 => std.builtin.CallingConvention.Stdcall,
835 else => std.builtin.CallingConvention.C,
836 };
837 const decl_cc = exported_decl.ty.fnCallingConvention();
838 if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and
839 self.base.options.link_libc)
840 {
841 module.stage1_flags.have_c_main = true;
842 } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) {
843 if (mem.eql(u8, exp.options.name, "WinMain")) {
844 module.stage1_flags.have_winmain = true;
845 } else if (mem.eql(u8, exp.options.name, "wWinMain")) {
846 module.stage1_flags.have_wwinmain = true;
847 } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) {
848 module.stage1_flags.have_winmain_crt_startup = true;
849 } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) {
850 module.stage1_flags.have_wwinmain_crt_startup = true;
851 } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) {
852 module.stage1_flags.have_dllmain_crt_startup = true;
853 }
854 }
855 }
856
857 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports);
858 }
859
860 const tracy = trace(@src());
861 defer tracy.end();
862
863 const gpa = self.base.allocator;
864
865 const decl = module.declPtr(decl_index);
866 const atom = &decl.link.coff;
867 if (atom.sym_index == 0) return;
868 const decl_sym = atom.getSymbol(self);
869
706870 for (exports) |exp| {
707 const exported_decl = module.declPtr(exp.exported_decl);
708 if (exported_decl.getFunction() == null) continue;
709 const winapi_cc = switch (self.base.options.target.cpu.arch) {
710 .i386 => std.builtin.CallingConvention.Stdcall,
711 else => std.builtin.CallingConvention.C,
712 };
713 const decl_cc = exported_decl.ty.fnCallingConvention();
714 if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and
715 self.base.options.link_libc)
716 {
717 module.stage1_flags.have_c_main = true;
718 } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) {
719 if (mem.eql(u8, exp.options.name, "WinMain")) {
720 module.stage1_flags.have_winmain = true;
721 } else if (mem.eql(u8, exp.options.name, "wWinMain")) {
722 module.stage1_flags.have_wwinmain = true;
723 } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) {
724 module.stage1_flags.have_winmain_crt_startup = true;
725 } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) {
726 module.stage1_flags.have_wwinmain_crt_startup = true;
727 } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) {
728 module.stage1_flags.have_dllmain_crt_startup = true;
871 log.debug("adding new export '{s}'", .{exp.options.name});
872
873 if (exp.options.section) |section_name| {
874 if (!mem.eql(u8, section_name, ".text")) {
875 try module.failed_exports.putNoClobber(
876 module.gpa,
877 exp,
878 try Module.ErrorMsg.create(
879 gpa,
880 decl.srcLoc(),
881 "Unimplemented: ExportOptions.section",
882 .{},
883 ),
884 );
885 continue;
729886 }
730887 }
888
889 if (exp.options.linkage == .LinkOnce) {
890 try module.failed_exports.putNoClobber(
891 module.gpa,
892 exp,
893 try Module.ErrorMsg.create(
894 gpa,
895 decl.srcLoc(),
896 "Unimplemented: GlobalLinkage.LinkOnce",
897 .{},
898 ),
899 );
900 continue;
901 }
902
903 const sym_index = exp.link.macho.sym_index orelse blk: {
904 const sym_index = try self.allocateSymbol();
905 exp.link.coff.sym_index = sym_index;
906 break :blk sym_index;
907 };
908 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
909 const sym = self.getSymbolPtr(sym_loc);
910 try self.setSymbolName(sym, exp.options.name);
911 sym.value = decl_sym.value;
912 sym.section_number = @intToEnum(coff.SectionNumber, self.text_section_index.? + 1);
913 sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
914
915 switch (exp.options.linkage) {
916 .Strong => {
917 sym.storage_class = .EXTERNAL;
918 },
919 .Internal => @panic("TODO Internal"),
920 .Weak => @panic("TODO WeakExternal"),
921 else => unreachable,
922 }
923
924 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
925 error.MultipleSymbolDefinitions => {
926 const global = self.globals.get(exp.options.name).?;
927 if (sym_loc.sym_index != global.sym_index and global.file != null) {
928 _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(
929 gpa,
930 decl.srcLoc(),
931 \\LinkError: symbol '{s}' defined multiple times
932 \\ first definition in '{s}'
933 ,
934 .{ exp.options.name, self.objects.items[global.file.?].name },
935 ));
936 }
937 },
938 else => |e| return e,
939 };
731940 }
941}
732942
733 if (build_options.have_llvm) {
734 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports);
943fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
944 const gpa = self.base.allocator;
945 const sym = self.getSymbol(current);
946 _ = sym;
947 const sym_name = self.getSymbolName(current);
948
949 const name = try gpa.dupe(u8, sym_name);
950 const global_index = @intCast(u32, self.globals.values().len);
951 _ = global_index;
952 const gop = try self.globals.getOrPut(gpa, name);
953 defer if (gop.found_existing) gpa.free(name);
954
955 if (!gop.found_existing) {
956 gop.value_ptr.* = current;
957 // TODO undef + tentative
958 return;
735959 }
736960
737 log.debug("TODO updateDeclExports", .{});
961 log.debug("TODO finish resolveGlobalSymbols implementation", .{});
962 return error.MultipleSymbolDefinitions;
738963}
739964
740965pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {
......@@ -805,7 +1030,7 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
8051030
8061031fn writeStrtab(self: *Coff) !void {
8071032 const allocated_size = self.allocatedSize(self.strtab_offset.?);
808 const needed_size = self.strtab.len();
1033 const needed_size = @intCast(u32, self.strtab.len());
8091034
8101035 if (needed_size > allocated_size) {
8111036 self.strtab_offset = null;
......@@ -870,7 +1095,7 @@ fn writeHeader(self: *Coff) !void {
8701095 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention
8711096 };
8721097 const subsystem: coff.Subsystem = .WINDOWS_CUI;
873 const size_of_headers: u32 = @intCast(u32, self.getSizeOfHeaders());
1098 const size_of_headers: u32 = self.getSizeOfHeaders();
8741099 const size_of_image_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, self.page_size);
8751100 const size_of_headers_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, default_file_alignment);
8761101 const image_base = self.base.options.image_base_override orelse switch (self.base.options.output_mode) {
......@@ -968,7 +1193,7 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
9681193 math.maxInt(@TypeOf(actual_size));
9691194}
9701195
971fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {
1196fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
9721197 const headers_size = self.getSizeOfHeaders();
9731198 if (start < headers_size)
9741199 return headers_size;
......@@ -976,7 +1201,7 @@ fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {
9761201 const end = start + padToIdeal(size);
9771202
9781203 if (self.strtab_offset) |off| {
979 const increased_size = padToIdeal(self.strtab.len());
1204 const increased_size = padToIdeal(@intCast(u32, self.strtab.len()));
9801205 const test_end = off + increased_size;
9811206 if (end > off and start < test_end) {
9821207 return test_end;
......@@ -994,10 +1219,10 @@ fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {
9941219 return null;
9951220}
9961221
997pub fn allocatedSize(self: *Coff, start: u64) u64 {
1222pub fn allocatedSize(self: *Coff, start: u32) u32 {
9981223 if (start == 0)
9991224 return 0;
1000 var min_pos: u64 = std.math.maxInt(u64);
1225 var min_pos: u32 = std.math.maxInt(u32);
10011226 if (self.strtab_offset) |off| {
10021227 if (off > start and off < min_pos) min_pos = off;
10031228 }
......@@ -1008,41 +1233,41 @@ pub fn allocatedSize(self: *Coff, start: u64) u64 {
10081233 return min_pos - start;
10091234}
10101235
1011pub fn findFreeSpace(self: *Coff, object_size: u64, min_alignment: u32) u64 {
1012 var start: u64 = 0;
1236pub fn findFreeSpace(self: *Coff, object_size: u32, min_alignment: u32) u32 {
1237 var start: u32 = 0;
10131238 while (self.detectAllocCollision(start, object_size)) |item_end| {
1014 start = mem.alignForwardGeneric(u64, item_end, min_alignment);
1239 start = mem.alignForwardGeneric(u32, item_end, min_alignment);
10151240 }
10161241 return start;
10171242}
10181243
1019inline fn getSizeOfHeaders(self: Coff) usize {
1244inline fn getSizeOfHeaders(self: Coff) u32 {
10201245 const msdos_hdr_size = msdos_stub.len + 8;
1021 return msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() +
1022 self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize();
1246 return @intCast(u32, msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() +
1247 self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize());
10231248}
10241249
1025inline fn getOptionalHeaderSize(self: Coff) usize {
1250inline fn getOptionalHeaderSize(self: Coff) u32 {
10261251 return switch (self.ptr_width) {
1027 .p32 => @sizeOf(coff.OptionalHeaderPE32),
1028 .p64 => @sizeOf(coff.OptionalHeaderPE64),
1252 .p32 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE32)),
1253 .p64 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE64)),
10291254 };
10301255}
10311256
1032inline fn getDataDirectoryHeadersSize(self: Coff) usize {
1033 return self.data_directories.len * @sizeOf(coff.ImageDataDirectory);
1257inline fn getDataDirectoryHeadersSize(self: Coff) u32 {
1258 return @intCast(u32, self.data_directories.len * @sizeOf(coff.ImageDataDirectory));
10341259}
10351260
1036inline fn getSectionHeadersSize(self: Coff) usize {
1037 return self.sections.slice().len * @sizeOf(coff.SectionHeader);
1261inline fn getSectionHeadersSize(self: Coff) u32 {
1262 return @intCast(u32, self.sections.slice().len * @sizeOf(coff.SectionHeader));
10381263}
10391264
1040inline fn getDataDirectoryHeadersOffset(self: Coff) usize {
1265inline fn getDataDirectoryHeadersOffset(self: Coff) u32 {
10411266 const msdos_hdr_size = msdos_stub.len + 8;
1042 return msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize();
1267 return @intCast(u32, msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize());
10431268}
10441269
1045inline fn getSectionHeadersOffset(self: Coff) usize {
1270inline fn getSectionHeadersOffset(self: Coff) u32 {
10461271 return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize();
10471272}
10481273
......@@ -1086,7 +1311,7 @@ fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !v
10861311 return;
10871312 }
10881313 const offset = try self.strtab.insert(self.base.allocator, name);
1089 const name_offset = try fmt.bufPrint(&header.name, "/{d}", .{offset});
1314 const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable;
10901315 mem.set(u8, header.name[name_offset.len..], 0);
10911316}
10921317
......@@ -1097,6 +1322,6 @@ fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {
10971322 return;
10981323 }
10991324 const offset = try self.strtab.insert(self.base.allocator, name);
1100 mem.copy(u8, symbol.name[0..4], 0);
1101 _ = try fmt.bufPrint(symbol.name[4..], "{d}", .{offset});
1325 mem.set(u8, symbol.name[0..4], 0);
1326 _ = fmt.bufPrint(symbol.name[4..], "{d}", .{offset}) catch unreachable;
11021327}
src/link/Coff/Atom.zig+13-3
......@@ -20,7 +20,7 @@ sym_index: u32,
2020file: ?u32,
2121
2222/// Used size of the atom
23size: u64,
23size: u32,
2424
2525/// Alignment of the atom
2626alignment: u32,
......@@ -44,10 +44,12 @@ pub fn deinit(self: *Atom, gpa: Allocator) void {
4444 _ = gpa;
4545}
4646
47/// Returns symbol referencing this atom.
4748pub fn getSymbol(self: Atom, coff_file: *Coff) coff.Symbol {
4849 return self.getSymbolPtr(coff_file).*;
4950}
5051
52/// Returns pointer-to-symbol referencing this atom.
5153pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol {
5254 return coff_file.getSymbolPtr(.{
5355 .sym_index = self.sym_index,
......@@ -59,8 +61,16 @@ pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {
5961 return .{ .sym_index = self.sym_index, .file = self.file };
6062}
6163
64/// Returns the name of this atom.
65pub fn getName(self: Atom, coff_file: *Coff) []const u8 {
66 return coff_file.getSymbolName(.{
67 .sym_index = self.sym_index,
68 .file = self.file,
69 });
70}
71
6272/// Returns how much room there is to grow in virtual address space.
63pub fn capacity(self: Atom, coff_file: *Coff) u64 {
73pub fn capacity(self: Atom, coff_file: *Coff) u32 {
6474 const self_sym = self.getSymbol(coff_file);
6575 if (self.next) |next| {
6676 const next_sym = next.getSymbol(coff_file);
......@@ -68,7 +78,7 @@ pub fn capacity(self: Atom, coff_file: *Coff) u64 {
6878 } else {
6979 // We are the last atom.
7080 // The capacity is limited only by virtual address space.
71 return std.math.maxInt(u64) - self_sym.value;
81 return std.math.maxInt(u32) - self_sym.value;
7282 }
7383}
7484