| ... | ... | @@ -55,11 +55,6 @@ debug_str_section_zig_size: u64 = 0, |
| 55 | 55 | debug_aranges_section_zig_size: u64 = 0, |
| 56 | 56 | debug_line_section_zig_size: u64 = 0, |
| 57 | 57 | |
| 58 | | /// Function jump table containing trampolines to Zcu functions. |
| 59 | | /// The table is used for Zig's incremental compilation and is embedded with |
| 60 | | /// the machine code section. |
| 61 | | jump_table: ?JumpTable = null, |
| 62 | | |
| 63 | 58 | pub const global_symbol_bit: u32 = 0x80000000; |
| 64 | 59 | pub const symbol_mask: u32 = 0x7fffffff; |
| 65 | 60 | pub const SHN_ATOM: u16 = 0x100; |
| ... | ... | @@ -127,10 +122,6 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 127 | 122 | if (self.dwarf) |*dw| { |
| 128 | 123 | dw.deinit(); |
| 129 | 124 | } |
| 130 | | |
| 131 | | if (self.jump_table) |*jt| { |
| 132 | | jt.deinit(allocator); |
| 133 | | } |
| 134 | 125 | } |
| 135 | 126 | |
| 136 | 127 | pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { |
| ... | ... | @@ -665,7 +656,7 @@ pub fn getNavVAddr( |
| 665 | 656 | else => try self.getOrCreateMetadataForNav(elf_file, nav_index), |
| 666 | 657 | }; |
| 667 | 658 | const this_sym = self.symbol(this_sym_index); |
| 668 | | const vaddr = this_sym.address(.{ .zjt = true }, elf_file); |
| 659 | const vaddr = this_sym.address(.{}, elf_file); |
| 669 | 660 | const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?; |
| 670 | 661 | const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); |
| 671 | 662 | try parent_atom.addReloc(elf_file, .{ |
| ... | ... | @@ -914,12 +905,6 @@ fn updateNavCode( |
| 914 | 905 | if (old_vaddr != atom_ptr.value) { |
| 915 | 906 | sym.value = 0; |
| 916 | 907 | esym.st_value = 0; |
| 917 | | |
| 918 | | if (stt_bits == elf.STT_FUNC) { |
| 919 | | const extra = sym.extra(elf_file); |
| 920 | | const jump_table = self.jumpTablePtr().?; |
| 921 | | jump_table.entries.items(.dirty)[extra.zjt] = true; |
| 922 | | } |
| 923 | 908 | } |
| 924 | 909 | } else if (code.len < old_size) { |
| 925 | 910 | atom_ptr.shrink(elf_file); |
| ... | ... | @@ -942,7 +927,7 @@ fn updateNavCode( |
| 942 | 927 | .len = code.len, |
| 943 | 928 | }}; |
| 944 | 929 | var remote_vec: [1]std.posix.iovec_const = .{.{ |
| 945 | | .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.address(.{ .zjt = true }, elf_file))))), |
| 930 | .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.address(.{}, elf_file))))), |
| 946 | 931 | .len = code.len, |
| 947 | 932 | }}; |
| 948 | 933 | const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0); |
| ... | ... | @@ -1036,31 +1021,12 @@ pub fn updateFunc( |
| 1036 | 1021 | const ip = &zcu.intern_pool; |
| 1037 | 1022 | const gpa = elf_file.base.comp.gpa; |
| 1038 | 1023 | const func = zcu.funcInfo(func_index); |
| 1039 | | if (!elf_file.base.isRelocatable() and self.jumpTablePtr() == null) { |
| 1040 | | try self.initJumpTable(gpa, elf_file); |
| 1041 | | } |
| 1042 | 1024 | |
| 1043 | 1025 | log.debug("updateFunc {}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav }); |
| 1044 | 1026 | |
| 1045 | 1027 | const sym_index = try self.getOrCreateMetadataForNav(elf_file, func.owner_nav); |
| 1046 | 1028 | self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); |
| 1047 | 1029 | |
| 1048 | | if (self.jumpTablePtr()) |jump_table| { |
| 1049 | | const sym = self.symbol(sym_index); |
| 1050 | | if (!sym.flags.has_zjt) { |
| 1051 | | const index = try jump_table.addSymbol(gpa, sym_index); |
| 1052 | | sym.flags.has_zjt = true; |
| 1053 | | sym.addExtra(.{ .zjt = index }, elf_file); |
| 1054 | | try jump_table.updateSize(self, elf_file); |
| 1055 | | const old_vaddr = jump_table.address(self, elf_file); |
| 1056 | | try self.symbol(jump_table.sym_index).atom(elf_file).?.allocate(elf_file); |
| 1057 | | const new_vaddr = jump_table.address(self, elf_file); |
| 1058 | | if (old_vaddr != new_vaddr) { |
| 1059 | | jump_table.dirty = true; |
| 1060 | | } |
| 1061 | | } |
| 1062 | | } |
| 1063 | | |
| 1064 | 1030 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1065 | 1031 | defer code_buffer.deinit(); |
| 1066 | 1032 | |
| ... | ... | @@ -1087,14 +1053,22 @@ pub fn updateFunc( |
| 1087 | 1053 | }; |
| 1088 | 1054 | |
| 1089 | 1055 | const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, code); |
| 1056 | const old_rva, const old_alignment = blk: { |
| 1057 | const atom_ptr = self.symbol(sym_index).atom(elf_file).?; |
| 1058 | break :blk .{ atom_ptr.value, atom_ptr.alignment }; |
| 1059 | }; |
| 1090 | 1060 | try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC); |
| 1061 | const new_rva, const new_alignment = blk: { |
| 1062 | const atom_ptr = self.symbol(sym_index).atom(elf_file).?; |
| 1063 | break :blk .{ atom_ptr.value, atom_ptr.alignment }; |
| 1064 | }; |
| 1091 | 1065 | |
| 1092 | 1066 | if (dwarf_state) |*ds| { |
| 1093 | 1067 | const sym = self.symbol(sym_index); |
| 1094 | 1068 | try self.dwarf.?.commitNavState( |
| 1095 | 1069 | pt, |
| 1096 | 1070 | func.owner_nav, |
| 1097 | | @intCast(sym.address(.{ .zjt = true }, elf_file)), |
| 1071 | @intCast(sym.address(.{}, elf_file)), |
| 1098 | 1072 | sym.atom(elf_file).?.size, |
| 1099 | 1073 | ds, |
| 1100 | 1074 | ); |
| ... | ... | @@ -1102,23 +1076,39 @@ pub fn updateFunc( |
| 1102 | 1076 | |
| 1103 | 1077 | // Exports will be updated by `Zcu.processExports` after the update. |
| 1104 | 1078 | |
| 1105 | | if (self.jumpTablePtr()) |jump_table| { |
| 1106 | | if (jump_table.dirty) { |
| 1107 | | // TODO write in bulk |
| 1108 | | for (jump_table.entries.items(.dirty), 0..) |*dirty, i| { |
| 1109 | | try jump_table.writeEntry(@intCast(i), self, elf_file); |
| 1110 | | dirty.* = false; |
| 1111 | | } |
| 1112 | | } else { |
| 1113 | | const sym = self.symbol(sym_index); |
| 1114 | | const jt_index = sym.extra(elf_file).zjt; |
| 1115 | | var jt_entry = jump_table.entries.get(jt_index); |
| 1116 | | if (jt_entry.dirty) { |
| 1117 | | try jump_table.writeEntry(jt_index, self, elf_file); |
| 1118 | | jt_entry.dirty = false; |
| 1119 | | } |
| 1120 | | jump_table.entries.set(jt_index, jt_entry); |
| 1079 | if (old_rva != new_rva and old_rva > 0) { |
| 1080 | // If we had to reallocate the function, we re-use the existing slot for a trampoline. |
| 1081 | // In the rare case that the function has been further overaligned we skip creating a |
| 1082 | // trampoline and update all symbols referring this function. |
| 1083 | if (old_alignment.order(new_alignment) == .lt) { |
| 1084 | @panic("TODO update all symbols referring this function"); |
| 1085 | } |
| 1086 | |
| 1087 | // Create a trampoline to the new location at `old_rva`. |
| 1088 | if (!self.symbol(sym_index).flags.has_trampoline) { |
| 1089 | const name = try std.fmt.allocPrint(gpa, "{s}$trampoline", .{ |
| 1090 | self.symbol(sym_index).name(elf_file), |
| 1091 | }); |
| 1092 | defer gpa.free(name); |
| 1093 | const name_off = try self.addString(gpa, name); |
| 1094 | const tr_size = trampolineSize(elf_file.getTarget().cpu.arch); |
| 1095 | const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off); |
| 1096 | const tr_sym = self.symbol(tr_sym_index); |
| 1097 | const tr_esym = &self.symtab.items(.elf_sym)[tr_sym.esym_index]; |
| 1098 | tr_esym.st_info |= elf.STT_OBJECT; |
| 1099 | tr_esym.st_size = tr_size; |
| 1100 | const tr_atom_ptr = tr_sym.atom(elf_file).?; |
| 1101 | tr_atom_ptr.value = old_rva; |
| 1102 | tr_atom_ptr.alive = true; |
| 1103 | tr_atom_ptr.alignment = old_alignment; |
| 1104 | tr_atom_ptr.output_section_index = elf_file.zig_text_section_index.?; |
| 1105 | tr_atom_ptr.size = tr_size; |
| 1106 | const target_sym = self.symbol(sym_index); |
| 1107 | target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file); |
| 1108 | target_sym.flags.has_trampoline = true; |
| 1121 | 1109 | } |
| 1110 | const target_sym = self.symbol(sym_index); |
| 1111 | try writeTrampoline(self.symbol(target_sym.extra(elf_file).trampoline).*, target_sym.*, elf_file); |
| 1122 | 1112 | } |
| 1123 | 1113 | } |
| 1124 | 1114 | |
| ... | ... | @@ -1193,7 +1183,7 @@ pub fn updateNav( |
| 1193 | 1183 | try self.dwarf.?.commitNavState( |
| 1194 | 1184 | pt, |
| 1195 | 1185 | nav_index, |
| 1196 | | @intCast(sym.address(.{ .zjt = true }, elf_file)), |
| 1186 | @intCast(sym.address(.{}, elf_file)), |
| 1197 | 1187 | sym.atom(elf_file).?.size, |
| 1198 | 1188 | ns, |
| 1199 | 1189 | ); |
| ... | ... | @@ -1474,21 +1464,50 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n |
| 1474 | 1464 | return lookup_gop.value_ptr.*; |
| 1475 | 1465 | } |
| 1476 | 1466 | |
| 1477 | | pub fn jumpTablePtr(self: *ZigObject) ?*JumpTable { |
| 1478 | | return if (self.jump_table) |*jt| jt else null; |
| 1479 | | } |
| 1467 | const max_trampoline_len = 12; |
| 1480 | 1468 | |
| 1481 | | fn initJumpTable(self: *ZigObject, allocator: Allocator, elf_file: *Elf) error{OutOfMemory}!void { |
| 1482 | | const name_off = try self.addString(allocator, "__zig_jump_table"); |
| 1483 | | const sym_index = try self.newSymbolWithAtom(allocator, name_off); |
| 1484 | | const sym = self.symbol(sym_index); |
| 1485 | | const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; |
| 1486 | | esym.st_info |= elf.STT_OBJECT; |
| 1487 | | const atom_ptr = sym.atom(elf_file).?; |
| 1488 | | atom_ptr.alive = true; |
| 1489 | | atom_ptr.alignment = Atom.Alignment.fromNonzeroByteUnits(JumpTable.alignment(elf_file.getTarget().cpu.arch)); |
| 1490 | | atom_ptr.output_section_index = elf_file.zig_text_section_index.?; |
| 1491 | | self.jump_table = JumpTable{ .sym_index = sym_index }; |
| 1469 | fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 { |
| 1470 | const len = switch (cpu_arch) { |
| 1471 | .x86_64 => 5, // jmp rel32 |
| 1472 | else => @panic("TODO implement trampoline size for this CPU arch"), |
| 1473 | }; |
| 1474 | comptime assert(len <= max_trampoline_len); |
| 1475 | return len; |
| 1476 | } |
| 1477 | |
| 1478 | fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { |
| 1479 | const atom_ptr = tr_sym.atom(elf_file).?; |
| 1480 | const shdr = elf_file.shdrs.items[atom_ptr.output_section_index]; |
| 1481 | const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 1482 | const source_addr = tr_sym.address(.{}, elf_file); |
| 1483 | const target_addr = target.address(.{ .trampoline = false }, elf_file); |
| 1484 | var buf: [max_trampoline_len]u8 = undefined; |
| 1485 | const out = switch (elf_file.getTarget().cpu.arch) { |
| 1486 | .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf), |
| 1487 | else => @panic("TODO implement write trampoline for this CPU arch"), |
| 1488 | }; |
| 1489 | try elf_file.base.file.?.pwriteAll(out, fileoff); |
| 1490 | |
| 1491 | if (elf_file.base.child_pid) |pid| { |
| 1492 | switch (builtin.os.tag) { |
| 1493 | .linux => { |
| 1494 | var local_vec: [1]std.posix.iovec_const = .{.{ |
| 1495 | .base = out.ptr, |
| 1496 | .len = out.len, |
| 1497 | }}; |
| 1498 | var remote_vec: [1]std.posix.iovec_const = .{.{ |
| 1499 | .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(source_addr)))), |
| 1500 | .len = out.len, |
| 1501 | }}; |
| 1502 | const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0); |
| 1503 | switch (std.os.linux.E.init(rc)) { |
| 1504 | .SUCCESS => assert(rc == out.len), |
| 1505 | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), |
| 1506 | } |
| 1507 | }, |
| 1508 | else => return error.HotSwapUnavailableOnHostOperatingSystem, |
| 1509 | } |
| 1510 | } |
| 1492 | 1511 | } |
| 1493 | 1512 | |
| 1494 | 1513 | pub fn asFile(self: *ZigObject) File { |
| ... | ... | @@ -1766,169 +1785,17 @@ const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata); |
| 1766 | 1785 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); |
| 1767 | 1786 | const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable); |
| 1768 | 1787 | |
| 1769 | | pub const JumpTable = struct { |
| 1770 | | sym_index: Symbol.Index, |
| 1771 | | entries: std.MultiArrayList(Entry) = .{}, |
| 1772 | | dirty: bool = false, |
| 1773 | | |
| 1774 | | pub fn deinit(jt: *JumpTable, allocator: Allocator) void { |
| 1775 | | jt.entries.deinit(allocator); |
| 1776 | | } |
| 1777 | | |
| 1778 | | pub fn addSymbol(jt: *JumpTable, allocator: Allocator, sym_index: Symbol.Index) !Index { |
| 1779 | | const index: Index = @intCast(try jt.entries.addOne(allocator)); |
| 1780 | | jt.entries.set(index, .{ .sym_index = sym_index }); |
| 1781 | | return index; |
| 1782 | | } |
| 1783 | | |
| 1784 | | pub fn address(jt: JumpTable, zo: *ZigObject, elf_file: *Elf) i64 { |
| 1785 | | const sym = zo.symbol(jt.sym_index); |
| 1786 | | return sym.address(.{}, elf_file); |
| 1787 | | } |
| 1788 | | |
| 1789 | | pub fn size(jt: JumpTable, zo: *ZigObject, elf_file: *Elf) u64 { |
| 1790 | | const sym = zo.symbol(jt.sym_index); |
| 1791 | | return sym.atom(elf_file).?.size; |
| 1792 | | } |
| 1793 | | |
| 1794 | | pub fn alignment(cpu_arch: std.Target.Cpu.Arch) u64 { |
| 1795 | | return switch (cpu_arch) { |
| 1796 | | .x86_64 => 1, |
| 1797 | | else => @panic("TODO implement alignment for this CPU arch"), |
| 1798 | | }; |
| 1799 | | } |
| 1800 | | |
| 1801 | | pub fn entryAddress(jt: JumpTable, index: Index, zo: *ZigObject, elf_file: *Elf) i64 { |
| 1802 | | return jt.address(zo, elf_file) + @as(i64, @intCast(index * entrySize(elf_file.getTarget().cpu.arch))); |
| 1803 | | } |
| 1804 | | |
| 1805 | | pub fn entryOffset(jt: JumpTable, index: Index, zo: *ZigObject, elf_file: *Elf) u64 { |
| 1806 | | const sym = zo.symbol(jt.sym_index); |
| 1807 | | const atom_ptr = sym.atom(elf_file).?; |
| 1808 | | const shdr = elf_file.shdrs.items[atom_ptr.output_section_index]; |
| 1809 | | return shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)) + index * entrySize(elf_file.getTarget().cpu.arch); |
| 1810 | | } |
| 1811 | | |
| 1812 | | pub fn entrySize(cpu_arch: std.Target.Cpu.Arch) u64 { |
| 1813 | | const seq_len = switch (cpu_arch) { |
| 1814 | | .x86_64 => 5, // jmp rel32 |
| 1815 | | else => @panic("TODO implement entry size for this CPU arch"), |
| 1788 | const x86_64 = struct { |
| 1789 | fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 { |
| 1790 | const disp = @as(i64, @intCast(target_addr)) - source_addr - 5; |
| 1791 | var bytes = [_]u8{ |
| 1792 | 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32 |
| 1816 | 1793 | }; |
| 1817 | | comptime assert(seq_len <= max_jump_seq_len); |
| 1818 | | return seq_len; |
| 1794 | assert(bytes.len == trampolineSize(.x86_64)); |
| 1795 | mem.writeInt(i32, bytes[1..][0..4], @intCast(disp), .little); |
| 1796 | @memcpy(buf[0..bytes.len], &bytes); |
| 1797 | return buf[0..bytes.len]; |
| 1819 | 1798 | } |
| 1820 | | |
| 1821 | | pub fn targetAddress(jt: JumpTable, index: Index, zo: *ZigObject, elf_file: *Elf) i64 { |
| 1822 | | const sym_index = jt.entries.items(.sym_index)[index]; |
| 1823 | | return zo.symbol(sym_index).address(.{}, elf_file); |
| 1824 | | } |
| 1825 | | |
| 1826 | | const max_jump_seq_len = 12; |
| 1827 | | |
| 1828 | | pub fn writeEntry(jt: JumpTable, index: Index, zo: *ZigObject, elf_file: *Elf) !void { |
| 1829 | | const fileoff = jt.entryOffset(index, zo, elf_file); |
| 1830 | | const source_addr = jt.entryAddress(index, zo, elf_file); |
| 1831 | | const target_addr = @as(i64, @intCast(jt.targetAddress(index, zo, elf_file))); |
| 1832 | | var buf: [max_jump_seq_len]u8 = undefined; |
| 1833 | | const out = switch (elf_file.getTarget().cpu.arch) { |
| 1834 | | .x86_64 => try x86_64.writeEntry(source_addr, target_addr, &buf), |
| 1835 | | else => @panic("TODO implement write entry for this CPU arch"), |
| 1836 | | }; |
| 1837 | | try elf_file.base.file.?.pwriteAll(out, fileoff); |
| 1838 | | |
| 1839 | | if (elf_file.base.child_pid) |pid| { |
| 1840 | | switch (builtin.os.tag) { |
| 1841 | | .linux => { |
| 1842 | | var local_vec: [1]std.posix.iovec_const = .{.{ |
| 1843 | | .base = out.ptr, |
| 1844 | | .len = out.len, |
| 1845 | | }}; |
| 1846 | | var remote_vec: [1]std.posix.iovec_const = .{.{ |
| 1847 | | .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(source_addr)))), |
| 1848 | | .len = out.len, |
| 1849 | | }}; |
| 1850 | | const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0); |
| 1851 | | switch (std.os.linux.E.init(rc)) { |
| 1852 | | .SUCCESS => assert(rc == out.len), |
| 1853 | | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), |
| 1854 | | } |
| 1855 | | }, |
| 1856 | | else => return error.HotSwapUnavailableOnHostOperatingSystem, |
| 1857 | | } |
| 1858 | | } |
| 1859 | | } |
| 1860 | | |
| 1861 | | pub fn updateSize(jt: JumpTable, zo: *ZigObject, elf_file: *Elf) !void { |
| 1862 | | const jt_size: u64 = @intCast(jt.entries.items(.sym_index).len * entrySize(elf_file.getTarget().cpu.arch)); |
| 1863 | | const sym = zo.symbol(jt.sym_index); |
| 1864 | | const esym = &zo.symtab.items(.elf_sym)[sym.esym_index]; |
| 1865 | | esym.st_size = jt_size; |
| 1866 | | const atom_ptr = sym.atom(elf_file).?; |
| 1867 | | atom_ptr.size = jt_size; |
| 1868 | | } |
| 1869 | | |
| 1870 | | const JumpTableFormatContext = struct { JumpTable, *ZigObject, *Elf }; |
| 1871 | | |
| 1872 | | pub fn format( |
| 1873 | | jt: JumpTable, |
| 1874 | | comptime unused_fmt_string: []const u8, |
| 1875 | | options: std.fmt.FormatOptions, |
| 1876 | | writer: anytype, |
| 1877 | | ) !void { |
| 1878 | | _ = jt; |
| 1879 | | _ = unused_fmt_string; |
| 1880 | | _ = options; |
| 1881 | | _ = writer; |
| 1882 | | @compileError("do not format JumpTable directly"); |
| 1883 | | } |
| 1884 | | |
| 1885 | | pub fn fmt(jt: JumpTable, zo: *ZigObject, elf_file: *Elf) std.fmt.Formatter(format2) { |
| 1886 | | return .{ .data = .{ jt, zo, elf_file } }; |
| 1887 | | } |
| 1888 | | |
| 1889 | | fn format2( |
| 1890 | | ctx: JumpTableFormatContext, |
| 1891 | | comptime unused_fmt_string: []const u8, |
| 1892 | | options: std.fmt.FormatOptions, |
| 1893 | | writer: anytype, |
| 1894 | | ) !void { |
| 1895 | | _ = options; |
| 1896 | | _ = unused_fmt_string; |
| 1897 | | const jt, const zo, const ef = ctx; |
| 1898 | | try writer.writeAll("__zig_jump_table\n"); |
| 1899 | | try writer.print(" @{x} : size({x})\n", .{ jt.address(zo, ef), jt.size(zo, ef) }); |
| 1900 | | for (jt.entries.items(.sym_index), jt.entries.items(.dirty)) |sym_index, dirty| { |
| 1901 | | const sym = zo.symbol(sym_index); |
| 1902 | | try writer.print(" {x} => {x} : %{d} : {s}", .{ |
| 1903 | | sym.address(.{ .zjt = true }, ef), |
| 1904 | | sym.address(.{}, ef), |
| 1905 | | sym_index, |
| 1906 | | sym.name(ef), |
| 1907 | | }); |
| 1908 | | if (dirty) try writer.writeAll(" : [!]"); |
| 1909 | | try writer.writeByte('\n'); |
| 1910 | | } |
| 1911 | | } |
| 1912 | | |
| 1913 | | const Entry = struct { |
| 1914 | | sym_index: Symbol.Index, |
| 1915 | | dirty: bool = true, |
| 1916 | | }; |
| 1917 | | |
| 1918 | | pub const Index = u32; |
| 1919 | | |
| 1920 | | const x86_64 = struct { |
| 1921 | | fn writeEntry(source_addr: i64, target_addr: i64, buf: *[max_jump_seq_len]u8) ![]u8 { |
| 1922 | | const disp = @as(i64, @intCast(target_addr)) - source_addr - 5; |
| 1923 | | var bytes = [_]u8{ |
| 1924 | | 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32 |
| 1925 | | }; |
| 1926 | | assert(bytes.len == entrySize(.x86_64)); |
| 1927 | | mem.writeInt(i32, bytes[1..][0..4], @intCast(disp), .little); |
| 1928 | | @memcpy(buf[0..bytes.len], &bytes); |
| 1929 | | return buf[0..bytes.len]; |
| 1930 | | } |
| 1931 | | }; |
| 1932 | 1799 | }; |
| 1933 | 1800 | |
| 1934 | 1801 | const assert = std.debug.assert; |