| ... | ... | @@ -49,11 +49,13 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 49 | 49 | |
| 50 | 50 | strtab: StringTable(.strtab) = .{}, |
| 51 | 51 | |
| 52 | symtab_offset: ?u32 = null, |
| 53 | |
| 52 | 54 | got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 53 | 55 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 54 | 56 | |
| 55 | 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 | 60 | /// Table of Decls that are currently alive. |
| 59 | 61 | /// We store them here so that we can properly dispose of any allocated |
| ... | ... | @@ -117,10 +119,6 @@ const ideal_factor = 3; |
| 117 | 119 | const minimum_text_block_size = 64; |
| 118 | 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 | 122 | pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff { |
| 125 | 123 | assert(options.target.ofmt == .coff); |
| 126 | 124 | |
| ... | ... | @@ -208,8 +206,11 @@ pub fn deinit(self: *Coff) void { |
| 208 | 206 | } |
| 209 | 207 | |
| 210 | 208 | fn populateMissingMetadata(self: *Coff) !void { |
| 211 | | _ = self; |
| 212 | | @panic("TODO populateMissingMetadata"); |
| 209 | log.debug("{x}", .{msdos_stub.len}); |
| 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 | 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 | 541 | _ = self; |
| 541 | 542 | _ = decl_index; |
| 542 | 543 | _ = code; |
| 543 | | @panic("TODO updateDeclCode"); |
| 544 | log.debug("TODO updateDeclCode", .{}); |
| 545 | return &self.locals.items[0]; |
| 544 | 546 | } |
| 545 | 547 | |
| 546 | 548 | pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { |
| ... | ... | @@ -621,7 +623,7 @@ pub fn updateDeclExports( |
| 621 | 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 | 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 | 659 | sub_prog_node.activate(); |
| 658 | 660 | defer sub_prog_node.end(); |
| 659 | 661 | |
| 662 | try self.writeHeader(); |
| 663 | |
| 660 | 664 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 661 | 665 | log.debug("flushing. no_entry_point_found = true\n", .{}); |
| 662 | 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 | 668 | log.debug("flushing. no_entry_point_found = false\n", .{}); |
| 665 | 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 | 674 | pub fn getDeclVAddr( |
| ... | ... | @@ -684,12 +689,227 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v |
| 684 | 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 | 825 | pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 688 | 826 | // TODO https://github.com/ziglang/zig/issues/1284 |
| 689 | 827 | return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch |
| 690 | 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 | 913 | /// Returns pointer-to-symbol described by `sym_with_loc` descriptor. |
| 694 | 914 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { |
| 695 | 915 | assert(sym_loc.file == null); // TODO linking object files |