mirror of
https://github.com/ziglang/zig.git
synced 2026-02-19 07:48:31 +00:00
macho: migrate Relocation struct
This commit is contained in:
parent
58997363d3
commit
b96339f6f6
@ -1,4 +1,4 @@
|
||||
tag: enum { @"extern", local },
|
||||
tag: Tag,
|
||||
offset: u32,
|
||||
target: u32,
|
||||
addend: i64,
|
||||
@ -10,34 +10,44 @@ meta: packed struct {
|
||||
symbolnum: u24,
|
||||
},
|
||||
|
||||
pub fn getTargetSymbol(rel: Relocation, macho_file: *MachO) *Symbol {
|
||||
pub fn getTargetSymbolRef(rel: Relocation, atom: Atom, macho_file: *MachO) MachO.Ref {
|
||||
assert(rel.tag == .@"extern");
|
||||
return macho_file.getSymbol(rel.target);
|
||||
return atom.getFile(macho_file).getSymbolRef(rel.target, macho_file);
|
||||
}
|
||||
|
||||
pub fn getTargetAtom(rel: Relocation, macho_file: *MachO) *Atom {
|
||||
pub fn getTargetSymbol(rel: Relocation, atom: Atom, macho_file: *MachO) *Symbol {
|
||||
assert(rel.tag == .@"extern");
|
||||
const ref = atom.getFile(macho_file).getSymbolRef(rel.target, macho_file);
|
||||
return ref.getSymbol(macho_file).?;
|
||||
}
|
||||
|
||||
pub fn getTargetAtom(rel: Relocation, atom: Atom, macho_file: *MachO) *Atom {
|
||||
assert(rel.tag == .local);
|
||||
return macho_file.getAtom(rel.target).?;
|
||||
return atom.getFile(macho_file).getAtom(rel.target).?;
|
||||
}
|
||||
|
||||
pub fn getTargetAddress(rel: Relocation, macho_file: *MachO) u64 {
|
||||
pub fn getTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 {
|
||||
return switch (rel.tag) {
|
||||
.local => rel.getTargetAtom(macho_file).getAddress(macho_file),
|
||||
.@"extern" => rel.getTargetSymbol(macho_file).getAddress(.{}, macho_file),
|
||||
.local => rel.getTargetAtom(atom, macho_file).getAddress(macho_file),
|
||||
.@"extern" => rel.getTargetSymbol(atom, macho_file).getAddress(.{}, macho_file),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 {
|
||||
pub fn getGotTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 {
|
||||
return switch (rel.tag) {
|
||||
.local => 0,
|
||||
.@"extern" => rel.getTargetSymbol(macho_file).getGotAddress(macho_file),
|
||||
.@"extern" => rel.getTargetSymbol(atom, macho_file).getGotAddress(macho_file),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getZigGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 {
|
||||
const zo = macho_file.getZigObject().?;
|
||||
return switch (rel.tag) {
|
||||
.local => 0,
|
||||
.@"extern" => rel.getTargetSymbol(macho_file).getZigGotAddress(macho_file),
|
||||
.@"extern" => {
|
||||
const ref = zo.getSymbolRef(rel.target, macho_file);
|
||||
return ref.getSymbol(macho_file).?.getZigGotAddress(macho_file);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -155,6 +165,8 @@ pub const Type = enum {
|
||||
unsigned,
|
||||
};
|
||||
|
||||
const Tag = enum { local, @"extern" };
|
||||
|
||||
const assert = std.debug.assert;
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
|
||||
@ -5,55 +5,45 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void {
|
||||
const gpa = macho_file.base.comp.gpa;
|
||||
const slice = macho_file.sections.slice();
|
||||
const header = &slice.items(.header)[sect_id];
|
||||
const thnks = &slice.items(.thunks)[sect_id];
|
||||
const atoms = slice.items(.atoms)[sect_id].items;
|
||||
assert(atoms.len > 0);
|
||||
|
||||
for (atoms) |atom_index| {
|
||||
macho_file.getAtom(atom_index).?.value = @bitCast(@as(i64, -1));
|
||||
for (atoms) |ref| {
|
||||
ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1));
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < atoms.len) {
|
||||
const start = i;
|
||||
const start_atom = macho_file.getAtom(atoms[start]).?;
|
||||
const start_atom = atoms[start].getAtom(macho_file).?;
|
||||
assert(start_atom.flags.alive);
|
||||
start_atom.value = try advance(header, start_atom.size, start_atom.alignment);
|
||||
start_atom.value = advance(header, start_atom.size, start_atom.alignment);
|
||||
i += 1;
|
||||
|
||||
while (i < atoms.len and
|
||||
header.size - start_atom.value < max_allowed_distance) : (i += 1)
|
||||
{
|
||||
const atom_index = atoms[i];
|
||||
const atom = macho_file.getAtom(atom_index).?;
|
||||
const atom = atoms[i].getAtom(macho_file).?;
|
||||
assert(atom.flags.alive);
|
||||
atom.value = try advance(header, atom.size, atom.alignment);
|
||||
atom.value = advance(header, atom.size, atom.alignment);
|
||||
}
|
||||
|
||||
// Insert a thunk at the group end
|
||||
const thunk_index = try macho_file.addThunk();
|
||||
const thunk = macho_file.getThunk(thunk_index);
|
||||
thunk.out_n_sect = sect_id;
|
||||
try thnks.append(gpa, thunk_index);
|
||||
|
||||
// Scan relocs in the group and create trampolines for any unreachable callsite
|
||||
for (atoms[start..i]) |atom_index| {
|
||||
const atom = macho_file.getAtom(atom_index).?;
|
||||
log.debug("atom({d}) {s}", .{ atom_index, atom.getName(macho_file) });
|
||||
for (atom.getRelocs(macho_file)) |rel| {
|
||||
if (rel.type != .branch) continue;
|
||||
if (isReachable(atom, rel, macho_file)) continue;
|
||||
try thunk.symbols.put(gpa, rel.target, {});
|
||||
}
|
||||
try atom.addExtra(.{ .thunk = thunk_index }, macho_file);
|
||||
atom.flags.thunk = true;
|
||||
}
|
||||
|
||||
try scanRelocs(thunk_index, gpa, atoms[start..i], macho_file);
|
||||
thunk.value = try advance(header, thunk.size(), .@"4");
|
||||
|
||||
log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) });
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 {
|
||||
fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) u64 {
|
||||
const offset = alignment.forward(sect.size);
|
||||
const padding = offset - sect.size;
|
||||
sect.size += padding + size;
|
||||
@ -61,14 +51,32 @@ fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 {
|
||||
return offset;
|
||||
}
|
||||
|
||||
fn scanRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref, macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const thunk = macho_file.getThunk(thunk_index);
|
||||
|
||||
for (atoms) |ref| {
|
||||
const atom = ref.getAtom(macho_file).?;
|
||||
log.debug("atom({d}) {s}", .{ atom.atom_index, atom.getName(macho_file) });
|
||||
for (atom.getRelocs(macho_file)) |rel| {
|
||||
if (rel.type != .branch) continue;
|
||||
if (isReachable(atom, rel, macho_file)) continue;
|
||||
try thunk.symbols.put(gpa, rel.getTargetSymbolRef(atom.*, macho_file), {});
|
||||
}
|
||||
atom.addExtra(.{ .thunk = thunk_index }, macho_file);
|
||||
}
|
||||
}
|
||||
|
||||
fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
|
||||
const target = rel.getTargetSymbol(macho_file);
|
||||
const target = rel.getTargetSymbol(atom.*, macho_file);
|
||||
if (target.flags.stubs or target.flags.objc_stubs) return false;
|
||||
if (atom.out_n_sect != target.out_n_sect) return false;
|
||||
if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false;
|
||||
const target_atom = target.getAtom(macho_file).?;
|
||||
if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false;
|
||||
const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off));
|
||||
const taddr: i64 = @intCast(rel.getTargetAddress(macho_file));
|
||||
const taddr: i64 = @intCast(rel.getTargetAddress(atom.*, macho_file));
|
||||
_ = math.cast(i28, taddr + rel.addend - saddr) orelse return false;
|
||||
return true;
|
||||
}
|
||||
@ -76,7 +84,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
|
||||
pub const Thunk = struct {
|
||||
value: u64 = 0,
|
||||
out_n_sect: u8 = 0,
|
||||
symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
|
||||
symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{},
|
||||
|
||||
pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
|
||||
thunk.symbols.deinit(allocator);
|
||||
@ -96,8 +104,8 @@ pub const Thunk = struct {
|
||||
}
|
||||
|
||||
pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
|
||||
for (thunk.symbols.keys(), 0..) |sym_index, i| {
|
||||
const sym = macho_file.getSymbol(sym_index);
|
||||
for (thunk.symbols.keys(), 0..) |ref, i| {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
|
||||
const taddr = sym.getAddress(.{}, macho_file);
|
||||
const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
|
||||
@ -144,9 +152,9 @@ pub const Thunk = struct {
|
||||
const thunk = ctx.thunk;
|
||||
const macho_file = ctx.macho_file;
|
||||
try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
|
||||
for (thunk.symbols.keys()) |index| {
|
||||
const sym = macho_file.getSymbol(index);
|
||||
try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.getName(macho_file), sym.value });
|
||||
for (thunk.symbols.keys()) |ref| {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user