| author | |
| committer | |
| log | f56054d129d19a006ff19c56b48bc9c7d9c04593 |
| tree | aa2880b4c127a39563232b7db8c851d13def8596 |
| parent | bc69d5a00fb197a7bafc716b84c8675382074c19 |
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 | 492 | |
| 493 | 493 | const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address); |
| 494 | 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 | 496 | try self.growSectionVirtualMemory(sect_id, needed_size); |
| 497 | 497 | } |
| 498 | 498 | |
| ... | ... | @@ -759,7 +759,9 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { |
| 759 | 759 | if (self.relocs.getPtr(atom_index)) |rels| { |
| 760 | 760 | try relocs.ensureTotalCapacityPrecise(rels.items.len); |
| 761 | 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 | } |
| 765 | 767 | |
| ... | ... | @@ -904,18 +906,28 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void { |
| 904 | 906 | } |
| 905 | 907 | |
| 906 | 908 | fn 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 | 916 | for (self.relocs.values()) |*relocs| { |
| 908 | 917 | for (relocs.items) |*reloc| { |
| 909 | const target_vaddr = reloc.getTargetAddress(self) orelse continue; | |
| 910 | if (target_vaddr < addr) continue; | |
| 911 | reloc.dirty = true; | |
| 918 | if (reloc.isGotIndirection()) { | |
| 919 | reloc.dirty = reloc.dirty or got_moved; | |
| 920 | } else { | |
| 921 | const target_vaddr = reloc.getTargetAddress(self) orelse continue; | |
| 922 | if (target_vaddr > addr) reloc.dirty = true; | |
| 923 | } | |
| 912 | 924 | } |
| 913 | 925 | } |
| 914 | 926 | |
| 915 | 927 | // TODO: dirty only really affected GOT cells |
| 916 | 928 | for (self.got_table.entries.items) |entry| { |
| 917 | 929 | const target_addr = self.getSymbol(entry).value; |
| 918 | if (target_addr >= addr) { | |
| 930 | if (target_addr > addr) { | |
| 919 | 931 | self.got_table_contents_dirty = true; |
| 920 | 932 | break; |
| 921 | 933 | } |
| ... | ... | @@ -1624,7 +1636,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1624 | 1636 | |
| 1625 | 1637 | for (self.relocs.keys(), self.relocs.values()) |atom_index, relocs| { |
| 1626 | 1638 | const needs_update = for (relocs.items) |reloc| { |
| 1627 | if (reloc.isResolvable(self)) break true; | |
| 1639 | if (reloc.dirty) break true; | |
| 1628 | 1640 | } else false; |
| 1629 | 1641 | |
| 1630 | 1642 | if (!needs_update) continue; |
src/link/Coff/Relocation.zig+18-12| ... | ... | @@ -45,6 +45,19 @@ pcrel: bool, |
| 45 | 45 | length: u2, |
| 46 | 46 | dirty: bool = true, |
| 47 | 47 | |
| 48 | /// Returns true if and only if the reloc can be resolved. | |
| 49 | pub fn isResolvable(self: Relocation, coff_file: *Coff) bool { | |
| 50 | _ = self.getTargetAddress(coff_file) orelse return false; | |
| 51 | return true; | |
| 52 | } | |
| 53 | ||
| 54 | pub fn isGotIndirection(self: Relocation) bool { | |
| 55 | return switch (self.type) { | |
| 56 | .got, .got_page, .got_pageoff => true, | |
| 57 | else => false, | |
| 58 | }; | |
| 59 | } | |
| 60 | ||
| 48 | 61 | /// Returns address of the target if any. |
| 49 | 62 | pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 { |
| 50 | 63 | switch (self.type) { |
| ... | ... | @@ -53,11 +66,6 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 { |
| 53 | 66 | const header = coff_file.sections.items(.header)[coff_file.got_section_index.?]; |
| 54 | 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 | 69 | .import, .import_page, .import_pageoff => { |
| 62 | 70 | const sym = coff_file.getSymbol(self.target); |
| 63 | 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 | 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 | } |
| 73 | 86 | |
| 74 | /// Returns true if and only if the reloc is dirty AND the target address is available. | |
| 75 | pub 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 | ||
| 81 | 87 | pub fn resolve(self: Relocation, atom_index: Atom.Index, code: []u8, image_base: u64, coff_file: *Coff) void { |
| 82 | 88 | const atom = coff_file.getAtom(atom_index); |
| 83 | 89 | const source_sym = atom.getSymbol(coff_file); |