| ... | @@ -126,6 +126,15 @@ pub const Reloc = struct { | ... | @@ -126,6 +126,15 @@ pub const Reloc = struct { |
| 126 | pcrel: bool, | 126 | pcrel: bool, |
| 127 | length: u2, | 127 | length: u2, |
| 128 | dirty: bool = true, | 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 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); | 140 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); |
| ... | @@ -355,7 +364,7 @@ fn populateMissingMetadata(self: *Coff) !void { | ... | @@ -355,7 +364,7 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 355 | } | 364 | } |
| 356 | | 365 | |
| 357 | if (self.rdata_section_index == null) { | 366 | if (self.rdata_section_index == null) { |
| 358 | const file_size: u32 = 1024; | 367 | const file_size: u32 = self.page_size; |
| 359 | self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ | 368 | self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ |
| 360 | .CNT_INITIALIZED_DATA = 1, | 369 | .CNT_INITIALIZED_DATA = 1, |
| 361 | .MEM_READ = 1, | 370 | .MEM_READ = 1, |
| ... | @@ -363,7 +372,7 @@ fn populateMissingMetadata(self: *Coff) !void { | ... | @@ -363,7 +372,7 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 363 | } | 372 | } |
| 364 | | 373 | |
| 365 | if (self.data_section_index == null) { | 374 | if (self.data_section_index == null) { |
| 366 | const file_size: u32 = 1024; | 375 | const file_size: u32 = self.page_size; |
| 367 | self.data_section_index = try self.allocateSection(".data", file_size, .{ | 376 | self.data_section_index = try self.allocateSection(".data", file_size, .{ |
| 368 | .CNT_INITIALIZED_DATA = 1, | 377 | .CNT_INITIALIZED_DATA = 1, |
| 369 | .MEM_READ = 1, | 378 | .MEM_READ = 1, |
| ... | @@ -371,19 +380,19 @@ fn populateMissingMetadata(self: *Coff) !void { | ... | @@ -371,19 +380,19 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 371 | }); | 380 | }); |
| 372 | } | 381 | } |
| 373 | | 382 | |
| 374 | if (self.reloc_section_index == null) { | 383 | if (self.idata_section_index == null) { |
| 375 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * @sizeOf(coff.BaseRelocation); | 384 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize(); |
| 376 | self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{ | 385 | self.idata_section_index = try self.allocateSection(".idata", file_size, .{ |
| 377 | .CNT_INITIALIZED_DATA = 1, | 386 | .CNT_INITIALIZED_DATA = 1, |
| 378 | .MEM_DISCARDABLE = 1, | | |
| 379 | .MEM_READ = 1, | 387 | .MEM_READ = 1, |
| 380 | }); | 388 | }); |
| 381 | } | 389 | } |
| 382 | | 390 | |
| 383 | if (self.idata_section_index == null) { | 391 | if (self.reloc_section_index == null) { |
| 384 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize(); | 392 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * @sizeOf(coff.BaseRelocation); |
| 385 | self.idata_section_index = try self.allocateSection(".idata", file_size, .{ | 393 | self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{ |
| 386 | .CNT_INITIALIZED_DATA = 1, | 394 | .CNT_INITIALIZED_DATA = 1, |
| | 395 | .MEM_DISCARDABLE = 1, |
| 387 | .MEM_READ = 1, | 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,6 +446,35 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section |
| 437 | return index; | 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 | pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { | 478 | pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { |
| 441 | if (self.llvm_object) |_| return; | 479 | if (self.llvm_object) |_| return; |
| 442 | const decl = self.base.options.module.?.declPtr(decl_index); | 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,13 +563,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u |
| 525 | const sym = last_atom.getSymbol(self); | 563 | const sym = last_atom.getSymbol(self); |
| 526 | break :blk (sym.value + last_atom.size) - header.virtual_address; | 564 | break :blk (sym.value + last_atom.size) - header.virtual_address; |
| 527 | } else 0; | 565 | } else 0; |
| 528 | log.debug("moving {s} from (0x{x} - 0x{x}) to (0x{x} - 0x{x})", .{ | 566 | log.debug("moving {s} from 0x{x} to 0x{x}", .{ self.getSectionName(header), header.pointer_to_raw_data, new_offset }); |
| 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 | }); | | |
| 535 | const amt = try self.base.file.?.copyRangeAll( | 567 | const amt = try self.base.file.?.copyRangeAll( |
| 536 | header.pointer_to_raw_data, | 568 | header.pointer_to_raw_data, |
| 537 | self.base.file.?, | 569 | self.base.file.?, |
| ... | @@ -544,8 +576,8 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u | ... | @@ -544,8 +576,8 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u |
| 544 | | 576 | |
| 545 | const sect_vm_capacity = self.allocatedSizeVM(header.virtual_address); | 577 | const sect_vm_capacity = self.allocatedSizeVM(header.virtual_address); |
| 546 | if (needed_size > sect_vm_capacity) { | 578 | if (needed_size > sect_vm_capacity) { |
| 547 | log.err("needed {x}, available {x}", .{ needed_size, sect_vm_capacity }); | 579 | try self.growSectionVM(sect_id, needed_size); |
| 548 | @panic("TODO expand section in virtual address space"); | 580 | self.markRelocsDirtyByAddress(header.virtual_address + needed_size); |
| 549 | } | 581 | } |
| 550 | | 582 | |
| 551 | header.virtual_size = @maximum(header.virtual_size, needed_size); | 583 | header.virtual_size = @maximum(header.virtual_size, needed_size); |
| ... | @@ -747,7 +779,7 @@ fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void { | ... | @@ -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 | // TODO: reverse-lookup might come in handy here | 783 | // TODO: reverse-lookup might come in handy here |
| 752 | var it = self.relocs.valueIterator(); | 784 | var it = self.relocs.valueIterator(); |
| 753 | while (it.next()) |relocs| { | 785 | while (it.next()) |relocs| { |
| ... | @@ -758,6 +790,18 @@ fn markRelocsDirty(self: *Coff, target: SymbolWithLoc) void { | ... | @@ -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 | fn resolveRelocs(self: *Coff, atom: *Atom) !void { | 805 | fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 762 | const relocs = self.relocs.get(atom) orelse return; | 806 | const relocs = self.relocs.get(atom) orelse return; |
| 763 | const source_sym = atom.getSymbol(self); | 807 | const source_sym = atom.getSymbol(self); |
| ... | @@ -769,19 +813,8 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { | ... | @@ -769,19 +813,8 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 769 | for (relocs.items) |*reloc| { | 813 | for (relocs.items) |*reloc| { |
| 770 | if (!reloc.dirty) continue; | 814 | if (!reloc.dirty) continue; |
| 771 | | 815 | |
| 772 | const target_vaddr = switch (reloc.@"type") { | 816 | const target_atom = reloc.getTargetAtom(self) orelse continue; |
| 773 | .got => blk: { | 817 | const target_vaddr = target_atom.getSymbol(self).value; |
| 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 | }; | | |
| 785 | const target_vaddr_with_addend = target_vaddr + reloc.addend; | 818 | const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| 786 | | 819 | |
| 787 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ | 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,7 +1128,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 1095 | log.debug(" (updating GOT entry)", .{}); | 1128 | log.debug(" (updating GOT entry)", .{}); |
| 1096 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; | 1129 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 1097 | const got_atom = self.getGotAtomForSymbol(got_target).?; | 1130 | const got_atom = self.getGotAtomForSymbol(got_target).?; |
| 1098 | self.markRelocsDirty(got_target); | 1131 | self.markRelocsDirtyByTarget(got_target); |
| 1099 | try self.writePtrWidthAtom(got_atom); | 1132 | try self.writePtrWidthAtom(got_atom); |
| 1100 | } | 1133 | } |
| 1101 | } else if (code_len < atom.size) { | 1134 | } else if (code_len < atom.size) { |
| ... | @@ -1120,7 +1153,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, | ... | @@ -1120,7 +1153,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 1120 | try self.writePtrWidthAtom(got_atom); | 1153 | try self.writePtrWidthAtom(got_atom); |
| 1121 | } | 1154 | } |
| 1122 | | 1155 | |
| 1123 | self.markRelocsDirty(atom.getSymbolWithLoc()); | 1156 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); |
| 1124 | try self.writeAtom(atom, code); | 1157 | try self.writeAtom(atom, code); |
| 1125 | } | 1158 | } |
| 1126 | | 1159 | |
| ... | @@ -1546,7 +1579,8 @@ fn writeBaseRelocations(self: *Coff) !void { | ... | @@ -1546,7 +1579,8 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 1546 | | 1579 | |
| 1547 | const sect_vm_capacity = self.allocatedSizeVM(header.virtual_address); | 1580 | const sect_vm_capacity = self.allocatedSizeVM(header.virtual_address); |
| 1548 | if (needed_size > sect_vm_capacity) { | 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 | header.virtual_size = @maximum(header.virtual_size, needed_size); | 1586 | header.virtual_size = @maximum(header.virtual_size, needed_size); |
| ... | @@ -1881,9 +1915,6 @@ fn allocatedSizeVM(self: *Coff, start: u32) u32 { | ... | @@ -1881,9 +1915,6 @@ fn allocatedSizeVM(self: *Coff, start: u32) u32 { |
| 1881 | if (start == 0) | 1915 | if (start == 0) |
| 1882 | return 0; | 1916 | return 0; |
| 1883 | var min_pos: u32 = std.math.maxInt(u32); | 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 | for (self.sections.items(.header)) |header| { | 1918 | for (self.sections.items(.header)) |header| { |
| 1888 | if (header.virtual_address <= start) continue; | 1919 | if (header.virtual_address <= start) continue; |
| 1889 | if (header.virtual_address < min_pos) min_pos = header.virtual_address; | 1920 | if (header.virtual_address < min_pos) min_pos = header.virtual_address; |
| ... | @@ -2116,3 +2147,16 @@ fn logSymtab(self: *Coff) void { | ... | @@ -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 | } |