Commit bee35fe3f0

Jakub Konka <kubkon@jakubkonka.com>
2023-04-20 14:07:02
coff: add image base to GOT relocations
Sort base relocations by address for deterministic debugging.
1 parent ae8fb21
Changed files (1)
src
src/link/Coff.zig
@@ -107,12 +107,6 @@ const HotUpdateState = struct {
     loaded_base_address: ?std.os.windows.HMODULE = null,
 };
 
-const Entry = struct {
-    target: SymbolWithLoc,
-    // Index into the synthetic symbol table (i.e., file == null).
-    sym_index: u32,
-};
-
 const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
 const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
 const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
@@ -843,17 +837,17 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
     const file_offset = header.pointer_to_raw_data + entry_offset;
     const vmaddr = header.virtual_address + entry_offset;
 
-    log.debug("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value });
+    log.debug("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value + self.getImageBase() });
 
     switch (self.ptr_width) {
         .p32 => {
             var buf: [4]u8 = undefined;
-            mem.writeIntLittle(u32, &buf, @intCast(u32, entry_value));
+            mem.writeIntLittle(u32, &buf, @intCast(u32, entry_value + self.getImageBase()));
             try self.base.file.?.pwriteAll(&buf, file_offset);
         },
         .p64 => {
             var buf: [8]u8 = undefined;
-            mem.writeIntLittle(u64, &buf, entry_value);
+            mem.writeIntLittle(u64, &buf, entry_value + self.getImageBase());
             try self.base.file.?.pwriteAll(&buf, file_offset);
         },
     }
@@ -881,12 +875,14 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
             switch (self.ptr_width) {
                 .p32 => {
                     var buf: [4]u8 = undefined;
+                    mem.writeIntLittle(u32, &buf, @intCast(u32, entry_value + slide));
                     writeMem(handle, pvaddr, &buf) catch |err| {
                         log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});
                     };
                 },
                 .p64 => {
                     var buf: [8]u8 = undefined;
+                    mem.writeIntLittle(u64, &buf, entry_value + slide);
                     writeMem(handle, pvaddr, &buf) catch |err| {
                         log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});
                     };
@@ -1744,69 +1740,82 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl_index: Module.Dec
 fn writeBaseRelocations(self: *Coff) !void {
     const gpa = self.base.allocator;
 
-    var pages = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa);
+    var page_table = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa);
     defer {
-        var it = pages.valueIterator();
+        var it = page_table.valueIterator();
         while (it.next()) |inner| {
             inner.deinit();
         }
-        pages.deinit();
+        page_table.deinit();
     }
 
-    var it = self.base_relocs.iterator();
-    while (it.next()) |entry| {
-        const atom_index = entry.key_ptr.*;
-        const atom = self.getAtom(atom_index);
-        const sym = atom.getSymbol(self);
-        const offsets = entry.value_ptr.*;
-
-        for (offsets.items) |offset| {
-            const rva = sym.value + offset;
-            const page = mem.alignBackwardGeneric(u32, rva, self.page_size);
-            const gop = try pages.getOrPut(page);
-            if (!gop.found_existing) {
-                gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
+    {
+        var it = self.base_relocs.iterator();
+        while (it.next()) |entry| {
+            const atom_index = entry.key_ptr.*;
+            const atom = self.getAtom(atom_index);
+            const sym = atom.getSymbol(self);
+            const offsets = entry.value_ptr.*;
+
+            for (offsets.items) |offset| {
+                const rva = sym.value + offset;
+                const page = mem.alignBackwardGeneric(u32, rva, self.page_size);
+                const gop = try page_table.getOrPut(page);
+                if (!gop.found_existing) {
+                    gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
+                }
+                try gop.value_ptr.append(.{
+                    .offset = @intCast(u12, rva - page),
+                    .type = .DIR64,
+                });
             }
-            try gop.value_ptr.append(.{
-                .offset = @intCast(u12, rva - page),
-                .type = .DIR64,
-            });
         }
-    }
 
-    {
-        const header = &self.sections.items(.header)[self.got_section_index.?];
-        for (self.got_table.entries.items, 0..) |entry, index| {
-            if (!self.got_table.lookup.contains(entry)) continue;
+        {
+            const header = &self.sections.items(.header)[self.got_section_index.?];
+            for (self.got_table.entries.items, 0..) |entry, index| {
+                if (!self.got_table.lookup.contains(entry)) continue;
 
-            const sym = self.getSymbol(entry);
-            if (sym.section_number == .UNDEFINED) continue;
+                const sym = self.getSymbol(entry);
+                if (sym.section_number == .UNDEFINED) continue;
 
-            const rva = @intCast(u32, header.virtual_address + index * self.ptr_width.size());
-            const page = mem.alignBackwardGeneric(u32, rva, self.page_size);
-            const gop = try pages.getOrPut(page);
-            if (!gop.found_existing) {
-                gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
+                const rva = @intCast(u32, header.virtual_address + index * self.ptr_width.size());
+                const page = mem.alignBackwardGeneric(u32, rva, self.page_size);
+                const gop = try page_table.getOrPut(page);
+                if (!gop.found_existing) {
+                    gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
+                }
+                try gop.value_ptr.append(.{
+                    .offset = @intCast(u12, rva - page),
+                    .type = .DIR64,
+                });
             }
-            try gop.value_ptr.append(.{
-                .offset = @intCast(u12, rva - page),
-                .type = .DIR64,
-            });
         }
     }
 
+    // Sort pages by address.
+    var pages = try std.ArrayList(u32).initCapacity(gpa, page_table.count());
+    defer pages.deinit();
+    {
+        var it = page_table.keyIterator();
+        while (it.next()) |page| {
+            pages.appendAssumeCapacity(page.*);
+        }
+    }
+    std.sort.sort(u32, pages.items, {}, std.sort.asc(u32));
+
     var buffer = std.ArrayList(u8).init(gpa);
     defer buffer.deinit();
 
-    var pages_it = pages.iterator();
-    while (pages_it.next()) |entry| {
+    for (pages.items) |page| {
+        const entries = page_table.getPtr(page).?;
         // Pad to required 4byte alignment
         if (!mem.isAlignedGeneric(
             usize,
-            entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation),
+            entries.items.len * @sizeOf(coff.BaseRelocation),
             @sizeOf(u32),
         )) {
-            try entry.value_ptr.append(.{
+            try entries.append(.{
                 .offset = 0,
                 .type = .ABSOLUTE,
             });
@@ -1814,14 +1823,14 @@ fn writeBaseRelocations(self: *Coff) !void {
 
         const block_size = @intCast(
             u32,
-            entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry),
+            entries.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry),
         );
         try buffer.ensureUnusedCapacity(block_size);
         buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{
-            .page_rva = entry.key_ptr.*,
+            .page_rva = page,
             .block_size = block_size,
         }));
-        buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entry.value_ptr.items));
+        buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entries.items));
     }
 
     const header = &self.sections.items(.header)[self.reloc_section_index.?];