authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-29 08:50:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 10:42:21+02:00
log30baba899cd20c6bc2224f3713f58ba40bbd8709
treecb3e07d794b9a7ba21e9f9dc019b1281c3a06fd0
parente5b8a1ac27367402c703a25774bc228499cfeb37

coff: add missing bits required for minimal PE example


3 files changed, 243 insertions(+), 77 deletions(-)

lib/std/start.zig+1-1
...@@ -37,7 +37,7 @@ comptime {...@@ -37,7 +37,7 @@ comptime {
37 @export(main2, .{ .name = "main" });37 @export(main2, .{ .name = "main" });
38 }38 }
39 } else if (builtin.os.tag == .windows) {39 } else if (builtin.os.tag == .windows) {
40 if (!@hasDecl(root, "wWinMainCRTStartup")) {40 if (!@hasDecl(root, "wWinMainCRTStartup") and !@hasDecl(root, "mainCRTStartup")) {
41 @export(wWinMainCRTStartup2, .{ .name = "wWinMainCRTStartup" });41 @export(wWinMainCRTStartup2, .{ .name = "wWinMainCRTStartup" });
42 }42 }
43 } else if (builtin.os.tag == .wasi and @hasDecl(root, "main")) {43 } else if (builtin.os.tag == .wasi and @hasDecl(root, "main")) {
src/Module.zig+3
...@@ -5391,6 +5391,9 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {...@@ -5391,6 +5391,9 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {
5391 if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {5391 if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {
5392 wasm.deleteExport(exp.link.wasm);5392 wasm.deleteExport(exp.link.wasm);
5393 }5393 }
5394 if (mod.comp.bin_file.cast(link.File.Coff)) |coff| {
5395 coff.deleteExport(exp.link.coff);
5396 }
5394 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {5397 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
5395 failed_kv.value.destroy(mod.gpa);5398 failed_kv.value.destroy(mod.gpa);
5396 }5399 }
src/link/Coff.zig+239-76
...@@ -46,8 +46,8 @@ sections: std.MultiArrayList(Section) = .{},...@@ -46,8 +46,8 @@ sections: std.MultiArrayList(Section) = .{},
46data_directories: [16]coff.ImageDataDirectory,46data_directories: [16]coff.ImageDataDirectory,
4747
48text_section_index: ?u16 = null,48text_section_index: ?u16 = null,
49got_section_index: ?u16 = null,
49rdata_section_index: ?u16 = null,50rdata_section_index: ?u16 = null,
50pdata_section_index: ?u16 = null,
51data_section_index: ?u16 = null,51data_section_index: ?u16 = null,
5252
53locals: std.ArrayListUnmanaged(coff.Symbol) = .{},53locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
...@@ -76,9 +76,49 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},...@@ -76,9 +76,49 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
76/// Table of atoms indexed by the symbol index.76/// Table of atoms indexed by the symbol index.
77atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},77atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
7878
79/// Table of unnamed constants associated with a parent `Decl`.
80/// We store them here so that we can free the constants whenever the `Decl`
81/// needs updating or is freed.
82///
83/// For example,
84///
85/// ```zig
86/// const Foo = struct{
87/// a: u8,
88/// };
89///
90/// pub fn main() void {
91/// var foo = Foo{ .a = 1 };
92/// _ = foo;
93/// }
94/// ```
95///
96/// value assigned to label `foo` is an unnamed constant belonging/associated
97/// with `Decl` `main`, and lives as long as that `Decl`.
98unnamed_const_atoms: UnnamedConstTable = .{},
99
100/// A table of relocations indexed by the owning them `TextBlock`.
101/// Note that once we refactor `TextBlock`'s lifetime and ownership rules,
102/// this will be a table indexed by index into the list of Atoms.
103relocs: RelocTable = .{},
104
105const Reloc = struct {
106 target: SymbolWithLoc,
107 offset: u32,
108 addend: u32,
109 prev_vaddr: u32,
110};
111
112const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc));
113const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));
114
79const default_file_alignment: u16 = 0x200;115const default_file_alignment: u16 = 0x200;
80const default_image_base_dll: u64 = 0x10000000;116const default_image_base_dll: u64 = 0x10000000;
81const default_image_base_exe: u64 = 0x10000;117const default_image_base_exe: u64 = 0x10000;
118const default_size_of_stack_reserve: u32 = 0x1000000;
119const default_size_of_stack_commit: u32 = 0x1000;
120const default_size_of_heap_reserve: u32 = 0x100000;
121const default_size_of_heap_commit: u32 = 0x1000;
82122
83const Section = struct {123const Section = struct {
84 header: coff.SectionHeader,124 header: coff.SectionHeader,
...@@ -211,6 +251,22 @@ pub fn deinit(self: *Coff) void {...@@ -211,6 +251,22 @@ pub fn deinit(self: *Coff) void {
211 self.got_entries_free_list.deinit(gpa);251 self.got_entries_free_list.deinit(gpa);
212 self.decls.deinit(gpa);252 self.decls.deinit(gpa);
213 self.atom_by_index_table.deinit(gpa);253 self.atom_by_index_table.deinit(gpa);
254
255 {
256 var it = self.unnamed_const_atoms.valueIterator();
257 while (it.next()) |atoms| {
258 atoms.deinit(gpa);
259 }
260 self.unnamed_const_atoms.deinit(gpa);
261 }
262
263 {
264 var it = self.relocs.valueIterator();
265 while (it.next()) |relocs| {
266 relocs.deinit(gpa);
267 }
268 self.relocs.deinit(gpa);
269 }
214}270}
215271
216fn populateMissingMetadata(self: *Coff) !void {272fn populateMissingMetadata(self: *Coff) !void {
...@@ -242,11 +298,11 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -242,11 +298,11 @@ fn populateMissingMetadata(self: *Coff) !void {
242 try self.sections.append(gpa, .{ .header = header });298 try self.sections.append(gpa, .{ .header = header });
243 }299 }
244300
245 if (self.pdata_section_index == null) {301 if (self.got_section_index == null) {
246 self.pdata_section_index = @intCast(u16, self.sections.slice().len);302 self.got_section_index = @intCast(u16, self.sections.slice().len);
247 const file_size = @intCast(u32, self.base.options.symbol_count_hint);303 const file_size = @intCast(u32, self.base.options.symbol_count_hint);
248 const off = self.findFreeSpace(file_size, self.page_size);304 const off = self.findFreeSpace(file_size, self.page_size);
249 log.debug("found .pdata free space 0x{x} to 0x{x}", .{ off, off + file_size });305 log.debug("found .got free space 0x{x} to 0x{x}", .{ off, off + file_size });
250 var header = coff.SectionHeader{306 var header = coff.SectionHeader{
251 .name = undefined,307 .name = undefined,
252 .virtual_size = file_size,308 .virtual_size = file_size,
...@@ -262,7 +318,7 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -262,7 +318,7 @@ fn populateMissingMetadata(self: *Coff) !void {
262 .MEM_READ = 1,318 .MEM_READ = 1,
263 },319 },
264 };320 };
265 try self.setSectionName(&header, ".pdata");321 try self.setSectionName(&header, ".got");
266 try self.sections.append(gpa, .{ .header = header });322 try self.sections.append(gpa, .{ .header = header });
267 }323 }
268324
...@@ -330,6 +386,20 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -330,6 +386,20 @@ fn populateMissingMetadata(self: *Coff) !void {
330 .storage_class = .NULL,386 .storage_class = .NULL,
331 .number_of_aux_symbols = 0,387 .number_of_aux_symbols = 0,
332 });388 });
389
390 {
391 // We need to find out what the max file offset is according to section headers.
392 // Otherwise, we may end up with an COFF binary with file size not matching the final section's
393 // offset + it's filesize.
394 // TODO I don't like this here one bit
395 var max_file_offset: u64 = 0;
396 for (self.sections.items(.header)) |header| {
397 if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) {
398 max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data;
399 }
400 }
401 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);
402 }
333}403}
334404
335pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {405pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {
...@@ -418,7 +488,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, se...@@ -418,7 +488,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, se
418 }488 }
419 maybe_last_atom.* = atom;489 maybe_last_atom.* = atom;
420 header.virtual_size = needed_size;490 header.virtual_size = needed_size;
421 header.size_of_raw_data = needed_size;491 header.size_of_raw_data = mem.alignForwardGeneric(u32, needed_size, default_file_alignment);
422 }492 }
423493
424 // if (header.getAlignment().? < alignment) {494 // if (header.getAlignment().? < alignment) {
...@@ -499,9 +569,35 @@ pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {...@@ -499,9 +569,35 @@ pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {
499}569}
500570
501fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {571fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
502 _ = self;572 const gpa = self.base.allocator;
503 _ = target;573 const atom = try gpa.create(Atom);
504 @panic("TODO createGotAtom");574 errdefer gpa.destroy(atom);
575 atom.* = Atom.empty;
576 atom.sym_index = try self.allocateSymbol();
577 atom.size = @sizeOf(u64);
578 atom.alignment = @alignOf(u64);
579
580 try self.managed_atoms.append(gpa, atom);
581 try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom);
582
583 const sym = atom.getSymbolPtr(self);
584 sym.value = try self.allocateAtom(atom, atom.size, atom.alignment, self.got_section_index.?);
585 sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1);
586
587 log.debug("allocated {s} atom at 0x{x}", .{ atom.getName(self), sym.value });
588
589 const gop_relocs = try self.relocs.getOrPut(gpa, atom);
590 if (!gop_relocs.found_existing) {
591 gop_relocs.value_ptr.* = .{};
592 }
593 try gop_relocs.value_ptr.append(gpa, .{
594 .target = target,
595 .offset = 0,
596 .addend = 0,
597 .prev_vaddr = sym.value,
598 });
599
600 return atom;
505}601}
506602
507fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 {603fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 {
...@@ -525,16 +621,46 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8, sect_id: u16) !void {...@@ -525,16 +621,46 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8, sect_id: u16) !void {
525 const section = self.sections.get(sect_id);621 const section = self.sections.get(sect_id);
526 const sym = atom.getSymbol(self);622 const sym = atom.getSymbol(self);
527 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;623 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
528 try self.resolveRelocs(atom, code);624 const resolved = try self.resolveRelocs(atom, code);
625 defer self.base.allocator.free(resolved);
529 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });626 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);627 try self.base.file.?.pwriteAll(resolved, file_offset);
531}628}
532629
533fn resolveRelocs(self: *Coff, atom: *Atom, code: []const u8) !void {630fn writeGotAtom(self: *Coff, atom: *Atom) !void {
534 _ = self;631 switch (self.ptr_width) {
535 _ = atom;632 .p32 => {
536 _ = code;633 var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32);
537 log.debug("TODO resolveRelocs", .{});634 try self.writeAtom(atom, &buffer, self.got_section_index.?);
635 },
636 .p64 => {
637 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
638 try self.writeAtom(atom, &buffer, self.got_section_index.?);
639 },
640 }
641}
642
643fn resolveRelocs(self: *Coff, atom: *Atom, code: []const u8) ![]const u8 {
644 const gpa = self.base.allocator;
645 const resolved = try gpa.dupe(u8, code);
646 const relocs = self.relocs.get(atom) orelse return resolved;
647
648 for (relocs.items) |*reloc| {
649 const target_sym = self.getSymbol(reloc.target);
650 const target_vaddr = target_sym.value + reloc.addend;
651 if (target_vaddr == reloc.prev_vaddr) continue;
652
653 log.debug(" ({x}: [() => 0x{x} ({s}))", .{ reloc.offset, target_vaddr, self.getSymbolName(reloc.target) });
654
655 switch (self.ptr_width) {
656 .p32 => mem.writeIntLittle(u32, resolved[reloc.offset..][0..4], @intCast(u32, target_vaddr)),
657 .p64 => mem.writeIntLittle(u64, resolved[reloc.offset..][0..8], target_vaddr),
658 }
659
660 reloc.prev_vaddr = target_vaddr;
661 }
662
663 return resolved;
538}664}
539665
540fn freeAtom(self: *Coff, atom: *Atom, sect_id: u16) void {666fn freeAtom(self: *Coff, atom: *Atom, sect_id: u16) void {
...@@ -623,7 +749,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live...@@ -623,7 +749,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
623 },749 },
624 };750 };
625751
626 try self.updateDeclCode(decl_index, code);752 try self.updateDeclCode(decl_index, code, .FUNCTION);
627753
628 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.754 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
629 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};755 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
...@@ -679,7 +805,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -679,7 +805,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
679 },805 },
680 };806 };
681807
682 try self.updateDeclCode(decl_index, code);808 try self.updateDeclCode(decl_index, code, .NULL);
683809
684 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.810 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
685 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};811 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
...@@ -709,7 +835,7 @@ fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 {...@@ -709,7 +835,7 @@ fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 {
709 return index;835 return index;
710}836}
711837
712fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) !void {838fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, complex_type: coff.ComplexType) !void {
713 const gpa = self.base.allocator;839 const gpa = self.base.allocator;
714 const mod = self.base.options.module.?;840 const mod = self.base.options.module.?;
715 const decl = mod.declPtr(decl_index);841 const decl = mod.declPtr(decl_index);
...@@ -742,9 +868,8 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8)...@@ -742,9 +868,8 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8)
742 if (vaddr != sym.value) {868 if (vaddr != sym.value) {
743 sym.value = vaddr;869 sym.value = vaddr;
744 log.debug(" (updating GOT entry)", .{});870 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 }).?;871 const got_atom = self.getGotAtomForSymbol(.{ .sym_index = atom.sym_index, .file = null }).?;
747 try self.writeAtom(got_atom, &buffer, self.pdata_section_index.?);872 try self.writeGotAtom(got_atom);
748 }873 }
749 } else if (code_len < atom.size) {874 } else if (code_len < atom.size) {
750 self.shrinkAtom(atom, code_len, sect_index);875 self.shrinkAtom(atom, code_len, sect_index);
...@@ -752,8 +877,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8)...@@ -752,8 +877,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8)
752 atom.size = code_len;877 atom.size = code_len;
753 try self.setSymbolName(sym, decl_name);878 try self.setSymbolName(sym, decl_name);
754 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);879 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
755 sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };880 sym.@"type" = .{ .complex_type = complex_type, .base_type = .NULL };
756 sym.storage_class = .NULL;
757 } else {881 } else {
758 const sym = atom.getSymbolPtr(self);882 const sym = atom.getSymbolPtr(self);
759 try self.setSymbolName(sym, decl_name);883 try self.setSymbolName(sym, decl_name);
...@@ -765,15 +889,12 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8)...@@ -765,15 +889,12 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8)
765 atom.size = code_len;889 atom.size = code_len;
766 sym.value = vaddr;890 sym.value = vaddr;
767 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);891 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
768 sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };892 sym.@"type" = .{ .complex_type = complex_type, .base_type = .NULL };
769 sym.storage_class = .NULL;
770893
771 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };894 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };
772 _ = try self.allocateGotEntry(got_target);895 _ = try self.allocateGotEntry(got_target);
773 const got_atom = try self.createGotAtom(got_target);896 const got_atom = try self.createGotAtom(got_target);
774897 try self.writeGotAtom(got_atom);
775 var buffer: [@sizeOf(u64)]u8 = undefined;
776 try self.writeAtom(got_atom, &buffer, self.pdata_section_index.?);
777 }898 }
778899
779 try self.writeAtom(atom, code, sect_index);900 try self.writeAtom(atom, code, sect_index);
...@@ -900,7 +1021,7 @@ pub fn updateDeclExports(...@@ -900,7 +1021,7 @@ pub fn updateDeclExports(
900 continue;1021 continue;
901 }1022 }
9021023
903 const sym_index = exp.link.macho.sym_index orelse blk: {1024 const sym_index = exp.link.coff.sym_index orelse blk: {
904 const sym_index = try self.allocateSymbol();1025 const sym_index = try self.allocateSymbol();
905 exp.link.coff.sym_index = sym_index;1026 exp.link.coff.sym_index = sym_index;
906 break :blk sym_index;1027 break :blk sym_index;
...@@ -921,22 +1042,36 @@ pub fn updateDeclExports(...@@ -921,22 +1042,36 @@ pub fn updateDeclExports(
921 else => unreachable,1042 else => unreachable,
922 }1043 }
9231044
924 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {1045 try self.resolveGlobalSymbol(sym_loc);
925 error.MultipleSymbolDefinitions => {1046 }
926 const global = self.globals.get(exp.options.name).?;1047}
927 if (sym_loc.sym_index != global.sym_index and global.file != null) {1048
928 _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(1049pub fn deleteExport(self: *Coff, exp: Export) void {
929 gpa,1050 if (self.llvm_object) |_| return;
930 decl.srcLoc(),1051 const sym_index = exp.sym_index orelse return;
931 \\LinkError: symbol '{s}' defined multiple times1052
932 \\ first definition in '{s}'1053 const gpa = self.base.allocator;
933 ,1054
934 .{ exp.options.name, self.objects.items[global.file.?].name },1055 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
935 ));1056 const sym = self.getSymbolPtr(sym_loc);
936 }1057 const sym_name = self.getSymbolName(sym_loc);
937 },1058 log.debug("deleting export '{s}'", .{sym_name});
938 else => |e| return e,1059 assert(sym.storage_class == .EXTERNAL);
939 };1060 sym.* = .{
1061 .name = [_]u8{0} ** 8,
1062 .value = 0,
1063 .section_number = @intToEnum(coff.SectionNumber, 0),
1064 .@"type" = .{ .base_type = .NULL, .complex_type = .NULL },
1065 .storage_class = .NULL,
1066 .number_of_aux_symbols = 0,
1067 };
1068 self.locals_free_list.append(gpa, sym_index) catch {};
1069
1070 if (self.globals.get(sym_name)) |global| blk: {
1071 if (global.sym_index != sym_index) break :blk;
1072 if (global.file != null) break :blk;
1073 const kv = self.globals.fetchSwapRemove(sym_name);
1074 gpa.free(kv.?.key);
940 }1075 }
941}1076}
9421077
...@@ -959,7 +1094,6 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {...@@ -959,7 +1094,6 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
959 }1094 }
9601095
961 log.debug("TODO finish resolveGlobalSymbols implementation", .{});1096 log.debug("TODO finish resolveGlobalSymbols implementation", .{});
962 return error.MultipleSymbolDefinitions;
963}1097}
9641098
965pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {1099pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {
...@@ -995,10 +1129,13 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -995,10 +1129,13 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
995 sub_prog_node.activate();1129 sub_prog_node.activate();
996 defer sub_prog_node.end();1130 defer sub_prog_node.end();
9971131
1132 if (self.getEntryPoint()) |entry_sym_loc| {
1133 self.entry_addr = self.getSymbol(entry_sym_loc).value;
1134 }
1135
998 try self.writeStrtab();1136 try self.writeStrtab();
999 try self.writeDataDirectoriesHeaders();1137 try self.writeDataDirectoriesHeaders();
1000 try self.writeSectionHeaders();1138 try self.writeSectionHeaders();
1001 try self.writeHeader();
10021139
1003 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {1140 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
1004 log.debug("flushing. no_entry_point_found = true\n", .{});1141 log.debug("flushing. no_entry_point_found = true\n", .{});
...@@ -1006,8 +1143,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1006,8 +1143,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1006 } else {1143 } else {
1007 log.debug("flushing. no_entry_point_found = false\n", .{});1144 log.debug("flushing. no_entry_point_found = false\n", .{});
1008 self.error_flags.no_entry_point_found = false;1145 self.error_flags.no_entry_point_found = false;
1146 try self.writeHeader();
1009 }1147 }
1010 self.error_flags.no_entry_point_found = false;
1011}1148}
10121149
1013pub fn getDeclVAddr(1150pub fn getDeclVAddr(
...@@ -1075,11 +1212,12 @@ fn writeHeader(self: *Coff) !void {...@@ -1075,11 +1212,12 @@ fn writeHeader(self: *Coff) !void {
1075 flags.DLL = 1;1212 flags.DLL = 1;
1076 }1213 }
10771214
1215 const timestamp = std.time.timestamp();
1078 const size_of_optional_header = @intCast(u16, self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize());1216 const size_of_optional_header = @intCast(u16, self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize());
1079 var coff_header = coff.CoffHeader{1217 var coff_header = coff.CoffHeader{
1080 .machine = coff.MachineType.fromTargetCpuArch(self.base.options.target.cpu.arch),1218 .machine = coff.MachineType.fromTargetCpuArch(self.base.options.target.cpu.arch),
1081 .number_of_sections = @intCast(u16, self.sections.slice().len), // TODO what if we prune a section1219 .number_of_sections = @intCast(u16, self.sections.slice().len), // TODO what if we prune a section
1082 .time_date_stamp = 0, // TODO1220 .time_date_stamp = @truncate(u32, @bitCast(u64, timestamp)),
1083 .pointer_to_symbol_table = self.strtab_offset orelse 0,1221 .pointer_to_symbol_table = self.strtab_offset orelse 0,
1084 .number_of_symbols = 0,1222 .number_of_symbols = 0,
1085 .size_of_optional_header = size_of_optional_header,1223 .size_of_optional_header = size_of_optional_header,
...@@ -1095,20 +1233,30 @@ fn writeHeader(self: *Coff) !void {...@@ -1095,20 +1233,30 @@ fn writeHeader(self: *Coff) !void {
1095 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention1233 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention
1096 };1234 };
1097 const subsystem: coff.Subsystem = .WINDOWS_CUI;1235 const subsystem: coff.Subsystem = .WINDOWS_CUI;
1098 const size_of_headers: u32 = self.getSizeOfHeaders();1236 const size_of_image: u32 = self.getSizeOfImage();
1099 const size_of_image_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, self.page_size);1237 const size_of_headers: u32 = mem.alignForwardGeneric(u32, self.getSizeOfHeaders(), default_file_alignment);
1100 const size_of_headers_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, default_file_alignment);
1101 const image_base = self.base.options.image_base_override orelse switch (self.base.options.output_mode) {1238 const image_base = self.base.options.image_base_override orelse switch (self.base.options.output_mode) {
1102 .Exe => default_image_base_exe,1239 .Exe => default_image_base_exe,
1103 .Lib => default_image_base_dll,1240 .Lib => default_image_base_dll,
1104 else => unreachable,1241 else => unreachable,
1105 };1242 };
1106 const text_section = self.sections.get(self.text_section_index.?).header;
11071243
1244 const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address;
1245 const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address;
1246
1247 var size_of_code: u32 = 0;
1108 var size_of_initialized_data: u32 = 0;1248 var size_of_initialized_data: u32 = 0;
1249 var size_of_uninitialized_data: u32 = 0;
1109 for (self.sections.items(.header)) |header| {1250 for (self.sections.items(.header)) |header| {
1110 if (header.flags.CNT_INITIALIZED_DATA == 0) continue;1251 if (header.flags.CNT_CODE == 1) {
1111 size_of_initialized_data += header.virtual_size;1252 size_of_code += header.size_of_raw_data;
1253 }
1254 if (header.flags.CNT_INITIALIZED_DATA == 1) {
1255 size_of_initialized_data += header.size_of_raw_data;
1256 }
1257 if (header.flags.CNT_UNINITIALIZED_DATA == 1) {
1258 size_of_uninitialized_data += header.size_of_raw_data;
1259 }
1112 }1260 }
11131261
1114 switch (self.ptr_width) {1262 switch (self.ptr_width) {
...@@ -1117,12 +1265,12 @@ fn writeHeader(self: *Coff) !void {...@@ -1117,12 +1265,12 @@ fn writeHeader(self: *Coff) !void {
1117 .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC,1265 .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC,
1118 .major_linker_version = 0,1266 .major_linker_version = 0,
1119 .minor_linker_version = 0,1267 .minor_linker_version = 0,
1120 .size_of_code = text_section.virtual_size,1268 .size_of_code = size_of_code,
1121 .size_of_initialized_data = size_of_initialized_data,1269 .size_of_initialized_data = size_of_initialized_data,
1122 .size_of_uninitialized_data = 0,1270 .size_of_uninitialized_data = size_of_uninitialized_data,
1123 .address_of_entry_point = self.entry_addr orelse 0,1271 .address_of_entry_point = self.entry_addr orelse 0,
1124 .base_of_code = text_section.virtual_address,1272 .base_of_code = base_of_code,
1125 .base_of_data = 0,1273 .base_of_data = base_of_data,
1126 .image_base = @intCast(u32, image_base),1274 .image_base = @intCast(u32, image_base),
1127 .section_alignment = self.page_size,1275 .section_alignment = self.page_size,
1128 .file_alignment = default_file_alignment,1276 .file_alignment = default_file_alignment,
...@@ -1133,15 +1281,15 @@ fn writeHeader(self: *Coff) !void {...@@ -1133,15 +1281,15 @@ fn writeHeader(self: *Coff) !void {
1133 .major_subsystem_version = 6,1281 .major_subsystem_version = 6,
1134 .minor_subsystem_version = 0,1282 .minor_subsystem_version = 0,
1135 .win32_version_value = 0,1283 .win32_version_value = 0,
1136 .size_of_image = size_of_image_aligned,1284 .size_of_image = size_of_image,
1137 .size_of_headers = size_of_headers_aligned,1285 .size_of_headers = size_of_headers,
1138 .checksum = 0,1286 .checksum = 0,
1139 .subsystem = subsystem,1287 .subsystem = subsystem,
1140 .dll_flags = dll_flags,1288 .dll_flags = dll_flags,
1141 .size_of_stack_reserve = 0,1289 .size_of_stack_reserve = default_size_of_stack_reserve,
1142 .size_of_stack_commit = 0,1290 .size_of_stack_commit = default_size_of_stack_commit,
1143 .size_of_heap_reserve = 0,1291 .size_of_heap_reserve = default_size_of_heap_reserve,
1144 .size_of_heap_commit = 0,1292 .size_of_heap_commit = default_size_of_heap_commit,
1145 .loader_flags = 0,1293 .loader_flags = 0,
1146 .number_of_rva_and_sizes = @intCast(u32, self.data_directories.len),1294 .number_of_rva_and_sizes = @intCast(u32, self.data_directories.len),
1147 };1295 };
...@@ -1152,11 +1300,11 @@ fn writeHeader(self: *Coff) !void {...@@ -1152,11 +1300,11 @@ fn writeHeader(self: *Coff) !void {
1152 .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC,1300 .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC,
1153 .major_linker_version = 0,1301 .major_linker_version = 0,
1154 .minor_linker_version = 0,1302 .minor_linker_version = 0,
1155 .size_of_code = text_section.virtual_size,1303 .size_of_code = size_of_code,
1156 .size_of_initialized_data = size_of_initialized_data,1304 .size_of_initialized_data = size_of_initialized_data,
1157 .size_of_uninitialized_data = 0,1305 .size_of_uninitialized_data = size_of_uninitialized_data,
1158 .address_of_entry_point = self.entry_addr orelse 0,1306 .address_of_entry_point = self.entry_addr orelse 0,
1159 .base_of_code = text_section.virtual_address,1307 .base_of_code = base_of_code,
1160 .image_base = image_base,1308 .image_base = image_base,
1161 .section_alignment = self.page_size,1309 .section_alignment = self.page_size,
1162 .file_alignment = default_file_alignment,1310 .file_alignment = default_file_alignment,
...@@ -1167,15 +1315,15 @@ fn writeHeader(self: *Coff) !void {...@@ -1167,15 +1315,15 @@ fn writeHeader(self: *Coff) !void {
1167 .major_subsystem_version = 6,1315 .major_subsystem_version = 6,
1168 .minor_subsystem_version = 0,1316 .minor_subsystem_version = 0,
1169 .win32_version_value = 0,1317 .win32_version_value = 0,
1170 .size_of_image = size_of_image_aligned,1318 .size_of_image = size_of_image,
1171 .size_of_headers = size_of_headers_aligned,1319 .size_of_headers = size_of_headers,
1172 .checksum = 0,1320 .checksum = 0,
1173 .subsystem = subsystem,1321 .subsystem = subsystem,
1174 .dll_flags = dll_flags,1322 .dll_flags = dll_flags,
1175 .size_of_stack_reserve = 0,1323 .size_of_stack_reserve = default_size_of_stack_reserve,
1176 .size_of_stack_commit = 0,1324 .size_of_stack_commit = default_size_of_stack_commit,
1177 .size_of_heap_reserve = 0,1325 .size_of_heap_reserve = default_size_of_heap_reserve,
1178 .size_of_heap_commit = 0,1326 .size_of_heap_commit = default_size_of_heap_commit,
1179 .loader_flags = 0,1327 .loader_flags = 0,
1180 .number_of_rva_and_sizes = @intCast(u32, self.data_directories.len),1328 .number_of_rva_and_sizes = @intCast(u32, self.data_directories.len),
1181 };1329 };
...@@ -1183,7 +1331,6 @@ fn writeHeader(self: *Coff) !void {...@@ -1183,7 +1331,6 @@ fn writeHeader(self: *Coff) !void {
1183 },1331 },
1184 }1332 }
11851333
1186 try self.base.file.?.pwriteAll(&[_]u8{0}, size_of_headers_aligned);
1187 try self.base.file.?.pwriteAll(buffer.items, 0);1334 try self.base.file.?.pwriteAll(buffer.items, 0);
1188}1335}
11891336
...@@ -1271,6 +1418,22 @@ inline fn getSectionHeadersOffset(self: Coff) u32 {...@@ -1271,6 +1418,22 @@ inline fn getSectionHeadersOffset(self: Coff) u32 {
1271 return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize();1418 return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize();
1272}1419}
12731420
1421inline fn getSizeOfImage(self: Coff) u32 {
1422 var max_image_size: u32 = 0;
1423 for (self.sections.items(.header)) |header| {
1424 if (header.virtual_address + header.virtual_size > max_image_size) {
1425 max_image_size = header.virtual_address + header.virtual_size;
1426 }
1427 }
1428 return mem.alignForwardGeneric(u32, @maximum(max_image_size, self.getSizeOfHeaders()), self.page_size);
1429}
1430
1431/// Returns symbol location corresponding to the set entrypoint (if any).
1432pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
1433 const entry_name = self.base.options.entry orelse "mainCRTStartup"; // TODO this is incomplete
1434 return self.globals.get(entry_name);
1435}
1436
1274/// Returns pointer-to-symbol described by `sym_with_loc` descriptor.1437/// Returns pointer-to-symbol described by `sym_with_loc` descriptor.
1275pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol {1438pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol {
1276 assert(sym_loc.file == null); // TODO linking object files1439 assert(sym_loc.file == null); // TODO linking object files
...@@ -1323,5 +1486,5 @@ fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {...@@ -1323,5 +1486,5 @@ fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {
1323 }1486 }
1324 const offset = try self.strtab.insert(self.base.allocator, name);1487 const offset = try self.strtab.insert(self.base.allocator, name);
1325 mem.set(u8, symbol.name[0..4], 0);1488 mem.set(u8, symbol.name[0..4], 0);
1326 _ = fmt.bufPrint(symbol.name[4..], "{d}", .{offset}) catch unreachable;1489 mem.writeIntLittle(u32, symbol.name[4..8], offset);
1327}1490}