From 944b0ef5188a066c9fe11a297c743bfb3301a02a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 24 Dec 2023 23:02:39 -0700 Subject: [PATCH] link.File.Coff: fix relationship between createEmpty/open similar commit to b0c433c80f2e4edd7b60e444b4ea56dacb727051 --- src/link/Coff.zig | 268 +++++++++++++++++++++++----------------------- 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 75feeeab46375deea69871f33ff2510e02bd4f81..6db49713fcefe3085be8ab79868422bd05163785 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -235,138 +235,6 @@ const ideal_factor = 3; const minimum_text_block_size = 64; pub const min_text_capacity = padToIdeal(minimum_text_block_size); -pub fn open( - arena: Allocator, - comp: *Compilation, - emit: Compilation.Emit, - options: link.File.OpenOptions, -) !*Coff { - const target = comp.root_mod.resolved_target.result; - assert(target.ofmt == .coff); - - const self = try createEmpty(arena, comp, emit, options); - errdefer self.base.destroy(); - - const use_lld = build_options.have_llvm and comp.config.use_lld; - const use_llvm = comp.config.use_llvm; - - if (use_lld and use_llvm) { - // LLVM emits the object file; LLD links it into the final product. - return self; - } - - const sub_path = if (!use_lld) emit.sub_path else p: { - // Open a temporary object file, not the final output file because we - // want to link with LLD. - const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ - emit.sub_path, target.ofmt.fileExt(target.cpu.arch), - }); - self.base.zcu_object_sub_path = o_file_path; - break :p o_file_path; - }; - - self.base.file = try emit.directory.handle.createFile(sub_path, .{ - .truncate = false, - .read = true, - .mode = link.File.determineMode( - use_lld, - comp.config.output_mode, - comp.config.link_mode, - ), - }); - - assert(self.llvm_object == null); - const gpa = comp.gpa; - - try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); - self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32)); - - try self.temp_strtab.buffer.append(gpa, 0); - - // Index 0 is always a null symbol. - try self.locals.append(gpa, .{ - .name = [_]u8{0} ** 8, - .value = 0, - .section_number = .UNDEFINED, - .type = .{ .base_type = .NULL, .complex_type = .NULL }, - .storage_class = .NULL, - .number_of_aux_symbols = 0, - }); - - if (self.text_section_index == null) { - const file_size: u32 = @intCast(options.program_code_size_hint); - self.text_section_index = try self.allocateSection(".text", file_size, .{ - .CNT_CODE = 1, - .MEM_EXECUTE = 1, - .MEM_READ = 1, - }); - } - - if (self.got_section_index == null) { - const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size(); - self.got_section_index = try self.allocateSection(".got", file_size, .{ - .CNT_INITIALIZED_DATA = 1, - .MEM_READ = 1, - }); - } - - if (self.rdata_section_index == null) { - const file_size: u32 = self.page_size; - self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ - .CNT_INITIALIZED_DATA = 1, - .MEM_READ = 1, - }); - } - - if (self.data_section_index == null) { - const file_size: u32 = self.page_size; - self.data_section_index = try self.allocateSection(".data", file_size, .{ - .CNT_INITIALIZED_DATA = 1, - .MEM_READ = 1, - .MEM_WRITE = 1, - }); - } - - if (self.idata_section_index == null) { - const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size(); - self.idata_section_index = try self.allocateSection(".idata", file_size, .{ - .CNT_INITIALIZED_DATA = 1, - .MEM_READ = 1, - }); - } - - if (self.reloc_section_index == null) { - const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff.BaseRelocation); - self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{ - .CNT_INITIALIZED_DATA = 1, - .MEM_DISCARDABLE = 1, - .MEM_READ = 1, - }); - } - - if (self.strtab_offset == null) { - const file_size = @as(u32, @intCast(self.strtab.buffer.items.len)); - self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here - log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size }); - } - - { - // We need to find out what the max file offset is according to section headers. - // Otherwise, we may end up with an COFF binary with file size not matching the final section's - // offset + it's filesize. - // TODO I don't like this here one bit - var max_file_offset: u64 = 0; - for (self.sections.items(.header)) |header| { - if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) { - max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data; - } - } - try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset); - } - - return self; -} - pub fn createEmpty( arena: Allocator, comp: *Compilation, @@ -374,8 +242,13 @@ pub fn createEmpty( options: link.File.OpenOptions, ) !*Coff { const target = comp.root_mod.resolved_target.result; + assert(target.ofmt == .coff); const optimize_mode = comp.root_mod.optimize_mode; const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; + const use_llvm = comp.config.use_llvm; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { 0...32 => .p32, 33...64 => .p64, @@ -384,12 +257,24 @@ pub fn createEmpty( const page_size: u32 = switch (target.cpu.arch) { else => 0x1000, }; + + // If using LLD to link, this code should produce an object file so that it + // can be passed to LLD. + // If using LLVM to generate the object file for the zig compilation unit, + // we need a place to put the object file so that it can be subsequently + // handled. + const zcu_object_sub_path = if (!use_lld and !use_llvm) + null + else + try std.fmt.allocPrint(arena, "{s}.obj", .{emit.sub_path}); + const self = try arena.create(Coff); self.* = .{ .base = .{ .tag = .coff, .comp = comp, .emit = emit, + .zcu_object_sub_path = zcu_object_sub_path, .stack_size = options.stack_size orelse 16777216, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), .print_gc_sections = options.print_gc_sections, @@ -430,14 +315,129 @@ pub fn createEmpty( .module_definition_file = options.module_definition_file, .pdb_out_path = options.pdb_out_path, }; - - const use_llvm = comp.config.use_llvm; if (use_llvm and comp.config.have_zcu) { self.llvm_object = try LlvmObject.create(arena, comp); } + errdefer self.base.destroy(); + + if (use_lld and use_llvm) { + // LLVM emits the object file; LLD links it into the final product. + return self; + } + + // What path should this COFF linker code output to? + // If using LLD to link, this code should produce an object file so that it + // can be passed to LLD. + const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; + self.base.file = try emit.directory.handle.createFile(sub_path, .{ + .truncate = true, + .read = true, + .mode = link.File.determineMode(use_lld, output_mode, link_mode), + }); + + assert(self.llvm_object == null); + const gpa = comp.gpa; + + try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); + self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32)); + + try self.temp_strtab.buffer.append(gpa, 0); + + // Index 0 is always a null symbol. + try self.locals.append(gpa, .{ + .name = [_]u8{0} ** 8, + .value = 0, + .section_number = .UNDEFINED, + .type = .{ .base_type = .NULL, .complex_type = .NULL }, + .storage_class = .NULL, + .number_of_aux_symbols = 0, + }); + + if (self.text_section_index == null) { + const file_size: u32 = @intCast(options.program_code_size_hint); + self.text_section_index = try self.allocateSection(".text", file_size, .{ + .CNT_CODE = 1, + .MEM_EXECUTE = 1, + .MEM_READ = 1, + }); + } + + if (self.got_section_index == null) { + const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size(); + self.got_section_index = try self.allocateSection(".got", file_size, .{ + .CNT_INITIALIZED_DATA = 1, + .MEM_READ = 1, + }); + } + + if (self.rdata_section_index == null) { + const file_size: u32 = self.page_size; + self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ + .CNT_INITIALIZED_DATA = 1, + .MEM_READ = 1, + }); + } + + if (self.data_section_index == null) { + const file_size: u32 = self.page_size; + self.data_section_index = try self.allocateSection(".data", file_size, .{ + .CNT_INITIALIZED_DATA = 1, + .MEM_READ = 1, + .MEM_WRITE = 1, + }); + } + + if (self.idata_section_index == null) { + const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size(); + self.idata_section_index = try self.allocateSection(".idata", file_size, .{ + .CNT_INITIALIZED_DATA = 1, + .MEM_READ = 1, + }); + } + + if (self.reloc_section_index == null) { + const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff.BaseRelocation); + self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{ + .CNT_INITIALIZED_DATA = 1, + .MEM_DISCARDABLE = 1, + .MEM_READ = 1, + }); + } + + if (self.strtab_offset == null) { + const file_size = @as(u32, @intCast(self.strtab.buffer.items.len)); + self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here + log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size }); + } + + { + // We need to find out what the max file offset is according to section headers. + // Otherwise, we may end up with an COFF binary with file size not matching the final section's + // offset + it's filesize. + // TODO I don't like this here one bit + var max_file_offset: u64 = 0; + for (self.sections.items(.header)) |header| { + if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) { + max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data; + } + } + try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset); + } + return self; } +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Coff { + // TODO: restore saved linker state, don't truncate the file, and + // participate in incremental compilation. + return createEmpty(arena, comp, emit, options); +} + pub fn deinit(self: *Coff) void { const gpa = self.base.comp.gpa; -- 2.54.0