| ... | @@ -46,8 +46,8 @@ sections: std.MultiArrayList(Section) = .{}, | ... | @@ -46,8 +46,8 @@ sections: std.MultiArrayList(Section) = .{}, |
| 46 | data_directories: [16]coff.ImageDataDirectory, | 46 | data_directories: [16]coff.ImageDataDirectory, |
| 47 | | 47 | |
| 48 | text_section_index: ?u16 = null, | 48 | text_section_index: ?u16 = null, |
| | 49 | got_section_index: ?u16 = null, |
| 49 | rdata_section_index: ?u16 = null, | 50 | rdata_section_index: ?u16 = null, |
| 50 | pdata_section_index: ?u16 = null, | | |
| 51 | data_section_index: ?u16 = null, | 51 | data_section_index: ?u16 = null, |
| 52 | | 52 | |
| 53 | locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, | 53 | locals: 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. |
| 77 | atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, | 77 | atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, |
| 78 | | 78 | |
| | 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`. |
| | 98 | unnamed_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. |
| | 103 | relocs: RelocTable = .{}, |
| | 104 | |
| | 105 | const Reloc = struct { |
| | 106 | target: SymbolWithLoc, |
| | 107 | offset: u32, |
| | 108 | addend: u32, |
| | 109 | prev_vaddr: u32, |
| | 110 | }; |
| | 111 | |
| | 112 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); |
| | 113 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| | 114 | |
| 79 | const default_file_alignment: u16 = 0x200; | 115 | const default_file_alignment: u16 = 0x200; |
| 80 | const default_image_base_dll: u64 = 0x10000000; | 116 | const default_image_base_dll: u64 = 0x10000000; |
| 81 | const default_image_base_exe: u64 = 0x10000; | 117 | const default_image_base_exe: u64 = 0x10000; |
| | 118 | const default_size_of_stack_reserve: u32 = 0x1000000; |
| | 119 | const default_size_of_stack_commit: u32 = 0x1000; |
| | 120 | const default_size_of_heap_reserve: u32 = 0x100000; |
| | 121 | const default_size_of_heap_commit: u32 = 0x1000; |
| 82 | | 122 | |
| 83 | const Section = struct { | 123 | const 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 | } |
| 215 | | 271 | |
| 216 | fn populateMissingMetadata(self: *Coff) !void { | 272 | fn 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 | } |
| 244 | | 300 | |
| 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 | } |
| 268 | | 324 | |
| ... | @@ -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 | } |
| 334 | | 404 | |
| 335 | pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { | 405 | pub 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 | } |
| 423 | | 493 | |
| 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 | } |
| 500 | | 570 | |
| 501 | fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { | 571 | fn 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 | } |
| 506 | | 602 | |
| 507 | fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 { | 603 | fn 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 | } |
| 532 | | 629 | |
| 533 | fn resolveRelocs(self: *Coff, atom: *Atom, code: []const u8) !void { | 630 | fn 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 | |
| | 643 | fn 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 | } |
| 539 | | 665 | |
| 540 | fn freeAtom(self: *Coff, atom: *Atom, sect_id: u16) void { | 666 | fn 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 | }; |
| 625 | | 751 | |
| 626 | try self.updateDeclCode(decl_index, code); | 752 | try self.updateDeclCode(decl_index, code, .FUNCTION); |
| 627 | | 753 | |
| 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 | }; |
| 681 | | 807 | |
| 682 | try self.updateDeclCode(decl_index, code); | 808 | try self.updateDeclCode(decl_index, code, .NULL); |
| 683 | | 809 | |
| 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 | } |
| 711 | | 837 | |
| 712 | fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) !void { | 838 | fn 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; | | |
| 770 | | 893 | |
| 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); |
| 774 | | 897 | 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 | } |
| 778 | | 899 | |
| 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 | } |
| 902 | | 1023 | |
| 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 | } |
| 923 | | 1044 | |
| 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( | 1049 | pub 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 times | 1052 | |
| 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 | } |
| 942 | | 1077 | |
| ... | @@ -959,7 +1094,6 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { | ... | @@ -959,7 +1094,6 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { |
| 959 | } | 1094 | } |
| 960 | | 1095 | |
| 961 | log.debug("TODO finish resolveGlobalSymbols implementation", .{}); | 1096 | log.debug("TODO finish resolveGlobalSymbols implementation", .{}); |
| 962 | return error.MultipleSymbolDefinitions; | | |
| 963 | } | 1097 | } |
| 964 | | 1098 | |
| 965 | pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void { | 1099 | pub 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(); |
| 997 | | 1131 | |
| | 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(); | | |
| 1002 | | 1139 | |
| 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 | } |
| 1012 | | 1149 | |
| 1013 | pub fn getDeclVAddr( | 1150 | pub 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 | } |
| 1077 | | 1214 | |
| | 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 section | 1219 | .number_of_sections = @intCast(u16, self.sections.slice().len), // TODO what if we prune a section |
| 1082 | .time_date_stamp = 0, // TODO | 1220 | .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 Prevention | 1233 | .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; | | |
| 1107 | | 1243 | |
| | 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 | } |
| 1113 | | 1261 | |
| 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 | } |
| 1185 | | 1333 | |
| 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 | } |
| 1189 | | 1336 | |
| ... | @@ -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 | } |
| 1273 | | 1420 | |
| | 1421 | inline 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). |
| | 1432 | pub 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. |
| 1275 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { | 1438 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { |
| 1276 | assert(sym_loc.file == null); // TODO linking object files | 1439 | 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 | } |