diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-08-27 09:55:24 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-08-29 11:40:18 +0200 |
| commit | 2c68fb3d7ce077fba711747ee7b05b2fa0df6bcc (patch) | |
| tree | 291b3aec840358c08a36c78c468c54fdc34727f0 /src/link/MachO/thunks.zig | |
| parent | 42e0850d78e63fcc602dd0e167ac90dfb3cfec02 (diff) | |
| download | zig-2c68fb3d7ce077fba711747ee7b05b2fa0df6bcc.tar.gz zig-2c68fb3d7ce077fba711747ee7b05b2fa0df6bcc.zip | |
macho: merge Zld state with MachO state
Diffstat (limited to 'src/link/MachO/thunks.zig')
| -rw-r--r-- | src/link/MachO/thunks.zig | 169 |
1 files changed, 84 insertions, 85 deletions
diff --git a/src/link/MachO/thunks.zig b/src/link/MachO/thunks.zig index c5debcc1fa..726fbdf2a6 100644 --- a/src/link/MachO/thunks.zig +++ b/src/link/MachO/thunks.zig @@ -5,22 +5,6 @@ //! The algorithm works pessimistically and assumes that any reference to an Atom in //! another output section is out of range. -const std = @import("std"); -const assert = std.debug.assert; -const log = std.log.scoped(.thunks); -const macho = std.macho; -const math = std.math; -const mem = std.mem; - -const aarch64 = @import("../../arch/aarch64/bits.zig"); - -const Allocator = mem.Allocator; -const Atom = @import("Atom.zig"); -const MachO = @import("../MachO.zig"); -const Relocation = @import("Relocation.zig"); -const SymbolWithLoc = MachO.SymbolWithLoc; -const Zld = @import("zld.zig").Zld; - /// Branch instruction has 26 bits immediate but 4 byte aligned. const jump_bits = @bitSizeOf(i28); @@ -74,18 +58,18 @@ pub const Thunk = struct { return @alignOf(u32); } - pub fn getTrampoline(self: Thunk, zld: *Zld, tag: Tag, target: SymbolWithLoc) ?SymbolWithLoc { + pub fn getTrampoline(self: Thunk, macho_file: *MachO, tag: Tag, target: SymbolWithLoc) ?SymbolWithLoc { const atom_index = self.lookup.get(.{ .tag = tag, .target = target }) orelse return null; - return zld.getAtom(atom_index).getSymbolWithLoc(); + return macho_file.getAtom(atom_index).getSymbolWithLoc(); } }; -pub fn createThunks(zld: *Zld, sect_id: u8) !void { - const header = &zld.sections.items(.header)[sect_id]; +pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { + const header = &macho_file.sections.items(.header)[sect_id]; if (header.size == 0) return; - const gpa = zld.gpa; - const first_atom_index = zld.sections.items(.first_atom_index)[sect_id].?; + const gpa = macho_file.base.allocator; + const first_atom_index = macho_file.sections.items(.first_atom_index)[sect_id].?; header.size = 0; header.@"align" = 0; @@ -95,8 +79,8 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void { { var atom_index = first_atom_index; while (true) { - const atom = zld.getAtom(atom_index); - const sym = zld.getSymbolPtr(atom.getSymbolWithLoc()); + const atom = macho_file.getAtom(atom_index); + const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); sym.n_value = 0; atom_count += 1; @@ -115,24 +99,24 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void { var offset: u64 = 0; while (true) { - const group_start_atom = zld.getAtom(group_start); + const group_start_atom = macho_file.getAtom(group_start); log.debug("GROUP START at {d}", .{group_start}); while (true) { - const atom = zld.getAtom(group_end); + const atom = macho_file.getAtom(group_end); offset = mem.alignForward(u64, offset, try math.powi(u32, 2, atom.alignment)); - const sym = zld.getSymbolPtr(atom.getSymbolWithLoc()); + const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); sym.n_value = offset; offset += atom.size; - zld.logAtom(group_end, log); + macho_file.logAtom(group_end, log); header.@"align" = @max(header.@"align", atom.alignment); allocated.putAssumeCapacityNoClobber(group_end, {}); - const group_start_sym = zld.getSymbol(group_start_atom.getSymbolWithLoc()); + const group_start_sym = macho_file.getSymbol(group_start_atom.getSymbolWithLoc()); if (offset - group_start_sym.n_value >= max_allowed_distance) break; if (atom.next_index) |next_index| { @@ -142,15 +126,15 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void { log.debug("GROUP END at {d}", .{group_end}); // Insert thunk at group_end - const thunk_index = @as(u32, @intCast(zld.thunks.items.len)); - try zld.thunks.append(gpa, .{ .start_index = undefined, .len = 0 }); + const thunk_index = @as(u32, @intCast(macho_file.thunks.items.len)); + try macho_file.thunks.append(gpa, .{ .start_index = undefined, .len = 0 }); // Scan relocs in the group and create trampolines for any unreachable callsite. var atom_index = group_start; while (true) { - const atom = zld.getAtom(atom_index); + const atom = macho_file.getAtom(atom_index); try scanRelocs( - zld, + macho_file, atom_index, allocated, thunk_index, @@ -165,19 +149,19 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void { } offset = mem.alignForward(u64, offset, Thunk.getAlignment()); - allocateThunk(zld, thunk_index, offset, header); - offset += zld.thunks.items[thunk_index].getSize(); + allocateThunk(macho_file, thunk_index, offset, header); + offset += macho_file.thunks.items[thunk_index].getSize(); - const thunk = zld.thunks.items[thunk_index]; + const thunk = macho_file.thunks.items[thunk_index]; if (thunk.len == 0) { - const group_end_atom = zld.getAtom(group_end); + const group_end_atom = macho_file.getAtom(group_end); if (group_end_atom.next_index) |next_index| { group_start = next_index; group_end = next_index; } else break; } else { const thunk_end_atom_index = thunk.getEndAtomIndex(); - const thunk_end_atom = zld.getAtom(thunk_end_atom_index); + const thunk_end_atom = macho_file.getAtom(thunk_end_atom_index); if (thunk_end_atom.next_index) |next_index| { group_start = next_index; group_end = next_index; @@ -189,12 +173,12 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void { } fn allocateThunk( - zld: *Zld, + macho_file: *MachO, thunk_index: Thunk.Index, base_offset: u64, header: *macho.section_64, ) void { - const thunk = zld.thunks.items[thunk_index]; + const thunk = macho_file.thunks.items[thunk_index]; if (thunk.len == 0) return; const first_atom_index = thunk.getStartAtomIndex(); @@ -203,14 +187,14 @@ fn allocateThunk( var atom_index = first_atom_index; var offset = base_offset; while (true) { - const atom = zld.getAtom(atom_index); + const atom = macho_file.getAtom(atom_index); offset = mem.alignForward(u64, offset, Thunk.getAlignment()); - const sym = zld.getSymbolPtr(atom.getSymbolWithLoc()); + const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); sym.n_value = offset; offset += atom.size; - zld.logAtom(atom_index, log); + macho_file.logAtom(atom_index, log); header.@"align" = @max(header.@"align", atom.alignment); @@ -223,69 +207,69 @@ fn allocateThunk( } fn scanRelocs( - zld: *Zld, + macho_file: *MachO, atom_index: Atom.Index, allocated: std.AutoHashMap(Atom.Index, void), thunk_index: Thunk.Index, group_end: Atom.Index, ) !void { - const atom = zld.getAtom(atom_index); - const object = zld.objects.items[atom.getFile().?]; + const atom = macho_file.getAtom(atom_index); + const object = macho_file.objects.items[atom.getFile().?]; const base_offset = if (object.getSourceSymbol(atom.sym_index)) |source_sym| blk: { const source_sect = object.getSourceSection(source_sym.n_sect - 1); break :blk @as(i32, @intCast(source_sym.n_value - source_sect.addr)); } else 0; - const code = Atom.getAtomCode(zld, atom_index); - const relocs = Atom.getAtomRelocs(zld, atom_index); - const ctx = Atom.getRelocContext(zld, atom_index); + const code = Atom.getAtomCode(macho_file, atom_index); + const relocs = Atom.getAtomRelocs(macho_file, atom_index); + const ctx = Atom.getRelocContext(macho_file, atom_index); for (relocs) |rel| { if (!relocNeedsThunk(rel)) continue; - const target = Atom.parseRelocTarget(zld, .{ + const target = Atom.parseRelocTarget(macho_file, .{ .object_id = atom.getFile().?, .rel = rel, .code = code, .base_offset = ctx.base_offset, .base_addr = ctx.base_addr, }); - if (isReachable(zld, atom_index, rel, base_offset, target, allocated)) continue; + if (isReachable(macho_file, atom_index, rel, base_offset, target, allocated)) continue; log.debug("{x}: source = {s}@{x}, target = {s}@{x} unreachable", .{ rel.r_address - base_offset, - zld.getSymbolName(atom.getSymbolWithLoc()), - zld.getSymbol(atom.getSymbolWithLoc()).n_value, - zld.getSymbolName(target), - zld.getSymbol(target).n_value, + macho_file.getSymbolName(atom.getSymbolWithLoc()), + macho_file.getSymbol(atom.getSymbolWithLoc()).n_value, + macho_file.getSymbolName(target), + macho_file.getSymbol(target).n_value, }); - const gpa = zld.gpa; - const target_sym = zld.getSymbol(target); - const thunk = &zld.thunks.items[thunk_index]; + const gpa = macho_file.base.allocator; + const target_sym = macho_file.getSymbol(target); + const thunk = &macho_file.thunks.items[thunk_index]; const tag: Thunk.Tag = if (target_sym.undf()) .stub else .atom; const thunk_target: Thunk.Target = .{ .tag = tag, .target = target }; const gop = try thunk.lookup.getOrPut(gpa, thunk_target); if (!gop.found_existing) { - gop.value_ptr.* = try pushThunkAtom(zld, thunk, group_end); + gop.value_ptr.* = try pushThunkAtom(macho_file, thunk, group_end); try thunk.targets.append(gpa, thunk_target); } - try zld.thunk_table.put(gpa, atom_index, thunk_index); + try macho_file.thunk_table.put(gpa, atom_index, thunk_index); } } -fn pushThunkAtom(zld: *Zld, thunk: *Thunk, group_end: Atom.Index) !Atom.Index { - const thunk_atom_index = try createThunkAtom(zld); +fn pushThunkAtom(macho_file: *MachO, thunk: *Thunk, group_end: Atom.Index) !Atom.Index { + const thunk_atom_index = try createThunkAtom(macho_file); - const thunk_atom = zld.getAtomPtr(thunk_atom_index); + const thunk_atom = macho_file.getAtomPtr(thunk_atom_index); const end_atom_index = if (thunk.len == 0) group_end else thunk.getEndAtomIndex(); - const end_atom = zld.getAtomPtr(end_atom_index); + const end_atom = macho_file.getAtomPtr(end_atom_index); if (end_atom.next_index) |first_after_index| { - const first_after_atom = zld.getAtomPtr(first_after_index); + const first_after_atom = macho_file.getAtomPtr(first_after_index); first_after_atom.prev_index = thunk_atom_index; thunk_atom.next_index = first_after_index; } @@ -308,58 +292,58 @@ inline fn relocNeedsThunk(rel: macho.relocation_info) bool { } fn isReachable( - zld: *Zld, + macho_file: *MachO, atom_index: Atom.Index, rel: macho.relocation_info, base_offset: i32, target: SymbolWithLoc, allocated: std.AutoHashMap(Atom.Index, void), ) bool { - if (zld.stubs_table.lookup.contains(target)) return false; + if (macho_file.stub_table.lookup.contains(target)) return false; - const source_atom = zld.getAtom(atom_index); - const source_sym = zld.getSymbol(source_atom.getSymbolWithLoc()); + const source_atom = macho_file.getAtom(atom_index); + const source_sym = macho_file.getSymbol(source_atom.getSymbolWithLoc()); - const target_object = zld.objects.items[target.getFile().?]; + const target_object = macho_file.objects.items[target.getFile().?]; const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?; - const target_atom = zld.getAtom(target_atom_index); - const target_sym = zld.getSymbol(target_atom.getSymbolWithLoc()); + const target_atom = macho_file.getAtom(target_atom_index); + const target_sym = macho_file.getSymbol(target_atom.getSymbolWithLoc()); if (source_sym.n_sect != target_sym.n_sect) return false; if (!allocated.contains(target_atom_index)) return false; const source_addr = source_sym.n_value + @as(u32, @intCast(rel.r_address - base_offset)); - const target_addr = if (Atom.relocRequiresGot(zld, rel)) - zld.getGotEntryAddress(target).? + const target_addr = if (Atom.relocRequiresGot(macho_file, rel)) + macho_file.getGotEntryAddress(target).? else - Atom.getRelocTargetAddress(zld, target, false) catch unreachable; + Atom.getRelocTargetAddress(macho_file, target, false) catch unreachable; _ = Relocation.calcPcRelativeDisplacementArm64(source_addr, target_addr) catch return false; return true; } -fn createThunkAtom(zld: *Zld) !Atom.Index { - const sym_index = try zld.allocateSymbol(); - const atom_index = try zld.createAtom(sym_index, .{ .size = @sizeOf(u32) * 3, .alignment = 2 }); - const sym = zld.getSymbolPtr(.{ .sym_index = sym_index }); +fn createThunkAtom(macho_file: *MachO) !Atom.Index { + const sym_index = try macho_file.allocateSymbol(); + const atom_index = try macho_file.createAtom(sym_index, .{ .size = @sizeOf(u32) * 3, .alignment = 2 }); + const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index }); sym.n_type = macho.N_SECT; - sym.n_sect = zld.text_section_index.? + 1; + sym.n_sect = macho_file.text_section_index.? + 1; return atom_index; } -pub fn writeThunkCode(zld: *Zld, thunk: *const Thunk, writer: anytype) !void { +pub fn writeThunkCode(macho_file: *MachO, thunk: *const Thunk, writer: anytype) !void { const slice = thunk.targets.slice(); for (thunk.getStartAtomIndex()..thunk.getEndAtomIndex(), 0..) |atom_index, target_index| { - const atom = zld.getAtom(@intCast(atom_index)); - const sym = zld.getSymbol(atom.getSymbolWithLoc()); + const atom = macho_file.getAtom(@intCast(atom_index)); + const sym = macho_file.getSymbol(atom.getSymbolWithLoc()); const source_addr = sym.n_value; const tag = slice.items(.tag)[target_index]; const target = slice.items(.target)[target_index]; const target_addr = switch (tag) { - .stub => zld.getStubsEntryAddress(target).?, - .atom => zld.getSymbol(target).n_value, + .stub => macho_file.getStubsEntryAddress(target).?, + .atom => macho_file.getSymbol(target).n_value, }; const pages = Relocation.calcNumberOfPages(source_addr, target_addr); try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32()); @@ -368,3 +352,18 @@ pub fn writeThunkCode(zld: *Zld, thunk: *const Thunk, writer: anytype) !void { try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32()); } } + +const std = @import("std"); +const assert = std.debug.assert; +const log = std.log.scoped(.thunks); +const macho = std.macho; +const math = std.math; +const mem = std.mem; + +const aarch64 = @import("../../arch/aarch64/bits.zig"); + +const Allocator = mem.Allocator; +const Atom = @import("Atom.zig"); +const MachO = @import("../MachO.zig"); +const Relocation = @import("Relocation.zig"); +const SymbolWithLoc = MachO.SymbolWithLoc; |
