| ... | @@ -26,10 +26,8 @@ repro: bool, | ... | @@ -26,10 +26,8 @@ repro: bool, |
| 26 | ptr_width: PtrWidth, | 26 | ptr_width: PtrWidth, |
| 27 | page_size: u32, | 27 | page_size: u32, |
| 28 | | 28 | |
| 29 | objects: std.ArrayListUnmanaged(Object) = .empty, | | |
| 30 | | | |
| 31 | sections: std.MultiArrayList(Section) = .{}, | 29 | sections: std.MultiArrayList(Section) = .{}, |
| 32 | data_directories: [coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory, | 30 | data_directories: [coff_util.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff_util.ImageDataDirectory, |
| 33 | | 31 | |
| 34 | text_section_index: ?u16 = null, | 32 | text_section_index: ?u16 = null, |
| 35 | got_section_index: ?u16 = null, | 33 | got_section_index: ?u16 = null, |
| ... | @@ -38,7 +36,7 @@ data_section_index: ?u16 = null, | ... | @@ -38,7 +36,7 @@ data_section_index: ?u16 = null, |
| 38 | reloc_section_index: ?u16 = null, | 36 | reloc_section_index: ?u16 = null, |
| 39 | idata_section_index: ?u16 = null, | 37 | idata_section_index: ?u16 = null, |
| 40 | | 38 | |
| 41 | locals: std.ArrayListUnmanaged(coff.Symbol) = .empty, | 39 | locals: std.ArrayListUnmanaged(coff_util.Symbol) = .empty, |
| 42 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .empty, | 40 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .empty, |
| 43 | resolver: std.StringHashMapUnmanaged(u32) = .empty, | 41 | resolver: std.StringHashMapUnmanaged(u32) = .empty, |
| 44 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .empty, | 42 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .empty, |
| ... | @@ -112,7 +110,7 @@ const default_size_of_heap_reserve: u32 = 0x100000; | ... | @@ -112,7 +110,7 @@ const default_size_of_heap_reserve: u32 = 0x100000; |
| 112 | const default_size_of_heap_commit: u32 = 0x1000; | 110 | const default_size_of_heap_commit: u32 = 0x1000; |
| 113 | | 111 | |
| 114 | const Section = struct { | 112 | const Section = struct { |
| 115 | header: coff.SectionHeader, | 113 | header: coff_util.SectionHeader, |
| 116 | | 114 | |
| 117 | last_atom_index: ?Atom.Index = null, | 115 | last_atom_index: ?Atom.Index = null, |
| 118 | | 116 | |
| ... | @@ -154,9 +152,9 @@ const AvMetadata = struct { | ... | @@ -154,9 +152,9 @@ const AvMetadata = struct { |
| 154 | m.exports.deinit(allocator); | 152 | m.exports.deinit(allocator); |
| 155 | } | 153 | } |
| 156 | | 154 | |
| 157 | fn getExport(m: AvMetadata, coff_file: *const Coff, name: []const u8) ?u32 { | 155 | fn getExport(m: AvMetadata, coff: *const Coff, name: []const u8) ?u32 { |
| 158 | for (m.exports.items) |exp| { | 156 | for (m.exports.items) |exp| { |
| 159 | if (mem.eql(u8, name, coff_file.getSymbolName(.{ | 157 | if (mem.eql(u8, name, coff.getSymbolName(.{ |
| 160 | .sym_index = exp, | 158 | .sym_index = exp, |
| 161 | .file = null, | 159 | .file = null, |
| 162 | }))) return exp; | 160 | }))) return exp; |
| ... | @@ -164,9 +162,9 @@ const AvMetadata = struct { | ... | @@ -164,9 +162,9 @@ const AvMetadata = struct { |
| 164 | return null; | 162 | return null; |
| 165 | } | 163 | } |
| 166 | | 164 | |
| 167 | fn getExportPtr(m: *AvMetadata, coff_file: *Coff, name: []const u8) ?*u32 { | 165 | fn getExportPtr(m: *AvMetadata, coff: *Coff, name: []const u8) ?*u32 { |
| 168 | for (m.exports.items) |*exp| { | 166 | for (m.exports.items) |*exp| { |
| 169 | if (mem.eql(u8, name, coff_file.getSymbolName(.{ | 167 | if (mem.eql(u8, name, coff.getSymbolName(.{ |
| 170 | .sym_index = exp.*, | 168 | .sym_index = exp.*, |
| 171 | .file = null, | 169 | .file = null, |
| 172 | }))) return exp; | 170 | }))) return exp; |
| ... | @@ -247,10 +245,10 @@ pub fn createEmpty( | ... | @@ -247,10 +245,10 @@ pub fn createEmpty( |
| 247 | const zcu_object_sub_path = if (!use_lld and !use_llvm) | 245 | const zcu_object_sub_path = if (!use_lld and !use_llvm) |
| 248 | null | 246 | null |
| 249 | else | 247 | else |
| 250 | try std.fmt.allocPrint(arena, "{s}.obj", .{emit.sub_path}); | 248 | try allocPrint(arena, "{s}.obj", .{emit.sub_path}); |
| 251 | | 249 | |
| 252 | const self = try arena.create(Coff); | 250 | const coff = try arena.create(Coff); |
| 253 | self.* = .{ | 251 | coff.* = .{ |
| 254 | .base = .{ | 252 | .base = .{ |
| 255 | .tag = .coff, | 253 | .tag = .coff, |
| 256 | .comp = comp, | 254 | .comp = comp, |
| ... | @@ -267,10 +265,10 @@ pub fn createEmpty( | ... | @@ -267,10 +265,10 @@ pub fn createEmpty( |
| 267 | .ptr_width = ptr_width, | 265 | .ptr_width = ptr_width, |
| 268 | .page_size = page_size, | 266 | .page_size = page_size, |
| 269 | | 267 | |
| 270 | .data_directories = [1]coff.ImageDataDirectory{.{ | 268 | .data_directories = [1]coff_util.ImageDataDirectory{.{ |
| 271 | .virtual_address = 0, | 269 | .virtual_address = 0, |
| 272 | .size = 0, | 270 | .size = 0, |
| 273 | }} ** coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES, | 271 | }} ** coff_util.IMAGE_NUMBEROF_DIRECTORY_ENTRIES, |
| 274 | | 272 | |
| 275 | .image_base = options.image_base orelse switch (output_mode) { | 273 | .image_base = options.image_base orelse switch (output_mode) { |
| 276 | .Exe => switch (target.cpu.arch) { | 274 | .Exe => switch (target.cpu.arch) { |
| ... | @@ -305,35 +303,35 @@ pub fn createEmpty( | ... | @@ -305,35 +303,35 @@ pub fn createEmpty( |
| 305 | .repro = options.repro, | 303 | .repro = options.repro, |
| 306 | }; | 304 | }; |
| 307 | if (use_llvm and comp.config.have_zcu) { | 305 | if (use_llvm and comp.config.have_zcu) { |
| 308 | self.llvm_object = try LlvmObject.create(arena, comp); | 306 | coff.llvm_object = try LlvmObject.create(arena, comp); |
| 309 | } | 307 | } |
| 310 | errdefer self.base.destroy(); | 308 | errdefer coff.base.destroy(); |
| 311 | | 309 | |
| 312 | if (use_lld and (use_llvm or !comp.config.have_zcu)) { | 310 | if (use_lld and (use_llvm or !comp.config.have_zcu)) { |
| 313 | // LLVM emits the object file (if any); LLD links it into the final product. | 311 | // LLVM emits the object file (if any); LLD links it into the final product. |
| 314 | return self; | 312 | return coff; |
| 315 | } | 313 | } |
| 316 | | 314 | |
| 317 | // What path should this COFF linker code output to? | 315 | // What path should this COFF linker code output to? |
| 318 | // If using LLD to link, this code should produce an object file so that it | 316 | // If using LLD to link, this code should produce an object file so that it |
| 319 | // can be passed to LLD. | 317 | // can be passed to LLD. |
| 320 | const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; | 318 | const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; |
| 321 | self.base.file = try emit.root_dir.handle.createFile(sub_path, .{ | 319 | coff.base.file = try emit.root_dir.handle.createFile(sub_path, .{ |
| 322 | .truncate = true, | 320 | .truncate = true, |
| 323 | .read = true, | 321 | .read = true, |
| 324 | .mode = link.File.determineMode(use_lld, output_mode, link_mode), | 322 | .mode = link.File.determineMode(use_lld, output_mode, link_mode), |
| 325 | }); | 323 | }); |
| 326 | | 324 | |
| 327 | assert(self.llvm_object == null); | 325 | assert(coff.llvm_object == null); |
| 328 | const gpa = comp.gpa; | 326 | const gpa = comp.gpa; |
| 329 | | 327 | |
| 330 | try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); | 328 | try coff.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); |
| 331 | self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32)); | 329 | coff.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32)); |
| 332 | | 330 | |
| 333 | try self.temp_strtab.buffer.append(gpa, 0); | 331 | try coff.temp_strtab.buffer.append(gpa, 0); |
| 334 | | 332 | |
| 335 | // Index 0 is always a null symbol. | 333 | // Index 0 is always a null symbol. |
| 336 | try self.locals.append(gpa, .{ | 334 | try coff.locals.append(gpa, .{ |
| 337 | .name = [_]u8{0} ** 8, | 335 | .name = [_]u8{0} ** 8, |
| 338 | .value = 0, | 336 | .value = 0, |
| 339 | .section_number = .UNDEFINED, | 337 | .section_number = .UNDEFINED, |
| ... | @@ -342,61 +340,61 @@ pub fn createEmpty( | ... | @@ -342,61 +340,61 @@ pub fn createEmpty( |
| 342 | .number_of_aux_symbols = 0, | 340 | .number_of_aux_symbols = 0, |
| 343 | }); | 341 | }); |
| 344 | | 342 | |
| 345 | if (self.text_section_index == null) { | 343 | if (coff.text_section_index == null) { |
| 346 | const file_size: u32 = @intCast(options.program_code_size_hint); | 344 | const file_size: u32 = @intCast(options.program_code_size_hint); |
| 347 | self.text_section_index = try self.allocateSection(".text", file_size, .{ | 345 | coff.text_section_index = try coff.allocateSection(".text", file_size, .{ |
| 348 | .CNT_CODE = 1, | 346 | .CNT_CODE = 1, |
| 349 | .MEM_EXECUTE = 1, | 347 | .MEM_EXECUTE = 1, |
| 350 | .MEM_READ = 1, | 348 | .MEM_READ = 1, |
| 351 | }); | 349 | }); |
| 352 | } | 350 | } |
| 353 | | 351 | |
| 354 | if (self.got_section_index == null) { | 352 | if (coff.got_section_index == null) { |
| 355 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size(); | 353 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size(); |
| 356 | self.got_section_index = try self.allocateSection(".got", file_size, .{ | 354 | coff.got_section_index = try coff.allocateSection(".got", file_size, .{ |
| 357 | .CNT_INITIALIZED_DATA = 1, | 355 | .CNT_INITIALIZED_DATA = 1, |
| 358 | .MEM_READ = 1, | 356 | .MEM_READ = 1, |
| 359 | }); | 357 | }); |
| 360 | } | 358 | } |
| 361 | | 359 | |
| 362 | if (self.rdata_section_index == null) { | 360 | if (coff.rdata_section_index == null) { |
| 363 | const file_size: u32 = self.page_size; | 361 | const file_size: u32 = coff.page_size; |
| 364 | self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ | 362 | coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{ |
| 365 | .CNT_INITIALIZED_DATA = 1, | 363 | .CNT_INITIALIZED_DATA = 1, |
| 366 | .MEM_READ = 1, | 364 | .MEM_READ = 1, |
| 367 | }); | 365 | }); |
| 368 | } | 366 | } |
| 369 | | 367 | |
| 370 | if (self.data_section_index == null) { | 368 | if (coff.data_section_index == null) { |
| 371 | const file_size: u32 = self.page_size; | 369 | const file_size: u32 = coff.page_size; |
| 372 | self.data_section_index = try self.allocateSection(".data", file_size, .{ | 370 | coff.data_section_index = try coff.allocateSection(".data", file_size, .{ |
| 373 | .CNT_INITIALIZED_DATA = 1, | 371 | .CNT_INITIALIZED_DATA = 1, |
| 374 | .MEM_READ = 1, | 372 | .MEM_READ = 1, |
| 375 | .MEM_WRITE = 1, | 373 | .MEM_WRITE = 1, |
| 376 | }); | 374 | }); |
| 377 | } | 375 | } |
| 378 | | 376 | |
| 379 | if (self.idata_section_index == null) { | 377 | if (coff.idata_section_index == null) { |
| 380 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size(); | 378 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size(); |
| 381 | self.idata_section_index = try self.allocateSection(".idata", file_size, .{ | 379 | coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{ |
| 382 | .CNT_INITIALIZED_DATA = 1, | 380 | .CNT_INITIALIZED_DATA = 1, |
| 383 | .MEM_READ = 1, | 381 | .MEM_READ = 1, |
| 384 | }); | 382 | }); |
| 385 | } | 383 | } |
| 386 | | 384 | |
| 387 | if (self.reloc_section_index == null) { | 385 | if (coff.reloc_section_index == null) { |
| 388 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff.BaseRelocation); | 386 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation); |
| 389 | self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{ | 387 | coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{ |
| 390 | .CNT_INITIALIZED_DATA = 1, | 388 | .CNT_INITIALIZED_DATA = 1, |
| 391 | .MEM_DISCARDABLE = 1, | 389 | .MEM_DISCARDABLE = 1, |
| 392 | .MEM_READ = 1, | 390 | .MEM_READ = 1, |
| 393 | }); | 391 | }); |
| 394 | } | 392 | } |
| 395 | | 393 | |
| 396 | if (self.strtab_offset == null) { | 394 | if (coff.strtab_offset == null) { |
| 397 | const file_size = @as(u32, @intCast(self.strtab.buffer.items.len)); | 395 | const file_size = @as(u32, @intCast(coff.strtab.buffer.items.len)); |
| 398 | self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here | 396 | coff.strtab_offset = coff.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here |
| 399 | log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size }); | 397 | log.debug("found strtab free space 0x{x} to 0x{x}", .{ coff.strtab_offset.?, coff.strtab_offset.? + file_size }); |
| 400 | } | 398 | } |
| 401 | | 399 | |
| 402 | { | 400 | { |
| ... | @@ -405,15 +403,15 @@ pub fn createEmpty( | ... | @@ -405,15 +403,15 @@ pub fn createEmpty( |
| 405 | // offset + it's filesize. | 403 | // offset + it's filesize. |
| 406 | // TODO I don't like this here one bit | 404 | // TODO I don't like this here one bit |
| 407 | var max_file_offset: u64 = 0; | 405 | var max_file_offset: u64 = 0; |
| 408 | for (self.sections.items(.header)) |header| { | 406 | for (coff.sections.items(.header)) |header| { |
| 409 | if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) { | 407 | if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) { |
| 410 | max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data; | 408 | max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data; |
| 411 | } | 409 | } |
| 412 | } | 410 | } |
| 413 | try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset); | 411 | try coff.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset); |
| 414 | } | 412 | } |
| 415 | | 413 | |
| 416 | return self; | 414 | return coff; |
| 417 | } | 415 | } |
| 418 | | 416 | |
| 419 | pub fn open( | 417 | pub fn open( |
| ... | @@ -427,85 +425,80 @@ pub fn open( | ... | @@ -427,85 +425,80 @@ pub fn open( |
| 427 | return createEmpty(arena, comp, emit, options); | 425 | return createEmpty(arena, comp, emit, options); |
| 428 | } | 426 | } |
| 429 | | 427 | |
| 430 | pub fn deinit(self: *Coff) void { | 428 | pub fn deinit(coff: *Coff) void { |
| 431 | const gpa = self.base.comp.gpa; | 429 | const gpa = coff.base.comp.gpa; |
| 432 | | | |
| 433 | if (self.llvm_object) |llvm_object| llvm_object.deinit(); | | |
| 434 | | 430 | |
| 435 | for (self.objects.items) |*object| { | 431 | if (coff.llvm_object) |llvm_object| llvm_object.deinit(); |
| 436 | object.deinit(gpa); | | |
| 437 | } | | |
| 438 | self.objects.deinit(gpa); | | |
| 439 | | 432 | |
| 440 | for (self.sections.items(.free_list)) |*free_list| { | 433 | for (coff.sections.items(.free_list)) |*free_list| { |
| 441 | free_list.deinit(gpa); | 434 | free_list.deinit(gpa); |
| 442 | } | 435 | } |
| 443 | self.sections.deinit(gpa); | 436 | coff.sections.deinit(gpa); |
| 444 | | 437 | |
| 445 | self.atoms.deinit(gpa); | 438 | coff.atoms.deinit(gpa); |
| 446 | self.locals.deinit(gpa); | 439 | coff.locals.deinit(gpa); |
| 447 | self.globals.deinit(gpa); | 440 | coff.globals.deinit(gpa); |
| 448 | | 441 | |
| 449 | { | 442 | { |
| 450 | var it = self.resolver.keyIterator(); | 443 | var it = coff.resolver.keyIterator(); |
| 451 | while (it.next()) |key_ptr| { | 444 | while (it.next()) |key_ptr| { |
| 452 | gpa.free(key_ptr.*); | 445 | gpa.free(key_ptr.*); |
| 453 | } | 446 | } |
| 454 | self.resolver.deinit(gpa); | 447 | coff.resolver.deinit(gpa); |
| 455 | } | 448 | } |
| 456 | | 449 | |
| 457 | self.unresolved.deinit(gpa); | 450 | coff.unresolved.deinit(gpa); |
| 458 | self.locals_free_list.deinit(gpa); | 451 | coff.locals_free_list.deinit(gpa); |
| 459 | self.globals_free_list.deinit(gpa); | 452 | coff.globals_free_list.deinit(gpa); |
| 460 | self.strtab.deinit(gpa); | 453 | coff.strtab.deinit(gpa); |
| 461 | self.temp_strtab.deinit(gpa); | 454 | coff.temp_strtab.deinit(gpa); |
| 462 | self.got_table.deinit(gpa); | 455 | coff.got_table.deinit(gpa); |
| 463 | | 456 | |
| 464 | for (self.import_tables.values()) |*itab| { | 457 | for (coff.import_tables.values()) |*itab| { |
| 465 | itab.deinit(gpa); | 458 | itab.deinit(gpa); |
| 466 | } | 459 | } |
| 467 | self.import_tables.deinit(gpa); | 460 | coff.import_tables.deinit(gpa); |
| 468 | | 461 | |
| 469 | self.lazy_syms.deinit(gpa); | 462 | coff.lazy_syms.deinit(gpa); |
| 470 | | 463 | |
| 471 | for (self.navs.values()) |*metadata| { | 464 | for (coff.navs.values()) |*metadata| { |
| 472 | metadata.deinit(gpa); | 465 | metadata.deinit(gpa); |
| 473 | } | 466 | } |
| 474 | self.navs.deinit(gpa); | 467 | coff.navs.deinit(gpa); |
| 475 | | 468 | |
| 476 | self.atom_by_index_table.deinit(gpa); | 469 | coff.atom_by_index_table.deinit(gpa); |
| 477 | | 470 | |
| 478 | { | 471 | { |
| 479 | var it = self.uavs.iterator(); | 472 | var it = coff.uavs.iterator(); |
| 480 | while (it.next()) |entry| { | 473 | while (it.next()) |entry| { |
| 481 | entry.value_ptr.exports.deinit(gpa); | 474 | entry.value_ptr.exports.deinit(gpa); |
| 482 | } | 475 | } |
| 483 | self.uavs.deinit(gpa); | 476 | coff.uavs.deinit(gpa); |
| 484 | } | 477 | } |
| 485 | | 478 | |
| 486 | for (self.relocs.values()) |*relocs| { | 479 | for (coff.relocs.values()) |*relocs| { |
| 487 | relocs.deinit(gpa); | 480 | relocs.deinit(gpa); |
| 488 | } | 481 | } |
| 489 | self.relocs.deinit(gpa); | 482 | coff.relocs.deinit(gpa); |
| 490 | | 483 | |
| 491 | for (self.base_relocs.values()) |*relocs| { | 484 | for (coff.base_relocs.values()) |*relocs| { |
| 492 | relocs.deinit(gpa); | 485 | relocs.deinit(gpa); |
| 493 | } | 486 | } |
| 494 | self.base_relocs.deinit(gpa); | 487 | coff.base_relocs.deinit(gpa); |
| 495 | } | 488 | } |
| 496 | | 489 | |
| 497 | fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.SectionHeaderFlags) !u16 { | 490 | fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeaderFlags) !u16 { |
| 498 | const index = @as(u16, @intCast(self.sections.slice().len)); | 491 | const index = @as(u16, @intCast(coff.sections.slice().len)); |
| 499 | const off = self.findFreeSpace(size, default_file_alignment); | 492 | const off = coff.findFreeSpace(size, default_file_alignment); |
| 500 | // Memory is always allocated in sequence | 493 | // Memory is always allocated in sequence |
| 501 | // TODO: investigate if we can allocate .text last; this way it would never need to grow in memory! | 494 | // TODO: investigate if we can allocate .text last; this way it would never need to grow in memory! |
| 502 | const vaddr = blk: { | 495 | const vaddr = blk: { |
| 503 | if (index == 0) break :blk self.page_size; | 496 | if (index == 0) break :blk coff.page_size; |
| 504 | const prev_header = self.sections.items(.header)[index - 1]; | 497 | const prev_header = coff.sections.items(.header)[index - 1]; |
| 505 | break :blk mem.alignForward(u32, prev_header.virtual_address + prev_header.virtual_size, self.page_size); | 498 | break :blk mem.alignForward(u32, prev_header.virtual_address + prev_header.virtual_size, coff.page_size); |
| 506 | }; | 499 | }; |
| 507 | // We commit more memory than needed upfront so that we don't have to reallocate too soon. | 500 | // We commit more memory than needed upfront so that we don't have to reallocate too soon. |
| 508 | const memsz = mem.alignForward(u32, size, self.page_size) * 100; | 501 | const memsz = mem.alignForward(u32, size, coff.page_size) * 100; |
| 509 | log.debug("found {s} free space 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ | 502 | log.debug("found {s} free space 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ |
| 510 | name, | 503 | name, |
| 511 | off, | 504 | off, |
| ... | @@ -513,7 +506,7 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section | ... | @@ -513,7 +506,7 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section |
| 513 | vaddr, | 506 | vaddr, |
| 514 | vaddr + size, | 507 | vaddr + size, |
| 515 | }); | 508 | }); |
| 516 | var header = coff.SectionHeader{ | 509 | var header = coff_util.SectionHeader{ |
| 517 | .name = undefined, | 510 | .name = undefined, |
| 518 | .virtual_size = memsz, | 511 | .virtual_size = memsz, |
| 519 | .virtual_address = vaddr, | 512 | .virtual_address = vaddr, |
| ... | @@ -525,32 +518,32 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section | ... | @@ -525,32 +518,32 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section |
| 525 | .number_of_linenumbers = 0, | 518 | .number_of_linenumbers = 0, |
| 526 | .flags = flags, | 519 | .flags = flags, |
| 527 | }; | 520 | }; |
| 528 | const gpa = self.base.comp.gpa; | 521 | const gpa = coff.base.comp.gpa; |
| 529 | try self.setSectionName(&header, name); | 522 | try coff.setSectionName(&header, name); |
| 530 | try self.sections.append(gpa, .{ .header = header }); | 523 | try coff.sections.append(gpa, .{ .header = header }); |
| 531 | return index; | 524 | return index; |
| 532 | } | 525 | } |
| 533 | | 526 | |
| 534 | fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void { | 527 | fn growSection(coff: *Coff, sect_id: u32, needed_size: u32) !void { |
| 535 | const header = &self.sections.items(.header)[sect_id]; | 528 | const header = &coff.sections.items(.header)[sect_id]; |
| 536 | const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id]; | 529 | const maybe_last_atom_index = coff.sections.items(.last_atom_index)[sect_id]; |
| 537 | const sect_capacity = self.allocatedSize(header.pointer_to_raw_data); | 530 | const sect_capacity = coff.allocatedSize(header.pointer_to_raw_data); |
| 538 | | 531 | |
| 539 | if (needed_size > sect_capacity) { | 532 | if (needed_size > sect_capacity) { |
| 540 | const new_offset = self.findFreeSpace(needed_size, default_file_alignment); | 533 | const new_offset = coff.findFreeSpace(needed_size, default_file_alignment); |
| 541 | const current_size = if (maybe_last_atom_index) |last_atom_index| blk: { | 534 | const current_size = if (maybe_last_atom_index) |last_atom_index| blk: { |
| 542 | const last_atom = self.getAtom(last_atom_index); | 535 | const last_atom = coff.getAtom(last_atom_index); |
| 543 | const sym = last_atom.getSymbol(self); | 536 | const sym = last_atom.getSymbol(coff); |
| 544 | break :blk (sym.value + last_atom.size) - header.virtual_address; | 537 | break :blk (sym.value + last_atom.size) - header.virtual_address; |
| 545 | } else 0; | 538 | } else 0; |
| 546 | log.debug("moving {s} from 0x{x} to 0x{x}", .{ | 539 | log.debug("moving {s} from 0x{x} to 0x{x}", .{ |
| 547 | self.getSectionName(header), | 540 | coff.getSectionName(header), |
| 548 | header.pointer_to_raw_data, | 541 | header.pointer_to_raw_data, |
| 549 | new_offset, | 542 | new_offset, |
| 550 | }); | 543 | }); |
| 551 | const amt = try self.base.file.?.copyRangeAll( | 544 | const amt = try coff.base.file.?.copyRangeAll( |
| 552 | header.pointer_to_raw_data, | 545 | header.pointer_to_raw_data, |
| 553 | self.base.file.?, | 546 | coff.base.file.?, |
| 554 | new_offset, | 547 | new_offset, |
| 555 | current_size, | 548 | current_size, |
| 556 | ); | 549 | ); |
| ... | @@ -558,35 +551,35 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void { | ... | @@ -558,35 +551,35 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void { |
| 558 | header.pointer_to_raw_data = new_offset; | 551 | header.pointer_to_raw_data = new_offset; |
| 559 | } | 552 | } |
| 560 | | 553 | |
| 561 | const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address); | 554 | const sect_vm_capacity = coff.allocatedVirtualSize(header.virtual_address); |
| 562 | if (needed_size > sect_vm_capacity) { | 555 | if (needed_size > sect_vm_capacity) { |
| 563 | self.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size); | 556 | coff.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size); |
| 564 | try self.growSectionVirtualMemory(sect_id, needed_size); | 557 | try coff.growSectionVirtualMemory(sect_id, needed_size); |
| 565 | } | 558 | } |
| 566 | | 559 | |
| 567 | header.virtual_size = @max(header.virtual_size, needed_size); | 560 | header.virtual_size = @max(header.virtual_size, needed_size); |
| 568 | header.size_of_raw_data = needed_size; | 561 | header.size_of_raw_data = needed_size; |
| 569 | } | 562 | } |
| 570 | | 563 | |
| 571 | fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void { | 564 | fn growSectionVirtualMemory(coff: *Coff, sect_id: u32, needed_size: u32) !void { |
| 572 | const header = &self.sections.items(.header)[sect_id]; | 565 | const header = &coff.sections.items(.header)[sect_id]; |
| 573 | const increased_size = padToIdeal(needed_size); | 566 | const increased_size = padToIdeal(needed_size); |
| 574 | const old_aligned_end = header.virtual_address + mem.alignForward(u32, header.virtual_size, self.page_size); | 567 | const old_aligned_end = header.virtual_address + mem.alignForward(u32, header.virtual_size, coff.page_size); |
| 575 | const new_aligned_end = header.virtual_address + mem.alignForward(u32, increased_size, self.page_size); | 568 | const new_aligned_end = header.virtual_address + mem.alignForward(u32, increased_size, coff.page_size); |
| 576 | const diff = new_aligned_end - old_aligned_end; | 569 | const diff = new_aligned_end - old_aligned_end; |
| 577 | log.debug("growing {s} in virtual memory by {x}", .{ self.getSectionName(header), diff }); | 570 | log.debug("growing {s} in virtual memory by {x}", .{ coff.getSectionName(header), diff }); |
| 578 | | 571 | |
| 579 | // TODO: enforce order by increasing VM addresses in self.sections container. | 572 | // TODO: enforce order by increasing VM addresses in coff.sections container. |
| 580 | // This is required by the loader anyhow as far as I can tell. | 573 | // This is required by the loader anyhow as far as I can tell. |
| 581 | for (self.sections.items(.header)[sect_id + 1 ..], 0..) |*next_header, next_sect_id| { | 574 | for (coff.sections.items(.header)[sect_id + 1 ..], 0..) |*next_header, next_sect_id| { |
| 582 | const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id]; | 575 | const maybe_last_atom_index = coff.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id]; |
| 583 | next_header.virtual_address += diff; | 576 | next_header.virtual_address += diff; |
| 584 | | 577 | |
| 585 | if (maybe_last_atom_index) |last_atom_index| { | 578 | if (maybe_last_atom_index) |last_atom_index| { |
| 586 | var atom_index = last_atom_index; | 579 | var atom_index = last_atom_index; |
| 587 | while (true) { | 580 | while (true) { |
| 588 | const atom = self.getAtom(atom_index); | 581 | const atom = coff.getAtom(atom_index); |
| 589 | const sym = atom.getSymbolPtr(self); | 582 | const sym = atom.getSymbolPtr(coff); |
| 590 | sym.value += diff; | 583 | sym.value += diff; |
| 591 | | 584 | |
| 592 | if (atom.prev_index) |prev_index| { | 585 | if (atom.prev_index) |prev_index| { |
| ... | @@ -599,15 +592,15 @@ fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void { | ... | @@ -599,15 +592,15 @@ fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void { |
| 599 | header.virtual_size = increased_size; | 592 | header.virtual_size = increased_size; |
| 600 | } | 593 | } |
| 601 | | 594 | |
| 602 | fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { | 595 | fn allocateAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { |
| 603 | const tracy = trace(@src()); | 596 | const tracy = trace(@src()); |
| 604 | defer tracy.end(); | 597 | defer tracy.end(); |
| 605 | | 598 | |
| 606 | const atom = self.getAtom(atom_index); | 599 | const atom = coff.getAtom(atom_index); |
| 607 | const sect_id = @intFromEnum(atom.getSymbol(self).section_number) - 1; | 600 | const sect_id = @intFromEnum(atom.getSymbol(coff).section_number) - 1; |
| 608 | const header = &self.sections.items(.header)[sect_id]; | 601 | const header = &coff.sections.items(.header)[sect_id]; |
| 609 | const free_list = &self.sections.items(.free_list)[sect_id]; | 602 | const free_list = &coff.sections.items(.free_list)[sect_id]; |
| 610 | const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; | 603 | const maybe_last_atom_index = &coff.sections.items(.last_atom_index)[sect_id]; |
| 611 | const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size; | 604 | const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size; |
| 612 | | 605 | |
| 613 | // We use these to indicate our intention to update metadata, placing the new atom, | 606 | // We use these to indicate our intention to update metadata, placing the new atom, |
| ... | @@ -624,11 +617,11 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme | ... | @@ -624,11 +617,11 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme |
| 624 | var i: usize = 0; | 617 | var i: usize = 0; |
| 625 | while (i < free_list.items.len) { | 618 | while (i < free_list.items.len) { |
| 626 | const big_atom_index = free_list.items[i]; | 619 | const big_atom_index = free_list.items[i]; |
| 627 | const big_atom = self.getAtom(big_atom_index); | 620 | const big_atom = coff.getAtom(big_atom_index); |
| 628 | // We now have a pointer to a live atom that has too much capacity. | 621 | // We now have a pointer to a live atom that has too much capacity. |
| 629 | // Is it enough that we could fit this new atom? | 622 | // Is it enough that we could fit this new atom? |
| 630 | const sym = big_atom.getSymbol(self); | 623 | const sym = big_atom.getSymbol(coff); |
| 631 | const capacity = big_atom.capacity(self); | 624 | const capacity = big_atom.capacity(coff); |
| 632 | const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity; | 625 | const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity; |
| 633 | const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity; | 626 | const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity; |
| 634 | const capacity_end_vaddr = sym.value + capacity; | 627 | const capacity_end_vaddr = sym.value + capacity; |
| ... | @@ -638,7 +631,7 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme | ... | @@ -638,7 +631,7 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme |
| 638 | // Additional bookkeeping here to notice if this free list node | 631 | // Additional bookkeeping here to notice if this free list node |
| 639 | // should be deleted because the atom that it points to has grown to take up | 632 | // should be deleted because the atom that it points to has grown to take up |
| 640 | // more of the extra capacity. | 633 | // more of the extra capacity. |
| 641 | if (!big_atom.freeListEligible(self)) { | 634 | if (!big_atom.freeListEligible(coff)) { |
| 642 | _ = free_list.swapRemove(i); | 635 | _ = free_list.swapRemove(i); |
| 643 | } else { | 636 | } else { |
| 644 | i += 1; | 637 | i += 1; |
| ... | @@ -658,8 +651,8 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme | ... | @@ -658,8 +651,8 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme |
| 658 | } | 651 | } |
| 659 | break :blk new_start_vaddr; | 652 | break :blk new_start_vaddr; |
| 660 | } else if (maybe_last_atom_index.*) |last_index| { | 653 | } else if (maybe_last_atom_index.*) |last_index| { |
| 661 | const last = self.getAtom(last_index); | 654 | const last = coff.getAtom(last_index); |
| 662 | const last_symbol = last.getSymbol(self); | 655 | const last_symbol = last.getSymbol(coff); |
| 663 | const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size; | 656 | const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size; |
| 664 | const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity; | 657 | const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity; |
| 665 | const new_start_vaddr = mem.alignForward(u32, ideal_capacity_end_vaddr, alignment); | 658 | const new_start_vaddr = mem.alignForward(u32, ideal_capacity_end_vaddr, alignment); |
| ... | @@ -671,33 +664,33 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme | ... | @@ -671,33 +664,33 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme |
| 671 | }; | 664 | }; |
| 672 | | 665 | |
| 673 | const expand_section = if (atom_placement) |placement_index| | 666 | const expand_section = if (atom_placement) |placement_index| |
| 674 | self.getAtom(placement_index).next_index == null | 667 | coff.getAtom(placement_index).next_index == null |
| 675 | else | 668 | else |
| 676 | true; | 669 | true; |
| 677 | if (expand_section) { | 670 | if (expand_section) { |
| 678 | const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address; | 671 | const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address; |
| 679 | try self.growSection(sect_id, needed_size); | 672 | try coff.growSection(sect_id, needed_size); |
| 680 | maybe_last_atom_index.* = atom_index; | 673 | maybe_last_atom_index.* = atom_index; |
| 681 | } | 674 | } |
| 682 | self.getAtomPtr(atom_index).size = new_atom_size; | 675 | coff.getAtomPtr(atom_index).size = new_atom_size; |
| 683 | | 676 | |
| 684 | if (atom.prev_index) |prev_index| { | 677 | if (atom.prev_index) |prev_index| { |
| 685 | const prev = self.getAtomPtr(prev_index); | 678 | const prev = coff.getAtomPtr(prev_index); |
| 686 | prev.next_index = atom.next_index; | 679 | prev.next_index = atom.next_index; |
| 687 | } | 680 | } |
| 688 | if (atom.next_index) |next_index| { | 681 | if (atom.next_index) |next_index| { |
| 689 | const next = self.getAtomPtr(next_index); | 682 | const next = coff.getAtomPtr(next_index); |
| 690 | next.prev_index = atom.prev_index; | 683 | next.prev_index = atom.prev_index; |
| 691 | } | 684 | } |
| 692 | | 685 | |
| 693 | if (atom_placement) |big_atom_index| { | 686 | if (atom_placement) |big_atom_index| { |
| 694 | const big_atom = self.getAtomPtr(big_atom_index); | 687 | const big_atom = coff.getAtomPtr(big_atom_index); |
| 695 | const atom_ptr = self.getAtomPtr(atom_index); | 688 | const atom_ptr = coff.getAtomPtr(atom_index); |
| 696 | atom_ptr.prev_index = big_atom_index; | 689 | atom_ptr.prev_index = big_atom_index; |
| 697 | atom_ptr.next_index = big_atom.next_index; | 690 | atom_ptr.next_index = big_atom.next_index; |
| 698 | big_atom.next_index = atom_index; | 691 | big_atom.next_index = atom_index; |
| 699 | } else { | 692 | } else { |
| 700 | const atom_ptr = self.getAtomPtr(atom_index); | 693 | const atom_ptr = coff.getAtomPtr(atom_index); |
| 701 | atom_ptr.prev_index = null; | 694 | atom_ptr.prev_index = null; |
| 702 | atom_ptr.next_index = null; | 695 | atom_ptr.next_index = null; |
| 703 | } | 696 | } |
| ... | @@ -708,23 +701,23 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme | ... | @@ -708,23 +701,23 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme |
| 708 | return vaddr; | 701 | return vaddr; |
| 709 | } | 702 | } |
| 710 | | 703 | |
| 711 | pub fn allocateSymbol(self: *Coff) !u32 { | 704 | pub fn allocateSymbol(coff: *Coff) !u32 { |
| 712 | const gpa = self.base.comp.gpa; | 705 | const gpa = coff.base.comp.gpa; |
| 713 | try self.locals.ensureUnusedCapacity(gpa, 1); | 706 | try coff.locals.ensureUnusedCapacity(gpa, 1); |
| 714 | | 707 | |
| 715 | const index = blk: { | 708 | const index = blk: { |
| 716 | if (self.locals_free_list.popOrNull()) |index| { | 709 | if (coff.locals_free_list.popOrNull()) |index| { |
| 717 | log.debug(" (reusing symbol index {d})", .{index}); | 710 | log.debug(" (reusing symbol index {d})", .{index}); |
| 718 | break :blk index; | 711 | break :blk index; |
| 719 | } else { | 712 | } else { |
| 720 | log.debug(" (allocating symbol index {d})", .{self.locals.items.len}); | 713 | log.debug(" (allocating symbol index {d})", .{coff.locals.items.len}); |
| 721 | const index = @as(u32, @intCast(self.locals.items.len)); | 714 | const index = @as(u32, @intCast(coff.locals.items.len)); |
| 722 | _ = self.locals.addOneAssumeCapacity(); | 715 | _ = coff.locals.addOneAssumeCapacity(); |
| 723 | break :blk index; | 716 | break :blk index; |
| 724 | } | 717 | } |
| 725 | }; | 718 | }; |
| 726 | | 719 | |
| 727 | self.locals.items[index] = .{ | 720 | coff.locals.items[index] = .{ |
| 728 | .name = [_]u8{0} ** 8, | 721 | .name = [_]u8{0} ** 8, |
| 729 | .value = 0, | 722 | .value = 0, |
| 730 | .section_number = .UNDEFINED, | 723 | .section_number = .UNDEFINED, |
| ... | @@ -736,23 +729,23 @@ pub fn allocateSymbol(self: *Coff) !u32 { | ... | @@ -736,23 +729,23 @@ pub fn allocateSymbol(self: *Coff) !u32 { |
| 736 | return index; | 729 | return index; |
| 737 | } | 730 | } |
| 738 | | 731 | |
| 739 | fn allocateGlobal(self: *Coff) !u32 { | 732 | fn allocateGlobal(coff: *Coff) !u32 { |
| 740 | const gpa = self.base.comp.gpa; | 733 | const gpa = coff.base.comp.gpa; |
| 741 | try self.globals.ensureUnusedCapacity(gpa, 1); | 734 | try coff.globals.ensureUnusedCapacity(gpa, 1); |
| 742 | | 735 | |
| 743 | const index = blk: { | 736 | const index = blk: { |
| 744 | if (self.globals_free_list.popOrNull()) |index| { | 737 | if (coff.globals_free_list.popOrNull()) |index| { |
| 745 | log.debug(" (reusing global index {d})", .{index}); | 738 | log.debug(" (reusing global index {d})", .{index}); |
| 746 | break :blk index; | 739 | break :blk index; |
| 747 | } else { | 740 | } else { |
| 748 | log.debug(" (allocating global index {d})", .{self.globals.items.len}); | 741 | log.debug(" (allocating global index {d})", .{coff.globals.items.len}); |
| 749 | const index = @as(u32, @intCast(self.globals.items.len)); | 742 | const index = @as(u32, @intCast(coff.globals.items.len)); |
| 750 | _ = self.globals.addOneAssumeCapacity(); | 743 | _ = coff.globals.addOneAssumeCapacity(); |
| 751 | break :blk index; | 744 | break :blk index; |
| 752 | } | 745 | } |
| 753 | }; | 746 | }; |
| 754 | | 747 | |
| 755 | self.globals.items[index] = .{ | 748 | coff.globals.items[index] = .{ |
| 756 | .sym_index = 0, | 749 | .sym_index = 0, |
| 757 | .file = null, | 750 | .file = null, |
| 758 | }; | 751 | }; |
| ... | @@ -760,21 +753,21 @@ fn allocateGlobal(self: *Coff) !u32 { | ... | @@ -760,21 +753,21 @@ fn allocateGlobal(self: *Coff) !u32 { |
| 760 | return index; | 753 | return index; |
| 761 | } | 754 | } |
| 762 | | 755 | |
| 763 | fn addGotEntry(self: *Coff, target: SymbolWithLoc) !void { | 756 | fn addGotEntry(coff: *Coff, target: SymbolWithLoc) !void { |
| 764 | const gpa = self.base.comp.gpa; | 757 | const gpa = coff.base.comp.gpa; |
| 765 | if (self.got_table.lookup.contains(target)) return; | 758 | if (coff.got_table.lookup.contains(target)) return; |
| 766 | const got_index = try self.got_table.allocateEntry(gpa, target); | 759 | const got_index = try coff.got_table.allocateEntry(gpa, target); |
| 767 | try self.writeOffsetTableEntry(got_index); | 760 | try coff.writeOffsetTableEntry(got_index); |
| 768 | self.got_table_count_dirty = true; | 761 | coff.got_table_count_dirty = true; |
| 769 | self.markRelocsDirtyByTarget(target); | 762 | coff.markRelocsDirtyByTarget(target); |
| 770 | } | 763 | } |
| 771 | | 764 | |
| 772 | pub fn createAtom(self: *Coff) !Atom.Index { | 765 | pub fn createAtom(coff: *Coff) !Atom.Index { |
| 773 | const gpa = self.base.comp.gpa; | 766 | const gpa = coff.base.comp.gpa; |
| 774 | const atom_index = @as(Atom.Index, @intCast(self.atoms.items.len)); | 767 | const atom_index = @as(Atom.Index, @intCast(coff.atoms.items.len)); |
| 775 | const atom = try self.atoms.addOne(gpa); | 768 | const atom = try coff.atoms.addOne(gpa); |
| 776 | const sym_index = try self.allocateSymbol(); | 769 | const sym_index = try coff.allocateSymbol(); |
| 777 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); | 770 | try coff.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); |
| 778 | atom.* = .{ | 771 | atom.* = .{ |
| 779 | .sym_index = sym_index, | 772 | .sym_index = sym_index, |
| 780 | .file = null, | 773 | .file = null, |
| ... | @@ -786,36 +779,36 @@ pub fn createAtom(self: *Coff) !Atom.Index { | ... | @@ -786,36 +779,36 @@ pub fn createAtom(self: *Coff) !Atom.Index { |
| 786 | return atom_index; | 779 | return atom_index; |
| 787 | } | 780 | } |
| 788 | | 781 | |
| 789 | fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { | 782 | fn growAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { |
| 790 | const atom = self.getAtom(atom_index); | 783 | const atom = coff.getAtom(atom_index); |
| 791 | const sym = atom.getSymbol(self); | 784 | const sym = atom.getSymbol(coff); |
| 792 | const align_ok = mem.alignBackward(u32, sym.value, alignment) == sym.value; | 785 | const align_ok = mem.alignBackward(u32, sym.value, alignment) == sym.value; |
| 793 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); | 786 | const need_realloc = !align_ok or new_atom_size > atom.capacity(coff); |
| 794 | if (!need_realloc) return sym.value; | 787 | if (!need_realloc) return sym.value; |
| 795 | return self.allocateAtom(atom_index, new_atom_size, alignment); | 788 | return coff.allocateAtom(atom_index, new_atom_size, alignment); |
| 796 | } | 789 | } |
| 797 | | 790 | |
| 798 | fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void { | 791 | fn shrinkAtom(coff: *Coff, atom_index: Atom.Index, new_block_size: u32) void { |
| 799 | _ = self; | 792 | _ = coff; |
| 800 | _ = atom_index; | 793 | _ = atom_index; |
| 801 | _ = new_block_size; | 794 | _ = new_block_size; |
| 802 | // TODO check the new capacity, and if it crosses the size threshold into a big enough | 795 | // TODO check the new capacity, and if it crosses the size threshold into a big enough |
| 803 | // capacity, insert a free list node for it. | 796 | // capacity, insert a free list node for it. |
| 804 | } | 797 | } |
| 805 | | 798 | |
| 806 | fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { | 799 | fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8) !void { |
| 807 | const atom = self.getAtom(atom_index); | 800 | const atom = coff.getAtom(atom_index); |
| 808 | const sym = atom.getSymbol(self); | 801 | const sym = atom.getSymbol(coff); |
| 809 | const section = self.sections.get(@intFromEnum(sym.section_number) - 1); | 802 | const section = coff.sections.get(@intFromEnum(sym.section_number) - 1); |
| 810 | const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address; | 803 | const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address; |
| 811 | | 804 | |
| 812 | log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{ | 805 | log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{ |
| 813 | atom.getName(self), | 806 | atom.getName(coff), |
| 814 | file_offset, | 807 | file_offset, |
| 815 | file_offset + code.len, | 808 | file_offset + code.len, |
| 816 | }); | 809 | }); |
| 817 | | 810 | |
| 818 | const gpa = self.base.comp.gpa; | 811 | const gpa = coff.base.comp.gpa; |
| 819 | | 812 | |
| 820 | // Gather relocs which can be resolved. | 813 | // Gather relocs which can be resolved. |
| 821 | // We need to do this as we will be applying different slide values depending | 814 | // We need to do this as we will be applying different slide values depending |
| ... | @@ -825,22 +818,22 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { | ... | @@ -825,22 +818,22 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { |
| 825 | var relocs = std.ArrayList(*Relocation).init(gpa); | 818 | var relocs = std.ArrayList(*Relocation).init(gpa); |
| 826 | defer relocs.deinit(); | 819 | defer relocs.deinit(); |
| 827 | | 820 | |
| 828 | if (self.relocs.getPtr(atom_index)) |rels| { | 821 | if (coff.relocs.getPtr(atom_index)) |rels| { |
| 829 | try relocs.ensureTotalCapacityPrecise(rels.items.len); | 822 | try relocs.ensureTotalCapacityPrecise(rels.items.len); |
| 830 | for (rels.items) |*reloc| { | 823 | for (rels.items) |*reloc| { |
| 831 | if (reloc.isResolvable(self) and reloc.dirty) { | 824 | if (reloc.isResolvable(coff) and reloc.dirty) { |
| 832 | relocs.appendAssumeCapacity(reloc); | 825 | relocs.appendAssumeCapacity(reloc); |
| 833 | } | 826 | } |
| 834 | } | 827 | } |
| 835 | } | 828 | } |
| 836 | | 829 | |
| 837 | if (is_hot_update_compatible) { | 830 | if (is_hot_update_compatible) { |
| 838 | if (self.base.child_pid) |handle| { | 831 | if (coff.base.child_pid) |handle| { |
| 839 | const slide = @intFromPtr(self.hot_state.loaded_base_address.?); | 832 | const slide = @intFromPtr(coff.hot_state.loaded_base_address.?); |
| 840 | | 833 | |
| 841 | const mem_code = try gpa.dupe(u8, code); | 834 | const mem_code = try gpa.dupe(u8, code); |
| 842 | defer gpa.free(mem_code); | 835 | defer gpa.free(mem_code); |
| 843 | self.resolveRelocs(atom_index, relocs.items, mem_code, slide); | 836 | coff.resolveRelocs(atom_index, relocs.items, mem_code, slide); |
| 844 | | 837 | |
| 845 | const vaddr = sym.value + slide; | 838 | const vaddr = sym.value + slide; |
| 846 | const pvaddr = @as(*anyopaque, @ptrFromInt(vaddr)); | 839 | const pvaddr = @as(*anyopaque, @ptrFromInt(vaddr)); |
| ... | @@ -863,8 +856,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { | ... | @@ -863,8 +856,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { |
| 863 | } | 856 | } |
| 864 | } | 857 | } |
| 865 | | 858 | |
| 866 | self.resolveRelocs(atom_index, relocs.items, code, self.image_base); | 859 | coff.resolveRelocs(atom_index, relocs.items, code, coff.image_base); |
| 867 | try self.base.file.?.pwriteAll(code, file_offset); | 860 | try coff.base.file.?.pwriteAll(code, file_offset); |
| 868 | | 861 | |
| 869 | // Now we can mark the relocs as resolved. | 862 | // Now we can mark the relocs as resolved. |
| 870 | while (relocs.popOrNull()) |reloc| { | 863 | while (relocs.popOrNull()) |reloc| { |
| ... | @@ -893,46 +886,46 @@ fn writeMem(handle: std.process.Child.Id, pvaddr: std.os.windows.LPVOID, code: [ | ... | @@ -893,46 +886,46 @@ fn writeMem(handle: std.process.Child.Id, pvaddr: std.os.windows.LPVOID, code: [ |
| 893 | if (amt != code.len) return error.InputOutput; | 886 | if (amt != code.len) return error.InputOutput; |
| 894 | } | 887 | } |
| 895 | | 888 | |
| 896 | fn writeOffsetTableEntry(self: *Coff, index: usize) !void { | 889 | fn writeOffsetTableEntry(coff: *Coff, index: usize) !void { |
| 897 | const sect_id = self.got_section_index.?; | 890 | const sect_id = coff.got_section_index.?; |
| 898 | | 891 | |
| 899 | if (self.got_table_count_dirty) { | 892 | if (coff.got_table_count_dirty) { |
| 900 | const needed_size = @as(u32, @intCast(self.got_table.entries.items.len * self.ptr_width.size())); | 893 | const needed_size = @as(u32, @intCast(coff.got_table.entries.items.len * coff.ptr_width.size())); |
| 901 | try self.growSection(sect_id, needed_size); | 894 | try coff.growSection(sect_id, needed_size); |
| 902 | self.got_table_count_dirty = false; | 895 | coff.got_table_count_dirty = false; |
| 903 | } | 896 | } |
| 904 | | 897 | |
| 905 | const header = &self.sections.items(.header)[sect_id]; | 898 | const header = &coff.sections.items(.header)[sect_id]; |
| 906 | const entry = self.got_table.entries.items[index]; | 899 | const entry = coff.got_table.entries.items[index]; |
| 907 | const entry_value = self.getSymbol(entry).value; | 900 | const entry_value = coff.getSymbol(entry).value; |
| 908 | const entry_offset = index * self.ptr_width.size(); | 901 | const entry_offset = index * coff.ptr_width.size(); |
| 909 | const file_offset = header.pointer_to_raw_data + entry_offset; | 902 | const file_offset = header.pointer_to_raw_data + entry_offset; |
| 910 | const vmaddr = header.virtual_address + entry_offset; | 903 | const vmaddr = header.virtual_address + entry_offset; |
| 911 | | 904 | |
| 912 | log.debug("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value + self.image_base }); | 905 | log.debug("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value + coff.image_base }); |
| 913 | | 906 | |
| 914 | switch (self.ptr_width) { | 907 | switch (coff.ptr_width) { |
| 915 | .p32 => { | 908 | .p32 => { |
| 916 | var buf: [4]u8 = undefined; | 909 | var buf: [4]u8 = undefined; |
| 917 | mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + self.image_base)), .little); | 910 | mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + coff.image_base)), .little); |
| 918 | try self.base.file.?.pwriteAll(&buf, file_offset); | 911 | try coff.base.file.?.pwriteAll(&buf, file_offset); |
| 919 | }, | 912 | }, |
| 920 | .p64 => { | 913 | .p64 => { |
| 921 | var buf: [8]u8 = undefined; | 914 | var buf: [8]u8 = undefined; |
| 922 | mem.writeInt(u64, &buf, entry_value + self.image_base, .little); | 915 | mem.writeInt(u64, &buf, entry_value + coff.image_base, .little); |
| 923 | try self.base.file.?.pwriteAll(&buf, file_offset); | 916 | try coff.base.file.?.pwriteAll(&buf, file_offset); |
| 924 | }, | 917 | }, |
| 925 | } | 918 | } |
| 926 | | 919 | |
| 927 | if (is_hot_update_compatible) { | 920 | if (is_hot_update_compatible) { |
| 928 | if (self.base.child_pid) |handle| { | 921 | if (coff.base.child_pid) |handle| { |
| 929 | const gpa = self.base.comp.gpa; | 922 | const gpa = coff.base.comp.gpa; |
| 930 | const slide = @intFromPtr(self.hot_state.loaded_base_address.?); | 923 | const slide = @intFromPtr(coff.hot_state.loaded_base_address.?); |
| 931 | const actual_vmaddr = vmaddr + slide; | 924 | const actual_vmaddr = vmaddr + slide; |
| 932 | const pvaddr = @as(*anyopaque, @ptrFromInt(actual_vmaddr)); | 925 | const pvaddr = @as(*anyopaque, @ptrFromInt(actual_vmaddr)); |
| 933 | log.debug("writing GOT entry to memory at address {x}", .{actual_vmaddr}); | 926 | log.debug("writing GOT entry to memory at address {x}", .{actual_vmaddr}); |
| 934 | if (build_options.enable_logging) { | 927 | if (build_options.enable_logging) { |
| 935 | switch (self.ptr_width) { | 928 | switch (coff.ptr_width) { |
| 936 | .p32 => { | 929 | .p32 => { |
| 937 | var buf: [4]u8 = undefined; | 930 | var buf: [4]u8 = undefined; |
| 938 | try debugMem(gpa, handle, pvaddr, &buf); | 931 | try debugMem(gpa, handle, pvaddr, &buf); |
| ... | @@ -944,7 +937,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void { | ... | @@ -944,7 +937,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void { |
| 944 | } | 937 | } |
| 945 | } | 938 | } |
| 946 | | 939 | |
| 947 | switch (self.ptr_width) { | 940 | switch (coff.ptr_width) { |
| 948 | .p32 => { | 941 | .p32 => { |
| 949 | var buf: [4]u8 = undefined; | 942 | var buf: [4]u8 = undefined; |
| 950 | mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + slide)), .little); | 943 | mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + slide)), .little); |
| ... | @@ -964,9 +957,9 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void { | ... | @@ -964,9 +957,9 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void { |
| 964 | } | 957 | } |
| 965 | } | 958 | } |
| 966 | | 959 | |
| 967 | fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void { | 960 | fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void { |
| 968 | // TODO: reverse-lookup might come in handy here | 961 | // TODO: reverse-lookup might come in handy here |
| 969 | for (self.relocs.values()) |*relocs| { | 962 | for (coff.relocs.values()) |*relocs| { |
| 970 | for (relocs.items) |*reloc| { | 963 | for (relocs.items) |*reloc| { |
| 971 | if (!reloc.target.eql(target)) continue; | 964 | if (!reloc.target.eql(target)) continue; |
| 972 | reloc.dirty = true; | 965 | reloc.dirty = true; |
| ... | @@ -974,71 +967,71 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void { | ... | @@ -974,71 +967,71 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void { |
| 974 | } | 967 | } |
| 975 | } | 968 | } |
| 976 | | 969 | |
| 977 | fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { | 970 | fn markRelocsDirtyByAddress(coff: *Coff, addr: u32) void { |
| 978 | const got_moved = blk: { | 971 | const got_moved = blk: { |
| 979 | const sect_id = self.got_section_index orelse break :blk false; | 972 | const sect_id = coff.got_section_index orelse break :blk false; |
| 980 | break :blk self.sections.items(.header)[sect_id].virtual_address >= addr; | 973 | break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr; |
| 981 | }; | 974 | }; |
| 982 | | 975 | |
| 983 | // TODO: dirty relocations targeting import table if that got moved in memory | 976 | // TODO: dirty relocations targeting import table if that got moved in memory |
| 984 | | 977 | |
| 985 | for (self.relocs.values()) |*relocs| { | 978 | for (coff.relocs.values()) |*relocs| { |
| 986 | for (relocs.items) |*reloc| { | 979 | for (relocs.items) |*reloc| { |
| 987 | if (reloc.isGotIndirection()) { | 980 | if (reloc.isGotIndirection()) { |
| 988 | reloc.dirty = reloc.dirty or got_moved; | 981 | reloc.dirty = reloc.dirty or got_moved; |
| 989 | } else { | 982 | } else { |
| 990 | const target_vaddr = reloc.getTargetAddress(self) orelse continue; | 983 | const target_vaddr = reloc.getTargetAddress(coff) orelse continue; |
| 991 | if (target_vaddr >= addr) reloc.dirty = true; | 984 | if (target_vaddr >= addr) reloc.dirty = true; |
| 992 | } | 985 | } |
| 993 | } | 986 | } |
| 994 | } | 987 | } |
| 995 | | 988 | |
| 996 | // TODO: dirty only really affected GOT cells | 989 | // TODO: dirty only really affected GOT cells |
| 997 | for (self.got_table.entries.items) |entry| { | 990 | for (coff.got_table.entries.items) |entry| { |
| 998 | const target_addr = self.getSymbol(entry).value; | 991 | const target_addr = coff.getSymbol(entry).value; |
| 999 | if (target_addr >= addr) { | 992 | if (target_addr >= addr) { |
| 1000 | self.got_table_contents_dirty = true; | 993 | coff.got_table_contents_dirty = true; |
| 1001 | break; | 994 | break; |
| 1002 | } | 995 | } |
| 1003 | } | 996 | } |
| 1004 | } | 997 | } |
| 1005 | | 998 | |
| 1006 | fn resolveRelocs(self: *Coff, atom_index: Atom.Index, relocs: []*const Relocation, code: []u8, image_base: u64) void { | 999 | fn resolveRelocs(coff: *Coff, atom_index: Atom.Index, relocs: []*const Relocation, code: []u8, image_base: u64) void { |
| 1007 | log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)}); | 1000 | log.debug("relocating '{s}'", .{coff.getAtom(atom_index).getName(coff)}); |
| 1008 | for (relocs) |reloc| { | 1001 | for (relocs) |reloc| { |
| 1009 | reloc.resolve(atom_index, code, image_base, self); | 1002 | reloc.resolve(atom_index, code, image_base, coff); |
| 1010 | } | 1003 | } |
| 1011 | } | 1004 | } |
| 1012 | | 1005 | |
| 1013 | pub fn ptraceAttach(self: *Coff, handle: std.process.Child.Id) !void { | 1006 | pub fn ptraceAttach(coff: *Coff, handle: std.process.Child.Id) !void { |
| 1014 | if (!is_hot_update_compatible) return; | 1007 | if (!is_hot_update_compatible) return; |
| 1015 | | 1008 | |
| 1016 | log.debug("attaching to process with handle {*}", .{handle}); | 1009 | log.debug("attaching to process with handle {*}", .{handle}); |
| 1017 | self.hot_state.loaded_base_address = std.os.windows.ProcessBaseAddress(handle) catch |err| { | 1010 | coff.hot_state.loaded_base_address = std.os.windows.ProcessBaseAddress(handle) catch |err| { |
| 1018 | log.warn("failed to get base address for the process with error: {s}", .{@errorName(err)}); | 1011 | log.warn("failed to get base address for the process with error: {s}", .{@errorName(err)}); |
| 1019 | return; | 1012 | return; |
| 1020 | }; | 1013 | }; |
| 1021 | } | 1014 | } |
| 1022 | | 1015 | |
| 1023 | pub fn ptraceDetach(self: *Coff, handle: std.process.Child.Id) void { | 1016 | pub fn ptraceDetach(coff: *Coff, handle: std.process.Child.Id) void { |
| 1024 | if (!is_hot_update_compatible) return; | 1017 | if (!is_hot_update_compatible) return; |
| 1025 | | 1018 | |
| 1026 | log.debug("detaching from process with handle {*}", .{handle}); | 1019 | log.debug("detaching from process with handle {*}", .{handle}); |
| 1027 | self.hot_state.loaded_base_address = null; | 1020 | coff.hot_state.loaded_base_address = null; |
| 1028 | } | 1021 | } |
| 1029 | | 1022 | |
| 1030 | fn freeAtom(self: *Coff, atom_index: Atom.Index) void { | 1023 | fn freeAtom(coff: *Coff, atom_index: Atom.Index) void { |
| 1031 | log.debug("freeAtom {d}", .{atom_index}); | 1024 | log.debug("freeAtom {d}", .{atom_index}); |
| 1032 | | 1025 | |
| 1033 | const gpa = self.base.comp.gpa; | 1026 | const gpa = coff.base.comp.gpa; |
| 1034 | | 1027 | |
| 1035 | // Remove any relocs and base relocs associated with this Atom | 1028 | // Remove any relocs and base relocs associated with this Atom |
| 1036 | Atom.freeRelocations(self, atom_index); | 1029 | coff.freeRelocations(atom_index); |
| 1037 | | 1030 | |
| 1038 | const atom = self.getAtom(atom_index); | 1031 | const atom = coff.getAtom(atom_index); |
| 1039 | const sym = atom.getSymbol(self); | 1032 | const sym = atom.getSymbol(coff); |
| 1040 | const sect_id = @intFromEnum(sym.section_number) - 1; | 1033 | const sect_id = @intFromEnum(sym.section_number) - 1; |
| 1041 | const free_list = &self.sections.items(.free_list)[sect_id]; | 1034 | const free_list = &coff.sections.items(.free_list)[sect_id]; |
| 1042 | var already_have_free_list_node = false; | 1035 | var already_have_free_list_node = false; |
| 1043 | { | 1036 | { |
| 1044 | var i: usize = 0; | 1037 | var i: usize = 0; |
| ... | @@ -1055,7 +1048,7 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void { | ... | @@ -1055,7 +1048,7 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void { |
| 1055 | } | 1048 | } |
| 1056 | } | 1049 | } |
| 1057 | | 1050 | |
| 1058 | const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; | 1051 | const maybe_last_atom_index = &coff.sections.items(.last_atom_index)[sect_id]; |
| 1059 | if (maybe_last_atom_index.*) |last_atom_index| { | 1052 | if (maybe_last_atom_index.*) |last_atom_index| { |
| 1060 | if (last_atom_index == atom_index) { | 1053 | if (last_atom_index == atom_index) { |
| 1061 | if (atom.prev_index) |prev_index| { | 1054 | if (atom.prev_index) |prev_index| { |
| ... | @@ -1068,42 +1061,42 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void { | ... | @@ -1068,42 +1061,42 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void { |
| 1068 | } | 1061 | } |
| 1069 | | 1062 | |
| 1070 | if (atom.prev_index) |prev_index| { | 1063 | if (atom.prev_index) |prev_index| { |
| 1071 | const prev = self.getAtomPtr(prev_index); | 1064 | const prev = coff.getAtomPtr(prev_index); |
| 1072 | prev.next_index = atom.next_index; | 1065 | prev.next_index = atom.next_index; |
| 1073 | | 1066 | |
| 1074 | if (!already_have_free_list_node and prev.*.freeListEligible(self)) { | 1067 | if (!already_have_free_list_node and prev.*.freeListEligible(coff)) { |
| 1075 | // The free list is heuristics, it doesn't have to be perfect, so we can | 1068 | // The free list is heuristics, it doesn't have to be perfect, so we can |
| 1076 | // ignore the OOM here. | 1069 | // ignore the OOM here. |
| 1077 | free_list.append(gpa, prev_index) catch {}; | 1070 | free_list.append(gpa, prev_index) catch {}; |
| 1078 | } | 1071 | } |
| 1079 | } else { | 1072 | } else { |
| 1080 | self.getAtomPtr(atom_index).prev_index = null; | 1073 | coff.getAtomPtr(atom_index).prev_index = null; |
| 1081 | } | 1074 | } |
| 1082 | | 1075 | |
| 1083 | if (atom.next_index) |next_index| { | 1076 | if (atom.next_index) |next_index| { |
| 1084 | self.getAtomPtr(next_index).prev_index = atom.prev_index; | 1077 | coff.getAtomPtr(next_index).prev_index = atom.prev_index; |
| 1085 | } else { | 1078 | } else { |
| 1086 | self.getAtomPtr(atom_index).next_index = null; | 1079 | coff.getAtomPtr(atom_index).next_index = null; |
| 1087 | } | 1080 | } |
| 1088 | | 1081 | |
| 1089 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 1082 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 1090 | const sym_index = atom.getSymbolIndex().?; | 1083 | const sym_index = atom.getSymbolIndex().?; |
| 1091 | self.locals_free_list.append(gpa, sym_index) catch {}; | 1084 | coff.locals_free_list.append(gpa, sym_index) catch {}; |
| 1092 | | 1085 | |
| 1093 | // Try freeing GOT atom if this decl had one | 1086 | // Try freeing GOT atom if this decl had one |
| 1094 | self.got_table.freeEntry(gpa, .{ .sym_index = sym_index }); | 1087 | coff.got_table.freeEntry(gpa, .{ .sym_index = sym_index }); |
| 1095 | | 1088 | |
| 1096 | self.locals.items[sym_index].section_number = .UNDEFINED; | 1089 | coff.locals.items[sym_index].section_number = .UNDEFINED; |
| 1097 | _ = self.atom_by_index_table.remove(sym_index); | 1090 | _ = coff.atom_by_index_table.remove(sym_index); |
| 1098 | log.debug(" adding local symbol index {d} to free list", .{sym_index}); | 1091 | log.debug(" adding local symbol index {d} to free list", .{sym_index}); |
| 1099 | self.getAtomPtr(atom_index).sym_index = 0; | 1092 | coff.getAtomPtr(atom_index).sym_index = 0; |
| 1100 | } | 1093 | } |
| 1101 | | 1094 | |
| 1102 | pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { | 1095 | pub fn updateFunc(coff: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { |
| 1103 | if (build_options.skip_non_native and builtin.object_format != .coff) { | 1096 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1104 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1097 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1105 | } | 1098 | } |
| 1106 | if (self.llvm_object) |llvm_object| { | 1099 | if (coff.llvm_object) |llvm_object| { |
| 1107 | return llvm_object.updateFunc(pt, func_index, air, liveness); | 1100 | return llvm_object.updateFunc(pt, func_index, air, liveness); |
| 1108 | } | 1101 | } |
| 1109 | const tracy = trace(@src()); | 1102 | const tracy = trace(@src()); |
| ... | @@ -1113,14 +1106,14 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, | ... | @@ -1113,14 +1106,14 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, |
| 1113 | const gpa = zcu.gpa; | 1106 | const gpa = zcu.gpa; |
| 1114 | const func = zcu.funcInfo(func_index); | 1107 | const func = zcu.funcInfo(func_index); |
| 1115 | | 1108 | |
| 1116 | const atom_index = try self.getOrCreateAtomForNav(func.owner_nav); | 1109 | const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav); |
| 1117 | Atom.freeRelocations(self, atom_index); | 1110 | coff.freeRelocations(atom_index); |
| 1118 | | 1111 | |
| 1119 | var code_buffer = std.ArrayList(u8).init(gpa); | 1112 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1120 | defer code_buffer.deinit(); | 1113 | defer code_buffer.deinit(); |
| 1121 | | 1114 | |
| 1122 | const res = try codegen.generateFunction( | 1115 | const res = try codegen.generateFunction( |
| 1123 | &self.base, | 1116 | &coff.base, |
| 1124 | pt, | 1117 | pt, |
| 1125 | zcu.navSrcLoc(func.owner_nav), | 1118 | zcu.navSrcLoc(func.owner_nav), |
| 1126 | func_index, | 1119 | func_index, |
| ... | @@ -1137,7 +1130,7 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, | ... | @@ -1137,7 +1130,7 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, |
| 1137 | }, | 1130 | }, |
| 1138 | }; | 1131 | }; |
| 1139 | | 1132 | |
| 1140 | try self.updateNavCode(pt, func.owner_nav, code, .FUNCTION); | 1133 | try coff.updateNavCode(pt, func.owner_nav, code, .FUNCTION); |
| 1141 | | 1134 | |
| 1142 | // Exports will be updated by `Zcu.processExports` after the update. | 1135 | // Exports will be updated by `Zcu.processExports` after the update. |
| 1143 | } | 1136 | } |
| ... | @@ -1148,7 +1141,7 @@ const LowerConstResult = union(enum) { | ... | @@ -1148,7 +1141,7 @@ const LowerConstResult = union(enum) { |
| 1148 | }; | 1141 | }; |
| 1149 | | 1142 | |
| 1150 | fn lowerConst( | 1143 | fn lowerConst( |
| 1151 | self: *Coff, | 1144 | coff: *Coff, |
| 1152 | pt: Zcu.PerThread, | 1145 | pt: Zcu.PerThread, |
| 1153 | name: []const u8, | 1146 | name: []const u8, |
| 1154 | val: Value, | 1147 | val: Value, |
| ... | @@ -1156,50 +1149,50 @@ fn lowerConst( | ... | @@ -1156,50 +1149,50 @@ fn lowerConst( |
| 1156 | sect_id: u16, | 1149 | sect_id: u16, |
| 1157 | src_loc: Zcu.LazySrcLoc, | 1150 | src_loc: Zcu.LazySrcLoc, |
| 1158 | ) !LowerConstResult { | 1151 | ) !LowerConstResult { |
| 1159 | const gpa = self.base.comp.gpa; | 1152 | const gpa = coff.base.comp.gpa; |
| 1160 | | 1153 | |
| 1161 | var code_buffer = std.ArrayList(u8).init(gpa); | 1154 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1162 | defer code_buffer.deinit(); | 1155 | defer code_buffer.deinit(); |
| 1163 | | 1156 | |
| 1164 | const atom_index = try self.createAtom(); | 1157 | const atom_index = try coff.createAtom(); |
| 1165 | const sym = self.getAtom(atom_index).getSymbolPtr(self); | 1158 | const sym = coff.getAtom(atom_index).getSymbolPtr(coff); |
| 1166 | try self.setSymbolName(sym, name); | 1159 | try coff.setSymbolName(sym, name); |
| 1167 | sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1)); | 1160 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_id + 1)); |
| 1168 | | 1161 | |
| 1169 | const res = try codegen.generateSymbol(&self.base, pt, src_loc, val, &code_buffer, .{ | 1162 | const res = try codegen.generateSymbol(&coff.base, pt, src_loc, val, &code_buffer, .{ |
| 1170 | .atom_index = self.getAtom(atom_index).getSymbolIndex().?, | 1163 | .atom_index = coff.getAtom(atom_index).getSymbolIndex().?, |
| 1171 | }); | 1164 | }); |
| 1172 | const code = switch (res) { | 1165 | const code = switch (res) { |
| 1173 | .ok => code_buffer.items, | 1166 | .ok => code_buffer.items, |
| 1174 | .fail => |em| return .{ .fail = em }, | 1167 | .fail => |em| return .{ .fail = em }, |
| 1175 | }; | 1168 | }; |
| 1176 | | 1169 | |
| 1177 | const atom = self.getAtomPtr(atom_index); | 1170 | const atom = coff.getAtomPtr(atom_index); |
| 1178 | atom.size = @as(u32, @intCast(code.len)); | 1171 | atom.size = @as(u32, @intCast(code.len)); |
| 1179 | atom.getSymbolPtr(self).value = try self.allocateAtom( | 1172 | atom.getSymbolPtr(coff).value = try coff.allocateAtom( |
| 1180 | atom_index, | 1173 | atom_index, |
| 1181 | atom.size, | 1174 | atom.size, |
| 1182 | @intCast(required_alignment.toByteUnits().?), | 1175 | @intCast(required_alignment.toByteUnits().?), |
| 1183 | ); | 1176 | ); |
| 1184 | errdefer self.freeAtom(atom_index); | 1177 | errdefer coff.freeAtom(atom_index); |
| 1185 | | 1178 | |
| 1186 | log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(self).value }); | 1179 | log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(coff).value }); |
| 1187 | log.debug(" (required alignment 0x{x})", .{required_alignment}); | 1180 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 1188 | | 1181 | |
| 1189 | try self.writeAtom(atom_index, code); | 1182 | try coff.writeAtom(atom_index, code); |
| 1190 | | 1183 | |
| 1191 | return .{ .ok = atom_index }; | 1184 | return .{ .ok = atom_index }; |
| 1192 | } | 1185 | } |
| 1193 | | 1186 | |
| 1194 | pub fn updateNav( | 1187 | pub fn updateNav( |
| 1195 | self: *Coff, | 1188 | coff: *Coff, |
| 1196 | pt: Zcu.PerThread, | 1189 | pt: Zcu.PerThread, |
| 1197 | nav_index: InternPool.Nav.Index, | 1190 | nav_index: InternPool.Nav.Index, |
| 1198 | ) link.File.UpdateNavError!void { | 1191 | ) link.File.UpdateNavError!void { |
| 1199 | if (build_options.skip_non_native and builtin.object_format != .coff) { | 1192 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1200 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1193 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1201 | } | 1194 | } |
| 1202 | if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index); | 1195 | if (coff.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index); |
| 1203 | const tracy = trace(@src()); | 1196 | const tracy = trace(@src()); |
| 1204 | defer tracy.end(); | 1197 | defer tracy.end(); |
| 1205 | | 1198 | |
| ... | @@ -1217,23 +1210,23 @@ pub fn updateNav( | ... | @@ -1217,23 +1210,23 @@ pub fn updateNav( |
| 1217 | // TODO make this part of getGlobalSymbol | 1210 | // TODO make this part of getGlobalSymbol |
| 1218 | const name = nav.name.toSlice(ip); | 1211 | const name = nav.name.toSlice(ip); |
| 1219 | const lib_name = @"extern".lib_name.toSlice(ip); | 1212 | const lib_name = @"extern".lib_name.toSlice(ip); |
| 1220 | const global_index = try self.getGlobalSymbol(name, lib_name); | 1213 | const global_index = try coff.getGlobalSymbol(name, lib_name); |
| 1221 | try self.need_got_table.put(gpa, global_index, {}); | 1214 | try coff.need_got_table.put(gpa, global_index, {}); |
| 1222 | return; | 1215 | return; |
| 1223 | }, | 1216 | }, |
| 1224 | else => nav_val, | 1217 | else => nav_val, |
| 1225 | }; | 1218 | }; |
| 1226 | | 1219 | |
| 1227 | if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) { | 1220 | if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) { |
| 1228 | const atom_index = try self.getOrCreateAtomForNav(nav_index); | 1221 | const atom_index = try coff.getOrCreateAtomForNav(nav_index); |
| 1229 | Atom.freeRelocations(self, atom_index); | 1222 | coff.freeRelocations(atom_index); |
| 1230 | const atom = self.getAtom(atom_index); | 1223 | const atom = coff.getAtom(atom_index); |
| 1231 | | 1224 | |
| 1232 | var code_buffer = std.ArrayList(u8).init(gpa); | 1225 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1233 | defer code_buffer.deinit(); | 1226 | defer code_buffer.deinit(); |
| 1234 | | 1227 | |
| 1235 | const res = try codegen.generateSymbol( | 1228 | const res = try codegen.generateSymbol( |
| 1236 | &self.base, | 1229 | &coff.base, |
| 1237 | pt, | 1230 | pt, |
| 1238 | zcu.navSrcLoc(nav_index), | 1231 | zcu.navSrcLoc(nav_index), |
| 1239 | nav_init, | 1232 | nav_init, |
| ... | @@ -1248,14 +1241,14 @@ pub fn updateNav( | ... | @@ -1248,14 +1241,14 @@ pub fn updateNav( |
| 1248 | }, | 1241 | }, |
| 1249 | }; | 1242 | }; |
| 1250 | | 1243 | |
| 1251 | try self.updateNavCode(pt, nav_index, code, .NULL); | 1244 | try coff.updateNavCode(pt, nav_index, code, .NULL); |
| 1252 | } | 1245 | } |
| 1253 | | 1246 | |
| 1254 | // Exports will be updated by `Zcu.processExports` after the update. | 1247 | // Exports will be updated by `Zcu.processExports` after the update. |
| 1255 | } | 1248 | } |
| 1256 | | 1249 | |
| 1257 | fn updateLazySymbolAtom( | 1250 | fn updateLazySymbolAtom( |
| 1258 | self: *Coff, | 1251 | coff: *Coff, |
| 1259 | pt: Zcu.PerThread, | 1252 | pt: Zcu.PerThread, |
| 1260 | sym: link.File.LazySymbol, | 1253 | sym: link.File.LazySymbol, |
| 1261 | atom_index: Atom.Index, | 1254 | atom_index: Atom.Index, |
| ... | @@ -1268,18 +1261,18 @@ fn updateLazySymbolAtom( | ... | @@ -1268,18 +1261,18 @@ fn updateLazySymbolAtom( |
| 1268 | var code_buffer = std.ArrayList(u8).init(gpa); | 1261 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1269 | defer code_buffer.deinit(); | 1262 | defer code_buffer.deinit(); |
| 1270 | | 1263 | |
| 1271 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ | 1264 | const name = try allocPrint(gpa, "__lazy_{s}_{}", .{ |
| 1272 | @tagName(sym.kind), | 1265 | @tagName(sym.kind), |
| 1273 | Type.fromInterned(sym.ty).fmt(pt), | 1266 | Type.fromInterned(sym.ty).fmt(pt), |
| 1274 | }); | 1267 | }); |
| 1275 | defer gpa.free(name); | 1268 | defer gpa.free(name); |
| 1276 | | 1269 | |
| 1277 | const atom = self.getAtomPtr(atom_index); | 1270 | const atom = coff.getAtomPtr(atom_index); |
| 1278 | const local_sym_index = atom.getSymbolIndex().?; | 1271 | const local_sym_index = atom.getSymbolIndex().?; |
| 1279 | | 1272 | |
| 1280 | const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded; | 1273 | const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded; |
| 1281 | const res = try codegen.generateLazySymbol( | 1274 | const res = try codegen.generateLazySymbol( |
| 1282 | &self.base, | 1275 | &coff.base, |
| 1283 | pt, | 1276 | pt, |
| 1284 | src, | 1277 | src, |
| 1285 | sym, | 1278 | sym, |
| ... | @@ -1297,13 +1290,13 @@ fn updateLazySymbolAtom( | ... | @@ -1297,13 +1290,13 @@ fn updateLazySymbolAtom( |
| 1297 | }; | 1290 | }; |
| 1298 | | 1291 | |
| 1299 | const code_len: u32 = @intCast(code.len); | 1292 | const code_len: u32 = @intCast(code.len); |
| 1300 | const symbol = atom.getSymbolPtr(self); | 1293 | const symbol = atom.getSymbolPtr(coff); |
| 1301 | try self.setSymbolName(symbol, name); | 1294 | try coff.setSymbolName(symbol, name); |
| 1302 | symbol.section_number = @enumFromInt(section_index + 1); | 1295 | symbol.section_number = @enumFromInt(section_index + 1); |
| 1303 | symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; | 1296 | symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; |
| 1304 | | 1297 | |
| 1305 | const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0)); | 1298 | const vaddr = try coff.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0)); |
| 1306 | errdefer self.freeAtom(atom_index); | 1299 | errdefer coff.freeAtom(atom_index); |
| 1307 | | 1300 | |
| 1308 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); | 1301 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); |
| 1309 | log.debug(" (required alignment 0x{x})", .{required_alignment}); | 1302 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| ... | @@ -1311,52 +1304,52 @@ fn updateLazySymbolAtom( | ... | @@ -1311,52 +1304,52 @@ fn updateLazySymbolAtom( |
| 1311 | atom.size = code_len; | 1304 | atom.size = code_len; |
| 1312 | symbol.value = vaddr; | 1305 | symbol.value = vaddr; |
| 1313 | | 1306 | |
| 1314 | try self.addGotEntry(.{ .sym_index = local_sym_index }); | 1307 | try coff.addGotEntry(.{ .sym_index = local_sym_index }); |
| 1315 | try self.writeAtom(atom_index, code); | 1308 | try coff.writeAtom(atom_index, code); |
| 1316 | } | 1309 | } |
| 1317 | | 1310 | |
| 1318 | pub fn getOrCreateAtomForLazySymbol( | 1311 | pub fn getOrCreateAtomForLazySymbol( |
| 1319 | self: *Coff, | 1312 | coff: *Coff, |
| 1320 | pt: Zcu.PerThread, | 1313 | pt: Zcu.PerThread, |
| 1321 | lazy_sym: link.File.LazySymbol, | 1314 | lazy_sym: link.File.LazySymbol, |
| 1322 | ) !Atom.Index { | 1315 | ) !Atom.Index { |
| 1323 | const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty); | 1316 | const gop = try coff.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty); |
| 1324 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); | 1317 | errdefer _ = if (!gop.found_existing) coff.lazy_syms.pop(); |
| 1325 | if (!gop.found_existing) gop.value_ptr.* = .{}; | 1318 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 1326 | const atom_ptr, const state_ptr = switch (lazy_sym.kind) { | 1319 | const atom_ptr, const state_ptr = switch (lazy_sym.kind) { |
| 1327 | .code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state }, | 1320 | .code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state }, |
| 1328 | .const_data => .{ &gop.value_ptr.rdata_atom, &gop.value_ptr.rdata_state }, | 1321 | .const_data => .{ &gop.value_ptr.rdata_atom, &gop.value_ptr.rdata_state }, |
| 1329 | }; | 1322 | }; |
| 1330 | switch (state_ptr.*) { | 1323 | switch (state_ptr.*) { |
| 1331 | .unused => atom_ptr.* = try self.createAtom(), | 1324 | .unused => atom_ptr.* = try coff.createAtom(), |
| 1332 | .pending_flush => return atom_ptr.*, | 1325 | .pending_flush => return atom_ptr.*, |
| 1333 | .flushed => {}, | 1326 | .flushed => {}, |
| 1334 | } | 1327 | } |
| 1335 | state_ptr.* = .pending_flush; | 1328 | state_ptr.* = .pending_flush; |
| 1336 | const atom = atom_ptr.*; | 1329 | const atom = atom_ptr.*; |
| 1337 | // anyerror needs to be deferred until flushModule | 1330 | // anyerror needs to be deferred until flushModule |
| 1338 | if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) { | 1331 | if (lazy_sym.ty != .anyerror_type) try coff.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) { |
| 1339 | .code => self.text_section_index.?, | 1332 | .code => coff.text_section_index.?, |
| 1340 | .const_data => self.rdata_section_index.?, | 1333 | .const_data => coff.rdata_section_index.?, |
| 1341 | }); | 1334 | }); |
| 1342 | return atom; | 1335 | return atom; |
| 1343 | } | 1336 | } |
| 1344 | | 1337 | |
| 1345 | pub fn getOrCreateAtomForNav(self: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index { | 1338 | pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index { |
| 1346 | const gpa = self.base.comp.gpa; | 1339 | const gpa = coff.base.comp.gpa; |
| 1347 | const gop = try self.navs.getOrPut(gpa, nav_index); | 1340 | const gop = try coff.navs.getOrPut(gpa, nav_index); |
| 1348 | if (!gop.found_existing) { | 1341 | if (!gop.found_existing) { |
| 1349 | gop.value_ptr.* = .{ | 1342 | gop.value_ptr.* = .{ |
| 1350 | .atom = try self.createAtom(), | 1343 | .atom = try coff.createAtom(), |
| 1351 | .section = self.getNavOutputSection(nav_index), | 1344 | .section = coff.getNavOutputSection(nav_index), |
| 1352 | .exports = .{}, | 1345 | .exports = .{}, |
| 1353 | }; | 1346 | }; |
| 1354 | } | 1347 | } |
| 1355 | return gop.value_ptr.atom; | 1348 | return gop.value_ptr.atom; |
| 1356 | } | 1349 | } |
| 1357 | | 1350 | |
| 1358 | fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 { | 1351 | fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 { |
| 1359 | const zcu = self.base.comp.zcu.?; | 1352 | const zcu = coff.base.comp.zcu.?; |
| 1360 | const ip = &zcu.intern_pool; | 1353 | const ip = &zcu.intern_pool; |
| 1361 | const nav = ip.getNav(nav_index); | 1354 | const nav = ip.getNav(nav_index); |
| 1362 | const ty = Type.fromInterned(nav.typeOf(ip)); | 1355 | const ty = Type.fromInterned(nav.typeOf(ip)); |
| ... | @@ -1365,17 +1358,17 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 { | ... | @@ -1365,17 +1358,17 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 { |
| 1365 | const index: u16 = blk: { | 1358 | const index: u16 = blk: { |
| 1366 | if (val.isUndefDeep(zcu)) { | 1359 | if (val.isUndefDeep(zcu)) { |
| 1367 | // TODO in release-fast and release-small, we should put undef in .bss | 1360 | // TODO in release-fast and release-small, we should put undef in .bss |
| 1368 | break :blk self.data_section_index.?; | 1361 | break :blk coff.data_section_index.?; |
| 1369 | } | 1362 | } |
| 1370 | | 1363 | |
| 1371 | switch (zig_ty) { | 1364 | switch (zig_ty) { |
| 1372 | // TODO: what if this is a function pointer? | 1365 | // TODO: what if this is a function pointer? |
| 1373 | .@"fn" => break :blk self.text_section_index.?, | 1366 | .@"fn" => break :blk coff.text_section_index.?, |
| 1374 | else => { | 1367 | else => { |
| 1375 | if (val.getVariable(zcu)) |_| { | 1368 | if (val.getVariable(zcu)) |_| { |
| 1376 | break :blk self.data_section_index.?; | 1369 | break :blk coff.data_section_index.?; |
| 1377 | } | 1370 | } |
| 1378 | break :blk self.rdata_section_index.?; | 1371 | break :blk coff.rdata_section_index.?; |
| 1379 | }, | 1372 | }, |
| 1380 | } | 1373 | } |
| 1381 | }; | 1374 | }; |
| ... | @@ -1383,11 +1376,11 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 { | ... | @@ -1383,11 +1376,11 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 { |
| 1383 | } | 1376 | } |
| 1384 | | 1377 | |
| 1385 | fn updateNavCode( | 1378 | fn updateNavCode( |
| 1386 | self: *Coff, | 1379 | coff: *Coff, |
| 1387 | pt: Zcu.PerThread, | 1380 | pt: Zcu.PerThread, |
| 1388 | nav_index: InternPool.Nav.Index, | 1381 | nav_index: InternPool.Nav.Index, |
| 1389 | code: []u8, | 1382 | code: []u8, |
| 1390 | complex_type: coff.ComplexType, | 1383 | complex_type: coff_util.ComplexType, |
| 1391 | ) !void { | 1384 | ) !void { |
| 1392 | const zcu = pt.zcu; | 1385 | const zcu = pt.zcu; |
| 1393 | const ip = &zcu.intern_pool; | 1386 | const ip = &zcu.intern_pool; |
| ... | @@ -1399,70 +1392,70 @@ fn updateNavCode( | ... | @@ -1399,70 +1392,70 @@ fn updateNavCode( |
| 1399 | target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result), | 1392 | target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result), |
| 1400 | ); | 1393 | ); |
| 1401 | | 1394 | |
| 1402 | const nav_metadata = self.navs.get(nav_index).?; | 1395 | const nav_metadata = coff.navs.get(nav_index).?; |
| 1403 | const atom_index = nav_metadata.atom; | 1396 | const atom_index = nav_metadata.atom; |
| 1404 | const atom = self.getAtom(atom_index); | 1397 | const atom = coff.getAtom(atom_index); |
| 1405 | const sym_index = atom.getSymbolIndex().?; | 1398 | const sym_index = atom.getSymbolIndex().?; |
| 1406 | const sect_index = nav_metadata.section; | 1399 | const sect_index = nav_metadata.section; |
| 1407 | const code_len = @as(u32, @intCast(code.len)); | 1400 | const code_len = @as(u32, @intCast(code.len)); |
| 1408 | | 1401 | |
| 1409 | if (atom.size != 0) { | 1402 | if (atom.size != 0) { |
| 1410 | const sym = atom.getSymbolPtr(self); | 1403 | const sym = atom.getSymbolPtr(coff); |
| 1411 | try self.setSymbolName(sym, nav.fqn.toSlice(ip)); | 1404 | try coff.setSymbolName(sym, nav.fqn.toSlice(ip)); |
| 1412 | sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1)); | 1405 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_index + 1)); |
| 1413 | sym.type = .{ .complex_type = complex_type, .base_type = .NULL }; | 1406 | sym.type = .{ .complex_type = complex_type, .base_type = .NULL }; |
| 1414 | | 1407 | |
| 1415 | const capacity = atom.capacity(self); | 1408 | const capacity = atom.capacity(coff); |
| 1416 | const need_realloc = code.len > capacity or !required_alignment.check(sym.value); | 1409 | const need_realloc = code.len > capacity or !required_alignment.check(sym.value); |
| 1417 | if (need_realloc) { | 1410 | if (need_realloc) { |
| 1418 | const vaddr = try self.growAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0)); | 1411 | const vaddr = try coff.growAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0)); |
| 1419 | log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr }); | 1412 | log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr }); |
| 1420 | log.debug(" (required alignment 0x{x}", .{required_alignment}); | 1413 | log.debug(" (required alignment 0x{x}", .{required_alignment}); |
| 1421 | | 1414 | |
| 1422 | if (vaddr != sym.value) { | 1415 | if (vaddr != sym.value) { |
| 1423 | sym.value = vaddr; | 1416 | sym.value = vaddr; |
| 1424 | log.debug(" (updating GOT entry)", .{}); | 1417 | log.debug(" (updating GOT entry)", .{}); |
| 1425 | const got_entry_index = self.got_table.lookup.get(.{ .sym_index = sym_index }).?; | 1418 | const got_entry_index = coff.got_table.lookup.get(.{ .sym_index = sym_index }).?; |
| 1426 | try self.writeOffsetTableEntry(got_entry_index); | 1419 | try coff.writeOffsetTableEntry(got_entry_index); |
| 1427 | self.markRelocsDirtyByTarget(.{ .sym_index = sym_index }); | 1420 | coff.markRelocsDirtyByTarget(.{ .sym_index = sym_index }); |
| 1428 | } | 1421 | } |
| 1429 | } else if (code_len < atom.size) { | 1422 | } else if (code_len < atom.size) { |
| 1430 | self.shrinkAtom(atom_index, code_len); | 1423 | coff.shrinkAtom(atom_index, code_len); |
| 1431 | } | 1424 | } |
| 1432 | self.getAtomPtr(atom_index).size = code_len; | 1425 | coff.getAtomPtr(atom_index).size = code_len; |
| 1433 | } else { | 1426 | } else { |
| 1434 | const sym = atom.getSymbolPtr(self); | 1427 | const sym = atom.getSymbolPtr(coff); |
| 1435 | try self.setSymbolName(sym, nav.fqn.toSlice(ip)); | 1428 | try coff.setSymbolName(sym, nav.fqn.toSlice(ip)); |
| 1436 | sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1)); | 1429 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_index + 1)); |
| 1437 | sym.type = .{ .complex_type = complex_type, .base_type = .NULL }; | 1430 | sym.type = .{ .complex_type = complex_type, .base_type = .NULL }; |
| 1438 | | 1431 | |
| 1439 | const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0)); | 1432 | const vaddr = try coff.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0)); |
| 1440 | errdefer self.freeAtom(atom_index); | 1433 | errdefer coff.freeAtom(atom_index); |
| 1441 | log.debug("allocated atom for {} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr }); | 1434 | log.debug("allocated atom for {} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr }); |
| 1442 | self.getAtomPtr(atom_index).size = code_len; | 1435 | coff.getAtomPtr(atom_index).size = code_len; |
| 1443 | sym.value = vaddr; | 1436 | sym.value = vaddr; |
| 1444 | | 1437 | |
| 1445 | try self.addGotEntry(.{ .sym_index = sym_index }); | 1438 | try coff.addGotEntry(.{ .sym_index = sym_index }); |
| 1446 | } | 1439 | } |
| 1447 | | 1440 | |
| 1448 | try self.writeAtom(atom_index, code); | 1441 | try coff.writeAtom(atom_index, code); |
| 1449 | } | 1442 | } |
| 1450 | | 1443 | |
| 1451 | pub fn freeNav(self: *Coff, nav_index: InternPool.NavIndex) void { | 1444 | pub fn freeNav(coff: *Coff, nav_index: InternPool.NavIndex) void { |
| 1452 | if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index); | 1445 | if (coff.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index); |
| 1453 | | 1446 | |
| 1454 | const gpa = self.base.comp.gpa; | 1447 | const gpa = coff.base.comp.gpa; |
| 1455 | log.debug("freeDecl 0x{x}", .{nav_index}); | 1448 | log.debug("freeDecl 0x{x}", .{nav_index}); |
| 1456 | | 1449 | |
| 1457 | if (self.decls.fetchOrderedRemove(nav_index)) |const_kv| { | 1450 | if (coff.decls.fetchOrderedRemove(nav_index)) |const_kv| { |
| 1458 | var kv = const_kv; | 1451 | var kv = const_kv; |
| 1459 | self.freeAtom(kv.value.atom); | 1452 | coff.freeAtom(kv.value.atom); |
| 1460 | kv.value.exports.deinit(gpa); | 1453 | kv.value.exports.deinit(gpa); |
| 1461 | } | 1454 | } |
| 1462 | } | 1455 | } |
| 1463 | | 1456 | |
| 1464 | pub fn updateExports( | 1457 | pub fn updateExports( |
| 1465 | self: *Coff, | 1458 | coff: *Coff, |
| 1466 | pt: Zcu.PerThread, | 1459 | pt: Zcu.PerThread, |
| 1467 | exported: Zcu.Exported, | 1460 | exported: Zcu.Exported, |
| 1468 | export_indices: []const u32, | 1461 | export_indices: []const u32, |
| ... | @@ -1473,7 +1466,7 @@ pub fn updateExports( | ... | @@ -1473,7 +1466,7 @@ pub fn updateExports( |
| 1473 | | 1466 | |
| 1474 | const zcu = pt.zcu; | 1467 | const zcu = pt.zcu; |
| 1475 | const ip = &zcu.intern_pool; | 1468 | const ip = &zcu.intern_pool; |
| 1476 | const comp = self.base.comp; | 1469 | const comp = coff.base.comp; |
| 1477 | const target = comp.root_mod.resolved_target.result; | 1470 | const target = comp.root_mod.resolved_target.result; |
| 1478 | | 1471 | |
| 1479 | if (comp.config.use_llvm) { | 1472 | if (comp.config.use_llvm) { |
| ... | @@ -1513,18 +1506,18 @@ pub fn updateExports( | ... | @@ -1513,18 +1506,18 @@ pub fn updateExports( |
| 1513 | } | 1506 | } |
| 1514 | } | 1507 | } |
| 1515 | | 1508 | |
| 1516 | if (self.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); | 1509 | if (coff.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); |
| 1517 | | 1510 | |
| 1518 | const gpa = comp.gpa; | 1511 | const gpa = comp.gpa; |
| 1519 | | 1512 | |
| 1520 | const metadata = switch (exported) { | 1513 | const metadata = switch (exported) { |
| 1521 | .nav => |nav| blk: { | 1514 | .nav => |nav| blk: { |
| 1522 | _ = try self.getOrCreateAtomForNav(nav); | 1515 | _ = try coff.getOrCreateAtomForNav(nav); |
| 1523 | break :blk self.navs.getPtr(nav).?; | 1516 | break :blk coff.navs.getPtr(nav).?; |
| 1524 | }, | 1517 | }, |
| 1525 | .uav => |uav| self.uavs.getPtr(uav) orelse blk: { | 1518 | .uav => |uav| coff.uavs.getPtr(uav) orelse blk: { |
| 1526 | const first_exp = zcu.all_exports.items[export_indices[0]]; | 1519 | const first_exp = zcu.all_exports.items[export_indices[0]]; |
| 1527 | const res = try self.lowerUav(pt, uav, .none, first_exp.src); | 1520 | const res = try coff.lowerUav(pt, uav, .none, first_exp.src); |
| 1528 | switch (res) { | 1521 | switch (res) { |
| 1529 | .mcv => {}, | 1522 | .mcv => {}, |
| 1530 | .fail => |em| { | 1523 | .fail => |em| { |
| ... | @@ -1535,11 +1528,11 @@ pub fn updateExports( | ... | @@ -1535,11 +1528,11 @@ pub fn updateExports( |
| 1535 | return; | 1528 | return; |
| 1536 | }, | 1529 | }, |
| 1537 | } | 1530 | } |
| 1538 | break :blk self.uavs.getPtr(uav).?; | 1531 | break :blk coff.uavs.getPtr(uav).?; |
| 1539 | }, | 1532 | }, |
| 1540 | }; | 1533 | }; |
| 1541 | const atom_index = metadata.atom; | 1534 | const atom_index = metadata.atom; |
| 1542 | const atom = self.getAtom(atom_index); | 1535 | const atom = coff.getAtom(atom_index); |
| 1543 | | 1536 | |
| 1544 | for (export_indices) |export_idx| { | 1537 | for (export_indices) |export_idx| { |
| 1545 | const exp = zcu.all_exports.items[export_idx]; | 1538 | const exp = zcu.all_exports.items[export_idx]; |
| ... | @@ -1568,27 +1561,27 @@ pub fn updateExports( | ... | @@ -1568,27 +1561,27 @@ pub fn updateExports( |
| 1568 | } | 1561 | } |
| 1569 | | 1562 | |
| 1570 | const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); | 1563 | const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); |
| 1571 | const sym_index = metadata.getExport(self, exp_name) orelse blk: { | 1564 | const sym_index = metadata.getExport(coff, exp_name) orelse blk: { |
| 1572 | const sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: { | 1565 | const sym_index = if (coff.getGlobalIndex(exp_name)) |global_index| ind: { |
| 1573 | const global = self.globals.items[global_index]; | 1566 | const global = coff.globals.items[global_index]; |
| 1574 | // TODO this is just plain wrong as it all should happen in a single `resolveSymbols` | 1567 | // TODO this is just plain wrong as it all should happen in a single `resolveSymbols` |
| 1575 | // pass. This will go away once we abstact away Zig's incremental compilation into | 1568 | // pass. This will go away once we abstact away Zig's incremental compilation into |
| 1576 | // its own module. | 1569 | // its own module. |
| 1577 | if (global.file == null and self.getSymbol(global).section_number == .UNDEFINED) { | 1570 | if (global.file == null and coff.getSymbol(global).section_number == .UNDEFINED) { |
| 1578 | _ = self.unresolved.swapRemove(global_index); | 1571 | _ = coff.unresolved.swapRemove(global_index); |
| 1579 | break :ind global.sym_index; | 1572 | break :ind global.sym_index; |
| 1580 | } | 1573 | } |
| 1581 | break :ind try self.allocateSymbol(); | 1574 | break :ind try coff.allocateSymbol(); |
| 1582 | } else try self.allocateSymbol(); | 1575 | } else try coff.allocateSymbol(); |
| 1583 | try metadata.exports.append(gpa, sym_index); | 1576 | try metadata.exports.append(gpa, sym_index); |
| 1584 | break :blk sym_index; | 1577 | break :blk sym_index; |
| 1585 | }; | 1578 | }; |
| 1586 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; | 1579 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1587 | const sym = self.getSymbolPtr(sym_loc); | 1580 | const sym = coff.getSymbolPtr(sym_loc); |
| 1588 | try self.setSymbolName(sym, exp_name); | 1581 | try coff.setSymbolName(sym, exp_name); |
| 1589 | sym.value = atom.getSymbol(self).value; | 1582 | sym.value = atom.getSymbol(coff).value; |
| 1590 | sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1)); | 1583 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1)); |
| 1591 | sym.type = atom.getSymbol(self).type; | 1584 | sym.type = atom.getSymbol(coff).type; |
| 1592 | | 1585 | |
| 1593 | switch (exp.opts.linkage) { | 1586 | switch (exp.opts.linkage) { |
| 1594 | .strong => { | 1587 | .strong => { |
| ... | @@ -1599,27 +1592,27 @@ pub fn updateExports( | ... | @@ -1599,27 +1592,27 @@ pub fn updateExports( |
| 1599 | else => unreachable, | 1592 | else => unreachable, |
| 1600 | } | 1593 | } |
| 1601 | | 1594 | |
| 1602 | try self.resolveGlobalSymbol(sym_loc); | 1595 | try coff.resolveGlobalSymbol(sym_loc); |
| 1603 | } | 1596 | } |
| 1604 | } | 1597 | } |
| 1605 | | 1598 | |
| 1606 | pub fn deleteExport( | 1599 | pub fn deleteExport( |
| 1607 | self: *Coff, | 1600 | coff: *Coff, |
| 1608 | exported: Zcu.Exported, | 1601 | exported: Zcu.Exported, |
| 1609 | name: InternPool.NullTerminatedString, | 1602 | name: InternPool.NullTerminatedString, |
| 1610 | ) void { | 1603 | ) void { |
| 1611 | if (self.llvm_object) |_| return; | 1604 | if (coff.llvm_object) |_| return; |
| 1612 | const metadata = switch (exported) { | 1605 | const metadata = switch (exported) { |
| 1613 | .nav => |nav| self.navs.getPtr(nav), | 1606 | .nav => |nav| coff.navs.getPtr(nav), |
| 1614 | .uav => |uav| self.uavs.getPtr(uav), | 1607 | .uav => |uav| coff.uavs.getPtr(uav), |
| 1615 | } orelse return; | 1608 | } orelse return; |
| 1616 | const zcu = self.base.comp.zcu.?; | 1609 | const zcu = coff.base.comp.zcu.?; |
| 1617 | const name_slice = name.toSlice(&zcu.intern_pool); | 1610 | const name_slice = name.toSlice(&zcu.intern_pool); |
| 1618 | const sym_index = metadata.getExportPtr(self, name_slice) orelse return; | 1611 | const sym_index = metadata.getExportPtr(coff, name_slice) orelse return; |
| 1619 | | 1612 | |
| 1620 | const gpa = self.base.comp.gpa; | 1613 | const gpa = coff.base.comp.gpa; |
| 1621 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null }; | 1614 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null }; |
| 1622 | const sym = self.getSymbolPtr(sym_loc); | 1615 | const sym = coff.getSymbolPtr(sym_loc); |
| 1623 | log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)}); | 1616 | log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)}); |
| 1624 | assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED); | 1617 | assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED); |
| 1625 | sym.* = .{ | 1618 | sym.* = .{ |
| ... | @@ -1630,12 +1623,12 @@ pub fn deleteExport( | ... | @@ -1630,12 +1623,12 @@ pub fn deleteExport( |
| 1630 | .storage_class = .NULL, | 1623 | .storage_class = .NULL, |
| 1631 | .number_of_aux_symbols = 0, | 1624 | .number_of_aux_symbols = 0, |
| 1632 | }; | 1625 | }; |
| 1633 | self.locals_free_list.append(gpa, sym_index.*) catch {}; | 1626 | coff.locals_free_list.append(gpa, sym_index.*) catch {}; |
| 1634 | | 1627 | |
| 1635 | if (self.resolver.fetchRemove(name_slice)) |entry| { | 1628 | if (coff.resolver.fetchRemove(name_slice)) |entry| { |
| 1636 | defer gpa.free(entry.key); | 1629 | defer gpa.free(entry.key); |
| 1637 | self.globals_free_list.append(gpa, entry.value) catch {}; | 1630 | coff.globals_free_list.append(gpa, entry.value) catch {}; |
| 1638 | self.globals.items[entry.value] = .{ | 1631 | coff.globals.items[entry.value] = .{ |
| 1639 | .sym_index = 0, | 1632 | .sym_index = 0, |
| 1640 | .file = null, | 1633 | .file = null, |
| 1641 | }; | 1634 | }; |
| ... | @@ -1644,16 +1637,16 @@ pub fn deleteExport( | ... | @@ -1644,16 +1637,16 @@ pub fn deleteExport( |
| 1644 | sym_index.* = 0; | 1637 | sym_index.* = 0; |
| 1645 | } | 1638 | } |
| 1646 | | 1639 | |
| 1647 | fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { | 1640 | fn resolveGlobalSymbol(coff: *Coff, current: SymbolWithLoc) !void { |
| 1648 | const gpa = self.base.comp.gpa; | 1641 | const gpa = coff.base.comp.gpa; |
| 1649 | const sym = self.getSymbol(current); | 1642 | const sym = coff.getSymbol(current); |
| 1650 | const sym_name = self.getSymbolName(current); | 1643 | const sym_name = coff.getSymbolName(current); |
| 1651 | | 1644 | |
| 1652 | const gop = try self.getOrPutGlobalPtr(sym_name); | 1645 | const gop = try coff.getOrPutGlobalPtr(sym_name); |
| 1653 | if (!gop.found_existing) { | 1646 | if (!gop.found_existing) { |
| 1654 | gop.value_ptr.* = current; | 1647 | gop.value_ptr.* = current; |
| 1655 | if (sym.section_number == .UNDEFINED) { | 1648 | if (sym.section_number == .UNDEFINED) { |
| 1656 | try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, false); | 1649 | try coff.unresolved.putNoClobber(gpa, coff.getGlobalIndex(sym_name).?, false); |
| 1657 | } | 1650 | } |
| 1658 | return; | 1651 | return; |
| 1659 | } | 1652 | } |
| ... | @@ -1662,33 +1655,560 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { | ... | @@ -1662,33 +1655,560 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { |
| 1662 | | 1655 | |
| 1663 | if (sym.section_number == .UNDEFINED) return; | 1656 | if (sym.section_number == .UNDEFINED) return; |
| 1664 | | 1657 | |
| 1665 | _ = self.unresolved.swapRemove(self.getGlobalIndex(sym_name).?); | 1658 | _ = coff.unresolved.swapRemove(coff.getGlobalIndex(sym_name).?); |
| 1666 | | 1659 | |
| 1667 | gop.value_ptr.* = current; | 1660 | gop.value_ptr.* = current; |
| 1668 | } | 1661 | } |
| 1669 | | 1662 | |
| 1670 | pub fn flush(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { | 1663 | pub fn flush(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 1671 | const comp = self.base.comp; | 1664 | const comp = coff.base.comp; |
| 1672 | const use_lld = build_options.have_llvm and comp.config.use_lld; | 1665 | const use_lld = build_options.have_llvm and comp.config.use_lld; |
| 1673 | if (use_lld) { | 1666 | if (use_lld) { |
| 1674 | return lld.linkWithLLD(self, arena, tid, prog_node); | 1667 | return coff.linkWithLLD(arena, tid, prog_node); |
| 1675 | } | 1668 | } |
| 1676 | switch (comp.config.output_mode) { | 1669 | switch (comp.config.output_mode) { |
| 1677 | .Exe, .Obj => return self.flushModule(arena, tid, prog_node), | 1670 | .Exe, .Obj => return coff.flushModule(arena, tid, prog_node), |
| 1678 | .Lib => return error.TODOImplementWritingLibFiles, | 1671 | .Lib => return error.TODOImplementWritingLibFiles, |
| 1679 | } | 1672 | } |
| 1680 | } | 1673 | } |
| 1681 | | 1674 | |
| 1682 | pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { | 1675 | fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { |
| | 1676 | dev.check(.lld_linker); |
| | 1677 | |
| 1683 | const tracy = trace(@src()); | 1678 | const tracy = trace(@src()); |
| 1684 | defer tracy.end(); | 1679 | defer tracy.end(); |
| 1685 | | 1680 | |
| 1686 | const comp = self.base.comp; | 1681 | const comp = coff.base.comp; |
| | 1682 | const gpa = comp.gpa; |
| | 1683 | |
| | 1684 | const directory = coff.base.emit.root_dir; // Just an alias to make it shorter to type. |
| | 1685 | const full_out_path = try directory.join(arena, &[_][]const u8{coff.base.emit.sub_path}); |
| | 1686 | |
| | 1687 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| | 1688 | // will not be part of the linker line anyway. |
| | 1689 | const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: { |
| | 1690 | try coff.flushModule(arena, tid, prog_node); |
| | 1691 | |
| | 1692 | if (fs.path.dirname(full_out_path)) |dirname| { |
| | 1693 | break :blk try fs.path.join(arena, &.{ dirname, coff.base.zcu_object_sub_path.? }); |
| | 1694 | } else { |
| | 1695 | break :blk coff.base.zcu_object_sub_path.?; |
| | 1696 | } |
| | 1697 | } else null; |
| | 1698 | |
| | 1699 | const sub_prog_node = prog_node.start("LLD Link", 0); |
| | 1700 | defer sub_prog_node.end(); |
| | 1701 | |
| | 1702 | const is_lib = comp.config.output_mode == .Lib; |
| | 1703 | const is_dyn_lib = comp.config.link_mode == .dynamic and is_lib; |
| | 1704 | const is_exe_or_dyn_lib = is_dyn_lib or comp.config.output_mode == .Exe; |
| | 1705 | const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib; |
| | 1706 | const target = comp.root_mod.resolved_target.result; |
| | 1707 | const optimize_mode = comp.root_mod.optimize_mode; |
| | 1708 | const entry_name: ?[]const u8 = switch (coff.entry) { |
| | 1709 | // This logic isn't quite right for disabled or enabled. No point in fixing it |
| | 1710 | // when the goal is to eliminate dependency on LLD anyway. |
| | 1711 | // https://github.com/ziglang/zig/issues/17751 |
| | 1712 | .disabled, .default, .enabled => null, |
| | 1713 | .named => |name| name, |
| | 1714 | }; |
| | 1715 | |
| | 1716 | // See link/Elf.zig for comments on how this mechanism works. |
| | 1717 | const id_symlink_basename = "lld.id"; |
| | 1718 | |
| | 1719 | var man: Cache.Manifest = undefined; |
| | 1720 | defer if (!coff.base.disable_lld_caching) man.deinit(); |
| | 1721 | |
| | 1722 | var digest: [Cache.hex_digest_len]u8 = undefined; |
| | 1723 | |
| | 1724 | if (!coff.base.disable_lld_caching) { |
| | 1725 | man = comp.cache_parent.obtain(); |
| | 1726 | coff.base.releaseLock(); |
| | 1727 | |
| | 1728 | comptime assert(Compilation.link_hash_implementation_version == 14); |
| | 1729 | |
| | 1730 | try link.hashInputs(&man, comp.link_inputs); |
| | 1731 | for (comp.c_object_table.keys()) |key| { |
| | 1732 | _ = try man.addFilePath(key.status.success.object_path, null); |
| | 1733 | } |
| | 1734 | for (comp.win32_resource_table.keys()) |key| { |
| | 1735 | _ = try man.addFile(key.status.success.res_path, null); |
| | 1736 | } |
| | 1737 | try man.addOptionalFile(module_obj_path); |
| | 1738 | man.hash.addOptionalBytes(entry_name); |
| | 1739 | man.hash.add(coff.base.stack_size); |
| | 1740 | man.hash.add(coff.image_base); |
| | 1741 | { |
| | 1742 | // TODO remove this, libraries must instead be resolved by the frontend. |
| | 1743 | for (coff.lib_directories) |lib_directory| man.hash.addOptionalBytes(lib_directory.path); |
| | 1744 | } |
| | 1745 | man.hash.add(comp.skip_linker_dependencies); |
| | 1746 | if (comp.config.link_libc) { |
| | 1747 | man.hash.add(comp.libc_installation != null); |
| | 1748 | if (comp.libc_installation) |libc_installation| { |
| | 1749 | man.hash.addBytes(libc_installation.crt_dir.?); |
| | 1750 | if (target.abi == .msvc or target.abi == .itanium) { |
| | 1751 | man.hash.addBytes(libc_installation.msvc_lib_dir.?); |
| | 1752 | man.hash.addBytes(libc_installation.kernel32_lib_dir.?); |
| | 1753 | } |
| | 1754 | } |
| | 1755 | } |
| | 1756 | man.hash.addListOfBytes(comp.windows_libs.keys()); |
| | 1757 | man.hash.addListOfBytes(comp.force_undefined_symbols.keys()); |
| | 1758 | man.hash.addOptional(coff.subsystem); |
| | 1759 | man.hash.add(comp.config.is_test); |
| | 1760 | man.hash.add(coff.tsaware); |
| | 1761 | man.hash.add(coff.nxcompat); |
| | 1762 | man.hash.add(coff.dynamicbase); |
| | 1763 | man.hash.add(coff.base.allow_shlib_undefined); |
| | 1764 | // strip does not need to go into the linker hash because it is part of the hash namespace |
| | 1765 | man.hash.add(coff.major_subsystem_version); |
| | 1766 | man.hash.add(coff.minor_subsystem_version); |
| | 1767 | man.hash.add(coff.repro); |
| | 1768 | man.hash.addOptional(comp.version); |
| | 1769 | try man.addOptionalFile(coff.module_definition_file); |
| | 1770 | |
| | 1771 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. |
| | 1772 | _ = try man.hit(); |
| | 1773 | digest = man.final(); |
| | 1774 | var prev_digest_buf: [digest.len]u8 = undefined; |
| | 1775 | const prev_digest: []u8 = Cache.readSmallFile( |
| | 1776 | directory.handle, |
| | 1777 | id_symlink_basename, |
| | 1778 | &prev_digest_buf, |
| | 1779 | ) catch |err| blk: { |
| | 1780 | log.debug("COFF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); |
| | 1781 | // Handle this as a cache miss. |
| | 1782 | break :blk prev_digest_buf[0..0]; |
| | 1783 | }; |
| | 1784 | if (mem.eql(u8, prev_digest, &digest)) { |
| | 1785 | log.debug("COFF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); |
| | 1786 | // Hot diggity dog! The output binary is already there. |
| | 1787 | coff.base.lock = man.toOwnedLock(); |
| | 1788 | return; |
| | 1789 | } |
| | 1790 | log.debug("COFF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); |
| | 1791 | |
| | 1792 | // We are about to change the output file to be different, so we invalidate the build hash now. |
| | 1793 | directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { |
| | 1794 | error.FileNotFound => {}, |
| | 1795 | else => |e| return e, |
| | 1796 | }; |
| | 1797 | } |
| | 1798 | |
| | 1799 | if (comp.config.output_mode == .Obj) { |
| | 1800 | // LLD's COFF driver does not support the equivalent of `-r` so we do a simple file copy |
| | 1801 | // here. TODO: think carefully about how we can avoid this redundant operation when doing |
| | 1802 | // build-obj. See also the corresponding TODO in linkAsArchive. |
| | 1803 | const the_object_path = blk: { |
| | 1804 | if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; |
| | 1805 | |
| | 1806 | if (comp.c_object_table.count() != 0) |
| | 1807 | break :blk comp.c_object_table.keys()[0].status.success.object_path; |
| | 1808 | |
| | 1809 | if (module_obj_path) |p| |
| | 1810 | break :blk Path.initCwd(p); |
| | 1811 | |
| | 1812 | // TODO I think this is unreachable. Audit this situation when solving the above TODO |
| | 1813 | // regarding eliding redundant object -> object transformations. |
| | 1814 | return error.NoObjectsToLink; |
| | 1815 | }; |
| | 1816 | try std.fs.Dir.copyFile( |
| | 1817 | the_object_path.root_dir.handle, |
| | 1818 | the_object_path.sub_path, |
| | 1819 | directory.handle, |
| | 1820 | coff.base.emit.sub_path, |
| | 1821 | .{}, |
| | 1822 | ); |
| | 1823 | } else { |
| | 1824 | // Create an LLD command line and invoke it. |
| | 1825 | var argv = std.ArrayList([]const u8).init(gpa); |
| | 1826 | defer argv.deinit(); |
| | 1827 | // We will invoke ourselves as a child process to gain access to LLD. |
| | 1828 | // This is necessary because LLD does not behave properly as a library - |
| | 1829 | // it calls exit() and does not reset all global data between invocations. |
| | 1830 | const linker_command = "lld-link"; |
| | 1831 | try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); |
| | 1832 | |
| | 1833 | try argv.append("-ERRORLIMIT:0"); |
| | 1834 | try argv.append("-NOLOGO"); |
| | 1835 | if (comp.config.debug_format != .strip) { |
| | 1836 | try argv.append("-DEBUG"); |
| | 1837 | |
| | 1838 | const out_ext = std.fs.path.extension(full_out_path); |
| | 1839 | const out_pdb = coff.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{ |
| | 1840 | full_out_path[0 .. full_out_path.len - out_ext.len], |
| | 1841 | }); |
| | 1842 | const out_pdb_basename = std.fs.path.basename(out_pdb); |
| | 1843 | |
| | 1844 | try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); |
| | 1845 | try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb_basename})); |
| | 1846 | } |
| | 1847 | if (comp.version) |version| { |
| | 1848 | try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); |
| | 1849 | } |
| | 1850 | if (comp.config.lto) { |
| | 1851 | switch (optimize_mode) { |
| | 1852 | .Debug => {}, |
| | 1853 | .ReleaseSmall => try argv.append("-OPT:lldlto=2"), |
| | 1854 | .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"), |
| | 1855 | } |
| | 1856 | } |
| | 1857 | if (comp.config.output_mode == .Exe) { |
| | 1858 | try argv.append(try allocPrint(arena, "-STACK:{d}", .{coff.base.stack_size})); |
| | 1859 | } |
| | 1860 | try argv.append(try allocPrint(arena, "-BASE:{d}", .{coff.image_base})); |
| | 1861 | |
| | 1862 | if (target.cpu.arch == .x86) { |
| | 1863 | try argv.append("-MACHINE:X86"); |
| | 1864 | } else if (target.cpu.arch == .x86_64) { |
| | 1865 | try argv.append("-MACHINE:X64"); |
| | 1866 | } else if (target.cpu.arch.isARM()) { |
| | 1867 | if (target.ptrBitWidth() == 32) { |
| | 1868 | try argv.append("-MACHINE:ARM"); |
| | 1869 | } else { |
| | 1870 | try argv.append("-MACHINE:ARM64"); |
| | 1871 | } |
| | 1872 | } |
| | 1873 | |
| | 1874 | for (comp.force_undefined_symbols.keys()) |symbol| { |
| | 1875 | try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol})); |
| | 1876 | } |
| | 1877 | |
| | 1878 | if (is_dyn_lib) { |
| | 1879 | try argv.append("-DLL"); |
| | 1880 | } |
| | 1881 | |
| | 1882 | if (entry_name) |name| { |
| | 1883 | try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{name})); |
| | 1884 | } |
| | 1885 | |
| | 1886 | if (coff.repro) { |
| | 1887 | try argv.append("-BREPRO"); |
| | 1888 | } |
| | 1889 | |
| | 1890 | if (coff.tsaware) { |
| | 1891 | try argv.append("-tsaware"); |
| | 1892 | } |
| | 1893 | if (coff.nxcompat) { |
| | 1894 | try argv.append("-nxcompat"); |
| | 1895 | } |
| | 1896 | if (!coff.dynamicbase) { |
| | 1897 | try argv.append("-dynamicbase:NO"); |
| | 1898 | } |
| | 1899 | if (coff.base.allow_shlib_undefined) { |
| | 1900 | try argv.append("-FORCE:UNRESOLVED"); |
| | 1901 | } |
| | 1902 | |
| | 1903 | try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path})); |
| | 1904 | |
| | 1905 | if (comp.implib_emit) |emit| { |
| | 1906 | const implib_out_path = try emit.root_dir.join(arena, &[_][]const u8{emit.sub_path}); |
| | 1907 | try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path})); |
| | 1908 | } |
| | 1909 | |
| | 1910 | if (comp.config.link_libc) { |
| | 1911 | if (comp.libc_installation) |libc_installation| { |
| | 1912 | try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?})); |
| | 1913 | |
| | 1914 | if (target.abi == .msvc or target.abi == .itanium) { |
| | 1915 | try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.msvc_lib_dir.?})); |
| | 1916 | try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.kernel32_lib_dir.?})); |
| | 1917 | } |
| | 1918 | } |
| | 1919 | } |
| | 1920 | |
| | 1921 | for (coff.lib_directories) |lib_directory| { |
| | 1922 | try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_directory.path orelse "."})); |
| | 1923 | } |
| | 1924 | |
| | 1925 | try argv.ensureUnusedCapacity(comp.link_inputs.len); |
| | 1926 | for (comp.link_inputs) |link_input| switch (link_input) { |
| | 1927 | .dso_exact => unreachable, // not applicable to PE/COFF |
| | 1928 | inline .dso, .res => |x| { |
| | 1929 | argv.appendAssumeCapacity(try x.path.toString(arena)); |
| | 1930 | }, |
| | 1931 | .object, .archive => |obj| { |
| | 1932 | if (obj.must_link) { |
| | 1933 | argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{}", .{@as(Path, obj.path)})); |
| | 1934 | } else { |
| | 1935 | argv.appendAssumeCapacity(try obj.path.toString(arena)); |
| | 1936 | } |
| | 1937 | }, |
| | 1938 | }; |
| | 1939 | |
| | 1940 | for (comp.c_object_table.keys()) |key| { |
| | 1941 | try argv.append(try key.status.success.object_path.toString(arena)); |
| | 1942 | } |
| | 1943 | |
| | 1944 | for (comp.win32_resource_table.keys()) |key| { |
| | 1945 | try argv.append(key.status.success.res_path); |
| | 1946 | } |
| | 1947 | |
| | 1948 | if (module_obj_path) |p| { |
| | 1949 | try argv.append(p); |
| | 1950 | } |
| | 1951 | |
| | 1952 | if (coff.module_definition_file) |def| { |
| | 1953 | try argv.append(try allocPrint(arena, "-DEF:{s}", .{def})); |
| | 1954 | } |
| | 1955 | |
| | 1956 | const resolved_subsystem: ?std.Target.SubSystem = blk: { |
| | 1957 | if (coff.subsystem) |explicit| break :blk explicit; |
| | 1958 | switch (target.os.tag) { |
| | 1959 | .windows => { |
| | 1960 | if (comp.zcu) |module| { |
| | 1961 | if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib) |
| | 1962 | break :blk null; |
| | 1963 | if (module.stage1_flags.have_c_main or comp.config.is_test or |
| | 1964 | module.stage1_flags.have_winmain_crt_startup or |
| | 1965 | module.stage1_flags.have_wwinmain_crt_startup) |
| | 1966 | { |
| | 1967 | break :blk .Console; |
| | 1968 | } |
| | 1969 | if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain) |
| | 1970 | break :blk .Windows; |
| | 1971 | } |
| | 1972 | }, |
| | 1973 | .uefi => break :blk .EfiApplication, |
| | 1974 | else => {}, |
| | 1975 | } |
| | 1976 | break :blk null; |
| | 1977 | }; |
| | 1978 | |
| | 1979 | const Mode = enum { uefi, win32 }; |
| | 1980 | const mode: Mode = mode: { |
| | 1981 | if (resolved_subsystem) |subsystem| { |
| | 1982 | const subsystem_suffix = try allocPrint(arena, ",{d}.{d}", .{ |
| | 1983 | coff.major_subsystem_version, coff.minor_subsystem_version, |
| | 1984 | }); |
| | 1985 | |
| | 1986 | switch (subsystem) { |
| | 1987 | .Console => { |
| | 1988 | try argv.append(try allocPrint(arena, "-SUBSYSTEM:console{s}", .{ |
| | 1989 | subsystem_suffix, |
| | 1990 | })); |
| | 1991 | break :mode .win32; |
| | 1992 | }, |
| | 1993 | .EfiApplication => { |
| | 1994 | try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_application{s}", .{ |
| | 1995 | subsystem_suffix, |
| | 1996 | })); |
| | 1997 | break :mode .uefi; |
| | 1998 | }, |
| | 1999 | .EfiBootServiceDriver => { |
| | 2000 | try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_boot_service_driver{s}", .{ |
| | 2001 | subsystem_suffix, |
| | 2002 | })); |
| | 2003 | break :mode .uefi; |
| | 2004 | }, |
| | 2005 | .EfiRom => { |
| | 2006 | try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_rom{s}", .{ |
| | 2007 | subsystem_suffix, |
| | 2008 | })); |
| | 2009 | break :mode .uefi; |
| | 2010 | }, |
| | 2011 | .EfiRuntimeDriver => { |
| | 2012 | try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_runtime_driver{s}", .{ |
| | 2013 | subsystem_suffix, |
| | 2014 | })); |
| | 2015 | break :mode .uefi; |
| | 2016 | }, |
| | 2017 | .Native => { |
| | 2018 | try argv.append(try allocPrint(arena, "-SUBSYSTEM:native{s}", .{ |
| | 2019 | subsystem_suffix, |
| | 2020 | })); |
| | 2021 | break :mode .win32; |
| | 2022 | }, |
| | 2023 | .Posix => { |
| | 2024 | try argv.append(try allocPrint(arena, "-SUBSYSTEM:posix{s}", .{ |
| | 2025 | subsystem_suffix, |
| | 2026 | })); |
| | 2027 | break :mode .win32; |
| | 2028 | }, |
| | 2029 | .Windows => { |
| | 2030 | try argv.append(try allocPrint(arena, "-SUBSYSTEM:windows{s}", .{ |
| | 2031 | subsystem_suffix, |
| | 2032 | })); |
| | 2033 | break :mode .win32; |
| | 2034 | }, |
| | 2035 | } |
| | 2036 | } else if (target.os.tag == .uefi) { |
| | 2037 | break :mode .uefi; |
| | 2038 | } else { |
| | 2039 | break :mode .win32; |
| | 2040 | } |
| | 2041 | }; |
| | 2042 | |
| | 2043 | switch (mode) { |
| | 2044 | .uefi => try argv.appendSlice(&[_][]const u8{ |
| | 2045 | "-BASE:0", |
| | 2046 | "-ENTRY:EfiMain", |
| | 2047 | "-OPT:REF", |
| | 2048 | "-SAFESEH:NO", |
| | 2049 | "-MERGE:.rdata=.data", |
| | 2050 | "-NODEFAULTLIB", |
| | 2051 | "-SECTION:.xdata,D", |
| | 2052 | }), |
| | 2053 | .win32 => { |
| | 2054 | if (link_in_crt) { |
| | 2055 | if (target.abi.isGnu()) { |
| | 2056 | try argv.append("-lldmingw"); |
| | 2057 | |
| | 2058 | if (target.cpu.arch == .x86) { |
| | 2059 | try argv.append("-ALTERNATENAME:__image_base__=___ImageBase"); |
| | 2060 | } else { |
| | 2061 | try argv.append("-ALTERNATENAME:__image_base__=__ImageBase"); |
| | 2062 | } |
| | 2063 | |
| | 2064 | if (is_dyn_lib) { |
| | 2065 | try argv.append(try comp.crtFileAsString(arena, "dllcrt2.obj")); |
| | 2066 | if (target.cpu.arch == .x86) { |
| | 2067 | try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12"); |
| | 2068 | } else { |
| | 2069 | try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup"); |
| | 2070 | } |
| | 2071 | } else { |
| | 2072 | try argv.append(try comp.crtFileAsString(arena, "crt2.obj")); |
| | 2073 | } |
| | 2074 | |
| | 2075 | try argv.append(try comp.crtFileAsString(arena, "mingw32.lib")); |
| | 2076 | } else { |
| | 2077 | const lib_str = switch (comp.config.link_mode) { |
| | 2078 | .dynamic => "", |
| | 2079 | .static => "lib", |
| | 2080 | }; |
| | 2081 | const d_str = switch (optimize_mode) { |
| | 2082 | .Debug => "d", |
| | 2083 | else => "", |
| | 2084 | }; |
| | 2085 | switch (comp.config.link_mode) { |
| | 2086 | .static => try argv.append(try allocPrint(arena, "libcmt{s}.lib", .{d_str})), |
| | 2087 | .dynamic => try argv.append(try allocPrint(arena, "msvcrt{s}.lib", .{d_str})), |
| | 2088 | } |
| | 2089 | |
| | 2090 | try argv.append(try allocPrint(arena, "{s}vcruntime{s}.lib", .{ lib_str, d_str })); |
| | 2091 | try argv.append(try allocPrint(arena, "{s}ucrt{s}.lib", .{ lib_str, d_str })); |
| | 2092 | |
| | 2093 | //Visual C++ 2015 Conformance Changes |
| | 2094 | //https://msdn.microsoft.com/en-us/library/bb531344.aspx |
| | 2095 | try argv.append("legacy_stdio_definitions.lib"); |
| | 2096 | |
| | 2097 | // msvcrt depends on kernel32 and ntdll |
| | 2098 | try argv.append("kernel32.lib"); |
| | 2099 | try argv.append("ntdll.lib"); |
| | 2100 | } |
| | 2101 | } else { |
| | 2102 | try argv.append("-NODEFAULTLIB"); |
| | 2103 | if (!is_lib and entry_name == null) { |
| | 2104 | if (comp.zcu) |module| { |
| | 2105 | if (module.stage1_flags.have_winmain_crt_startup) { |
| | 2106 | try argv.append("-ENTRY:WinMainCRTStartup"); |
| | 2107 | } else { |
| | 2108 | try argv.append("-ENTRY:wWinMainCRTStartup"); |
| | 2109 | } |
| | 2110 | } else { |
| | 2111 | try argv.append("-ENTRY:wWinMainCRTStartup"); |
| | 2112 | } |
| | 2113 | } |
| | 2114 | } |
| | 2115 | }, |
| | 2116 | } |
| | 2117 | |
| | 2118 | // libc++ dep |
| | 2119 | if (comp.config.link_libcpp) { |
| | 2120 | try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); |
| | 2121 | try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); |
| | 2122 | } |
| | 2123 | |
| | 2124 | // libunwind dep |
| | 2125 | if (comp.config.link_libunwind) { |
| | 2126 | try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena)); |
| | 2127 | } |
| | 2128 | |
| | 2129 | if (comp.config.any_fuzz) { |
| | 2130 | try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena)); |
| | 2131 | } |
| | 2132 | |
| | 2133 | if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) { |
| | 2134 | if (!comp.config.link_libc) { |
| | 2135 | if (comp.libc_static_lib) |lib| { |
| | 2136 | try argv.append(try lib.full_object_path.toString(arena)); |
| | 2137 | } |
| | 2138 | } |
| | 2139 | // MSVC compiler_rt is missing some stuff, so we build it unconditionally but |
| | 2140 | // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. |
| | 2141 | if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena)); |
| | 2142 | if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena)); |
| | 2143 | } |
| | 2144 | |
| | 2145 | try argv.ensureUnusedCapacity(comp.windows_libs.count()); |
| | 2146 | for (comp.windows_libs.keys()) |key| { |
| | 2147 | const lib_basename = try allocPrint(arena, "{s}.lib", .{key}); |
| | 2148 | if (comp.crt_files.get(lib_basename)) |crt_file| { |
| | 2149 | argv.appendAssumeCapacity(try crt_file.full_object_path.toString(arena)); |
| | 2150 | continue; |
| | 2151 | } |
| | 2152 | if (try findLib(arena, lib_basename, coff.lib_directories)) |full_path| { |
| | 2153 | argv.appendAssumeCapacity(full_path); |
| | 2154 | continue; |
| | 2155 | } |
| | 2156 | if (target.abi.isGnu()) { |
| | 2157 | const fallback_name = try allocPrint(arena, "lib{s}.dll.a", .{key}); |
| | 2158 | if (try findLib(arena, fallback_name, coff.lib_directories)) |full_path| { |
| | 2159 | argv.appendAssumeCapacity(full_path); |
| | 2160 | continue; |
| | 2161 | } |
| | 2162 | } |
| | 2163 | if (target.abi == .msvc or target.abi == .itanium) { |
| | 2164 | argv.appendAssumeCapacity(lib_basename); |
| | 2165 | continue; |
| | 2166 | } |
| | 2167 | |
| | 2168 | log.err("DLL import library for -l{s} not found", .{key}); |
| | 2169 | return error.DllImportLibraryNotFound; |
| | 2170 | } |
| | 2171 | |
| | 2172 | try link.spawnLld(comp, arena, argv.items); |
| | 2173 | } |
| | 2174 | |
| | 2175 | if (!coff.base.disable_lld_caching) { |
| | 2176 | // Update the file with the digest. If it fails we can continue; it only |
| | 2177 | // means that the next invocation will have an unnecessary cache miss. |
| | 2178 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { |
| | 2179 | log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)}); |
| | 2180 | }; |
| | 2181 | // Again failure here only means an unnecessary cache miss. |
| | 2182 | man.writeManifest() catch |err| { |
| | 2183 | log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)}); |
| | 2184 | }; |
| | 2185 | // We hang on to this lock so that the output file path can be used without |
| | 2186 | // other processes clobbering it. |
| | 2187 | coff.base.lock = man.toOwnedLock(); |
| | 2188 | } |
| | 2189 | } |
| | 2190 | |
| | 2191 | fn findLib(arena: Allocator, name: []const u8, lib_directories: []const Directory) !?[]const u8 { |
| | 2192 | for (lib_directories) |lib_directory| { |
| | 2193 | lib_directory.handle.access(name, .{}) catch |err| switch (err) { |
| | 2194 | error.FileNotFound => continue, |
| | 2195 | else => |e| return e, |
| | 2196 | }; |
| | 2197 | return try lib_directory.join(arena, &.{name}); |
| | 2198 | } |
| | 2199 | return null; |
| | 2200 | } |
| | 2201 | |
| | 2202 | pub fn flushModule(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { |
| | 2203 | const tracy = trace(@src()); |
| | 2204 | defer tracy.end(); |
| | 2205 | |
| | 2206 | const comp = coff.base.comp; |
| 1687 | const gpa = comp.gpa; | 2207 | const gpa = comp.gpa; |
| 1688 | const diags = &comp.link_diags; | 2208 | const diags = &comp.link_diags; |
| 1689 | | 2209 | |
| 1690 | if (self.llvm_object) |llvm_object| { | 2210 | if (coff.llvm_object) |llvm_object| { |
| 1691 | try self.base.emitLlvmObject(arena, llvm_object, prog_node); | 2211 | try coff.base.emitLlvmObject(arena, llvm_object, prog_node); |
| 1692 | return; | 2212 | return; |
| 1693 | } | 2213 | } |
| 1694 | | 2214 | |
| ... | @@ -1700,46 +2220,46 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no | ... | @@ -1700,46 +2220,46 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no |
| 1700 | .tid = tid, | 2220 | .tid = tid, |
| 1701 | }; | 2221 | }; |
| 1702 | | 2222 | |
| 1703 | if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| { | 2223 | if (coff.lazy_syms.getPtr(.anyerror_type)) |metadata| { |
| 1704 | // Most lazy symbols can be updated on first use, but | 2224 | // Most lazy symbols can be updated on first use, but |
| 1705 | // anyerror needs to wait for everything to be flushed. | 2225 | // anyerror needs to wait for everything to be flushed. |
| 1706 | if (metadata.text_state != .unused) self.updateLazySymbolAtom( | 2226 | if (metadata.text_state != .unused) coff.updateLazySymbolAtom( |
| 1707 | pt, | 2227 | pt, |
| 1708 | .{ .kind = .code, .ty = .anyerror_type }, | 2228 | .{ .kind = .code, .ty = .anyerror_type }, |
| 1709 | metadata.text_atom, | 2229 | metadata.text_atom, |
| 1710 | self.text_section_index.?, | 2230 | coff.text_section_index.?, |
| 1711 | ) catch |err| return switch (err) { | 2231 | ) catch |err| return switch (err) { |
| 1712 | error.CodegenFail => error.FlushFailure, | 2232 | error.CodegenFail => error.FlushFailure, |
| 1713 | else => |e| e, | 2233 | else => |e| e, |
| 1714 | }; | 2234 | }; |
| 1715 | if (metadata.rdata_state != .unused) self.updateLazySymbolAtom( | 2235 | if (metadata.rdata_state != .unused) coff.updateLazySymbolAtom( |
| 1716 | pt, | 2236 | pt, |
| 1717 | .{ .kind = .const_data, .ty = .anyerror_type }, | 2237 | .{ .kind = .const_data, .ty = .anyerror_type }, |
| 1718 | metadata.rdata_atom, | 2238 | metadata.rdata_atom, |
| 1719 | self.rdata_section_index.?, | 2239 | coff.rdata_section_index.?, |
| 1720 | ) catch |err| return switch (err) { | 2240 | ) catch |err| return switch (err) { |
| 1721 | error.CodegenFail => error.FlushFailure, | 2241 | error.CodegenFail => error.FlushFailure, |
| 1722 | else => |e| e, | 2242 | else => |e| e, |
| 1723 | }; | 2243 | }; |
| 1724 | } | 2244 | } |
| 1725 | for (self.lazy_syms.values()) |*metadata| { | 2245 | for (coff.lazy_syms.values()) |*metadata| { |
| 1726 | if (metadata.text_state != .unused) metadata.text_state = .flushed; | 2246 | if (metadata.text_state != .unused) metadata.text_state = .flushed; |
| 1727 | if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed; | 2247 | if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed; |
| 1728 | } | 2248 | } |
| 1729 | | 2249 | |
| 1730 | { | 2250 | { |
| 1731 | var it = self.need_got_table.iterator(); | 2251 | var it = coff.need_got_table.iterator(); |
| 1732 | while (it.next()) |entry| { | 2252 | while (it.next()) |entry| { |
| 1733 | const global = self.globals.items[entry.key_ptr.*]; | 2253 | const global = coff.globals.items[entry.key_ptr.*]; |
| 1734 | try self.addGotEntry(global); | 2254 | try coff.addGotEntry(global); |
| 1735 | } | 2255 | } |
| 1736 | } | 2256 | } |
| 1737 | | 2257 | |
| 1738 | while (self.unresolved.popOrNull()) |entry| { | 2258 | while (coff.unresolved.popOrNull()) |entry| { |
| 1739 | assert(entry.value); | 2259 | assert(entry.value); |
| 1740 | const global = self.globals.items[entry.key]; | 2260 | const global = coff.globals.items[entry.key]; |
| 1741 | const sym = self.getSymbol(global); | 2261 | const sym = coff.getSymbol(global); |
| 1742 | const res = try self.import_tables.getOrPut(gpa, sym.value); | 2262 | const res = try coff.import_tables.getOrPut(gpa, sym.value); |
| 1743 | const itable = res.value_ptr; | 2263 | const itable = res.value_ptr; |
| 1744 | if (!res.found_existing) { | 2264 | if (!res.found_existing) { |
| 1745 | itable.* = .{}; | 2265 | itable.* = .{}; |
| ... | @@ -1748,21 +2268,21 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no | ... | @@ -1748,21 +2268,21 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no |
| 1748 | // TODO: we could technically write the pointer placeholder for to-be-bound import here, | 2268 | // TODO: we could technically write the pointer placeholder for to-be-bound import here, |
| 1749 | // but since this happens in flush, there is currently no point. | 2269 | // but since this happens in flush, there is currently no point. |
| 1750 | _ = try itable.addImport(gpa, global); | 2270 | _ = try itable.addImport(gpa, global); |
| 1751 | self.imports_count_dirty = true; | 2271 | coff.imports_count_dirty = true; |
| 1752 | } | 2272 | } |
| 1753 | | 2273 | |
| 1754 | try self.writeImportTables(); | 2274 | try coff.writeImportTables(); |
| 1755 | | 2275 | |
| 1756 | for (self.relocs.keys(), self.relocs.values()) |atom_index, relocs| { | 2276 | for (coff.relocs.keys(), coff.relocs.values()) |atom_index, relocs| { |
| 1757 | const needs_update = for (relocs.items) |reloc| { | 2277 | const needs_update = for (relocs.items) |reloc| { |
| 1758 | if (reloc.dirty) break true; | 2278 | if (reloc.dirty) break true; |
| 1759 | } else false; | 2279 | } else false; |
| 1760 | | 2280 | |
| 1761 | if (!needs_update) continue; | 2281 | if (!needs_update) continue; |
| 1762 | | 2282 | |
| 1763 | const atom = self.getAtom(atom_index); | 2283 | const atom = coff.getAtom(atom_index); |
| 1764 | const sym = atom.getSymbol(self); | 2284 | const sym = atom.getSymbol(coff); |
| 1765 | const section = self.sections.get(@intFromEnum(sym.section_number) - 1).header; | 2285 | const section = coff.sections.get(@intFromEnum(sym.section_number) - 1).header; |
| 1766 | const file_offset = section.pointer_to_raw_data + sym.value - section.virtual_address; | 2286 | const file_offset = section.pointer_to_raw_data + sym.value - section.virtual_address; |
| 1767 | | 2287 | |
| 1768 | var code = std.ArrayList(u8).init(gpa); | 2288 | var code = std.ArrayList(u8).init(gpa); |
| ... | @@ -1770,70 +2290,70 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no | ... | @@ -1770,70 +2290,70 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no |
| 1770 | try code.resize(math.cast(usize, atom.size) orelse return error.Overflow); | 2290 | try code.resize(math.cast(usize, atom.size) orelse return error.Overflow); |
| 1771 | assert(atom.size > 0); | 2291 | assert(atom.size > 0); |
| 1772 | | 2292 | |
| 1773 | const amt = try self.base.file.?.preadAll(code.items, file_offset); | 2293 | const amt = try coff.base.file.?.preadAll(code.items, file_offset); |
| 1774 | if (amt != code.items.len) return error.InputOutput; | 2294 | if (amt != code.items.len) return error.InputOutput; |
| 1775 | | 2295 | |
| 1776 | try self.writeAtom(atom_index, code.items); | 2296 | try coff.writeAtom(atom_index, code.items); |
| 1777 | } | 2297 | } |
| 1778 | | 2298 | |
| 1779 | // Update GOT if it got moved in memory. | 2299 | // Update GOT if it got moved in memory. |
| 1780 | if (self.got_table_contents_dirty) { | 2300 | if (coff.got_table_contents_dirty) { |
| 1781 | for (self.got_table.entries.items, 0..) |entry, i| { | 2301 | for (coff.got_table.entries.items, 0..) |entry, i| { |
| 1782 | if (!self.got_table.lookup.contains(entry)) continue; | 2302 | if (!coff.got_table.lookup.contains(entry)) continue; |
| 1783 | // TODO: write all in one go rather than incrementally. | 2303 | // TODO: write all in one go rather than incrementally. |
| 1784 | try self.writeOffsetTableEntry(i); | 2304 | try coff.writeOffsetTableEntry(i); |
| 1785 | } | 2305 | } |
| 1786 | self.got_table_contents_dirty = false; | 2306 | coff.got_table_contents_dirty = false; |
| 1787 | } | 2307 | } |
| 1788 | | 2308 | |
| 1789 | try self.writeBaseRelocations(); | 2309 | try coff.writeBaseRelocations(); |
| 1790 | | 2310 | |
| 1791 | if (self.getEntryPoint()) |entry_sym_loc| { | 2311 | if (coff.getEntryPoint()) |entry_sym_loc| { |
| 1792 | self.entry_addr = self.getSymbol(entry_sym_loc).value; | 2312 | coff.entry_addr = coff.getSymbol(entry_sym_loc).value; |
| 1793 | } | 2313 | } |
| 1794 | | 2314 | |
| 1795 | if (build_options.enable_logging) { | 2315 | if (build_options.enable_logging) { |
| 1796 | self.logSymtab(); | 2316 | coff.logSymtab(); |
| 1797 | self.logImportTables(); | 2317 | coff.logImportTables(); |
| 1798 | } | 2318 | } |
| 1799 | | 2319 | |
| 1800 | try self.writeStrtab(); | 2320 | try coff.writeStrtab(); |
| 1801 | try self.writeDataDirectoriesHeaders(); | 2321 | try coff.writeDataDirectoriesHeaders(); |
| 1802 | try self.writeSectionHeaders(); | 2322 | try coff.writeSectionHeaders(); |
| 1803 | | 2323 | |
| 1804 | if (self.entry_addr == null and comp.config.output_mode == .Exe) { | 2324 | if (coff.entry_addr == null and comp.config.output_mode == .Exe) { |
| 1805 | log.debug("flushing. no_entry_point_found = true\n", .{}); | 2325 | log.debug("flushing. no_entry_point_found = true\n", .{}); |
| 1806 | diags.flags.no_entry_point_found = true; | 2326 | diags.flags.no_entry_point_found = true; |
| 1807 | } else { | 2327 | } else { |
| 1808 | log.debug("flushing. no_entry_point_found = false\n", .{}); | 2328 | log.debug("flushing. no_entry_point_found = false\n", .{}); |
| 1809 | diags.flags.no_entry_point_found = false; | 2329 | diags.flags.no_entry_point_found = false; |
| 1810 | try self.writeHeader(); | 2330 | try coff.writeHeader(); |
| 1811 | } | 2331 | } |
| 1812 | | 2332 | |
| 1813 | assert(!self.imports_count_dirty); | 2333 | assert(!coff.imports_count_dirty); |
| 1814 | } | 2334 | } |
| 1815 | | 2335 | |
| 1816 | pub fn getNavVAddr( | 2336 | pub fn getNavVAddr( |
| 1817 | self: *Coff, | 2337 | coff: *Coff, |
| 1818 | pt: Zcu.PerThread, | 2338 | pt: Zcu.PerThread, |
| 1819 | nav_index: InternPool.Nav.Index, | 2339 | nav_index: InternPool.Nav.Index, |
| 1820 | reloc_info: link.File.RelocInfo, | 2340 | reloc_info: link.File.RelocInfo, |
| 1821 | ) !u64 { | 2341 | ) !u64 { |
| 1822 | assert(self.llvm_object == null); | 2342 | assert(coff.llvm_object == null); |
| 1823 | const zcu = pt.zcu; | 2343 | const zcu = pt.zcu; |
| 1824 | const ip = &zcu.intern_pool; | 2344 | const ip = &zcu.intern_pool; |
| 1825 | const nav = ip.getNav(nav_index); | 2345 | const nav = ip.getNav(nav_index); |
| 1826 | log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index }); | 2346 | log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index }); |
| 1827 | const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) { | 2347 | const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) { |
| 1828 | .@"extern" => |@"extern"| try self.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)), | 2348 | .@"extern" => |@"extern"| try coff.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)), |
| 1829 | else => self.getAtom(try self.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?, | 2349 | else => coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?, |
| 1830 | }; | 2350 | }; |
| 1831 | const atom_index = self.getAtomIndexForSymbol(.{ | 2351 | const atom_index = coff.getAtomIndexForSymbol(.{ |
| 1832 | .sym_index = reloc_info.parent.atom_index, | 2352 | .sym_index = reloc_info.parent.atom_index, |
| 1833 | .file = null, | 2353 | .file = null, |
| 1834 | }).?; | 2354 | }).?; |
| 1835 | const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; | 2355 | const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1836 | try Atom.addRelocation(self, atom_index, .{ | 2356 | try coff.addRelocation(atom_index, .{ |
| 1837 | .type = .direct, | 2357 | .type = .direct, |
| 1838 | .target = target, | 2358 | .target = target, |
| 1839 | .offset = @as(u32, @intCast(reloc_info.offset)), | 2359 | .offset = @as(u32, @intCast(reloc_info.offset)), |
| ... | @@ -1841,13 +2361,13 @@ pub fn getNavVAddr( | ... | @@ -1841,13 +2361,13 @@ pub fn getNavVAddr( |
| 1841 | .pcrel = false, | 2361 | .pcrel = false, |
| 1842 | .length = 3, | 2362 | .length = 3, |
| 1843 | }); | 2363 | }); |
| 1844 | try Atom.addBaseRelocation(self, atom_index, @as(u32, @intCast(reloc_info.offset))); | 2364 | try coff.addBaseRelocation(atom_index, @as(u32, @intCast(reloc_info.offset))); |
| 1845 | | 2365 | |
| 1846 | return 0; | 2366 | return 0; |
| 1847 | } | 2367 | } |
| 1848 | | 2368 | |
| 1849 | pub fn lowerUav( | 2369 | pub fn lowerUav( |
| 1850 | self: *Coff, | 2370 | coff: *Coff, |
| 1851 | pt: Zcu.PerThread, | 2371 | pt: Zcu.PerThread, |
| 1852 | uav: InternPool.Index, | 2372 | uav: InternPool.Index, |
| 1853 | explicit_alignment: InternPool.Alignment, | 2373 | explicit_alignment: InternPool.Alignment, |
| ... | @@ -1860,9 +2380,9 @@ pub fn lowerUav( | ... | @@ -1860,9 +2380,9 @@ pub fn lowerUav( |
| 1860 | .none => val.typeOf(zcu).abiAlignment(zcu), | 2380 | .none => val.typeOf(zcu).abiAlignment(zcu), |
| 1861 | else => explicit_alignment, | 2381 | else => explicit_alignment, |
| 1862 | }; | 2382 | }; |
| 1863 | if (self.uavs.get(uav)) |metadata| { | 2383 | if (coff.uavs.get(uav)) |metadata| { |
| 1864 | const atom = self.getAtom(metadata.atom); | 2384 | const atom = coff.getAtom(metadata.atom); |
| 1865 | const existing_addr = atom.getSymbol(self).value; | 2385 | const existing_addr = atom.getSymbol(coff).value; |
| 1866 | if (uav_alignment.check(existing_addr)) | 2386 | if (uav_alignment.check(existing_addr)) |
| 1867 | return .{ .mcv = .{ .load_direct = atom.getSymbolIndex().? } }; | 2387 | return .{ .mcv = .{ .load_direct = atom.getSymbolIndex().? } }; |
| 1868 | } | 2388 | } |
| ... | @@ -1871,12 +2391,12 @@ pub fn lowerUav( | ... | @@ -1871,12 +2391,12 @@ pub fn lowerUav( |
| 1871 | const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ | 2391 | const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ |
| 1872 | @intFromEnum(uav), | 2392 | @intFromEnum(uav), |
| 1873 | }) catch unreachable; | 2393 | }) catch unreachable; |
| 1874 | const res = self.lowerConst( | 2394 | const res = coff.lowerConst( |
| 1875 | pt, | 2395 | pt, |
| 1876 | name, | 2396 | name, |
| 1877 | val, | 2397 | val, |
| 1878 | uav_alignment, | 2398 | uav_alignment, |
| 1879 | self.rdata_section_index.?, | 2399 | coff.rdata_section_index.?, |
| 1880 | src_loc, | 2400 | src_loc, |
| 1881 | ) catch |err| switch (err) { | 2401 | ) catch |err| switch (err) { |
| 1882 | error.OutOfMemory => return error.OutOfMemory, | 2402 | error.OutOfMemory => return error.OutOfMemory, |
| ... | @@ -1891,30 +2411,30 @@ pub fn lowerUav( | ... | @@ -1891,30 +2411,30 @@ pub fn lowerUav( |
| 1891 | .ok => |atom_index| atom_index, | 2411 | .ok => |atom_index| atom_index, |
| 1892 | .fail => |em| return .{ .fail = em }, | 2412 | .fail => |em| return .{ .fail = em }, |
| 1893 | }; | 2413 | }; |
| 1894 | try self.uavs.put(gpa, uav, .{ | 2414 | try coff.uavs.put(gpa, uav, .{ |
| 1895 | .atom = atom_index, | 2415 | .atom = atom_index, |
| 1896 | .section = self.rdata_section_index.?, | 2416 | .section = coff.rdata_section_index.?, |
| 1897 | }); | 2417 | }); |
| 1898 | return .{ .mcv = .{ | 2418 | return .{ .mcv = .{ |
| 1899 | .load_direct = self.getAtom(atom_index).getSymbolIndex().?, | 2419 | .load_direct = coff.getAtom(atom_index).getSymbolIndex().?, |
| 1900 | } }; | 2420 | } }; |
| 1901 | } | 2421 | } |
| 1902 | | 2422 | |
| 1903 | pub fn getUavVAddr( | 2423 | pub fn getUavVAddr( |
| 1904 | self: *Coff, | 2424 | coff: *Coff, |
| 1905 | uav: InternPool.Index, | 2425 | uav: InternPool.Index, |
| 1906 | reloc_info: link.File.RelocInfo, | 2426 | reloc_info: link.File.RelocInfo, |
| 1907 | ) !u64 { | 2427 | ) !u64 { |
| 1908 | assert(self.llvm_object == null); | 2428 | assert(coff.llvm_object == null); |
| 1909 | | 2429 | |
| 1910 | const this_atom_index = self.uavs.get(uav).?.atom; | 2430 | const this_atom_index = coff.uavs.get(uav).?.atom; |
| 1911 | const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; | 2431 | const sym_index = coff.getAtom(this_atom_index).getSymbolIndex().?; |
| 1912 | const atom_index = self.getAtomIndexForSymbol(.{ | 2432 | const atom_index = coff.getAtomIndexForSymbol(.{ |
| 1913 | .sym_index = reloc_info.parent.atom_index, | 2433 | .sym_index = reloc_info.parent.atom_index, |
| 1914 | .file = null, | 2434 | .file = null, |
| 1915 | }).?; | 2435 | }).?; |
| 1916 | const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; | 2436 | const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1917 | try Atom.addRelocation(self, atom_index, .{ | 2437 | try coff.addRelocation(atom_index, .{ |
| 1918 | .type = .direct, | 2438 | .type = .direct, |
| 1919 | .target = target, | 2439 | .target = target, |
| 1920 | .offset = @as(u32, @intCast(reloc_info.offset)), | 2440 | .offset = @as(u32, @intCast(reloc_info.offset)), |
| ... | @@ -1922,41 +2442,41 @@ pub fn getUavVAddr( | ... | @@ -1922,41 +2442,41 @@ pub fn getUavVAddr( |
| 1922 | .pcrel = false, | 2442 | .pcrel = false, |
| 1923 | .length = 3, | 2443 | .length = 3, |
| 1924 | }); | 2444 | }); |
| 1925 | try Atom.addBaseRelocation(self, atom_index, @as(u32, @intCast(reloc_info.offset))); | 2445 | try coff.addBaseRelocation(atom_index, @as(u32, @intCast(reloc_info.offset))); |
| 1926 | | 2446 | |
| 1927 | return 0; | 2447 | return 0; |
| 1928 | } | 2448 | } |
| 1929 | | 2449 | |
| 1930 | pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 { | 2450 | pub fn getGlobalSymbol(coff: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 { |
| 1931 | const gop = try self.getOrPutGlobalPtr(name); | 2451 | const gop = try coff.getOrPutGlobalPtr(name); |
| 1932 | const global_index = self.getGlobalIndex(name).?; | 2452 | const global_index = coff.getGlobalIndex(name).?; |
| 1933 | | 2453 | |
| 1934 | if (gop.found_existing) { | 2454 | if (gop.found_existing) { |
| 1935 | return global_index; | 2455 | return global_index; |
| 1936 | } | 2456 | } |
| 1937 | | 2457 | |
| 1938 | const sym_index = try self.allocateSymbol(); | 2458 | const sym_index = try coff.allocateSymbol(); |
| 1939 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; | 2459 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1940 | gop.value_ptr.* = sym_loc; | 2460 | gop.value_ptr.* = sym_loc; |
| 1941 | | 2461 | |
| 1942 | const gpa = self.base.comp.gpa; | 2462 | const gpa = coff.base.comp.gpa; |
| 1943 | const sym = self.getSymbolPtr(sym_loc); | 2463 | const sym = coff.getSymbolPtr(sym_loc); |
| 1944 | try self.setSymbolName(sym, name); | 2464 | try coff.setSymbolName(sym, name); |
| 1945 | sym.storage_class = .EXTERNAL; | 2465 | sym.storage_class = .EXTERNAL; |
| 1946 | | 2466 | |
| 1947 | if (lib_name_name) |lib_name| { | 2467 | if (lib_name_name) |lib_name| { |
| 1948 | // We repurpose the 'value' of the Symbol struct to store an offset into | 2468 | // We repurpose the 'value' of the Symbol struct to store an offset into |
| 1949 | // temporary string table where we will store the library name hint. | 2469 | // temporary string table where we will store the library name hint. |
| 1950 | sym.value = try self.temp_strtab.insert(gpa, lib_name); | 2470 | sym.value = try coff.temp_strtab.insert(gpa, lib_name); |
| 1951 | } | 2471 | } |
| 1952 | | 2472 | |
| 1953 | try self.unresolved.putNoClobber(gpa, global_index, true); | 2473 | try coff.unresolved.putNoClobber(gpa, global_index, true); |
| 1954 | | 2474 | |
| 1955 | return global_index; | 2475 | return global_index; |
| 1956 | } | 2476 | } |
| 1957 | | 2477 | |
| 1958 | pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void { | 2478 | pub fn updateDeclLineNumber(coff: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void { |
| 1959 | _ = self; | 2479 | _ = coff; |
| 1960 | _ = pt; | 2480 | _ = pt; |
| 1961 | _ = decl_index; | 2481 | _ = decl_index; |
| 1962 | log.debug("TODO implement updateDeclLineNumber", .{}); | 2482 | log.debug("TODO implement updateDeclLineNumber", .{}); |
| ... | @@ -1965,10 +2485,10 @@ pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPo | ... | @@ -1965,10 +2485,10 @@ pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPo |
| 1965 | /// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table | 2485 | /// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table |
| 1966 | /// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do | 2486 | /// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do |
| 1967 | /// incremental updates and writes into the table instead of doing it all at once | 2487 | /// incremental updates and writes into the table instead of doing it all at once |
| 1968 | fn writeBaseRelocations(self: *Coff) !void { | 2488 | fn writeBaseRelocations(coff: *Coff) !void { |
| 1969 | const gpa = self.base.comp.gpa; | 2489 | const gpa = coff.base.comp.gpa; |
| 1970 | | 2490 | |
| 1971 | var page_table = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa); | 2491 | var page_table = std.AutoHashMap(u32, std.ArrayList(coff_util.BaseRelocation)).init(gpa); |
| 1972 | defer { | 2492 | defer { |
| 1973 | var it = page_table.valueIterator(); | 2493 | var it = page_table.valueIterator(); |
| 1974 | while (it.next()) |inner| { | 2494 | while (it.next()) |inner| { |
| ... | @@ -1978,19 +2498,19 @@ fn writeBaseRelocations(self: *Coff) !void { | ... | @@ -1978,19 +2498,19 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 1978 | } | 2498 | } |
| 1979 | | 2499 | |
| 1980 | { | 2500 | { |
| 1981 | var it = self.base_relocs.iterator(); | 2501 | var it = coff.base_relocs.iterator(); |
| 1982 | while (it.next()) |entry| { | 2502 | while (it.next()) |entry| { |
| 1983 | const atom_index = entry.key_ptr.*; | 2503 | const atom_index = entry.key_ptr.*; |
| 1984 | const atom = self.getAtom(atom_index); | 2504 | const atom = coff.getAtom(atom_index); |
| 1985 | const sym = atom.getSymbol(self); | 2505 | const sym = atom.getSymbol(coff); |
| 1986 | const offsets = entry.value_ptr.*; | 2506 | const offsets = entry.value_ptr.*; |
| 1987 | | 2507 | |
| 1988 | for (offsets.items) |offset| { | 2508 | for (offsets.items) |offset| { |
| 1989 | const rva = sym.value + offset; | 2509 | const rva = sym.value + offset; |
| 1990 | const page = mem.alignBackward(u32, rva, self.page_size); | 2510 | const page = mem.alignBackward(u32, rva, coff.page_size); |
| 1991 | const gop = try page_table.getOrPut(page); | 2511 | const gop = try page_table.getOrPut(page); |
| 1992 | if (!gop.found_existing) { | 2512 | if (!gop.found_existing) { |
| 1993 | gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa); | 2513 | gop.value_ptr.* = std.ArrayList(coff_util.BaseRelocation).init(gpa); |
| 1994 | } | 2514 | } |
| 1995 | try gop.value_ptr.append(.{ | 2515 | try gop.value_ptr.append(.{ |
| 1996 | .offset = @as(u12, @intCast(rva - page)), | 2516 | .offset = @as(u12, @intCast(rva - page)), |
| ... | @@ -2000,18 +2520,18 @@ fn writeBaseRelocations(self: *Coff) !void { | ... | @@ -2000,18 +2520,18 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 2000 | } | 2520 | } |
| 2001 | | 2521 | |
| 2002 | { | 2522 | { |
| 2003 | const header = &self.sections.items(.header)[self.got_section_index.?]; | 2523 | const header = &coff.sections.items(.header)[coff.got_section_index.?]; |
| 2004 | for (self.got_table.entries.items, 0..) |entry, index| { | 2524 | for (coff.got_table.entries.items, 0..) |entry, index| { |
| 2005 | if (!self.got_table.lookup.contains(entry)) continue; | 2525 | if (!coff.got_table.lookup.contains(entry)) continue; |
| 2006 | | 2526 | |
| 2007 | const sym = self.getSymbol(entry); | 2527 | const sym = coff.getSymbol(entry); |
| 2008 | if (sym.section_number == .UNDEFINED) continue; | 2528 | if (sym.section_number == .UNDEFINED) continue; |
| 2009 | | 2529 | |
| 2010 | const rva = @as(u32, @intCast(header.virtual_address + index * self.ptr_width.size())); | 2530 | const rva = @as(u32, @intCast(header.virtual_address + index * coff.ptr_width.size())); |
| 2011 | const page = mem.alignBackward(u32, rva, self.page_size); | 2531 | const page = mem.alignBackward(u32, rva, coff.page_size); |
| 2012 | const gop = try page_table.getOrPut(page); | 2532 | const gop = try page_table.getOrPut(page); |
| 2013 | if (!gop.found_existing) { | 2533 | if (!gop.found_existing) { |
| 2014 | gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa); | 2534 | gop.value_ptr.* = std.ArrayList(coff_util.BaseRelocation).init(gpa); |
| 2015 | } | 2535 | } |
| 2016 | try gop.value_ptr.append(.{ | 2536 | try gop.value_ptr.append(.{ |
| 2017 | .offset = @as(u12, @intCast(rva - page)), | 2537 | .offset = @as(u12, @intCast(rva - page)), |
| ... | @@ -2040,7 +2560,7 @@ fn writeBaseRelocations(self: *Coff) !void { | ... | @@ -2040,7 +2560,7 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 2040 | // Pad to required 4byte alignment | 2560 | // Pad to required 4byte alignment |
| 2041 | if (!mem.isAlignedGeneric( | 2561 | if (!mem.isAlignedGeneric( |
| 2042 | usize, | 2562 | usize, |
| 2043 | entries.items.len * @sizeOf(coff.BaseRelocation), | 2563 | entries.items.len * @sizeOf(coff_util.BaseRelocation), |
| 2044 | @sizeOf(u32), | 2564 | @sizeOf(u32), |
| 2045 | )) { | 2565 | )) { |
| 2046 | try entries.append(.{ | 2566 | try entries.append(.{ |
| ... | @@ -2051,58 +2571,58 @@ fn writeBaseRelocations(self: *Coff) !void { | ... | @@ -2051,58 +2571,58 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 2051 | | 2571 | |
| 2052 | const block_size = @as( | 2572 | const block_size = @as( |
| 2053 | u32, | 2573 | u32, |
| 2054 | @intCast(entries.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry)), | 2574 | @intCast(entries.items.len * @sizeOf(coff_util.BaseRelocation) + @sizeOf(coff_util.BaseRelocationDirectoryEntry)), |
| 2055 | ); | 2575 | ); |
| 2056 | try buffer.ensureUnusedCapacity(block_size); | 2576 | try buffer.ensureUnusedCapacity(block_size); |
| 2057 | buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{ | 2577 | buffer.appendSliceAssumeCapacity(mem.asBytes(&coff_util.BaseRelocationDirectoryEntry{ |
| 2058 | .page_rva = page, | 2578 | .page_rva = page, |
| 2059 | .block_size = block_size, | 2579 | .block_size = block_size, |
| 2060 | })); | 2580 | })); |
| 2061 | buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entries.items)); | 2581 | buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entries.items)); |
| 2062 | } | 2582 | } |
| 2063 | | 2583 | |
| 2064 | const header = &self.sections.items(.header)[self.reloc_section_index.?]; | 2584 | const header = &coff.sections.items(.header)[coff.reloc_section_index.?]; |
| 2065 | const needed_size = @as(u32, @intCast(buffer.items.len)); | 2585 | const needed_size = @as(u32, @intCast(buffer.items.len)); |
| 2066 | try self.growSection(self.reloc_section_index.?, needed_size); | 2586 | try coff.growSection(coff.reloc_section_index.?, needed_size); |
| 2067 | | 2587 | |
| 2068 | try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data); | 2588 | try coff.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data); |
| 2069 | | 2589 | |
| 2070 | self.data_directories[@intFromEnum(coff.DirectoryEntry.BASERELOC)] = .{ | 2590 | coff.data_directories[@intFromEnum(coff_util.DirectoryEntry.BASERELOC)] = .{ |
| 2071 | .virtual_address = header.virtual_address, | 2591 | .virtual_address = header.virtual_address, |
| 2072 | .size = needed_size, | 2592 | .size = needed_size, |
| 2073 | }; | 2593 | }; |
| 2074 | } | 2594 | } |
| 2075 | | 2595 | |
| 2076 | fn writeImportTables(self: *Coff) !void { | 2596 | fn writeImportTables(coff: *Coff) !void { |
| 2077 | if (self.idata_section_index == null) return; | 2597 | if (coff.idata_section_index == null) return; |
| 2078 | if (!self.imports_count_dirty) return; | 2598 | if (!coff.imports_count_dirty) return; |
| 2079 | | 2599 | |
| 2080 | const gpa = self.base.comp.gpa; | 2600 | const gpa = coff.base.comp.gpa; |
| 2081 | | 2601 | |
| 2082 | const ext = ".dll"; | 2602 | const ext = ".dll"; |
| 2083 | const header = &self.sections.items(.header)[self.idata_section_index.?]; | 2603 | const header = &coff.sections.items(.header)[coff.idata_section_index.?]; |
| 2084 | | 2604 | |
| 2085 | // Calculate needed size | 2605 | // Calculate needed size |
| 2086 | var iat_size: u32 = 0; | 2606 | var iat_size: u32 = 0; |
| 2087 | var dir_table_size: u32 = @sizeOf(coff.ImportDirectoryEntry); // sentinel | 2607 | var dir_table_size: u32 = @sizeOf(coff_util.ImportDirectoryEntry); // sentinel |
| 2088 | var lookup_table_size: u32 = 0; | 2608 | var lookup_table_size: u32 = 0; |
| 2089 | var names_table_size: u32 = 0; | 2609 | var names_table_size: u32 = 0; |
| 2090 | var dll_names_size: u32 = 0; | 2610 | var dll_names_size: u32 = 0; |
| 2091 | for (self.import_tables.keys(), 0..) |off, i| { | 2611 | for (coff.import_tables.keys(), 0..) |off, i| { |
| 2092 | const lib_name = self.temp_strtab.getAssumeExists(off); | 2612 | const lib_name = coff.temp_strtab.getAssumeExists(off); |
| 2093 | const itable = self.import_tables.values()[i]; | 2613 | const itable = coff.import_tables.values()[i]; |
| 2094 | iat_size += itable.size() + 8; | 2614 | iat_size += itable.size() + 8; |
| 2095 | dir_table_size += @sizeOf(coff.ImportDirectoryEntry); | 2615 | dir_table_size += @sizeOf(coff_util.ImportDirectoryEntry); |
| 2096 | lookup_table_size += @as(u32, @intCast(itable.entries.items.len + 1)) * @sizeOf(coff.ImportLookupEntry64.ByName); | 2616 | lookup_table_size += @as(u32, @intCast(itable.entries.items.len + 1)) * @sizeOf(coff_util.ImportLookupEntry64.ByName); |
| 2097 | for (itable.entries.items) |entry| { | 2617 | for (itable.entries.items) |entry| { |
| 2098 | const sym_name = self.getSymbolName(entry); | 2618 | const sym_name = coff.getSymbolName(entry); |
| 2099 | names_table_size += 2 + mem.alignForward(u32, @as(u32, @intCast(sym_name.len + 1)), 2); | 2619 | names_table_size += 2 + mem.alignForward(u32, @as(u32, @intCast(sym_name.len + 1)), 2); |
| 2100 | } | 2620 | } |
| 2101 | dll_names_size += @as(u32, @intCast(lib_name.len + ext.len + 1)); | 2621 | dll_names_size += @as(u32, @intCast(lib_name.len + ext.len + 1)); |
| 2102 | } | 2622 | } |
| 2103 | | 2623 | |
| 2104 | const needed_size = iat_size + dir_table_size + lookup_table_size + names_table_size + dll_names_size; | 2624 | const needed_size = iat_size + dir_table_size + lookup_table_size + names_table_size + dll_names_size; |
| 2105 | try self.growSection(self.idata_section_index.?, needed_size); | 2625 | try coff.growSection(coff.idata_section_index.?, needed_size); |
| 2106 | | 2626 | |
| 2107 | // Do the actual writes | 2627 | // Do the actual writes |
| 2108 | var buffer = std.ArrayList(u8).init(gpa); | 2628 | var buffer = std.ArrayList(u8).init(gpa); |
| ... | @@ -2110,41 +2630,41 @@ fn writeImportTables(self: *Coff) !void { | ... | @@ -2110,41 +2630,41 @@ fn writeImportTables(self: *Coff) !void { |
| 2110 | try buffer.ensureTotalCapacityPrecise(needed_size); | 2630 | try buffer.ensureTotalCapacityPrecise(needed_size); |
| 2111 | buffer.resize(needed_size) catch unreachable; | 2631 | buffer.resize(needed_size) catch unreachable; |
| 2112 | | 2632 | |
| 2113 | const dir_header_size = @sizeOf(coff.ImportDirectoryEntry); | 2633 | const dir_header_size = @sizeOf(coff_util.ImportDirectoryEntry); |
| 2114 | const lookup_entry_size = @sizeOf(coff.ImportLookupEntry64.ByName); | 2634 | const lookup_entry_size = @sizeOf(coff_util.ImportLookupEntry64.ByName); |
| 2115 | | 2635 | |
| 2116 | var iat_offset: u32 = 0; | 2636 | var iat_offset: u32 = 0; |
| 2117 | var dir_table_offset = iat_size; | 2637 | var dir_table_offset = iat_size; |
| 2118 | var lookup_table_offset = dir_table_offset + dir_table_size; | 2638 | var lookup_table_offset = dir_table_offset + dir_table_size; |
| 2119 | var names_table_offset = lookup_table_offset + lookup_table_size; | 2639 | var names_table_offset = lookup_table_offset + lookup_table_size; |
| 2120 | var dll_names_offset = names_table_offset + names_table_size; | 2640 | var dll_names_offset = names_table_offset + names_table_size; |
| 2121 | for (self.import_tables.keys(), 0..) |off, i| { | 2641 | for (coff.import_tables.keys(), 0..) |off, i| { |
| 2122 | const lib_name = self.temp_strtab.getAssumeExists(off); | 2642 | const lib_name = coff.temp_strtab.getAssumeExists(off); |
| 2123 | const itable = self.import_tables.values()[i]; | 2643 | const itable = coff.import_tables.values()[i]; |
| 2124 | | 2644 | |
| 2125 | // Lookup table header | 2645 | // Lookup table header |
| 2126 | const lookup_header = coff.ImportDirectoryEntry{ | 2646 | const lookup_header = coff_util.ImportDirectoryEntry{ |
| 2127 | .import_lookup_table_rva = header.virtual_address + lookup_table_offset, | 2647 | .import_lookup_table_rva = header.virtual_address + lookup_table_offset, |
| 2128 | .time_date_stamp = 0, | 2648 | .time_date_stamp = 0, |
| 2129 | .forwarder_chain = 0, | 2649 | .forwarder_chain = 0, |
| 2130 | .name_rva = header.virtual_address + dll_names_offset, | 2650 | .name_rva = header.virtual_address + dll_names_offset, |
| 2131 | .import_address_table_rva = header.virtual_address + iat_offset, | 2651 | .import_address_table_rva = header.virtual_address + iat_offset, |
| 2132 | }; | 2652 | }; |
| 2133 | @memcpy(buffer.items[dir_table_offset..][0..@sizeOf(coff.ImportDirectoryEntry)], mem.asBytes(&lookup_header)); | 2653 | @memcpy(buffer.items[dir_table_offset..][0..@sizeOf(coff_util.ImportDirectoryEntry)], mem.asBytes(&lookup_header)); |
| 2134 | dir_table_offset += dir_header_size; | 2654 | dir_table_offset += dir_header_size; |
| 2135 | | 2655 | |
| 2136 | for (itable.entries.items) |entry| { | 2656 | for (itable.entries.items) |entry| { |
| 2137 | const import_name = self.getSymbolName(entry); | 2657 | const import_name = coff.getSymbolName(entry); |
| 2138 | | 2658 | |
| 2139 | // IAT and lookup table entry | 2659 | // IAT and lookup table entry |
| 2140 | const lookup = coff.ImportLookupEntry64.ByName{ .name_table_rva = @as(u31, @intCast(header.virtual_address + names_table_offset)) }; | 2660 | const lookup = coff_util.ImportLookupEntry64.ByName{ .name_table_rva = @as(u31, @intCast(header.virtual_address + names_table_offset)) }; |
| 2141 | @memcpy( | 2661 | @memcpy( |
| 2142 | buffer.items[iat_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)], | 2662 | buffer.items[iat_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)], |
| 2143 | mem.asBytes(&lookup), | 2663 | mem.asBytes(&lookup), |
| 2144 | ); | 2664 | ); |
| 2145 | iat_offset += lookup_entry_size; | 2665 | iat_offset += lookup_entry_size; |
| 2146 | @memcpy( | 2666 | @memcpy( |
| 2147 | buffer.items[lookup_table_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)], | 2667 | buffer.items[lookup_table_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)], |
| 2148 | mem.asBytes(&lookup), | 2668 | mem.asBytes(&lookup), |
| 2149 | ); | 2669 | ); |
| 2150 | lookup_table_offset += lookup_entry_size; | 2670 | lookup_table_offset += lookup_entry_size; |
| ... | @@ -2168,8 +2688,8 @@ fn writeImportTables(self: *Coff) !void { | ... | @@ -2168,8 +2688,8 @@ fn writeImportTables(self: *Coff) !void { |
| 2168 | | 2688 | |
| 2169 | // Lookup table sentinel | 2689 | // Lookup table sentinel |
| 2170 | @memcpy( | 2690 | @memcpy( |
| 2171 | buffer.items[lookup_table_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)], | 2691 | buffer.items[lookup_table_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)], |
| 2172 | mem.asBytes(&coff.ImportLookupEntry64.ByName{ .name_table_rva = 0 }), | 2692 | mem.asBytes(&coff_util.ImportLookupEntry64.ByName{ .name_table_rva = 0 }), |
| 2173 | ); | 2693 | ); |
| 2174 | lookup_table_offset += lookup_entry_size; | 2694 | lookup_table_offset += lookup_entry_size; |
| 2175 | | 2695 | |
| ... | @@ -2183,7 +2703,7 @@ fn writeImportTables(self: *Coff) !void { | ... | @@ -2183,7 +2703,7 @@ fn writeImportTables(self: *Coff) !void { |
| 2183 | } | 2703 | } |
| 2184 | | 2704 | |
| 2185 | // Sentinel | 2705 | // Sentinel |
| 2186 | const lookup_header = coff.ImportDirectoryEntry{ | 2706 | const lookup_header = coff_util.ImportDirectoryEntry{ |
| 2187 | .import_lookup_table_rva = 0, | 2707 | .import_lookup_table_rva = 0, |
| 2188 | .time_date_stamp = 0, | 2708 | .time_date_stamp = 0, |
| 2189 | .forwarder_chain = 0, | 2709 | .forwarder_chain = 0, |
| ... | @@ -2191,93 +2711,93 @@ fn writeImportTables(self: *Coff) !void { | ... | @@ -2191,93 +2711,93 @@ fn writeImportTables(self: *Coff) !void { |
| 2191 | .import_address_table_rva = 0, | 2711 | .import_address_table_rva = 0, |
| 2192 | }; | 2712 | }; |
| 2193 | @memcpy( | 2713 | @memcpy( |
| 2194 | buffer.items[dir_table_offset..][0..@sizeOf(coff.ImportDirectoryEntry)], | 2714 | buffer.items[dir_table_offset..][0..@sizeOf(coff_util.ImportDirectoryEntry)], |
| 2195 | mem.asBytes(&lookup_header), | 2715 | mem.asBytes(&lookup_header), |
| 2196 | ); | 2716 | ); |
| 2197 | dir_table_offset += dir_header_size; | 2717 | dir_table_offset += dir_header_size; |
| 2198 | | 2718 | |
| 2199 | assert(dll_names_offset == needed_size); | 2719 | assert(dll_names_offset == needed_size); |
| 2200 | | 2720 | |
| 2201 | try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data); | 2721 | try coff.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data); |
| 2202 | | 2722 | |
| 2203 | self.data_directories[@intFromEnum(coff.DirectoryEntry.IMPORT)] = .{ | 2723 | coff.data_directories[@intFromEnum(coff_util.DirectoryEntry.IMPORT)] = .{ |
| 2204 | .virtual_address = header.virtual_address + iat_size, | 2724 | .virtual_address = header.virtual_address + iat_size, |
| 2205 | .size = dir_table_size, | 2725 | .size = dir_table_size, |
| 2206 | }; | 2726 | }; |
| 2207 | self.data_directories[@intFromEnum(coff.DirectoryEntry.IAT)] = .{ | 2727 | coff.data_directories[@intFromEnum(coff_util.DirectoryEntry.IAT)] = .{ |
| 2208 | .virtual_address = header.virtual_address, | 2728 | .virtual_address = header.virtual_address, |
| 2209 | .size = iat_size, | 2729 | .size = iat_size, |
| 2210 | }; | 2730 | }; |
| 2211 | | 2731 | |
| 2212 | self.imports_count_dirty = false; | 2732 | coff.imports_count_dirty = false; |
| 2213 | } | 2733 | } |
| 2214 | | 2734 | |
| 2215 | fn writeStrtab(self: *Coff) !void { | 2735 | fn writeStrtab(coff: *Coff) !void { |
| 2216 | if (self.strtab_offset == null) return; | 2736 | if (coff.strtab_offset == null) return; |
| 2217 | | 2737 | |
| 2218 | const allocated_size = self.allocatedSize(self.strtab_offset.?); | 2738 | const allocated_size = coff.allocatedSize(coff.strtab_offset.?); |
| 2219 | const needed_size = @as(u32, @intCast(self.strtab.buffer.items.len)); | 2739 | const needed_size = @as(u32, @intCast(coff.strtab.buffer.items.len)); |
| 2220 | | 2740 | |
| 2221 | if (needed_size > allocated_size) { | 2741 | if (needed_size > allocated_size) { |
| 2222 | self.strtab_offset = null; | 2742 | coff.strtab_offset = null; |
| 2223 | self.strtab_offset = @as(u32, @intCast(self.findFreeSpace(needed_size, @alignOf(u32)))); | 2743 | coff.strtab_offset = @as(u32, @intCast(coff.findFreeSpace(needed_size, @alignOf(u32)))); |
| 2224 | } | 2744 | } |
| 2225 | | 2745 | |
| 2226 | log.debug("writing strtab from 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + needed_size }); | 2746 | log.debug("writing strtab from 0x{x} to 0x{x}", .{ coff.strtab_offset.?, coff.strtab_offset.? + needed_size }); |
| 2227 | | 2747 | |
| 2228 | const gpa = self.base.comp.gpa; | 2748 | const gpa = coff.base.comp.gpa; |
| 2229 | var buffer = std.ArrayList(u8).init(gpa); | 2749 | var buffer = std.ArrayList(u8).init(gpa); |
| 2230 | defer buffer.deinit(); | 2750 | defer buffer.deinit(); |
| 2231 | try buffer.ensureTotalCapacityPrecise(needed_size); | 2751 | try buffer.ensureTotalCapacityPrecise(needed_size); |
| 2232 | buffer.appendSliceAssumeCapacity(self.strtab.buffer.items); | 2752 | buffer.appendSliceAssumeCapacity(coff.strtab.buffer.items); |
| 2233 | // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead | 2753 | // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead |
| 2234 | // we write the length of the strtab to a temporary buffer that goes to file. | 2754 | // we write the length of the strtab to a temporary buffer that goes to file. |
| 2235 | mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(self.strtab.buffer.items.len)), .little); | 2755 | mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(coff.strtab.buffer.items.len)), .little); |
| 2236 | | 2756 | |
| 2237 | try self.base.file.?.pwriteAll(buffer.items, self.strtab_offset.?); | 2757 | try coff.base.file.?.pwriteAll(buffer.items, coff.strtab_offset.?); |
| 2238 | } | 2758 | } |
| 2239 | | 2759 | |
| 2240 | fn writeSectionHeaders(self: *Coff) !void { | 2760 | fn writeSectionHeaders(coff: *Coff) !void { |
| 2241 | const offset = self.getSectionHeadersOffset(); | 2761 | const offset = coff.getSectionHeadersOffset(); |
| 2242 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items(.header)), offset); | 2762 | try coff.base.file.?.pwriteAll(mem.sliceAsBytes(coff.sections.items(.header)), offset); |
| 2243 | } | 2763 | } |
| 2244 | | 2764 | |
| 2245 | fn writeDataDirectoriesHeaders(self: *Coff) !void { | 2765 | fn writeDataDirectoriesHeaders(coff: *Coff) !void { |
| 2246 | const offset = self.getDataDirectoryHeadersOffset(); | 2766 | const offset = coff.getDataDirectoryHeadersOffset(); |
| 2247 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(&self.data_directories), offset); | 2767 | try coff.base.file.?.pwriteAll(mem.sliceAsBytes(&coff.data_directories), offset); |
| 2248 | } | 2768 | } |
| 2249 | | 2769 | |
| 2250 | fn writeHeader(self: *Coff) !void { | 2770 | fn writeHeader(coff: *Coff) !void { |
| 2251 | const target = self.base.comp.root_mod.resolved_target.result; | 2771 | const target = coff.base.comp.root_mod.resolved_target.result; |
| 2252 | const gpa = self.base.comp.gpa; | 2772 | const gpa = coff.base.comp.gpa; |
| 2253 | var buffer = std.ArrayList(u8).init(gpa); | 2773 | var buffer = std.ArrayList(u8).init(gpa); |
| 2254 | defer buffer.deinit(); | 2774 | defer buffer.deinit(); |
| 2255 | const writer = buffer.writer(); | 2775 | const writer = buffer.writer(); |
| 2256 | | 2776 | |
| 2257 | try buffer.ensureTotalCapacity(self.getSizeOfHeaders()); | 2777 | try buffer.ensureTotalCapacity(coff.getSizeOfHeaders()); |
| 2258 | writer.writeAll(msdos_stub) catch unreachable; | 2778 | writer.writeAll(msdos_stub) catch unreachable; |
| 2259 | mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little); | 2779 | mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little); |
| 2260 | | 2780 | |
| 2261 | writer.writeAll("PE\x00\x00") catch unreachable; | 2781 | writer.writeAll("PE\x00\x00") catch unreachable; |
| 2262 | var flags = coff.CoffHeaderFlags{ | 2782 | var flags = coff_util.CoffHeaderFlags{ |
| 2263 | .EXECUTABLE_IMAGE = 1, | 2783 | .EXECUTABLE_IMAGE = 1, |
| 2264 | .DEBUG_STRIPPED = 1, // TODO | 2784 | .DEBUG_STRIPPED = 1, // TODO |
| 2265 | }; | 2785 | }; |
| 2266 | switch (self.ptr_width) { | 2786 | switch (coff.ptr_width) { |
| 2267 | .p32 => flags.@"32BIT_MACHINE" = 1, | 2787 | .p32 => flags.@"32BIT_MACHINE" = 1, |
| 2268 | .p64 => flags.LARGE_ADDRESS_AWARE = 1, | 2788 | .p64 => flags.LARGE_ADDRESS_AWARE = 1, |
| 2269 | } | 2789 | } |
| 2270 | if (self.base.comp.config.output_mode == .Lib and self.base.comp.config.link_mode == .dynamic) { | 2790 | if (coff.base.comp.config.output_mode == .Lib and coff.base.comp.config.link_mode == .dynamic) { |
| 2271 | flags.DLL = 1; | 2791 | flags.DLL = 1; |
| 2272 | } | 2792 | } |
| 2273 | | 2793 | |
| 2274 | const timestamp = if (self.repro) 0 else std.time.timestamp(); | 2794 | const timestamp = if (coff.repro) 0 else std.time.timestamp(); |
| 2275 | const size_of_optional_header = @as(u16, @intCast(self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize())); | 2795 | const size_of_optional_header = @as(u16, @intCast(coff.getOptionalHeaderSize() + coff.getDataDirectoryHeadersSize())); |
| 2276 | var coff_header = coff.CoffHeader{ | 2796 | var coff_header = coff_util.CoffHeader{ |
| 2277 | .machine = target.toCoffMachine(), | 2797 | .machine = target.toCoffMachine(), |
| 2278 | .number_of_sections = @as(u16, @intCast(self.sections.slice().len)), // TODO what if we prune a section | 2798 | .number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section |
| 2279 | .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))), | 2799 | .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))), |
| 2280 | .pointer_to_symbol_table = self.strtab_offset orelse 0, | 2800 | .pointer_to_symbol_table = coff.strtab_offset orelse 0, |
| 2281 | .number_of_symbols = 0, | 2801 | .number_of_symbols = 0, |
| 2282 | .size_of_optional_header = size_of_optional_header, | 2802 | .size_of_optional_header = size_of_optional_header, |
| 2283 | .flags = flags, | 2803 | .flags = flags, |
| ... | @@ -2285,22 +2805,22 @@ fn writeHeader(self: *Coff) !void { | ... | @@ -2285,22 +2805,22 @@ fn writeHeader(self: *Coff) !void { |
| 2285 | | 2805 | |
| 2286 | writer.writeAll(mem.asBytes(&coff_header)) catch unreachable; | 2806 | writer.writeAll(mem.asBytes(&coff_header)) catch unreachable; |
| 2287 | | 2807 | |
| 2288 | const dll_flags: coff.DllFlags = .{ | 2808 | const dll_flags: coff_util.DllFlags = .{ |
| 2289 | .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all? | 2809 | .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all? |
| 2290 | .DYNAMIC_BASE = 1, | 2810 | .DYNAMIC_BASE = 1, |
| 2291 | .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app | 2811 | .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app |
| 2292 | .NX_COMPAT = 1, // We are compatible with Data Execution Prevention | 2812 | .NX_COMPAT = 1, // We are compatible with Data Execution Prevention |
| 2293 | }; | 2813 | }; |
| 2294 | const subsystem: coff.Subsystem = .WINDOWS_CUI; | 2814 | const subsystem: coff_util.Subsystem = .WINDOWS_CUI; |
| 2295 | const size_of_image: u32 = self.getSizeOfImage(); | 2815 | const size_of_image: u32 = coff.getSizeOfImage(); |
| 2296 | const size_of_headers: u32 = mem.alignForward(u32, self.getSizeOfHeaders(), default_file_alignment); | 2816 | const size_of_headers: u32 = mem.alignForward(u32, coff.getSizeOfHeaders(), default_file_alignment); |
| 2297 | const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address; | 2817 | const base_of_code = coff.sections.get(coff.text_section_index.?).header.virtual_address; |
| 2298 | const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address; | 2818 | const base_of_data = coff.sections.get(coff.data_section_index.?).header.virtual_address; |
| 2299 | | 2819 | |
| 2300 | var size_of_code: u32 = 0; | 2820 | var size_of_code: u32 = 0; |
| 2301 | var size_of_initialized_data: u32 = 0; | 2821 | var size_of_initialized_data: u32 = 0; |
| 2302 | var size_of_uninitialized_data: u32 = 0; | 2822 | var size_of_uninitialized_data: u32 = 0; |
| 2303 | for (self.sections.items(.header)) |header| { | 2823 | for (coff.sections.items(.header)) |header| { |
| 2304 | if (header.flags.CNT_CODE == 1) { | 2824 | if (header.flags.CNT_CODE == 1) { |
| 2305 | size_of_code += header.size_of_raw_data; | 2825 | size_of_code += header.size_of_raw_data; |
| 2306 | } | 2826 | } |
| ... | @@ -2312,27 +2832,27 @@ fn writeHeader(self: *Coff) !void { | ... | @@ -2312,27 +2832,27 @@ fn writeHeader(self: *Coff) !void { |
| 2312 | } | 2832 | } |
| 2313 | } | 2833 | } |
| 2314 | | 2834 | |
| 2315 | switch (self.ptr_width) { | 2835 | switch (coff.ptr_width) { |
| 2316 | .p32 => { | 2836 | .p32 => { |
| 2317 | var opt_header = coff.OptionalHeaderPE32{ | 2837 | var opt_header = coff_util.OptionalHeaderPE32{ |
| 2318 | .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC, | 2838 | .magic = coff_util.IMAGE_NT_OPTIONAL_HDR32_MAGIC, |
| 2319 | .major_linker_version = 0, | 2839 | .major_linker_version = 0, |
| 2320 | .minor_linker_version = 0, | 2840 | .minor_linker_version = 0, |
| 2321 | .size_of_code = size_of_code, | 2841 | .size_of_code = size_of_code, |
| 2322 | .size_of_initialized_data = size_of_initialized_data, | 2842 | .size_of_initialized_data = size_of_initialized_data, |
| 2323 | .size_of_uninitialized_data = size_of_uninitialized_data, | 2843 | .size_of_uninitialized_data = size_of_uninitialized_data, |
| 2324 | .address_of_entry_point = self.entry_addr orelse 0, | 2844 | .address_of_entry_point = coff.entry_addr orelse 0, |
| 2325 | .base_of_code = base_of_code, | 2845 | .base_of_code = base_of_code, |
| 2326 | .base_of_data = base_of_data, | 2846 | .base_of_data = base_of_data, |
| 2327 | .image_base = @intCast(self.image_base), | 2847 | .image_base = @intCast(coff.image_base), |
| 2328 | .section_alignment = self.page_size, | 2848 | .section_alignment = coff.page_size, |
| 2329 | .file_alignment = default_file_alignment, | 2849 | .file_alignment = default_file_alignment, |
| 2330 | .major_operating_system_version = 6, | 2850 | .major_operating_system_version = 6, |
| 2331 | .minor_operating_system_version = 0, | 2851 | .minor_operating_system_version = 0, |
| 2332 | .major_image_version = 0, | 2852 | .major_image_version = 0, |
| 2333 | .minor_image_version = 0, | 2853 | .minor_image_version = 0, |
| 2334 | .major_subsystem_version = @intCast(self.major_subsystem_version), | 2854 | .major_subsystem_version = @intCast(coff.major_subsystem_version), |
| 2335 | .minor_subsystem_version = @intCast(self.minor_subsystem_version), | 2855 | .minor_subsystem_version = @intCast(coff.minor_subsystem_version), |
| 2336 | .win32_version_value = 0, | 2856 | .win32_version_value = 0, |
| 2337 | .size_of_image = size_of_image, | 2857 | .size_of_image = size_of_image, |
| 2338 | .size_of_headers = size_of_headers, | 2858 | .size_of_headers = size_of_headers, |
| ... | @@ -2344,29 +2864,29 @@ fn writeHeader(self: *Coff) !void { | ... | @@ -2344,29 +2864,29 @@ fn writeHeader(self: *Coff) !void { |
| 2344 | .size_of_heap_reserve = default_size_of_heap_reserve, | 2864 | .size_of_heap_reserve = default_size_of_heap_reserve, |
| 2345 | .size_of_heap_commit = default_size_of_heap_commit, | 2865 | .size_of_heap_commit = default_size_of_heap_commit, |
| 2346 | .loader_flags = 0, | 2866 | .loader_flags = 0, |
| 2347 | .number_of_rva_and_sizes = @intCast(self.data_directories.len), | 2867 | .number_of_rva_and_sizes = @intCast(coff.data_directories.len), |
| 2348 | }; | 2868 | }; |
| 2349 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; | 2869 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; |
| 2350 | }, | 2870 | }, |
| 2351 | .p64 => { | 2871 | .p64 => { |
| 2352 | var opt_header = coff.OptionalHeaderPE64{ | 2872 | var opt_header = coff_util.OptionalHeaderPE64{ |
| 2353 | .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC, | 2873 | .magic = coff_util.IMAGE_NT_OPTIONAL_HDR64_MAGIC, |
| 2354 | .major_linker_version = 0, | 2874 | .major_linker_version = 0, |
| 2355 | .minor_linker_version = 0, | 2875 | .minor_linker_version = 0, |
| 2356 | .size_of_code = size_of_code, | 2876 | .size_of_code = size_of_code, |
| 2357 | .size_of_initialized_data = size_of_initialized_data, | 2877 | .size_of_initialized_data = size_of_initialized_data, |
| 2358 | .size_of_uninitialized_data = size_of_uninitialized_data, | 2878 | .size_of_uninitialized_data = size_of_uninitialized_data, |
| 2359 | .address_of_entry_point = self.entry_addr orelse 0, | 2879 | .address_of_entry_point = coff.entry_addr orelse 0, |
| 2360 | .base_of_code = base_of_code, | 2880 | .base_of_code = base_of_code, |
| 2361 | .image_base = self.image_base, | 2881 | .image_base = coff.image_base, |
| 2362 | .section_alignment = self.page_size, | 2882 | .section_alignment = coff.page_size, |
| 2363 | .file_alignment = default_file_alignment, | 2883 | .file_alignment = default_file_alignment, |
| 2364 | .major_operating_system_version = 6, | 2884 | .major_operating_system_version = 6, |
| 2365 | .minor_operating_system_version = 0, | 2885 | .minor_operating_system_version = 0, |
| 2366 | .major_image_version = 0, | 2886 | .major_image_version = 0, |
| 2367 | .minor_image_version = 0, | 2887 | .minor_image_version = 0, |
| 2368 | .major_subsystem_version = self.major_subsystem_version, | 2888 | .major_subsystem_version = coff.major_subsystem_version, |
| 2369 | .minor_subsystem_version = self.minor_subsystem_version, | 2889 | .minor_subsystem_version = coff.minor_subsystem_version, |
| 2370 | .win32_version_value = 0, | 2890 | .win32_version_value = 0, |
| 2371 | .size_of_image = size_of_image, | 2891 | .size_of_image = size_of_image, |
| 2372 | .size_of_headers = size_of_headers, | 2892 | .size_of_headers = size_of_headers, |
| ... | @@ -2378,28 +2898,28 @@ fn writeHeader(self: *Coff) !void { | ... | @@ -2378,28 +2898,28 @@ fn writeHeader(self: *Coff) !void { |
| 2378 | .size_of_heap_reserve = default_size_of_heap_reserve, | 2898 | .size_of_heap_reserve = default_size_of_heap_reserve, |
| 2379 | .size_of_heap_commit = default_size_of_heap_commit, | 2899 | .size_of_heap_commit = default_size_of_heap_commit, |
| 2380 | .loader_flags = 0, | 2900 | .loader_flags = 0, |
| 2381 | .number_of_rva_and_sizes = @intCast(self.data_directories.len), | 2901 | .number_of_rva_and_sizes = @intCast(coff.data_directories.len), |
| 2382 | }; | 2902 | }; |
| 2383 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; | 2903 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; |
| 2384 | }, | 2904 | }, |
| 2385 | } | 2905 | } |
| 2386 | | 2906 | |
| 2387 | try self.base.file.?.pwriteAll(buffer.items, 0); | 2907 | try coff.base.file.?.pwriteAll(buffer.items, 0); |
| 2388 | } | 2908 | } |
| 2389 | | 2909 | |
| 2390 | pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { | 2910 | pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 2391 | return actual_size +| (actual_size / ideal_factor); | 2911 | return actual_size +| (actual_size / ideal_factor); |
| 2392 | } | 2912 | } |
| 2393 | | 2913 | |
| 2394 | fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 { | 2914 | fn detectAllocCollision(coff: *Coff, start: u32, size: u32) ?u32 { |
| 2395 | const headers_size = @max(self.getSizeOfHeaders(), self.page_size); | 2915 | const headers_size = @max(coff.getSizeOfHeaders(), coff.page_size); |
| 2396 | if (start < headers_size) | 2916 | if (start < headers_size) |
| 2397 | return headers_size; | 2917 | return headers_size; |
| 2398 | | 2918 | |
| 2399 | const end = start + padToIdeal(size); | 2919 | const end = start + padToIdeal(size); |
| 2400 | | 2920 | |
| 2401 | if (self.strtab_offset) |off| { | 2921 | if (coff.strtab_offset) |off| { |
| 2402 | const tight_size = @as(u32, @intCast(self.strtab.buffer.items.len)); | 2922 | const tight_size = @as(u32, @intCast(coff.strtab.buffer.items.len)); |
| 2403 | const increased_size = padToIdeal(tight_size); | 2923 | const increased_size = padToIdeal(tight_size); |
| 2404 | const test_end = off + increased_size; | 2924 | const test_end = off + increased_size; |
| 2405 | if (end > off and start < test_end) { | 2925 | if (end > off and start < test_end) { |
| ... | @@ -2407,7 +2927,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 { | ... | @@ -2407,7 +2927,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 { |
| 2407 | } | 2927 | } |
| 2408 | } | 2928 | } |
| 2409 | | 2929 | |
| 2410 | for (self.sections.items(.header)) |header| { | 2930 | for (coff.sections.items(.header)) |header| { |
| 2411 | const tight_size = header.size_of_raw_data; | 2931 | const tight_size = header.size_of_raw_data; |
| 2412 | const increased_size = padToIdeal(tight_size); | 2932 | const increased_size = padToIdeal(tight_size); |
| 2413 | const test_end = header.pointer_to_raw_data + increased_size; | 2933 | const test_end = header.pointer_to_raw_data + increased_size; |
| ... | @@ -2419,86 +2939,86 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 { | ... | @@ -2419,86 +2939,86 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 { |
| 2419 | return null; | 2939 | return null; |
| 2420 | } | 2940 | } |
| 2421 | | 2941 | |
| 2422 | fn allocatedSize(self: *Coff, start: u32) u32 { | 2942 | fn allocatedSize(coff: *Coff, start: u32) u32 { |
| 2423 | if (start == 0) | 2943 | if (start == 0) |
| 2424 | return 0; | 2944 | return 0; |
| 2425 | var min_pos: u32 = std.math.maxInt(u32); | 2945 | var min_pos: u32 = std.math.maxInt(u32); |
| 2426 | if (self.strtab_offset) |off| { | 2946 | if (coff.strtab_offset) |off| { |
| 2427 | if (off > start and off < min_pos) min_pos = off; | 2947 | if (off > start and off < min_pos) min_pos = off; |
| 2428 | } | 2948 | } |
| 2429 | for (self.sections.items(.header)) |header| { | 2949 | for (coff.sections.items(.header)) |header| { |
| 2430 | if (header.pointer_to_raw_data <= start) continue; | 2950 | if (header.pointer_to_raw_data <= start) continue; |
| 2431 | if (header.pointer_to_raw_data < min_pos) min_pos = header.pointer_to_raw_data; | 2951 | if (header.pointer_to_raw_data < min_pos) min_pos = header.pointer_to_raw_data; |
| 2432 | } | 2952 | } |
| 2433 | return min_pos - start; | 2953 | return min_pos - start; |
| 2434 | } | 2954 | } |
| 2435 | | 2955 | |
| 2436 | fn findFreeSpace(self: *Coff, object_size: u32, min_alignment: u32) u32 { | 2956 | fn findFreeSpace(coff: *Coff, object_size: u32, min_alignment: u32) u32 { |
| 2437 | var start: u32 = 0; | 2957 | var start: u32 = 0; |
| 2438 | while (self.detectAllocCollision(start, object_size)) |item_end| { | 2958 | while (coff.detectAllocCollision(start, object_size)) |item_end| { |
| 2439 | start = mem.alignForward(u32, item_end, min_alignment); | 2959 | start = mem.alignForward(u32, item_end, min_alignment); |
| 2440 | } | 2960 | } |
| 2441 | return start; | 2961 | return start; |
| 2442 | } | 2962 | } |
| 2443 | | 2963 | |
| 2444 | fn allocatedVirtualSize(self: *Coff, start: u32) u32 { | 2964 | fn allocatedVirtualSize(coff: *Coff, start: u32) u32 { |
| 2445 | if (start == 0) | 2965 | if (start == 0) |
| 2446 | return 0; | 2966 | return 0; |
| 2447 | var min_pos: u32 = std.math.maxInt(u32); | 2967 | var min_pos: u32 = std.math.maxInt(u32); |
| 2448 | for (self.sections.items(.header)) |header| { | 2968 | for (coff.sections.items(.header)) |header| { |
| 2449 | if (header.virtual_address <= start) continue; | 2969 | if (header.virtual_address <= start) continue; |
| 2450 | if (header.virtual_address < min_pos) min_pos = header.virtual_address; | 2970 | if (header.virtual_address < min_pos) min_pos = header.virtual_address; |
| 2451 | } | 2971 | } |
| 2452 | return min_pos - start; | 2972 | return min_pos - start; |
| 2453 | } | 2973 | } |
| 2454 | | 2974 | |
| 2455 | inline fn getSizeOfHeaders(self: Coff) u32 { | 2975 | fn getSizeOfHeaders(coff: Coff) u32 { |
| 2456 | const msdos_hdr_size = msdos_stub.len + 4; | 2976 | const msdos_hdr_size = msdos_stub.len + 4; |
| 2457 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() + | 2977 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize() + |
| 2458 | self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize())); | 2978 | coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize())); |
| 2459 | } | 2979 | } |
| 2460 | | 2980 | |
| 2461 | inline fn getOptionalHeaderSize(self: Coff) u32 { | 2981 | fn getOptionalHeaderSize(coff: Coff) u32 { |
| 2462 | return switch (self.ptr_width) { | 2982 | return switch (coff.ptr_width) { |
| 2463 | .p32 => @as(u32, @intCast(@sizeOf(coff.OptionalHeaderPE32))), | 2983 | .p32 => @as(u32, @intCast(@sizeOf(coff_util.OptionalHeaderPE32))), |
| 2464 | .p64 => @as(u32, @intCast(@sizeOf(coff.OptionalHeaderPE64))), | 2984 | .p64 => @as(u32, @intCast(@sizeOf(coff_util.OptionalHeaderPE64))), |
| 2465 | }; | 2985 | }; |
| 2466 | } | 2986 | } |
| 2467 | | 2987 | |
| 2468 | inline fn getDataDirectoryHeadersSize(self: Coff) u32 { | 2988 | fn getDataDirectoryHeadersSize(coff: Coff) u32 { |
| 2469 | return @as(u32, @intCast(self.data_directories.len * @sizeOf(coff.ImageDataDirectory))); | 2989 | return @as(u32, @intCast(coff.data_directories.len * @sizeOf(coff_util.ImageDataDirectory))); |
| 2470 | } | 2990 | } |
| 2471 | | 2991 | |
| 2472 | inline fn getSectionHeadersSize(self: Coff) u32 { | 2992 | fn getSectionHeadersSize(coff: Coff) u32 { |
| 2473 | return @as(u32, @intCast(self.sections.slice().len * @sizeOf(coff.SectionHeader))); | 2993 | return @as(u32, @intCast(coff.sections.slice().len * @sizeOf(coff_util.SectionHeader))); |
| 2474 | } | 2994 | } |
| 2475 | | 2995 | |
| 2476 | inline fn getDataDirectoryHeadersOffset(self: Coff) u32 { | 2996 | fn getDataDirectoryHeadersOffset(coff: Coff) u32 { |
| 2477 | const msdos_hdr_size = msdos_stub.len + 4; | 2997 | const msdos_hdr_size = msdos_stub.len + 4; |
| 2478 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize())); | 2998 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize())); |
| 2479 | } | 2999 | } |
| 2480 | | 3000 | |
| 2481 | inline fn getSectionHeadersOffset(self: Coff) u32 { | 3001 | fn getSectionHeadersOffset(coff: Coff) u32 { |
| 2482 | return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize(); | 3002 | return coff.getDataDirectoryHeadersOffset() + coff.getDataDirectoryHeadersSize(); |
| 2483 | } | 3003 | } |
| 2484 | | 3004 | |
| 2485 | inline fn getSizeOfImage(self: Coff) u32 { | 3005 | fn getSizeOfImage(coff: Coff) u32 { |
| 2486 | var image_size: u32 = mem.alignForward(u32, self.getSizeOfHeaders(), self.page_size); | 3006 | var image_size: u32 = mem.alignForward(u32, coff.getSizeOfHeaders(), coff.page_size); |
| 2487 | for (self.sections.items(.header)) |header| { | 3007 | for (coff.sections.items(.header)) |header| { |
| 2488 | image_size += mem.alignForward(u32, header.virtual_size, self.page_size); | 3008 | image_size += mem.alignForward(u32, header.virtual_size, coff.page_size); |
| 2489 | } | 3009 | } |
| 2490 | return image_size; | 3010 | return image_size; |
| 2491 | } | 3011 | } |
| 2492 | | 3012 | |
| 2493 | /// Returns symbol location corresponding to the set entrypoint (if any). | 3013 | /// Returns symbol location corresponding to the set entrypoint (if any). |
| 2494 | pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { | 3014 | pub fn getEntryPoint(coff: Coff) ?SymbolWithLoc { |
| 2495 | const comp = self.base.comp; | 3015 | const comp = coff.base.comp; |
| 2496 | | 3016 | |
| 2497 | // TODO This is incomplete. | 3017 | // TODO This is incomplete. |
| 2498 | // The entry symbol name depends on the subsystem as well as the set of | 3018 | // The entry symbol name depends on the subsystem as well as the set of |
| 2499 | // public symbol names from linked objects. | 3019 | // public symbol names from linked objects. |
| 2500 | // See LinkerDriver::findDefaultEntry from the LLD project for the flow chart. | 3020 | // See LinkerDriver::findDefaultEntry from the LLD project for the flow chart. |
| 2501 | const entry_name = switch (self.entry) { | 3021 | const entry_name = switch (coff.entry) { |
| 2502 | .disabled => return null, | 3022 | .disabled => return null, |
| 2503 | .default => switch (comp.config.output_mode) { | 3023 | .default => switch (comp.config.output_mode) { |
| 2504 | .Exe => "wWinMainCRTStartup", | 3024 | .Exe => "wWinMainCRTStartup", |
| ... | @@ -2507,51 +3027,51 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { | ... | @@ -2507,51 +3027,51 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { |
| 2507 | .enabled => "wWinMainCRTStartup", | 3027 | .enabled => "wWinMainCRTStartup", |
| 2508 | .named => |name| name, | 3028 | .named => |name| name, |
| 2509 | }; | 3029 | }; |
| 2510 | const global_index = self.resolver.get(entry_name) orelse return null; | 3030 | const global_index = coff.resolver.get(entry_name) orelse return null; |
| 2511 | return self.globals.items[global_index]; | 3031 | return coff.globals.items[global_index]; |
| 2512 | } | 3032 | } |
| 2513 | | 3033 | |
| 2514 | /// Returns pointer-to-symbol described by `sym_loc` descriptor. | 3034 | /// Returns pointer-to-symbol described by `sym_loc` descriptor. |
| 2515 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { | 3035 | pub fn getSymbolPtr(coff: *Coff, sym_loc: SymbolWithLoc) *coff_util.Symbol { |
| 2516 | assert(sym_loc.file == null); // TODO linking object files | 3036 | assert(sym_loc.file == null); // TODO linking object files |
| 2517 | return &self.locals.items[sym_loc.sym_index]; | 3037 | return &coff.locals.items[sym_loc.sym_index]; |
| 2518 | } | 3038 | } |
| 2519 | | 3039 | |
| 2520 | /// Returns symbol described by `sym_loc` descriptor. | 3040 | /// Returns symbol described by `sym_loc` descriptor. |
| 2521 | pub fn getSymbol(self: *const Coff, sym_loc: SymbolWithLoc) *const coff.Symbol { | 3041 | pub fn getSymbol(coff: *const Coff, sym_loc: SymbolWithLoc) *const coff_util.Symbol { |
| 2522 | assert(sym_loc.file == null); // TODO linking object files | 3042 | assert(sym_loc.file == null); // TODO linking object files |
| 2523 | return &self.locals.items[sym_loc.sym_index]; | 3043 | return &coff.locals.items[sym_loc.sym_index]; |
| 2524 | } | 3044 | } |
| 2525 | | 3045 | |
| 2526 | /// Returns name of the symbol described by `sym_loc` descriptor. | 3046 | /// Returns name of the symbol described by `sym_loc` descriptor. |
| 2527 | pub fn getSymbolName(self: *const Coff, sym_loc: SymbolWithLoc) []const u8 { | 3047 | pub fn getSymbolName(coff: *const Coff, sym_loc: SymbolWithLoc) []const u8 { |
| 2528 | assert(sym_loc.file == null); // TODO linking object files | 3048 | assert(sym_loc.file == null); // TODO linking object files |
| 2529 | const sym = self.getSymbol(sym_loc); | 3049 | const sym = coff.getSymbol(sym_loc); |
| 2530 | const offset = sym.getNameOffset() orelse return sym.getName().?; | 3050 | const offset = sym.getNameOffset() orelse return sym.getName().?; |
| 2531 | return self.strtab.get(offset).?; | 3051 | return coff.strtab.get(offset).?; |
| 2532 | } | 3052 | } |
| 2533 | | 3053 | |
| 2534 | /// Returns pointer to the global entry for `name` if one exists. | 3054 | /// Returns pointer to the global entry for `name` if one exists. |
| 2535 | pub fn getGlobalPtr(self: *Coff, name: []const u8) ?*SymbolWithLoc { | 3055 | pub fn getGlobalPtr(coff: *Coff, name: []const u8) ?*SymbolWithLoc { |
| 2536 | const global_index = self.resolver.get(name) orelse return null; | 3056 | const global_index = coff.resolver.get(name) orelse return null; |
| 2537 | return &self.globals.items[global_index]; | 3057 | return &coff.globals.items[global_index]; |
| 2538 | } | 3058 | } |
| 2539 | | 3059 | |
| 2540 | /// Returns the global entry for `name` if one exists. | 3060 | /// Returns the global entry for `name` if one exists. |
| 2541 | pub fn getGlobal(self: *const Coff, name: []const u8) ?SymbolWithLoc { | 3061 | pub fn getGlobal(coff: *const Coff, name: []const u8) ?SymbolWithLoc { |
| 2542 | const global_index = self.resolver.get(name) orelse return null; | 3062 | const global_index = coff.resolver.get(name) orelse return null; |
| 2543 | return self.globals.items[global_index]; | 3063 | return coff.globals.items[global_index]; |
| 2544 | } | 3064 | } |
| 2545 | | 3065 | |
| 2546 | /// Returns the index of the global entry for `name` if one exists. | 3066 | /// Returns the index of the global entry for `name` if one exists. |
| 2547 | pub fn getGlobalIndex(self: *const Coff, name: []const u8) ?u32 { | 3067 | pub fn getGlobalIndex(coff: *const Coff, name: []const u8) ?u32 { |
| 2548 | return self.resolver.get(name); | 3068 | return coff.resolver.get(name); |
| 2549 | } | 3069 | } |
| 2550 | | 3070 | |
| 2551 | /// Returns global entry at `index`. | 3071 | /// Returns global entry at `index`. |
| 2552 | pub fn getGlobalByIndex(self: *const Coff, index: u32) SymbolWithLoc { | 3072 | pub fn getGlobalByIndex(coff: *const Coff, index: u32) SymbolWithLoc { |
| 2553 | assert(index < self.globals.items.len); | 3073 | assert(index < coff.globals.items.len); |
| 2554 | return self.globals.items[index]; | 3074 | return coff.globals.items[index]; |
| 2555 | } | 3075 | } |
| 2556 | | 3076 | |
| 2557 | const GetOrPutGlobalPtrResult = struct { | 3077 | const GetOrPutGlobalPtrResult = struct { |
| ... | @@ -2567,68 +3087,68 @@ pub const global_symbol_mask: u32 = 0x7fffffff; | ... | @@ -2567,68 +3087,68 @@ pub const global_symbol_mask: u32 = 0x7fffffff; |
| 2567 | /// Return pointer to the global entry for `name` if one exists. | 3087 | /// Return pointer to the global entry for `name` if one exists. |
| 2568 | /// Puts a new global entry for `name` if one doesn't exist, and | 3088 | /// Puts a new global entry for `name` if one doesn't exist, and |
| 2569 | /// returns a pointer to it. | 3089 | /// returns a pointer to it. |
| 2570 | pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult { | 3090 | pub fn getOrPutGlobalPtr(coff: *Coff, name: []const u8) !GetOrPutGlobalPtrResult { |
| 2571 | if (self.getGlobalPtr(name)) |ptr| { | 3091 | if (coff.getGlobalPtr(name)) |ptr| { |
| 2572 | return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr }; | 3092 | return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr }; |
| 2573 | } | 3093 | } |
| 2574 | const gpa = self.base.comp.gpa; | 3094 | const gpa = coff.base.comp.gpa; |
| 2575 | const global_index = try self.allocateGlobal(); | 3095 | const global_index = try coff.allocateGlobal(); |
| 2576 | const global_name = try gpa.dupe(u8, name); | 3096 | const global_name = try gpa.dupe(u8, name); |
| 2577 | _ = try self.resolver.put(gpa, global_name, global_index); | 3097 | _ = try coff.resolver.put(gpa, global_name, global_index); |
| 2578 | const ptr = &self.globals.items[global_index]; | 3098 | const ptr = &coff.globals.items[global_index]; |
| 2579 | return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr }; | 3099 | return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr }; |
| 2580 | } | 3100 | } |
| 2581 | | 3101 | |
| 2582 | pub fn getAtom(self: *const Coff, atom_index: Atom.Index) Atom { | 3102 | pub fn getAtom(coff: *const Coff, atom_index: Atom.Index) Atom { |
| 2583 | assert(atom_index < self.atoms.items.len); | 3103 | assert(atom_index < coff.atoms.items.len); |
| 2584 | return self.atoms.items[atom_index]; | 3104 | return coff.atoms.items[atom_index]; |
| 2585 | } | 3105 | } |
| 2586 | | 3106 | |
| 2587 | pub fn getAtomPtr(self: *Coff, atom_index: Atom.Index) *Atom { | 3107 | pub fn getAtomPtr(coff: *Coff, atom_index: Atom.Index) *Atom { |
| 2588 | assert(atom_index < self.atoms.items.len); | 3108 | assert(atom_index < coff.atoms.items.len); |
| 2589 | return &self.atoms.items[atom_index]; | 3109 | return &coff.atoms.items[atom_index]; |
| 2590 | } | 3110 | } |
| 2591 | | 3111 | |
| 2592 | /// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor. | 3112 | /// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor. |
| 2593 | /// Returns null on failure. | 3113 | /// Returns null on failure. |
| 2594 | pub fn getAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index { | 3114 | pub fn getAtomIndexForSymbol(coff: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index { |
| 2595 | assert(sym_loc.file == null); // TODO linking with object files | 3115 | assert(sym_loc.file == null); // TODO linking with object files |
| 2596 | return self.atom_by_index_table.get(sym_loc.sym_index); | 3116 | return coff.atom_by_index_table.get(sym_loc.sym_index); |
| 2597 | } | 3117 | } |
| 2598 | | 3118 | |
| 2599 | fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void { | 3119 | fn setSectionName(coff: *Coff, header: *coff_util.SectionHeader, name: []const u8) !void { |
| 2600 | if (name.len <= 8) { | 3120 | if (name.len <= 8) { |
| 2601 | @memcpy(header.name[0..name.len], name); | 3121 | @memcpy(header.name[0..name.len], name); |
| 2602 | @memset(header.name[name.len..], 0); | 3122 | @memset(header.name[name.len..], 0); |
| 2603 | return; | 3123 | return; |
| 2604 | } | 3124 | } |
| 2605 | const gpa = self.base.comp.gpa; | 3125 | const gpa = coff.base.comp.gpa; |
| 2606 | const offset = try self.strtab.insert(gpa, name); | 3126 | const offset = try coff.strtab.insert(gpa, name); |
| 2607 | const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable; | 3127 | const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable; |
| 2608 | @memset(header.name[name_offset.len..], 0); | 3128 | @memset(header.name[name_offset.len..], 0); |
| 2609 | } | 3129 | } |
| 2610 | | 3130 | |
| 2611 | fn getSectionName(self: *const Coff, header: *const coff.SectionHeader) []const u8 { | 3131 | fn getSectionName(coff: *const Coff, header: *const coff_util.SectionHeader) []const u8 { |
| 2612 | if (header.getName()) |name| { | 3132 | if (header.getName()) |name| { |
| 2613 | return name; | 3133 | return name; |
| 2614 | } | 3134 | } |
| 2615 | const offset = header.getNameOffset().?; | 3135 | const offset = header.getNameOffset().?; |
| 2616 | return self.strtab.get(offset).?; | 3136 | return coff.strtab.get(offset).?; |
| 2617 | } | 3137 | } |
| 2618 | | 3138 | |
| 2619 | fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void { | 3139 | fn setSymbolName(coff: *Coff, symbol: *coff_util.Symbol, name: []const u8) !void { |
| 2620 | if (name.len <= 8) { | 3140 | if (name.len <= 8) { |
| 2621 | @memcpy(symbol.name[0..name.len], name); | 3141 | @memcpy(symbol.name[0..name.len], name); |
| 2622 | @memset(symbol.name[name.len..], 0); | 3142 | @memset(symbol.name[name.len..], 0); |
| 2623 | return; | 3143 | return; |
| 2624 | } | 3144 | } |
| 2625 | const gpa = self.base.comp.gpa; | 3145 | const gpa = coff.base.comp.gpa; |
| 2626 | const offset = try self.strtab.insert(gpa, name); | 3146 | const offset = try coff.strtab.insert(gpa, name); |
| 2627 | @memset(symbol.name[0..4], 0); | 3147 | @memset(symbol.name[0..4], 0); |
| 2628 | mem.writeInt(u32, symbol.name[4..8], offset, .little); | 3148 | mem.writeInt(u32, symbol.name[4..8], offset, .little); |
| 2629 | } | 3149 | } |
| 2630 | | 3150 | |
| 2631 | fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 { | 3151 | fn logSymAttributes(sym: *const coff_util.Symbol, buf: *[4]u8) []const u8 { |
| 2632 | @memset(buf[0..4], '_'); | 3152 | @memset(buf[0..4], '_'); |
| 2633 | switch (sym.section_number) { | 3153 | switch (sym.section_number) { |
| 2634 | .UNDEFINED => { | 3154 | .UNDEFINED => { |
| ... | @@ -2655,12 +3175,12 @@ fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 { | ... | @@ -2655,12 +3175,12 @@ fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 { |
| 2655 | return buf[0..]; | 3175 | return buf[0..]; |
| 2656 | } | 3176 | } |
| 2657 | | 3177 | |
| 2658 | fn logSymtab(self: *Coff) void { | 3178 | fn logSymtab(coff: *Coff) void { |
| 2659 | var buf: [4]u8 = undefined; | 3179 | var buf: [4]u8 = undefined; |
| 2660 | | 3180 | |
| 2661 | log.debug("symtab:", .{}); | 3181 | log.debug("symtab:", .{}); |
| 2662 | log.debug(" object(null)", .{}); | 3182 | log.debug(" object(null)", .{}); |
| 2663 | for (self.locals.items, 0..) |*sym, sym_id| { | 3183 | for (coff.locals.items, 0..) |*sym, sym_id| { |
| 2664 | const where = if (sym.section_number == .UNDEFINED) "ord" else "sect"; | 3184 | const where = if (sym.section_number == .UNDEFINED) "ord" else "sect"; |
| 2665 | const def_index: u16 = switch (sym.section_number) { | 3185 | const def_index: u16 = switch (sym.section_number) { |
| 2666 | .UNDEFINED => 0, // TODO | 3186 | .UNDEFINED => 0, // TODO |
| ... | @@ -2670,7 +3190,7 @@ fn logSymtab(self: *Coff) void { | ... | @@ -2670,7 +3190,7 @@ fn logSymtab(self: *Coff) void { |
| 2670 | }; | 3190 | }; |
| 2671 | log.debug(" %{d}: {?s} @{x} in {s}({d}), {s}", .{ | 3191 | log.debug(" %{d}: {?s} @{x} in {s}({d}), {s}", .{ |
| 2672 | sym_id, | 3192 | sym_id, |
| 2673 | self.getSymbolName(.{ .sym_index = @as(u32, @intCast(sym_id)), .file = null }), | 3193 | coff.getSymbolName(.{ .sym_index = @as(u32, @intCast(sym_id)), .file = null }), |
| 2674 | sym.value, | 3194 | sym.value, |
| 2675 | where, | 3195 | where, |
| 2676 | def_index, | 3196 | def_index, |
| ... | @@ -2679,20 +3199,20 @@ fn logSymtab(self: *Coff) void { | ... | @@ -2679,20 +3199,20 @@ fn logSymtab(self: *Coff) void { |
| 2679 | } | 3199 | } |
| 2680 | | 3200 | |
| 2681 | log.debug("globals table:", .{}); | 3201 | log.debug("globals table:", .{}); |
| 2682 | for (self.globals.items) |sym_loc| { | 3202 | for (coff.globals.items) |sym_loc| { |
| 2683 | const sym_name = self.getSymbolName(sym_loc); | 3203 | const sym_name = coff.getSymbolName(sym_loc); |
| 2684 | log.debug(" {s} => %{d} in object({?d})", .{ sym_name, sym_loc.sym_index, sym_loc.file }); | 3204 | log.debug(" {s} => %{d} in object({?d})", .{ sym_name, sym_loc.sym_index, sym_loc.file }); |
| 2685 | } | 3205 | } |
| 2686 | | 3206 | |
| 2687 | log.debug("GOT entries:", .{}); | 3207 | log.debug("GOT entries:", .{}); |
| 2688 | log.debug("{}", .{self.got_table}); | 3208 | log.debug("{}", .{coff.got_table}); |
| 2689 | } | 3209 | } |
| 2690 | | 3210 | |
| 2691 | fn logSections(self: *Coff) void { | 3211 | fn logSections(coff: *Coff) void { |
| 2692 | log.debug("sections:", .{}); | 3212 | log.debug("sections:", .{}); |
| 2693 | for (self.sections.items(.header)) |*header| { | 3213 | for (coff.sections.items(.header)) |*header| { |
| 2694 | log.debug(" {s}: VM({x}, {x}) FILE({x}, {x})", .{ | 3214 | log.debug(" {s}: VM({x}, {x}) FILE({x}, {x})", .{ |
| 2695 | self.getSectionName(header), | 3215 | coff.getSectionName(header), |
| 2696 | header.virtual_address, | 3216 | header.virtual_address, |
| 2697 | header.virtual_address + header.virtual_size, | 3217 | header.virtual_address + header.virtual_size, |
| 2698 | header.pointer_to_raw_data, | 3218 | header.pointer_to_raw_data, |
| ... | @@ -2701,26 +3221,495 @@ fn logSections(self: *Coff) void { | ... | @@ -2701,26 +3221,495 @@ fn logSections(self: *Coff) void { |
| 2701 | } | 3221 | } |
| 2702 | } | 3222 | } |
| 2703 | | 3223 | |
| 2704 | fn logImportTables(self: *const Coff) void { | 3224 | fn logImportTables(coff: *const Coff) void { |
| 2705 | log.debug("import tables:", .{}); | 3225 | log.debug("import tables:", .{}); |
| 2706 | for (self.import_tables.keys(), 0..) |off, i| { | 3226 | for (coff.import_tables.keys(), 0..) |off, i| { |
| 2707 | const itable = self.import_tables.values()[i]; | 3227 | const itable = coff.import_tables.values()[i]; |
| 2708 | log.debug("{}", .{itable.fmtDebug(.{ | 3228 | log.debug("{}", .{itable.fmtDebug(.{ |
| 2709 | .coff_file = self, | 3229 | .coff = coff, |
| 2710 | .index = i, | 3230 | .index = i, |
| 2711 | .name_off = off, | 3231 | .name_off = off, |
| 2712 | })}); | 3232 | })}); |
| 2713 | } | 3233 | } |
| 2714 | } | 3234 | } |
| 2715 | | 3235 | |
| | 3236 | pub const Atom = struct { |
| | 3237 | /// Each decl always gets a local symbol with the fully qualified name. |
| | 3238 | /// The vaddr and size are found here directly. |
| | 3239 | /// The file offset is found by computing the vaddr offset from the section vaddr |
| | 3240 | /// the symbol references, and adding that to the file offset of the section. |
| | 3241 | /// If this field is 0, it means the codegen size = 0 and there is no symbol or |
| | 3242 | /// offset table entry. |
| | 3243 | sym_index: u32, |
| | 3244 | |
| | 3245 | /// null means symbol defined by Zig source. |
| | 3246 | file: ?u32, |
| | 3247 | |
| | 3248 | /// Size of the atom |
| | 3249 | size: u32, |
| | 3250 | |
| | 3251 | /// Points to the previous and next neighbors, based on the `text_offset`. |
| | 3252 | /// This can be used to find, for example, the capacity of this `Atom`. |
| | 3253 | prev_index: ?Index, |
| | 3254 | next_index: ?Index, |
| | 3255 | |
| | 3256 | const Index = u32; |
| | 3257 | |
| | 3258 | pub fn getSymbolIndex(atom: Atom) ?u32 { |
| | 3259 | if (atom.sym_index == 0) return null; |
| | 3260 | return atom.sym_index; |
| | 3261 | } |
| | 3262 | |
| | 3263 | /// Returns symbol referencing this atom. |
| | 3264 | fn getSymbol(atom: Atom, coff: *const Coff) *const coff_util.Symbol { |
| | 3265 | const sym_index = atom.getSymbolIndex().?; |
| | 3266 | return coff.getSymbol(.{ |
| | 3267 | .sym_index = sym_index, |
| | 3268 | .file = atom.file, |
| | 3269 | }); |
| | 3270 | } |
| | 3271 | |
| | 3272 | /// Returns pointer-to-symbol referencing this atom. |
| | 3273 | fn getSymbolPtr(atom: Atom, coff: *Coff) *coff_util.Symbol { |
| | 3274 | const sym_index = atom.getSymbolIndex().?; |
| | 3275 | return coff.getSymbolPtr(.{ |
| | 3276 | .sym_index = sym_index, |
| | 3277 | .file = atom.file, |
| | 3278 | }); |
| | 3279 | } |
| | 3280 | |
| | 3281 | fn getSymbolWithLoc(atom: Atom) SymbolWithLoc { |
| | 3282 | const sym_index = atom.getSymbolIndex().?; |
| | 3283 | return .{ .sym_index = sym_index, .file = atom.file }; |
| | 3284 | } |
| | 3285 | |
| | 3286 | /// Returns the name of this atom. |
| | 3287 | fn getName(atom: Atom, coff: *const Coff) []const u8 { |
| | 3288 | const sym_index = atom.getSymbolIndex().?; |
| | 3289 | return coff.getSymbolName(.{ |
| | 3290 | .sym_index = sym_index, |
| | 3291 | .file = atom.file, |
| | 3292 | }); |
| | 3293 | } |
| | 3294 | |
| | 3295 | /// Returns how much room there is to grow in virtual address space. |
| | 3296 | fn capacity(atom: Atom, coff: *const Coff) u32 { |
| | 3297 | const atom_sym = atom.getSymbol(coff); |
| | 3298 | if (atom.next_index) |next_index| { |
| | 3299 | const next = coff.getAtom(next_index); |
| | 3300 | const next_sym = next.getSymbol(coff); |
| | 3301 | return next_sym.value - atom_sym.value; |
| | 3302 | } else { |
| | 3303 | // We are the last atom. |
| | 3304 | // The capacity is limited only by virtual address space. |
| | 3305 | return std.math.maxInt(u32) - atom_sym.value; |
| | 3306 | } |
| | 3307 | } |
| | 3308 | |
| | 3309 | fn freeListEligible(atom: Atom, coff: *const Coff) bool { |
| | 3310 | // No need to keep a free list node for the last atom. |
| | 3311 | const next_index = atom.next_index orelse return false; |
| | 3312 | const next = coff.getAtom(next_index); |
| | 3313 | const atom_sym = atom.getSymbol(coff); |
| | 3314 | const next_sym = next.getSymbol(coff); |
| | 3315 | const cap = next_sym.value - atom_sym.value; |
| | 3316 | const ideal_cap = padToIdeal(atom.size); |
| | 3317 | if (cap <= ideal_cap) return false; |
| | 3318 | const surplus = cap - ideal_cap; |
| | 3319 | return surplus >= min_text_capacity; |
| | 3320 | } |
| | 3321 | }; |
| | 3322 | |
| | 3323 | pub const Relocation = struct { |
| | 3324 | type: enum { |
| | 3325 | // x86, x86_64 |
| | 3326 | /// RIP-relative displacement to a GOT pointer |
| | 3327 | got, |
| | 3328 | /// RIP-relative displacement to an import pointer |
| | 3329 | import, |
| | 3330 | |
| | 3331 | // aarch64 |
| | 3332 | /// PC-relative distance to target page in GOT section |
| | 3333 | got_page, |
| | 3334 | /// Offset to a GOT pointer relative to the start of a page in GOT section |
| | 3335 | got_pageoff, |
| | 3336 | /// PC-relative distance to target page in a section (e.g., .rdata) |
| | 3337 | page, |
| | 3338 | /// Offset to a pointer relative to the start of a page in a section (e.g., .rdata) |
| | 3339 | pageoff, |
| | 3340 | /// PC-relative distance to target page in a import section |
| | 3341 | import_page, |
| | 3342 | /// Offset to a pointer relative to the start of a page in an import section (e.g., .rdata) |
| | 3343 | import_pageoff, |
| | 3344 | |
| | 3345 | // common |
| | 3346 | /// Absolute pointer value |
| | 3347 | direct, |
| | 3348 | }, |
| | 3349 | target: SymbolWithLoc, |
| | 3350 | offset: u32, |
| | 3351 | addend: u32, |
| | 3352 | pcrel: bool, |
| | 3353 | length: u2, |
| | 3354 | dirty: bool = true, |
| | 3355 | |
| | 3356 | /// Returns true if and only if the reloc can be resolved. |
| | 3357 | fn isResolvable(reloc: Relocation, coff: *Coff) bool { |
| | 3358 | _ = reloc.getTargetAddress(coff) orelse return false; |
| | 3359 | return true; |
| | 3360 | } |
| | 3361 | |
| | 3362 | fn isGotIndirection(reloc: Relocation) bool { |
| | 3363 | return switch (reloc.type) { |
| | 3364 | .got, .got_page, .got_pageoff => true, |
| | 3365 | else => false, |
| | 3366 | }; |
| | 3367 | } |
| | 3368 | |
| | 3369 | /// Returns address of the target if any. |
| | 3370 | fn getTargetAddress(reloc: Relocation, coff: *const Coff) ?u32 { |
| | 3371 | switch (reloc.type) { |
| | 3372 | .got, .got_page, .got_pageoff => { |
| | 3373 | const got_index = coff.got_table.lookup.get(reloc.target) orelse return null; |
| | 3374 | const header = coff.sections.items(.header)[coff.got_section_index.?]; |
| | 3375 | return header.virtual_address + got_index * coff.ptr_width.size(); |
| | 3376 | }, |
| | 3377 | .import, .import_page, .import_pageoff => { |
| | 3378 | const sym = coff.getSymbol(reloc.target); |
| | 3379 | const index = coff.import_tables.getIndex(sym.value) orelse return null; |
| | 3380 | const itab = coff.import_tables.values()[index]; |
| | 3381 | return itab.getImportAddress(reloc.target, .{ |
| | 3382 | .coff = coff, |
| | 3383 | .index = index, |
| | 3384 | .name_off = sym.value, |
| | 3385 | }); |
| | 3386 | }, |
| | 3387 | else => { |
| | 3388 | const target_atom_index = coff.getAtomIndexForSymbol(reloc.target) orelse return null; |
| | 3389 | const target_atom = coff.getAtom(target_atom_index); |
| | 3390 | return target_atom.getSymbol(coff).value; |
| | 3391 | }, |
| | 3392 | } |
| | 3393 | } |
| | 3394 | |
| | 3395 | fn resolve(reloc: Relocation, atom_index: Atom.Index, code: []u8, image_base: u64, coff: *Coff) void { |
| | 3396 | const atom = coff.getAtom(atom_index); |
| | 3397 | const source_sym = atom.getSymbol(coff); |
| | 3398 | const source_vaddr = source_sym.value + reloc.offset; |
| | 3399 | |
| | 3400 | const target_vaddr = reloc.getTargetAddress(coff).?; // Oops, you didn't check if the relocation can be resolved with isResolvable(). |
| | 3401 | const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| | 3402 | |
| | 3403 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) ", .{ |
| | 3404 | source_vaddr, |
| | 3405 | target_vaddr_with_addend, |
| | 3406 | coff.getSymbolName(reloc.target), |
| | 3407 | @tagName(reloc.type), |
| | 3408 | }); |
| | 3409 | |
| | 3410 | const ctx: Context = .{ |
| | 3411 | .source_vaddr = source_vaddr, |
| | 3412 | .target_vaddr = target_vaddr_with_addend, |
| | 3413 | .image_base = image_base, |
| | 3414 | .code = code, |
| | 3415 | .ptr_width = coff.ptr_width, |
| | 3416 | }; |
| | 3417 | |
| | 3418 | const target = coff.base.comp.root_mod.resolved_target.result; |
| | 3419 | switch (target.cpu.arch) { |
| | 3420 | .aarch64 => reloc.resolveAarch64(ctx), |
| | 3421 | .x86, .x86_64 => reloc.resolveX86(ctx), |
| | 3422 | else => unreachable, // unhandled target architecture |
| | 3423 | } |
| | 3424 | } |
| | 3425 | |
| | 3426 | const Context = struct { |
| | 3427 | source_vaddr: u32, |
| | 3428 | target_vaddr: u32, |
| | 3429 | image_base: u64, |
| | 3430 | code: []u8, |
| | 3431 | ptr_width: PtrWidth, |
| | 3432 | }; |
| | 3433 | |
| | 3434 | fn resolveAarch64(reloc: Relocation, ctx: Context) void { |
| | 3435 | var buffer = ctx.code[reloc.offset..]; |
| | 3436 | switch (reloc.type) { |
| | 3437 | .got_page, .import_page, .page => { |
| | 3438 | const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12)); |
| | 3439 | const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12)); |
| | 3440 | const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page)))); |
| | 3441 | var inst = aarch64_util.Instruction{ |
| | 3442 | .pc_relative_address = mem.bytesToValue(std.meta.TagPayload( |
| | 3443 | aarch64_util.Instruction, |
| | 3444 | aarch64_util.Instruction.pc_relative_address, |
| | 3445 | ), buffer[0..4]), |
| | 3446 | }; |
| | 3447 | inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2)); |
| | 3448 | inst.pc_relative_address.immlo = @as(u2, @truncate(pages)); |
| | 3449 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); |
| | 3450 | }, |
| | 3451 | .got_pageoff, .import_pageoff, .pageoff => { |
| | 3452 | assert(!reloc.pcrel); |
| | 3453 | |
| | 3454 | const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr)))); |
| | 3455 | if (isArithmeticOp(buffer[0..4])) { |
| | 3456 | var inst = aarch64_util.Instruction{ |
| | 3457 | .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( |
| | 3458 | aarch64_util.Instruction, |
| | 3459 | aarch64_util.Instruction.add_subtract_immediate, |
| | 3460 | ), buffer[0..4]), |
| | 3461 | }; |
| | 3462 | inst.add_subtract_immediate.imm12 = narrowed; |
| | 3463 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); |
| | 3464 | } else { |
| | 3465 | var inst = aarch64_util.Instruction{ |
| | 3466 | .load_store_register = mem.bytesToValue(std.meta.TagPayload( |
| | 3467 | aarch64_util.Instruction, |
| | 3468 | aarch64_util.Instruction.load_store_register, |
| | 3469 | ), buffer[0..4]), |
| | 3470 | }; |
| | 3471 | const offset: u12 = blk: { |
| | 3472 | if (inst.load_store_register.size == 0) { |
| | 3473 | if (inst.load_store_register.v == 1) { |
| | 3474 | // 128-bit SIMD is scaled by 16. |
| | 3475 | break :blk @divExact(narrowed, 16); |
| | 3476 | } |
| | 3477 | // Otherwise, 8-bit SIMD or ldrb. |
| | 3478 | break :blk narrowed; |
| | 3479 | } else { |
| | 3480 | const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable; |
| | 3481 | break :blk @divExact(narrowed, denom); |
| | 3482 | } |
| | 3483 | }; |
| | 3484 | inst.load_store_register.offset = offset; |
| | 3485 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); |
| | 3486 | } |
| | 3487 | }, |
| | 3488 | .direct => { |
| | 3489 | assert(!reloc.pcrel); |
| | 3490 | switch (reloc.length) { |
| | 3491 | 2 => mem.writeInt( |
| | 3492 | u32, |
| | 3493 | buffer[0..4], |
| | 3494 | @as(u32, @truncate(ctx.target_vaddr + ctx.image_base)), |
| | 3495 | .little, |
| | 3496 | ), |
| | 3497 | 3 => mem.writeInt(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base, .little), |
| | 3498 | else => unreachable, |
| | 3499 | } |
| | 3500 | }, |
| | 3501 | |
| | 3502 | .got => unreachable, |
| | 3503 | .import => unreachable, |
| | 3504 | } |
| | 3505 | } |
| | 3506 | |
| | 3507 | fn resolveX86(reloc: Relocation, ctx: Context) void { |
| | 3508 | var buffer = ctx.code[reloc.offset..]; |
| | 3509 | switch (reloc.type) { |
| | 3510 | .got_page => unreachable, |
| | 3511 | .got_pageoff => unreachable, |
| | 3512 | .page => unreachable, |
| | 3513 | .pageoff => unreachable, |
| | 3514 | .import_page => unreachable, |
| | 3515 | .import_pageoff => unreachable, |
| | 3516 | |
| | 3517 | .got, .import => { |
| | 3518 | assert(reloc.pcrel); |
| | 3519 | const disp = @as(i32, @intCast(ctx.target_vaddr)) - @as(i32, @intCast(ctx.source_vaddr)) - 4; |
| | 3520 | mem.writeInt(i32, buffer[0..4], disp, .little); |
| | 3521 | }, |
| | 3522 | .direct => { |
| | 3523 | if (reloc.pcrel) { |
| | 3524 | const disp = @as(i32, @intCast(ctx.target_vaddr)) - @as(i32, @intCast(ctx.source_vaddr)) - 4; |
| | 3525 | mem.writeInt(i32, buffer[0..4], disp, .little); |
| | 3526 | } else switch (ctx.ptr_width) { |
| | 3527 | .p32 => mem.writeInt(u32, buffer[0..4], @as(u32, @intCast(ctx.target_vaddr + ctx.image_base)), .little), |
| | 3528 | .p64 => switch (reloc.length) { |
| | 3529 | 2 => mem.writeInt(u32, buffer[0..4], @as(u32, @truncate(ctx.target_vaddr + ctx.image_base)), .little), |
| | 3530 | 3 => mem.writeInt(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base, .little), |
| | 3531 | else => unreachable, |
| | 3532 | }, |
| | 3533 | } |
| | 3534 | }, |
| | 3535 | } |
| | 3536 | } |
| | 3537 | |
| | 3538 | fn isArithmeticOp(inst: *const [4]u8) bool { |
| | 3539 | const group_decode = @as(u5, @truncate(inst[3])); |
| | 3540 | return ((group_decode >> 2) == 4); |
| | 3541 | } |
| | 3542 | }; |
| | 3543 | |
| | 3544 | pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void { |
| | 3545 | const comp = coff.base.comp; |
| | 3546 | const gpa = comp.gpa; |
| | 3547 | log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.type), reloc.target.sym_index }); |
| | 3548 | const gop = try coff.relocs.getOrPut(gpa, atom_index); |
| | 3549 | if (!gop.found_existing) { |
| | 3550 | gop.value_ptr.* = .{}; |
| | 3551 | } |
| | 3552 | try gop.value_ptr.append(gpa, reloc); |
| | 3553 | } |
| | 3554 | |
| | 3555 | fn addBaseRelocation(coff: *Coff, atom_index: Atom.Index, offset: u32) !void { |
| | 3556 | const comp = coff.base.comp; |
| | 3557 | const gpa = comp.gpa; |
| | 3558 | log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ |
| | 3559 | offset, |
| | 3560 | coff.getAtom(atom_index).getSymbolIndex().?, |
| | 3561 | }); |
| | 3562 | const gop = try coff.base_relocs.getOrPut(gpa, atom_index); |
| | 3563 | if (!gop.found_existing) { |
| | 3564 | gop.value_ptr.* = .{}; |
| | 3565 | } |
| | 3566 | try gop.value_ptr.append(gpa, offset); |
| | 3567 | } |
| | 3568 | |
| | 3569 | fn freeRelocations(coff: *Coff, atom_index: Atom.Index) void { |
| | 3570 | const comp = coff.base.comp; |
| | 3571 | const gpa = comp.gpa; |
| | 3572 | var removed_relocs = coff.relocs.fetchOrderedRemove(atom_index); |
| | 3573 | if (removed_relocs) |*relocs| relocs.value.deinit(gpa); |
| | 3574 | var removed_base_relocs = coff.base_relocs.fetchOrderedRemove(atom_index); |
| | 3575 | if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(gpa); |
| | 3576 | } |
| | 3577 | |
| | 3578 | /// Represents an import table in the .idata section where each contained pointer |
| | 3579 | /// is to a symbol from the same DLL. |
| | 3580 | /// |
| | 3581 | /// The layout of .idata section is as follows: |
| | 3582 | /// |
| | 3583 | /// --- ADDR1 : IAT (all import tables concatenated together) |
| | 3584 | /// ptr |
| | 3585 | /// ptr |
| | 3586 | /// 0 sentinel |
| | 3587 | /// ptr |
| | 3588 | /// 0 sentinel |
| | 3589 | /// --- ADDR2: headers |
| | 3590 | /// ImportDirectoryEntry header |
| | 3591 | /// ImportDirectoryEntry header |
| | 3592 | /// sentinel |
| | 3593 | /// --- ADDR2: lookup tables |
| | 3594 | /// Lookup table |
| | 3595 | /// 0 sentinel |
| | 3596 | /// Lookup table |
| | 3597 | /// 0 sentinel |
| | 3598 | /// --- ADDR3: name hint tables |
| | 3599 | /// hint-symname |
| | 3600 | /// hint-symname |
| | 3601 | /// --- ADDR4: DLL names |
| | 3602 | /// DLL#1 name |
| | 3603 | /// DLL#2 name |
| | 3604 | /// --- END |
| | 3605 | const ImportTable = struct { |
| | 3606 | entries: std.ArrayListUnmanaged(SymbolWithLoc) = .empty, |
| | 3607 | free_list: std.ArrayListUnmanaged(u32) = .empty, |
| | 3608 | lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .empty, |
| | 3609 | |
| | 3610 | fn deinit(itab: *ImportTable, allocator: Allocator) void { |
| | 3611 | itab.entries.deinit(allocator); |
| | 3612 | itab.free_list.deinit(allocator); |
| | 3613 | itab.lookup.deinit(allocator); |
| | 3614 | } |
| | 3615 | |
| | 3616 | /// Size of the import table does not include the sentinel. |
| | 3617 | fn size(itab: ImportTable) u32 { |
| | 3618 | return @as(u32, @intCast(itab.entries.items.len)) * @sizeOf(u64); |
| | 3619 | } |
| | 3620 | |
| | 3621 | fn addImport(itab: *ImportTable, allocator: Allocator, target: SymbolWithLoc) !ImportIndex { |
| | 3622 | try itab.entries.ensureUnusedCapacity(allocator, 1); |
| | 3623 | const index: u32 = blk: { |
| | 3624 | if (itab.free_list.popOrNull()) |index| { |
| | 3625 | log.debug(" (reusing import entry index {d})", .{index}); |
| | 3626 | break :blk index; |
| | 3627 | } else { |
| | 3628 | log.debug(" (allocating import entry at index {d})", .{itab.entries.items.len}); |
| | 3629 | const index = @as(u32, @intCast(itab.entries.items.len)); |
| | 3630 | _ = itab.entries.addOneAssumeCapacity(); |
| | 3631 | break :blk index; |
| | 3632 | } |
| | 3633 | }; |
| | 3634 | itab.entries.items[index] = target; |
| | 3635 | try itab.lookup.putNoClobber(allocator, target, index); |
| | 3636 | return index; |
| | 3637 | } |
| | 3638 | |
| | 3639 | const Context = struct { |
| | 3640 | coff: *const Coff, |
| | 3641 | /// Index of this ImportTable in a global list of all tables. |
| | 3642 | /// This is required in order to calculate the base vaddr of this ImportTable. |
| | 3643 | index: usize, |
| | 3644 | /// Offset into the string interning table of the DLL this ImportTable corresponds to. |
| | 3645 | name_off: u32, |
| | 3646 | }; |
| | 3647 | |
| | 3648 | fn getBaseAddress(ctx: Context) u32 { |
| | 3649 | const header = ctx.coff.sections.items(.header)[ctx.coff.idata_section_index.?]; |
| | 3650 | var addr = header.virtual_address; |
| | 3651 | for (ctx.coff.import_tables.values(), 0..) |other_itab, i| { |
| | 3652 | if (ctx.index == i) break; |
| | 3653 | addr += @as(u32, @intCast(other_itab.entries.items.len * @sizeOf(u64))) + 8; |
| | 3654 | } |
| | 3655 | return addr; |
| | 3656 | } |
| | 3657 | |
| | 3658 | fn getImportAddress(itab: *const ImportTable, target: SymbolWithLoc, ctx: Context) ?u32 { |
| | 3659 | const index = itab.lookup.get(target) orelse return null; |
| | 3660 | const base_vaddr = getBaseAddress(ctx); |
| | 3661 | return base_vaddr + index * @sizeOf(u64); |
| | 3662 | } |
| | 3663 | |
| | 3664 | const FormatContext = struct { |
| | 3665 | itab: ImportTable, |
| | 3666 | ctx: Context, |
| | 3667 | }; |
| | 3668 | |
| | 3669 | fn format(itab: ImportTable, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| | 3670 | _ = itab; |
| | 3671 | _ = unused_format_string; |
| | 3672 | _ = options; |
| | 3673 | _ = writer; |
| | 3674 | @compileError("do not format ImportTable directly; use itab.fmtDebug()"); |
| | 3675 | } |
| | 3676 | |
| | 3677 | fn format2( |
| | 3678 | fmt_ctx: FormatContext, |
| | 3679 | comptime unused_format_string: []const u8, |
| | 3680 | options: fmt.FormatOptions, |
| | 3681 | writer: anytype, |
| | 3682 | ) @TypeOf(writer).Error!void { |
| | 3683 | _ = options; |
| | 3684 | comptime assert(unused_format_string.len == 0); |
| | 3685 | const lib_name = fmt_ctx.ctx.coff.temp_strtab.getAssumeExists(fmt_ctx.ctx.name_off); |
| | 3686 | const base_vaddr = getBaseAddress(fmt_ctx.ctx); |
| | 3687 | try writer.print("IAT({s}.dll) @{x}:", .{ lib_name, base_vaddr }); |
| | 3688 | for (fmt_ctx.itab.entries.items, 0..) |entry, i| { |
| | 3689 | try writer.print("\n {d}@{?x} => {s}", .{ |
| | 3690 | i, |
| | 3691 | fmt_ctx.itab.getImportAddress(entry, fmt_ctx.ctx), |
| | 3692 | fmt_ctx.ctx.coff.getSymbolName(entry), |
| | 3693 | }); |
| | 3694 | } |
| | 3695 | } |
| | 3696 | |
| | 3697 | fn fmtDebug(itab: ImportTable, ctx: Context) fmt.Formatter(format2) { |
| | 3698 | return .{ .data = .{ .itab = itab, .ctx = ctx } }; |
| | 3699 | } |
| | 3700 | |
| | 3701 | const ImportIndex = u32; |
| | 3702 | }; |
| | 3703 | |
| 2716 | const Coff = @This(); | 3704 | const Coff = @This(); |
| 2717 | | 3705 | |
| 2718 | const std = @import("std"); | 3706 | const std = @import("std"); |
| 2719 | const build_options = @import("build_options"); | 3707 | const build_options = @import("build_options"); |
| 2720 | const builtin = @import("builtin"); | 3708 | const builtin = @import("builtin"); |
| 2721 | const assert = std.debug.assert; | 3709 | const assert = std.debug.assert; |
| 2722 | const coff = std.coff; | 3710 | const coff_util = std.coff; |
| 2723 | const fmt = std.fmt; | 3711 | const fmt = std.fmt; |
| | 3712 | const fs = std.fs; |
| 2724 | const log = std.log.scoped(.link); | 3713 | const log = std.log.scoped(.link); |
| 2725 | const math = std.math; | 3714 | const math = std.math; |
| 2726 | const mem = std.mem; | 3715 | const mem = std.mem; |
| ... | @@ -2728,23 +3717,21 @@ const mem = std.mem; | ... | @@ -2728,23 +3717,21 @@ const mem = std.mem; |
| 2728 | const Allocator = std.mem.Allocator; | 3717 | const Allocator = std.mem.Allocator; |
| 2729 | const Path = std.Build.Cache.Path; | 3718 | const Path = std.Build.Cache.Path; |
| 2730 | const Directory = std.Build.Cache.Directory; | 3719 | const Directory = std.Build.Cache.Directory; |
| | 3720 | const Cache = std.Build.Cache; |
| 2731 | | 3721 | |
| | 3722 | const aarch64_util = @import("../arch/aarch64/bits.zig"); |
| | 3723 | const allocPrint = std.fmt.allocPrint; |
| 2732 | const codegen = @import("../codegen.zig"); | 3724 | const codegen = @import("../codegen.zig"); |
| 2733 | const link = @import("../link.zig"); | 3725 | const link = @import("../link.zig"); |
| 2734 | const lld = @import("Coff/lld.zig"); | | |
| 2735 | const target_util = @import("../target.zig"); | 3726 | const target_util = @import("../target.zig"); |
| 2736 | const trace = @import("../tracy.zig").trace; | 3727 | const trace = @import("../tracy.zig").trace; |
| 2737 | | 3728 | |
| 2738 | const Air = @import("../Air.zig"); | 3729 | const Air = @import("../Air.zig"); |
| 2739 | pub const Atom = @import("Coff/Atom.zig"); | | |
| 2740 | const Compilation = @import("../Compilation.zig"); | 3730 | const Compilation = @import("../Compilation.zig"); |
| 2741 | const ImportTable = @import("Coff/ImportTable.zig"); | | |
| 2742 | const Liveness = @import("../Liveness.zig"); | 3731 | const Liveness = @import("../Liveness.zig"); |
| 2743 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 3732 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 2744 | const Zcu = @import("../Zcu.zig"); | 3733 | const Zcu = @import("../Zcu.zig"); |
| 2745 | const InternPool = @import("../InternPool.zig"); | 3734 | const InternPool = @import("../InternPool.zig"); |
| 2746 | const Object = @import("Coff/Object.zig"); | | |
| 2747 | const Relocation = @import("Coff/Relocation.zig"); | | |
| 2748 | const TableSection = @import("table_section.zig").TableSection; | 3735 | const TableSection = @import("table_section.zig").TableSection; |
| 2749 | const StringTable = @import("StringTable.zig"); | 3736 | const StringTable = @import("StringTable.zig"); |
| 2750 | const Type = @import("../Type.zig"); | 3737 | const Type = @import("../Type.zig"); |