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 {...@@ -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};
130139
131const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc));140const 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 }
356365
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 }
364373
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 }
373382
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 }
382390
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}
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
440pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {478pub 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
544576
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 }
550582
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}
749781
750fn markRelocsDirty(self: *Coff, target: SymbolWithLoc) void {782fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {
751 // TODO: reverse-lookup might come in handy here783 // 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}
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
761fn resolveRelocs(self: *Coff, atom: *Atom) !void {805fn 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;
771815
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;
786819
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 }
11221155
1123 self.markRelocsDirty(atom.getSymbolWithLoc());1156 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
1124 try self.writeAtom(atom, code);1157 try self.writeAtom(atom, code);
1125}1158}
11261159
...@@ -1546,7 +1579,8 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1546,7 +1579,8 @@ fn writeBaseRelocations(self: *Coff) !void {
15461579
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
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}