| ... | ... | @@ -38,6 +38,7 @@ error_flags: link.File.ErrorFlags = .{}, |
| 38 | 38 | ptr_width: PtrWidth, |
| 39 | 39 | |
| 40 | 40 | sections: std.MultiArrayList(Section) = .{}, |
| 41 | data_directories: std.ArrayListUnmanaged(coff.ImageDataDirectory) = .{}, |
| 41 | 42 | |
| 42 | 43 | text_section_index: ?u16 = null, |
| 43 | 44 | got_section_index: ?u16 = null, |
| ... | ... | @@ -49,8 +50,6 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 49 | 50 | |
| 50 | 51 | strtab: StringTable(.strtab) = .{}, |
| 51 | 52 | |
| 52 | | symtab_offset: ?u32 = null, |
| 53 | | |
| 54 | 53 | got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 55 | 54 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 56 | 55 | |
| ... | ... | @@ -73,6 +72,7 @@ const default_section_alignment: u16 = 0x1000; |
| 73 | 72 | const default_file_alignment: u16 = 0x200; |
| 74 | 73 | const default_image_base_dll: u64 = 0x10000000; |
| 75 | 74 | const default_image_base_exe: u64 = 0x10000; |
| 75 | const default_header_size: u64 = default_section_alignment; |
| 76 | 76 | |
| 77 | 77 | const Section = struct { |
| 78 | 78 | header: coff.SectionHeader, |
| ... | ... | @@ -192,6 +192,7 @@ pub fn deinit(self: *Coff) void { |
| 192 | 192 | free_list.deinit(gpa); |
| 193 | 193 | } |
| 194 | 194 | self.sections.deinit(gpa); |
| 195 | self.data_directories.deinit(gpa); |
| 195 | 196 | |
| 196 | 197 | for (self.managed_atoms.items) |atom| { |
| 197 | 198 | gpa.destroy(atom); |
| ... | ... | @@ -209,11 +210,8 @@ pub fn deinit(self: *Coff) void { |
| 209 | 210 | } |
| 210 | 211 | |
| 211 | 212 | fn populateMissingMetadata(self: *Coff) !void { |
| 212 | | log.debug("{x}", .{msdos_stub.len}); |
| 213 | | |
| 214 | 213 | if (self.text_section_index == null) {} |
| 215 | 214 | if (self.got_section_index == null) {} |
| 216 | | if (self.symtab_offset == null) {} |
| 217 | 215 | } |
| 218 | 216 | |
| 219 | 217 | pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { |
| ... | ... | @@ -662,6 +660,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 662 | 660 | sub_prog_node.activate(); |
| 663 | 661 | defer sub_prog_node.end(); |
| 664 | 662 | |
| 663 | try self.writeDataDirectoriesHeaders(); |
| 664 | try self.writeSectionHeaders(); |
| 665 | 665 | try self.writeHeader(); |
| 666 | 666 | |
| 667 | 667 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| ... | ... | @@ -692,24 +692,28 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v |
| 692 | 692 | log.debug("TODO implement updateDeclLineNumber", .{}); |
| 693 | 693 | } |
| 694 | 694 | |
| 695 | fn writeSectionHeaders(self: *Coff) !void { |
| 696 | const offset = self.getSectionHeadersOffset(); |
| 697 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items(.header)), offset); |
| 698 | } |
| 699 | |
| 700 | fn writeDataDirectoriesHeaders(self: *Coff) !void { |
| 701 | const offset = self.getDataDirectoryHeadersOffset(); |
| 702 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.data_directories.items), offset); |
| 703 | } |
| 704 | |
| 695 | 705 | fn writeHeader(self: *Coff) !void { |
| 696 | 706 | const gpa = self.base.allocator; |
| 697 | 707 | var buffer = std.ArrayList(u8).init(gpa); |
| 698 | 708 | defer buffer.deinit(); |
| 699 | 709 | const writer = buffer.writer(); |
| 700 | 710 | |
| 701 | | try buffer.ensureUnusedCapacity(msdos_stub.len + 8); |
| 711 | try buffer.ensureTotalCapacity(self.getSizeOfHeaders()); |
| 702 | 712 | writer.writeAll(msdos_stub) catch unreachable; |
| 703 | 713 | writer.writeByteNTimes(0, 4) catch unreachable; // align to 8 bytes |
| 704 | 714 | writer.writeAll("PE\x00\x00") catch unreachable; |
| 705 | 715 | buffer.items[0x3c] = @intCast(u8, msdos_stub.len + 4); |
| 706 | 716 | |
| 707 | | var num_data_directories: u32 = 0; |
| 708 | | var size_of_optional_header = switch (self.ptr_width) { |
| 709 | | .p32 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE32)), |
| 710 | | .p64 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE64)), |
| 711 | | } + num_data_directories * @sizeOf(coff.ImageDataDirectory); |
| 712 | | |
| 713 | 717 | var flags = coff.CoffHeaderFlags{ |
| 714 | 718 | .EXECUTABLE_IMAGE = 1, |
| 715 | 719 | .DEBUG_STRIPPED = 1, // TODO |
| ... | ... | @@ -722,17 +726,20 @@ fn writeHeader(self: *Coff) !void { |
| 722 | 726 | flags.DLL = 1; |
| 723 | 727 | } |
| 724 | 728 | |
| 729 | const size_of_optional_header = @intCast( |
| 730 | u16, |
| 731 | self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize(), |
| 732 | ); |
| 725 | 733 | var coff_header = coff.CoffHeader{ |
| 726 | 734 | .machine = coff.MachineType.fromTargetCpuArch(self.base.options.target.cpu.arch), |
| 727 | 735 | .number_of_sections = @intCast(u16, self.sections.slice().len), // TODO what if we prune a section |
| 728 | 736 | .time_date_stamp = 0, // TODO |
| 729 | | .pointer_to_symbol_table = self.symtab_offset orelse 0, |
| 730 | | .number_of_symbols = if (self.symtab_offset) |_| self.getTotalNumberOfSymbols() else 0, |
| 731 | | .size_of_optional_header = @intCast(u16, size_of_optional_header), |
| 737 | .pointer_to_symbol_table = 0, |
| 738 | .number_of_symbols = 0, |
| 739 | .size_of_optional_header = size_of_optional_header, |
| 732 | 740 | .flags = flags, |
| 733 | 741 | }; |
| 734 | 742 | |
| 735 | | try buffer.ensureUnusedCapacity(@sizeOf(coff.CoffHeader)); |
| 736 | 743 | writer.writeAll(mem.asBytes(&coff_header)) catch unreachable; |
| 737 | 744 | |
| 738 | 745 | const dll_flags: coff.DllFlags = .{ |
| ... | ... | @@ -742,10 +749,7 @@ fn writeHeader(self: *Coff) !void { |
| 742 | 749 | .NX_COMPAT = 1, // We are compatible with Data Execution Prevention |
| 743 | 750 | }; |
| 744 | 751 | const subsystem: coff.Subsystem = .WINDOWS_CUI; |
| 745 | | const size_of_headers: u32 = @intCast( |
| 746 | | u32, |
| 747 | | msdos_stub.len + 8 + size_of_optional_header + self.sections.slice().len * @sizeOf(coff.SectionHeader), |
| 748 | | ); |
| 752 | const size_of_headers: u32 = @intCast(u32, self.getSizeOfHeaders()); |
| 749 | 753 | const size_of_image_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, default_section_alignment); |
| 750 | 754 | const size_of_headers_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, default_file_alignment); |
| 751 | 755 | const image_base = self.base.options.image_base_override orelse switch (self.base.options.output_mode) { |
| ... | ... | @@ -756,7 +760,6 @@ fn writeHeader(self: *Coff) !void { |
| 756 | 760 | |
| 757 | 761 | switch (self.ptr_width) { |
| 758 | 762 | .p32 => { |
| 759 | | try buffer.ensureUnusedCapacity(@sizeOf(coff.OptionalHeaderPE32)); |
| 760 | 763 | var opt_header = coff.OptionalHeaderPE32{ |
| 761 | 764 | .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC, |
| 762 | 765 | .major_linker_version = 0, |
| ... | ... | @@ -787,12 +790,11 @@ fn writeHeader(self: *Coff) !void { |
| 787 | 790 | .size_of_heap_reserve = 0, |
| 788 | 791 | .size_of_heap_commit = 0, |
| 789 | 792 | .loader_flags = 0, |
| 790 | | .number_of_rva_and_sizes = num_data_directories, |
| 793 | .number_of_rva_and_sizes = @intCast(u32, self.data_directories.items.len), |
| 791 | 794 | }; |
| 792 | 795 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; |
| 793 | 796 | }, |
| 794 | 797 | .p64 => { |
| 795 | | try buffer.ensureUnusedCapacity(@sizeOf(coff.OptionalHeaderPE64)); |
| 796 | 798 | var opt_header = coff.OptionalHeaderPE64{ |
| 797 | 799 | .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC, |
| 798 | 800 | .major_linker_version = 0, |
| ... | ... | @@ -822,33 +824,16 @@ fn writeHeader(self: *Coff) !void { |
| 822 | 824 | .size_of_heap_reserve = 0, |
| 823 | 825 | .size_of_heap_commit = 0, |
| 824 | 826 | .loader_flags = 0, |
| 825 | | .number_of_rva_and_sizes = num_data_directories, |
| 827 | .number_of_rva_and_sizes = @intCast(u32, self.data_directories.items.len), |
| 826 | 828 | }; |
| 827 | 829 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; |
| 828 | 830 | }, |
| 829 | 831 | } |
| 830 | 832 | |
| 831 | | try buffer.ensureUnusedCapacity(num_data_directories * @sizeOf(coff.ImageDataDirectory)); |
| 832 | | { |
| 833 | | var i: usize = 0; |
| 834 | | while (i < num_data_directories) : (i += 1) { |
| 835 | | writer.writeAll(mem.asBytes(&coff.ImageDataDirectory{ |
| 836 | | .virtual_address = 0, |
| 837 | | .size = 0, |
| 838 | | })) catch unreachable; |
| 839 | | } |
| 840 | | } |
| 841 | | |
| 842 | 833 | try self.base.file.?.pwriteAll(&[_]u8{0}, size_of_headers_aligned); |
| 843 | 834 | try self.base.file.?.pwriteAll(buffer.items, 0); |
| 844 | 835 | } |
| 845 | 836 | |
| 846 | | fn getTotalNumberOfSymbols(self: Coff) u32 { |
| 847 | | _ = self; |
| 848 | | // TODO |
| 849 | | return 0; |
| 850 | | } |
| 851 | | |
| 852 | 837 | pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 853 | 838 | // TODO https://github.com/ziglang/zig/issues/1284 |
| 854 | 839 | return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch |
| ... | ... | @@ -856,14 +841,12 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 856 | 841 | } |
| 857 | 842 | |
| 858 | 843 | // fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 { |
| 859 | | // const small_ptr = self.ptr_width == .p32; |
| 860 | | // const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr); |
| 861 | 844 | // if (start < default_header_size) |
| 862 | | // return ehdr_size; |
| 845 | // return default_header_size; |
| 863 | 846 | |
| 864 | 847 | // const end = start + padToIdeal(size); |
| 865 | 848 | |
| 866 | | // if (self.shdr_table_offset) |off| { |
| 849 | // if (self.symtab_offset) |off| { |
| 867 | 850 | // const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); |
| 868 | 851 | // const tight_size = self.sections.items.len * shdr_size; |
| 869 | 852 | // const increased_size = padToIdeal(tight_size); |
| ... | ... | @@ -900,26 +883,26 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 900 | 883 | // return null; |
| 901 | 884 | // } |
| 902 | 885 | |
| 903 | | // pub fn allocatedSize(self: *Coff, start: u64) u64 { |
| 904 | | // if (start == 0) |
| 905 | | // return 0; |
| 906 | | // var min_pos: u64 = std.math.maxInt(u64); |
| 907 | | // if (self.shdr_table_offset) |off| { |
| 908 | | // if (off > start and off < min_pos) min_pos = off; |
| 909 | | // } |
| 910 | | // if (self.phdr_table_offset) |off| { |
| 911 | | // if (off > start and off < min_pos) min_pos = off; |
| 912 | | // } |
| 913 | | // for (self.sections.items) |section| { |
| 914 | | // if (section.sh_offset <= start) continue; |
| 915 | | // if (section.sh_offset < min_pos) min_pos = section.sh_offset; |
| 916 | | // } |
| 917 | | // for (self.program_headers.items) |program_header| { |
| 918 | | // if (program_header.p_offset <= start) continue; |
| 919 | | // if (program_header.p_offset < min_pos) min_pos = program_header.p_offset; |
| 920 | | // } |
| 921 | | // return min_pos - start; |
| 922 | | // } |
| 886 | // // pub fn allocatedSize(self: *Coff, start: u64) u64 { |
| 887 | // // if (start == 0) |
| 888 | // // return 0; |
| 889 | // // var min_pos: u64 = std.math.maxInt(u64); |
| 890 | // // if (self.shdr_table_offset) |off| { |
| 891 | // // if (off > start and off < min_pos) min_pos = off; |
| 892 | // // } |
| 893 | // // if (self.phdr_table_offset) |off| { |
| 894 | // // if (off > start and off < min_pos) min_pos = off; |
| 895 | // // } |
| 896 | // // for (self.sections.items) |section| { |
| 897 | // // if (section.sh_offset <= start) continue; |
| 898 | // // if (section.sh_offset < min_pos) min_pos = section.sh_offset; |
| 899 | // // } |
| 900 | // // for (self.program_headers.items) |program_header| { |
| 901 | // // if (program_header.p_offset <= start) continue; |
| 902 | // // if (program_header.p_offset < min_pos) min_pos = program_header.p_offset; |
| 903 | // // } |
| 904 | // // return min_pos - start; |
| 905 | // // } |
| 923 | 906 | |
| 924 | 907 | // pub fn findFreeSpace(self: *Coff, object_size: u64, min_alignment: u32) u64 { |
| 925 | 908 | // var start: u64 = 0; |
| ... | ... | @@ -929,12 +912,34 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 929 | 912 | // return start; |
| 930 | 913 | // } |
| 931 | 914 | |
| 932 | | fn getMaxOptionalHeaderSize(self: Coff) usize { |
| 933 | | const hdr_size: usize = switch (self.ptr_width) { |
| 915 | inline fn getSizeOfHeaders(self: Coff) usize { |
| 916 | const msdos_hdr_size = msdos_stub.len + 8; |
| 917 | return msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() + |
| 918 | self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize(); |
| 919 | } |
| 920 | |
| 921 | inline fn getOptionalHeaderSize(self: Coff) usize { |
| 922 | return switch (self.ptr_width) { |
| 934 | 923 | .p32 => @sizeOf(coff.OptionalHeaderPE32), |
| 935 | 924 | .p64 => @sizeOf(coff.OptionalHeaderPE64), |
| 936 | 925 | }; |
| 937 | | return hdr_size + @sizeOf(coff.ImageDataDirectory) * 16; |
| 926 | } |
| 927 | |
| 928 | inline fn getDataDirectoryHeadersSize(self: Coff) usize { |
| 929 | return self.data_directories.items.len * @sizeOf(coff.ImageDataDirectory); |
| 930 | } |
| 931 | |
| 932 | inline fn getSectionHeadersSize(self: Coff) usize { |
| 933 | return self.sections.slice().len * @sizeOf(coff.SectionHeader); |
| 934 | } |
| 935 | |
| 936 | inline fn getDataDirectoryHeadersOffset(self: Coff) usize { |
| 937 | const msdos_hdr_size = msdos_stub.len + 8; |
| 938 | return msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize(); |
| 939 | } |
| 940 | |
| 941 | inline fn getSectionHeadersOffset(self: Coff) usize { |
| 942 | return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize(); |
| 938 | 943 | } |
| 939 | 944 | |
| 940 | 945 | /// Returns pointer-to-symbol described by `sym_with_loc` descriptor. |