authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-26 18:02:12+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 10:42:21+02:00
loged481e3837218659ab1c18d9d4b836cf656307b9
tree42ab597577a4f5bde351ae72d356951e85db4781
parent90b3599c6846b29a6162a670783d6c2763683f36

coff: write headers to file


2 files changed, 244 insertions(+), 9 deletions(-)

lib/std/coff.zig+15
......@@ -787,6 +787,21 @@ pub const MachineType = enum(u16) {
787787 /// MIPS little-endian WCE v2
788788 WCEMIPSV2 = 0x169,
789789
790 pub fn fromTargetCpuArch(arch: std.Target.Cpu.Arch) MachineType {
791 return switch (arch) {
792 .arm => .ARM,
793 .powerpc => .POWERPC,
794 .riscv32 => .RISCV32,
795 .thumb => .Thumb,
796 .i386 => .I386,
797 .aarch64 => .ARM64,
798 .riscv64 => .RISCV64,
799 .x86_64 => .X64,
800 // there's cases we don't (yet) handle
801 else => unreachable,
802 };
803 }
804
790805 pub fn toTargetCpuArch(machine_type: MachineType) ?std.Target.Cpu.Arch {
791806 return switch (machine_type) {
792807 .ARM => .arm,
src/link/Coff.zig+229-9
......@@ -49,11 +49,13 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{},
4949
5050strtab: StringTable(.strtab) = .{},
5151
52symtab_offset: ?u32 = null,
53
5254got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{},
5355got_entries_free_list: std.ArrayListUnmanaged(u32) = .{},
5456
5557/// Virtual address of the entry point procedure relative to image base.
56entry_addr: ?u64 = null,
58entry_addr: ?u32 = null,
5759
5860/// Table of Decls that are currently alive.
5961/// We store them here so that we can properly dispose of any allocated
......@@ -117,10 +119,6 @@ const ideal_factor = 3;
117119const minimum_text_block_size = 64;
118120pub const min_text_capacity = padToIdeal(minimum_text_block_size);
119121
120/// We commit 0x1000 = 4096 bytes of space to the headers.
121/// This should be plenty for any potential future extensions.
122const default_headerpad_size: u32 = 0x1000;
123
124122pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff {
125123 assert(options.target.ofmt == .coff);
126124
......@@ -208,8 +206,11 @@ pub fn deinit(self: *Coff) void {
208206}
209207
210208fn 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) {}
213214}
214215
215216pub 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)
540541 _ = self;
541542 _ = decl_index;
542543 _ = code;
543 @panic("TODO updateDeclCode");
544 log.debug("TODO updateDeclCode", .{});
545 return &self.locals.items[0];
544546}
545547
546548pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
......@@ -621,7 +623,7 @@ pub fn updateDeclExports(
621623 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports);
622624 }
623625
624 @panic("TODO updateDeclExports");
626 log.debug("TODO updateDeclExports", .{});
625627}
626628
627629pub 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
657659 sub_prog_node.activate();
658660 defer sub_prog_node.end();
659661
662 try self.writeHeader();
663
660664 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
661665 log.debug("flushing. no_entry_point_found = true\n", .{});
662666 self.error_flags.no_entry_point_found = true;
......@@ -664,6 +668,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
664668 log.debug("flushing. no_entry_point_found = false\n", .{});
665669 self.error_flags.no_entry_point_found = false;
666670 }
671 self.error_flags.no_entry_point_found = false;
667672}
668673
669674pub fn getDeclVAddr(
......@@ -684,12 +689,227 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
684689 log.debug("TODO implement updateDeclLineNumber", .{});
685690}
686691
692fn 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
819fn getTotalNumberOfSymbols(self: Coff) u32 {
820 _ = self;
821 // TODO
822 return 0;
823}
824
687825pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
688826 // TODO https://github.com/ziglang/zig/issues/1284
689827 return math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
690828 math.maxInt(@TypeOf(actual_size));
691829}
692830
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
905fn 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
693913/// Returns pointer-to-symbol described by `sym_with_loc` descriptor.
694914pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol {
695915 assert(sym_loc.file == null); // TODO linking object files