| author | |
| committer | |
| log | 004f32e79d61cb549b6cf71499138db0df56e152 |
| tree | 33d16cd1890d3db5493869347d9b295fcbc5cbfc |
| parent | 43487eb3ef0933c1da53b917c44ba6070d8e5a21 |
3 files changed, 53 insertions(+), 59 deletions(-)
src/link.zig+2| ... | ... | @@ -395,6 +395,7 @@ pub const File = struct { |
| 395 | 395 | .macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| { |
| 396 | 396 | log.warn("attaching failed with error: {s}", .{@errorName(err)}); |
| 397 | 397 | }, |
| 398 | .windows => {}, | |
| 398 | 399 | else => return error.HotSwapUnavailableOnHostOperatingSystem, |
| 399 | 400 | } |
| 400 | 401 | } |
| ... | ... | @@ -436,6 +437,7 @@ pub const File = struct { |
| 436 | 437 | .macos => base.cast(MachO).?.ptraceDetach(pid) catch |err| { |
| 437 | 438 | log.warn("detaching failed with error: {s}", .{@errorName(err)}); |
| 438 | 439 | }, |
| 440 | .windows => {}, | |
| 439 | 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 | 771 | // capacity, insert a free list node for it. |
| 772 | 772 | } |
| 773 | 773 | |
| 774 | fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void { | |
| 774 | fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { | |
| 775 | 775 | const atom = self.getAtom(atom_index); |
| 776 | 776 | const sym = atom.getSymbol(self); |
| 777 | 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 | 781 | file_offset, |
| 782 | 782 | file_offset + code.len, |
| 783 | 783 | }); |
| 784 | self.resolveRelocs(atom_index, code); | |
| 784 | 785 | try self.base.file.?.pwriteAll(code, file_offset); |
| 785 | try self.resolveRelocs(atom_index); | |
| 786 | 786 | } |
| 787 | 787 | |
| 788 | 788 | fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void { |
| ... | ... | @@ -820,14 +820,15 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { |
| 820 | 820 | } |
| 821 | 821 | } |
| 822 | 822 | |
| 823 | fn resolveRelocs(self: *Coff, atom_index: Atom.Index) !void { | |
| 823 | fn resolveRelocs(self: *Coff, atom_index: Atom.Index, code: []u8) void { | |
| 824 | 824 | const relocs = self.relocs.get(atom_index) orelse return; |
| 825 | 825 | |
| 826 | 826 | log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)}); |
| 827 | 827 | |
| 828 | 828 | for (relocs.items) |*reloc| { |
| 829 | 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 | } |
| 833 | 834 | |
| ... | ... | @@ -944,7 +945,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 944 | 945 | &code_buffer, |
| 945 | 946 | .none, |
| 946 | 947 | ); |
| 947 | const code = switch (res) { | |
| 948 | var code = switch (res) { | |
| 948 | 949 | .ok => code_buffer.items, |
| 949 | 950 | .fail => |em| { |
| 950 | 951 | decl.analysis = .codegen_failure; |
| ... | ... | @@ -994,7 +995,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 994 | 995 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{ |
| 995 | 996 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| 996 | 997 | }); |
| 997 | const code = switch (res) { | |
| 998 | var code = switch (res) { | |
| 998 | 999 | .ok => code_buffer.items, |
| 999 | 1000 | .fail => |em| { |
| 1000 | 1001 | decl.analysis = .codegen_failure; |
| ... | ... | @@ -1057,7 +1058,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! |
| 1057 | 1058 | }, &code_buffer, .none, .{ |
| 1058 | 1059 | .parent_atom_index = atom.getSymbolIndex().?, |
| 1059 | 1060 | }); |
| 1060 | const code = switch (res) { | |
| 1061 | var code = switch (res) { | |
| 1061 | 1062 | .ok => code_buffer.items, |
| 1062 | 1063 | .fail => |em| { |
| 1063 | 1064 | decl.analysis = .codegen_failure; |
| ... | ... | @@ -1110,7 +1111,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { |
| 1110 | 1111 | return index; |
| 1111 | 1112 | } |
| 1112 | 1113 | |
| 1113 | fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, complex_type: coff.ComplexType) !void { | |
| 1114 | fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, complex_type: coff.ComplexType) !void { | |
| 1114 | 1115 | const gpa = self.base.allocator; |
| 1115 | 1116 | const mod = self.base.options.module.?; |
| 1116 | 1117 | const decl = mod.declPtr(decl_index); |
| ... | ... | @@ -1424,8 +1425,28 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1424 | 1425 | try self.writeImportTables(); |
| 1425 | 1426 | { |
| 1426 | 1427 | var it = self.relocs.keyIterator(); |
| 1427 | while (it.next()) |atom| { | |
| 1428 | try self.resolveRelocs(atom.*); | |
| 1428 | while (it.next()) |atom_index_ptr| { | |
| 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 | 1452 | try self.writeBaseRelocations(); |
| ... | ... | @@ -1642,6 +1663,7 @@ fn writeImportTables(self: *Coff) !void { |
| 1642 | 1663 | const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address); |
| 1643 | 1664 | if (needed_size > sect_vm_capacity) { |
| 1644 | 1665 | try self.growSectionVM(self.idata_section_index.?, needed_size); |
| 1666 | self.markRelocsDirtyByAddress(header.virtual_address + needed_size); | |
| 1645 | 1667 | } |
| 1646 | 1668 | |
| 1647 | 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 | 72 | } |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | pub fn resolve(self: *Relocation, atom_index: Atom.Index, coff_file: *Coff) !void { | |
| 75 | pub fn resolve(self: *Relocation, atom_index: Atom.Index, code: []u8, coff_file: *Coff) void { | |
| 76 | 76 | const atom = coff_file.getAtom(atom_index); |
| 77 | 77 | const source_sym = atom.getSymbol(coff_file); |
| 78 | const source_section = coff_file.sections.get(@enumToInt(source_sym.section_number) - 1).header; | |
| 79 | 78 | const source_vaddr = source_sym.value + self.offset; |
| 80 | 79 | |
| 81 | const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address; | |
| 82 | ||
| 83 | 80 | const target_vaddr = self.getTargetAddress(coff_file) orelse return; |
| 84 | 81 | const target_vaddr_with_addend = target_vaddr + self.addend; |
| 85 | 82 | |
| 86 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ | |
| 83 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) ", .{ | |
| 87 | 84 | source_vaddr, |
| 88 | 85 | target_vaddr_with_addend, |
| 89 | 86 | coff_file.getSymbolName(self.target), |
| 90 | 87 | @tagName(self.type), |
| 91 | file_offset + self.offset, | |
| 92 | 88 | }); |
| 93 | 89 | |
| 94 | 90 | const ctx: Context = .{ |
| 95 | 91 | .source_vaddr = source_vaddr, |
| 96 | 92 | .target_vaddr = target_vaddr_with_addend, |
| 97 | .file_offset = file_offset, | |
| 98 | 93 | .image_base = coff_file.getImageBase(), |
| 94 | .code = code, | |
| 95 | .ptr_width = coff_file.ptr_width, | |
| 99 | 96 | }; |
| 100 | 97 | |
| 101 | 98 | switch (coff_file.base.options.target.cpu.arch) { |
| 102 | .aarch64 => try self.resolveAarch64(ctx, coff_file), | |
| 103 | .x86, .x86_64 => try self.resolveX86(ctx, coff_file), | |
| 99 | .aarch64 => self.resolveAarch64(ctx), | |
| 100 | .x86, .x86_64 => self.resolveX86(ctx), | |
| 104 | 101 | else => unreachable, // unhandled target architecture |
| 105 | 102 | } |
| 106 | ||
| 107 | self.dirty = false; | |
| 108 | 103 | } |
| 109 | 104 | |
| 110 | 105 | const Context = struct { |
| 111 | 106 | source_vaddr: u32, |
| 112 | 107 | target_vaddr: u32, |
| 113 | file_offset: u32, | |
| 114 | 108 | image_base: u64, |
| 109 | code: []u8, | |
| 110 | ptr_width: Coff.PtrWidth, | |
| 115 | 111 | }; |
| 116 | 112 | |
| 117 | fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void { | |
| 118 | var buffer: [@sizeOf(u64)]u8 = undefined; | |
| 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 | ||
| 113 | fn resolveAarch64(self: Relocation, ctx: Context) void { | |
| 114 | var buffer = ctx.code[self.offset..]; | |
| 131 | 115 | switch (self.type) { |
| 132 | 116 | .got_page, .import_page, .page => { |
| 133 | 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 | 172 | buffer[0..4], |
| 189 | 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 | 176 | else => unreachable, |
| 193 | 177 | } |
| 194 | 178 | }, |
| ... | ... | @@ -196,15 +180,10 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void { |
| 196 | 180 | .got => unreachable, |
| 197 | 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 | } |
| 206 | 184 | |
| 207 | fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void { | |
| 185 | fn resolveX86(self: Relocation, ctx: Context) void { | |
| 186 | var buffer = ctx.code[self.offset..]; | |
| 208 | 187 | switch (self.type) { |
| 209 | 188 | .got_page => unreachable, |
| 210 | 189 | .got_pageoff => unreachable, |
| ... | ... | @@ -216,26 +195,17 @@ fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void { |
| 216 | 195 | .got, .import => { |
| 217 | 196 | assert(self.pcrel); |
| 218 | 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 | 200 | .direct => { |
| 222 | 201 | if (self.pcrel) { |
| 223 | 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); | |
| 225 | } else switch (coff_file.ptr_width) { | |
| 226 | .p32 => try coff_file.base.file.?.pwriteAll( | |
| 227 | mem.asBytes(&@intCast(u32, ctx.target_vaddr + ctx.image_base)), | |
| 228 | ctx.file_offset + self.offset, | |
| 229 | ), | |
| 203 | mem.writeIntLittle(i32, buffer[0..4], disp); | |
| 204 | } else switch (ctx.ptr_width) { | |
| 205 | .p32 => mem.writeIntLittle(u32, buffer[0..4], @intCast(u32, ctx.target_vaddr + ctx.image_base)), | |
| 230 | 206 | .p64 => switch (self.length) { |
| 231 | 2 => try coff_file.base.file.?.pwriteAll( | |
| 232 | mem.asBytes(&@truncate(u32, 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 | ), | |
| 207 | 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, ctx.target_vaddr + ctx.image_base)), | |
| 208 | 3 => mem.writeIntLittle(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base), | |
| 239 | 209 | else => unreachable, |
| 240 | 210 | }, |
| 241 | 211 | } |