aboutsummaryrefslogtreecommitdiff
path: root/src/link/MachO/thunks.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-08-27 09:55:24 +0200
committerJakub Konka <kubkon@jakubkonka.com>2023-08-29 11:40:18 +0200
commit2c68fb3d7ce077fba711747ee7b05b2fa0df6bcc (patch)
tree291b3aec840358c08a36c78c468c54fdc34727f0 /src/link/MachO/thunks.zig
parent42e0850d78e63fcc602dd0e167ac90dfb3cfec02 (diff)
downloadzig-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.zig169
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;