| 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,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 | } |
| 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 | 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 | } |
| 787 | 787 | ||
| 788 | fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void { | 788 | fn 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 | } |
| 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 | const relocs = self.relocs.get(atom_index) orelse return; | 824 | const relocs = self.relocs.get(atom_index) orelse return; |
| 825 | 825 | ||
| 826 | log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)}); | 826 | log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)}); |
| 827 | 827 | ||
| 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 | } |
| 833 | 834 | ||
| ... | @@ -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 | } |
| 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 | 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 | } |
| 1646 | 1668 | ||
| 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 | } |
| 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 | 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; |
| 80 | 79 | ||
| 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; |
| 85 | 82 | ||
| 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 | }); |
| 93 | 89 | ||
| 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 | }; |
| 100 | 97 | ||
| 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 architecture | 101 | else => unreachable, // unhandled target architecture |
| 105 | } | 102 | } |
| 106 | |||
| 107 | self.dirty = false; | ||
| 108 | } | 103 | } |
| 109 | 104 | ||
| 110 | const Context = struct { | 105 | const 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 | }; |
| 116 | 112 | ||
| 117 | fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void { | 113 | fn 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 | } |
| 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 | 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 | } |