| ... | @@ -5,55 +5,45 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void { | ... | @@ -5,55 +5,45 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void { |
| 5 | const gpa = macho_file.base.comp.gpa; | 5 | const gpa = macho_file.base.comp.gpa; |
| 6 | const slice = macho_file.sections.slice(); | 6 | const slice = macho_file.sections.slice(); |
| 7 | const header = &slice.items(.header)[sect_id]; | 7 | const header = &slice.items(.header)[sect_id]; |
| | 8 | const thnks = &slice.items(.thunks)[sect_id]; |
| 8 | const atoms = slice.items(.atoms)[sect_id].items; | 9 | const atoms = slice.items(.atoms)[sect_id].items; |
| 9 | assert(atoms.len > 0); | 10 | assert(atoms.len > 0); |
| 10 | | 11 | |
| 11 | for (atoms) |atom_index| { | 12 | for (atoms) |ref| { |
| 12 | macho_file.getAtom(atom_index).?.value = @bitCast(@as(i64, -1)); | 13 | ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1)); |
| 13 | } | 14 | } |
| 14 | | 15 | |
| 15 | var i: usize = 0; | 16 | var i: usize = 0; |
| 16 | while (i < atoms.len) { | 17 | while (i < atoms.len) { |
| 17 | const start = i; | 18 | const start = i; |
| 18 | const start_atom = macho_file.getAtom(atoms[start]).?; | 19 | const start_atom = atoms[start].getAtom(macho_file).?; |
| 19 | assert(start_atom.flags.alive); | 20 | assert(start_atom.flags.alive); |
| 20 | start_atom.value = try advance(header, start_atom.size, start_atom.alignment); | 21 | start_atom.value = advance(header, start_atom.size, start_atom.alignment); |
| 21 | i += 1; | 22 | i += 1; |
| 22 | | 23 | |
| 23 | while (i < atoms.len and | 24 | while (i < atoms.len and |
| 24 | header.size - start_atom.value < max_allowed_distance) : (i += 1) | 25 | header.size - start_atom.value < max_allowed_distance) : (i += 1) |
| 25 | { | 26 | { |
| 26 | const atom_index = atoms[i]; | 27 | const atom = atoms[i].getAtom(macho_file).?; |
| 27 | const atom = macho_file.getAtom(atom_index).?; | | |
| 28 | assert(atom.flags.alive); | 28 | assert(atom.flags.alive); |
| 29 | atom.value = try advance(header, atom.size, atom.alignment); | 29 | atom.value = advance(header, atom.size, atom.alignment); |
| 30 | } | 30 | } |
| 31 | | 31 | |
| 32 | // Insert a thunk at the group end | 32 | // Insert a thunk at the group end |
| 33 | const thunk_index = try macho_file.addThunk(); | 33 | const thunk_index = try macho_file.addThunk(); |
| 34 | const thunk = macho_file.getThunk(thunk_index); | 34 | const thunk = macho_file.getThunk(thunk_index); |
| 35 | thunk.out_n_sect = sect_id; | 35 | thunk.out_n_sect = sect_id; |
| | 36 | try thnks.append(gpa, thunk_index); |
| 36 | | 37 | |
| 37 | // Scan relocs in the group and create trampolines for any unreachable callsite | 38 | // Scan relocs in the group and create trampolines for any unreachable callsite |
| 38 | for (atoms[start..i]) |atom_index| { | 39 | try scanRelocs(thunk_index, gpa, atoms[start..i], macho_file); |
| 39 | const atom = macho_file.getAtom(atom_index).?; | | |
| 40 | log.debug("atom({d}) {s}", .{ atom_index, atom.getName(macho_file) }); | | |
| 41 | for (atom.getRelocs(macho_file)) |rel| { | | |
| 42 | if (rel.type != .branch) continue; | | |
| 43 | if (isReachable(atom, rel, macho_file)) continue; | | |
| 44 | try thunk.symbols.put(gpa, rel.target, {}); | | |
| 45 | } | | |
| 46 | try atom.addExtra(.{ .thunk = thunk_index }, macho_file); | | |
| 47 | atom.flags.thunk = true; | | |
| 48 | } | | |
| 49 | | | |
| 50 | thunk.value = try advance(header, thunk.size(), .@"4"); | 40 | thunk.value = try advance(header, thunk.size(), .@"4"); |
| 51 | | 41 | |
| 52 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) }); | 42 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) }); |
| 53 | } | 43 | } |
| 54 | } | 44 | } |
| 55 | | 45 | |
| 56 | fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 { | 46 | fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) u64 { |
| 57 | const offset = alignment.forward(sect.size); | 47 | const offset = alignment.forward(sect.size); |
| 58 | const padding = offset - sect.size; | 48 | const padding = offset - sect.size; |
| 59 | sect.size += padding + size; | 49 | sect.size += padding + size; |
| ... | @@ -61,14 +51,32 @@ fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 { | ... | @@ -61,14 +51,32 @@ fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 { |
| 61 | return offset; | 51 | return offset; |
| 62 | } | 52 | } |
| 63 | | 53 | |
| | 54 | fn scanRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref, macho_file: *MachO) !void { |
| | 55 | const tracy = trace(@src()); |
| | 56 | defer tracy.end(); |
| | 57 | |
| | 58 | const thunk = macho_file.getThunk(thunk_index); |
| | 59 | |
| | 60 | for (atoms) |ref| { |
| | 61 | const atom = ref.getAtom(macho_file).?; |
| | 62 | log.debug("atom({d}) {s}", .{ atom.atom_index, atom.getName(macho_file) }); |
| | 63 | for (atom.getRelocs(macho_file)) |rel| { |
| | 64 | if (rel.type != .branch) continue; |
| | 65 | if (isReachable(atom, rel, macho_file)) continue; |
| | 66 | try thunk.symbols.put(gpa, rel.getTargetSymbolRef(atom.*, macho_file), {}); |
| | 67 | } |
| | 68 | atom.addExtra(.{ .thunk = thunk_index }, macho_file); |
| | 69 | } |
| | 70 | } |
| | 71 | |
| 64 | fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { | 72 | fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { |
| 65 | const target = rel.getTargetSymbol(macho_file); | 73 | const target = rel.getTargetSymbol(atom.*, macho_file); |
| 66 | if (target.flags.stubs or target.flags.objc_stubs) return false; | 74 | if (target.flags.stubs or target.flags.objc_stubs) return false; |
| 67 | if (atom.out_n_sect != target.out_n_sect) return false; | 75 | if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false; |
| 68 | const target_atom = target.getAtom(macho_file).?; | 76 | const target_atom = target.getAtom(macho_file).?; |
| 69 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; | 77 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; |
| 70 | const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off)); | 78 | const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off)); |
| 71 | const taddr: i64 = @intCast(rel.getTargetAddress(macho_file)); | 79 | const taddr: i64 = @intCast(rel.getTargetAddress(atom.*, macho_file)); |
| 72 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; | 80 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; |
| 73 | return true; | 81 | return true; |
| 74 | } | 82 | } |
| ... | @@ -76,7 +84,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { | ... | @@ -76,7 +84,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { |
| 76 | pub const Thunk = struct { | 84 | pub const Thunk = struct { |
| 77 | value: u64 = 0, | 85 | value: u64 = 0, |
| 78 | out_n_sect: u8 = 0, | 86 | out_n_sect: u8 = 0, |
| 79 | symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, | 87 | symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{}, |
| 80 | | 88 | |
| 81 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { | 89 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { |
| 82 | thunk.symbols.deinit(allocator); | 90 | thunk.symbols.deinit(allocator); |
| ... | @@ -96,8 +104,8 @@ pub const Thunk = struct { | ... | @@ -96,8 +104,8 @@ pub const Thunk = struct { |
| 96 | } | 104 | } |
| 97 | | 105 | |
| 98 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { | 106 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { |
| 99 | for (thunk.symbols.keys(), 0..) |sym_index, i| { | 107 | for (thunk.symbols.keys(), 0..) |ref, i| { |
| 100 | const sym = macho_file.getSymbol(sym_index); | 108 | const sym = ref.getSymbol(macho_file).?; |
| 101 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; | 109 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; |
| 102 | const taddr = sym.getAddress(.{}, macho_file); | 110 | const taddr = sym.getAddress(.{}, macho_file); |
| 103 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); | 111 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); |
| ... | @@ -144,9 +152,9 @@ pub const Thunk = struct { | ... | @@ -144,9 +152,9 @@ pub const Thunk = struct { |
| 144 | const thunk = ctx.thunk; | 152 | const thunk = ctx.thunk; |
| 145 | const macho_file = ctx.macho_file; | 153 | const macho_file = ctx.macho_file; |
| 146 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); | 154 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); |
| 147 | for (thunk.symbols.keys()) |index| { | 155 | for (thunk.symbols.keys()) |ref| { |
| 148 | const sym = macho_file.getSymbol(index); | 156 | const sym = ref.getSymbol(macho_file).?; |
| 149 | try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.getName(macho_file), sym.value }); | 157 | try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value }); |
| 150 | } | 158 | } |
| 151 | } | 159 | } |
| 152 | | 160 | |