authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-28 18:59:44+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-28 18:59:44+02:00
log004f32e79d61cb549b6cf71499138db0df56e152
tree33d16cd1890d3db5493869347d9b295fcbc5cbfc
parent43487eb3ef0933c1da53b917c44ba6070d8e5a21

coff: resolve relocs on bytes buffer directly


3 files changed, 53 insertions(+), 59 deletions(-)

src/link.zig+2
...@@ -395,6 +395,7 @@ pub const File = struct {...@@ -395,6 +395,7 @@ pub const File = struct {
395 .macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| {395 .macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| {
396 log.warn("attaching failed with error: {s}", .{@errorName(err)});396 log.warn("attaching failed with error: {s}", .{@errorName(err)});
397 },397 },
398 .windows => {},
398 else => return error.HotSwapUnavailableOnHostOperatingSystem,399 else => return error.HotSwapUnavailableOnHostOperatingSystem,
399 }400 }
400 }401 }
...@@ -436,6 +437,7 @@ pub const File = struct {...@@ -436,6 +437,7 @@ pub const File = struct {
436 .macos => base.cast(MachO).?.ptraceDetach(pid) catch |err| {437 .macos => base.cast(MachO).?.ptraceDetach(pid) catch |err| {
437 log.warn("detaching failed with error: {s}", .{@errorName(err)});438 log.warn("detaching failed with error: {s}", .{@errorName(err)});
438 },439 },
440 .windows => {},
439 else => return error.HotSwapUnavailableOnHostOperatingSystem,441 else => return error.HotSwapUnavailableOnHostOperatingSystem,
440 }442 }
441 }443 }
src/link/Coff.zig+32-10
...@@ -771,7 +771,7 @@ fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void {...@@ -771,7 +771,7 @@ fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void {
771 // capacity, insert a free list node for it.771 // capacity, insert a free list node for it.
772}772}
773773
774fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void {774fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
775 const atom = self.getAtom(atom_index);775 const atom = self.getAtom(atom_index);
776 const sym = atom.getSymbol(self);776 const sym = atom.getSymbol(self);
777 const section = self.sections.get(@enumToInt(sym.section_number) - 1);777 const section = self.sections.get(@enumToInt(sym.section_number) - 1);
...@@ -781,8 +781,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void {...@@ -781,8 +781,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void {
781 file_offset,781 file_offset,
782 file_offset + code.len,782 file_offset + code.len,
783 });783 });
784 self.resolveRelocs(atom_index, code);
784 try self.base.file.?.pwriteAll(code, file_offset);785 try self.base.file.?.pwriteAll(code, file_offset);
785 try self.resolveRelocs(atom_index);
786}786}
787787
788fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {788fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {
...@@ -820,14 +820,15 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {...@@ -820,14 +820,15 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
820 }820 }
821}821}
822822
823fn resolveRelocs(self: *Coff, atom_index: Atom.Index) !void {823fn resolveRelocs(self: *Coff, atom_index: Atom.Index, code: []u8) void {
824 const relocs = self.relocs.get(atom_index) orelse return;824 const relocs = self.relocs.get(atom_index) orelse return;
825825
826 log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)});826 log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)});
827827
828 for (relocs.items) |*reloc| {828 for (relocs.items) |*reloc| {
829 if (!reloc.dirty) continue;829 if (!reloc.dirty) continue;
830 try reloc.resolve(atom_index, self);830 reloc.resolve(atom_index, code, self);
831 reloc.dirty = false;
831 }832 }
832}833}
833834
...@@ -944,7 +945,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live...@@ -944,7 +945,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
944 &code_buffer,945 &code_buffer,
945 .none,946 .none,
946 );947 );
947 const code = switch (res) {948 var code = switch (res) {
948 .ok => code_buffer.items,949 .ok => code_buffer.items,
949 .fail => |em| {950 .fail => |em| {
950 decl.analysis = .codegen_failure;951 decl.analysis = .codegen_failure;
...@@ -994,7 +995,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -994,7 +995,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
994 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{995 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{
995 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,996 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
996 });997 });
997 const code = switch (res) {998 var code = switch (res) {
998 .ok => code_buffer.items,999 .ok => code_buffer.items,
999 .fail => |em| {1000 .fail => |em| {
1000 decl.analysis = .codegen_failure;1001 decl.analysis = .codegen_failure;
...@@ -1057,7 +1058,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1057,7 +1058,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1057 }, &code_buffer, .none, .{1058 }, &code_buffer, .none, .{
1058 .parent_atom_index = atom.getSymbolIndex().?,1059 .parent_atom_index = atom.getSymbolIndex().?,
1059 });1060 });
1060 const code = switch (res) {1061 var code = switch (res) {
1061 .ok => code_buffer.items,1062 .ok => code_buffer.items,
1062 .fail => |em| {1063 .fail => |em| {
1063 decl.analysis = .codegen_failure;1064 decl.analysis = .codegen_failure;
...@@ -1110,7 +1111,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 {...@@ -1110,7 +1111,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 {
1110 return index;1111 return index;
1111}1112}
11121113
1113fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, complex_type: coff.ComplexType) !void {1114fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, complex_type: coff.ComplexType) !void {
1114 const gpa = self.base.allocator;1115 const gpa = self.base.allocator;
1115 const mod = self.base.options.module.?;1116 const mod = self.base.options.module.?;
1116 const decl = mod.declPtr(decl_index);1117 const decl = mod.declPtr(decl_index);
...@@ -1424,8 +1425,28 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1424,8 +1425,28 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1424 try self.writeImportTables();1425 try self.writeImportTables();
1425 {1426 {
1426 var it = self.relocs.keyIterator();1427 var it = self.relocs.keyIterator();
1427 while (it.next()) |atom| {1428 while (it.next()) |atom_index_ptr| {
1428 try self.resolveRelocs(atom.*);1429 const atom_index = atom_index_ptr.*;
1430 const relocs = self.relocs.get(atom_index).?;
1431 const needs_update = for (relocs.items) |reloc| {
1432 if (reloc.dirty) break true;
1433 } else false;
1434
1435 if (!needs_update) continue;
1436
1437 const atom = self.getAtom(atom_index);
1438 const sym = atom.getSymbol(self);
1439 const section = self.sections.get(@enumToInt(sym.section_number) - 1).header;
1440 const file_offset = section.pointer_to_raw_data + sym.value - section.virtual_address;
1441
1442 var code = std.ArrayList(u8).init(gpa);
1443 defer code.deinit();
1444 try code.resize(math.cast(usize, atom.size) orelse return error.Overflow);
1445
1446 const amt = try self.base.file.?.preadAll(code.items, file_offset);
1447 if (amt != code.items.len) return error.InputOutput;
1448
1449 try self.writeAtom(atom_index, code.items);
1429 }1450 }
1430 }1451 }
1431 try self.writeBaseRelocations();1452 try self.writeBaseRelocations();
...@@ -1642,6 +1663,7 @@ fn writeImportTables(self: *Coff) !void {...@@ -1642,6 +1663,7 @@ fn writeImportTables(self: *Coff) !void {
1642 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);1663 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);
1643 if (needed_size > sect_vm_capacity) {1664 if (needed_size > sect_vm_capacity) {
1644 try self.growSectionVM(self.idata_section_index.?, needed_size);1665 try self.growSectionVM(self.idata_section_index.?, needed_size);
1666 self.markRelocsDirtyByAddress(header.virtual_address + needed_size);
1645 }1667 }
16461668
1647 header.virtual_size = @max(header.virtual_size, needed_size);1669 header.virtual_size = @max(header.virtual_size, needed_size);
src/link/Coff/Relocation.zig+19-49
...@@ -72,62 +72,46 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {...@@ -72,62 +72,46 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
72 }72 }
73}73}
7474
75pub fn resolve(self: *Relocation, atom_index: Atom.Index, coff_file: *Coff) !void {75pub fn resolve(self: *Relocation, atom_index: Atom.Index, code: []u8, coff_file: *Coff) void {
76 const atom = coff_file.getAtom(atom_index);76 const atom = coff_file.getAtom(atom_index);
77 const source_sym = atom.getSymbol(coff_file);77 const source_sym = atom.getSymbol(coff_file);
78 const source_section = coff_file.sections.get(@enumToInt(source_sym.section_number) - 1).header;
79 const source_vaddr = source_sym.value + self.offset;78 const source_vaddr = source_sym.value + self.offset;
8079
81 const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address;
82
83 const target_vaddr = self.getTargetAddress(coff_file) orelse return;80 const target_vaddr = self.getTargetAddress(coff_file) orelse return;
84 const target_vaddr_with_addend = target_vaddr + self.addend;81 const target_vaddr_with_addend = target_vaddr + self.addend;
8582
86 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{83 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) ", .{
87 source_vaddr,84 source_vaddr,
88 target_vaddr_with_addend,85 target_vaddr_with_addend,
89 coff_file.getSymbolName(self.target),86 coff_file.getSymbolName(self.target),
90 @tagName(self.type),87 @tagName(self.type),
91 file_offset + self.offset,
92 });88 });
9389
94 const ctx: Context = .{90 const ctx: Context = .{
95 .source_vaddr = source_vaddr,91 .source_vaddr = source_vaddr,
96 .target_vaddr = target_vaddr_with_addend,92 .target_vaddr = target_vaddr_with_addend,
97 .file_offset = file_offset,
98 .image_base = coff_file.getImageBase(),93 .image_base = coff_file.getImageBase(),
94 .code = code,
95 .ptr_width = coff_file.ptr_width,
99 };96 };
10097
101 switch (coff_file.base.options.target.cpu.arch) {98 switch (coff_file.base.options.target.cpu.arch) {
102 .aarch64 => try self.resolveAarch64(ctx, coff_file),99 .aarch64 => self.resolveAarch64(ctx),
103 .x86, .x86_64 => try self.resolveX86(ctx, coff_file),100 .x86, .x86_64 => self.resolveX86(ctx),
104 else => unreachable, // unhandled target architecture101 else => unreachable, // unhandled target architecture
105 }102 }
106
107 self.dirty = false;
108}103}
109104
110const Context = struct {105const Context = struct {
111 source_vaddr: u32,106 source_vaddr: u32,
112 target_vaddr: u32,107 target_vaddr: u32,
113 file_offset: u32,
114 image_base: u64,108 image_base: u64,
109 code: []u8,
110 ptr_width: Coff.PtrWidth,
115};111};
116112
117fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {113fn resolveAarch64(self: Relocation, ctx: Context) void {
118 var buffer: [@sizeOf(u64)]u8 = undefined;114 var buffer = ctx.code[self.offset..];
119 switch (self.length) {
120 2 => {
121 const amt = try coff_file.base.file.?.preadAll(buffer[0..4], ctx.file_offset + self.offset);
122 if (amt != 4) return error.InputOutput;
123 },
124 3 => {
125 const amt = try coff_file.base.file.?.preadAll(&buffer, ctx.file_offset + self.offset);
126 if (amt != 8) return error.InputOutput;
127 },
128 else => unreachable,
129 }
130
131 switch (self.type) {115 switch (self.type) {
132 .got_page, .import_page, .page => {116 .got_page, .import_page, .page => {
133 const source_page = @intCast(i32, ctx.source_vaddr >> 12);117 const source_page = @intCast(i32, ctx.source_vaddr >> 12);
...@@ -188,7 +172,7 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {...@@ -188,7 +172,7 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {
188 buffer[0..4],172 buffer[0..4],
189 @truncate(u32, ctx.target_vaddr + ctx.image_base),173 @truncate(u32, ctx.target_vaddr + ctx.image_base),
190 ),174 ),
191 3 => mem.writeIntLittle(u64, &buffer, ctx.target_vaddr + ctx.image_base),175 3 => mem.writeIntLittle(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base),
192 else => unreachable,176 else => unreachable,
193 }177 }
194 },178 },
...@@ -196,15 +180,10 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {...@@ -196,15 +180,10 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {
196 .got => unreachable,180 .got => unreachable,
197 .import => unreachable,181 .import => unreachable,
198 }182 }
199
200 switch (self.length) {
201 2 => try coff_file.base.file.?.pwriteAll(buffer[0..4], ctx.file_offset + self.offset),
202 3 => try coff_file.base.file.?.pwriteAll(&buffer, ctx.file_offset + self.offset),
203 else => unreachable,
204 }
205}183}
206184
207fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void {185fn resolveX86(self: Relocation, ctx: Context) void {
186 var buffer = ctx.code[self.offset..];
208 switch (self.type) {187 switch (self.type) {
209 .got_page => unreachable,188 .got_page => unreachable,
210 .got_pageoff => unreachable,189 .got_pageoff => unreachable,
...@@ -216,26 +195,17 @@ fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void {...@@ -216,26 +195,17 @@ fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void {
216 .got, .import => {195 .got, .import => {
217 assert(self.pcrel);196 assert(self.pcrel);
218 const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4;197 const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4;
219 try coff_file.base.file.?.pwriteAll(mem.asBytes(&disp), ctx.file_offset + self.offset);198 mem.writeIntLittle(i32, buffer[0..4], disp);
220 },199 },
221 .direct => {200 .direct => {
222 if (self.pcrel) {201 if (self.pcrel) {
223 const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4;202 const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4;
224 try coff_file.base.file.?.pwriteAll(mem.asBytes(&disp), ctx.file_offset + self.offset);203 mem.writeIntLittle(i32, buffer[0..4], disp);
225 } else switch (coff_file.ptr_width) {204 } else switch (ctx.ptr_width) {
226 .p32 => try coff_file.base.file.?.pwriteAll(205 .p32 => mem.writeIntLittle(u32, buffer[0..4], @intCast(u32, ctx.target_vaddr + ctx.image_base)),
227 mem.asBytes(&@intCast(u32, ctx.target_vaddr + ctx.image_base)),
228 ctx.file_offset + self.offset,
229 ),
230 .p64 => switch (self.length) {206 .p64 => switch (self.length) {
231 2 => try coff_file.base.file.?.pwriteAll(207 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, ctx.target_vaddr + ctx.image_base)),
232 mem.asBytes(&@truncate(u32, ctx.target_vaddr + ctx.image_base)),208 3 => mem.writeIntLittle(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base),
233 ctx.file_offset + self.offset,
234 ),
235 3 => try coff_file.base.file.?.pwriteAll(
236 mem.asBytes(&(ctx.target_vaddr + ctx.image_base)),
237 ctx.file_offset + self.offset,
238 ),
239 else => unreachable,209 else => unreachable,
240 },210 },
241 }211 }