| ... | ... | @@ -26,10 +26,8 @@ repro: bool, |
| 26 | 26 | ptr_width: PtrWidth, |
| 27 | 27 | page_size: u32, |
| 28 | 28 | |
| 29 | | objects: std.ArrayListUnmanaged(Object) = .empty, |
| 30 | | |
| 31 | 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 | 32 | text_section_index: ?u16 = null, |
| 35 | 33 | got_section_index: ?u16 = null, |
| ... | ... | @@ -38,7 +36,7 @@ data_section_index: ?u16 = null, |
| 38 | 36 | reloc_section_index: ?u16 = null, |
| 39 | 37 | idata_section_index: ?u16 = null, |
| 40 | 38 | |
| 41 | | locals: std.ArrayListUnmanaged(coff.Symbol) = .empty, |
| 39 | locals: std.ArrayListUnmanaged(coff_util.Symbol) = .empty, |
| 42 | 40 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .empty, |
| 43 | 41 | resolver: std.StringHashMapUnmanaged(u32) = .empty, |
| 44 | 42 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .empty, |
| ... | ... | @@ -112,7 +110,7 @@ const default_size_of_heap_reserve: u32 = 0x100000; |
| 112 | 110 | const default_size_of_heap_commit: u32 = 0x1000; |
| 113 | 111 | |
| 114 | 112 | const Section = struct { |
| 115 | | header: coff.SectionHeader, |
| 113 | header: coff_util.SectionHeader, |
| 116 | 114 | |
| 117 | 115 | last_atom_index: ?Atom.Index = null, |
| 118 | 116 | |
| ... | ... | @@ -154,9 +152,9 @@ const AvMetadata = struct { |
| 154 | 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 | 156 | for (m.exports.items) |exp| { |
| 159 | | if (mem.eql(u8, name, coff_file.getSymbolName(.{ |
| 157 | if (mem.eql(u8, name, coff.getSymbolName(.{ |
| 160 | 158 | .sym_index = exp, |
| 161 | 159 | .file = null, |
| 162 | 160 | }))) return exp; |
| ... | ... | @@ -164,9 +162,9 @@ const AvMetadata = struct { |
| 164 | 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 | 166 | for (m.exports.items) |*exp| { |
| 169 | | if (mem.eql(u8, name, coff_file.getSymbolName(.{ |
| 167 | if (mem.eql(u8, name, coff.getSymbolName(.{ |
| 170 | 168 | .sym_index = exp.*, |
| 171 | 169 | .file = null, |
| 172 | 170 | }))) return exp; |
| ... | ... | @@ -247,10 +245,10 @@ pub fn createEmpty( |
| 247 | 245 | const zcu_object_sub_path = if (!use_lld and !use_llvm) |
| 248 | 246 | null |
| 249 | 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); |
| 253 | | self.* = .{ |
| 250 | const coff = try arena.create(Coff); |
| 251 | coff.* = .{ |
| 254 | 252 | .base = .{ |
| 255 | 253 | .tag = .coff, |
| 256 | 254 | .comp = comp, |
| ... | ... | @@ -267,10 +265,10 @@ pub fn createEmpty( |
| 267 | 265 | .ptr_width = ptr_width, |
| 268 | 266 | .page_size = page_size, |
| 269 | 267 | |
| 270 | | .data_directories = [1]coff.ImageDataDirectory{.{ |
| 268 | .data_directories = [1]coff_util.ImageDataDirectory{.{ |
| 271 | 269 | .virtual_address = 0, |
| 272 | 270 | .size = 0, |
| 273 | | }} ** coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES, |
| 271 | }} ** coff_util.IMAGE_NUMBEROF_DIRECTORY_ENTRIES, |
| 274 | 272 | |
| 275 | 273 | .image_base = options.image_base orelse switch (output_mode) { |
| 276 | 274 | .Exe => switch (target.cpu.arch) { |
| ... | ... | @@ -305,35 +303,35 @@ pub fn createEmpty( |
| 305 | 303 | .repro = options.repro, |
| 306 | 304 | }; |
| 307 | 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 | 310 | if (use_lld and (use_llvm or !comp.config.have_zcu)) { |
| 313 | 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 | 315 | // What path should this COFF linker code output to? |
| 318 | 316 | // If using LLD to link, this code should produce an object file so that it |
| 319 | 317 | // can be passed to LLD. |
| 320 | 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 | 320 | .truncate = true, |
| 323 | 321 | .read = true, |
| 324 | 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 | 326 | const gpa = comp.gpa; |
| 329 | 327 | |
| 330 | | try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); |
| 331 | | self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32)); |
| 328 | try coff.strtab.buffer.ensureUnusedCapacity(gpa, @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 | 333 | // Index 0 is always a null symbol. |
| 336 | | try self.locals.append(gpa, .{ |
| 334 | try coff.locals.append(gpa, .{ |
| 337 | 335 | .name = [_]u8{0} ** 8, |
| 338 | 336 | .value = 0, |
| 339 | 337 | .section_number = .UNDEFINED, |
| ... | ... | @@ -342,61 +340,61 @@ pub fn createEmpty( |
| 342 | 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 | 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 | 346 | .CNT_CODE = 1, |
| 349 | 347 | .MEM_EXECUTE = 1, |
| 350 | 348 | .MEM_READ = 1, |
| 351 | 349 | }); |
| 352 | 350 | } |
| 353 | 351 | |
| 354 | | if (self.got_section_index == null) { |
| 355 | | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size(); |
| 356 | | self.got_section_index = try self.allocateSection(".got", file_size, .{ |
| 352 | if (coff.got_section_index == null) { |
| 353 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size(); |
| 354 | coff.got_section_index = try coff.allocateSection(".got", file_size, .{ |
| 357 | 355 | .CNT_INITIALIZED_DATA = 1, |
| 358 | 356 | .MEM_READ = 1, |
| 359 | 357 | }); |
| 360 | 358 | } |
| 361 | 359 | |
| 362 | | if (self.rdata_section_index == null) { |
| 363 | | const file_size: u32 = self.page_size; |
| 364 | | self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ |
| 360 | if (coff.rdata_section_index == null) { |
| 361 | const file_size: u32 = coff.page_size; |
| 362 | coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{ |
| 365 | 363 | .CNT_INITIALIZED_DATA = 1, |
| 366 | 364 | .MEM_READ = 1, |
| 367 | 365 | }); |
| 368 | 366 | } |
| 369 | 367 | |
| 370 | | if (self.data_section_index == null) { |
| 371 | | const file_size: u32 = self.page_size; |
| 372 | | self.data_section_index = try self.allocateSection(".data", file_size, .{ |
| 368 | if (coff.data_section_index == null) { |
| 369 | const file_size: u32 = coff.page_size; |
| 370 | coff.data_section_index = try coff.allocateSection(".data", file_size, .{ |
| 373 | 371 | .CNT_INITIALIZED_DATA = 1, |
| 374 | 372 | .MEM_READ = 1, |
| 375 | 373 | .MEM_WRITE = 1, |
| 376 | 374 | }); |
| 377 | 375 | } |
| 378 | 376 | |
| 379 | | if (self.idata_section_index == null) { |
| 380 | | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size(); |
| 381 | | self.idata_section_index = try self.allocateSection(".idata", file_size, .{ |
| 377 | if (coff.idata_section_index == null) { |
| 378 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size(); |
| 379 | coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{ |
| 382 | 380 | .CNT_INITIALIZED_DATA = 1, |
| 383 | 381 | .MEM_READ = 1, |
| 384 | 382 | }); |
| 385 | 383 | } |
| 386 | 384 | |
| 387 | | if (self.reloc_section_index == null) { |
| 388 | | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff.BaseRelocation); |
| 389 | | self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{ |
| 385 | if (coff.reloc_section_index == null) { |
| 386 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation); |
| 387 | coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{ |
| 390 | 388 | .CNT_INITIALIZED_DATA = 1, |
| 391 | 389 | .MEM_DISCARDABLE = 1, |
| 392 | 390 | .MEM_READ = 1, |
| 393 | 391 | }); |
| 394 | 392 | } |
| 395 | 393 | |
| 396 | | if (self.strtab_offset == null) { |
| 397 | | const file_size = @as(u32, @intCast(self.strtab.buffer.items.len)); |
| 398 | | self.strtab_offset = self.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 }); |
| 394 | if (coff.strtab_offset == null) { |
| 395 | const file_size = @as(u32, @intCast(coff.strtab.buffer.items.len)); |
| 396 | coff.strtab_offset = coff.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here |
| 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 | 403 | // offset + it's filesize. |
| 406 | 404 | // TODO I don't like this here one bit |
| 407 | 405 | var max_file_offset: u64 = 0; |
| 408 | | for (self.sections.items(.header)) |header| { |
| 406 | for (coff.sections.items(.header)) |header| { |
| 409 | 407 | if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) { |
| 410 | 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 | 417 | pub fn open( |
| ... | ... | @@ -427,85 +425,80 @@ pub fn open( |
| 427 | 425 | return createEmpty(arena, comp, emit, options); |
| 428 | 426 | } |
| 429 | 427 | |
| 430 | | pub fn deinit(self: *Coff) void { |
| 431 | | const gpa = self.base.comp.gpa; |
| 432 | | |
| 433 | | if (self.llvm_object) |llvm_object| llvm_object.deinit(); |
| 428 | pub fn deinit(coff: *Coff) void { |
| 429 | const gpa = coff.base.comp.gpa; |
| 434 | 430 | |
| 435 | | for (self.objects.items) |*object| { |
| 436 | | object.deinit(gpa); |
| 437 | | } |
| 438 | | self.objects.deinit(gpa); |
| 431 | if (coff.llvm_object) |llvm_object| llvm_object.deinit(); |
| 439 | 432 | |
| 440 | | for (self.sections.items(.free_list)) |*free_list| { |
| 433 | for (coff.sections.items(.free_list)) |*free_list| { |
| 441 | 434 | free_list.deinit(gpa); |
| 442 | 435 | } |
| 443 | | self.sections.deinit(gpa); |
| 436 | coff.sections.deinit(gpa); |
| 444 | 437 | |
| 445 | | self.atoms.deinit(gpa); |
| 446 | | self.locals.deinit(gpa); |
| 447 | | self.globals.deinit(gpa); |
| 438 | coff.atoms.deinit(gpa); |
| 439 | coff.locals.deinit(gpa); |
| 440 | coff.globals.deinit(gpa); |
| 448 | 441 | |
| 449 | 442 | { |
| 450 | | var it = self.resolver.keyIterator(); |
| 443 | var it = coff.resolver.keyIterator(); |
| 451 | 444 | while (it.next()) |key_ptr| { |
| 452 | 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); |
| 458 | | self.locals_free_list.deinit(gpa); |
| 459 | | self.globals_free_list.deinit(gpa); |
| 460 | | self.strtab.deinit(gpa); |
| 461 | | self.temp_strtab.deinit(gpa); |
| 462 | | self.got_table.deinit(gpa); |
| 450 | coff.unresolved.deinit(gpa); |
| 451 | coff.locals_free_list.deinit(gpa); |
| 452 | coff.globals_free_list.deinit(gpa); |
| 453 | coff.strtab.deinit(gpa); |
| 454 | coff.temp_strtab.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 | 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 | 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 | 473 | while (it.next()) |entry| { |
| 481 | 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 | 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 | 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 { |
| 498 | | const index = @as(u16, @intCast(self.sections.slice().len)); |
| 499 | | const off = self.findFreeSpace(size, default_file_alignment); |
| 490 | fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeaderFlags) !u16 { |
| 491 | const index = @as(u16, @intCast(coff.sections.slice().len)); |
| 492 | const off = coff.findFreeSpace(size, default_file_alignment); |
| 500 | 493 | // Memory is always allocated in sequence |
| 501 | 494 | // TODO: investigate if we can allocate .text last; this way it would never need to grow in memory! |
| 502 | 495 | const vaddr = blk: { |
| 503 | | if (index == 0) break :blk self.page_size; |
| 504 | | const prev_header = self.sections.items(.header)[index - 1]; |
| 505 | | break :blk mem.alignForward(u32, prev_header.virtual_address + prev_header.virtual_size, self.page_size); |
| 496 | if (index == 0) break :blk coff.page_size; |
| 497 | const prev_header = coff.sections.items(.header)[index - 1]; |
| 498 | break :blk mem.alignForward(u32, prev_header.virtual_address + prev_header.virtual_size, coff.page_size); |
| 506 | 499 | }; |
| 507 | 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 | 502 | log.debug("found {s} free space 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ |
| 510 | 503 | name, |
| 511 | 504 | off, |
| ... | ... | @@ -513,7 +506,7 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section |
| 513 | 506 | vaddr, |
| 514 | 507 | vaddr + size, |
| 515 | 508 | }); |
| 516 | | var header = coff.SectionHeader{ |
| 509 | var header = coff_util.SectionHeader{ |
| 517 | 510 | .name = undefined, |
| 518 | 511 | .virtual_size = memsz, |
| 519 | 512 | .virtual_address = vaddr, |
| ... | ... | @@ -525,32 +518,32 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section |
| 525 | 518 | .number_of_linenumbers = 0, |
| 526 | 519 | .flags = flags, |
| 527 | 520 | }; |
| 528 | | const gpa = self.base.comp.gpa; |
| 529 | | try self.setSectionName(&header, name); |
| 530 | | try self.sections.append(gpa, .{ .header = header }); |
| 521 | const gpa = coff.base.comp.gpa; |
| 522 | try coff.setSectionName(&header, name); |
| 523 | try coff.sections.append(gpa, .{ .header = header }); |
| 531 | 524 | return index; |
| 532 | 525 | } |
| 533 | 526 | |
| 534 | | fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void { |
| 535 | | const header = &self.sections.items(.header)[sect_id]; |
| 536 | | const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id]; |
| 537 | | const sect_capacity = self.allocatedSize(header.pointer_to_raw_data); |
| 527 | fn growSection(coff: *Coff, sect_id: u32, needed_size: u32) !void { |
| 528 | const header = &coff.sections.items(.header)[sect_id]; |
| 529 | const maybe_last_atom_index = coff.sections.items(.last_atom_index)[sect_id]; |
| 530 | const sect_capacity = coff.allocatedSize(header.pointer_to_raw_data); |
| 538 | 531 | |
| 539 | 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 | 534 | const current_size = if (maybe_last_atom_index) |last_atom_index| blk: { |
| 542 | | const last_atom = self.getAtom(last_atom_index); |
| 543 | | const sym = last_atom.getSymbol(self); |
| 535 | const last_atom = coff.getAtom(last_atom_index); |
| 536 | const sym = last_atom.getSymbol(coff); |
| 544 | 537 | break :blk (sym.value + last_atom.size) - header.virtual_address; |
| 545 | 538 | } else 0; |
| 546 | 539 | log.debug("moving {s} from 0x{x} to 0x{x}", .{ |
| 547 | | self.getSectionName(header), |
| 540 | coff.getSectionName(header), |
| 548 | 541 | header.pointer_to_raw_data, |
| 549 | 542 | new_offset, |
| 550 | 543 | }); |
| 551 | | const amt = try self.base.file.?.copyRangeAll( |
| 544 | const amt = try coff.base.file.?.copyRangeAll( |
| 552 | 545 | header.pointer_to_raw_data, |
| 553 | | self.base.file.?, |
| 546 | coff.base.file.?, |
| 554 | 547 | new_offset, |
| 555 | 548 | current_size, |
| 556 | 549 | ); |
| ... | ... | @@ -558,35 +551,35 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void { |
| 558 | 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 | 555 | if (needed_size > sect_vm_capacity) { |
| 563 | | self.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size); |
| 564 | | try self.growSectionVirtualMemory(sect_id, needed_size); |
| 556 | coff.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size); |
| 557 | try coff.growSectionVirtualMemory(sect_id, needed_size); |
| 565 | 558 | } |
| 566 | 559 | |
| 567 | 560 | header.virtual_size = @max(header.virtual_size, needed_size); |
| 568 | 561 | header.size_of_raw_data = needed_size; |
| 569 | 562 | } |
| 570 | 563 | |
| 571 | | fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void { |
| 572 | | const header = &self.sections.items(.header)[sect_id]; |
| 564 | fn growSectionVirtualMemory(coff: *Coff, sect_id: u32, needed_size: u32) !void { |
| 565 | const header = &coff.sections.items(.header)[sect_id]; |
| 573 | 566 | const increased_size = padToIdeal(needed_size); |
| 574 | | const old_aligned_end = header.virtual_address + mem.alignForward(u32, header.virtual_size, self.page_size); |
| 575 | | const new_aligned_end = header.virtual_address + mem.alignForward(u32, increased_size, self.page_size); |
| 567 | const old_aligned_end = header.virtual_address + mem.alignForward(u32, header.virtual_size, coff.page_size); |
| 568 | const new_aligned_end = header.virtual_address + mem.alignForward(u32, increased_size, coff.page_size); |
| 576 | 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 | 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| { |
| 582 | | const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id]; |
| 574 | for (coff.sections.items(.header)[sect_id + 1 ..], 0..) |*next_header, next_sect_id| { |
| 575 | const maybe_last_atom_index = coff.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id]; |
| 583 | 576 | next_header.virtual_address += diff; |
| 584 | 577 | |
| 585 | 578 | if (maybe_last_atom_index) |last_atom_index| { |
| 586 | 579 | var atom_index = last_atom_index; |
| 587 | 580 | while (true) { |
| 588 | | const atom = self.getAtom(atom_index); |
| 589 | | const sym = atom.getSymbolPtr(self); |
| 581 | const atom = coff.getAtom(atom_index); |
| 582 | const sym = atom.getSymbolPtr(coff); |
| 590 | 583 | sym.value += diff; |
| 591 | 584 | |
| 592 | 585 | if (atom.prev_index) |prev_index| { |
| ... | ... | @@ -599,15 +592,15 @@ fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void { |
| 599 | 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 | 596 | const tracy = trace(@src()); |
| 604 | 597 | defer tracy.end(); |
| 605 | 598 | |
| 606 | | const atom = self.getAtom(atom_index); |
| 607 | | const sect_id = @intFromEnum(atom.getSymbol(self).section_number) - 1; |
| 608 | | const header = &self.sections.items(.header)[sect_id]; |
| 609 | | const free_list = &self.sections.items(.free_list)[sect_id]; |
| 610 | | const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; |
| 599 | const atom = coff.getAtom(atom_index); |
| 600 | const sect_id = @intFromEnum(atom.getSymbol(coff).section_number) - 1; |
| 601 | const header = &coff.sections.items(.header)[sect_id]; |
| 602 | const free_list = &coff.sections.items(.free_list)[sect_id]; |
| 603 | const maybe_last_atom_index = &coff.sections.items(.last_atom_index)[sect_id]; |
| 611 | 604 | const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size; |
| 612 | 605 | |
| 613 | 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 | 617 | var i: usize = 0; |
| 625 | 618 | while (i < free_list.items.len) { |
| 626 | 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 | 621 | // We now have a pointer to a live atom that has too much capacity. |
| 629 | 622 | // Is it enough that we could fit this new atom? |
| 630 | | const sym = big_atom.getSymbol(self); |
| 631 | | const capacity = big_atom.capacity(self); |
| 623 | const sym = big_atom.getSymbol(coff); |
| 624 | const capacity = big_atom.capacity(coff); |
| 632 | 625 | const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity; |
| 633 | 626 | const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity; |
| 634 | 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 | 631 | // Additional bookkeeping here to notice if this free list node |
| 639 | 632 | // should be deleted because the atom that it points to has grown to take up |
| 640 | 633 | // more of the extra capacity. |
| 641 | | if (!big_atom.freeListEligible(self)) { |
| 634 | if (!big_atom.freeListEligible(coff)) { |
| 642 | 635 | _ = free_list.swapRemove(i); |
| 643 | 636 | } else { |
| 644 | 637 | i += 1; |
| ... | ... | @@ -658,8 +651,8 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme |
| 658 | 651 | } |
| 659 | 652 | break :blk new_start_vaddr; |
| 660 | 653 | } else if (maybe_last_atom_index.*) |last_index| { |
| 661 | | const last = self.getAtom(last_index); |
| 662 | | const last_symbol = last.getSymbol(self); |
| 654 | const last = coff.getAtom(last_index); |
| 655 | const last_symbol = last.getSymbol(coff); |
| 663 | 656 | const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size; |
| 664 | 657 | const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity; |
| 665 | 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 | 664 | }; |
| 672 | 665 | |
| 673 | 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 | 668 | else |
| 676 | 669 | true; |
| 677 | 670 | if (expand_section) { |
| 678 | 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 | 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 | 677 | if (atom.prev_index) |prev_index| { |
| 685 | | const prev = self.getAtomPtr(prev_index); |
| 678 | const prev = coff.getAtomPtr(prev_index); |
| 686 | 679 | prev.next_index = atom.next_index; |
| 687 | 680 | } |
| 688 | 681 | if (atom.next_index) |next_index| { |
| 689 | | const next = self.getAtomPtr(next_index); |
| 682 | const next = coff.getAtomPtr(next_index); |
| 690 | 683 | next.prev_index = atom.prev_index; |
| 691 | 684 | } |
| 692 | 685 | |
| 693 | 686 | if (atom_placement) |big_atom_index| { |
| 694 | | const big_atom = self.getAtomPtr(big_atom_index); |
| 695 | | const atom_ptr = self.getAtomPtr(atom_index); |
| 687 | const big_atom = coff.getAtomPtr(big_atom_index); |
| 688 | const atom_ptr = coff.getAtomPtr(atom_index); |
| 696 | 689 | atom_ptr.prev_index = big_atom_index; |
| 697 | 690 | atom_ptr.next_index = big_atom.next_index; |
| 698 | 691 | big_atom.next_index = atom_index; |
| 699 | 692 | } else { |
| 700 | | const atom_ptr = self.getAtomPtr(atom_index); |
| 693 | const atom_ptr = coff.getAtomPtr(atom_index); |
| 701 | 694 | atom_ptr.prev_index = null; |
| 702 | 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 | 701 | return vaddr; |
| 709 | 702 | } |
| 710 | 703 | |
| 711 | | pub fn allocateSymbol(self: *Coff) !u32 { |
| 712 | | const gpa = self.base.comp.gpa; |
| 713 | | try self.locals.ensureUnusedCapacity(gpa, 1); |
| 704 | pub fn allocateSymbol(coff: *Coff) !u32 { |
| 705 | const gpa = coff.base.comp.gpa; |
| 706 | try coff.locals.ensureUnusedCapacity(gpa, 1); |
| 714 | 707 | |
| 715 | 708 | const index = blk: { |
| 716 | | if (self.locals_free_list.popOrNull()) |index| { |
| 709 | if (coff.locals_free_list.popOrNull()) |index| { |
| 717 | 710 | log.debug(" (reusing symbol index {d})", .{index}); |
| 718 | 711 | break :blk index; |
| 719 | 712 | } else { |
| 720 | | log.debug(" (allocating symbol index {d})", .{self.locals.items.len}); |
| 721 | | const index = @as(u32, @intCast(self.locals.items.len)); |
| 722 | | _ = self.locals.addOneAssumeCapacity(); |
| 713 | log.debug(" (allocating symbol index {d})", .{coff.locals.items.len}); |
| 714 | const index = @as(u32, @intCast(coff.locals.items.len)); |
| 715 | _ = coff.locals.addOneAssumeCapacity(); |
| 723 | 716 | break :blk index; |
| 724 | 717 | } |
| 725 | 718 | }; |
| 726 | 719 | |
| 727 | | self.locals.items[index] = .{ |
| 720 | coff.locals.items[index] = .{ |
| 728 | 721 | .name = [_]u8{0} ** 8, |
| 729 | 722 | .value = 0, |
| 730 | 723 | .section_number = .UNDEFINED, |
| ... | ... | @@ -736,23 +729,23 @@ pub fn allocateSymbol(self: *Coff) !u32 { |
| 736 | 729 | return index; |
| 737 | 730 | } |
| 738 | 731 | |
| 739 | | fn allocateGlobal(self: *Coff) !u32 { |
| 740 | | const gpa = self.base.comp.gpa; |
| 741 | | try self.globals.ensureUnusedCapacity(gpa, 1); |
| 732 | fn allocateGlobal(coff: *Coff) !u32 { |
| 733 | const gpa = coff.base.comp.gpa; |
| 734 | try coff.globals.ensureUnusedCapacity(gpa, 1); |
| 742 | 735 | |
| 743 | 736 | const index = blk: { |
| 744 | | if (self.globals_free_list.popOrNull()) |index| { |
| 737 | if (coff.globals_free_list.popOrNull()) |index| { |
| 745 | 738 | log.debug(" (reusing global index {d})", .{index}); |
| 746 | 739 | break :blk index; |
| 747 | 740 | } else { |
| 748 | | log.debug(" (allocating global index {d})", .{self.globals.items.len}); |
| 749 | | const index = @as(u32, @intCast(self.globals.items.len)); |
| 750 | | _ = self.globals.addOneAssumeCapacity(); |
| 741 | log.debug(" (allocating global index {d})", .{coff.globals.items.len}); |
| 742 | const index = @as(u32, @intCast(coff.globals.items.len)); |
| 743 | _ = coff.globals.addOneAssumeCapacity(); |
| 751 | 744 | break :blk index; |
| 752 | 745 | } |
| 753 | 746 | }; |
| 754 | 747 | |
| 755 | | self.globals.items[index] = .{ |
| 748 | coff.globals.items[index] = .{ |
| 756 | 749 | .sym_index = 0, |
| 757 | 750 | .file = null, |
| 758 | 751 | }; |
| ... | ... | @@ -760,21 +753,21 @@ fn allocateGlobal(self: *Coff) !u32 { |
| 760 | 753 | return index; |
| 761 | 754 | } |
| 762 | 755 | |
| 763 | | fn addGotEntry(self: *Coff, target: SymbolWithLoc) !void { |
| 764 | | const gpa = self.base.comp.gpa; |
| 765 | | if (self.got_table.lookup.contains(target)) return; |
| 766 | | const got_index = try self.got_table.allocateEntry(gpa, target); |
| 767 | | try self.writeOffsetTableEntry(got_index); |
| 768 | | self.got_table_count_dirty = true; |
| 769 | | self.markRelocsDirtyByTarget(target); |
| 756 | fn addGotEntry(coff: *Coff, target: SymbolWithLoc) !void { |
| 757 | const gpa = coff.base.comp.gpa; |
| 758 | if (coff.got_table.lookup.contains(target)) return; |
| 759 | const got_index = try coff.got_table.allocateEntry(gpa, target); |
| 760 | try coff.writeOffsetTableEntry(got_index); |
| 761 | coff.got_table_count_dirty = true; |
| 762 | coff.markRelocsDirtyByTarget(target); |
| 770 | 763 | } |
| 771 | 764 | |
| 772 | | pub fn createAtom(self: *Coff) !Atom.Index { |
| 773 | | const gpa = self.base.comp.gpa; |
| 774 | | const atom_index = @as(Atom.Index, @intCast(self.atoms.items.len)); |
| 775 | | const atom = try self.atoms.addOne(gpa); |
| 776 | | const sym_index = try self.allocateSymbol(); |
| 777 | | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); |
| 765 | pub fn createAtom(coff: *Coff) !Atom.Index { |
| 766 | const gpa = coff.base.comp.gpa; |
| 767 | const atom_index = @as(Atom.Index, @intCast(coff.atoms.items.len)); |
| 768 | const atom = try coff.atoms.addOne(gpa); |
| 769 | const sym_index = try coff.allocateSymbol(); |
| 770 | try coff.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); |
| 778 | 771 | atom.* = .{ |
| 779 | 772 | .sym_index = sym_index, |
| 780 | 773 | .file = null, |
| ... | ... | @@ -786,36 +779,36 @@ pub fn createAtom(self: *Coff) !Atom.Index { |
| 786 | 779 | return atom_index; |
| 787 | 780 | } |
| 788 | 781 | |
| 789 | | fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { |
| 790 | | const atom = self.getAtom(atom_index); |
| 791 | | const sym = atom.getSymbol(self); |
| 782 | fn growAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { |
| 783 | const atom = coff.getAtom(atom_index); |
| 784 | const sym = atom.getSymbol(coff); |
| 792 | 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 | 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 { |
| 799 | | _ = self; |
| 791 | fn shrinkAtom(coff: *Coff, atom_index: Atom.Index, new_block_size: u32) void { |
| 792 | _ = coff; |
| 800 | 793 | _ = atom_index; |
| 801 | 794 | _ = new_block_size; |
| 802 | 795 | // TODO check the new capacity, and if it crosses the size threshold into a big enough |
| 803 | 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 { |
| 807 | | const atom = self.getAtom(atom_index); |
| 808 | | const sym = atom.getSymbol(self); |
| 809 | | const section = self.sections.get(@intFromEnum(sym.section_number) - 1); |
| 799 | fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8) !void { |
| 800 | const atom = coff.getAtom(atom_index); |
| 801 | const sym = atom.getSymbol(coff); |
| 802 | const section = coff.sections.get(@intFromEnum(sym.section_number) - 1); |
| 810 | 803 | const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address; |
| 811 | 804 | |
| 812 | 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 | 807 | file_offset, |
| 815 | 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 | 813 | // Gather relocs which can be resolved. |
| 821 | 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 | 818 | var relocs = std.ArrayList(*Relocation).init(gpa); |
| 826 | 819 | defer relocs.deinit(); |
| 827 | 820 | |
| 828 | | if (self.relocs.getPtr(atom_index)) |rels| { |
| 821 | if (coff.relocs.getPtr(atom_index)) |rels| { |
| 829 | 822 | try relocs.ensureTotalCapacityPrecise(rels.items.len); |
| 830 | 823 | for (rels.items) |*reloc| { |
| 831 | | if (reloc.isResolvable(self) and reloc.dirty) { |
| 824 | if (reloc.isResolvable(coff) and reloc.dirty) { |
| 832 | 825 | relocs.appendAssumeCapacity(reloc); |
| 833 | 826 | } |
| 834 | 827 | } |
| 835 | 828 | } |
| 836 | 829 | |
| 837 | 830 | if (is_hot_update_compatible) { |
| 838 | | if (self.base.child_pid) |handle| { |
| 839 | | const slide = @intFromPtr(self.hot_state.loaded_base_address.?); |
| 831 | if (coff.base.child_pid) |handle| { |
| 832 | const slide = @intFromPtr(coff.hot_state.loaded_base_address.?); |
| 840 | 833 | |
| 841 | 834 | const mem_code = try gpa.dupe(u8, code); |
| 842 | 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 | 838 | const vaddr = sym.value + slide; |
| 846 | 839 | const pvaddr = @as(*anyopaque, @ptrFromInt(vaddr)); |
| ... | ... | @@ -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); |
| 867 | | try self.base.file.?.pwriteAll(code, file_offset); |
| 859 | coff.resolveRelocs(atom_index, relocs.items, code, coff.image_base); |
| 860 | try coff.base.file.?.pwriteAll(code, file_offset); |
| 868 | 861 | |
| 869 | 862 | // Now we can mark the relocs as resolved. |
| 870 | 863 | while (relocs.popOrNull()) |reloc| { |
| ... | ... | @@ -893,46 +886,46 @@ fn writeMem(handle: std.process.Child.Id, pvaddr: std.os.windows.LPVOID, code: [ |
| 893 | 886 | if (amt != code.len) return error.InputOutput; |
| 894 | 887 | } |
| 895 | 888 | |
| 896 | | fn writeOffsetTableEntry(self: *Coff, index: usize) !void { |
| 897 | | const sect_id = self.got_section_index.?; |
| 889 | fn writeOffsetTableEntry(coff: *Coff, index: usize) !void { |
| 890 | const sect_id = coff.got_section_index.?; |
| 898 | 891 | |
| 899 | | if (self.got_table_count_dirty) { |
| 900 | | const needed_size = @as(u32, @intCast(self.got_table.entries.items.len * self.ptr_width.size())); |
| 901 | | try self.growSection(sect_id, needed_size); |
| 902 | | self.got_table_count_dirty = false; |
| 892 | if (coff.got_table_count_dirty) { |
| 893 | const needed_size = @as(u32, @intCast(coff.got_table.entries.items.len * coff.ptr_width.size())); |
| 894 | try coff.growSection(sect_id, needed_size); |
| 895 | coff.got_table_count_dirty = false; |
| 903 | 896 | } |
| 904 | 897 | |
| 905 | | const header = &self.sections.items(.header)[sect_id]; |
| 906 | | const entry = self.got_table.entries.items[index]; |
| 907 | | const entry_value = self.getSymbol(entry).value; |
| 908 | | const entry_offset = index * self.ptr_width.size(); |
| 898 | const header = &coff.sections.items(.header)[sect_id]; |
| 899 | const entry = coff.got_table.entries.items[index]; |
| 900 | const entry_value = coff.getSymbol(entry).value; |
| 901 | const entry_offset = index * coff.ptr_width.size(); |
| 909 | 902 | const file_offset = header.pointer_to_raw_data + entry_offset; |
| 910 | 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 | 908 | .p32 => { |
| 916 | 909 | var buf: [4]u8 = undefined; |
| 917 | | mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + self.image_base)), .little); |
| 918 | | try self.base.file.?.pwriteAll(&buf, file_offset); |
| 910 | mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + coff.image_base)), .little); |
| 911 | try coff.base.file.?.pwriteAll(&buf, file_offset); |
| 919 | 912 | }, |
| 920 | 913 | .p64 => { |
| 921 | 914 | var buf: [8]u8 = undefined; |
| 922 | | mem.writeInt(u64, &buf, entry_value + self.image_base, .little); |
| 923 | | try self.base.file.?.pwriteAll(&buf, file_offset); |
| 915 | mem.writeInt(u64, &buf, entry_value + coff.image_base, .little); |
| 916 | try coff.base.file.?.pwriteAll(&buf, file_offset); |
| 924 | 917 | }, |
| 925 | 918 | } |
| 926 | 919 | |
| 927 | 920 | if (is_hot_update_compatible) { |
| 928 | | if (self.base.child_pid) |handle| { |
| 929 | | const gpa = self.base.comp.gpa; |
| 930 | | const slide = @intFromPtr(self.hot_state.loaded_base_address.?); |
| 921 | if (coff.base.child_pid) |handle| { |
| 922 | const gpa = coff.base.comp.gpa; |
| 923 | const slide = @intFromPtr(coff.hot_state.loaded_base_address.?); |
| 931 | 924 | const actual_vmaddr = vmaddr + slide; |
| 932 | 925 | const pvaddr = @as(*anyopaque, @ptrFromInt(actual_vmaddr)); |
| 933 | 926 | log.debug("writing GOT entry to memory at address {x}", .{actual_vmaddr}); |
| 934 | 927 | if (build_options.enable_logging) { |
| 935 | | switch (self.ptr_width) { |
| 928 | switch (coff.ptr_width) { |
| 936 | 929 | .p32 => { |
| 937 | 930 | var buf: [4]u8 = undefined; |
| 938 | 931 | try debugMem(gpa, handle, pvaddr, &buf); |
| ... | ... | @@ -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 | 941 | .p32 => { |
| 949 | 942 | var buf: [4]u8 = undefined; |
| 950 | 943 | mem.writeInt(u32, &buf, @as(u32, @intCast(entry_value + slide)), .little); |
| ... | ... | @@ -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 | 961 | // TODO: reverse-lookup might come in handy here |
| 969 | | for (self.relocs.values()) |*relocs| { |
| 962 | for (coff.relocs.values()) |*relocs| { |
| 970 | 963 | for (relocs.items) |*reloc| { |
| 971 | 964 | if (!reloc.target.eql(target)) continue; |
| 972 | 965 | reloc.dirty = true; |
| ... | ... | @@ -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 | 971 | const got_moved = blk: { |
| 979 | | const sect_id = self.got_section_index orelse break :blk false; |
| 980 | | break :blk self.sections.items(.header)[sect_id].virtual_address >= addr; |
| 972 | const sect_id = coff.got_section_index orelse break :blk false; |
| 973 | break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr; |
| 981 | 974 | }; |
| 982 | 975 | |
| 983 | 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 | 979 | for (relocs.items) |*reloc| { |
| 987 | 980 | if (reloc.isGotIndirection()) { |
| 988 | 981 | reloc.dirty = reloc.dirty or got_moved; |
| 989 | 982 | } else { |
| 990 | | const target_vaddr = reloc.getTargetAddress(self) orelse continue; |
| 983 | const target_vaddr = reloc.getTargetAddress(coff) orelse continue; |
| 991 | 984 | if (target_vaddr >= addr) reloc.dirty = true; |
| 992 | 985 | } |
| 993 | 986 | } |
| 994 | 987 | } |
| 995 | 988 | |
| 996 | 989 | // TODO: dirty only really affected GOT cells |
| 997 | | for (self.got_table.entries.items) |entry| { |
| 998 | | const target_addr = self.getSymbol(entry).value; |
| 990 | for (coff.got_table.entries.items) |entry| { |
| 991 | const target_addr = coff.getSymbol(entry).value; |
| 999 | 992 | if (target_addr >= addr) { |
| 1000 | | self.got_table_contents_dirty = true; |
| 993 | coff.got_table_contents_dirty = true; |
| 1001 | 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 { |
| 1007 | | log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)}); |
| 999 | fn resolveRelocs(coff: *Coff, atom_index: Atom.Index, relocs: []*const Relocation, code: []u8, image_base: u64) void { |
| 1000 | log.debug("relocating '{s}'", .{coff.getAtom(atom_index).getName(coff)}); |
| 1008 | 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 | 1007 | if (!is_hot_update_compatible) return; |
| 1015 | 1008 | |
| 1016 | 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 | 1011 | log.warn("failed to get base address for the process with error: {s}", .{@errorName(err)}); |
| 1019 | 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 | 1017 | if (!is_hot_update_compatible) return; |
| 1025 | 1018 | |
| 1026 | 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 | 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 | 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); |
| 1039 | | const sym = atom.getSymbol(self); |
| 1031 | const atom = coff.getAtom(atom_index); |
| 1032 | const sym = atom.getSymbol(coff); |
| 1040 | 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 | 1035 | var already_have_free_list_node = false; |
| 1043 | 1036 | { |
| 1044 | 1037 | var i: usize = 0; |
| ... | ... | @@ -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 | 1052 | if (maybe_last_atom_index.*) |last_atom_index| { |
| 1060 | 1053 | if (last_atom_index == atom_index) { |
| 1061 | 1054 | if (atom.prev_index) |prev_index| { |
| ... | ... | @@ -1068,42 +1061,42 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void { |
| 1068 | 1061 | } |
| 1069 | 1062 | |
| 1070 | 1063 | if (atom.prev_index) |prev_index| { |
| 1071 | | const prev = self.getAtomPtr(prev_index); |
| 1064 | const prev = coff.getAtomPtr(prev_index); |
| 1072 | 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 | 1068 | // The free list is heuristics, it doesn't have to be perfect, so we can |
| 1076 | 1069 | // ignore the OOM here. |
| 1077 | 1070 | free_list.append(gpa, prev_index) catch {}; |
| 1078 | 1071 | } |
| 1079 | 1072 | } else { |
| 1080 | | self.getAtomPtr(atom_index).prev_index = null; |
| 1073 | coff.getAtomPtr(atom_index).prev_index = null; |
| 1081 | 1074 | } |
| 1082 | 1075 | |
| 1083 | 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 | 1078 | } else { |
| 1086 | | self.getAtomPtr(atom_index).next_index = null; |
| 1079 | coff.getAtomPtr(atom_index).next_index = null; |
| 1087 | 1080 | } |
| 1088 | 1081 | |
| 1089 | 1082 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 1090 | 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 | 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; |
| 1097 | | _ = self.atom_by_index_table.remove(sym_index); |
| 1089 | coff.locals.items[sym_index].section_number = .UNDEFINED; |
| 1090 | _ = coff.atom_by_index_table.remove(sym_index); |
| 1098 | 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 | 1096 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1104 | 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 | 1100 | return llvm_object.updateFunc(pt, func_index, air, liveness); |
| 1108 | 1101 | } |
| 1109 | 1102 | const tracy = trace(@src()); |
| ... | ... | @@ -1113,14 +1106,14 @@ pub fn updateFunc(self: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, |
| 1113 | 1106 | const gpa = zcu.gpa; |
| 1114 | 1107 | const func = zcu.funcInfo(func_index); |
| 1115 | 1108 | |
| 1116 | | const atom_index = try self.getOrCreateAtomForNav(func.owner_nav); |
| 1117 | | Atom.freeRelocations(self, atom_index); |
| 1109 | const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav); |
| 1110 | coff.freeRelocations(atom_index); |
| 1118 | 1111 | |
| 1119 | 1112 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1120 | 1113 | defer code_buffer.deinit(); |
| 1121 | 1114 | |
| 1122 | 1115 | const res = try codegen.generateFunction( |
| 1123 | | &self.base, |
| 1116 | &coff.base, |
| 1124 | 1117 | pt, |
| 1125 | 1118 | zcu.navSrcLoc(func.owner_nav), |
| 1126 | 1119 | func_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 | 1135 | // Exports will be updated by `Zcu.processExports` after the update. |
| 1143 | 1136 | } |
| ... | ... | @@ -1148,7 +1141,7 @@ const LowerConstResult = union(enum) { |
| 1148 | 1141 | }; |
| 1149 | 1142 | |
| 1150 | 1143 | fn lowerConst( |
| 1151 | | self: *Coff, |
| 1144 | coff: *Coff, |
| 1152 | 1145 | pt: Zcu.PerThread, |
| 1153 | 1146 | name: []const u8, |
| 1154 | 1147 | val: Value, |
| ... | ... | @@ -1156,50 +1149,50 @@ fn lowerConst( |
| 1156 | 1149 | sect_id: u16, |
| 1157 | 1150 | src_loc: Zcu.LazySrcLoc, |
| 1158 | 1151 | ) !LowerConstResult { |
| 1159 | | const gpa = self.base.comp.gpa; |
| 1152 | const gpa = coff.base.comp.gpa; |
| 1160 | 1153 | |
| 1161 | 1154 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1162 | 1155 | defer code_buffer.deinit(); |
| 1163 | 1156 | |
| 1164 | | const atom_index = try self.createAtom(); |
| 1165 | | const sym = self.getAtom(atom_index).getSymbolPtr(self); |
| 1166 | | try self.setSymbolName(sym, name); |
| 1167 | | sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1)); |
| 1157 | const atom_index = try coff.createAtom(); |
| 1158 | const sym = coff.getAtom(atom_index).getSymbolPtr(coff); |
| 1159 | try coff.setSymbolName(sym, name); |
| 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, .{ |
| 1170 | | .atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| 1162 | const res = try codegen.generateSymbol(&coff.base, pt, src_loc, val, &code_buffer, .{ |
| 1163 | .atom_index = coff.getAtom(atom_index).getSymbolIndex().?, |
| 1171 | 1164 | }); |
| 1172 | 1165 | const code = switch (res) { |
| 1173 | 1166 | .ok => code_buffer.items, |
| 1174 | 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 | 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 | 1173 | atom_index, |
| 1181 | 1174 | atom.size, |
| 1182 | 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 | 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 | 1184 | return .{ .ok = atom_index }; |
| 1192 | 1185 | } |
| 1193 | 1186 | |
| 1194 | 1187 | pub fn updateNav( |
| 1195 | | self: *Coff, |
| 1188 | coff: *Coff, |
| 1196 | 1189 | pt: Zcu.PerThread, |
| 1197 | 1190 | nav_index: InternPool.Nav.Index, |
| 1198 | 1191 | ) link.File.UpdateNavError!void { |
| 1199 | 1192 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1200 | 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 | 1196 | const tracy = trace(@src()); |
| 1204 | 1197 | defer tracy.end(); |
| 1205 | 1198 | |
| ... | ... | @@ -1217,23 +1210,23 @@ pub fn updateNav( |
| 1217 | 1210 | // TODO make this part of getGlobalSymbol |
| 1218 | 1211 | const name = nav.name.toSlice(ip); |
| 1219 | 1212 | const lib_name = @"extern".lib_name.toSlice(ip); |
| 1220 | | const global_index = try self.getGlobalSymbol(name, lib_name); |
| 1221 | | try self.need_got_table.put(gpa, global_index, {}); |
| 1213 | const global_index = try coff.getGlobalSymbol(name, lib_name); |
| 1214 | try coff.need_got_table.put(gpa, global_index, {}); |
| 1222 | 1215 | return; |
| 1223 | 1216 | }, |
| 1224 | 1217 | else => nav_val, |
| 1225 | 1218 | }; |
| 1226 | 1219 | |
| 1227 | 1220 | if (nav_init.typeOf(zcu).hasRuntimeBits(zcu)) { |
| 1228 | | const atom_index = try self.getOrCreateAtomForNav(nav_index); |
| 1229 | | Atom.freeRelocations(self, atom_index); |
| 1230 | | const atom = self.getAtom(atom_index); |
| 1221 | const atom_index = try coff.getOrCreateAtomForNav(nav_index); |
| 1222 | coff.freeRelocations(atom_index); |
| 1223 | const atom = coff.getAtom(atom_index); |
| 1231 | 1224 | |
| 1232 | 1225 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1233 | 1226 | defer code_buffer.deinit(); |
| 1234 | 1227 | |
| 1235 | 1228 | const res = try codegen.generateSymbol( |
| 1236 | | &self.base, |
| 1229 | &coff.base, |
| 1237 | 1230 | pt, |
| 1238 | 1231 | zcu.navSrcLoc(nav_index), |
| 1239 | 1232 | nav_init, |
| ... | ... | @@ -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 | 1247 | // Exports will be updated by `Zcu.processExports` after the update. |
| 1255 | 1248 | } |
| 1256 | 1249 | |
| 1257 | 1250 | fn updateLazySymbolAtom( |
| 1258 | | self: *Coff, |
| 1251 | coff: *Coff, |
| 1259 | 1252 | pt: Zcu.PerThread, |
| 1260 | 1253 | sym: link.File.LazySymbol, |
| 1261 | 1254 | atom_index: Atom.Index, |
| ... | ... | @@ -1268,18 +1261,18 @@ fn updateLazySymbolAtom( |
| 1268 | 1261 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1269 | 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 | 1265 | @tagName(sym.kind), |
| 1273 | 1266 | Type.fromInterned(sym.ty).fmt(pt), |
| 1274 | 1267 | }); |
| 1275 | 1268 | defer gpa.free(name); |
| 1276 | 1269 | |
| 1277 | | const atom = self.getAtomPtr(atom_index); |
| 1270 | const atom = coff.getAtomPtr(atom_index); |
| 1278 | 1271 | const local_sym_index = atom.getSymbolIndex().?; |
| 1279 | 1272 | |
| 1280 | 1273 | const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded; |
| 1281 | 1274 | const res = try codegen.generateLazySymbol( |
| 1282 | | &self.base, |
| 1275 | &coff.base, |
| 1283 | 1276 | pt, |
| 1284 | 1277 | src, |
| 1285 | 1278 | sym, |
| ... | ... | @@ -1297,13 +1290,13 @@ fn updateLazySymbolAtom( |
| 1297 | 1290 | }; |
| 1298 | 1291 | |
| 1299 | 1292 | const code_len: u32 = @intCast(code.len); |
| 1300 | | const symbol = atom.getSymbolPtr(self); |
| 1301 | | try self.setSymbolName(symbol, name); |
| 1293 | const symbol = atom.getSymbolPtr(coff); |
| 1294 | try coff.setSymbolName(symbol, name); |
| 1302 | 1295 | symbol.section_number = @enumFromInt(section_index + 1); |
| 1303 | 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)); |
| 1306 | | errdefer self.freeAtom(atom_index); |
| 1298 | const vaddr = try coff.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0)); |
| 1299 | errdefer coff.freeAtom(atom_index); |
| 1307 | 1300 | |
| 1308 | 1301 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); |
| 1309 | 1302 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| ... | ... | @@ -1311,52 +1304,52 @@ fn updateLazySymbolAtom( |
| 1311 | 1304 | atom.size = code_len; |
| 1312 | 1305 | symbol.value = vaddr; |
| 1313 | 1306 | |
| 1314 | | try self.addGotEntry(.{ .sym_index = local_sym_index }); |
| 1315 | | try self.writeAtom(atom_index, code); |
| 1307 | try coff.addGotEntry(.{ .sym_index = local_sym_index }); |
| 1308 | try coff.writeAtom(atom_index, code); |
| 1316 | 1309 | } |
| 1317 | 1310 | |
| 1318 | 1311 | pub fn getOrCreateAtomForLazySymbol( |
| 1319 | | self: *Coff, |
| 1312 | coff: *Coff, |
| 1320 | 1313 | pt: Zcu.PerThread, |
| 1321 | 1314 | lazy_sym: link.File.LazySymbol, |
| 1322 | 1315 | ) !Atom.Index { |
| 1323 | | const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty); |
| 1324 | | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 1316 | const gop = try coff.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty); |
| 1317 | errdefer _ = if (!gop.found_existing) coff.lazy_syms.pop(); |
| 1325 | 1318 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 1326 | 1319 | const atom_ptr, const state_ptr = switch (lazy_sym.kind) { |
| 1327 | 1320 | .code => .{ &gop.value_ptr.text_atom, &gop.value_ptr.text_state }, |
| 1328 | 1321 | .const_data => .{ &gop.value_ptr.rdata_atom, &gop.value_ptr.rdata_state }, |
| 1329 | 1322 | }; |
| 1330 | 1323 | switch (state_ptr.*) { |
| 1331 | | .unused => atom_ptr.* = try self.createAtom(), |
| 1324 | .unused => atom_ptr.* = try coff.createAtom(), |
| 1332 | 1325 | .pending_flush => return atom_ptr.*, |
| 1333 | 1326 | .flushed => {}, |
| 1334 | 1327 | } |
| 1335 | 1328 | state_ptr.* = .pending_flush; |
| 1336 | 1329 | const atom = atom_ptr.*; |
| 1337 | 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) { |
| 1339 | | .code => self.text_section_index.?, |
| 1340 | | .const_data => self.rdata_section_index.?, |
| 1331 | if (lazy_sym.ty != .anyerror_type) try coff.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) { |
| 1332 | .code => coff.text_section_index.?, |
| 1333 | .const_data => coff.rdata_section_index.?, |
| 1341 | 1334 | }); |
| 1342 | 1335 | return atom; |
| 1343 | 1336 | } |
| 1344 | 1337 | |
| 1345 | | pub fn getOrCreateAtomForNav(self: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index { |
| 1346 | | const gpa = self.base.comp.gpa; |
| 1347 | | const gop = try self.navs.getOrPut(gpa, nav_index); |
| 1338 | pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom.Index { |
| 1339 | const gpa = coff.base.comp.gpa; |
| 1340 | const gop = try coff.navs.getOrPut(gpa, nav_index); |
| 1348 | 1341 | if (!gop.found_existing) { |
| 1349 | 1342 | gop.value_ptr.* = .{ |
| 1350 | | .atom = try self.createAtom(), |
| 1351 | | .section = self.getNavOutputSection(nav_index), |
| 1343 | .atom = try coff.createAtom(), |
| 1344 | .section = coff.getNavOutputSection(nav_index), |
| 1352 | 1345 | .exports = .{}, |
| 1353 | 1346 | }; |
| 1354 | 1347 | } |
| 1355 | 1348 | return gop.value_ptr.atom; |
| 1356 | 1349 | } |
| 1357 | 1350 | |
| 1358 | | fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 { |
| 1359 | | const zcu = self.base.comp.zcu.?; |
| 1351 | fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 { |
| 1352 | const zcu = coff.base.comp.zcu.?; |
| 1360 | 1353 | const ip = &zcu.intern_pool; |
| 1361 | 1354 | const nav = ip.getNav(nav_index); |
| 1362 | 1355 | const ty = Type.fromInterned(nav.typeOf(ip)); |
| ... | ... | @@ -1365,17 +1358,17 @@ fn getNavOutputSection(self: *Coff, nav_index: InternPool.Nav.Index) u16 { |
| 1365 | 1358 | const index: u16 = blk: { |
| 1366 | 1359 | if (val.isUndefDeep(zcu)) { |
| 1367 | 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 | 1364 | switch (zig_ty) { |
| 1372 | 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 | 1367 | else => { |
| 1375 | 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 | 1376 | } |
| 1384 | 1377 | |
| 1385 | 1378 | fn updateNavCode( |
| 1386 | | self: *Coff, |
| 1379 | coff: *Coff, |
| 1387 | 1380 | pt: Zcu.PerThread, |
| 1388 | 1381 | nav_index: InternPool.Nav.Index, |
| 1389 | 1382 | code: []u8, |
| 1390 | | complex_type: coff.ComplexType, |
| 1383 | complex_type: coff_util.ComplexType, |
| 1391 | 1384 | ) !void { |
| 1392 | 1385 | const zcu = pt.zcu; |
| 1393 | 1386 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -1399,70 +1392,70 @@ fn updateNavCode( |
| 1399 | 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 | 1396 | const atom_index = nav_metadata.atom; |
| 1404 | | const atom = self.getAtom(atom_index); |
| 1397 | const atom = coff.getAtom(atom_index); |
| 1405 | 1398 | const sym_index = atom.getSymbolIndex().?; |
| 1406 | 1399 | const sect_index = nav_metadata.section; |
| 1407 | 1400 | const code_len = @as(u32, @intCast(code.len)); |
| 1408 | 1401 | |
| 1409 | 1402 | if (atom.size != 0) { |
| 1410 | | const sym = atom.getSymbolPtr(self); |
| 1411 | | try self.setSymbolName(sym, nav.fqn.toSlice(ip)); |
| 1412 | | sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1)); |
| 1403 | const sym = atom.getSymbolPtr(coff); |
| 1404 | try coff.setSymbolName(sym, nav.fqn.toSlice(ip)); |
| 1405 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_index + 1)); |
| 1413 | 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 | 1409 | const need_realloc = code.len > capacity or !required_alignment.check(sym.value); |
| 1417 | 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 | 1412 | log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr }); |
| 1420 | 1413 | log.debug(" (required alignment 0x{x}", .{required_alignment}); |
| 1421 | 1414 | |
| 1422 | 1415 | if (vaddr != sym.value) { |
| 1423 | 1416 | sym.value = vaddr; |
| 1424 | 1417 | log.debug(" (updating GOT entry)", .{}); |
| 1425 | | const got_entry_index = self.got_table.lookup.get(.{ .sym_index = sym_index }).?; |
| 1426 | | try self.writeOffsetTableEntry(got_entry_index); |
| 1427 | | self.markRelocsDirtyByTarget(.{ .sym_index = sym_index }); |
| 1418 | const got_entry_index = coff.got_table.lookup.get(.{ .sym_index = sym_index }).?; |
| 1419 | try coff.writeOffsetTableEntry(got_entry_index); |
| 1420 | coff.markRelocsDirtyByTarget(.{ .sym_index = sym_index }); |
| 1428 | 1421 | } |
| 1429 | 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 | 1426 | } else { |
| 1434 | | const sym = atom.getSymbolPtr(self); |
| 1435 | | try self.setSymbolName(sym, nav.fqn.toSlice(ip)); |
| 1436 | | sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1)); |
| 1427 | const sym = atom.getSymbolPtr(coff); |
| 1428 | try coff.setSymbolName(sym, nav.fqn.toSlice(ip)); |
| 1429 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_index + 1)); |
| 1437 | 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)); |
| 1440 | | errdefer self.freeAtom(atom_index); |
| 1432 | const vaddr = try coff.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0)); |
| 1433 | errdefer coff.freeAtom(atom_index); |
| 1441 | 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 | 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 { |
| 1452 | | if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index); |
| 1444 | pub fn freeNav(coff: *Coff, nav_index: InternPool.NavIndex) void { |
| 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 | 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 | 1451 | var kv = const_kv; |
| 1459 | | self.freeAtom(kv.value.atom); |
| 1452 | coff.freeAtom(kv.value.atom); |
| 1460 | 1453 | kv.value.exports.deinit(gpa); |
| 1461 | 1454 | } |
| 1462 | 1455 | } |
| 1463 | 1456 | |
| 1464 | 1457 | pub fn updateExports( |
| 1465 | | self: *Coff, |
| 1458 | coff: *Coff, |
| 1466 | 1459 | pt: Zcu.PerThread, |
| 1467 | 1460 | exported: Zcu.Exported, |
| 1468 | 1461 | export_indices: []const u32, |
| ... | ... | @@ -1473,7 +1466,7 @@ pub fn updateExports( |
| 1473 | 1466 | |
| 1474 | 1467 | const zcu = pt.zcu; |
| 1475 | 1468 | const ip = &zcu.intern_pool; |
| 1476 | | const comp = self.base.comp; |
| 1469 | const comp = coff.base.comp; |
| 1477 | 1470 | const target = comp.root_mod.resolved_target.result; |
| 1478 | 1471 | |
| 1479 | 1472 | if (comp.config.use_llvm) { |
| ... | ... | @@ -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 | 1511 | const gpa = comp.gpa; |
| 1519 | 1512 | |
| 1520 | 1513 | const metadata = switch (exported) { |
| 1521 | 1514 | .nav => |nav| blk: { |
| 1522 | | _ = try self.getOrCreateAtomForNav(nav); |
| 1523 | | break :blk self.navs.getPtr(nav).?; |
| 1515 | _ = try coff.getOrCreateAtomForNav(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 | 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 | 1521 | switch (res) { |
| 1529 | 1522 | .mcv => {}, |
| 1530 | 1523 | .fail => |em| { |
| ... | ... | @@ -1535,11 +1528,11 @@ pub fn updateExports( |
| 1535 | 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 | 1534 | const atom_index = metadata.atom; |
| 1542 | | const atom = self.getAtom(atom_index); |
| 1535 | const atom = coff.getAtom(atom_index); |
| 1543 | 1536 | |
| 1544 | 1537 | for (export_indices) |export_idx| { |
| 1545 | 1538 | const exp = zcu.all_exports.items[export_idx]; |
| ... | ... | @@ -1568,27 +1561,27 @@ pub fn updateExports( |
| 1568 | 1561 | } |
| 1569 | 1562 | |
| 1570 | 1563 | const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); |
| 1571 | | const sym_index = metadata.getExport(self, exp_name) orelse blk: { |
| 1572 | | const sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: { |
| 1573 | | const global = self.globals.items[global_index]; |
| 1564 | const sym_index = metadata.getExport(coff, exp_name) orelse blk: { |
| 1565 | const sym_index = if (coff.getGlobalIndex(exp_name)) |global_index| ind: { |
| 1566 | const global = coff.globals.items[global_index]; |
| 1574 | 1567 | // TODO this is just plain wrong as it all should happen in a single `resolveSymbols` |
| 1575 | 1568 | // pass. This will go away once we abstact away Zig's incremental compilation into |
| 1576 | 1569 | // its own module. |
| 1577 | | if (global.file == null and self.getSymbol(global).section_number == .UNDEFINED) { |
| 1578 | | _ = self.unresolved.swapRemove(global_index); |
| 1570 | if (global.file == null and coff.getSymbol(global).section_number == .UNDEFINED) { |
| 1571 | _ = coff.unresolved.swapRemove(global_index); |
| 1579 | 1572 | break :ind global.sym_index; |
| 1580 | 1573 | } |
| 1581 | | break :ind try self.allocateSymbol(); |
| 1582 | | } else try self.allocateSymbol(); |
| 1574 | break :ind try coff.allocateSymbol(); |
| 1575 | } else try coff.allocateSymbol(); |
| 1583 | 1576 | try metadata.exports.append(gpa, sym_index); |
| 1584 | 1577 | break :blk sym_index; |
| 1585 | 1578 | }; |
| 1586 | 1579 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1587 | | const sym = self.getSymbolPtr(sym_loc); |
| 1588 | | try self.setSymbolName(sym, exp_name); |
| 1589 | | sym.value = atom.getSymbol(self).value; |
| 1590 | | sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1)); |
| 1591 | | sym.type = atom.getSymbol(self).type; |
| 1580 | const sym = coff.getSymbolPtr(sym_loc); |
| 1581 | try coff.setSymbolName(sym, exp_name); |
| 1582 | sym.value = atom.getSymbol(coff).value; |
| 1583 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1)); |
| 1584 | sym.type = atom.getSymbol(coff).type; |
| 1592 | 1585 | |
| 1593 | 1586 | switch (exp.opts.linkage) { |
| 1594 | 1587 | .strong => { |
| ... | ... | @@ -1599,27 +1592,27 @@ pub fn updateExports( |
| 1599 | 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 | 1599 | pub fn deleteExport( |
| 1607 | | self: *Coff, |
| 1600 | coff: *Coff, |
| 1608 | 1601 | exported: Zcu.Exported, |
| 1609 | 1602 | name: InternPool.NullTerminatedString, |
| 1610 | 1603 | ) void { |
| 1611 | | if (self.llvm_object) |_| return; |
| 1604 | if (coff.llvm_object) |_| return; |
| 1612 | 1605 | const metadata = switch (exported) { |
| 1613 | | .nav => |nav| self.navs.getPtr(nav), |
| 1614 | | .uav => |uav| self.uavs.getPtr(uav), |
| 1606 | .nav => |nav| coff.navs.getPtr(nav), |
| 1607 | .uav => |uav| coff.uavs.getPtr(uav), |
| 1615 | 1608 | } orelse return; |
| 1616 | | const zcu = self.base.comp.zcu.?; |
| 1609 | const zcu = coff.base.comp.zcu.?; |
| 1617 | 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 | 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 | 1616 | log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)}); |
| 1624 | 1617 | assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED); |
| 1625 | 1618 | sym.* = .{ |
| ... | ... | @@ -1630,12 +1623,12 @@ pub fn deleteExport( |
| 1630 | 1623 | .storage_class = .NULL, |
| 1631 | 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 | 1629 | defer gpa.free(entry.key); |
| 1637 | | self.globals_free_list.append(gpa, entry.value) catch {}; |
| 1638 | | self.globals.items[entry.value] = .{ |
| 1630 | coff.globals_free_list.append(gpa, entry.value) catch {}; |
| 1631 | coff.globals.items[entry.value] = .{ |
| 1639 | 1632 | .sym_index = 0, |
| 1640 | 1633 | .file = null, |
| 1641 | 1634 | }; |
| ... | ... | @@ -1644,16 +1637,16 @@ pub fn deleteExport( |
| 1644 | 1637 | sym_index.* = 0; |
| 1645 | 1638 | } |
| 1646 | 1639 | |
| 1647 | | fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { |
| 1648 | | const gpa = self.base.comp.gpa; |
| 1649 | | const sym = self.getSymbol(current); |
| 1650 | | const sym_name = self.getSymbolName(current); |
| 1640 | fn resolveGlobalSymbol(coff: *Coff, current: SymbolWithLoc) !void { |
| 1641 | const gpa = coff.base.comp.gpa; |
| 1642 | const sym = coff.getSymbol(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 | 1646 | if (!gop.found_existing) { |
| 1654 | 1647 | gop.value_ptr.* = current; |
| 1655 | 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 | 1651 | return; |
| 1659 | 1652 | } |
| ... | ... | @@ -1662,33 +1655,560 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { |
| 1662 | 1655 | |
| 1663 | 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 | 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 { |
| 1671 | | const comp = self.base.comp; |
| 1663 | pub fn flush(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 1664 | const comp = coff.base.comp; |
| 1672 | 1665 | const use_lld = build_options.have_llvm and comp.config.use_lld; |
| 1673 | 1666 | if (use_lld) { |
| 1674 | | return lld.linkWithLLD(self, arena, tid, prog_node); |
| 1667 | return coff.linkWithLLD(arena, tid, prog_node); |
| 1675 | 1668 | } |
| 1676 | 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 | 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 | 1678 | const tracy = trace(@src()); |
| 1684 | 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 | 2207 | const gpa = comp.gpa; |
| 1688 | 2208 | const diags = &comp.link_diags; |
| 1689 | 2209 | |
| 1690 | | if (self.llvm_object) |llvm_object| { |
| 1691 | | try self.base.emitLlvmObject(arena, llvm_object, prog_node); |
| 2210 | if (coff.llvm_object) |llvm_object| { |
| 2211 | try coff.base.emitLlvmObject(arena, llvm_object, prog_node); |
| 1692 | 2212 | return; |
| 1693 | 2213 | } |
| 1694 | 2214 | |
| ... | ... | @@ -1700,46 +2220,46 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no |
| 1700 | 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 | 2224 | // Most lazy symbols can be updated on first use, but |
| 1705 | 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 | 2227 | pt, |
| 1708 | 2228 | .{ .kind = .code, .ty = .anyerror_type }, |
| 1709 | 2229 | metadata.text_atom, |
| 1710 | | self.text_section_index.?, |
| 2230 | coff.text_section_index.?, |
| 1711 | 2231 | ) catch |err| return switch (err) { |
| 1712 | 2232 | error.CodegenFail => error.FlushFailure, |
| 1713 | 2233 | else => |e| e, |
| 1714 | 2234 | }; |
| 1715 | | if (metadata.rdata_state != .unused) self.updateLazySymbolAtom( |
| 2235 | if (metadata.rdata_state != .unused) coff.updateLazySymbolAtom( |
| 1716 | 2236 | pt, |
| 1717 | 2237 | .{ .kind = .const_data, .ty = .anyerror_type }, |
| 1718 | 2238 | metadata.rdata_atom, |
| 1719 | | self.rdata_section_index.?, |
| 2239 | coff.rdata_section_index.?, |
| 1720 | 2240 | ) catch |err| return switch (err) { |
| 1721 | 2241 | error.CodegenFail => error.FlushFailure, |
| 1722 | 2242 | else => |e| e, |
| 1723 | 2243 | }; |
| 1724 | 2244 | } |
| 1725 | | for (self.lazy_syms.values()) |*metadata| { |
| 2245 | for (coff.lazy_syms.values()) |*metadata| { |
| 1726 | 2246 | if (metadata.text_state != .unused) metadata.text_state = .flushed; |
| 1727 | 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 | 2252 | while (it.next()) |entry| { |
| 1733 | | const global = self.globals.items[entry.key_ptr.*]; |
| 1734 | | try self.addGotEntry(global); |
| 2253 | const global = coff.globals.items[entry.key_ptr.*]; |
| 2254 | try coff.addGotEntry(global); |
| 1735 | 2255 | } |
| 1736 | 2256 | } |
| 1737 | 2257 | |
| 1738 | | while (self.unresolved.popOrNull()) |entry| { |
| 2258 | while (coff.unresolved.popOrNull()) |entry| { |
| 1739 | 2259 | assert(entry.value); |
| 1740 | | const global = self.globals.items[entry.key]; |
| 1741 | | const sym = self.getSymbol(global); |
| 1742 | | const res = try self.import_tables.getOrPut(gpa, sym.value); |
| 2260 | const global = coff.globals.items[entry.key]; |
| 2261 | const sym = coff.getSymbol(global); |
| 2262 | const res = try coff.import_tables.getOrPut(gpa, sym.value); |
| 1743 | 2263 | const itable = res.value_ptr; |
| 1744 | 2264 | if (!res.found_existing) { |
| 1745 | 2265 | itable.* = .{}; |
| ... | ... | @@ -1748,21 +2268,21 @@ pub fn flushModule(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no |
| 1748 | 2268 | // TODO: we could technically write the pointer placeholder for to-be-bound import here, |
| 1749 | 2269 | // but since this happens in flush, there is currently no point. |
| 1750 | 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 | 2277 | const needs_update = for (relocs.items) |reloc| { |
| 1758 | 2278 | if (reloc.dirty) break true; |
| 1759 | 2279 | } else false; |
| 1760 | 2280 | |
| 1761 | 2281 | if (!needs_update) continue; |
| 1762 | 2282 | |
| 1763 | | const atom = self.getAtom(atom_index); |
| 1764 | | const sym = atom.getSymbol(self); |
| 1765 | | const section = self.sections.get(@intFromEnum(sym.section_number) - 1).header; |
| 2283 | const atom = coff.getAtom(atom_index); |
| 2284 | const sym = atom.getSymbol(coff); |
| 2285 | const section = coff.sections.get(@intFromEnum(sym.section_number) - 1).header; |
| 1766 | 2286 | const file_offset = section.pointer_to_raw_data + sym.value - section.virtual_address; |
| 1767 | 2287 | |
| 1768 | 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 | 2290 | try code.resize(math.cast(usize, atom.size) orelse return error.Overflow); |
| 1771 | 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 | 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 | 2299 | // Update GOT if it got moved in memory. |
| 1780 | | if (self.got_table_contents_dirty) { |
| 1781 | | for (self.got_table.entries.items, 0..) |entry, i| { |
| 1782 | | if (!self.got_table.lookup.contains(entry)) continue; |
| 2300 | if (coff.got_table_contents_dirty) { |
| 2301 | for (coff.got_table.entries.items, 0..) |entry, i| { |
| 2302 | if (!coff.got_table.lookup.contains(entry)) continue; |
| 1783 | 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| { |
| 1792 | | self.entry_addr = self.getSymbol(entry_sym_loc).value; |
| 2311 | if (coff.getEntryPoint()) |entry_sym_loc| { |
| 2312 | coff.entry_addr = coff.getSymbol(entry_sym_loc).value; |
| 1793 | 2313 | } |
| 1794 | 2314 | |
| 1795 | 2315 | if (build_options.enable_logging) { |
| 1796 | | self.logSymtab(); |
| 1797 | | self.logImportTables(); |
| 2316 | coff.logSymtab(); |
| 2317 | coff.logImportTables(); |
| 1798 | 2318 | } |
| 1799 | 2319 | |
| 1800 | | try self.writeStrtab(); |
| 1801 | | try self.writeDataDirectoriesHeaders(); |
| 1802 | | try self.writeSectionHeaders(); |
| 2320 | try coff.writeStrtab(); |
| 2321 | try coff.writeDataDirectoriesHeaders(); |
| 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 | 2325 | log.debug("flushing. no_entry_point_found = true\n", .{}); |
| 1806 | 2326 | diags.flags.no_entry_point_found = true; |
| 1807 | 2327 | } else { |
| 1808 | 2328 | log.debug("flushing. no_entry_point_found = false\n", .{}); |
| 1809 | 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 | 2336 | pub fn getNavVAddr( |
| 1817 | | self: *Coff, |
| 2337 | coff: *Coff, |
| 1818 | 2338 | pt: Zcu.PerThread, |
| 1819 | 2339 | nav_index: InternPool.Nav.Index, |
| 1820 | 2340 | reloc_info: link.File.RelocInfo, |
| 1821 | 2341 | ) !u64 { |
| 1822 | | assert(self.llvm_object == null); |
| 2342 | assert(coff.llvm_object == null); |
| 1823 | 2343 | const zcu = pt.zcu; |
| 1824 | 2344 | const ip = &zcu.intern_pool; |
| 1825 | 2345 | const nav = ip.getNav(nav_index); |
| 1826 | 2346 | log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index }); |
| 1827 | 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)), |
| 1829 | | else => self.getAtom(try self.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?, |
| 2348 | .@"extern" => |@"extern"| try coff.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)), |
| 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 | 2352 | .sym_index = reloc_info.parent.atom_index, |
| 1833 | 2353 | .file = null, |
| 1834 | 2354 | }).?; |
| 1835 | 2355 | const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1836 | | try Atom.addRelocation(self, atom_index, .{ |
| 2356 | try coff.addRelocation(atom_index, .{ |
| 1837 | 2357 | .type = .direct, |
| 1838 | 2358 | .target = target, |
| 1839 | 2359 | .offset = @as(u32, @intCast(reloc_info.offset)), |
| ... | ... | @@ -1841,13 +2361,13 @@ pub fn getNavVAddr( |
| 1841 | 2361 | .pcrel = false, |
| 1842 | 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 | 2366 | return 0; |
| 1847 | 2367 | } |
| 1848 | 2368 | |
| 1849 | 2369 | pub fn lowerUav( |
| 1850 | | self: *Coff, |
| 2370 | coff: *Coff, |
| 1851 | 2371 | pt: Zcu.PerThread, |
| 1852 | 2372 | uav: InternPool.Index, |
| 1853 | 2373 | explicit_alignment: InternPool.Alignment, |
| ... | ... | @@ -1860,9 +2380,9 @@ pub fn lowerUav( |
| 1860 | 2380 | .none => val.typeOf(zcu).abiAlignment(zcu), |
| 1861 | 2381 | else => explicit_alignment, |
| 1862 | 2382 | }; |
| 1863 | | if (self.uavs.get(uav)) |metadata| { |
| 1864 | | const atom = self.getAtom(metadata.atom); |
| 1865 | | const existing_addr = atom.getSymbol(self).value; |
| 2383 | if (coff.uavs.get(uav)) |metadata| { |
| 2384 | const atom = coff.getAtom(metadata.atom); |
| 2385 | const existing_addr = atom.getSymbol(coff).value; |
| 1866 | 2386 | if (uav_alignment.check(existing_addr)) |
| 1867 | 2387 | return .{ .mcv = .{ .load_direct = atom.getSymbolIndex().? } }; |
| 1868 | 2388 | } |
| ... | ... | @@ -1871,12 +2391,12 @@ pub fn lowerUav( |
| 1871 | 2391 | const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ |
| 1872 | 2392 | @intFromEnum(uav), |
| 1873 | 2393 | }) catch unreachable; |
| 1874 | | const res = self.lowerConst( |
| 2394 | const res = coff.lowerConst( |
| 1875 | 2395 | pt, |
| 1876 | 2396 | name, |
| 1877 | 2397 | val, |
| 1878 | 2398 | uav_alignment, |
| 1879 | | self.rdata_section_index.?, |
| 2399 | coff.rdata_section_index.?, |
| 1880 | 2400 | src_loc, |
| 1881 | 2401 | ) catch |err| switch (err) { |
| 1882 | 2402 | error.OutOfMemory => return error.OutOfMemory, |
| ... | ... | @@ -1891,30 +2411,30 @@ pub fn lowerUav( |
| 1891 | 2411 | .ok => |atom_index| atom_index, |
| 1892 | 2412 | .fail => |em| return .{ .fail = em }, |
| 1893 | 2413 | }; |
| 1894 | | try self.uavs.put(gpa, uav, .{ |
| 2414 | try coff.uavs.put(gpa, uav, .{ |
| 1895 | 2415 | .atom = atom_index, |
| 1896 | | .section = self.rdata_section_index.?, |
| 2416 | .section = coff.rdata_section_index.?, |
| 1897 | 2417 | }); |
| 1898 | 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 | 2423 | pub fn getUavVAddr( |
| 1904 | | self: *Coff, |
| 2424 | coff: *Coff, |
| 1905 | 2425 | uav: InternPool.Index, |
| 1906 | 2426 | reloc_info: link.File.RelocInfo, |
| 1907 | 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; |
| 1911 | | const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; |
| 1912 | | const atom_index = self.getAtomIndexForSymbol(.{ |
| 2430 | const this_atom_index = coff.uavs.get(uav).?.atom; |
| 2431 | const sym_index = coff.getAtom(this_atom_index).getSymbolIndex().?; |
| 2432 | const atom_index = coff.getAtomIndexForSymbol(.{ |
| 1913 | 2433 | .sym_index = reloc_info.parent.atom_index, |
| 1914 | 2434 | .file = null, |
| 1915 | 2435 | }).?; |
| 1916 | 2436 | const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1917 | | try Atom.addRelocation(self, atom_index, .{ |
| 2437 | try coff.addRelocation(atom_index, .{ |
| 1918 | 2438 | .type = .direct, |
| 1919 | 2439 | .target = target, |
| 1920 | 2440 | .offset = @as(u32, @intCast(reloc_info.offset)), |
| ... | ... | @@ -1922,41 +2442,41 @@ pub fn getUavVAddr( |
| 1922 | 2442 | .pcrel = false, |
| 1923 | 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 | 2447 | return 0; |
| 1928 | 2448 | } |
| 1929 | 2449 | |
| 1930 | | pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 { |
| 1931 | | const gop = try self.getOrPutGlobalPtr(name); |
| 1932 | | const global_index = self.getGlobalIndex(name).?; |
| 2450 | pub fn getGlobalSymbol(coff: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 { |
| 2451 | const gop = try coff.getOrPutGlobalPtr(name); |
| 2452 | const global_index = coff.getGlobalIndex(name).?; |
| 1933 | 2453 | |
| 1934 | 2454 | if (gop.found_existing) { |
| 1935 | 2455 | return global_index; |
| 1936 | 2456 | } |
| 1937 | 2457 | |
| 1938 | | const sym_index = try self.allocateSymbol(); |
| 2458 | const sym_index = try coff.allocateSymbol(); |
| 1939 | 2459 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1940 | 2460 | gop.value_ptr.* = sym_loc; |
| 1941 | 2461 | |
| 1942 | | const gpa = self.base.comp.gpa; |
| 1943 | | const sym = self.getSymbolPtr(sym_loc); |
| 1944 | | try self.setSymbolName(sym, name); |
| 2462 | const gpa = coff.base.comp.gpa; |
| 2463 | const sym = coff.getSymbolPtr(sym_loc); |
| 2464 | try coff.setSymbolName(sym, name); |
| 1945 | 2465 | sym.storage_class = .EXTERNAL; |
| 1946 | 2466 | |
| 1947 | 2467 | if (lib_name_name) |lib_name| { |
| 1948 | 2468 | // We repurpose the 'value' of the Symbol struct to store an offset into |
| 1949 | 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 | 2475 | return global_index; |
| 1956 | 2476 | } |
| 1957 | 2477 | |
| 1958 | | pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void { |
| 1959 | | _ = self; |
| 2478 | pub fn updateDeclLineNumber(coff: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void { |
| 2479 | _ = coff; |
| 1960 | 2480 | _ = pt; |
| 1961 | 2481 | _ = decl_index; |
| 1962 | 2482 | log.debug("TODO implement updateDeclLineNumber", .{}); |
| ... | ... | @@ -1965,10 +2485,10 @@ pub fn updateDeclLineNumber(self: *Coff, pt: Zcu.PerThread, decl_index: InternPo |
| 1965 | 2485 | /// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table |
| 1966 | 2486 | /// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do |
| 1967 | 2487 | /// incremental updates and writes into the table instead of doing it all at once |
| 1968 | | fn writeBaseRelocations(self: *Coff) !void { |
| 1969 | | const gpa = self.base.comp.gpa; |
| 2488 | fn writeBaseRelocations(coff: *Coff) !void { |
| 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 | 2492 | defer { |
| 1973 | 2493 | var it = page_table.valueIterator(); |
| 1974 | 2494 | while (it.next()) |inner| { |
| ... | ... | @@ -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 | 2502 | while (it.next()) |entry| { |
| 1983 | 2503 | const atom_index = entry.key_ptr.*; |
| 1984 | | const atom = self.getAtom(atom_index); |
| 1985 | | const sym = atom.getSymbol(self); |
| 2504 | const atom = coff.getAtom(atom_index); |
| 2505 | const sym = atom.getSymbol(coff); |
| 1986 | 2506 | const offsets = entry.value_ptr.*; |
| 1987 | 2507 | |
| 1988 | 2508 | for (offsets.items) |offset| { |
| 1989 | 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 | 2511 | const gop = try page_table.getOrPut(page); |
| 1992 | 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 | 2515 | try gop.value_ptr.append(.{ |
| 1996 | 2516 | .offset = @as(u12, @intCast(rva - page)), |
| ... | ... | @@ -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.?]; |
| 2004 | | for (self.got_table.entries.items, 0..) |entry, index| { |
| 2005 | | if (!self.got_table.lookup.contains(entry)) continue; |
| 2523 | const header = &coff.sections.items(.header)[coff.got_section_index.?]; |
| 2524 | for (coff.got_table.entries.items, 0..) |entry, index| { |
| 2525 | if (!coff.got_table.lookup.contains(entry)) continue; |
| 2006 | 2526 | |
| 2007 | | const sym = self.getSymbol(entry); |
| 2527 | const sym = coff.getSymbol(entry); |
| 2008 | 2528 | if (sym.section_number == .UNDEFINED) continue; |
| 2009 | 2529 | |
| 2010 | | const rva = @as(u32, @intCast(header.virtual_address + index * self.ptr_width.size())); |
| 2011 | | const page = mem.alignBackward(u32, rva, self.page_size); |
| 2530 | const rva = @as(u32, @intCast(header.virtual_address + index * coff.ptr_width.size())); |
| 2531 | const page = mem.alignBackward(u32, rva, coff.page_size); |
| 2012 | 2532 | const gop = try page_table.getOrPut(page); |
| 2013 | 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 | 2536 | try gop.value_ptr.append(.{ |
| 2017 | 2537 | .offset = @as(u12, @intCast(rva - page)), |
| ... | ... | @@ -2040,7 +2560,7 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 2040 | 2560 | // Pad to required 4byte alignment |
| 2041 | 2561 | if (!mem.isAlignedGeneric( |
| 2042 | 2562 | usize, |
| 2043 | | entries.items.len * @sizeOf(coff.BaseRelocation), |
| 2563 | entries.items.len * @sizeOf(coff_util.BaseRelocation), |
| 2044 | 2564 | @sizeOf(u32), |
| 2045 | 2565 | )) { |
| 2046 | 2566 | try entries.append(.{ |
| ... | ... | @@ -2051,58 +2571,58 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 2051 | 2571 | |
| 2052 | 2572 | const block_size = @as( |
| 2053 | 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 | 2576 | try buffer.ensureUnusedCapacity(block_size); |
| 2057 | | buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{ |
| 2577 | buffer.appendSliceAssumeCapacity(mem.asBytes(&coff_util.BaseRelocationDirectoryEntry{ |
| 2058 | 2578 | .page_rva = page, |
| 2059 | 2579 | .block_size = block_size, |
| 2060 | 2580 | })); |
| 2061 | 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 | 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 | 2591 | .virtual_address = header.virtual_address, |
| 2072 | 2592 | .size = needed_size, |
| 2073 | 2593 | }; |
| 2074 | 2594 | } |
| 2075 | 2595 | |
| 2076 | | fn writeImportTables(self: *Coff) !void { |
| 2077 | | if (self.idata_section_index == null) return; |
| 2078 | | if (!self.imports_count_dirty) return; |
| 2596 | fn writeImportTables(coff: *Coff) !void { |
| 2597 | if (coff.idata_section_index == null) 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 | 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 | 2605 | // Calculate needed size |
| 2086 | 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 | 2608 | var lookup_table_size: u32 = 0; |
| 2089 | 2609 | var names_table_size: u32 = 0; |
| 2090 | 2610 | var dll_names_size: u32 = 0; |
| 2091 | | for (self.import_tables.keys(), 0..) |off, i| { |
| 2092 | | const lib_name = self.temp_strtab.getAssumeExists(off); |
| 2093 | | const itable = self.import_tables.values()[i]; |
| 2611 | for (coff.import_tables.keys(), 0..) |off, i| { |
| 2612 | const lib_name = coff.temp_strtab.getAssumeExists(off); |
| 2613 | const itable = coff.import_tables.values()[i]; |
| 2094 | 2614 | iat_size += itable.size() + 8; |
| 2095 | | dir_table_size += @sizeOf(coff.ImportDirectoryEntry); |
| 2096 | | lookup_table_size += @as(u32, @intCast(itable.entries.items.len + 1)) * @sizeOf(coff.ImportLookupEntry64.ByName); |
| 2615 | dir_table_size += @sizeOf(coff_util.ImportDirectoryEntry); |
| 2616 | lookup_table_size += @as(u32, @intCast(itable.entries.items.len + 1)) * @sizeOf(coff_util.ImportLookupEntry64.ByName); |
| 2097 | 2617 | for (itable.entries.items) |entry| { |
| 2098 | | const sym_name = self.getSymbolName(entry); |
| 2618 | const sym_name = coff.getSymbolName(entry); |
| 2099 | 2619 | names_table_size += 2 + mem.alignForward(u32, @as(u32, @intCast(sym_name.len + 1)), 2); |
| 2100 | 2620 | } |
| 2101 | 2621 | dll_names_size += @as(u32, @intCast(lib_name.len + ext.len + 1)); |
| 2102 | 2622 | } |
| 2103 | 2623 | |
| 2104 | 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 | 2627 | // Do the actual writes |
| 2108 | 2628 | var buffer = std.ArrayList(u8).init(gpa); |
| ... | ... | @@ -2110,41 +2630,41 @@ fn writeImportTables(self: *Coff) !void { |
| 2110 | 2630 | try buffer.ensureTotalCapacityPrecise(needed_size); |
| 2111 | 2631 | buffer.resize(needed_size) catch unreachable; |
| 2112 | 2632 | |
| 2113 | | const dir_header_size = @sizeOf(coff.ImportDirectoryEntry); |
| 2114 | | const lookup_entry_size = @sizeOf(coff.ImportLookupEntry64.ByName); |
| 2633 | const dir_header_size = @sizeOf(coff_util.ImportDirectoryEntry); |
| 2634 | const lookup_entry_size = @sizeOf(coff_util.ImportLookupEntry64.ByName); |
| 2115 | 2635 | |
| 2116 | 2636 | var iat_offset: u32 = 0; |
| 2117 | 2637 | var dir_table_offset = iat_size; |
| 2118 | 2638 | var lookup_table_offset = dir_table_offset + dir_table_size; |
| 2119 | 2639 | var names_table_offset = lookup_table_offset + lookup_table_size; |
| 2120 | 2640 | var dll_names_offset = names_table_offset + names_table_size; |
| 2121 | | for (self.import_tables.keys(), 0..) |off, i| { |
| 2122 | | const lib_name = self.temp_strtab.getAssumeExists(off); |
| 2123 | | const itable = self.import_tables.values()[i]; |
| 2641 | for (coff.import_tables.keys(), 0..) |off, i| { |
| 2642 | const lib_name = coff.temp_strtab.getAssumeExists(off); |
| 2643 | const itable = coff.import_tables.values()[i]; |
| 2124 | 2644 | |
| 2125 | 2645 | // Lookup table header |
| 2126 | | const lookup_header = coff.ImportDirectoryEntry{ |
| 2646 | const lookup_header = coff_util.ImportDirectoryEntry{ |
| 2127 | 2647 | .import_lookup_table_rva = header.virtual_address + lookup_table_offset, |
| 2128 | 2648 | .time_date_stamp = 0, |
| 2129 | 2649 | .forwarder_chain = 0, |
| 2130 | 2650 | .name_rva = header.virtual_address + dll_names_offset, |
| 2131 | 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 | 2654 | dir_table_offset += dir_header_size; |
| 2135 | 2655 | |
| 2136 | 2656 | for (itable.entries.items) |entry| { |
| 2137 | | const import_name = self.getSymbolName(entry); |
| 2657 | const import_name = coff.getSymbolName(entry); |
| 2138 | 2658 | |
| 2139 | 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 | 2661 | @memcpy( |
| 2142 | | buffer.items[iat_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)], |
| 2662 | buffer.items[iat_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)], |
| 2143 | 2663 | mem.asBytes(&lookup), |
| 2144 | 2664 | ); |
| 2145 | 2665 | iat_offset += lookup_entry_size; |
| 2146 | 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 | 2668 | mem.asBytes(&lookup), |
| 2149 | 2669 | ); |
| 2150 | 2670 | lookup_table_offset += lookup_entry_size; |
| ... | ... | @@ -2168,8 +2688,8 @@ fn writeImportTables(self: *Coff) !void { |
| 2168 | 2688 | |
| 2169 | 2689 | // Lookup table sentinel |
| 2170 | 2690 | @memcpy( |
| 2171 | | buffer.items[lookup_table_offset..][0..@sizeOf(coff.ImportLookupEntry64.ByName)], |
| 2172 | | mem.asBytes(&coff.ImportLookupEntry64.ByName{ .name_table_rva = 0 }), |
| 2691 | buffer.items[lookup_table_offset..][0..@sizeOf(coff_util.ImportLookupEntry64.ByName)], |
| 2692 | mem.asBytes(&coff_util.ImportLookupEntry64.ByName{ .name_table_rva = 0 }), |
| 2173 | 2693 | ); |
| 2174 | 2694 | lookup_table_offset += lookup_entry_size; |
| 2175 | 2695 | |
| ... | ... | @@ -2183,7 +2703,7 @@ fn writeImportTables(self: *Coff) !void { |
| 2183 | 2703 | } |
| 2184 | 2704 | |
| 2185 | 2705 | // Sentinel |
| 2186 | | const lookup_header = coff.ImportDirectoryEntry{ |
| 2706 | const lookup_header = coff_util.ImportDirectoryEntry{ |
| 2187 | 2707 | .import_lookup_table_rva = 0, |
| 2188 | 2708 | .time_date_stamp = 0, |
| 2189 | 2709 | .forwarder_chain = 0, |
| ... | ... | @@ -2191,93 +2711,93 @@ fn writeImportTables(self: *Coff) !void { |
| 2191 | 2711 | .import_address_table_rva = 0, |
| 2192 | 2712 | }; |
| 2193 | 2713 | @memcpy( |
| 2194 | | buffer.items[dir_table_offset..][0..@sizeOf(coff.ImportDirectoryEntry)], |
| 2714 | buffer.items[dir_table_offset..][0..@sizeOf(coff_util.ImportDirectoryEntry)], |
| 2195 | 2715 | mem.asBytes(&lookup_header), |
| 2196 | 2716 | ); |
| 2197 | 2717 | dir_table_offset += dir_header_size; |
| 2198 | 2718 | |
| 2199 | 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 | 2724 | .virtual_address = header.virtual_address + iat_size, |
| 2205 | 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 | 2728 | .virtual_address = header.virtual_address, |
| 2209 | 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 { |
| 2216 | | if (self.strtab_offset == null) return; |
| 2735 | fn writeStrtab(coff: *Coff) !void { |
| 2736 | if (coff.strtab_offset == null) return; |
| 2217 | 2737 | |
| 2218 | | const allocated_size = self.allocatedSize(self.strtab_offset.?); |
| 2219 | | const needed_size = @as(u32, @intCast(self.strtab.buffer.items.len)); |
| 2738 | const allocated_size = coff.allocatedSize(coff.strtab_offset.?); |
| 2739 | const needed_size = @as(u32, @intCast(coff.strtab.buffer.items.len)); |
| 2220 | 2740 | |
| 2221 | 2741 | if (needed_size > allocated_size) { |
| 2222 | | self.strtab_offset = null; |
| 2223 | | self.strtab_offset = @as(u32, @intCast(self.findFreeSpace(needed_size, @alignOf(u32)))); |
| 2742 | coff.strtab_offset = null; |
| 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 | 2749 | var buffer = std.ArrayList(u8).init(gpa); |
| 2230 | 2750 | defer buffer.deinit(); |
| 2231 | 2751 | try buffer.ensureTotalCapacityPrecise(needed_size); |
| 2232 | | buffer.appendSliceAssumeCapacity(self.strtab.buffer.items); |
| 2752 | buffer.appendSliceAssumeCapacity(coff.strtab.buffer.items); |
| 2233 | 2753 | // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead |
| 2234 | 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 { |
| 2241 | | const offset = self.getSectionHeadersOffset(); |
| 2242 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items(.header)), offset); |
| 2760 | fn writeSectionHeaders(coff: *Coff) !void { |
| 2761 | const offset = coff.getSectionHeadersOffset(); |
| 2762 | try coff.base.file.?.pwriteAll(mem.sliceAsBytes(coff.sections.items(.header)), offset); |
| 2243 | 2763 | } |
| 2244 | 2764 | |
| 2245 | | fn writeDataDirectoriesHeaders(self: *Coff) !void { |
| 2246 | | const offset = self.getDataDirectoryHeadersOffset(); |
| 2247 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(&self.data_directories), offset); |
| 2765 | fn writeDataDirectoriesHeaders(coff: *Coff) !void { |
| 2766 | const offset = coff.getDataDirectoryHeadersOffset(); |
| 2767 | try coff.base.file.?.pwriteAll(mem.sliceAsBytes(&coff.data_directories), offset); |
| 2248 | 2768 | } |
| 2249 | 2769 | |
| 2250 | | fn writeHeader(self: *Coff) !void { |
| 2251 | | const target = self.base.comp.root_mod.resolved_target.result; |
| 2252 | | const gpa = self.base.comp.gpa; |
| 2770 | fn writeHeader(coff: *Coff) !void { |
| 2771 | const target = coff.base.comp.root_mod.resolved_target.result; |
| 2772 | const gpa = coff.base.comp.gpa; |
| 2253 | 2773 | var buffer = std.ArrayList(u8).init(gpa); |
| 2254 | 2774 | defer buffer.deinit(); |
| 2255 | 2775 | const writer = buffer.writer(); |
| 2256 | 2776 | |
| 2257 | | try buffer.ensureTotalCapacity(self.getSizeOfHeaders()); |
| 2777 | try buffer.ensureTotalCapacity(coff.getSizeOfHeaders()); |
| 2258 | 2778 | writer.writeAll(msdos_stub) catch unreachable; |
| 2259 | 2779 | mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little); |
| 2260 | 2780 | |
| 2261 | 2781 | writer.writeAll("PE\x00\x00") catch unreachable; |
| 2262 | | var flags = coff.CoffHeaderFlags{ |
| 2782 | var flags = coff_util.CoffHeaderFlags{ |
| 2263 | 2783 | .EXECUTABLE_IMAGE = 1, |
| 2264 | 2784 | .DEBUG_STRIPPED = 1, // TODO |
| 2265 | 2785 | }; |
| 2266 | | switch (self.ptr_width) { |
| 2786 | switch (coff.ptr_width) { |
| 2267 | 2787 | .p32 => flags.@"32BIT_MACHINE" = 1, |
| 2268 | 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 | 2791 | flags.DLL = 1; |
| 2272 | 2792 | } |
| 2273 | 2793 | |
| 2274 | | const timestamp = if (self.repro) 0 else std.time.timestamp(); |
| 2275 | | const size_of_optional_header = @as(u16, @intCast(self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize())); |
| 2276 | | var coff_header = coff.CoffHeader{ |
| 2794 | const timestamp = if (coff.repro) 0 else std.time.timestamp(); |
| 2795 | const size_of_optional_header = @as(u16, @intCast(coff.getOptionalHeaderSize() + coff.getDataDirectoryHeadersSize())); |
| 2796 | var coff_header = coff_util.CoffHeader{ |
| 2277 | 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 | 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 | 2801 | .number_of_symbols = 0, |
| 2282 | 2802 | .size_of_optional_header = size_of_optional_header, |
| 2283 | 2803 | .flags = flags, |
| ... | ... | @@ -2285,22 +2805,22 @@ fn writeHeader(self: *Coff) !void { |
| 2285 | 2805 | |
| 2286 | 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 | 2809 | .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all? |
| 2290 | 2810 | .DYNAMIC_BASE = 1, |
| 2291 | 2811 | .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app |
| 2292 | 2812 | .NX_COMPAT = 1, // We are compatible with Data Execution Prevention |
| 2293 | 2813 | }; |
| 2294 | | const subsystem: coff.Subsystem = .WINDOWS_CUI; |
| 2295 | | const size_of_image: u32 = self.getSizeOfImage(); |
| 2296 | | const size_of_headers: u32 = mem.alignForward(u32, self.getSizeOfHeaders(), default_file_alignment); |
| 2297 | | const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address; |
| 2298 | | const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address; |
| 2814 | const subsystem: coff_util.Subsystem = .WINDOWS_CUI; |
| 2815 | const size_of_image: u32 = coff.getSizeOfImage(); |
| 2816 | const size_of_headers: u32 = mem.alignForward(u32, coff.getSizeOfHeaders(), default_file_alignment); |
| 2817 | const base_of_code = coff.sections.get(coff.text_section_index.?).header.virtual_address; |
| 2818 | const base_of_data = coff.sections.get(coff.data_section_index.?).header.virtual_address; |
| 2299 | 2819 | |
| 2300 | 2820 | var size_of_code: u32 = 0; |
| 2301 | 2821 | var size_of_initialized_data: u32 = 0; |
| 2302 | 2822 | var size_of_uninitialized_data: u32 = 0; |
| 2303 | | for (self.sections.items(.header)) |header| { |
| 2823 | for (coff.sections.items(.header)) |header| { |
| 2304 | 2824 | if (header.flags.CNT_CODE == 1) { |
| 2305 | 2825 | size_of_code += header.size_of_raw_data; |
| 2306 | 2826 | } |
| ... | ... | @@ -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 | 2836 | .p32 => { |
| 2317 | | var opt_header = coff.OptionalHeaderPE32{ |
| 2318 | | .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC, |
| 2837 | var opt_header = coff_util.OptionalHeaderPE32{ |
| 2838 | .magic = coff_util.IMAGE_NT_OPTIONAL_HDR32_MAGIC, |
| 2319 | 2839 | .major_linker_version = 0, |
| 2320 | 2840 | .minor_linker_version = 0, |
| 2321 | 2841 | .size_of_code = size_of_code, |
| 2322 | 2842 | .size_of_initialized_data = size_of_initialized_data, |
| 2323 | 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 | 2845 | .base_of_code = base_of_code, |
| 2326 | 2846 | .base_of_data = base_of_data, |
| 2327 | | .image_base = @intCast(self.image_base), |
| 2328 | | .section_alignment = self.page_size, |
| 2847 | .image_base = @intCast(coff.image_base), |
| 2848 | .section_alignment = coff.page_size, |
| 2329 | 2849 | .file_alignment = default_file_alignment, |
| 2330 | 2850 | .major_operating_system_version = 6, |
| 2331 | 2851 | .minor_operating_system_version = 0, |
| 2332 | 2852 | .major_image_version = 0, |
| 2333 | 2853 | .minor_image_version = 0, |
| 2334 | | .major_subsystem_version = @intCast(self.major_subsystem_version), |
| 2335 | | .minor_subsystem_version = @intCast(self.minor_subsystem_version), |
| 2854 | .major_subsystem_version = @intCast(coff.major_subsystem_version), |
| 2855 | .minor_subsystem_version = @intCast(coff.minor_subsystem_version), |
| 2336 | 2856 | .win32_version_value = 0, |
| 2337 | 2857 | .size_of_image = size_of_image, |
| 2338 | 2858 | .size_of_headers = size_of_headers, |
| ... | ... | @@ -2344,29 +2864,29 @@ fn writeHeader(self: *Coff) !void { |
| 2344 | 2864 | .size_of_heap_reserve = default_size_of_heap_reserve, |
| 2345 | 2865 | .size_of_heap_commit = default_size_of_heap_commit, |
| 2346 | 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 | 2869 | writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; |
| 2350 | 2870 | }, |
| 2351 | 2871 | .p64 => { |
| 2352 | | var opt_header = coff.OptionalHeaderPE64{ |
| 2353 | | .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC, |
| 2872 | var opt_header = coff_util.OptionalHeaderPE64{ |
| 2873 | .magic = coff_util.IMAGE_NT_OPTIONAL_HDR64_MAGIC, |
| 2354 | 2874 | .major_linker_version = 0, |
| 2355 | 2875 | .minor_linker_version = 0, |
| 2356 | 2876 | .size_of_code = size_of_code, |
| 2357 | 2877 | .size_of_initialized_data = size_of_initialized_data, |
| 2358 | 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 | 2880 | .base_of_code = base_of_code, |
| 2361 | | .image_base = self.image_base, |
| 2362 | | .section_alignment = self.page_size, |
| 2881 | .image_base = coff.image_base, |
| 2882 | .section_alignment = coff.page_size, |
| 2363 | 2883 | .file_alignment = default_file_alignment, |
| 2364 | 2884 | .major_operating_system_version = 6, |
| 2365 | 2885 | .minor_operating_system_version = 0, |
| 2366 | 2886 | .major_image_version = 0, |
| 2367 | 2887 | .minor_image_version = 0, |
| 2368 | | .major_subsystem_version = self.major_subsystem_version, |
| 2369 | | .minor_subsystem_version = self.minor_subsystem_version, |
| 2888 | .major_subsystem_version = coff.major_subsystem_version, |
| 2889 | .minor_subsystem_version = coff.minor_subsystem_version, |
| 2370 | 2890 | .win32_version_value = 0, |
| 2371 | 2891 | .size_of_image = size_of_image, |
| 2372 | 2892 | .size_of_headers = size_of_headers, |
| ... | ... | @@ -2378,28 +2898,28 @@ fn writeHeader(self: *Coff) !void { |
| 2378 | 2898 | .size_of_heap_reserve = default_size_of_heap_reserve, |
| 2379 | 2899 | .size_of_heap_commit = default_size_of_heap_commit, |
| 2380 | 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 | 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 | 2910 | pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 2391 | 2911 | return actual_size +| (actual_size / ideal_factor); |
| 2392 | 2912 | } |
| 2393 | 2913 | |
| 2394 | | fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 { |
| 2395 | | const headers_size = @max(self.getSizeOfHeaders(), self.page_size); |
| 2914 | fn detectAllocCollision(coff: *Coff, start: u32, size: u32) ?u32 { |
| 2915 | const headers_size = @max(coff.getSizeOfHeaders(), coff.page_size); |
| 2396 | 2916 | if (start < headers_size) |
| 2397 | 2917 | return headers_size; |
| 2398 | 2918 | |
| 2399 | 2919 | const end = start + padToIdeal(size); |
| 2400 | 2920 | |
| 2401 | | if (self.strtab_offset) |off| { |
| 2402 | | const tight_size = @as(u32, @intCast(self.strtab.buffer.items.len)); |
| 2921 | if (coff.strtab_offset) |off| { |
| 2922 | const tight_size = @as(u32, @intCast(coff.strtab.buffer.items.len)); |
| 2403 | 2923 | const increased_size = padToIdeal(tight_size); |
| 2404 | 2924 | const test_end = off + increased_size; |
| 2405 | 2925 | if (end > off and start < test_end) { |
| ... | ... | @@ -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 | 2931 | const tight_size = header.size_of_raw_data; |
| 2412 | 2932 | const increased_size = padToIdeal(tight_size); |
| 2413 | 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 | 2939 | return null; |
| 2420 | 2940 | } |
| 2421 | 2941 | |
| 2422 | | fn allocatedSize(self: *Coff, start: u32) u32 { |
| 2942 | fn allocatedSize(coff: *Coff, start: u32) u32 { |
| 2423 | 2943 | if (start == 0) |
| 2424 | 2944 | return 0; |
| 2425 | 2945 | var min_pos: u32 = std.math.maxInt(u32); |
| 2426 | | if (self.strtab_offset) |off| { |
| 2946 | if (coff.strtab_offset) |off| { |
| 2427 | 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 | 2950 | if (header.pointer_to_raw_data <= start) continue; |
| 2431 | 2951 | if (header.pointer_to_raw_data < min_pos) min_pos = header.pointer_to_raw_data; |
| 2432 | 2952 | } |
| 2433 | 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 | 2957 | var start: u32 = 0; |
| 2438 | | while (self.detectAllocCollision(start, object_size)) |item_end| { |
| 2958 | while (coff.detectAllocCollision(start, object_size)) |item_end| { |
| 2439 | 2959 | start = mem.alignForward(u32, item_end, min_alignment); |
| 2440 | 2960 | } |
| 2441 | 2961 | return start; |
| 2442 | 2962 | } |
| 2443 | 2963 | |
| 2444 | | fn allocatedVirtualSize(self: *Coff, start: u32) u32 { |
| 2964 | fn allocatedVirtualSize(coff: *Coff, start: u32) u32 { |
| 2445 | 2965 | if (start == 0) |
| 2446 | 2966 | return 0; |
| 2447 | 2967 | var min_pos: u32 = std.math.maxInt(u32); |
| 2448 | | for (self.sections.items(.header)) |header| { |
| 2968 | for (coff.sections.items(.header)) |header| { |
| 2449 | 2969 | if (header.virtual_address <= start) continue; |
| 2450 | 2970 | if (header.virtual_address < min_pos) min_pos = header.virtual_address; |
| 2451 | 2971 | } |
| 2452 | 2972 | return min_pos - start; |
| 2453 | 2973 | } |
| 2454 | 2974 | |
| 2455 | | inline fn getSizeOfHeaders(self: Coff) u32 { |
| 2975 | fn getSizeOfHeaders(coff: Coff) u32 { |
| 2456 | 2976 | const msdos_hdr_size = msdos_stub.len + 4; |
| 2457 | | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() + |
| 2458 | | self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize())); |
| 2977 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize() + |
| 2978 | coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize())); |
| 2459 | 2979 | } |
| 2460 | 2980 | |
| 2461 | | inline fn getOptionalHeaderSize(self: Coff) u32 { |
| 2462 | | return switch (self.ptr_width) { |
| 2463 | | .p32 => @as(u32, @intCast(@sizeOf(coff.OptionalHeaderPE32))), |
| 2464 | | .p64 => @as(u32, @intCast(@sizeOf(coff.OptionalHeaderPE64))), |
| 2981 | fn getOptionalHeaderSize(coff: Coff) u32 { |
| 2982 | return switch (coff.ptr_width) { |
| 2983 | .p32 => @as(u32, @intCast(@sizeOf(coff_util.OptionalHeaderPE32))), |
| 2984 | .p64 => @as(u32, @intCast(@sizeOf(coff_util.OptionalHeaderPE64))), |
| 2465 | 2985 | }; |
| 2466 | 2986 | } |
| 2467 | 2987 | |
| 2468 | | inline fn getDataDirectoryHeadersSize(self: Coff) u32 { |
| 2469 | | return @as(u32, @intCast(self.data_directories.len * @sizeOf(coff.ImageDataDirectory))); |
| 2988 | fn getDataDirectoryHeadersSize(coff: Coff) u32 { |
| 2989 | return @as(u32, @intCast(coff.data_directories.len * @sizeOf(coff_util.ImageDataDirectory))); |
| 2470 | 2990 | } |
| 2471 | 2991 | |
| 2472 | | inline fn getSectionHeadersSize(self: Coff) u32 { |
| 2473 | | return @as(u32, @intCast(self.sections.slice().len * @sizeOf(coff.SectionHeader))); |
| 2992 | fn getSectionHeadersSize(coff: Coff) u32 { |
| 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 | 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 { |
| 2482 | | return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize(); |
| 3001 | fn getSectionHeadersOffset(coff: Coff) u32 { |
| 3002 | return coff.getDataDirectoryHeadersOffset() + coff.getDataDirectoryHeadersSize(); |
| 2483 | 3003 | } |
| 2484 | 3004 | |
| 2485 | | inline fn getSizeOfImage(self: Coff) u32 { |
| 2486 | | var image_size: u32 = mem.alignForward(u32, self.getSizeOfHeaders(), self.page_size); |
| 2487 | | for (self.sections.items(.header)) |header| { |
| 2488 | | image_size += mem.alignForward(u32, header.virtual_size, self.page_size); |
| 3005 | fn getSizeOfImage(coff: Coff) u32 { |
| 3006 | var image_size: u32 = mem.alignForward(u32, coff.getSizeOfHeaders(), coff.page_size); |
| 3007 | for (coff.sections.items(.header)) |header| { |
| 3008 | image_size += mem.alignForward(u32, header.virtual_size, coff.page_size); |
| 2489 | 3009 | } |
| 2490 | 3010 | return image_size; |
| 2491 | 3011 | } |
| 2492 | 3012 | |
| 2493 | 3013 | /// Returns symbol location corresponding to the set entrypoint (if any). |
| 2494 | | pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { |
| 2495 | | const comp = self.base.comp; |
| 3014 | pub fn getEntryPoint(coff: Coff) ?SymbolWithLoc { |
| 3015 | const comp = coff.base.comp; |
| 2496 | 3016 | |
| 2497 | 3017 | // TODO This is incomplete. |
| 2498 | 3018 | // The entry symbol name depends on the subsystem as well as the set of |
| 2499 | 3019 | // public symbol names from linked objects. |
| 2500 | 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 | 3022 | .disabled => return null, |
| 2503 | 3023 | .default => switch (comp.config.output_mode) { |
| 2504 | 3024 | .Exe => "wWinMainCRTStartup", |
| ... | ... | @@ -2507,51 +3027,51 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { |
| 2507 | 3027 | .enabled => "wWinMainCRTStartup", |
| 2508 | 3028 | .named => |name| name, |
| 2509 | 3029 | }; |
| 2510 | | const global_index = self.resolver.get(entry_name) orelse return null; |
| 2511 | | return self.globals.items[global_index]; |
| 3030 | const global_index = coff.resolver.get(entry_name) orelse return null; |
| 3031 | return coff.globals.items[global_index]; |
| 2512 | 3032 | } |
| 2513 | 3033 | |
| 2514 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 3054 | /// Returns pointer to the global entry for `name` if one exists. |
| 2535 | | pub fn getGlobalPtr(self: *Coff, name: []const u8) ?*SymbolWithLoc { |
| 2536 | | const global_index = self.resolver.get(name) orelse return null; |
| 2537 | | return &self.globals.items[global_index]; |
| 3055 | pub fn getGlobalPtr(coff: *Coff, name: []const u8) ?*SymbolWithLoc { |
| 3056 | const global_index = coff.resolver.get(name) orelse return null; |
| 3057 | return &coff.globals.items[global_index]; |
| 2538 | 3058 | } |
| 2539 | 3059 | |
| 2540 | 3060 | /// Returns the global entry for `name` if one exists. |
| 2541 | | pub fn getGlobal(self: *const Coff, name: []const u8) ?SymbolWithLoc { |
| 2542 | | const global_index = self.resolver.get(name) orelse return null; |
| 2543 | | return self.globals.items[global_index]; |
| 3061 | pub fn getGlobal(coff: *const Coff, name: []const u8) ?SymbolWithLoc { |
| 3062 | const global_index = coff.resolver.get(name) orelse return null; |
| 3063 | return coff.globals.items[global_index]; |
| 2544 | 3064 | } |
| 2545 | 3065 | |
| 2546 | 3066 | /// Returns the index of the global entry for `name` if one exists. |
| 2547 | | pub fn getGlobalIndex(self: *const Coff, name: []const u8) ?u32 { |
| 2548 | | return self.resolver.get(name); |
| 3067 | pub fn getGlobalIndex(coff: *const Coff, name: []const u8) ?u32 { |
| 3068 | return coff.resolver.get(name); |
| 2549 | 3069 | } |
| 2550 | 3070 | |
| 2551 | 3071 | /// Returns global entry at `index`. |
| 2552 | | pub fn getGlobalByIndex(self: *const Coff, index: u32) SymbolWithLoc { |
| 2553 | | assert(index < self.globals.items.len); |
| 2554 | | return self.globals.items[index]; |
| 3072 | pub fn getGlobalByIndex(coff: *const Coff, index: u32) SymbolWithLoc { |
| 3073 | assert(index < coff.globals.items.len); |
| 3074 | return coff.globals.items[index]; |
| 2555 | 3075 | } |
| 2556 | 3076 | |
| 2557 | 3077 | const GetOrPutGlobalPtrResult = struct { |
| ... | ... | @@ -2567,68 +3087,68 @@ pub const global_symbol_mask: u32 = 0x7fffffff; |
| 2567 | 3087 | /// Return pointer to the global entry for `name` if one exists. |
| 2568 | 3088 | /// Puts a new global entry for `name` if one doesn't exist, and |
| 2569 | 3089 | /// returns a pointer to it. |
| 2570 | | pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult { |
| 2571 | | if (self.getGlobalPtr(name)) |ptr| { |
| 3090 | pub fn getOrPutGlobalPtr(coff: *Coff, name: []const u8) !GetOrPutGlobalPtrResult { |
| 3091 | if (coff.getGlobalPtr(name)) |ptr| { |
| 2572 | 3092 | return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr }; |
| 2573 | 3093 | } |
| 2574 | | const gpa = self.base.comp.gpa; |
| 2575 | | const global_index = try self.allocateGlobal(); |
| 3094 | const gpa = coff.base.comp.gpa; |
| 3095 | const global_index = try coff.allocateGlobal(); |
| 2576 | 3096 | const global_name = try gpa.dupe(u8, name); |
| 2577 | | _ = try self.resolver.put(gpa, global_name, global_index); |
| 2578 | | const ptr = &self.globals.items[global_index]; |
| 3097 | _ = try coff.resolver.put(gpa, global_name, global_index); |
| 3098 | const ptr = &coff.globals.items[global_index]; |
| 2579 | 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 { |
| 2583 | | assert(atom_index < self.atoms.items.len); |
| 2584 | | return self.atoms.items[atom_index]; |
| 3102 | pub fn getAtom(coff: *const Coff, atom_index: Atom.Index) Atom { |
| 3103 | assert(atom_index < coff.atoms.items.len); |
| 3104 | return coff.atoms.items[atom_index]; |
| 2585 | 3105 | } |
| 2586 | 3106 | |
| 2587 | | pub fn getAtomPtr(self: *Coff, atom_index: Atom.Index) *Atom { |
| 2588 | | assert(atom_index < self.atoms.items.len); |
| 2589 | | return &self.atoms.items[atom_index]; |
| 3107 | pub fn getAtomPtr(coff: *Coff, atom_index: Atom.Index) *Atom { |
| 3108 | assert(atom_index < coff.atoms.items.len); |
| 3109 | return &coff.atoms.items[atom_index]; |
| 2590 | 3110 | } |
| 2591 | 3111 | |
| 2592 | 3112 | /// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor. |
| 2593 | 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 | 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 | 3120 | if (name.len <= 8) { |
| 2601 | 3121 | @memcpy(header.name[0..name.len], name); |
| 2602 | 3122 | @memset(header.name[name.len..], 0); |
| 2603 | 3123 | return; |
| 2604 | 3124 | } |
| 2605 | | const gpa = self.base.comp.gpa; |
| 2606 | | const offset = try self.strtab.insert(gpa, name); |
| 3125 | const gpa = coff.base.comp.gpa; |
| 3126 | const offset = try coff.strtab.insert(gpa, name); |
| 2607 | 3127 | const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable; |
| 2608 | 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 | 3132 | if (header.getName()) |name| { |
| 2613 | 3133 | return name; |
| 2614 | 3134 | } |
| 2615 | 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 | 3140 | if (name.len <= 8) { |
| 2621 | 3141 | @memcpy(symbol.name[0..name.len], name); |
| 2622 | 3142 | @memset(symbol.name[name.len..], 0); |
| 2623 | 3143 | return; |
| 2624 | 3144 | } |
| 2625 | | const gpa = self.base.comp.gpa; |
| 2626 | | const offset = try self.strtab.insert(gpa, name); |
| 3145 | const gpa = coff.base.comp.gpa; |
| 3146 | const offset = try coff.strtab.insert(gpa, name); |
| 2627 | 3147 | @memset(symbol.name[0..4], 0); |
| 2628 | 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 | 3152 | @memset(buf[0..4], '_'); |
| 2633 | 3153 | switch (sym.section_number) { |
| 2634 | 3154 | .UNDEFINED => { |
| ... | ... | @@ -2655,12 +3175,12 @@ fn logSymAttributes(sym: *const coff.Symbol, buf: *[4]u8) []const u8 { |
| 2655 | 3175 | return buf[0..]; |
| 2656 | 3176 | } |
| 2657 | 3177 | |
| 2658 | | fn logSymtab(self: *Coff) void { |
| 3178 | fn logSymtab(coff: *Coff) void { |
| 2659 | 3179 | var buf: [4]u8 = undefined; |
| 2660 | 3180 | |
| 2661 | 3181 | log.debug("symtab:", .{}); |
| 2662 | 3182 | log.debug(" object(null)", .{}); |
| 2663 | | for (self.locals.items, 0..) |*sym, sym_id| { |
| 3183 | for (coff.locals.items, 0..) |*sym, sym_id| { |
| 2664 | 3184 | const where = if (sym.section_number == .UNDEFINED) "ord" else "sect"; |
| 2665 | 3185 | const def_index: u16 = switch (sym.section_number) { |
| 2666 | 3186 | .UNDEFINED => 0, // TODO |
| ... | ... | @@ -2670,7 +3190,7 @@ fn logSymtab(self: *Coff) void { |
| 2670 | 3190 | }; |
| 2671 | 3191 | log.debug(" %{d}: {?s} @{x} in {s}({d}), {s}", .{ |
| 2672 | 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 | 3194 | sym.value, |
| 2675 | 3195 | where, |
| 2676 | 3196 | def_index, |
| ... | ... | @@ -2679,20 +3199,20 @@ fn logSymtab(self: *Coff) void { |
| 2679 | 3199 | } |
| 2680 | 3200 | |
| 2681 | 3201 | log.debug("globals table:", .{}); |
| 2682 | | for (self.globals.items) |sym_loc| { |
| 2683 | | const sym_name = self.getSymbolName(sym_loc); |
| 3202 | for (coff.globals.items) |sym_loc| { |
| 3203 | const sym_name = coff.getSymbolName(sym_loc); |
| 2684 | 3204 | log.debug(" {s} => %{d} in object({?d})", .{ sym_name, sym_loc.sym_index, sym_loc.file }); |
| 2685 | 3205 | } |
| 2686 | 3206 | |
| 2687 | 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 | 3212 | log.debug("sections:", .{}); |
| 2693 | | for (self.sections.items(.header)) |*header| { |
| 3213 | for (coff.sections.items(.header)) |*header| { |
| 2694 | 3214 | log.debug(" {s}: VM({x}, {x}) FILE({x}, {x})", .{ |
| 2695 | | self.getSectionName(header), |
| 3215 | coff.getSectionName(header), |
| 2696 | 3216 | header.virtual_address, |
| 2697 | 3217 | header.virtual_address + header.virtual_size, |
| 2698 | 3218 | header.pointer_to_raw_data, |
| ... | ... | @@ -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 | 3225 | log.debug("import tables:", .{}); |
| 2706 | | for (self.import_tables.keys(), 0..) |off, i| { |
| 2707 | | const itable = self.import_tables.values()[i]; |
| 3226 | for (coff.import_tables.keys(), 0..) |off, i| { |
| 3227 | const itable = coff.import_tables.values()[i]; |
| 2708 | 3228 | log.debug("{}", .{itable.fmtDebug(.{ |
| 2709 | | .coff_file = self, |
| 3229 | .coff = coff, |
| 2710 | 3230 | .index = i, |
| 2711 | 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 | 3704 | const Coff = @This(); |
| 2717 | 3705 | |
| 2718 | 3706 | const std = @import("std"); |
| 2719 | 3707 | const build_options = @import("build_options"); |
| 2720 | 3708 | const builtin = @import("builtin"); |
| 2721 | 3709 | const assert = std.debug.assert; |
| 2722 | | const coff = std.coff; |
| 3710 | const coff_util = std.coff; |
| 2723 | 3711 | const fmt = std.fmt; |
| 3712 | const fs = std.fs; |
| 2724 | 3713 | const log = std.log.scoped(.link); |
| 2725 | 3714 | const math = std.math; |
| 2726 | 3715 | const mem = std.mem; |
| ... | ... | @@ -2728,23 +3717,21 @@ const mem = std.mem; |
| 2728 | 3717 | const Allocator = std.mem.Allocator; |
| 2729 | 3718 | const Path = std.Build.Cache.Path; |
| 2730 | 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 | 3724 | const codegen = @import("../codegen.zig"); |
| 2733 | 3725 | const link = @import("../link.zig"); |
| 2734 | | const lld = @import("Coff/lld.zig"); |
| 2735 | 3726 | const target_util = @import("../target.zig"); |
| 2736 | 3727 | const trace = @import("../tracy.zig").trace; |
| 2737 | 3728 | |
| 2738 | 3729 | const Air = @import("../Air.zig"); |
| 2739 | | pub const Atom = @import("Coff/Atom.zig"); |
| 2740 | 3730 | const Compilation = @import("../Compilation.zig"); |
| 2741 | | const ImportTable = @import("Coff/ImportTable.zig"); |
| 2742 | 3731 | const Liveness = @import("../Liveness.zig"); |
| 2743 | 3732 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 2744 | 3733 | const Zcu = @import("../Zcu.zig"); |
| 2745 | 3734 | const InternPool = @import("../InternPool.zig"); |
| 2746 | | const Object = @import("Coff/Object.zig"); |
| 2747 | | const Relocation = @import("Coff/Relocation.zig"); |
| 2748 | 3735 | const TableSection = @import("table_section.zig").TableSection; |
| 2749 | 3736 | const StringTable = @import("StringTable.zig"); |
| 2750 | 3737 | const Type = @import("../Type.zig"); |