authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-20 14:07:02+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-21 22:44:28+02:00
logbee35fe3f018dd7b52716f757974ba405266558b
treeb24c52e0291512cb57ddd0d52f79659ebdf37955
parentae8fb2151425dc7f61ad46e4c13b6c61f67cc68b

coff: add image base to GOT relocations

Sort base relocations by address for deterministic debugging.

1 files changed, 61 insertions(+), 52 deletions(-)

src/link/Coff.zig+61-52
...@@ -107,12 +107,6 @@ const HotUpdateState = struct {...@@ -107,12 +107,6 @@ const HotUpdateState = struct {
107 loaded_base_address: ?std.os.windows.HMODULE = null,107 loaded_base_address: ?std.os.windows.HMODULE = null,
108};108};
109109
110const Entry = struct {
111 target: SymbolWithLoc,
112 // Index into the synthetic symbol table (i.e., file == null).
113 sym_index: u32,
114};
115
116const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));110const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
117const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));111const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
118const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));112const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
...@@ -843,17 +837,17 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {...@@ -843,17 +837,17 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
843 const file_offset = header.pointer_to_raw_data + entry_offset;837 const file_offset = header.pointer_to_raw_data + entry_offset;
844 const vmaddr = header.virtual_address + entry_offset;838 const vmaddr = header.virtual_address + entry_offset;
845839
846 log.debug("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value });840 log.debug("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value + self.getImageBase() });
847841
848 switch (self.ptr_width) {842 switch (self.ptr_width) {
849 .p32 => {843 .p32 => {
850 var buf: [4]u8 = undefined;844 var buf: [4]u8 = undefined;
851 mem.writeIntLittle(u32, &buf, @intCast(u32, entry_value));845 mem.writeIntLittle(u32, &buf, @intCast(u32, entry_value + self.getImageBase()));
852 try self.base.file.?.pwriteAll(&buf, file_offset);846 try self.base.file.?.pwriteAll(&buf, file_offset);
853 },847 },
854 .p64 => {848 .p64 => {
855 var buf: [8]u8 = undefined;849 var buf: [8]u8 = undefined;
856 mem.writeIntLittle(u64, &buf, entry_value);850 mem.writeIntLittle(u64, &buf, entry_value + self.getImageBase());
857 try self.base.file.?.pwriteAll(&buf, file_offset);851 try self.base.file.?.pwriteAll(&buf, file_offset);
858 },852 },
859 }853 }
...@@ -881,12 +875,14 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {...@@ -881,12 +875,14 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
881 switch (self.ptr_width) {875 switch (self.ptr_width) {
882 .p32 => {876 .p32 => {
883 var buf: [4]u8 = undefined;877 var buf: [4]u8 = undefined;
878 mem.writeIntLittle(u32, &buf, @intCast(u32, entry_value + slide));
884 writeMem(handle, pvaddr, &buf) catch |err| {879 writeMem(handle, pvaddr, &buf) catch |err| {
885 log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});880 log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});
886 };881 };
887 },882 },
888 .p64 => {883 .p64 => {
889 var buf: [8]u8 = undefined;884 var buf: [8]u8 = undefined;
885 mem.writeIntLittle(u64, &buf, entry_value + slide);
890 writeMem(handle, pvaddr, &buf) catch |err| {886 writeMem(handle, pvaddr, &buf) catch |err| {
891 log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});887 log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});
892 };888 };
...@@ -1744,69 +1740,82 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl_index: Module.Dec...@@ -1744,69 +1740,82 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl_index: Module.Dec
1744fn writeBaseRelocations(self: *Coff) !void {1740fn writeBaseRelocations(self: *Coff) !void {
1745 const gpa = self.base.allocator;1741 const gpa = self.base.allocator;
17461742
1747 var pages = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa);1743 var page_table = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa);
1748 defer {1744 defer {
1749 var it = pages.valueIterator();1745 var it = page_table.valueIterator();
1750 while (it.next()) |inner| {1746 while (it.next()) |inner| {
1751 inner.deinit();1747 inner.deinit();
1752 }1748 }
1753 pages.deinit();1749 page_table.deinit();
1754 }1750 }
17551751
1756 var it = self.base_relocs.iterator();1752 {
1757 while (it.next()) |entry| {1753 var it = self.base_relocs.iterator();
1758 const atom_index = entry.key_ptr.*;1754 while (it.next()) |entry| {
1759 const atom = self.getAtom(atom_index);1755 const atom_index = entry.key_ptr.*;
1760 const sym = atom.getSymbol(self);1756 const atom = self.getAtom(atom_index);
1761 const offsets = entry.value_ptr.*;1757 const sym = atom.getSymbol(self);
17621758 const offsets = entry.value_ptr.*;
1763 for (offsets.items) |offset| {1759
1764 const rva = sym.value + offset;1760 for (offsets.items) |offset| {
1765 const page = mem.alignBackwardGeneric(u32, rva, self.page_size);1761 const rva = sym.value + offset;
1766 const gop = try pages.getOrPut(page);1762 const page = mem.alignBackwardGeneric(u32, rva, self.page_size);
1767 if (!gop.found_existing) {1763 const gop = try page_table.getOrPut(page);
1768 gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);1764 if (!gop.found_existing) {
1765 gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
1766 }
1767 try gop.value_ptr.append(.{
1768 .offset = @intCast(u12, rva - page),
1769 .type = .DIR64,
1770 });
1769 }1771 }
1770 try gop.value_ptr.append(.{
1771 .offset = @intCast(u12, rva - page),
1772 .type = .DIR64,
1773 });
1774 }1772 }
1775 }
17761773
1777 {1774 {
1778 const header = &self.sections.items(.header)[self.got_section_index.?];1775 const header = &self.sections.items(.header)[self.got_section_index.?];
1779 for (self.got_table.entries.items, 0..) |entry, index| {1776 for (self.got_table.entries.items, 0..) |entry, index| {
1780 if (!self.got_table.lookup.contains(entry)) continue;1777 if (!self.got_table.lookup.contains(entry)) continue;
17811778
1782 const sym = self.getSymbol(entry);1779 const sym = self.getSymbol(entry);
1783 if (sym.section_number == .UNDEFINED) continue;1780 if (sym.section_number == .UNDEFINED) continue;
17841781
1785 const rva = @intCast(u32, header.virtual_address + index * self.ptr_width.size());1782 const rva = @intCast(u32, header.virtual_address + index * self.ptr_width.size());
1786 const page = mem.alignBackwardGeneric(u32, rva, self.page_size);1783 const page = mem.alignBackwardGeneric(u32, rva, self.page_size);
1787 const gop = try pages.getOrPut(page);1784 const gop = try page_table.getOrPut(page);
1788 if (!gop.found_existing) {1785 if (!gop.found_existing) {
1789 gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);1786 gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
1787 }
1788 try gop.value_ptr.append(.{
1789 .offset = @intCast(u12, rva - page),
1790 .type = .DIR64,
1791 });
1790 }1792 }
1791 try gop.value_ptr.append(.{
1792 .offset = @intCast(u12, rva - page),
1793 .type = .DIR64,
1794 });
1795 }1793 }
1796 }1794 }
17971795
1796 // Sort pages by address.
1797 var pages = try std.ArrayList(u32).initCapacity(gpa, page_table.count());
1798 defer pages.deinit();
1799 {
1800 var it = page_table.keyIterator();
1801 while (it.next()) |page| {
1802 pages.appendAssumeCapacity(page.*);
1803 }
1804 }
1805 std.sort.sort(u32, pages.items, {}, std.sort.asc(u32));
1806
1798 var buffer = std.ArrayList(u8).init(gpa);1807 var buffer = std.ArrayList(u8).init(gpa);
1799 defer buffer.deinit();1808 defer buffer.deinit();
18001809
1801 var pages_it = pages.iterator();1810 for (pages.items) |page| {
1802 while (pages_it.next()) |entry| {1811 const entries = page_table.getPtr(page).?;
1803 // Pad to required 4byte alignment1812 // Pad to required 4byte alignment
1804 if (!mem.isAlignedGeneric(1813 if (!mem.isAlignedGeneric(
1805 usize,1814 usize,
1806 entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation),1815 entries.items.len * @sizeOf(coff.BaseRelocation),
1807 @sizeOf(u32),1816 @sizeOf(u32),
1808 )) {1817 )) {
1809 try entry.value_ptr.append(.{1818 try entries.append(.{
1810 .offset = 0,1819 .offset = 0,
1811 .type = .ABSOLUTE,1820 .type = .ABSOLUTE,
1812 });1821 });
...@@ -1814,14 +1823,14 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1814,14 +1823,14 @@ fn writeBaseRelocations(self: *Coff) !void {
18141823
1815 const block_size = @intCast(1824 const block_size = @intCast(
1816 u32,1825 u32,
1817 entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry),1826 entries.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry),
1818 );1827 );
1819 try buffer.ensureUnusedCapacity(block_size);1828 try buffer.ensureUnusedCapacity(block_size);
1820 buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{1829 buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{
1821 .page_rva = entry.key_ptr.*,1830 .page_rva = page,
1822 .block_size = block_size,1831 .block_size = block_size,
1823 }));1832 }));
1824 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entry.value_ptr.items));1833 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entries.items));
1825 }1834 }
18261835
1827 const header = &self.sections.items(.header)[self.reloc_section_index.?];1836 const header = &self.sections.items(.header)[self.reloc_section_index.?];