diff --git a/src/link/Coff.zig b/src/link/Coff.zig index ac98457360..ed3e213b0e 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -492,7 +492,7 @@ fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void { const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address); if (needed_size > sect_vm_capacity) { - self.markRelocsDirtyByAddress(header.virtual_address + needed_size); + self.markRelocsDirtyByAddress(header.virtual_address + header.virtual_size); try self.growSectionVirtualMemory(sect_id, needed_size); } @@ -759,7 +759,9 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { if (self.relocs.getPtr(atom_index)) |rels| { try relocs.ensureTotalCapacityPrecise(rels.items.len); for (rels.items) |*reloc| { - if (reloc.isResolvable(self)) relocs.appendAssumeCapacity(reloc); + if (reloc.isResolvable(self) and reloc.dirty) { + relocs.appendAssumeCapacity(reloc); + } } } @@ -904,18 +906,28 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void { } fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { + const got_moved = blk: { + const sect_id = self.got_section_index orelse break :blk false; + break :blk self.sections.items(.header)[sect_id].virtual_address > addr; + }; + + // TODO: dirty relocations targeting import table if that got moved in memory + for (self.relocs.values()) |*relocs| { for (relocs.items) |*reloc| { - const target_vaddr = reloc.getTargetAddress(self) orelse continue; - if (target_vaddr < addr) continue; - reloc.dirty = true; + if (reloc.isGotIndirection()) { + reloc.dirty = reloc.dirty or got_moved; + } else { + const target_vaddr = reloc.getTargetAddress(self) orelse continue; + if (target_vaddr > addr) reloc.dirty = true; + } } } // TODO: dirty only really affected GOT cells for (self.got_table.entries.items) |entry| { const target_addr = self.getSymbol(entry).value; - if (target_addr >= addr) { + if (target_addr > addr) { self.got_table_contents_dirty = true; break; } @@ -1624,7 +1636,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod for (self.relocs.keys(), self.relocs.values()) |atom_index, relocs| { const needs_update = for (relocs.items) |reloc| { - if (reloc.isResolvable(self)) break true; + if (reloc.dirty) break true; } else false; if (!needs_update) continue; diff --git a/src/link/Coff/Relocation.zig b/src/link/Coff/Relocation.zig index 4449691ac0..10d4eed92b 100644 --- a/src/link/Coff/Relocation.zig +++ b/src/link/Coff/Relocation.zig @@ -45,6 +45,19 @@ pcrel: bool, length: u2, dirty: bool = true, +/// Returns true if and only if the reloc can be resolved. +pub fn isResolvable(self: Relocation, coff_file: *Coff) bool { + _ = self.getTargetAddress(coff_file) orelse return false; + return true; +} + +pub fn isGotIndirection(self: Relocation) bool { + return switch (self.type) { + .got, .got_page, .got_pageoff => true, + else => false, + }; +} + /// Returns address of the target if any. pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 { switch (self.type) { @@ -53,11 +66,6 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 { const header = coff_file.sections.items(.header)[coff_file.got_section_index.?]; return header.virtual_address + got_index * coff_file.ptr_width.size(); }, - .direct, .page, .pageoff => { - const target_atom_index = coff_file.getAtomIndexForSymbol(self.target) orelse return null; - const target_atom = coff_file.getAtom(target_atom_index); - return target_atom.getSymbol(coff_file).value; - }, .import, .import_page, .import_pageoff => { const sym = coff_file.getSymbol(self.target); 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 { .name_off = sym.value, }); }, + else => { + const target_atom_index = coff_file.getAtomIndexForSymbol(self.target) orelse return null; + const target_atom = coff_file.getAtom(target_atom_index); + return target_atom.getSymbol(coff_file).value; + }, } } -/// Returns true if and only if the reloc is dirty AND the target address is available. -pub fn isResolvable(self: Relocation, coff_file: *Coff) bool { - const addr = self.getTargetAddress(coff_file) orelse return false; - if (addr == 0) return false; - return self.dirty; -} - pub fn resolve(self: Relocation, atom_index: Atom.Index, code: []u8, image_base: u64, coff_file: *Coff) void { const atom = coff_file.getAtom(atom_index); const source_sym = atom.getSymbol(coff_file);