| ... | ... | @@ -126,6 +126,15 @@ pub const Reloc = struct { |
| 126 | 126 | pcrel: bool, |
| 127 | 127 | length: u2, |
| 128 | 128 | dirty: bool = true, |
| 129 | |
| 130 | /// Returns an Atom which is the target node of this relocation edge (if any). |
| 131 | fn getTargetAtom(self: Reloc, coff_file: *Coff) ?*Atom { |
| 132 | switch (self.@"type") { |
| 133 | .got => return coff_file.getGotAtomForSymbol(self.target), |
| 134 | .direct => return coff_file.getAtomForSymbol(self.target), |
| 135 | .imports => return coff_file.getImportAtomForSymbol(self.target), |
| 136 | } |
| 137 | } |
| 129 | 138 | }; |
| 130 | 139 | |
| 131 | 140 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); |
| ... | ... | @@ -355,7 +364,7 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 355 | 364 | } |
| 356 | 365 | |
| 357 | 366 | if (self.rdata_section_index == null) { |
| 358 | | const file_size: u32 = 1024; |
| 367 | const file_size: u32 = self.page_size; |
| 359 | 368 | self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ |
| 360 | 369 | .CNT_INITIALIZED_DATA = 1, |
| 361 | 370 | .MEM_READ = 1, |
| ... | ... | @@ -363,7 +372,7 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 363 | 372 | } |
| 364 | 373 | |
| 365 | 374 | if (self.data_section_index == null) { |
| 366 | | const file_size: u32 = 1024; |
| 375 | const file_size: u32 = self.page_size; |
| 367 | 376 | self.data_section_index = try self.allocateSection(".data", file_size, .{ |
| 368 | 377 | .CNT_INITIALIZED_DATA = 1, |
| 369 | 378 | .MEM_READ = 1, |
| ... | ... | @@ -371,19 +380,19 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 371 | 380 | }); |
| 372 | 381 | } |
| 373 | 382 | |
| 374 | | if (self.reloc_section_index == null) { |
| 375 | | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * @sizeOf(coff.BaseRelocation); |
| 376 | | self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{ |
| 383 | if (self.idata_section_index == null) { |
| 384 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize(); |
| 385 | self.idata_section_index = try self.allocateSection(".idata", file_size, .{ |
| 377 | 386 | .CNT_INITIALIZED_DATA = 1, |
| 378 | | .MEM_DISCARDABLE = 1, |
| 379 | 387 | .MEM_READ = 1, |
| 380 | 388 | }); |
| 381 | 389 | } |
| 382 | 390 | |
| 383 | | if (self.idata_section_index == null) { |
| 384 | | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize(); |
| 385 | | self.idata_section_index = try self.allocateSection(".idata", file_size, .{ |
| 391 | if (self.reloc_section_index == null) { |
| 392 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * @sizeOf(coff.BaseRelocation); |
| 393 | self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{ |
| 386 | 394 | .CNT_INITIALIZED_DATA = 1, |
| 395 | .MEM_DISCARDABLE = 1, |
| 387 | 396 | .MEM_READ = 1, |
| 388 | 397 | }); |
| 389 | 398 | } |
| ... | ... | @@ -437,6 +446,35 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section |
| 437 | 446 | return index; |
| 438 | 447 | } |
| 439 | 448 | |
| 449 | fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void { |
| 450 | const header = &self.sections.items(.header)[sect_id]; |
| 451 | const increased_size = padToIdeal(needed_size); |
| 452 | const old_aligned_end = header.virtual_address + mem.alignForwardGeneric(u32, header.virtual_size, self.page_size); |
| 453 | const new_aligned_end = header.virtual_address + mem.alignForwardGeneric(u32, increased_size, self.page_size); |
| 454 | const diff = new_aligned_end - old_aligned_end; |
| 455 | |
| 456 | // TODO: enforce order by increasing VM addresses in self.sections container. |
| 457 | // This is required by the loader anyhow as far as I can tell. |
| 458 | for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| { |
| 459 | const maybe_last_atom = &self.sections.items(.last_atom)[sect_id + 1 + next_sect_id]; |
| 460 | next_header.virtual_address += diff; |
| 461 | |
| 462 | if (maybe_last_atom.*) |last_atom| { |
| 463 | var atom = last_atom; |
| 464 | while (true) { |
| 465 | const sym = atom.getSymbolPtr(self); |
| 466 | sym.value += diff; |
| 467 | |
| 468 | if (atom.prev) |prev| { |
| 469 | atom = prev; |
| 470 | } else break; |
| 471 | } |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | header.virtual_size = increased_size; |
| 476 | } |
| 477 | |
| 440 | 478 | pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { |
| 441 | 479 | if (self.llvm_object) |_| return; |
| 442 | 480 | const decl = self.base.options.module.?.declPtr(decl_index); |
| ... | ... | @@ -525,13 +563,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u |
| 525 | 563 | const sym = last_atom.getSymbol(self); |
| 526 | 564 | break :blk (sym.value + last_atom.size) - header.virtual_address; |
| 527 | 565 | } else 0; |
| 528 | | log.debug("moving {s} from (0x{x} - 0x{x}) to (0x{x} - 0x{x})", .{ |
| 529 | | self.getSectionName(header), |
| 530 | | header.pointer_to_raw_data, |
| 531 | | header.pointer_to_raw_data + current_size, |
| 532 | | new_offset, |
| 533 | | new_offset + current_size, |
| 534 | | }); |
| 566 | log.debug("moving {s} from 0x{x} to 0x{x}", .{ self.getSectionName(header), header.pointer_to_raw_data, new_offset }); |
| 535 | 567 | const amt = try self.base.file.?.copyRangeAll( |
| 536 | 568 | header.pointer_to_raw_data, |
| 537 | 569 | self.base.file.?, |
| ... | ... | @@ -544,8 +576,8 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u |
| 544 | 576 | |
| 545 | 577 | const sect_vm_capacity = self.allocatedSizeVM(header.virtual_address); |
| 546 | 578 | if (needed_size > sect_vm_capacity) { |
| 547 | | log.err("needed {x}, available {x}", .{ needed_size, sect_vm_capacity }); |
| 548 | | @panic("TODO expand section in virtual address space"); |
| 579 | try self.growSectionVM(sect_id, needed_size); |
| 580 | self.markRelocsDirtyByAddress(header.virtual_address + needed_size); |
| 549 | 581 | } |
| 550 | 582 | |
| 551 | 583 | header.virtual_size = @maximum(header.virtual_size, needed_size); |
| ... | ... | @@ -747,7 +779,7 @@ fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void { |
| 747 | 779 | } |
| 748 | 780 | } |
| 749 | 781 | |
| 750 | | fn markRelocsDirty(self: *Coff, target: SymbolWithLoc) void { |
| 782 | fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void { |
| 751 | 783 | // TODO: reverse-lookup might come in handy here |
| 752 | 784 | var it = self.relocs.valueIterator(); |
| 753 | 785 | while (it.next()) |relocs| { |
| ... | ... | @@ -758,6 +790,18 @@ fn markRelocsDirty(self: *Coff, target: SymbolWithLoc) void { |
| 758 | 790 | } |
| 759 | 791 | } |
| 760 | 792 | |
| 793 | fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { |
| 794 | var it = self.relocs.valueIterator(); |
| 795 | while (it.next()) |relocs| { |
| 796 | for (relocs.items) |*reloc| { |
| 797 | const target_atom = reloc.getTargetAtom(self) orelse continue; |
| 798 | const target_sym = target_atom.getSymbol(self); |
| 799 | if (target_sym.value < addr) continue; |
| 800 | reloc.dirty = true; |
| 801 | } |
| 802 | } |
| 803 | } |
| 804 | |
| 761 | 805 | fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 762 | 806 | const relocs = self.relocs.get(atom) orelse return; |
| 763 | 807 | const source_sym = atom.getSymbol(self); |
| ... | ... | @@ -769,19 +813,8 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 769 | 813 | for (relocs.items) |*reloc| { |
| 770 | 814 | if (!reloc.dirty) continue; |
| 771 | 815 | |
| 772 | | const target_vaddr = switch (reloc.@"type") { |
| 773 | | .got => blk: { |
| 774 | | const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue; |
| 775 | | break :blk got_atom.getSymbol(self).value; |
| 776 | | }, |
| 777 | | .direct => blk: { |
| 778 | | break :blk self.getSymbol(reloc.target).value; |
| 779 | | }, |
| 780 | | .imports => blk: { |
| 781 | | const import_atom = self.getImportAtomForSymbol(reloc.target) orelse continue; |
| 782 | | break :blk import_atom.getSymbol(self).value; |
| 783 | | }, |
| 784 | | }; |
| 816 | const target_atom = reloc.getTargetAtom(self) orelse continue; |
| 817 | const target_vaddr = target_atom.getSymbol(self).value; |
| 785 | 818 | const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| 786 | 819 | |
| 787 | 820 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ |
| ... | ... | @@ -1095,7 +1128,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 1095 | 1128 | log.debug(" (updating GOT entry)", .{}); |
| 1096 | 1129 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 1097 | 1130 | const got_atom = self.getGotAtomForSymbol(got_target).?; |
| 1098 | | self.markRelocsDirty(got_target); |
| 1131 | self.markRelocsDirtyByTarget(got_target); |
| 1099 | 1132 | try self.writePtrWidthAtom(got_atom); |
| 1100 | 1133 | } |
| 1101 | 1134 | } else if (code_len < atom.size) { |
| ... | ... | @@ -1120,7 +1153,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 1120 | 1153 | try self.writePtrWidthAtom(got_atom); |
| 1121 | 1154 | } |
| 1122 | 1155 | |
| 1123 | | self.markRelocsDirty(atom.getSymbolWithLoc()); |
| 1156 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); |
| 1124 | 1157 | try self.writeAtom(atom, code); |
| 1125 | 1158 | } |
| 1126 | 1159 | |
| ... | ... | @@ -1546,7 +1579,8 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 1546 | 1579 | |
| 1547 | 1580 | const sect_vm_capacity = self.allocatedSizeVM(header.virtual_address); |
| 1548 | 1581 | if (needed_size > sect_vm_capacity) { |
| 1549 | | @panic("TODO expand section in virtual address space"); |
| 1582 | // TODO: we want to enforce .reloc after every alloc section. |
| 1583 | try self.growSectionVM(self.reloc_section_index.?, needed_size); |
| 1550 | 1584 | } |
| 1551 | 1585 | } |
| 1552 | 1586 | header.virtual_size = @maximum(header.virtual_size, needed_size); |
| ... | ... | @@ -1881,9 +1915,6 @@ fn allocatedSizeVM(self: *Coff, start: u32) u32 { |
| 1881 | 1915 | if (start == 0) |
| 1882 | 1916 | return 0; |
| 1883 | 1917 | var min_pos: u32 = std.math.maxInt(u32); |
| 1884 | | if (self.strtab_offset) |off| { |
| 1885 | | if (off > start and off < min_pos) min_pos = off; |
| 1886 | | } |
| 1887 | 1918 | for (self.sections.items(.header)) |header| { |
| 1888 | 1919 | if (header.virtual_address <= start) continue; |
| 1889 | 1920 | if (header.virtual_address < min_pos) min_pos = header.virtual_address; |
| ... | ... | @@ -2116,3 +2147,16 @@ fn logSymtab(self: *Coff) void { |
| 2116 | 2147 | } |
| 2117 | 2148 | } |
| 2118 | 2149 | } |
| 2150 | |
| 2151 | fn logSections(self: *Coff) void { |
| 2152 | log.debug("sections:", .{}); |
| 2153 | for (self.sections.items(.header)) |*header| { |
| 2154 | log.debug(" {s}: VM({x}, {x}) FILE({x}, {x})", .{ |
| 2155 | self.getSectionName(header), |
| 2156 | header.virtual_address, |
| 2157 | header.virtual_address + header.virtual_size, |
| 2158 | header.pointer_to_raw_data, |
| 2159 | header.pointer_to_raw_data + header.size_of_raw_data, |
| 2160 | }); |
| 2161 | } |
| 2162 | } |