authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-27 18:10:29+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 10:42:21+02:00
log9fc6933418be00df54db79aa8eb3e2c759a2c038
treef56ea9e9d4f0cc12b4b72a70f364d66c0d90344a
parent93127a615be716efa0a74ca08e0a17fda2f4074f

coff: write data directory and section headers to file


1 files changed, 73 insertions(+), 68 deletions(-)

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