coff: invalidate GOT relocs after segment shift in memory
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user