| ... | @@ -49,11 +49,13 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | ... | @@ -49,11 +49,13 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 49 | | 49 | |
| 50 | strtab: StringTable(.strtab) = .{}, | 50 | strtab: StringTable(.strtab) = .{}, |
| 51 | | 51 | |
| | 52 | symtab_offset: ?u32 = null, |
| | 53 | |
| 52 | got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, | 54 | got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 53 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, | 55 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 54 | | 56 | |
| 55 | /// Virtual address of the entry point procedure relative to image base. | 57 | /// Virtual address of the entry point procedure relative to image base. |
| 56 | entry_addr: ?u64 = null, | 58 | entry_addr: ?u32 = null, |
| 57 | | 59 | |
| 58 | /// Table of Decls that are currently alive. | 60 | /// Table of Decls that are currently alive. |
| 59 | /// We store them here so that we can properly dispose of any allocated | 61 | /// We store them here so that we can properly dispose of any allocated |
| ... | @@ -117,10 +119,6 @@ const ideal_factor = 3; | ... | @@ -117,10 +119,6 @@ const ideal_factor = 3; |
| 117 | const minimum_text_block_size = 64; | 119 | const minimum_text_block_size = 64; |
| 118 | pub const min_text_capacity = padToIdeal(minimum_text_block_size); | 120 | pub const min_text_capacity = padToIdeal(minimum_text_block_size); |
| 119 | | 121 | |
| 120 | /// We commit 0x1000 = 4096 bytes of space to the headers. | | |
| 121 | /// This should be plenty for any potential future extensions. | | |
| 122 | const default_headerpad_size: u32 = 0x1000; | | |
| 123 | | | |
| 124 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff { | 122 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff { |
| 125 | assert(options.target.ofmt == .coff); | 123 | assert(options.target.ofmt == .coff); |
| 126 | | 124 | |
| ... | @@ -208,8 +206,11 @@ pub fn deinit(self: *Coff) void { | ... | @@ -208,8 +206,11 @@ pub fn deinit(self: *Coff) void { |
| 208 | } | 206 | } |
| 209 | | 207 | |
| 210 | fn populateMissingMetadata(self: *Coff) !void { | 208 | fn populateMissingMetadata(self: *Coff) !void { |
| 211 | _ = self; | 209 | log.debug("{x}", .{msdos_stub.len}); |
| 212 | @panic("TODO populateMissingMetadata"); | 210 | |
| | 211 | if (self.text_section_index == null) {} |
| | 212 | if (self.got_section_index == null) {} |
| | 213 | if (self.symtab_offset == null) {} |
| 213 | } | 214 | } |
| 214 | | 215 | |
| 215 | pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { | 216 | pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { |
| ... | @@ -540,7 +541,8 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) | ... | @@ -540,7 +541,8 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) |
| 540 | _ = self; | 541 | _ = self; |
| 541 | _ = decl_index; | 542 | _ = decl_index; |
| 542 | _ = code; | 543 | _ = code; |
| 543 | @panic("TODO updateDeclCode"); | 544 | log.debug("TODO updateDeclCode", .{}); |
| | 545 | return &self.locals.items[0]; |
| 544 | } | 546 | } |
| 545 | | 547 | |
| 546 | pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { | 548 | pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { |
| ... | @@ -621,7 +623,7 @@ pub fn updateDeclExports( | ... | @@ -621,7 +623,7 @@ pub fn updateDeclExports( |
| 621 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports); | 623 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports); |
| 622 | } | 624 | } |
| 623 | | 625 | |
| 624 | @panic("TODO updateDeclExports"); | 626 | log.debug("TODO updateDeclExports", .{}); |
| 625 | } | 627 | } |
| 626 | | 628 | |
| 627 | pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void { | 629 | pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| ... | @@ -657,6 +659,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -657,6 +659,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 657 | sub_prog_node.activate(); | 659 | sub_prog_node.activate(); |
| 658 | defer sub_prog_node.end(); | 660 | defer sub_prog_node.end(); |
| 659 | | 661 | |
| | 662 | try self.writeHeader(); |
| | 663 | |
| 660 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { | 664 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 661 | log.debug("flushing. no_entry_point_found = true\n", .{}); | 665 | log.debug("flushing. no_entry_point_found = true\n", .{}); |
| 662 | self.error_flags.no_entry_point_found = true; | 666 | self.error_flags.no_entry_point_found = true; |
| ... | @@ -664,6 +668,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -664,6 +668,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 664 | log.debug("flushing. no_entry_point_found = false\n", .{}); | 668 | log.debug("flushing. no_entry_point_found = false\n", .{}); |
| 665 | self.error_flags.no_entry_point_found = false; | 669 | self.error_flags.no_entry_point_found = false; |
| 666 | } | 670 | } |
| | 671 | self.error_flags.no_entry_point_found = false; |
| 667 | } | 672 | } |
| 668 | | 673 | |
| 669 | pub fn getDeclVAddr( | 674 | pub fn getDeclVAddr( |
| ... | @@ -684,12 +689,227 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v | ... | @@ -684,12 +689,227 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v |
| 684 | log.debug("TODO implement updateDeclLineNumber", .{}); | 689 | log.debug("TODO implement updateDeclLineNumber", .{}); |
| 685 | } | 690 | } |
| 686 | | 691 | |
| | 692 | fn writeHeader(self: *Coff) !void { |
| | 693 | const gpa = self.base.allocator; |
| | 694 | var buffer = std.ArrayList(u8).init(gpa); |
| | 695 | defer buffer.deinit(); |
| | 696 | const writer = buffer.writer(); |
| | 697 | |
| | 698 | try buffer.ensureUnusedCapacity(msdos_stub.len + 8); |
| | 699 | writer.writeAll(msdos_stub) catch unreachable; |
| | 700 | writer.writeByteNTimes(0, 4) catch unreachable; // align to 8 bytes |
| | 701 | writer.writeAll("PE\x00\x00") catch unreachable; |
| | 702 | buffer.items[0x3c] = @intCast(u8, msdos_stub.len + 4); |
| | 703 | |
| | 704 | var num_data_directories: u32 = 1; |
| | 705 | var size_of_optional_header = switch (self.ptr_width) { |
| | 706 | .p32 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE32)), |
| | 707 | .p64 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE64)), |
| | 708 | } + num_data_directories * @sizeOf(coff.ImageDataDirectory); |
| | 709 | |
| | 710 | var flags = coff.CoffHeaderFlags{ |
| | 711 | .EXECUTABLE_IMAGE = 1, |
| | 712 | .DEBUG_STRIPPED = 1, // TODO |
| | 713 | }; |
| | 714 | switch (self.ptr_width) { |
| | 715 | .p32 => flags.@"32BIT_MACHINE" = 1, |
| | 716 | .p64 => flags.LARGE_ADDRESS_AWARE = 1, |
| | 717 | } |
| | 718 | if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic) { |
| | 719 | flags.DLL = 1; |
| | 720 | } |
| | 721 | |
| | 722 | var coff_header = coff.CoffHeader{ |
| | 723 | .machine = coff.MachineType.fromTargetCpuArch(self.base.options.target.cpu.arch), |
| | 724 | .number_of_sections = @intCast(u16, self.sections.slice().len), // TODO what if we prune a section |
| | 725 | .time_date_stamp = 0, // TODO |
| | 726 | .pointer_to_symbol_table = self.symtab_offset orelse 0, |
| | 727 | .number_of_symbols = if (self.symtab_offset) |_| self.getTotalNumberOfSymbols() else 0, |
| | 728 | .size_of_optional_header = @intCast(u16, size_of_optional_header), |
| | 729 | .flags = flags, |
| | 730 | }; |
| | 731 | |
| | 732 | try buffer.ensureUnusedCapacity(@sizeOf(coff.CoffHeader)); |
| | 733 | writer.writeAll(mem.asBytes(&coff_header)) catch unreachable; |
| | 734 | |
| | 735 | const subsystem: coff.Subsystem = .WINDOWS_CUI; |
| | 736 | switch (self.ptr_width) { |
| | 737 | .p32 => { |
| | 738 | try buffer.ensureUnusedCapacity(@sizeOf(coff.OptionalHeaderPE32)); |
| | 739 | var opt_header = coff.OptionalHeaderPE32{ |
| | 740 | .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC, |
| | 741 | .major_linker_version = 0, |
| | 742 | .minor_linker_version = 0, |
| | 743 | .size_of_code = 0, |
| | 744 | .size_of_initialized_data = 0, |
| | 745 | .size_of_uninitialized_data = 0, |
| | 746 | .address_of_entry_point = self.entry_addr orelse 0, |
| | 747 | .base_of_code = 0, |
| | 748 | .base_of_data = 0, |
| | 749 | .image_base = 0, |
| | 750 | .section_alignment = 0, |
| | 751 | .file_alignment = 0, |
| | 752 | .major_operating_system_version = 0, |
| | 753 | .minor_operating_system_version = 0, |
| | 754 | .major_image_version = 0, |
| | 755 | .minor_image_version = 0, |
| | 756 | .major_subsystem_version = 0, |
| | 757 | .minor_subsystem_version = 0, |
| | 758 | .win32_version_value = 0, |
| | 759 | .size_of_image = 0, |
| | 760 | .size_of_headers = 0, |
| | 761 | .checksum = 0, |
| | 762 | .subsystem = subsystem, |
| | 763 | .dll_flags = .{}, |
| | 764 | .size_of_stack_reserve = 0, |
| | 765 | .size_of_stack_commit = 0, |
| | 766 | .size_of_heap_reserve = 0, |
| | 767 | .size_of_heap_commit = 0, |
| | 768 | .loader_flags = 0, |
| | 769 | .number_of_rva_and_sizes = num_data_directories, |
| | 770 | }; |
| | 771 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; |
| | 772 | }, |
| | 773 | .p64 => { |
| | 774 | try buffer.ensureUnusedCapacity(@sizeOf(coff.OptionalHeaderPE64)); |
| | 775 | var opt_header = coff.OptionalHeaderPE64{ |
| | 776 | .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC, |
| | 777 | .major_linker_version = 0, |
| | 778 | .minor_linker_version = 0, |
| | 779 | .size_of_code = 0, |
| | 780 | .size_of_initialized_data = 0, |
| | 781 | .size_of_uninitialized_data = 0, |
| | 782 | .address_of_entry_point = self.entry_addr orelse 0, |
| | 783 | .base_of_code = 0, |
| | 784 | .image_base = 0, |
| | 785 | .section_alignment = 0, |
| | 786 | .file_alignment = 0, |
| | 787 | .major_operating_system_version = 0, |
| | 788 | .minor_operating_system_version = 0, |
| | 789 | .major_image_version = 0, |
| | 790 | .minor_image_version = 0, |
| | 791 | .major_subsystem_version = 0, |
| | 792 | .minor_subsystem_version = 0, |
| | 793 | .win32_version_value = 0, |
| | 794 | .size_of_image = 0, |
| | 795 | .size_of_headers = 0, |
| | 796 | .checksum = 0, |
| | 797 | .subsystem = subsystem, |
| | 798 | .dll_flags = .{}, |
| | 799 | .size_of_stack_reserve = 0, |
| | 800 | .size_of_stack_commit = 0, |
| | 801 | .size_of_heap_reserve = 0, |
| | 802 | .size_of_heap_commit = 0, |
| | 803 | .loader_flags = 0, |
| | 804 | .number_of_rva_and_sizes = num_data_directories, |
| | 805 | }; |
| | 806 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; |
| | 807 | }, |
| | 808 | } |
| | 809 | |
| | 810 | try buffer.ensureUnusedCapacity(num_data_directories * @sizeOf(coff.ImageDataDirectory)); |
| | 811 | writer.writeAll(mem.asBytes(&coff.ImageDataDirectory{ |
| | 812 | .virtual_address = 0, |
| | 813 | .size = 0, |
| | 814 | })) catch unreachable; |
| | 815 | |
| | 816 | try self.base.file.?.pwriteAll(buffer.items, 0); |
| | 817 | } |
| | 818 | |
| | 819 | fn getTotalNumberOfSymbols(self: Coff) u32 { |
| | 820 | _ = self; |
| | 821 | // TODO |
| | 822 | return 0; |
| | 823 | } |
| | 824 | |
| 687 | pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { | 825 | pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 688 | // TODO https://github.com/ziglang/zig/issues/1284 | 826 | // TODO https://github.com/ziglang/zig/issues/1284 |
| 689 | return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch | 827 | return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch |
| 690 | math.maxInt(@TypeOf(actual_size)); | 828 | math.maxInt(@TypeOf(actual_size)); |
| 691 | } | 829 | } |
| 692 | | 830 | |
| | 831 | // fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 { |
| | 832 | // const small_ptr = self.ptr_width == .p32; |
| | 833 | // const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr); |
| | 834 | // if (start < default_header_size) |
| | 835 | // return ehdr_size; |
| | 836 | |
| | 837 | // const end = start + padToIdeal(size); |
| | 838 | |
| | 839 | // if (self.shdr_table_offset) |off| { |
| | 840 | // const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); |
| | 841 | // const tight_size = self.sections.items.len * shdr_size; |
| | 842 | // const increased_size = padToIdeal(tight_size); |
| | 843 | // const test_end = off + increased_size; |
| | 844 | // if (end > off and start < test_end) { |
| | 845 | // return test_end; |
| | 846 | // } |
| | 847 | // } |
| | 848 | |
| | 849 | // if (self.phdr_table_offset) |off| { |
| | 850 | // const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr); |
| | 851 | // const tight_size = self.sections.items.len * phdr_size; |
| | 852 | // const increased_size = padToIdeal(tight_size); |
| | 853 | // const test_end = off + increased_size; |
| | 854 | // if (end > off and start < test_end) { |
| | 855 | // return test_end; |
| | 856 | // } |
| | 857 | // } |
| | 858 | |
| | 859 | // for (self.sections.items) |section| { |
| | 860 | // const increased_size = padToIdeal(section.sh_size); |
| | 861 | // const test_end = section.sh_offset + increased_size; |
| | 862 | // if (end > section.sh_offset and start < test_end) { |
| | 863 | // return test_end; |
| | 864 | // } |
| | 865 | // } |
| | 866 | // for (self.program_headers.items) |program_header| { |
| | 867 | // const increased_size = padToIdeal(program_header.p_filesz); |
| | 868 | // const test_end = program_header.p_offset + increased_size; |
| | 869 | // if (end > program_header.p_offset and start < test_end) { |
| | 870 | // return test_end; |
| | 871 | // } |
| | 872 | // } |
| | 873 | // return null; |
| | 874 | // } |
| | 875 | |
| | 876 | // pub fn allocatedSize(self: *Coff, start: u64) u64 { |
| | 877 | // if (start == 0) |
| | 878 | // return 0; |
| | 879 | // var min_pos: u64 = std.math.maxInt(u64); |
| | 880 | // if (self.shdr_table_offset) |off| { |
| | 881 | // if (off > start and off < min_pos) min_pos = off; |
| | 882 | // } |
| | 883 | // if (self.phdr_table_offset) |off| { |
| | 884 | // if (off > start and off < min_pos) min_pos = off; |
| | 885 | // } |
| | 886 | // for (self.sections.items) |section| { |
| | 887 | // if (section.sh_offset <= start) continue; |
| | 888 | // if (section.sh_offset < min_pos) min_pos = section.sh_offset; |
| | 889 | // } |
| | 890 | // for (self.program_headers.items) |program_header| { |
| | 891 | // if (program_header.p_offset <= start) continue; |
| | 892 | // if (program_header.p_offset < min_pos) min_pos = program_header.p_offset; |
| | 893 | // } |
| | 894 | // return min_pos - start; |
| | 895 | // } |
| | 896 | |
| | 897 | // pub fn findFreeSpace(self: *Coff, object_size: u64, min_alignment: u32) u64 { |
| | 898 | // var start: u64 = 0; |
| | 899 | // while (self.detectAllocCollision(start, object_size)) |item_end| { |
| | 900 | // start = mem.alignForwardGeneric(u64, item_end, min_alignment); |
| | 901 | // } |
| | 902 | // return start; |
| | 903 | // } |
| | 904 | |
| | 905 | fn getMaxOptionalHeaderSize(self: Coff) usize { |
| | 906 | const hdr_size: usize = switch (self.ptr_width) { |
| | 907 | .p32 => @sizeOf(coff.OptionalHeaderPE32), |
| | 908 | .p64 => @sizeOf(coff.OptionalHeaderPE64), |
| | 909 | }; |
| | 910 | return hdr_size + @sizeOf(coff.ImageDataDirectory) * 16; |
| | 911 | } |
| | 912 | |
| 693 | /// Returns pointer-to-symbol described by `sym_with_loc` descriptor. | 913 | /// Returns pointer-to-symbol described by `sym_with_loc` descriptor. |
| 694 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { | 914 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { |
| 695 | assert(sym_loc.file == null); // TODO linking object files | 915 | assert(sym_loc.file == null); // TODO linking object files |