authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-26 13:04:24+02:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-26 19:08:38-04:00
logf56054d129d19a006ff19c56b48bc9c7d9c04593
treeaa2880b4c127a39563232b7db8c851d13def8596
parentbc69d5a00fb197a7bafc716b84c8675382074c19

coff: invalidate GOT relocs after segment shift in memory


2 files changed, 37 insertions(+), 19 deletions(-)

src/link/Coff.zig+19-7
...@@ -492,7 +492,7 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void {...@@ -492,7 +492,7 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void {
492492
493 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);493 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);
494 if (needed_size > sect_vm_capacity) {494 if (needed_size > sect_vm_capacity) {
495 self.markRelocsDirtyByAddress(header.virtual_address + needed_size);495 self.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size);
496 try self.growSectionVirtualMemory(sect_id, needed_size);496 try self.growSectionVirtualMemory(sect_id, needed_size);
497 }497 }
498498
...@@ -759,7 +759,9 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {...@@ -759,7 +759,9 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
759 if (self.relocs.getPtr(atom_index)) |rels| {759 if (self.relocs.getPtr(atom_index)) |rels| {
760 try relocs.ensureTotalCapacityPrecise(rels.items.len);760 try relocs.ensureTotalCapacityPrecise(rels.items.len);
761 for (rels.items) |*reloc| {761 for (rels.items) |*reloc| {
762 if (reloc.isResolvable(self)) relocs.appendAssumeCapacity(reloc);762 if (reloc.isResolvable(self) and reloc.dirty) {
763 relocs.appendAssumeCapacity(reloc);
764 }
763 }765 }
764 }766 }
765767
...@@ -904,18 +906,28 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {...@@ -904,18 +906,28 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {
904}906}
905907
906fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {908fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
909 const got_moved = blk: {
910 const sect_id = self.got_section_index orelse break :blk false;
911 break :blk self.sections.items(.header)[sect_id].virtual_address > addr;
912 };
913
914 // TODO: dirty relocations targeting import table if that got moved in memory
915
907 for (self.relocs.values()) |*relocs| {916 for (self.relocs.values()) |*relocs| {
908 for (relocs.items) |*reloc| {917 for (relocs.items) |*reloc| {
909 const target_vaddr = reloc.getTargetAddress(self) orelse continue;918 if (reloc.isGotIndirection()) {
910 if (target_vaddr < addr) continue;919 reloc.dirty = reloc.dirty or got_moved;
911 reloc.dirty = true;920 } else {
921 const target_vaddr = reloc.getTargetAddress(self) orelse continue;
922 if (target_vaddr > addr) reloc.dirty = true;
923 }
912 }924 }
913 }925 }
914926
915 // TODO: dirty only really affected GOT cells927 // TODO: dirty only really affected GOT cells
916 for (self.got_table.entries.items) |entry| {928 for (self.got_table.entries.items) |entry| {
917 const target_addr = self.getSymbol(entry).value;929 const target_addr = self.getSymbol(entry).value;
918 if (target_addr >= addr) {930 if (target_addr > addr) {
919 self.got_table_contents_dirty = true;931 self.got_table_contents_dirty = true;
920 break;932 break;
921 }933 }
...@@ -1624,7 +1636,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1624,7 +1636,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
16241636
1625 for (self.relocs.keys(), self.relocs.values()) |atom_index, relocs| {1637 for (self.relocs.keys(), self.relocs.values()) |atom_index, relocs| {
1626 const needs_update = for (relocs.items) |reloc| {1638 const needs_update = for (relocs.items) |reloc| {
1627 if (reloc.isResolvable(self)) break true;1639 if (reloc.dirty) break true;
1628 } else false;1640 } else false;
16291641
1630 if (!needs_update) continue;1642 if (!needs_update) continue;
src/link/Coff/Relocation.zig+18-12
...@@ -45,6 +45,19 @@ pcrel: bool,...@@ -45,6 +45,19 @@ pcrel: bool,
45length: u2,45length: u2,
46dirty: bool = true,46dirty: bool = true,
4747
48/// Returns true if and only if the reloc can be resolved.
49pub fn isResolvable(self: Relocation, coff_file: *Coff) bool {
50 _ = self.getTargetAddress(coff_file) orelse return false;
51 return true;
52}
53
54pub fn isGotIndirection(self: Relocation) bool {
55 return switch (self.type) {
56 .got, .got_page, .got_pageoff => true,
57 else => false,
58 };
59}
60
48/// Returns address of the target if any.61/// Returns address of the target if any.
49pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {62pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
50 switch (self.type) {63 switch (self.type) {
...@@ -53,11 +66,6 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {...@@ -53,11 +66,6 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
53 const header = coff_file.sections.items(.header)[coff_file.got_section_index.?];66 const header = coff_file.sections.items(.header)[coff_file.got_section_index.?];
54 return header.virtual_address + got_index * coff_file.ptr_width.size();67 return header.virtual_address + got_index * coff_file.ptr_width.size();
55 },68 },
56 .direct, .page, .pageoff => {
57 const target_atom_index = coff_file.getAtomIndexForSymbol(self.target) orelse return null;
58 const target_atom = coff_file.getAtom(target_atom_index);
59 return target_atom.getSymbol(coff_file).value;
60 },
61 .import, .import_page, .import_pageoff => {69 .import, .import_page, .import_pageoff => {
62 const sym = coff_file.getSymbol(self.target);70 const sym = coff_file.getSymbol(self.target);
63 const index = coff_file.import_tables.getIndex(sym.value) orelse return null;71 const index = coff_file.import_tables.getIndex(sym.value) orelse return null;
...@@ -68,16 +76,14 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {...@@ -68,16 +76,14 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
68 .name_off = sym.value,76 .name_off = sym.value,
69 });77 });
70 },78 },
79 else => {
80 const target_atom_index = coff_file.getAtomIndexForSymbol(self.target) orelse return null;
81 const target_atom = coff_file.getAtom(target_atom_index);
82 return target_atom.getSymbol(coff_file).value;
83 },
71 }84 }
72}85}
7386
74/// Returns true if and only if the reloc is dirty AND the target address is available.
75pub fn isResolvable(self: Relocation, coff_file: *Coff) bool {
76 const addr = self.getTargetAddress(coff_file) orelse return false;
77 if (addr == 0) return false;
78 return self.dirty;
79}
80
81pub fn resolve(self: Relocation, atom_index: Atom.Index, code: []u8, image_base: u64, coff_file: *Coff) void {87pub fn resolve(self: Relocation, atom_index: Atom.Index, code: []u8, image_base: u64, coff_file: *Coff) void {
82 const atom = coff_file.getAtom(atom_index);88 const atom = coff_file.getAtom(atom_index);
83 const source_sym = atom.getSymbol(coff_file);89 const source_sym = atom.getSymbol(coff_file);