authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-06 14:12:01+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-07 22:42:58+02:00
log2b373b05793d617f308c7f99b35be7ad1ca0321f
tree5f329feaa866f80eaa0d0c10c499b6ee7db84642
parent9116e0f7464c65912d758ebd58aad35d9b07cabc

coff: grow section in virtual address space when required


1 files changed, 82 insertions(+), 38 deletions(-)

src/link/Coff.zig+82-38
......@@ -126,6 +126,15 @@ pub const Reloc = struct {
126126 pcrel: bool,
127127 length: u2,
128128 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 }
129138};
130139
131140const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc));
......@@ -355,7 +364,7 @@ fn populateMissingMetadata(self: *Coff) !void {
355364 }
356365
357366 if (self.rdata_section_index == null) {
358 const file_size: u32 = 1024;
367 const file_size: u32 = self.page_size;
359368 self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{
360369 .CNT_INITIALIZED_DATA = 1,
361370 .MEM_READ = 1,
......@@ -363,7 +372,7 @@ fn populateMissingMetadata(self: *Coff) !void {
363372 }
364373
365374 if (self.data_section_index == null) {
366 const file_size: u32 = 1024;
375 const file_size: u32 = self.page_size;
367376 self.data_section_index = try self.allocateSection(".data", file_size, .{
368377 .CNT_INITIALIZED_DATA = 1,
369378 .MEM_READ = 1,
......@@ -371,19 +380,19 @@ fn populateMissingMetadata(self: *Coff) !void {
371380 });
372381 }
373382
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, .{
377386 .CNT_INITIALIZED_DATA = 1,
378 .MEM_DISCARDABLE = 1,
379387 .MEM_READ = 1,
380388 });
381389 }
382390
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, .{
386394 .CNT_INITIALIZED_DATA = 1,
395 .MEM_DISCARDABLE = 1,
387396 .MEM_READ = 1,
388397 });
389398 }
......@@ -437,6 +446,35 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section
437446 return index;
438447}
439448
449fn 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
440478pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {
441479 if (self.llvm_object) |_| return;
442480 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
525563 const sym = last_atom.getSymbol(self);
526564 break :blk (sym.value + last_atom.size) - header.virtual_address;
527565 } 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 });
535567 const amt = try self.base.file.?.copyRangeAll(
536568 header.pointer_to_raw_data,
537569 self.base.file.?,
......@@ -544,8 +576,8 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
544576
545577 const sect_vm_capacity = self.allocatedSizeVM(header.virtual_address);
546578 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);
549581 }
550582
551583 header.virtual_size = @maximum(header.virtual_size, needed_size);
......@@ -747,7 +779,7 @@ fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void {
747779 }
748780}
749781
750fn markRelocsDirty(self: *Coff, target: SymbolWithLoc) void {
782fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {
751783 // TODO: reverse-lookup might come in handy here
752784 var it = self.relocs.valueIterator();
753785 while (it.next()) |relocs| {
......@@ -758,6 +790,18 @@ fn markRelocsDirty(self: *Coff, target: SymbolWithLoc) void {
758790 }
759791}
760792
793fn 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
761805fn resolveRelocs(self: *Coff, atom: *Atom) !void {
762806 const relocs = self.relocs.get(atom) orelse return;
763807 const source_sym = atom.getSymbol(self);
......@@ -769,19 +813,8 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
769813 for (relocs.items) |*reloc| {
770814 if (!reloc.dirty) continue;
771815
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;
785818 const target_vaddr_with_addend = target_vaddr + reloc.addend;
786819
787820 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
......@@ -1095,7 +1128,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
10951128 log.debug(" (updating GOT entry)", .{});
10961129 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };
10971130 const got_atom = self.getGotAtomForSymbol(got_target).?;
1098 self.markRelocsDirty(got_target);
1131 self.markRelocsDirtyByTarget(got_target);
10991132 try self.writePtrWidthAtom(got_atom);
11001133 }
11011134 } else if (code_len < atom.size) {
......@@ -1120,7 +1153,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
11201153 try self.writePtrWidthAtom(got_atom);
11211154 }
11221155
1123 self.markRelocsDirty(atom.getSymbolWithLoc());
1156 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
11241157 try self.writeAtom(atom, code);
11251158}
11261159
......@@ -1546,7 +1579,8 @@ fn writeBaseRelocations(self: *Coff) !void {
15461579
15471580 const sect_vm_capacity = self.allocatedSizeVM(header.virtual_address);
15481581 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);
15501584 }
15511585 }
15521586 header.virtual_size = @maximum(header.virtual_size, needed_size);
......@@ -1881,9 +1915,6 @@ fn allocatedSizeVM(self: *Coff, start: u32) u32 {
18811915 if (start == 0)
18821916 return 0;
18831917 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 }
18871918 for (self.sections.items(.header)) |header| {
18881919 if (header.virtual_address <= start) continue;
18891920 if (header.virtual_address < min_pos) min_pos = header.virtual_address;
......@@ -2116,3 +2147,16 @@ fn logSymtab(self: *Coff) void {
21162147 }
21172148 }
21182149}
2150
2151fn 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}