| ... | @@ -144,39 +144,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -144,39 +144,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 144 | }); | 144 | }); |
| 145 | self.base.file = file; | 145 | self.base.file = file; |
| 146 | | 146 | |
| 147 | // TODO Write object specific relocations, COFF symbol table, then enable object file output. | 147 | const coff_file_header_offset: u32 = if (options.output_mode == .Exe) msdos_stub.len + 4 else 0; |
| 148 | switch (options.output_mode) { | 148 | const default_offset_table_size = file_alignment; |
| 149 | .Exe => {}, | | |
| 150 | .Obj => return error.TODOImplementWritingObjFiles, | | |
| 151 | .Lib => return error.TODOImplementWritingLibFiles, | | |
| 152 | } | | |
| 153 | | | |
| 154 | var coff_file_header_offset: u32 = 0; | | |
| 155 | if (options.output_mode == .Exe) { | | |
| 156 | // Write the MS-DOS stub and the PE signature | | |
| 157 | try self.base.file.?.pwriteAll(msdos_stub ++ "PE\x00\x00", 0); | | |
| 158 | coff_file_header_offset = msdos_stub.len + 4; | | |
| 159 | } | | |
| 160 | | | |
| 161 | // COFF file header | | |
| 162 | const data_directory_count = 0; | 149 | const data_directory_count = 0; |
| 163 | var hdr_data: [112 + data_directory_count * 8 + section_table_size]u8 = undefined; | 150 | const default_size_of_code = 0; |
| 164 | var index: usize = 0; | | |
| 165 | | | |
| 166 | const machine = self.base.options.target.cpu.arch.toCoffMachine(); | | |
| 167 | if (machine == .Unknown) { | | |
| 168 | return error.UnsupportedCOFFArchitecture; | | |
| 169 | } | | |
| 170 | mem.writeIntLittle(u16, hdr_data[0..2], @enumToInt(machine)); | | |
| 171 | index += 2; | | |
| 172 | | | |
| 173 | // Number of sections (we only use .got, .text) | | |
| 174 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 2); | | |
| 175 | index += 2; | | |
| 176 | // TimeDateStamp (u32), PointerToSymbolTable (u32), NumberOfSymbols (u32) | | |
| 177 | mem.set(u8, hdr_data[index..][0..12], 0); | | |
| 178 | index += 12; | | |
| 179 | | | |
| 180 | const optional_header_size = switch (options.output_mode) { | 151 | const optional_header_size = switch (options.output_mode) { |
| 181 | .Exe => data_directory_count * 8 + switch (self.ptr_width) { | 152 | .Exe => data_directory_count * 8 + switch (self.ptr_width) { |
| 182 | .p32 => @as(u16, 96), | 153 | .p32 => @as(u16, 96), |
| ... | @@ -184,218 +155,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -184,218 +155,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 184 | }, | 155 | }, |
| 185 | else => 0, | 156 | else => 0, |
| 186 | }; | 157 | }; |
| 187 | | | |
| 188 | const section_table_offset = coff_file_header_offset + 20 + optional_header_size; | 158 | const section_table_offset = coff_file_header_offset + 20 + optional_header_size; |
| 189 | const default_offset_table_size = file_alignment; | 159 | self.section_data_offset = mem.alignForwardGeneric(u32, section_table_offset + section_table_size, file_alignment); |
| 190 | const default_size_of_code = 0; | 160 | const section_data_relative_virtual_address = mem.alignForwardGeneric(u32, section_table_offset + section_table_size, section_alignment); |
| 191 | | | |
| 192 | self.section_data_offset = mem.alignForwardGeneric(u32, self.section_table_offset + section_table_size, file_alignment); | | |
| 193 | const section_data_relative_virtual_address = mem.alignForwardGeneric(u32, self.section_table_offset + section_table_size, section_alignment); | | |
| 194 | self.offset_table_virtual_address = default_image_base + section_data_relative_virtual_address; | 161 | self.offset_table_virtual_address = default_image_base + section_data_relative_virtual_address; |
| 195 | self.offset_table_size = default_offset_table_size; | 162 | self.offset_table_size = default_offset_table_size; |
| 196 | self.section_table_offset = section_table_offset; | 163 | self.section_table_offset = section_table_offset; |
| 197 | self.text_section_virtual_address = default_image_base + section_data_relative_virtual_address + section_alignment; | 164 | self.text_section_virtual_address = default_image_base + section_data_relative_virtual_address + section_alignment; |
| 198 | self.text_section_size = default_size_of_code; | 165 | self.text_section_size = default_size_of_code; |
| 199 | | 166 | |
| 200 | // Size of file when loaded in memory | | |
| 201 | const size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - default_image_base + default_size_of_code, section_alignment); | | |
| 202 | | | |
| 203 | mem.writeIntLittle(u16, hdr_data[index..][0..2], optional_header_size); | | |
| 204 | index += 2; | | |
| 205 | | | |
| 206 | // Characteristics | | |
| 207 | var characteristics: std.coff.CoffHeaderFlags = .{ | | |
| 208 | .DEBUG_STRIPPED = 1, // TODO remove debug info stripped flag when necessary | | |
| 209 | .RELOCS_STRIPPED = 1, | | |
| 210 | }; | | |
| 211 | if (options.output_mode == .Exe) { | | |
| 212 | characteristics.EXECUTABLE_IMAGE = 1; | | |
| 213 | } | | |
| 214 | switch (self.ptr_width) { | | |
| 215 | .p32 => characteristics.@"32BIT_MACHINE" = 1, | | |
| 216 | .p64 => characteristics.LARGE_ADDRESS_AWARE = 1, | | |
| 217 | } | | |
| 218 | mem.writeIntLittle(u16, hdr_data[index..][0..2], @bitCast(u16, characteristics)); | | |
| 219 | index += 2; | | |
| 220 | | | |
| 221 | assert(index == 20); | | |
| 222 | try self.base.file.?.pwriteAll(hdr_data[0..index], coff_file_header_offset); | | |
| 223 | | | |
| 224 | if (options.output_mode == .Exe) { | | |
| 225 | self.optional_header_offset = coff_file_header_offset + 20; | | |
| 226 | // Optional header | | |
| 227 | index = 0; | | |
| 228 | mem.writeIntLittle(u16, hdr_data[0..2], switch (self.ptr_width) { | | |
| 229 | .p32 => @as(u16, 0x10b), | | |
| 230 | .p64 => 0x20b, | | |
| 231 | }); | | |
| 232 | index += 2; | | |
| 233 | | | |
| 234 | // Linker version (u8 + u8) | | |
| 235 | mem.set(u8, hdr_data[index..][0..2], 0); | | |
| 236 | index += 2; | | |
| 237 | | | |
| 238 | // SizeOfCode (UNUSED, u32), SizeOfInitializedData (u32), SizeOfUninitializedData (u32), AddressOfEntryPoint (u32), BaseOfCode (UNUSED, u32) | | |
| 239 | mem.set(u8, hdr_data[index..][0..20], 0); | | |
| 240 | index += 20; | | |
| 241 | | | |
| 242 | if (self.ptr_width == .p32) { | | |
| 243 | // Base of data relative to the image base (UNUSED) | | |
| 244 | mem.set(u8, hdr_data[index..][0..4], 0); | | |
| 245 | index += 4; | | |
| 246 | | | |
| 247 | // Image base address | | |
| 248 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_image_base); | | |
| 249 | index += 4; | | |
| 250 | } else { | | |
| 251 | // Image base address | | |
| 252 | mem.writeIntLittle(u64, hdr_data[index..][0..8], default_image_base); | | |
| 253 | index += 8; | | |
| 254 | } | | |
| 255 | | | |
| 256 | // Section alignment | | |
| 257 | mem.writeIntLittle(u32, hdr_data[index..][0..4], section_alignment); | | |
| 258 | index += 4; | | |
| 259 | // File alignment | | |
| 260 | mem.writeIntLittle(u32, hdr_data[index..][0..4], file_alignment); | | |
| 261 | index += 4; | | |
| 262 | // Required OS version, 6.0 is vista | | |
| 263 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 6); | | |
| 264 | index += 2; | | |
| 265 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 0); | | |
| 266 | index += 2; | | |
| 267 | // Image version | | |
| 268 | mem.set(u8, hdr_data[index..][0..4], 0); | | |
| 269 | index += 4; | | |
| 270 | // Required subsystem version, same as OS version | | |
| 271 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 6); | | |
| 272 | index += 2; | | |
| 273 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 0); | | |
| 274 | index += 2; | | |
| 275 | // Reserved zeroes (u32) | | |
| 276 | mem.set(u8, hdr_data[index..][0..4], 0); | | |
| 277 | index += 4; | | |
| 278 | mem.writeIntLittle(u32, hdr_data[index..][0..4], size_of_image); | | |
| 279 | index += 4; | | |
| 280 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset); | | |
| 281 | index += 4; | | |
| 282 | // CheckSum (u32) | | |
| 283 | mem.set(u8, hdr_data[index..][0..4], 0); | | |
| 284 | index += 4; | | |
| 285 | // Subsystem, TODO: Let users specify the subsystem, always CUI for now | | |
| 286 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 3); | | |
| 287 | index += 2; | | |
| 288 | // DLL characteristics | | |
| 289 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 0x0); | | |
| 290 | index += 2; | | |
| 291 | | | |
| 292 | switch (self.ptr_width) { | | |
| 293 | .p32 => { | | |
| 294 | // Size of stack reserve + commit | | |
| 295 | mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000_000); | | |
| 296 | index += 4; | | |
| 297 | mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000); | | |
| 298 | index += 4; | | |
| 299 | // Size of heap reserve + commit | | |
| 300 | mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x100_000); | | |
| 301 | index += 4; | | |
| 302 | mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000); | | |
| 303 | index += 4; | | |
| 304 | }, | | |
| 305 | .p64 => { | | |
| 306 | // Size of stack reserve + commit | | |
| 307 | mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000_000); | | |
| 308 | index += 8; | | |
| 309 | mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000); | | |
| 310 | index += 8; | | |
| 311 | // Size of heap reserve + commit | | |
| 312 | mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x100_000); | | |
| 313 | index += 8; | | |
| 314 | mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000); | | |
| 315 | index += 8; | | |
| 316 | }, | | |
| 317 | } | | |
| 318 | | | |
| 319 | // Reserved zeroes | | |
| 320 | mem.set(u8, hdr_data[index..][0..4], 0); | | |
| 321 | index += 4; | | |
| 322 | | | |
| 323 | // Number of data directories | | |
| 324 | mem.writeIntLittle(u32, hdr_data[index..][0..4], data_directory_count); | | |
| 325 | index += 4; | | |
| 326 | // Initialize data directories to zero | | |
| 327 | mem.set(u8, hdr_data[index..][0 .. data_directory_count * 8], 0); | | |
| 328 | index += data_directory_count * 8; | | |
| 329 | | | |
| 330 | assert(index == optional_header_size); | | |
| 331 | } | | |
| 332 | | | |
| 333 | // Write section table. | | |
| 334 | // First, the .got section | | |
| 335 | hdr_data[index..][0..8].* = ".got\x00\x00\x00\x00".*; | | |
| 336 | index += 8; | | |
| 337 | if (options.output_mode == .Exe) { | | |
| 338 | // Virtual size (u32) | | |
| 339 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_offset_table_size); | | |
| 340 | index += 4; | | |
| 341 | // Virtual address (u32) | | |
| 342 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.offset_table_virtual_address - default_image_base); | | |
| 343 | index += 4; | | |
| 344 | } else { | | |
| 345 | mem.set(u8, hdr_data[index..][0..8], 0); | | |
| 346 | index += 8; | | |
| 347 | } | | |
| 348 | // Size of raw data (u32) | | |
| 349 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_offset_table_size); | | |
| 350 | index += 4; | | |
| 351 | // File pointer to the start of the section | | |
| 352 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset); | | |
| 353 | index += 4; | | |
| 354 | // Pointer to relocations (u32), PointerToLinenumbers (u32), NumberOfRelocations (u16), NumberOfLinenumbers (u16) | | |
| 355 | mem.set(u8, hdr_data[index..][0..12], 0); | | |
| 356 | index += 12; | | |
| 357 | // Section flags | | |
| 358 | mem.writeIntLittle(u32, hdr_data[index..][0..4], @bitCast(u32, std.coff.SectionHeaderFlags{ | | |
| 359 | .CNT_INITIALIZED_DATA = 1, | | |
| 360 | .MEM_READ = 1, | | |
| 361 | })); | | |
| 362 | index += 4; | | |
| 363 | // Then, the .text section | | |
| 364 | hdr_data[index..][0..8].* = ".text\x00\x00\x00".*; | | |
| 365 | index += 8; | | |
| 366 | if (options.output_mode == .Exe) { | | |
| 367 | // Virtual size (u32) | | |
| 368 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_size_of_code); | | |
| 369 | index += 4; | | |
| 370 | // Virtual address (u32) | | |
| 371 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.text_section_virtual_address - default_image_base); | | |
| 372 | index += 4; | | |
| 373 | } else { | | |
| 374 | mem.set(u8, hdr_data[index..][0..8], 0); | | |
| 375 | index += 8; | | |
| 376 | } | | |
| 377 | // Size of raw data (u32) | | |
| 378 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_size_of_code); | | |
| 379 | index += 4; | | |
| 380 | // File pointer to the start of the section | | |
| 381 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset + default_offset_table_size); | | |
| 382 | index += 4; | | |
| 383 | // Pointer to relocations (u32), PointerToLinenumbers (u32), NumberOfRelocations (u16), NumberOfLinenumbers (u16) | | |
| 384 | mem.set(u8, hdr_data[index..][0..12], 0); | | |
| 385 | index += 12; | | |
| 386 | // Section flags | | |
| 387 | mem.writeIntLittle(u32, hdr_data[index..][0..4], @bitCast(u32, std.coff.SectionHeaderFlags{ | | |
| 388 | .CNT_CODE = 1, | | |
| 389 | .MEM_EXECUTE = 1, | | |
| 390 | .MEM_READ = 1, | | |
| 391 | .MEM_WRITE = 1, | | |
| 392 | })); | | |
| 393 | index += 4; | | |
| 394 | | | |
| 395 | assert(index == optional_header_size + section_table_size); | | |
| 396 | try self.base.file.?.pwriteAll(hdr_data[0..index], self.optional_header_offset); | | |
| 397 | try self.base.file.?.setEndPos(self.section_data_offset + default_offset_table_size + default_size_of_code); | | |
| 398 | | | |
| 399 | return self; | 167 | return self; |
| 400 | } | 168 | } |
| 401 | | 169 | |
| ... | @@ -728,6 +496,12 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! | ... | @@ -728,6 +496,12 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! |
| 728 | if (decl.val.tag() == .extern_fn) { | 496 | if (decl.val.tag() == .extern_fn) { |
| 729 | return; // TODO Should we do more when front-end analyzed extern decl? | 497 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 730 | } | 498 | } |
| | 499 | if (decl.val.castTag(.variable)) |payload| { |
| | 500 | const variable = payload.data; |
| | 501 | if (variable.is_extern) { |
| | 502 | return; // TODO Should we do more when front-end analyzed extern decl? |
| | 503 | } |
| | 504 | } |
| 731 | | 505 | |
| 732 | // TODO COFF/PE debug information | 506 | // TODO COFF/PE debug information |
| 733 | // TODO Implement exports | 507 | // TODO Implement exports |
| ... | @@ -735,9 +509,10 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! | ... | @@ -735,9 +509,10 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! |
| 735 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 509 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 736 | defer code_buffer.deinit(); | 510 | defer code_buffer.deinit(); |
| 737 | | 511 | |
| | 512 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 738 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 513 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 739 | .ty = decl.ty, | 514 | .ty = decl.ty, |
| 740 | .val = decl.val, | 515 | .val = decl_val, |
| 741 | }, &code_buffer, .none, .{ | 516 | }, &code_buffer, .none, .{ |
| 742 | .parent_atom_index = 0, | 517 | .parent_atom_index = 0, |
| 743 | }); | 518 | }); |
| ... | @@ -862,15 +637,14 @@ pub fn updateDeclExports( | ... | @@ -862,15 +637,14 @@ pub fn updateDeclExports( |
| 862 | continue; | 637 | continue; |
| 863 | } | 638 | } |
| 864 | } | 639 | } |
| 865 | if (mem.eql(u8, exp.options.name, "_start")) { | 640 | if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) { |
| 866 | self.entry_addr = decl.link.coff.getVAddr(self.*) - default_image_base; | 641 | self.entry_addr = decl.link.coff.getVAddr(self.*) - default_image_base; |
| 867 | } else { | 642 | } else { |
| 868 | try module.failed_exports.ensureUnusedCapacity(module.gpa, 1); | 643 | try module.failed_exports.ensureUnusedCapacity(module.gpa, 1); |
| 869 | module.failed_exports.putAssumeCapacityNoClobber( | 644 | module.failed_exports.putAssumeCapacityNoClobber( |
| 870 | exp, | 645 | exp, |
| 871 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: Exports other than '_start'", .{}), | 646 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: Exports other than 'wWinMainCRTStartup'", .{}), |
| 872 | ); | 647 | ); |
| 873 | continue; | | |
| 874 | } | 648 | } |
| 875 | } | 649 | } |
| 876 | } | 650 | } |
| ... | @@ -884,14 +658,13 @@ pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !vo | ... | @@ -884,14 +658,13 @@ pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !vo |
| 884 | } | 658 | } |
| 885 | return; | 659 | return; |
| 886 | } | 660 | } |
| 887 | if (build_options.have_llvm and self.base.options.use_lld) { | 661 | const use_lld = build_options.have_llvm and self.base.options.use_lld; |
| | 662 | if (use_lld) { |
| 888 | return self.linkWithLLD(comp, prog_node); | 663 | return self.linkWithLLD(comp, prog_node); |
| 889 | } else { | 664 | } |
| 890 | switch (self.base.options.effectiveOutputMode()) { | 665 | switch (self.base.options.output_mode) { |
| 891 | .Exe, .Obj => {}, | 666 | .Exe, .Obj => return self.flushModule(comp, prog_node), |
| 892 | .Lib => return error.TODOImplementWritingLibFiles, | 667 | .Lib => return error.TODOImplementWritingLibFiles, |
| 893 | } | | |
| 894 | return self.flushModule(comp, prog_node); | | |
| 895 | } | 668 | } |
| 896 | } | 669 | } |
| 897 | | 670 | |
| ... | @@ -909,6 +682,238 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -909,6 +682,238 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 909 | sub_prog_node.activate(); | 682 | sub_prog_node.activate(); |
| 910 | defer sub_prog_node.end(); | 683 | defer sub_prog_node.end(); |
| 911 | | 684 | |
| | 685 | const output_mode = self.base.options.output_mode; |
| | 686 | log.debug("in flushModule with {}", .{output_mode}); |
| | 687 | |
| | 688 | var coff_file_header_offset: u32 = 0; |
| | 689 | if (output_mode == .Exe) { |
| | 690 | // Write the MS-DOS stub and the PE signature |
| | 691 | try self.base.file.?.pwriteAll(msdos_stub ++ "PE\x00\x00", 0); |
| | 692 | coff_file_header_offset = msdos_stub.len + 4; |
| | 693 | } |
| | 694 | |
| | 695 | // COFF file header |
| | 696 | const data_directory_count = 0; |
| | 697 | var hdr_data: [112 + data_directory_count * 8 + section_table_size]u8 = undefined; |
| | 698 | var index: usize = 0; |
| | 699 | |
| | 700 | const machine = self.base.options.target.cpu.arch.toCoffMachine(); |
| | 701 | if (machine == .Unknown) { |
| | 702 | return error.UnsupportedCOFFArchitecture; |
| | 703 | } |
| | 704 | mem.writeIntLittle(u16, hdr_data[0..2], @enumToInt(machine)); |
| | 705 | index += 2; |
| | 706 | |
| | 707 | // Number of sections (we only use .got, .text) |
| | 708 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 2); |
| | 709 | index += 2; |
| | 710 | // TimeDateStamp (u32), PointerToSymbolTable (u32), NumberOfSymbols (u32) |
| | 711 | mem.set(u8, hdr_data[index..][0..12], 0); |
| | 712 | index += 12; |
| | 713 | |
| | 714 | const optional_header_size = switch (output_mode) { |
| | 715 | .Exe => data_directory_count * 8 + switch (self.ptr_width) { |
| | 716 | .p32 => @as(u16, 96), |
| | 717 | .p64 => 112, |
| | 718 | }, |
| | 719 | else => 0, |
| | 720 | }; |
| | 721 | |
| | 722 | const default_offset_table_size = file_alignment; |
| | 723 | const default_size_of_code = 0; |
| | 724 | |
| | 725 | // Size of file when loaded in memory |
| | 726 | const size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - default_image_base + default_size_of_code, section_alignment); |
| | 727 | |
| | 728 | mem.writeIntLittle(u16, hdr_data[index..][0..2], optional_header_size); |
| | 729 | index += 2; |
| | 730 | |
| | 731 | // Characteristics |
| | 732 | var characteristics: u16 = std.coff.IMAGE_FILE_DEBUG_STRIPPED | std.coff.IMAGE_FILE_RELOCS_STRIPPED; // TODO Remove debug info stripped flag when necessary |
| | 733 | if (output_mode == .Exe) { |
| | 734 | characteristics |= std.coff.IMAGE_FILE_EXECUTABLE_IMAGE; |
| | 735 | } |
| | 736 | switch (self.ptr_width) { |
| | 737 | .p32 => characteristics |= std.coff.IMAGE_FILE_32BIT_MACHINE, |
| | 738 | .p64 => characteristics |= std.coff.IMAGE_FILE_LARGE_ADDRESS_AWARE, |
| | 739 | } |
| | 740 | mem.writeIntLittle(u16, hdr_data[index..][0..2], characteristics); |
| | 741 | index += 2; |
| | 742 | |
| | 743 | assert(index == 20); |
| | 744 | try self.base.file.?.pwriteAll(hdr_data[0..index], coff_file_header_offset); |
| | 745 | |
| | 746 | if (output_mode == .Exe) { |
| | 747 | self.optional_header_offset = coff_file_header_offset + 20; |
| | 748 | // Optional header |
| | 749 | index = 0; |
| | 750 | mem.writeIntLittle(u16, hdr_data[0..2], switch (self.ptr_width) { |
| | 751 | .p32 => @as(u16, 0x10b), |
| | 752 | .p64 => 0x20b, |
| | 753 | }); |
| | 754 | index += 2; |
| | 755 | |
| | 756 | // Linker version (u8 + u8) |
| | 757 | mem.set(u8, hdr_data[index..][0..2], 0); |
| | 758 | index += 2; |
| | 759 | |
| | 760 | // SizeOfCode (UNUSED, u32), SizeOfInitializedData (u32), SizeOfUninitializedData (u32), AddressOfEntryPoint (u32), BaseOfCode (UNUSED, u32) |
| | 761 | mem.set(u8, hdr_data[index..][0..20], 0); |
| | 762 | index += 20; |
| | 763 | |
| | 764 | if (self.ptr_width == .p32) { |
| | 765 | // Base of data relative to the image base (UNUSED) |
| | 766 | mem.set(u8, hdr_data[index..][0..4], 0); |
| | 767 | index += 4; |
| | 768 | |
| | 769 | // Image base address |
| | 770 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_image_base); |
| | 771 | index += 4; |
| | 772 | } else { |
| | 773 | // Image base address |
| | 774 | mem.writeIntLittle(u64, hdr_data[index..][0..8], default_image_base); |
| | 775 | index += 8; |
| | 776 | } |
| | 777 | |
| | 778 | // Section alignment |
| | 779 | mem.writeIntLittle(u32, hdr_data[index..][0..4], section_alignment); |
| | 780 | index += 4; |
| | 781 | // File alignment |
| | 782 | mem.writeIntLittle(u32, hdr_data[index..][0..4], file_alignment); |
| | 783 | index += 4; |
| | 784 | // Required OS version, 6.0 is vista |
| | 785 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 6); |
| | 786 | index += 2; |
| | 787 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 0); |
| | 788 | index += 2; |
| | 789 | // Image version |
| | 790 | mem.set(u8, hdr_data[index..][0..4], 0); |
| | 791 | index += 4; |
| | 792 | // Required subsystem version, same as OS version |
| | 793 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 6); |
| | 794 | index += 2; |
| | 795 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 0); |
| | 796 | index += 2; |
| | 797 | // Reserved zeroes (u32) |
| | 798 | mem.set(u8, hdr_data[index..][0..4], 0); |
| | 799 | index += 4; |
| | 800 | mem.writeIntLittle(u32, hdr_data[index..][0..4], size_of_image); |
| | 801 | index += 4; |
| | 802 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset); |
| | 803 | index += 4; |
| | 804 | // CheckSum (u32) |
| | 805 | mem.set(u8, hdr_data[index..][0..4], 0); |
| | 806 | index += 4; |
| | 807 | // Subsystem, TODO: Let users specify the subsystem, always CUI for now |
| | 808 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 3); |
| | 809 | index += 2; |
| | 810 | // DLL characteristics |
| | 811 | mem.writeIntLittle(u16, hdr_data[index..][0..2], 0x0); |
| | 812 | index += 2; |
| | 813 | |
| | 814 | switch (self.ptr_width) { |
| | 815 | .p32 => { |
| | 816 | // Size of stack reserve + commit |
| | 817 | mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000_000); |
| | 818 | index += 4; |
| | 819 | mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000); |
| | 820 | index += 4; |
| | 821 | // Size of heap reserve + commit |
| | 822 | mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x100_000); |
| | 823 | index += 4; |
| | 824 | mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000); |
| | 825 | index += 4; |
| | 826 | }, |
| | 827 | .p64 => { |
| | 828 | // Size of stack reserve + commit |
| | 829 | mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000_000); |
| | 830 | index += 8; |
| | 831 | mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000); |
| | 832 | index += 8; |
| | 833 | // Size of heap reserve + commit |
| | 834 | mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x100_000); |
| | 835 | index += 8; |
| | 836 | mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000); |
| | 837 | index += 8; |
| | 838 | }, |
| | 839 | } |
| | 840 | |
| | 841 | // Reserved zeroes |
| | 842 | mem.set(u8, hdr_data[index..][0..4], 0); |
| | 843 | index += 4; |
| | 844 | |
| | 845 | // Number of data directories |
| | 846 | mem.writeIntLittle(u32, hdr_data[index..][0..4], data_directory_count); |
| | 847 | index += 4; |
| | 848 | // Initialize data directories to zero |
| | 849 | mem.set(u8, hdr_data[index..][0 .. data_directory_count * 8], 0); |
| | 850 | index += data_directory_count * 8; |
| | 851 | |
| | 852 | assert(index == optional_header_size); |
| | 853 | } |
| | 854 | |
| | 855 | // Write section table. |
| | 856 | // First, the .got section |
| | 857 | hdr_data[index..][0..8].* = ".got\x00\x00\x00\x00".*; |
| | 858 | index += 8; |
| | 859 | if (output_mode == .Exe) { |
| | 860 | // Virtual size (u32) |
| | 861 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_offset_table_size); |
| | 862 | index += 4; |
| | 863 | // Virtual address (u32) |
| | 864 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.offset_table_virtual_address - default_image_base); |
| | 865 | index += 4; |
| | 866 | } else { |
| | 867 | mem.set(u8, hdr_data[index..][0..8], 0); |
| | 868 | index += 8; |
| | 869 | } |
| | 870 | // Size of raw data (u32) |
| | 871 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_offset_table_size); |
| | 872 | index += 4; |
| | 873 | // File pointer to the start of the section |
| | 874 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset); |
| | 875 | index += 4; |
| | 876 | // Pointer to relocations (u32), PointerToLinenumbers (u32), NumberOfRelocations (u16), NumberOfLinenumbers (u16) |
| | 877 | mem.set(u8, hdr_data[index..][0..12], 0); |
| | 878 | index += 12; |
| | 879 | // Section flags |
| | 880 | mem.writeIntLittle(u32, hdr_data[index..][0..4], std.coff.IMAGE_SCN_CNT_INITIALIZED_DATA | std.coff.IMAGE_SCN_MEM_READ); |
| | 881 | index += 4; |
| | 882 | // Then, the .text section |
| | 883 | hdr_data[index..][0..8].* = ".text\x00\x00\x00".*; |
| | 884 | index += 8; |
| | 885 | if (output_mode == .Exe) { |
| | 886 | // Virtual size (u32) |
| | 887 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_size_of_code); |
| | 888 | index += 4; |
| | 889 | // Virtual address (u32) |
| | 890 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.text_section_virtual_address - default_image_base); |
| | 891 | index += 4; |
| | 892 | } else { |
| | 893 | mem.set(u8, hdr_data[index..][0..8], 0); |
| | 894 | index += 8; |
| | 895 | } |
| | 896 | // Size of raw data (u32) |
| | 897 | mem.writeIntLittle(u32, hdr_data[index..][0..4], default_size_of_code); |
| | 898 | index += 4; |
| | 899 | // File pointer to the start of the section |
| | 900 | mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset + default_offset_table_size); |
| | 901 | index += 4; |
| | 902 | // Pointer to relocations (u32), PointerToLinenumbers (u32), NumberOfRelocations (u16), NumberOfLinenumbers (u16) |
| | 903 | mem.set(u8, hdr_data[index..][0..12], 0); |
| | 904 | index += 12; |
| | 905 | // Section flags |
| | 906 | mem.writeIntLittle( |
| | 907 | u32, |
| | 908 | hdr_data[index..][0..4], |
| | 909 | std.coff.IMAGE_SCN_CNT_CODE | std.coff.IMAGE_SCN_MEM_EXECUTE | std.coff.IMAGE_SCN_MEM_READ | std.coff.IMAGE_SCN_MEM_WRITE, |
| | 910 | ); |
| | 911 | index += 4; |
| | 912 | |
| | 913 | assert(index == optional_header_size + section_table_size); |
| | 914 | try self.base.file.?.pwriteAll(hdr_data[0..index], self.optional_header_offset); |
| | 915 | try self.base.file.?.setEndPos(self.section_data_offset + default_offset_table_size + default_size_of_code); |
| | 916 | |
| 912 | if (self.text_section_size_dirty) { | 917 | if (self.text_section_size_dirty) { |
| 913 | // Write the new raw size in the .text header | 918 | // Write the new raw size in the .text header |
| 914 | var buf: [4]u8 = undefined; | 919 | var buf: [4]u8 = undefined; |