| ... | @@ -235,7 +235,7 @@ const ideal_factor = 3; | ... | @@ -235,7 +235,7 @@ const ideal_factor = 3; |
| 235 | const minimum_text_block_size = 64; | 235 | const minimum_text_block_size = 64; |
| 236 | pub const min_text_capacity = padToIdeal(minimum_text_block_size); | 236 | pub const min_text_capacity = padToIdeal(minimum_text_block_size); |
| 237 | | 237 | |
| 238 | pub fn open( | 238 | pub fn createEmpty( |
| 239 | arena: Allocator, | 239 | arena: Allocator, |
| 240 | comp: *Compilation, | 240 | comp: *Compilation, |
| 241 | emit: Compilation.Emit, | 241 | emit: Compilation.Emit, |
| ... | @@ -243,36 +243,96 @@ pub fn open( | ... | @@ -243,36 +243,96 @@ pub fn open( |
| 243 | ) !*Coff { | 243 | ) !*Coff { |
| 244 | const target = comp.root_mod.resolved_target.result; | 244 | const target = comp.root_mod.resolved_target.result; |
| 245 | assert(target.ofmt == .coff); | 245 | assert(target.ofmt == .coff); |
| | 246 | const optimize_mode = comp.root_mod.optimize_mode; |
| | 247 | const output_mode = comp.config.output_mode; |
| | 248 | const link_mode = comp.config.link_mode; |
| | 249 | const use_llvm = comp.config.use_llvm; |
| | 250 | const use_lld = build_options.have_llvm and comp.config.use_lld; |
| 246 | | 251 | |
| 247 | const self = try createEmpty(arena, comp, emit, options); | 252 | const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { |
| 248 | errdefer self.base.destroy(); | 253 | 0...32 => .p32, |
| | 254 | 33...64 => .p64, |
| | 255 | else => return error.UnsupportedCOFFArchitecture, |
| | 256 | }; |
| | 257 | const page_size: u32 = switch (target.cpu.arch) { |
| | 258 | else => 0x1000, |
| | 259 | }; |
| 249 | | 260 | |
| 250 | const use_lld = build_options.have_llvm and comp.config.use_lld; | 261 | // If using LLD to link, this code should produce an object file so that it |
| 251 | const use_llvm = comp.config.use_llvm; | 262 | // can be passed to LLD. |
| | 263 | // If using LLVM to generate the object file for the zig compilation unit, |
| | 264 | // we need a place to put the object file so that it can be subsequently |
| | 265 | // handled. |
| | 266 | const zcu_object_sub_path = if (!use_lld and !use_llvm) |
| | 267 | null |
| | 268 | else |
| | 269 | try std.fmt.allocPrint(arena, "{s}.obj", .{emit.sub_path}); |
| | 270 | |
| | 271 | const self = try arena.create(Coff); |
| | 272 | self.* = .{ |
| | 273 | .base = .{ |
| | 274 | .tag = .coff, |
| | 275 | .comp = comp, |
| | 276 | .emit = emit, |
| | 277 | .zcu_object_sub_path = zcu_object_sub_path, |
| | 278 | .stack_size = options.stack_size orelse 16777216, |
| | 279 | .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), |
| | 280 | .print_gc_sections = options.print_gc_sections, |
| | 281 | .allow_shlib_undefined = options.allow_shlib_undefined orelse false, |
| | 282 | .file = null, |
| | 283 | .disable_lld_caching = options.disable_lld_caching, |
| | 284 | .build_id = options.build_id, |
| | 285 | .rpath_list = options.rpath_list, |
| | 286 | .force_undefined_symbols = options.force_undefined_symbols, |
| | 287 | }, |
| | 288 | .ptr_width = ptr_width, |
| | 289 | .page_size = page_size, |
| | 290 | |
| | 291 | .data_directories = [1]coff.ImageDataDirectory{.{ |
| | 292 | .virtual_address = 0, |
| | 293 | .size = 0, |
| | 294 | }} ** coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES, |
| | 295 | |
| | 296 | .image_base = options.image_base orelse switch (output_mode) { |
| | 297 | .Exe => switch (target.cpu.arch) { |
| | 298 | .aarch64 => 0x140000000, |
| | 299 | .x86_64, .x86 => 0x400000, |
| | 300 | else => unreachable, |
| | 301 | }, |
| | 302 | .Lib => 0x10000000, |
| | 303 | .Obj => 0, |
| | 304 | }, |
| | 305 | |
| | 306 | .subsystem = options.subsystem, |
| | 307 | .tsaware = options.tsaware, |
| | 308 | .nxcompat = options.nxcompat, |
| | 309 | .dynamicbase = options.dynamicbase, |
| | 310 | .major_subsystem_version = options.major_subsystem_version orelse 6, |
| | 311 | .minor_subsystem_version = options.minor_subsystem_version orelse 0, |
| | 312 | .lib_dirs = options.lib_dirs, |
| | 313 | .entry_addr = math.cast(u32, options.entry_addr orelse 0) orelse |
| | 314 | return error.EntryAddressTooBig, |
| | 315 | .module_definition_file = options.module_definition_file, |
| | 316 | .pdb_out_path = options.pdb_out_path, |
| | 317 | }; |
| | 318 | if (use_llvm and comp.config.have_zcu) { |
| | 319 | self.llvm_object = try LlvmObject.create(arena, comp); |
| | 320 | } |
| | 321 | errdefer self.base.destroy(); |
| 252 | | 322 | |
| 253 | if (use_lld and use_llvm) { | 323 | if (use_lld and use_llvm) { |
| 254 | // LLVM emits the object file; LLD links it into the final product. | 324 | // LLVM emits the object file; LLD links it into the final product. |
| 255 | return self; | 325 | return self; |
| 256 | } | 326 | } |
| 257 | | 327 | |
| 258 | const sub_path = if (!use_lld) emit.sub_path else p: { | 328 | // What path should this COFF linker code output to? |
| 259 | // Open a temporary object file, not the final output file because we | 329 | // If using LLD to link, this code should produce an object file so that it |
| 260 | // want to link with LLD. | 330 | // can be passed to LLD. |
| 261 | const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ | 331 | const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; |
| 262 | emit.sub_path, target.ofmt.fileExt(target.cpu.arch), | | |
| 263 | }); | | |
| 264 | self.base.zcu_object_sub_path = o_file_path; | | |
| 265 | break :p o_file_path; | | |
| 266 | }; | | |
| 267 | | | |
| 268 | self.base.file = try emit.directory.handle.createFile(sub_path, .{ | 332 | self.base.file = try emit.directory.handle.createFile(sub_path, .{ |
| 269 | .truncate = false, | 333 | .truncate = true, |
| 270 | .read = true, | 334 | .read = true, |
| 271 | .mode = link.File.determineMode( | 335 | .mode = link.File.determineMode(use_lld, output_mode, link_mode), |
| 272 | use_lld, | | |
| 273 | comp.config.output_mode, | | |
| 274 | comp.config.link_mode, | | |
| 275 | ), | | |
| 276 | }); | 336 | }); |
| 277 | | 337 | |
| 278 | assert(self.llvm_object == null); | 338 | assert(self.llvm_object == null); |
| ... | @@ -367,75 +427,15 @@ pub fn open( | ... | @@ -367,75 +427,15 @@ pub fn open( |
| 367 | return self; | 427 | return self; |
| 368 | } | 428 | } |
| 369 | | 429 | |
| 370 | pub fn createEmpty( | 430 | pub fn open( |
| 371 | arena: Allocator, | 431 | arena: Allocator, |
| 372 | comp: *Compilation, | 432 | comp: *Compilation, |
| 373 | emit: Compilation.Emit, | 433 | emit: Compilation.Emit, |
| 374 | options: link.File.OpenOptions, | 434 | options: link.File.OpenOptions, |
| 375 | ) !*Coff { | 435 | ) !*Coff { |
| 376 | const target = comp.root_mod.resolved_target.result; | 436 | // TODO: restore saved linker state, don't truncate the file, and |
| 377 | const optimize_mode = comp.root_mod.optimize_mode; | 437 | // participate in incremental compilation. |
| 378 | const output_mode = comp.config.output_mode; | 438 | return createEmpty(arena, comp, emit, options); |
| 379 | const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { | | |
| 380 | 0...32 => .p32, | | |
| 381 | 33...64 => .p64, | | |
| 382 | else => return error.UnsupportedCOFFArchitecture, | | |
| 383 | }; | | |
| 384 | const page_size: u32 = switch (target.cpu.arch) { | | |
| 385 | else => 0x1000, | | |
| 386 | }; | | |
| 387 | const self = try arena.create(Coff); | | |
| 388 | self.* = .{ | | |
| 389 | .base = .{ | | |
| 390 | .tag = .coff, | | |
| 391 | .comp = comp, | | |
| 392 | .emit = emit, | | |
| 393 | .stack_size = options.stack_size orelse 16777216, | | |
| 394 | .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), | | |
| 395 | .print_gc_sections = options.print_gc_sections, | | |
| 396 | .allow_shlib_undefined = options.allow_shlib_undefined orelse false, | | |
| 397 | .file = null, | | |
| 398 | .disable_lld_caching = options.disable_lld_caching, | | |
| 399 | .build_id = options.build_id, | | |
| 400 | .rpath_list = options.rpath_list, | | |
| 401 | .force_undefined_symbols = options.force_undefined_symbols, | | |
| 402 | }, | | |
| 403 | .ptr_width = ptr_width, | | |
| 404 | .page_size = page_size, | | |
| 405 | | | |
| 406 | .data_directories = [1]coff.ImageDataDirectory{.{ | | |
| 407 | .virtual_address = 0, | | |
| 408 | .size = 0, | | |
| 409 | }} ** coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES, | | |
| 410 | | | |
| 411 | .image_base = options.image_base orelse switch (output_mode) { | | |
| 412 | .Exe => switch (target.cpu.arch) { | | |
| 413 | .aarch64 => 0x140000000, | | |
| 414 | .x86_64, .x86 => 0x400000, | | |
| 415 | else => unreachable, | | |
| 416 | }, | | |
| 417 | .Lib => 0x10000000, | | |
| 418 | .Obj => 0, | | |
| 419 | }, | | |
| 420 | | | |
| 421 | .subsystem = options.subsystem, | | |
| 422 | .tsaware = options.tsaware, | | |
| 423 | .nxcompat = options.nxcompat, | | |
| 424 | .dynamicbase = options.dynamicbase, | | |
| 425 | .major_subsystem_version = options.major_subsystem_version orelse 6, | | |
| 426 | .minor_subsystem_version = options.minor_subsystem_version orelse 0, | | |
| 427 | .lib_dirs = options.lib_dirs, | | |
| 428 | .entry_addr = math.cast(u32, options.entry_addr orelse 0) orelse | | |
| 429 | return error.EntryAddressTooBig, | | |
| 430 | .module_definition_file = options.module_definition_file, | | |
| 431 | .pdb_out_path = options.pdb_out_path, | | |
| 432 | }; | | |
| 433 | | | |
| 434 | const use_llvm = comp.config.use_llvm; | | |
| 435 | if (use_llvm and comp.config.have_zcu) { | | |
| 436 | self.llvm_object = try LlvmObject.create(arena, comp); | | |
| 437 | } | | |
| 438 | return self; | | |
| 439 | } | 439 | } |
| 440 | | 440 | |
| 441 | pub fn deinit(self: *Coff) void { | 441 | pub fn deinit(self: *Coff) void { |