mirror of
https://github.com/ziglang/zig.git
synced 2025-12-26 16:13:07 +00:00
macho: merge Zld state with MachO state
This commit is contained in:
parent
42e0850d78
commit
2c68fb3d7c
1391
src/link/MachO.zig
1391
src/link/MachO.zig
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,3 @@
|
||||
const Archive = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Object = @import("Object.zig");
|
||||
|
||||
file: fs.File,
|
||||
fat_offset: u64,
|
||||
name: []const u8,
|
||||
@ -215,3 +203,15 @@ pub fn parseObject(self: Archive, gpa: Allocator, offset: u32) !Object {
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
const Archive = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Object = @import("Object.zig");
|
||||
|
||||
@ -105,8 +105,7 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
|
||||
return surplus >= MachO.min_text_capacity;
|
||||
}
|
||||
|
||||
pub fn getOutputSection(zld: *Zld, sect: macho.section_64) !?u8 {
|
||||
const gpa = zld.gpa;
|
||||
pub fn getOutputSection(macho_file: *MachO, sect: macho.section_64) !?u8 {
|
||||
const segname = sect.segName();
|
||||
const sectname = sect.sectName();
|
||||
const res: ?u8 = blk: {
|
||||
@ -126,20 +125,14 @@ pub fn getOutputSection(zld: *Zld, sect: macho.section_64) !?u8 {
|
||||
}
|
||||
|
||||
if (sect.isCode()) {
|
||||
if (zld.text_section_index == null) {
|
||||
zld.text_section_index = try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
"__TEXT",
|
||||
"__text",
|
||||
.{
|
||||
.flags = macho.S_REGULAR |
|
||||
macho.S_ATTR_PURE_INSTRUCTIONS |
|
||||
macho.S_ATTR_SOME_INSTRUCTIONS,
|
||||
},
|
||||
);
|
||||
if (macho_file.text_section_index == null) {
|
||||
macho_file.text_section_index = try macho_file.initSection("__TEXT", "__text", .{
|
||||
.flags = macho.S_REGULAR |
|
||||
macho.S_ATTR_PURE_INSTRUCTIONS |
|
||||
macho.S_ATTR_SOME_INSTRUCTIONS,
|
||||
});
|
||||
}
|
||||
break :blk zld.text_section_index.?;
|
||||
break :blk macho_file.text_section_index.?;
|
||||
}
|
||||
|
||||
if (sect.isDebug()) {
|
||||
@ -151,42 +144,26 @@ pub fn getOutputSection(zld: *Zld, sect: macho.section_64) !?u8 {
|
||||
macho.S_8BYTE_LITERALS,
|
||||
macho.S_16BYTE_LITERALS,
|
||||
=> {
|
||||
break :blk zld.getSectionByName("__TEXT", "__const") orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
"__TEXT",
|
||||
"__const",
|
||||
.{},
|
||||
);
|
||||
break :blk macho_file.getSectionByName("__TEXT", "__const") orelse
|
||||
try macho_file.initSection("__TEXT", "__const", .{});
|
||||
},
|
||||
macho.S_CSTRING_LITERALS => {
|
||||
if (mem.startsWith(u8, sectname, "__objc")) {
|
||||
break :blk zld.getSectionByName(segname, sectname) orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
segname,
|
||||
sectname,
|
||||
.{},
|
||||
);
|
||||
break :blk macho_file.getSectionByName(segname, sectname) orelse
|
||||
try macho_file.initSection(segname, sectname, .{});
|
||||
}
|
||||
break :blk zld.getSectionByName("__TEXT", "__cstring") orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
"__TEXT",
|
||||
"__cstring",
|
||||
.{ .flags = macho.S_CSTRING_LITERALS },
|
||||
);
|
||||
break :blk macho_file.getSectionByName("__TEXT", "__cstring") orelse
|
||||
try macho_file.initSection("__TEXT", "__cstring", .{
|
||||
.flags = macho.S_CSTRING_LITERALS,
|
||||
});
|
||||
},
|
||||
macho.S_MOD_INIT_FUNC_POINTERS,
|
||||
macho.S_MOD_TERM_FUNC_POINTERS,
|
||||
=> {
|
||||
break :blk zld.getSectionByName("__DATA_CONST", sectname) orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
"__DATA_CONST",
|
||||
sectname,
|
||||
.{ .flags = sect.flags },
|
||||
);
|
||||
break :blk macho_file.getSectionByName("__DATA_CONST", sectname) orelse
|
||||
try macho_file.initSection("__DATA_CONST", sectname, .{
|
||||
.flags = sect.flags,
|
||||
});
|
||||
},
|
||||
macho.S_LITERAL_POINTERS,
|
||||
macho.S_ZEROFILL,
|
||||
@ -195,23 +172,14 @@ pub fn getOutputSection(zld: *Zld, sect: macho.section_64) !?u8 {
|
||||
macho.S_THREAD_LOCAL_REGULAR,
|
||||
macho.S_THREAD_LOCAL_ZEROFILL,
|
||||
=> {
|
||||
break :blk zld.getSectionByName(segname, sectname) orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
segname,
|
||||
sectname,
|
||||
.{ .flags = sect.flags },
|
||||
);
|
||||
break :blk macho_file.getSectionByName(segname, sectname) orelse
|
||||
try macho_file.initSection(segname, sectname, .{
|
||||
.flags = sect.flags,
|
||||
});
|
||||
},
|
||||
macho.S_COALESCED => {
|
||||
break :blk zld.getSectionByName(segname, sectname) orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
|
||||
segname,
|
||||
sectname,
|
||||
.{},
|
||||
);
|
||||
break :blk macho_file.getSectionByName(segname, sectname) orelse
|
||||
try macho_file.initSection(segname, sectname, .{});
|
||||
},
|
||||
macho.S_REGULAR => {
|
||||
if (mem.eql(u8, segname, "__TEXT")) {
|
||||
@ -221,13 +189,8 @@ pub fn getOutputSection(zld: *Zld, sect: macho.section_64) !?u8 {
|
||||
mem.eql(u8, sectname, "__gosymtab") or
|
||||
mem.eql(u8, sectname, "__gopclntab"))
|
||||
{
|
||||
break :blk zld.getSectionByName("__TEXT", sectname) orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
"__TEXT",
|
||||
sectname,
|
||||
.{},
|
||||
);
|
||||
break :blk macho_file.getSectionByName("__TEXT", sectname) orelse
|
||||
try macho_file.initSection("__TEXT", sectname, .{});
|
||||
}
|
||||
}
|
||||
if (mem.eql(u8, segname, "__DATA")) {
|
||||
@ -236,33 +199,17 @@ pub fn getOutputSection(zld: *Zld, sect: macho.section_64) !?u8 {
|
||||
mem.eql(u8, sectname, "__objc_classlist") or
|
||||
mem.eql(u8, sectname, "__objc_imageinfo"))
|
||||
{
|
||||
break :blk zld.getSectionByName("__DATA_CONST", sectname) orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
"__DATA_CONST",
|
||||
sectname,
|
||||
.{},
|
||||
);
|
||||
break :blk macho_file.getSectionByName("__DATA_CONST", sectname) orelse
|
||||
try macho_file.initSection("__DATA_CONST", sectname, .{});
|
||||
} else if (mem.eql(u8, sectname, "__data")) {
|
||||
if (zld.data_section_index == null) {
|
||||
zld.data_section_index = try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
"__DATA",
|
||||
"__data",
|
||||
.{},
|
||||
);
|
||||
if (macho_file.data_section_index == null) {
|
||||
macho_file.data_section_index = try macho_file.initSection("__DATA", "__data", .{});
|
||||
}
|
||||
break :blk zld.data_section_index.?;
|
||||
break :blk macho_file.data_section_index.?;
|
||||
}
|
||||
}
|
||||
break :blk zld.getSectionByName(segname, sectname) orelse try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
segname,
|
||||
sectname,
|
||||
.{},
|
||||
);
|
||||
break :blk macho_file.getSectionByName(segname, sectname) orelse
|
||||
try macho_file.initSection(segname, sectname, .{});
|
||||
},
|
||||
else => break :blk null,
|
||||
}
|
||||
@ -270,29 +217,29 @@ pub fn getOutputSection(zld: *Zld, sect: macho.section_64) !?u8 {
|
||||
|
||||
// TODO we can do this directly in the selection logic above.
|
||||
// Or is it not worth it?
|
||||
if (zld.data_const_section_index == null) {
|
||||
if (zld.getSectionByName("__DATA_CONST", "__const")) |index| {
|
||||
zld.data_const_section_index = index;
|
||||
if (macho_file.data_const_section_index == null) {
|
||||
if (macho_file.getSectionByName("__DATA_CONST", "__const")) |index| {
|
||||
macho_file.data_const_section_index = index;
|
||||
}
|
||||
}
|
||||
if (zld.thread_vars_section_index == null) {
|
||||
if (zld.getSectionByName("__DATA", "__thread_vars")) |index| {
|
||||
zld.thread_vars_section_index = index;
|
||||
if (macho_file.thread_vars_section_index == null) {
|
||||
if (macho_file.getSectionByName("__DATA", "__thread_vars")) |index| {
|
||||
macho_file.thread_vars_section_index = index;
|
||||
}
|
||||
}
|
||||
if (zld.thread_data_section_index == null) {
|
||||
if (zld.getSectionByName("__DATA", "__thread_data")) |index| {
|
||||
zld.thread_data_section_index = index;
|
||||
if (macho_file.thread_data_section_index == null) {
|
||||
if (macho_file.getSectionByName("__DATA", "__thread_data")) |index| {
|
||||
macho_file.thread_data_section_index = index;
|
||||
}
|
||||
}
|
||||
if (zld.thread_bss_section_index == null) {
|
||||
if (zld.getSectionByName("__DATA", "__thread_bss")) |index| {
|
||||
zld.thread_bss_section_index = index;
|
||||
if (macho_file.thread_bss_section_index == null) {
|
||||
if (macho_file.getSectionByName("__DATA", "__thread_bss")) |index| {
|
||||
macho_file.thread_bss_section_index = index;
|
||||
}
|
||||
}
|
||||
if (zld.bss_section_index == null) {
|
||||
if (zld.getSectionByName("__DATA", "__bss")) |index| {
|
||||
zld.bss_section_index = index;
|
||||
if (macho_file.bss_section_index == null) {
|
||||
if (macho_file.getSectionByName("__DATA", "__bss")) |index| {
|
||||
macho_file.bss_section_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,8 +330,8 @@ const InnerSymIterator = struct {
|
||||
|
||||
/// Returns an iterator over potentially contained symbols.
|
||||
/// Panics when called on a synthetic Atom.
|
||||
pub fn getInnerSymbolsIterator(zld: *Zld, atom_index: Index) InnerSymIterator {
|
||||
const atom = zld.getAtom(atom_index);
|
||||
pub fn getInnerSymbolsIterator(macho_file: *MachO, atom_index: Index) InnerSymIterator {
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null);
|
||||
return .{
|
||||
.sym_index = atom.inner_sym_index,
|
||||
@ -397,11 +344,11 @@ pub fn getInnerSymbolsIterator(zld: *Zld, atom_index: Index) InnerSymIterator {
|
||||
/// An alias symbol is used to represent the start of an input section
|
||||
/// if there were no symbols defined within that range.
|
||||
/// Alias symbols are only used on x86_64.
|
||||
pub fn getSectionAlias(zld: *Zld, atom_index: Index) ?SymbolWithLoc {
|
||||
const atom = zld.getAtom(atom_index);
|
||||
pub fn getSectionAlias(macho_file: *MachO, atom_index: Index) ?SymbolWithLoc {
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null);
|
||||
|
||||
const object = zld.objects.items[atom.getFile().?];
|
||||
const object = macho_file.objects.items[atom.getFile().?];
|
||||
const nbase = @as(u32, @intCast(object.in_symtab.?.len));
|
||||
const ntotal = @as(u32, @intCast(object.symtab.len));
|
||||
var sym_index: u32 = nbase;
|
||||
@ -418,13 +365,13 @@ pub fn getSectionAlias(zld: *Zld, atom_index: Index) ?SymbolWithLoc {
|
||||
|
||||
/// Given an index into a contained symbol within, calculates an offset wrt
|
||||
/// the start of this Atom.
|
||||
pub fn calcInnerSymbolOffset(zld: *Zld, atom_index: Index, sym_index: u32) u64 {
|
||||
const atom = zld.getAtom(atom_index);
|
||||
pub fn calcInnerSymbolOffset(macho_file: *MachO, atom_index: Index, sym_index: u32) u64 {
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null);
|
||||
|
||||
if (atom.sym_index == sym_index) return 0;
|
||||
|
||||
const object = zld.objects.items[atom.getFile().?];
|
||||
const object = macho_file.objects.items[atom.getFile().?];
|
||||
const source_sym = object.getSourceSymbol(sym_index).?;
|
||||
const base_addr = if (object.getSourceSymbol(atom.sym_index)) |sym|
|
||||
sym.n_value
|
||||
@ -437,14 +384,14 @@ pub fn calcInnerSymbolOffset(zld: *Zld, atom_index: Index, sym_index: u32) u64 {
|
||||
return source_sym.n_value - base_addr;
|
||||
}
|
||||
|
||||
pub fn scanAtomRelocs(zld: *Zld, atom_index: Index, relocs: []align(1) const macho.relocation_info) !void {
|
||||
const arch = zld.options.target.cpu.arch;
|
||||
const atom = zld.getAtom(atom_index);
|
||||
pub fn scanAtomRelocs(macho_file: *MachO, atom_index: Index, relocs: []align(1) const macho.relocation_info) !void {
|
||||
const arch = macho_file.base.options.target.cpu.arch;
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null); // synthetic atoms do not have relocs
|
||||
|
||||
return switch (arch) {
|
||||
.aarch64 => scanAtomRelocsArm64(zld, atom_index, relocs),
|
||||
.x86_64 => scanAtomRelocsX86(zld, atom_index, relocs),
|
||||
.aarch64 => scanAtomRelocsArm64(macho_file, atom_index, relocs),
|
||||
.x86_64 => scanAtomRelocsX86(macho_file, atom_index, relocs),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
@ -454,11 +401,11 @@ const RelocContext = struct {
|
||||
base_offset: i32 = 0,
|
||||
};
|
||||
|
||||
pub fn getRelocContext(zld: *Zld, atom_index: Index) RelocContext {
|
||||
const atom = zld.getAtom(atom_index);
|
||||
pub fn getRelocContext(macho_file: *MachO, atom_index: Index) RelocContext {
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null); // synthetic atoms do not have relocs
|
||||
|
||||
const object = zld.objects.items[atom.getFile().?];
|
||||
const object = macho_file.objects.items[atom.getFile().?];
|
||||
if (object.getSourceSymbol(atom.sym_index)) |source_sym| {
|
||||
const source_sect = object.getSourceSection(source_sym.n_sect - 1);
|
||||
return .{
|
||||
@ -475,7 +422,7 @@ pub fn getRelocContext(zld: *Zld, atom_index: Index) RelocContext {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parseRelocTarget(zld: *Zld, ctx: struct {
|
||||
pub fn parseRelocTarget(macho_file: *MachO, ctx: struct {
|
||||
object_id: u32,
|
||||
rel: macho.relocation_info,
|
||||
code: []const u8,
|
||||
@ -485,7 +432,7 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const object = &zld.objects.items[ctx.object_id];
|
||||
const object = &macho_file.objects.items[ctx.object_id];
|
||||
log.debug("parsing reloc target in object({d}) '{s}' ", .{ ctx.object_id, object.name });
|
||||
|
||||
const sym_index = if (ctx.rel.r_extern == 0) sym_index: {
|
||||
@ -498,7 +445,7 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {
|
||||
else
|
||||
mem.readIntLittle(u32, ctx.code[rel_offset..][0..4]);
|
||||
} else blk: {
|
||||
assert(zld.options.target.cpu.arch == .x86_64);
|
||||
assert(macho_file.base.options.target.cpu.arch == .x86_64);
|
||||
const correction: u3 = switch (@as(macho.reloc_type_x86_64, @enumFromInt(ctx.rel.r_type))) {
|
||||
.X86_64_RELOC_SIGNED => 0,
|
||||
.X86_64_RELOC_SIGNED_1 => 1,
|
||||
@ -517,35 +464,39 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {
|
||||
} else object.reverse_symtab_lookup[ctx.rel.r_symbolnum];
|
||||
|
||||
const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 };
|
||||
const sym = zld.getSymbol(sym_loc);
|
||||
const sym = macho_file.getSymbol(sym_loc);
|
||||
const target = if (sym.sect() and !sym.ext())
|
||||
sym_loc
|
||||
else if (object.getGlobal(sym_index)) |global_index|
|
||||
zld.globals.items[global_index]
|
||||
macho_file.globals.items[global_index]
|
||||
else
|
||||
sym_loc;
|
||||
log.debug(" | target %{d} ('{s}') in object({?d})", .{
|
||||
target.sym_index,
|
||||
zld.getSymbolName(target),
|
||||
macho_file.getSymbolName(target),
|
||||
target.getFile(),
|
||||
});
|
||||
return target;
|
||||
}
|
||||
|
||||
pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc) ?Index {
|
||||
pub fn getRelocTargetAtomIndex(macho_file: *MachO, target: SymbolWithLoc) ?Index {
|
||||
if (target.getFile() == null) {
|
||||
const target_sym_name = zld.getSymbolName(target);
|
||||
const target_sym_name = macho_file.getSymbolName(target);
|
||||
if (mem.eql(u8, "__mh_execute_header", target_sym_name)) return null;
|
||||
if (mem.eql(u8, "___dso_handle", target_sym_name)) return null;
|
||||
|
||||
unreachable; // referenced symbol not found
|
||||
}
|
||||
|
||||
const object = zld.objects.items[target.getFile().?];
|
||||
const object = macho_file.objects.items[target.getFile().?];
|
||||
return object.getAtomIndexForSymbol(target.sym_index);
|
||||
}
|
||||
|
||||
fn scanAtomRelocsArm64(zld: *Zld, atom_index: Index, relocs: []align(1) const macho.relocation_info) !void {
|
||||
fn scanAtomRelocsArm64(
|
||||
macho_file: *MachO,
|
||||
atom_index: Index,
|
||||
relocs: []align(1) const macho.relocation_info,
|
||||
) !void {
|
||||
for (relocs) |rel| {
|
||||
const rel_type = @as(macho.reloc_type_arm64, @enumFromInt(rel.r_type));
|
||||
|
||||
@ -556,8 +507,8 @@ fn scanAtomRelocsArm64(zld: *Zld, atom_index: Index, relocs: []align(1) const ma
|
||||
|
||||
if (rel.r_extern == 0) continue;
|
||||
|
||||
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 sym_index = object.reverse_symtab_lookup[rel.r_symbolnum];
|
||||
const sym_loc = SymbolWithLoc{
|
||||
.sym_index = sym_index,
|
||||
@ -565,35 +516,39 @@ fn scanAtomRelocsArm64(zld: *Zld, atom_index: Index, relocs: []align(1) const ma
|
||||
};
|
||||
|
||||
const target = if (object.getGlobal(sym_index)) |global_index|
|
||||
zld.globals.items[global_index]
|
||||
macho_file.globals.items[global_index]
|
||||
else
|
||||
sym_loc;
|
||||
|
||||
switch (rel_type) {
|
||||
.ARM64_RELOC_BRANCH26 => {
|
||||
// TODO rewrite relocation
|
||||
const sym = zld.getSymbol(target);
|
||||
if (sym.undf()) try zld.addStubEntry(target);
|
||||
const sym = macho_file.getSymbol(target);
|
||||
if (sym.undf()) try macho_file.addStubEntry(target);
|
||||
},
|
||||
.ARM64_RELOC_GOT_LOAD_PAGE21,
|
||||
.ARM64_RELOC_GOT_LOAD_PAGEOFF12,
|
||||
.ARM64_RELOC_POINTER_TO_GOT,
|
||||
=> {
|
||||
// TODO rewrite relocation
|
||||
try zld.addGotEntry(target);
|
||||
try macho_file.addGotEntry(target);
|
||||
},
|
||||
.ARM64_RELOC_TLVP_LOAD_PAGE21,
|
||||
.ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
|
||||
=> {
|
||||
const sym = zld.getSymbol(target);
|
||||
if (sym.undf()) try zld.addTlvPtrEntry(target);
|
||||
const sym = macho_file.getSymbol(target);
|
||||
if (sym.undf()) try macho_file.addTlvPtrEntry(target);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const macho.relocation_info) !void {
|
||||
fn scanAtomRelocsX86(
|
||||
macho_file: *MachO,
|
||||
atom_index: Index,
|
||||
relocs: []align(1) const macho.relocation_info,
|
||||
) !void {
|
||||
for (relocs) |rel| {
|
||||
const rel_type = @as(macho.reloc_type_x86_64, @enumFromInt(rel.r_type));
|
||||
|
||||
@ -604,8 +559,8 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach
|
||||
|
||||
if (rel.r_extern == 0) continue;
|
||||
|
||||
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 sym_index = object.reverse_symtab_lookup[rel.r_symbolnum];
|
||||
const sym_loc = SymbolWithLoc{
|
||||
.sym_index = sym_index,
|
||||
@ -613,23 +568,23 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach
|
||||
};
|
||||
|
||||
const target = if (object.getGlobal(sym_index)) |global_index|
|
||||
zld.globals.items[global_index]
|
||||
macho_file.globals.items[global_index]
|
||||
else
|
||||
sym_loc;
|
||||
|
||||
switch (rel_type) {
|
||||
.X86_64_RELOC_BRANCH => {
|
||||
// TODO rewrite relocation
|
||||
const sym = zld.getSymbol(target);
|
||||
if (sym.undf()) try zld.addStubEntry(target);
|
||||
const sym = macho_file.getSymbol(target);
|
||||
if (sym.undf()) try macho_file.addStubEntry(target);
|
||||
},
|
||||
.X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => {
|
||||
// TODO rewrite relocation
|
||||
try zld.addGotEntry(target);
|
||||
try macho_file.addGotEntry(target);
|
||||
},
|
||||
.X86_64_RELOC_TLV => {
|
||||
const sym = zld.getSymbol(target);
|
||||
if (sym.undf()) try zld.addTlvPtrEntry(target);
|
||||
const sym = macho_file.getSymbol(target);
|
||||
if (sym.undf()) try macho_file.addTlvPtrEntry(target);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@ -637,53 +592,53 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach
|
||||
}
|
||||
|
||||
pub fn resolveRelocs(
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
atom_index: Index,
|
||||
atom_code: []u8,
|
||||
atom_relocs: []align(1) const macho.relocation_info,
|
||||
) !void {
|
||||
const arch = zld.options.target.cpu.arch;
|
||||
const atom = zld.getAtom(atom_index);
|
||||
const arch = macho_file.base.options.target.cpu.arch;
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null); // synthetic atoms do not have relocs
|
||||
|
||||
log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{
|
||||
atom.sym_index,
|
||||
zld.getSymbolName(atom.getSymbolWithLoc()),
|
||||
macho_file.getSymbolName(atom.getSymbolWithLoc()),
|
||||
});
|
||||
|
||||
const ctx = getRelocContext(zld, atom_index);
|
||||
const ctx = getRelocContext(macho_file, atom_index);
|
||||
|
||||
return switch (arch) {
|
||||
.aarch64 => resolveRelocsArm64(zld, atom_index, atom_code, atom_relocs, ctx),
|
||||
.x86_64 => resolveRelocsX86(zld, atom_index, atom_code, atom_relocs, ctx),
|
||||
.aarch64 => resolveRelocsArm64(macho_file, atom_index, atom_code, atom_relocs, ctx),
|
||||
.x86_64 => resolveRelocsX86(macho_file, atom_index, atom_code, atom_relocs, ctx),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getRelocTargetAddress(zld: *Zld, target: SymbolWithLoc, is_tlv: bool) !u64 {
|
||||
const target_atom_index = getRelocTargetAtomIndex(zld, target) orelse {
|
||||
pub fn getRelocTargetAddress(macho_file: *MachO, target: SymbolWithLoc, is_tlv: bool) !u64 {
|
||||
const target_atom_index = getRelocTargetAtomIndex(macho_file, target) orelse {
|
||||
// If there is no atom for target, we still need to check for special, atom-less
|
||||
// symbols such as `___dso_handle`.
|
||||
const target_name = zld.getSymbolName(target);
|
||||
const atomless_sym = zld.getSymbol(target);
|
||||
const target_name = macho_file.getSymbolName(target);
|
||||
const atomless_sym = macho_file.getSymbol(target);
|
||||
log.debug(" | atomless target '{s}'", .{target_name});
|
||||
return atomless_sym.n_value;
|
||||
};
|
||||
const target_atom = zld.getAtom(target_atom_index);
|
||||
const target_atom = macho_file.getAtom(target_atom_index);
|
||||
log.debug(" | target ATOM(%{d}, '{s}') in object({?})", .{
|
||||
target_atom.sym_index,
|
||||
zld.getSymbolName(target_atom.getSymbolWithLoc()),
|
||||
macho_file.getSymbolName(target_atom.getSymbolWithLoc()),
|
||||
target_atom.getFile(),
|
||||
});
|
||||
|
||||
const target_sym = zld.getSymbol(target_atom.getSymbolWithLoc());
|
||||
const target_sym = macho_file.getSymbol(target_atom.getSymbolWithLoc());
|
||||
assert(target_sym.n_desc != MachO.N_DEAD);
|
||||
|
||||
// If `target` is contained within the target atom, pull its address value.
|
||||
const offset = if (target_atom.getFile() != null) blk: {
|
||||
const object = zld.objects.items[target_atom.getFile().?];
|
||||
const object = macho_file.objects.items[target_atom.getFile().?];
|
||||
break :blk if (object.getSourceSymbol(target.sym_index)) |_|
|
||||
Atom.calcInnerSymbolOffset(zld, target_atom_index, target.sym_index)
|
||||
Atom.calcInnerSymbolOffset(macho_file, target_atom_index, target.sym_index)
|
||||
else
|
||||
0; // section alias
|
||||
} else 0;
|
||||
@ -694,9 +649,9 @@ pub fn getRelocTargetAddress(zld: *Zld, target: SymbolWithLoc, is_tlv: bool) !u6
|
||||
// * wrt to __thread_data if defined, then
|
||||
// * wrt to __thread_bss
|
||||
const sect_id: u16 = sect_id: {
|
||||
if (zld.thread_data_section_index) |i| {
|
||||
if (macho_file.thread_data_section_index) |i| {
|
||||
break :sect_id i;
|
||||
} else if (zld.thread_bss_section_index) |i| {
|
||||
} else if (macho_file.thread_bss_section_index) |i| {
|
||||
break :sect_id i;
|
||||
} else {
|
||||
log.err("threadlocal variables present but no initializer sections found", .{});
|
||||
@ -705,20 +660,20 @@ pub fn getRelocTargetAddress(zld: *Zld, target: SymbolWithLoc, is_tlv: bool) !u6
|
||||
return error.FailedToResolveRelocationTarget;
|
||||
}
|
||||
};
|
||||
break :base_address zld.sections.items(.header)[sect_id].addr;
|
||||
break :base_address macho_file.sections.items(.header)[sect_id].addr;
|
||||
} else 0;
|
||||
return target_sym.n_value + offset - base_address;
|
||||
}
|
||||
|
||||
fn resolveRelocsArm64(
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
atom_index: Index,
|
||||
atom_code: []u8,
|
||||
atom_relocs: []align(1) const macho.relocation_info,
|
||||
context: RelocContext,
|
||||
) !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().?];
|
||||
|
||||
var addend: ?i64 = null;
|
||||
var subtractor: ?SymbolWithLoc = null;
|
||||
@ -745,7 +700,7 @@ fn resolveRelocsArm64(
|
||||
atom.getFile(),
|
||||
});
|
||||
|
||||
subtractor = parseRelocTarget(zld, .{
|
||||
subtractor = parseRelocTarget(macho_file, .{
|
||||
.object_id = atom.getFile().?,
|
||||
.rel = rel,
|
||||
.code = atom_code,
|
||||
@ -757,7 +712,7 @@ fn resolveRelocsArm64(
|
||||
else => {},
|
||||
}
|
||||
|
||||
const target = parseRelocTarget(zld, .{
|
||||
const target = parseRelocTarget(macho_file, .{
|
||||
.object_id = atom.getFile().?,
|
||||
.rel = rel,
|
||||
.code = atom_code,
|
||||
@ -770,26 +725,26 @@ fn resolveRelocsArm64(
|
||||
@tagName(rel_type),
|
||||
rel.r_address,
|
||||
target.sym_index,
|
||||
zld.getSymbolName(target),
|
||||
macho_file.getSymbolName(target),
|
||||
target.getFile(),
|
||||
});
|
||||
|
||||
const source_addr = blk: {
|
||||
const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
|
||||
const source_sym = macho_file.getSymbol(atom.getSymbolWithLoc());
|
||||
break :blk source_sym.n_value + rel_offset;
|
||||
};
|
||||
const target_addr = blk: {
|
||||
if (relocRequiresGot(zld, rel)) break :blk zld.getGotEntryAddress(target).?;
|
||||
if (relocIsTlv(zld, rel) and zld.getSymbol(target).undf())
|
||||
break :blk zld.getTlvPtrEntryAddress(target).?;
|
||||
if (relocIsStub(zld, rel) and zld.getSymbol(target).undf())
|
||||
break :blk zld.getStubsEntryAddress(target).?;
|
||||
if (relocRequiresGot(macho_file, rel)) break :blk macho_file.getGotEntryAddress(target).?;
|
||||
if (relocIsTlv(macho_file, rel) and macho_file.getSymbol(target).undf())
|
||||
break :blk macho_file.getTlvPtrEntryAddress(target).?;
|
||||
if (relocIsStub(macho_file, rel) and macho_file.getSymbol(target).undf())
|
||||
break :blk macho_file.getStubsEntryAddress(target).?;
|
||||
const is_tlv = is_tlv: {
|
||||
const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
|
||||
const header = zld.sections.items(.header)[source_sym.n_sect - 1];
|
||||
const source_sym = macho_file.getSymbol(atom.getSymbolWithLoc());
|
||||
const header = macho_file.sections.items(.header)[source_sym.n_sect - 1];
|
||||
break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
|
||||
};
|
||||
break :blk try getRelocTargetAddress(zld, target, is_tlv);
|
||||
break :blk try getRelocTargetAddress(macho_file, target, is_tlv);
|
||||
};
|
||||
|
||||
log.debug(" | source_addr = 0x{x}", .{source_addr});
|
||||
@ -797,9 +752,9 @@ fn resolveRelocsArm64(
|
||||
switch (rel_type) {
|
||||
.ARM64_RELOC_BRANCH26 => {
|
||||
log.debug(" source {s} (object({?})), target {s}", .{
|
||||
zld.getSymbolName(atom.getSymbolWithLoc()),
|
||||
macho_file.getSymbolName(atom.getSymbolWithLoc()),
|
||||
atom.getFile(),
|
||||
zld.getSymbolName(target),
|
||||
macho_file.getSymbolName(target),
|
||||
});
|
||||
|
||||
const displacement = if (Relocation.calcPcRelativeDisplacementArm64(
|
||||
@ -809,13 +764,13 @@ fn resolveRelocsArm64(
|
||||
log.debug(" | target_addr = 0x{x}", .{target_addr});
|
||||
break :blk disp;
|
||||
} else |_| blk: {
|
||||
const thunk_index = zld.thunk_table.get(atom_index).?;
|
||||
const thunk = zld.thunks.items[thunk_index];
|
||||
const thunk_sym_loc = if (zld.getSymbol(target).undf())
|
||||
thunk.getTrampoline(zld, .stub, target).?
|
||||
const thunk_index = macho_file.thunk_table.get(atom_index).?;
|
||||
const thunk = macho_file.thunks.items[thunk_index];
|
||||
const thunk_sym_loc = if (macho_file.getSymbol(target).undf())
|
||||
thunk.getTrampoline(macho_file, .stub, target).?
|
||||
else
|
||||
thunk.getTrampoline(zld, .atom, target).?;
|
||||
const thunk_addr = zld.getSymbol(thunk_sym_loc).n_value;
|
||||
thunk.getTrampoline(macho_file, .atom, target).?;
|
||||
const thunk_addr = macho_file.getSymbol(thunk_sym_loc).n_value;
|
||||
log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_addr});
|
||||
break :blk try Relocation.calcPcRelativeDisplacementArm64(source_addr, thunk_addr);
|
||||
};
|
||||
@ -944,7 +899,7 @@ fn resolveRelocsArm64(
|
||||
}
|
||||
};
|
||||
|
||||
var inst = if (zld.tlv_ptr_table.lookup.contains(target)) aarch64.Instruction{
|
||||
var inst = if (macho_file.tlv_ptr_table.lookup.contains(target)) aarch64.Instruction{
|
||||
.load_store_register = .{
|
||||
.rt = reg_info.rd,
|
||||
.rn = reg_info.rn,
|
||||
@ -992,7 +947,7 @@ fn resolveRelocsArm64(
|
||||
|
||||
const result = blk: {
|
||||
if (subtractor) |sub| {
|
||||
const sym = zld.getSymbol(sub);
|
||||
const sym = macho_file.getSymbol(sub);
|
||||
break :blk @as(i64, @intCast(target_addr)) - @as(i64, @intCast(sym.n_value)) + ptr_addend;
|
||||
} else {
|
||||
break :blk @as(i64, @intCast(target_addr)) + ptr_addend;
|
||||
@ -1016,14 +971,14 @@ fn resolveRelocsArm64(
|
||||
}
|
||||
|
||||
fn resolveRelocsX86(
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
atom_index: Index,
|
||||
atom_code: []u8,
|
||||
atom_relocs: []align(1) const macho.relocation_info,
|
||||
context: RelocContext,
|
||||
) !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().?];
|
||||
|
||||
var subtractor: ?SymbolWithLoc = null;
|
||||
|
||||
@ -1041,7 +996,7 @@ fn resolveRelocsX86(
|
||||
atom.getFile(),
|
||||
});
|
||||
|
||||
subtractor = parseRelocTarget(zld, .{
|
||||
subtractor = parseRelocTarget(macho_file, .{
|
||||
.object_id = atom.getFile().?,
|
||||
.rel = rel,
|
||||
.code = atom_code,
|
||||
@ -1053,7 +1008,7 @@ fn resolveRelocsX86(
|
||||
else => {},
|
||||
}
|
||||
|
||||
const target = parseRelocTarget(zld, .{
|
||||
const target = parseRelocTarget(macho_file, .{
|
||||
.object_id = atom.getFile().?,
|
||||
.rel = rel,
|
||||
.code = atom_code,
|
||||
@ -1066,26 +1021,26 @@ fn resolveRelocsX86(
|
||||
@tagName(rel_type),
|
||||
rel.r_address,
|
||||
target.sym_index,
|
||||
zld.getSymbolName(target),
|
||||
macho_file.getSymbolName(target),
|
||||
target.getFile(),
|
||||
});
|
||||
|
||||
const source_addr = blk: {
|
||||
const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
|
||||
const source_sym = macho_file.getSymbol(atom.getSymbolWithLoc());
|
||||
break :blk source_sym.n_value + rel_offset;
|
||||
};
|
||||
const target_addr = blk: {
|
||||
if (relocRequiresGot(zld, rel)) break :blk zld.getGotEntryAddress(target).?;
|
||||
if (relocIsStub(zld, rel) and zld.getSymbol(target).undf())
|
||||
break :blk zld.getStubsEntryAddress(target).?;
|
||||
if (relocIsTlv(zld, rel) and zld.getSymbol(target).undf())
|
||||
break :blk zld.getTlvPtrEntryAddress(target).?;
|
||||
if (relocRequiresGot(macho_file, rel)) break :blk macho_file.getGotEntryAddress(target).?;
|
||||
if (relocIsStub(macho_file, rel) and macho_file.getSymbol(target).undf())
|
||||
break :blk macho_file.getStubsEntryAddress(target).?;
|
||||
if (relocIsTlv(macho_file, rel) and macho_file.getSymbol(target).undf())
|
||||
break :blk macho_file.getTlvPtrEntryAddress(target).?;
|
||||
const is_tlv = is_tlv: {
|
||||
const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
|
||||
const header = zld.sections.items(.header)[source_sym.n_sect - 1];
|
||||
const source_sym = macho_file.getSymbol(atom.getSymbolWithLoc());
|
||||
const header = macho_file.sections.items(.header)[source_sym.n_sect - 1];
|
||||
break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
|
||||
};
|
||||
break :blk try getRelocTargetAddress(zld, target, is_tlv);
|
||||
break :blk try getRelocTargetAddress(macho_file, target, is_tlv);
|
||||
};
|
||||
|
||||
log.debug(" | source_addr = 0x{x}", .{source_addr});
|
||||
@ -1115,7 +1070,7 @@ fn resolveRelocsX86(
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
|
||||
|
||||
if (zld.tlv_ptr_table.lookup.get(target) == null) {
|
||||
if (macho_file.tlv_ptr_table.lookup.get(target) == null) {
|
||||
// We need to rewrite the opcode from movq to leaq.
|
||||
atom_code[rel_offset - 2] = 0x8d;
|
||||
}
|
||||
@ -1170,7 +1125,7 @@ fn resolveRelocsX86(
|
||||
|
||||
const result = blk: {
|
||||
if (subtractor) |sub| {
|
||||
const sym = zld.getSymbol(sub);
|
||||
const sym = macho_file.getSymbol(sub);
|
||||
break :blk @as(i64, @intCast(target_addr)) - @as(i64, @intCast(sym.n_value)) + addend;
|
||||
} else {
|
||||
break :blk @as(i64, @intCast(target_addr)) + addend;
|
||||
@ -1192,10 +1147,10 @@ fn resolveRelocsX86(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getAtomCode(zld: *Zld, atom_index: Index) []const u8 {
|
||||
const atom = zld.getAtom(atom_index);
|
||||
pub fn getAtomCode(macho_file: *MachO, atom_index: Index) []const u8 {
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null); // Synthetic atom shouldn't need to inquire for code.
|
||||
const object = zld.objects.items[atom.getFile().?];
|
||||
const object = macho_file.objects.items[atom.getFile().?];
|
||||
const source_sym = object.getSourceSymbol(atom.sym_index) orelse {
|
||||
// If there was no matching symbol present in the source symtab, this means
|
||||
// we are dealing with either an entire section, or part of it, but also
|
||||
@ -1216,10 +1171,10 @@ pub fn getAtomCode(zld: *Zld, atom_index: Index) []const u8 {
|
||||
return code[offset..][0..code_len];
|
||||
}
|
||||
|
||||
pub fn getAtomRelocs(zld: *Zld, atom_index: Index) []const macho.relocation_info {
|
||||
const atom = zld.getAtom(atom_index);
|
||||
pub fn getAtomRelocs(macho_file: *MachO, atom_index: Index) []const macho.relocation_info {
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null); // Synthetic atom shouldn't need to unique for relocs.
|
||||
const object = zld.objects.items[atom.getFile().?];
|
||||
const object = macho_file.objects.items[atom.getFile().?];
|
||||
const cache = object.relocs_lookup[atom.sym_index];
|
||||
|
||||
const source_sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
|
||||
@ -1238,8 +1193,8 @@ pub fn getAtomRelocs(zld: *Zld, atom_index: Index) []const macho.relocation_info
|
||||
return relocs[cache.start..][0..cache.len];
|
||||
}
|
||||
|
||||
pub fn relocRequiresGot(zld: *Zld, rel: macho.relocation_info) bool {
|
||||
switch (zld.options.target.cpu.arch) {
|
||||
pub fn relocRequiresGot(macho_file: *MachO, rel: macho.relocation_info) bool {
|
||||
switch (macho_file.base.options.target.cpu.arch) {
|
||||
.aarch64 => switch (@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type))) {
|
||||
.ARM64_RELOC_GOT_LOAD_PAGE21,
|
||||
.ARM64_RELOC_GOT_LOAD_PAGEOFF12,
|
||||
@ -1257,8 +1212,8 @@ pub fn relocRequiresGot(zld: *Zld, rel: macho.relocation_info) bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn relocIsTlv(zld: *Zld, rel: macho.relocation_info) bool {
|
||||
switch (zld.options.target.cpu.arch) {
|
||||
pub fn relocIsTlv(macho_file: *MachO, rel: macho.relocation_info) bool {
|
||||
switch (macho_file.base.options.target.cpu.arch) {
|
||||
.aarch64 => switch (@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type))) {
|
||||
.ARM64_RELOC_TLVP_LOAD_PAGE21,
|
||||
.ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
|
||||
@ -1273,8 +1228,8 @@ pub fn relocIsTlv(zld: *Zld, rel: macho.relocation_info) bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn relocIsStub(zld: *Zld, rel: macho.relocation_info) bool {
|
||||
switch (zld.options.target.cpu.arch) {
|
||||
pub fn relocIsStub(macho_file: *MachO, rel: macho.relocation_info) bool {
|
||||
switch (macho_file.base.options.target.cpu.arch) {
|
||||
.aarch64 => switch (@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type))) {
|
||||
.ARM64_RELOC_BRANCH26 => return true,
|
||||
else => return false,
|
||||
@ -1305,4 +1260,3 @@ const Arch = std.Target.Cpu.Arch;
|
||||
const MachO = @import("../MachO.zig");
|
||||
pub const Relocation = @import("Relocation.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const Zld = @import("zld.zig").Zld;
|
||||
|
||||
@ -1,17 +1,175 @@
|
||||
const CodeSignature = @This();
|
||||
page_size: u16,
|
||||
code_directory: CodeDirectory,
|
||||
requirements: ?Requirements = null,
|
||||
entitlements: ?Entitlements = null,
|
||||
signature: ?Signature = null,
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
pub fn init(page_size: u16) CodeSignature {
|
||||
return .{
|
||||
.page_size = page_size,
|
||||
.code_directory = CodeDirectory.init(page_size),
|
||||
};
|
||||
}
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Compilation = @import("../../Compilation.zig");
|
||||
const Hasher = @import("hasher.zig").ParallelHasher;
|
||||
const Sha256 = std.crypto.hash.sha2.Sha256;
|
||||
pub fn deinit(self: *CodeSignature, allocator: Allocator) void {
|
||||
self.code_directory.deinit(allocator);
|
||||
if (self.requirements) |*req| {
|
||||
req.deinit(allocator);
|
||||
}
|
||||
if (self.entitlements) |*ents| {
|
||||
ents.deinit(allocator);
|
||||
}
|
||||
if (self.signature) |*sig| {
|
||||
sig.deinit(allocator);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {
|
||||
const file = try fs.cwd().openFile(path, .{});
|
||||
defer file.close();
|
||||
const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32));
|
||||
self.entitlements = .{ .inner = inner };
|
||||
}
|
||||
|
||||
pub const WriteOpts = struct {
|
||||
file: fs.File,
|
||||
exec_seg_base: u64,
|
||||
exec_seg_limit: u64,
|
||||
file_size: u32,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
};
|
||||
|
||||
pub fn writeAdhocSignature(
|
||||
self: *CodeSignature,
|
||||
comp: *const Compilation,
|
||||
opts: WriteOpts,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
const gpa = comp.gpa;
|
||||
|
||||
var header: macho.SuperBlob = .{
|
||||
.magic = macho.CSMAGIC_EMBEDDED_SIGNATURE,
|
||||
.length = @sizeOf(macho.SuperBlob),
|
||||
.count = 0,
|
||||
};
|
||||
|
||||
var blobs = std.ArrayList(Blob).init(gpa);
|
||||
defer blobs.deinit();
|
||||
|
||||
self.code_directory.inner.execSegBase = opts.exec_seg_base;
|
||||
self.code_directory.inner.execSegLimit = opts.exec_seg_limit;
|
||||
self.code_directory.inner.execSegFlags = if (opts.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0;
|
||||
self.code_directory.inner.codeLimit = opts.file_size;
|
||||
|
||||
const total_pages = @as(u32, @intCast(mem.alignForward(usize, opts.file_size, self.page_size) / self.page_size));
|
||||
|
||||
try self.code_directory.code_slots.ensureTotalCapacityPrecise(gpa, total_pages);
|
||||
self.code_directory.code_slots.items.len = total_pages;
|
||||
self.code_directory.inner.nCodeSlots = total_pages;
|
||||
|
||||
// Calculate hash for each page (in file) and write it to the buffer
|
||||
var hasher = Hasher(Sha256){ .allocator = gpa, .thread_pool = comp.thread_pool };
|
||||
try hasher.hash(opts.file, self.code_directory.code_slots.items, .{
|
||||
.chunk_size = self.page_size,
|
||||
.max_file_size = opts.file_size,
|
||||
});
|
||||
|
||||
try blobs.append(.{ .code_directory = &self.code_directory });
|
||||
header.length += @sizeOf(macho.BlobIndex);
|
||||
header.count += 1;
|
||||
|
||||
var hash: [hash_size]u8 = undefined;
|
||||
|
||||
if (self.requirements) |*req| {
|
||||
var buf = std.ArrayList(u8).init(gpa);
|
||||
defer buf.deinit();
|
||||
try req.write(buf.writer());
|
||||
Sha256.hash(buf.items, &hash, .{});
|
||||
self.code_directory.addSpecialHash(req.slotType(), hash);
|
||||
|
||||
try blobs.append(.{ .requirements = req });
|
||||
header.count += 1;
|
||||
header.length += @sizeOf(macho.BlobIndex) + req.size();
|
||||
}
|
||||
|
||||
if (self.entitlements) |*ents| {
|
||||
var buf = std.ArrayList(u8).init(gpa);
|
||||
defer buf.deinit();
|
||||
try ents.write(buf.writer());
|
||||
Sha256.hash(buf.items, &hash, .{});
|
||||
self.code_directory.addSpecialHash(ents.slotType(), hash);
|
||||
|
||||
try blobs.append(.{ .entitlements = ents });
|
||||
header.count += 1;
|
||||
header.length += @sizeOf(macho.BlobIndex) + ents.size();
|
||||
}
|
||||
|
||||
if (self.signature) |*sig| {
|
||||
try blobs.append(.{ .signature = sig });
|
||||
header.count += 1;
|
||||
header.length += @sizeOf(macho.BlobIndex) + sig.size();
|
||||
}
|
||||
|
||||
self.code_directory.inner.hashOffset =
|
||||
@sizeOf(macho.CodeDirectory) + @as(u32, @intCast(self.code_directory.ident.len + 1 + self.code_directory.inner.nSpecialSlots * hash_size));
|
||||
self.code_directory.inner.length = self.code_directory.size();
|
||||
header.length += self.code_directory.size();
|
||||
|
||||
try writer.writeIntBig(u32, header.magic);
|
||||
try writer.writeIntBig(u32, header.length);
|
||||
try writer.writeIntBig(u32, header.count);
|
||||
|
||||
var offset: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) * @as(u32, @intCast(blobs.items.len));
|
||||
for (blobs.items) |blob| {
|
||||
try writer.writeIntBig(u32, blob.slotType());
|
||||
try writer.writeIntBig(u32, offset);
|
||||
offset += blob.size();
|
||||
}
|
||||
|
||||
for (blobs.items) |blob| {
|
||||
try blob.write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(self: CodeSignature) u32 {
|
||||
var ssize: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size();
|
||||
if (self.requirements) |req| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + req.size();
|
||||
}
|
||||
if (self.entitlements) |ent| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + ent.size();
|
||||
}
|
||||
if (self.signature) |sig| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + sig.size();
|
||||
}
|
||||
return ssize;
|
||||
}
|
||||
|
||||
pub fn estimateSize(self: CodeSignature, file_size: u64) u32 {
|
||||
var ssize: u64 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size();
|
||||
// Approx code slots
|
||||
const total_pages = mem.alignForward(u64, file_size, self.page_size) / self.page_size;
|
||||
ssize += total_pages * hash_size;
|
||||
var n_special_slots: u32 = 0;
|
||||
if (self.requirements) |req| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + req.size();
|
||||
n_special_slots = @max(n_special_slots, req.slotType());
|
||||
}
|
||||
if (self.entitlements) |ent| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + ent.size() + hash_size;
|
||||
n_special_slots = @max(n_special_slots, ent.slotType());
|
||||
}
|
||||
if (self.signature) |sig| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + sig.size();
|
||||
}
|
||||
ssize += n_special_slots * hash_size;
|
||||
return @as(u32, @intCast(mem.alignForward(u64, ssize, @sizeOf(u64))));
|
||||
}
|
||||
|
||||
pub fn clear(self: *CodeSignature, allocator: Allocator) void {
|
||||
self.code_directory.deinit(allocator);
|
||||
self.code_directory = CodeDirectory.init(self.page_size);
|
||||
}
|
||||
|
||||
const hash_size = Sha256.digest_length;
|
||||
|
||||
@ -218,175 +376,17 @@ const Signature = struct {
|
||||
}
|
||||
};
|
||||
|
||||
page_size: u16,
|
||||
code_directory: CodeDirectory,
|
||||
requirements: ?Requirements = null,
|
||||
entitlements: ?Entitlements = null,
|
||||
signature: ?Signature = null,
|
||||
const CodeSignature = @This();
|
||||
|
||||
pub fn init(page_size: u16) CodeSignature {
|
||||
return .{
|
||||
.page_size = page_size,
|
||||
.code_directory = CodeDirectory.init(page_size),
|
||||
};
|
||||
}
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
|
||||
pub fn deinit(self: *CodeSignature, allocator: Allocator) void {
|
||||
self.code_directory.deinit(allocator);
|
||||
if (self.requirements) |*req| {
|
||||
req.deinit(allocator);
|
||||
}
|
||||
if (self.entitlements) |*ents| {
|
||||
ents.deinit(allocator);
|
||||
}
|
||||
if (self.signature) |*sig| {
|
||||
sig.deinit(allocator);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {
|
||||
const file = try fs.cwd().openFile(path, .{});
|
||||
defer file.close();
|
||||
const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32));
|
||||
self.entitlements = .{ .inner = inner };
|
||||
}
|
||||
|
||||
pub const WriteOpts = struct {
|
||||
file: fs.File,
|
||||
exec_seg_base: u64,
|
||||
exec_seg_limit: u64,
|
||||
file_size: u32,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
};
|
||||
|
||||
pub fn writeAdhocSignature(
|
||||
self: *CodeSignature,
|
||||
comp: *const Compilation,
|
||||
opts: WriteOpts,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
const gpa = comp.gpa;
|
||||
|
||||
var header: macho.SuperBlob = .{
|
||||
.magic = macho.CSMAGIC_EMBEDDED_SIGNATURE,
|
||||
.length = @sizeOf(macho.SuperBlob),
|
||||
.count = 0,
|
||||
};
|
||||
|
||||
var blobs = std.ArrayList(Blob).init(gpa);
|
||||
defer blobs.deinit();
|
||||
|
||||
self.code_directory.inner.execSegBase = opts.exec_seg_base;
|
||||
self.code_directory.inner.execSegLimit = opts.exec_seg_limit;
|
||||
self.code_directory.inner.execSegFlags = if (opts.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0;
|
||||
self.code_directory.inner.codeLimit = opts.file_size;
|
||||
|
||||
const total_pages = @as(u32, @intCast(mem.alignForward(usize, opts.file_size, self.page_size) / self.page_size));
|
||||
|
||||
try self.code_directory.code_slots.ensureTotalCapacityPrecise(gpa, total_pages);
|
||||
self.code_directory.code_slots.items.len = total_pages;
|
||||
self.code_directory.inner.nCodeSlots = total_pages;
|
||||
|
||||
// Calculate hash for each page (in file) and write it to the buffer
|
||||
var hasher = Hasher(Sha256){ .allocator = gpa, .thread_pool = comp.thread_pool };
|
||||
try hasher.hash(opts.file, self.code_directory.code_slots.items, .{
|
||||
.chunk_size = self.page_size,
|
||||
.max_file_size = opts.file_size,
|
||||
});
|
||||
|
||||
try blobs.append(.{ .code_directory = &self.code_directory });
|
||||
header.length += @sizeOf(macho.BlobIndex);
|
||||
header.count += 1;
|
||||
|
||||
var hash: [hash_size]u8 = undefined;
|
||||
|
||||
if (self.requirements) |*req| {
|
||||
var buf = std.ArrayList(u8).init(gpa);
|
||||
defer buf.deinit();
|
||||
try req.write(buf.writer());
|
||||
Sha256.hash(buf.items, &hash, .{});
|
||||
self.code_directory.addSpecialHash(req.slotType(), hash);
|
||||
|
||||
try blobs.append(.{ .requirements = req });
|
||||
header.count += 1;
|
||||
header.length += @sizeOf(macho.BlobIndex) + req.size();
|
||||
}
|
||||
|
||||
if (self.entitlements) |*ents| {
|
||||
var buf = std.ArrayList(u8).init(gpa);
|
||||
defer buf.deinit();
|
||||
try ents.write(buf.writer());
|
||||
Sha256.hash(buf.items, &hash, .{});
|
||||
self.code_directory.addSpecialHash(ents.slotType(), hash);
|
||||
|
||||
try blobs.append(.{ .entitlements = ents });
|
||||
header.count += 1;
|
||||
header.length += @sizeOf(macho.BlobIndex) + ents.size();
|
||||
}
|
||||
|
||||
if (self.signature) |*sig| {
|
||||
try blobs.append(.{ .signature = sig });
|
||||
header.count += 1;
|
||||
header.length += @sizeOf(macho.BlobIndex) + sig.size();
|
||||
}
|
||||
|
||||
self.code_directory.inner.hashOffset =
|
||||
@sizeOf(macho.CodeDirectory) + @as(u32, @intCast(self.code_directory.ident.len + 1 + self.code_directory.inner.nSpecialSlots * hash_size));
|
||||
self.code_directory.inner.length = self.code_directory.size();
|
||||
header.length += self.code_directory.size();
|
||||
|
||||
try writer.writeIntBig(u32, header.magic);
|
||||
try writer.writeIntBig(u32, header.length);
|
||||
try writer.writeIntBig(u32, header.count);
|
||||
|
||||
var offset: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) * @as(u32, @intCast(blobs.items.len));
|
||||
for (blobs.items) |blob| {
|
||||
try writer.writeIntBig(u32, blob.slotType());
|
||||
try writer.writeIntBig(u32, offset);
|
||||
offset += blob.size();
|
||||
}
|
||||
|
||||
for (blobs.items) |blob| {
|
||||
try blob.write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(self: CodeSignature) u32 {
|
||||
var ssize: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size();
|
||||
if (self.requirements) |req| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + req.size();
|
||||
}
|
||||
if (self.entitlements) |ent| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + ent.size();
|
||||
}
|
||||
if (self.signature) |sig| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + sig.size();
|
||||
}
|
||||
return ssize;
|
||||
}
|
||||
|
||||
pub fn estimateSize(self: CodeSignature, file_size: u64) u32 {
|
||||
var ssize: u64 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size();
|
||||
// Approx code slots
|
||||
const total_pages = mem.alignForward(u64, file_size, self.page_size) / self.page_size;
|
||||
ssize += total_pages * hash_size;
|
||||
var n_special_slots: u32 = 0;
|
||||
if (self.requirements) |req| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + req.size();
|
||||
n_special_slots = @max(n_special_slots, req.slotType());
|
||||
}
|
||||
if (self.entitlements) |ent| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + ent.size() + hash_size;
|
||||
n_special_slots = @max(n_special_slots, ent.slotType());
|
||||
}
|
||||
if (self.signature) |sig| {
|
||||
ssize += @sizeOf(macho.BlobIndex) + sig.size();
|
||||
}
|
||||
ssize += n_special_slots * hash_size;
|
||||
return @as(u32, @intCast(mem.alignForward(u64, ssize, @sizeOf(u64))));
|
||||
}
|
||||
|
||||
pub fn clear(self: *CodeSignature, allocator: Allocator) void {
|
||||
self.code_directory.deinit(allocator);
|
||||
self.code_directory = CodeDirectory.init(self.page_size);
|
||||
}
|
||||
const Allocator = mem.Allocator;
|
||||
const Compilation = @import("../../Compilation.zig");
|
||||
const Hasher = @import("hasher.zig").ParallelHasher;
|
||||
const Sha256 = std.crypto.hash.sha2.Sha256;
|
||||
|
||||
@ -1,26 +1,3 @@
|
||||
const DebugSymbols = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const build_options = @import("build_options");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const link = @import("../../link.zig");
|
||||
const load_commands = @import("load_commands.zig");
|
||||
const log = std.log.scoped(.dsym);
|
||||
const macho = std.macho;
|
||||
const makeStaticString = MachO.makeStaticString;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const padToIdeal = MachO.padToIdeal;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Dwarf = @import("../Dwarf.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Module = @import("../../Module.zig");
|
||||
const StringTable = @import("../strtab.zig").StringTable;
|
||||
const Type = @import("../../type.zig").Type;
|
||||
|
||||
allocator: Allocator,
|
||||
dwarf: Dwarf,
|
||||
file: fs.File,
|
||||
@ -569,3 +546,26 @@ pub fn getSection(self: DebugSymbols, sect: u8) macho.section_64 {
|
||||
assert(sect < self.sections.items.len);
|
||||
return self.sections.items[sect];
|
||||
}
|
||||
|
||||
const DebugSymbols = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const build_options = @import("build_options");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const link = @import("../../link.zig");
|
||||
const load_commands = @import("load_commands.zig");
|
||||
const log = std.log.scoped(.dsym);
|
||||
const macho = std.macho;
|
||||
const makeStaticString = MachO.makeStaticString;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const padToIdeal = MachO.padToIdeal;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Dwarf = @import("../Dwarf.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Module = @import("../../Module.zig");
|
||||
const StringTable = @import("../strtab.zig").StringTable;
|
||||
const Type = @import("../../type.zig").Type;
|
||||
|
||||
@ -1,17 +1,3 @@
|
||||
const DwarfInfo = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const dwarf = std.dwarf;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.macho);
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
pub const AbbrevLookupTable = std.AutoHashMap(u64, struct { pos: usize, len: usize });
|
||||
pub const SubprogramLookupByName = std.StringHashMap(struct { addr: u64, size: u64 });
|
||||
|
||||
debug_info: []const u8,
|
||||
debug_abbrev: []const u8,
|
||||
debug_str: []const u8,
|
||||
@ -501,3 +487,17 @@ fn getString(self: DwarfInfo, off: u64) []const u8 {
|
||||
assert(off < self.debug_str.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.debug_str.ptr + @as(usize, @intCast(off)))), 0);
|
||||
}
|
||||
|
||||
const DwarfInfo = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const dwarf = std.dwarf;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.macho);
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
pub const AbbrevLookupTable = std.AutoHashMap(u64, struct { pos: usize, len: usize });
|
||||
pub const SubprogramLookupByName = std.StringHashMap(struct { addr: u64, size: u64 });
|
||||
|
||||
@ -1,23 +1,3 @@
|
||||
const Dylib = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const fmt = std.fmt;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const fat = @import("fat.zig");
|
||||
const tapi = @import("../tapi.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
const LibStub = tapi.LibStub;
|
||||
const LoadCommandIterator = macho.LoadCommandIterator;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Tbd = tapi.Tbd;
|
||||
|
||||
id: ?Id = null,
|
||||
weak: bool = false,
|
||||
/// Header is only set if Dylib is parsed directly from a binary and not a stub file.
|
||||
@ -546,3 +526,23 @@ pub fn parseFromStub(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Dylib = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const fmt = std.fmt;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const fat = @import("fat.zig");
|
||||
const tapi = @import("../tapi.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
const LibStub = tapi.LibStub;
|
||||
const LoadCommandIterator = macho.LoadCommandIterator;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Tbd = tapi.Tbd;
|
||||
|
||||
@ -2,31 +2,6 @@
|
||||
//! Each Object is fully loaded into memory for easier
|
||||
//! access into different data within.
|
||||
|
||||
const Object = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const build_options = @import("build_options");
|
||||
const assert = std.debug.assert;
|
||||
const dwarf = std.dwarf;
|
||||
const eh_frame = @import("eh_frame.zig");
|
||||
const fs = std.fs;
|
||||
const io = std.io;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const sort = std.sort;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const DwarfInfo = @import("DwarfInfo.zig");
|
||||
const LoadCommandIterator = macho.LoadCommandIterator;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const UnwindInfo = @import("UnwindInfo.zig");
|
||||
const Zld = @import("zld.zig").Zld;
|
||||
|
||||
name: []const u8,
|
||||
mtime: u64,
|
||||
contents: []align(@alignOf(u64)) const u8,
|
||||
@ -359,25 +334,25 @@ fn sectionLessThanByAddress(ctx: void, lhs: SortedSection, rhs: SortedSection) b
|
||||
return lhs.header.addr < rhs.header.addr;
|
||||
}
|
||||
|
||||
pub fn splitIntoAtoms(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
pub fn splitIntoAtoms(self: *Object, macho_file: *MachO, object_id: u32) !void {
|
||||
log.debug("splitting object({d}, {s}) into atoms", .{ object_id, self.name });
|
||||
|
||||
try self.splitRegularSections(zld, object_id);
|
||||
try self.parseEhFrameSection(zld, object_id);
|
||||
try self.parseUnwindInfo(zld, object_id);
|
||||
try self.parseDataInCode(zld.gpa);
|
||||
try self.splitRegularSections(macho_file, object_id);
|
||||
try self.parseEhFrameSection(macho_file, object_id);
|
||||
try self.parseUnwindInfo(macho_file, object_id);
|
||||
try self.parseDataInCode(macho_file.base.allocator);
|
||||
}
|
||||
|
||||
/// Splits input regular sections into Atoms.
|
||||
/// If the Object was compiled with `MH_SUBSECTIONS_VIA_SYMBOLS`, splits section
|
||||
/// into subsections where each subsection then represents an Atom.
|
||||
pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
const gpa = zld.gpa;
|
||||
pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !void {
|
||||
const gpa = macho_file.base.allocator;
|
||||
|
||||
const sections = self.getSourceSections();
|
||||
for (sections, 0..) |sect, id| {
|
||||
if (sect.isDebug()) continue;
|
||||
const out_sect_id = (try Atom.getOutputSection(zld, sect)) orelse {
|
||||
const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse {
|
||||
log.debug(" unhandled section '{s},{s}'", .{ sect.segName(), sect.sectName() });
|
||||
continue;
|
||||
};
|
||||
@ -397,13 +372,13 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
if (self.in_symtab == null) {
|
||||
for (sections, 0..) |sect, id| {
|
||||
if (sect.isDebug()) continue;
|
||||
const out_sect_id = (try Atom.getOutputSection(zld, sect)) orelse continue;
|
||||
const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue;
|
||||
if (sect.size == 0) continue;
|
||||
|
||||
const sect_id = @as(u8, @intCast(id));
|
||||
const sym_index = self.getSectionAliasSymbolIndex(sect_id);
|
||||
const atom_index = try self.createAtomFromSubsection(
|
||||
zld,
|
||||
macho_file,
|
||||
object_id,
|
||||
sym_index,
|
||||
sym_index,
|
||||
@ -412,7 +387,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
sect.@"align",
|
||||
out_sect_id,
|
||||
);
|
||||
zld.addAtomToSection(atom_index);
|
||||
macho_file.addAtomToSection(atom_index);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -456,17 +431,17 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() });
|
||||
|
||||
// Get output segment/section in the final artifact.
|
||||
const out_sect_id = (try Atom.getOutputSection(zld, sect)) orelse continue;
|
||||
const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue;
|
||||
|
||||
log.debug(" output sect({d}, '{s},{s}')", .{
|
||||
out_sect_id + 1,
|
||||
zld.sections.items(.header)[out_sect_id].segName(),
|
||||
zld.sections.items(.header)[out_sect_id].sectName(),
|
||||
macho_file.sections.items(.header)[out_sect_id].segName(),
|
||||
macho_file.sections.items(.header)[out_sect_id].sectName(),
|
||||
});
|
||||
|
||||
try self.parseRelocs(gpa, section.id);
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
const sect_loc = filterSymbolsBySection(symtab[sect_sym_index..], sect_id + 1);
|
||||
const sect_start_index = sect_sym_index + sect_loc.index;
|
||||
|
||||
@ -482,7 +457,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
const sym_index = self.getSectionAliasSymbolIndex(sect_id);
|
||||
const atom_size = first_sym.n_value - sect.addr;
|
||||
const atom_index = try self.createAtomFromSubsection(
|
||||
zld,
|
||||
macho_file,
|
||||
object_id,
|
||||
sym_index,
|
||||
sym_index,
|
||||
@ -492,9 +467,9 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
out_sect_id,
|
||||
);
|
||||
if (!sect.isZerofill()) {
|
||||
try self.cacheRelocs(zld, atom_index);
|
||||
try self.cacheRelocs(macho_file, atom_index);
|
||||
}
|
||||
zld.addAtomToSection(atom_index);
|
||||
macho_file.addAtomToSection(atom_index);
|
||||
}
|
||||
|
||||
var next_sym_index = sect_start_index;
|
||||
@ -518,7 +493,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
sect.@"align";
|
||||
|
||||
const atom_index = try self.createAtomFromSubsection(
|
||||
zld,
|
||||
macho_file,
|
||||
object_id,
|
||||
atom_sym_index,
|
||||
atom_sym_index,
|
||||
@ -537,14 +512,14 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
self.atom_by_index_table[alias_index] = atom_index;
|
||||
}
|
||||
if (!sect.isZerofill()) {
|
||||
try self.cacheRelocs(zld, atom_index);
|
||||
try self.cacheRelocs(macho_file, atom_index);
|
||||
}
|
||||
zld.addAtomToSection(atom_index);
|
||||
macho_file.addAtomToSection(atom_index);
|
||||
}
|
||||
} else {
|
||||
const alias_index = self.getSectionAliasSymbolIndex(sect_id);
|
||||
const atom_index = try self.createAtomFromSubsection(
|
||||
zld,
|
||||
macho_file,
|
||||
object_id,
|
||||
alias_index,
|
||||
sect_start_index,
|
||||
@ -554,16 +529,16 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
out_sect_id,
|
||||
);
|
||||
if (!sect.isZerofill()) {
|
||||
try self.cacheRelocs(zld, atom_index);
|
||||
try self.cacheRelocs(macho_file, atom_index);
|
||||
}
|
||||
zld.addAtomToSection(atom_index);
|
||||
macho_file.addAtomToSection(atom_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn createAtomFromSubsection(
|
||||
self: *Object,
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
object_id: u32,
|
||||
sym_index: u32,
|
||||
inner_sym_index: u32,
|
||||
@ -572,9 +547,9 @@ fn createAtomFromSubsection(
|
||||
alignment: u32,
|
||||
out_sect_id: u8,
|
||||
) !Atom.Index {
|
||||
const gpa = zld.gpa;
|
||||
const atom_index = try zld.createAtom(sym_index, .{ .size = size, .alignment = alignment });
|
||||
const atom = zld.getAtomPtr(atom_index);
|
||||
const gpa = macho_file.base.allocator;
|
||||
const atom_index = try macho_file.createAtom(sym_index, .{ .size = size, .alignment = alignment });
|
||||
const atom = macho_file.getAtomPtr(atom_index);
|
||||
atom.inner_sym_index = inner_sym_index;
|
||||
atom.inner_nsyms_trailing = inner_nsyms_trailing;
|
||||
atom.file = object_id + 1;
|
||||
@ -584,22 +559,22 @@ fn createAtomFromSubsection(
|
||||
sym_index,
|
||||
self.getSymbolName(sym_index),
|
||||
out_sect_id + 1,
|
||||
zld.sections.items(.header)[out_sect_id].segName(),
|
||||
zld.sections.items(.header)[out_sect_id].sectName(),
|
||||
macho_file.sections.items(.header)[out_sect_id].segName(),
|
||||
macho_file.sections.items(.header)[out_sect_id].sectName(),
|
||||
object_id,
|
||||
});
|
||||
|
||||
try self.atoms.append(gpa, atom_index);
|
||||
self.atom_by_index_table[sym_index] = atom_index;
|
||||
|
||||
var it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
while (it.next()) |sym_loc| {
|
||||
const inner = zld.getSymbolPtr(sym_loc);
|
||||
const inner = macho_file.getSymbolPtr(sym_loc);
|
||||
inner.n_sect = out_sect_id + 1;
|
||||
self.atom_by_index_table[sym_loc.sym_index] = atom_index;
|
||||
}
|
||||
|
||||
const out_sect = zld.sections.items(.header)[out_sect_id];
|
||||
const out_sect = macho_file.sections.items(.header)[out_sect_id];
|
||||
if (out_sect.isCode() and
|
||||
mem.eql(u8, "__TEXT", out_sect.segName()) and
|
||||
mem.eql(u8, "__text", out_sect.sectName()))
|
||||
@ -651,8 +626,8 @@ fn parseRelocs(self: *Object, gpa: Allocator, sect_id: u8) !void {
|
||||
self.section_relocs_lookup.items[sect_id] = start;
|
||||
}
|
||||
|
||||
fn cacheRelocs(self: *Object, zld: *Zld, atom_index: Atom.Index) !void {
|
||||
const atom = zld.getAtom(atom_index);
|
||||
fn cacheRelocs(self: *Object, macho_file: *MachO, atom_index: Atom.Index) !void {
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
|
||||
const source_sect_id = if (self.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
|
||||
break :blk source_sym.n_sect - 1;
|
||||
@ -679,19 +654,19 @@ fn relocGreaterThan(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation
|
||||
return lhs.r_address > rhs.r_address;
|
||||
}
|
||||
|
||||
fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
fn parseEhFrameSection(self: *Object, macho_file: *MachO, object_id: u32) !void {
|
||||
const sect_id = self.eh_frame_sect_id orelse return;
|
||||
const sect = self.getSourceSection(sect_id);
|
||||
|
||||
log.debug("parsing __TEXT,__eh_frame section", .{});
|
||||
|
||||
const gpa = zld.gpa;
|
||||
const gpa = macho_file.base.allocator;
|
||||
|
||||
if (zld.eh_frame_section_index == null) {
|
||||
zld.eh_frame_section_index = try MachO.initSection(gpa, zld, "__TEXT", "__eh_frame", .{});
|
||||
if (macho_file.eh_frame_section_index == null) {
|
||||
macho_file.eh_frame_section_index = try macho_file.initSection("__TEXT", "__eh_frame", .{});
|
||||
}
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
try self.parseRelocs(gpa, sect_id);
|
||||
const relocs = self.getRelocs(sect_id);
|
||||
|
||||
@ -729,7 +704,7 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type)) == .ARM64_RELOC_UNSIGNED)
|
||||
break rel;
|
||||
} else unreachable;
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = object_id,
|
||||
.rel = rel,
|
||||
.code = it.data[offset..],
|
||||
@ -744,7 +719,7 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
});
|
||||
const target_sym_index = self.getSymbolByAddress(target_address, null);
|
||||
const target = if (self.getGlobal(target_sym_index)) |global_index|
|
||||
zld.globals.items[global_index]
|
||||
macho_file.globals.items[global_index]
|
||||
else
|
||||
SymbolWithLoc{ .sym_index = target_sym_index, .file = object_id + 1 };
|
||||
break :blk target;
|
||||
@ -770,7 +745,7 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
};
|
||||
log.debug("FDE at offset {x} tracks {s}", .{
|
||||
offset,
|
||||
zld.getSymbolName(actual_target),
|
||||
macho_file.getSymbolName(actual_target),
|
||||
});
|
||||
try self.eh_frame_records_lookup.putNoClobber(gpa, actual_target, offset);
|
||||
}
|
||||
@ -779,19 +754,17 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
const gpa = zld.gpa;
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
fn parseUnwindInfo(self: *Object, macho_file: *MachO, object_id: u32) !void {
|
||||
const gpa = macho_file.base.allocator;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
const sect_id = self.unwind_info_sect_id orelse {
|
||||
// If it so happens that the object had `__eh_frame` section defined but no `__compact_unwind`,
|
||||
// we will try fully synthesising unwind info records to somewhat match Apple ld's
|
||||
// approach. However, we will only synthesise DWARF records and nothing more. For this reason,
|
||||
// we still create the output `__TEXT,__unwind_info` section.
|
||||
if (self.hasEhFrameRecords()) {
|
||||
if (zld.unwind_info_section_index == null) {
|
||||
zld.unwind_info_section_index = try MachO.initSection(
|
||||
gpa,
|
||||
zld,
|
||||
if (macho_file.unwind_info_section_index == null) {
|
||||
macho_file.unwind_info_section_index = try macho_file.initSection(
|
||||
"__TEXT",
|
||||
"__unwind_info",
|
||||
.{},
|
||||
@ -803,8 +776,8 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
|
||||
log.debug("parsing unwind info in {s}", .{self.name});
|
||||
|
||||
if (zld.unwind_info_section_index == null) {
|
||||
zld.unwind_info_section_index = try MachO.initSection(gpa, zld, "__TEXT", "__unwind_info", .{});
|
||||
if (macho_file.unwind_info_section_index == null) {
|
||||
macho_file.unwind_info_section_index = try macho_file.initSection("__TEXT", "__unwind_info", .{});
|
||||
}
|
||||
|
||||
const unwind_records = self.getUnwindRecords();
|
||||
@ -839,7 +812,7 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
|
||||
// Find function symbol that this record describes
|
||||
const rel = relocs[rel_pos.start..][rel_pos.len - 1];
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = object_id,
|
||||
.rel = rel,
|
||||
.code = mem.asBytes(&record),
|
||||
@ -863,7 +836,7 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||
};
|
||||
log.debug("unwind record {d} tracks {s}", .{
|
||||
record_id,
|
||||
zld.getSymbolName(actual_target),
|
||||
macho_file.getSymbolName(actual_target),
|
||||
});
|
||||
try self.unwind_records_lookup.putNoClobber(gpa, actual_target, @intCast(record_id));
|
||||
}
|
||||
@ -1094,3 +1067,27 @@ pub fn getEhFrameRecordsIterator(self: Object) eh_frame.Iterator {
|
||||
pub fn hasDataInCode(self: Object) bool {
|
||||
return self.data_in_code.items.len > 0;
|
||||
}
|
||||
|
||||
const Object = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const build_options = @import("build_options");
|
||||
const assert = std.debug.assert;
|
||||
const dwarf = std.dwarf;
|
||||
const eh_frame = @import("eh_frame.zig");
|
||||
const fs = std.fs;
|
||||
const io = std.io;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const sort = std.sort;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const DwarfInfo = @import("DwarfInfo.zig");
|
||||
const LoadCommandIterator = macho.LoadCommandIterator;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const UnwindInfo = @import("UnwindInfo.zig");
|
||||
|
||||
@ -28,248 +28,6 @@
|
||||
//! After the optional exported symbol information is a byte of how many edges (0-255) that
|
||||
//! this node has leaving it, followed by each edge. Each edge is a zero terminated UTF8 of
|
||||
//! the addition chars in the symbol, followed by a uleb128 offset for the node that edge points to.
|
||||
const Trie = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const testing = std.testing;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
pub const Node = struct {
|
||||
base: *Trie,
|
||||
|
||||
/// Terminal info associated with this node.
|
||||
/// If this node is not a terminal node, info is null.
|
||||
terminal_info: ?struct {
|
||||
/// Export flags associated with this exported symbol.
|
||||
export_flags: u64,
|
||||
/// VM address offset wrt to the section this symbol is defined against.
|
||||
vmaddr_offset: u64,
|
||||
} = null,
|
||||
|
||||
/// Offset of this node in the trie output byte stream.
|
||||
trie_offset: ?u64 = null,
|
||||
|
||||
/// List of all edges originating from this node.
|
||||
edges: std.ArrayListUnmanaged(Edge) = .{},
|
||||
|
||||
node_dirty: bool = true,
|
||||
|
||||
/// Edge connecting to nodes in the trie.
|
||||
pub const Edge = struct {
|
||||
from: *Node,
|
||||
to: *Node,
|
||||
label: []u8,
|
||||
|
||||
fn deinit(self: *Edge, allocator: Allocator) void {
|
||||
self.to.deinit(allocator);
|
||||
allocator.destroy(self.to);
|
||||
allocator.free(self.label);
|
||||
self.from = undefined;
|
||||
self.to = undefined;
|
||||
self.label = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
fn deinit(self: *Node, allocator: Allocator) void {
|
||||
for (self.edges.items) |*edge| {
|
||||
edge.deinit(allocator);
|
||||
}
|
||||
self.edges.deinit(allocator);
|
||||
}
|
||||
|
||||
/// Inserts a new node starting from `self`.
|
||||
fn put(self: *Node, allocator: Allocator, label: []const u8) !*Node {
|
||||
// Check for match with edges from this node.
|
||||
for (self.edges.items) |*edge| {
|
||||
const match = mem.indexOfDiff(u8, edge.label, label) orelse return edge.to;
|
||||
if (match == 0) continue;
|
||||
if (match == edge.label.len) return edge.to.put(allocator, label[match..]);
|
||||
|
||||
// Found a match, need to splice up nodes.
|
||||
// From: A -> B
|
||||
// To: A -> C -> B
|
||||
const mid = try allocator.create(Node);
|
||||
mid.* = .{ .base = self.base };
|
||||
var to_label = try allocator.dupe(u8, edge.label[match..]);
|
||||
allocator.free(edge.label);
|
||||
const to_node = edge.to;
|
||||
edge.to = mid;
|
||||
edge.label = try allocator.dupe(u8, label[0..match]);
|
||||
self.base.node_count += 1;
|
||||
|
||||
try mid.edges.append(allocator, .{
|
||||
.from = mid,
|
||||
.to = to_node,
|
||||
.label = to_label,
|
||||
});
|
||||
|
||||
return if (match == label.len) mid else mid.put(allocator, label[match..]);
|
||||
}
|
||||
|
||||
// Add a new node.
|
||||
const node = try allocator.create(Node);
|
||||
node.* = .{ .base = self.base };
|
||||
self.base.node_count += 1;
|
||||
|
||||
try self.edges.append(allocator, .{
|
||||
.from = self,
|
||||
.to = node,
|
||||
.label = try allocator.dupe(u8, label),
|
||||
});
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/// Recursively parses the node from the input byte stream.
|
||||
fn read(self: *Node, allocator: Allocator, reader: anytype) Trie.ReadError!usize {
|
||||
self.node_dirty = true;
|
||||
const trie_offset = try reader.context.getPos();
|
||||
self.trie_offset = trie_offset;
|
||||
|
||||
var nread: usize = 0;
|
||||
|
||||
const node_size = try leb.readULEB128(u64, reader);
|
||||
if (node_size > 0) {
|
||||
const export_flags = try leb.readULEB128(u64, reader);
|
||||
// TODO Parse special flags.
|
||||
assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
|
||||
export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
|
||||
|
||||
const vmaddr_offset = try leb.readULEB128(u64, reader);
|
||||
|
||||
self.terminal_info = .{
|
||||
.export_flags = export_flags,
|
||||
.vmaddr_offset = vmaddr_offset,
|
||||
};
|
||||
}
|
||||
|
||||
const nedges = try reader.readByte();
|
||||
self.base.node_count += nedges;
|
||||
|
||||
nread += (try reader.context.getPos()) - trie_offset;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < nedges) : (i += 1) {
|
||||
const edge_start_pos = try reader.context.getPos();
|
||||
|
||||
const label = blk: {
|
||||
var label_buf = std.ArrayList(u8).init(allocator);
|
||||
while (true) {
|
||||
const next = try reader.readByte();
|
||||
if (next == @as(u8, 0))
|
||||
break;
|
||||
try label_buf.append(next);
|
||||
}
|
||||
break :blk try label_buf.toOwnedSlice();
|
||||
};
|
||||
|
||||
const seek_to = try leb.readULEB128(u64, reader);
|
||||
const return_pos = try reader.context.getPos();
|
||||
|
||||
nread += return_pos - edge_start_pos;
|
||||
try reader.context.seekTo(seek_to);
|
||||
|
||||
const node = try allocator.create(Node);
|
||||
node.* = .{ .base = self.base };
|
||||
|
||||
nread += try node.read(allocator, reader);
|
||||
try self.edges.append(allocator, .{
|
||||
.from = self,
|
||||
.to = node,
|
||||
.label = label,
|
||||
});
|
||||
try reader.context.seekTo(return_pos);
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
/// Writes this node to a byte stream.
|
||||
/// The children of this node *are* not written to the byte stream
|
||||
/// recursively. To write all nodes to a byte stream in sequence,
|
||||
/// iterate over `Trie.ordered_nodes` and call this method on each node.
|
||||
/// This is one of the requirements of the MachO.
|
||||
/// Panics if `finalize` was not called before calling this method.
|
||||
fn write(self: Node, writer: anytype) !void {
|
||||
assert(!self.node_dirty);
|
||||
if (self.terminal_info) |info| {
|
||||
// Terminal node info: encode export flags and vmaddr offset of this symbol.
|
||||
var info_buf: [@sizeOf(u64) * 2]u8 = undefined;
|
||||
var info_stream = std.io.fixedBufferStream(&info_buf);
|
||||
// TODO Implement for special flags.
|
||||
assert(info.export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
|
||||
info.export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
|
||||
try leb.writeULEB128(info_stream.writer(), info.export_flags);
|
||||
try leb.writeULEB128(info_stream.writer(), info.vmaddr_offset);
|
||||
|
||||
// Encode the size of the terminal node info.
|
||||
var size_buf: [@sizeOf(u64)]u8 = undefined;
|
||||
var size_stream = std.io.fixedBufferStream(&size_buf);
|
||||
try leb.writeULEB128(size_stream.writer(), info_stream.pos);
|
||||
|
||||
// Now, write them to the output stream.
|
||||
try writer.writeAll(size_buf[0..size_stream.pos]);
|
||||
try writer.writeAll(info_buf[0..info_stream.pos]);
|
||||
} else {
|
||||
// Non-terminal node is delimited by 0 byte.
|
||||
try writer.writeByte(0);
|
||||
}
|
||||
// Write number of edges (max legal number of edges is 256).
|
||||
try writer.writeByte(@as(u8, @intCast(self.edges.items.len)));
|
||||
|
||||
for (self.edges.items) |edge| {
|
||||
// Write edge label and offset to next node in trie.
|
||||
try writer.writeAll(edge.label);
|
||||
try writer.writeByte(0);
|
||||
try leb.writeULEB128(writer, edge.to.trie_offset.?);
|
||||
}
|
||||
}
|
||||
|
||||
const FinalizeResult = struct {
|
||||
/// Current size of this node in bytes.
|
||||
node_size: u64,
|
||||
|
||||
/// True if the trie offset of this node in the output byte stream
|
||||
/// would need updating; false otherwise.
|
||||
updated: bool,
|
||||
};
|
||||
|
||||
/// Updates offset of this node in the output byte stream.
|
||||
fn finalize(self: *Node, offset_in_trie: u64) !FinalizeResult {
|
||||
var stream = std.io.countingWriter(std.io.null_writer);
|
||||
var writer = stream.writer();
|
||||
|
||||
var node_size: u64 = 0;
|
||||
if (self.terminal_info) |info| {
|
||||
try leb.writeULEB128(writer, info.export_flags);
|
||||
try leb.writeULEB128(writer, info.vmaddr_offset);
|
||||
try leb.writeULEB128(writer, stream.bytes_written);
|
||||
} else {
|
||||
node_size += 1; // 0x0 for non-terminal nodes
|
||||
}
|
||||
node_size += 1; // 1 byte for edge count
|
||||
|
||||
for (self.edges.items) |edge| {
|
||||
const next_node_offset = edge.to.trie_offset orelse 0;
|
||||
node_size += edge.label.len + 1;
|
||||
try leb.writeULEB128(writer, next_node_offset);
|
||||
}
|
||||
|
||||
const trie_offset = self.trie_offset orelse 0;
|
||||
const updated = offset_in_trie != trie_offset;
|
||||
self.trie_offset = offset_in_trie;
|
||||
self.node_dirty = false;
|
||||
node_size += stream.bytes_written;
|
||||
|
||||
return FinalizeResult{ .node_size = node_size, .updated = updated };
|
||||
}
|
||||
};
|
||||
|
||||
/// The root node of the trie.
|
||||
root: ?*Node = null,
|
||||
|
||||
@ -611,3 +369,245 @@ test "ordering bug" {
|
||||
_ = try trie.write(stream.writer());
|
||||
try expectEqualHexStrings(&exp_buffer, buffer);
|
||||
}
|
||||
|
||||
pub const Node = struct {
|
||||
base: *Trie,
|
||||
|
||||
/// Terminal info associated with this node.
|
||||
/// If this node is not a terminal node, info is null.
|
||||
terminal_info: ?struct {
|
||||
/// Export flags associated with this exported symbol.
|
||||
export_flags: u64,
|
||||
/// VM address offset wrt to the section this symbol is defined against.
|
||||
vmaddr_offset: u64,
|
||||
} = null,
|
||||
|
||||
/// Offset of this node in the trie output byte stream.
|
||||
trie_offset: ?u64 = null,
|
||||
|
||||
/// List of all edges originating from this node.
|
||||
edges: std.ArrayListUnmanaged(Edge) = .{},
|
||||
|
||||
node_dirty: bool = true,
|
||||
|
||||
/// Edge connecting to nodes in the trie.
|
||||
pub const Edge = struct {
|
||||
from: *Node,
|
||||
to: *Node,
|
||||
label: []u8,
|
||||
|
||||
fn deinit(self: *Edge, allocator: Allocator) void {
|
||||
self.to.deinit(allocator);
|
||||
allocator.destroy(self.to);
|
||||
allocator.free(self.label);
|
||||
self.from = undefined;
|
||||
self.to = undefined;
|
||||
self.label = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
fn deinit(self: *Node, allocator: Allocator) void {
|
||||
for (self.edges.items) |*edge| {
|
||||
edge.deinit(allocator);
|
||||
}
|
||||
self.edges.deinit(allocator);
|
||||
}
|
||||
|
||||
/// Inserts a new node starting from `self`.
|
||||
fn put(self: *Node, allocator: Allocator, label: []const u8) !*Node {
|
||||
// Check for match with edges from this node.
|
||||
for (self.edges.items) |*edge| {
|
||||
const match = mem.indexOfDiff(u8, edge.label, label) orelse return edge.to;
|
||||
if (match == 0) continue;
|
||||
if (match == edge.label.len) return edge.to.put(allocator, label[match..]);
|
||||
|
||||
// Found a match, need to splice up nodes.
|
||||
// From: A -> B
|
||||
// To: A -> C -> B
|
||||
const mid = try allocator.create(Node);
|
||||
mid.* = .{ .base = self.base };
|
||||
var to_label = try allocator.dupe(u8, edge.label[match..]);
|
||||
allocator.free(edge.label);
|
||||
const to_node = edge.to;
|
||||
edge.to = mid;
|
||||
edge.label = try allocator.dupe(u8, label[0..match]);
|
||||
self.base.node_count += 1;
|
||||
|
||||
try mid.edges.append(allocator, .{
|
||||
.from = mid,
|
||||
.to = to_node,
|
||||
.label = to_label,
|
||||
});
|
||||
|
||||
return if (match == label.len) mid else mid.put(allocator, label[match..]);
|
||||
}
|
||||
|
||||
// Add a new node.
|
||||
const node = try allocator.create(Node);
|
||||
node.* = .{ .base = self.base };
|
||||
self.base.node_count += 1;
|
||||
|
||||
try self.edges.append(allocator, .{
|
||||
.from = self,
|
||||
.to = node,
|
||||
.label = try allocator.dupe(u8, label),
|
||||
});
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/// Recursively parses the node from the input byte stream.
|
||||
fn read(self: *Node, allocator: Allocator, reader: anytype) Trie.ReadError!usize {
|
||||
self.node_dirty = true;
|
||||
const trie_offset = try reader.context.getPos();
|
||||
self.trie_offset = trie_offset;
|
||||
|
||||
var nread: usize = 0;
|
||||
|
||||
const node_size = try leb.readULEB128(u64, reader);
|
||||
if (node_size > 0) {
|
||||
const export_flags = try leb.readULEB128(u64, reader);
|
||||
// TODO Parse special flags.
|
||||
assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
|
||||
export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
|
||||
|
||||
const vmaddr_offset = try leb.readULEB128(u64, reader);
|
||||
|
||||
self.terminal_info = .{
|
||||
.export_flags = export_flags,
|
||||
.vmaddr_offset = vmaddr_offset,
|
||||
};
|
||||
}
|
||||
|
||||
const nedges = try reader.readByte();
|
||||
self.base.node_count += nedges;
|
||||
|
||||
nread += (try reader.context.getPos()) - trie_offset;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < nedges) : (i += 1) {
|
||||
const edge_start_pos = try reader.context.getPos();
|
||||
|
||||
const label = blk: {
|
||||
var label_buf = std.ArrayList(u8).init(allocator);
|
||||
while (true) {
|
||||
const next = try reader.readByte();
|
||||
if (next == @as(u8, 0))
|
||||
break;
|
||||
try label_buf.append(next);
|
||||
}
|
||||
break :blk try label_buf.toOwnedSlice();
|
||||
};
|
||||
|
||||
const seek_to = try leb.readULEB128(u64, reader);
|
||||
const return_pos = try reader.context.getPos();
|
||||
|
||||
nread += return_pos - edge_start_pos;
|
||||
try reader.context.seekTo(seek_to);
|
||||
|
||||
const node = try allocator.create(Node);
|
||||
node.* = .{ .base = self.base };
|
||||
|
||||
nread += try node.read(allocator, reader);
|
||||
try self.edges.append(allocator, .{
|
||||
.from = self,
|
||||
.to = node,
|
||||
.label = label,
|
||||
});
|
||||
try reader.context.seekTo(return_pos);
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
/// Writes this node to a byte stream.
|
||||
/// The children of this node *are* not written to the byte stream
|
||||
/// recursively. To write all nodes to a byte stream in sequence,
|
||||
/// iterate over `Trie.ordered_nodes` and call this method on each node.
|
||||
/// This is one of the requirements of the MachO.
|
||||
/// Panics if `finalize` was not called before calling this method.
|
||||
fn write(self: Node, writer: anytype) !void {
|
||||
assert(!self.node_dirty);
|
||||
if (self.terminal_info) |info| {
|
||||
// Terminal node info: encode export flags and vmaddr offset of this symbol.
|
||||
var info_buf: [@sizeOf(u64) * 2]u8 = undefined;
|
||||
var info_stream = std.io.fixedBufferStream(&info_buf);
|
||||
// TODO Implement for special flags.
|
||||
assert(info.export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
|
||||
info.export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
|
||||
try leb.writeULEB128(info_stream.writer(), info.export_flags);
|
||||
try leb.writeULEB128(info_stream.writer(), info.vmaddr_offset);
|
||||
|
||||
// Encode the size of the terminal node info.
|
||||
var size_buf: [@sizeOf(u64)]u8 = undefined;
|
||||
var size_stream = std.io.fixedBufferStream(&size_buf);
|
||||
try leb.writeULEB128(size_stream.writer(), info_stream.pos);
|
||||
|
||||
// Now, write them to the output stream.
|
||||
try writer.writeAll(size_buf[0..size_stream.pos]);
|
||||
try writer.writeAll(info_buf[0..info_stream.pos]);
|
||||
} else {
|
||||
// Non-terminal node is delimited by 0 byte.
|
||||
try writer.writeByte(0);
|
||||
}
|
||||
// Write number of edges (max legal number of edges is 256).
|
||||
try writer.writeByte(@as(u8, @intCast(self.edges.items.len)));
|
||||
|
||||
for (self.edges.items) |edge| {
|
||||
// Write edge label and offset to next node in trie.
|
||||
try writer.writeAll(edge.label);
|
||||
try writer.writeByte(0);
|
||||
try leb.writeULEB128(writer, edge.to.trie_offset.?);
|
||||
}
|
||||
}
|
||||
|
||||
const FinalizeResult = struct {
|
||||
/// Current size of this node in bytes.
|
||||
node_size: u64,
|
||||
|
||||
/// True if the trie offset of this node in the output byte stream
|
||||
/// would need updating; false otherwise.
|
||||
updated: bool,
|
||||
};
|
||||
|
||||
/// Updates offset of this node in the output byte stream.
|
||||
fn finalize(self: *Node, offset_in_trie: u64) !FinalizeResult {
|
||||
var stream = std.io.countingWriter(std.io.null_writer);
|
||||
var writer = stream.writer();
|
||||
|
||||
var node_size: u64 = 0;
|
||||
if (self.terminal_info) |info| {
|
||||
try leb.writeULEB128(writer, info.export_flags);
|
||||
try leb.writeULEB128(writer, info.vmaddr_offset);
|
||||
try leb.writeULEB128(writer, stream.bytes_written);
|
||||
} else {
|
||||
node_size += 1; // 0x0 for non-terminal nodes
|
||||
}
|
||||
node_size += 1; // 1 byte for edge count
|
||||
|
||||
for (self.edges.items) |edge| {
|
||||
const next_node_offset = edge.to.trie_offset orelse 0;
|
||||
node_size += edge.label.len + 1;
|
||||
try leb.writeULEB128(writer, next_node_offset);
|
||||
}
|
||||
|
||||
const trie_offset = self.trie_offset orelse 0;
|
||||
const updated = offset_in_trie != trie_offset;
|
||||
self.trie_offset = offset_in_trie;
|
||||
self.node_dirty = false;
|
||||
node_size += stream.bytes_written;
|
||||
|
||||
return FinalizeResult{ .node_size = node_size, .updated = updated };
|
||||
}
|
||||
};
|
||||
|
||||
const Trie = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const testing = std.testing;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
@ -1,25 +1,3 @@
|
||||
const UnwindInfo = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const eh_frame = @import("eh_frame.zig");
|
||||
const fs = std.fs;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.unwind_info);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const AtomIndex = @import("zld.zig").AtomIndex;
|
||||
const EhFrameRecord = eh_frame.EhFrameRecord;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const Zld = @import("zld.zig").Zld;
|
||||
|
||||
gpa: Allocator,
|
||||
|
||||
/// List of all unwind records gathered from all objects and sorted
|
||||
@ -203,28 +181,28 @@ pub fn deinit(info: *UnwindInfo) void {
|
||||
info.lsdas_lookup.deinit(info.gpa);
|
||||
}
|
||||
|
||||
pub fn scanRelocs(zld: *Zld) !void {
|
||||
if (zld.unwind_info_section_index == null) return;
|
||||
pub fn scanRelocs(macho_file: *MachO) !void {
|
||||
if (macho_file.unwind_info_section_index == null) return;
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
for (zld.objects.items, 0..) |*object, object_id| {
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
for (macho_file.objects.items, 0..) |*object, object_id| {
|
||||
const unwind_records = object.getUnwindRecords();
|
||||
for (object.exec_atoms.items) |atom_index| {
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
while (inner_syms_it.next()) |sym| {
|
||||
const record_id = object.unwind_records_lookup.get(sym) orelse continue;
|
||||
if (object.unwind_relocs_lookup[record_id].dead) continue;
|
||||
const record = unwind_records[record_id];
|
||||
if (!UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
|
||||
if (getPersonalityFunctionReloc(zld, @as(u32, @intCast(object_id)), record_id)) |rel| {
|
||||
if (getPersonalityFunctionReloc(macho_file, @as(u32, @intCast(object_id)), record_id)) |rel| {
|
||||
// Personality function; add GOT pointer.
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = @as(u32, @intCast(object_id)),
|
||||
.rel = rel,
|
||||
.code = mem.asBytes(&record),
|
||||
.base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
|
||||
});
|
||||
try zld.addGotEntry(target);
|
||||
try macho_file.addGotEntry(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,10 +210,10 @@ pub fn scanRelocs(zld: *Zld) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
if (zld.unwind_info_section_index == null) return;
|
||||
pub fn collect(info: *UnwindInfo, macho_file: *MachO) !void {
|
||||
if (macho_file.unwind_info_section_index == null) return;
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
|
||||
var records = std.ArrayList(macho.compact_unwind_entry).init(info.gpa);
|
||||
defer records.deinit();
|
||||
@ -244,7 +222,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
defer sym_indexes.deinit();
|
||||
|
||||
// TODO handle dead stripping
|
||||
for (zld.objects.items, 0..) |*object, object_id| {
|
||||
for (macho_file.objects.items, 0..) |*object, object_id| {
|
||||
log.debug("collecting unwind records in {s} ({d})", .{ object.name, object_id });
|
||||
const unwind_records = object.getUnwindRecords();
|
||||
|
||||
@ -254,7 +232,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
try sym_indexes.ensureUnusedCapacity(object.exec_atoms.items.len);
|
||||
|
||||
for (object.exec_atoms.items) |atom_index| {
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
var prev_symbol: ?SymbolWithLoc = null;
|
||||
while (inner_syms_it.next()) |symbol| {
|
||||
var record = if (object.unwind_records_lookup.get(symbol)) |record_id| blk: {
|
||||
@ -262,14 +240,14 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
var record = unwind_records[record_id];
|
||||
|
||||
if (UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
|
||||
try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), symbol, &record);
|
||||
try info.collectPersonalityFromDwarf(macho_file, @as(u32, @intCast(object_id)), symbol, &record);
|
||||
} else {
|
||||
if (getPersonalityFunctionReloc(
|
||||
zld,
|
||||
macho_file,
|
||||
@as(u32, @intCast(object_id)),
|
||||
record_id,
|
||||
)) |rel| {
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = @as(u32, @intCast(object_id)),
|
||||
.rel = rel,
|
||||
.code = mem.asBytes(&record),
|
||||
@ -286,8 +264,8 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
UnwindEncoding.setPersonalityIndex(&record.compactUnwindEncoding, personality_index + 1);
|
||||
}
|
||||
|
||||
if (getLsdaReloc(zld, @as(u32, @intCast(object_id)), record_id)) |rel| {
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
if (getLsdaReloc(macho_file, @as(u32, @intCast(object_id)), record_id)) |rel| {
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = @as(u32, @intCast(object_id)),
|
||||
.rel = rel,
|
||||
.code = mem.asBytes(&record),
|
||||
@ -298,7 +276,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
}
|
||||
break :blk record;
|
||||
} else blk: {
|
||||
const sym = zld.getSymbol(symbol);
|
||||
const sym = macho_file.getSymbol(symbol);
|
||||
if (sym.n_desc == MachO.N_DEAD) continue;
|
||||
if (prev_symbol) |prev_sym| {
|
||||
const prev_addr = object.getSourceSymbol(prev_sym.sym_index).?.n_value;
|
||||
@ -310,7 +288,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
if (object.eh_frame_records_lookup.get(symbol)) |fde_offset| {
|
||||
if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue;
|
||||
var record = nullRecord();
|
||||
try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), symbol, &record);
|
||||
try info.collectPersonalityFromDwarf(macho_file, @as(u32, @intCast(object_id)), symbol, &record);
|
||||
switch (cpu_arch) {
|
||||
.aarch64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_ARM64_MODE.DWARF),
|
||||
.x86_64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_X86_64_MODE.DWARF),
|
||||
@ -323,8 +301,8 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
break :blk nullRecord();
|
||||
};
|
||||
|
||||
const atom = zld.getAtom(atom_index);
|
||||
const sym = zld.getSymbol(symbol);
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
const sym = macho_file.getSymbol(symbol);
|
||||
assert(sym.n_desc != MachO.N_DEAD);
|
||||
const size = if (inner_syms_it.next()) |next_sym| blk: {
|
||||
// All this trouble to account for symbol aliases.
|
||||
@ -336,8 +314,8 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
const curr_addr = object.getSourceSymbol(symbol.sym_index).?.n_value;
|
||||
const next_addr = object.getSourceSymbol(next_sym.sym_index).?.n_value;
|
||||
if (next_addr > curr_addr) break :blk next_addr - curr_addr;
|
||||
break :blk zld.getSymbol(atom.getSymbolWithLoc()).n_value + atom.size - sym.n_value;
|
||||
} else zld.getSymbol(atom.getSymbolWithLoc()).n_value + atom.size - sym.n_value;
|
||||
break :blk macho_file.getSymbol(atom.getSymbolWithLoc()).n_value + atom.size - sym.n_value;
|
||||
} else macho_file.getSymbol(atom.getSymbolWithLoc()).n_value + atom.size - sym.n_value;
|
||||
record.rangeStart = sym.n_value;
|
||||
record.rangeLength = @as(u32, @intCast(size));
|
||||
|
||||
@ -518,23 +496,23 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
|
||||
|
||||
fn collectPersonalityFromDwarf(
|
||||
info: *UnwindInfo,
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
object_id: u32,
|
||||
sym_loc: SymbolWithLoc,
|
||||
record: *macho.compact_unwind_entry,
|
||||
) !void {
|
||||
const object = &zld.objects.items[object_id];
|
||||
const object = &macho_file.objects.items[object_id];
|
||||
var it = object.getEhFrameRecordsIterator();
|
||||
const fde_offset = object.eh_frame_records_lookup.get(sym_loc).?;
|
||||
it.seekTo(fde_offset);
|
||||
const fde = (try it.next()).?;
|
||||
const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset);
|
||||
const cie_ptr = fde.getCiePointerSource(object_id, macho_file, fde_offset);
|
||||
const cie_offset = fde_offset + 4 - cie_ptr;
|
||||
it.seekTo(cie_offset);
|
||||
const cie = (try it.next()).?;
|
||||
|
||||
if (cie.getPersonalityPointerReloc(
|
||||
zld,
|
||||
macho_file,
|
||||
@as(u32, @intCast(object_id)),
|
||||
cie_offset,
|
||||
)) |target| {
|
||||
@ -550,9 +528,9 @@ fn collectPersonalityFromDwarf(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calcSectionSize(info: UnwindInfo, zld: *Zld) !void {
|
||||
const sect_id = zld.unwind_info_section_index orelse return;
|
||||
const sect = &zld.sections.items(.header)[sect_id];
|
||||
pub fn calcSectionSize(info: UnwindInfo, macho_file: *MachO) !void {
|
||||
const sect_id = macho_file.unwind_info_section_index orelse return;
|
||||
const sect = &macho_file.sections.items(.header)[sect_id];
|
||||
sect.@"align" = 2;
|
||||
sect.size = info.calcRequiredSize();
|
||||
}
|
||||
@ -569,23 +547,23 @@ fn calcRequiredSize(info: UnwindInfo) usize {
|
||||
return total_size;
|
||||
}
|
||||
|
||||
pub fn write(info: *UnwindInfo, zld: *Zld) !void {
|
||||
const sect_id = zld.unwind_info_section_index orelse return;
|
||||
const sect = &zld.sections.items(.header)[sect_id];
|
||||
const seg_id = zld.sections.items(.segment_index)[sect_id];
|
||||
const seg = zld.segments.items[seg_id];
|
||||
pub fn write(info: *UnwindInfo, macho_file: *MachO) !void {
|
||||
const sect_id = macho_file.unwind_info_section_index orelse return;
|
||||
const sect = &macho_file.sections.items(.header)[sect_id];
|
||||
const seg_id = macho_file.sections.items(.segment_index)[sect_id];
|
||||
const seg = macho_file.segments.items[seg_id];
|
||||
|
||||
const text_sect_id = zld.text_section_index.?;
|
||||
const text_sect = zld.sections.items(.header)[text_sect_id];
|
||||
const text_sect_id = macho_file.text_section_index.?;
|
||||
const text_sect = macho_file.sections.items(.header)[text_sect_id];
|
||||
|
||||
var personalities: [max_personalities]u32 = undefined;
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
|
||||
log.debug("Personalities:", .{});
|
||||
for (info.personalities[0..info.personalities_count], 0..) |target, i| {
|
||||
const addr = zld.getGotEntryAddress(target).?;
|
||||
const addr = macho_file.getGotEntryAddress(target).?;
|
||||
personalities[i] = @as(u32, @intCast(addr - seg.vmaddr));
|
||||
log.debug(" {d}: 0x{x} ({s})", .{ i, personalities[i], zld.getSymbolName(target) });
|
||||
log.debug(" {d}: 0x{x} ({s})", .{ i, personalities[i], macho_file.getSymbolName(target) });
|
||||
}
|
||||
|
||||
for (info.records.items) |*rec| {
|
||||
@ -599,7 +577,7 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {
|
||||
if (rec.compactUnwindEncoding > 0 and !UnwindEncoding.isDwarf(rec.compactUnwindEncoding, cpu_arch)) {
|
||||
const lsda_target = @as(SymbolWithLoc, @bitCast(rec.lsda));
|
||||
if (lsda_target.getFile()) |_| {
|
||||
const sym = zld.getSymbol(lsda_target);
|
||||
const sym = macho_file.getSymbol(lsda_target);
|
||||
rec.lsda = sym.n_value - seg.vmaddr;
|
||||
}
|
||||
}
|
||||
@ -689,11 +667,11 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {
|
||||
@memset(buffer.items[offset..], 0);
|
||||
}
|
||||
|
||||
try zld.file.pwriteAll(buffer.items, sect.offset);
|
||||
try macho_file.base.file.?.pwriteAll(buffer.items, sect.offset);
|
||||
}
|
||||
|
||||
fn getRelocs(zld: *Zld, object_id: u32, record_id: usize) []const macho.relocation_info {
|
||||
const object = &zld.objects.items[object_id];
|
||||
fn getRelocs(macho_file: *MachO, object_id: u32, record_id: usize) []const macho.relocation_info {
|
||||
const object = &macho_file.objects.items[object_id];
|
||||
assert(object.hasUnwindRecords());
|
||||
const rel_pos = object.unwind_relocs_lookup[record_id].reloc;
|
||||
const relocs = object.getRelocs(object.unwind_info_sect_id.?);
|
||||
@ -707,11 +685,11 @@ fn isPersonalityFunction(record_id: usize, rel: macho.relocation_info) bool {
|
||||
}
|
||||
|
||||
pub fn getPersonalityFunctionReloc(
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
object_id: u32,
|
||||
record_id: usize,
|
||||
) ?macho.relocation_info {
|
||||
const relocs = getRelocs(zld, object_id, record_id);
|
||||
const relocs = getRelocs(macho_file, object_id, record_id);
|
||||
for (relocs) |rel| {
|
||||
if (isPersonalityFunction(record_id, rel)) return rel;
|
||||
}
|
||||
@ -735,8 +713,8 @@ fn isLsda(record_id: usize, rel: macho.relocation_info) bool {
|
||||
return rel_offset == 24;
|
||||
}
|
||||
|
||||
pub fn getLsdaReloc(zld: *Zld, object_id: u32, record_id: usize) ?macho.relocation_info {
|
||||
const relocs = getRelocs(zld, object_id, record_id);
|
||||
pub fn getLsdaReloc(macho_file: *MachO, object_id: u32, record_id: usize) ?macho.relocation_info {
|
||||
const relocs = getRelocs(macho_file, object_id, record_id);
|
||||
for (relocs) |rel| {
|
||||
if (isLsda(record_id, rel)) return rel;
|
||||
}
|
||||
@ -828,3 +806,23 @@ pub const UnwindEncoding = struct {
|
||||
enc.* |= offset;
|
||||
}
|
||||
};
|
||||
|
||||
const UnwindInfo = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const eh_frame = @import("eh_frame.zig");
|
||||
const fs = std.fs;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.unwind_info);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const EhFrameRecord = eh_frame.EhFrameRecord;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
|
||||
@ -1,89 +1,72 @@
|
||||
//! An algorithm for dead stripping of unreferenced Atoms.
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const eh_frame = @import("eh_frame.zig");
|
||||
const log = std.log.scoped(.dead_strip);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const UnwindInfo = @import("UnwindInfo.zig");
|
||||
const Zld = @import("zld.zig").Zld;
|
||||
|
||||
const AtomTable = std.AutoHashMap(Atom.Index, void);
|
||||
|
||||
pub fn gcAtoms(zld: *Zld) !void {
|
||||
const gpa = zld.gpa;
|
||||
pub fn gcAtoms(macho_file: *MachO) !void {
|
||||
const gpa = macho_file.base.allocator;
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||
defer arena.deinit();
|
||||
|
||||
var roots = AtomTable.init(arena.allocator());
|
||||
try roots.ensureUnusedCapacity(@as(u32, @intCast(zld.globals.items.len)));
|
||||
try roots.ensureUnusedCapacity(@as(u32, @intCast(macho_file.globals.items.len)));
|
||||
|
||||
var alive = AtomTable.init(arena.allocator());
|
||||
try alive.ensureTotalCapacity(@as(u32, @intCast(zld.atoms.items.len)));
|
||||
try alive.ensureTotalCapacity(@as(u32, @intCast(macho_file.atoms.items.len)));
|
||||
|
||||
try collectRoots(zld, &roots);
|
||||
try mark(zld, roots, &alive);
|
||||
prune(zld, alive);
|
||||
try collectRoots(macho_file, &roots);
|
||||
try mark(macho_file, roots, &alive);
|
||||
prune(macho_file, alive);
|
||||
}
|
||||
|
||||
fn addRoot(zld: *Zld, roots: *AtomTable, file: u32, sym_loc: SymbolWithLoc) !void {
|
||||
const sym = zld.getSymbol(sym_loc);
|
||||
fn addRoot(macho_file: *MachO, roots: *AtomTable, file: u32, sym_loc: SymbolWithLoc) !void {
|
||||
const sym = macho_file.getSymbol(sym_loc);
|
||||
assert(!sym.undf());
|
||||
const object = &zld.objects.items[file];
|
||||
const object = &macho_file.objects.items[file];
|
||||
const atom_index = object.getAtomIndexForSymbol(sym_loc.sym_index).?; // panic here means fatal error
|
||||
log.debug("root(ATOM({d}, %{d}, {d}))", .{
|
||||
atom_index,
|
||||
zld.getAtom(atom_index).sym_index,
|
||||
macho_file.getAtom(atom_index).sym_index,
|
||||
file,
|
||||
});
|
||||
_ = try roots.getOrPut(atom_index);
|
||||
}
|
||||
|
||||
fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
|
||||
fn collectRoots(macho_file: *MachO, roots: *AtomTable) !void {
|
||||
log.debug("collecting roots", .{});
|
||||
|
||||
switch (zld.options.output_mode) {
|
||||
switch (macho_file.base.options.output_mode) {
|
||||
.Exe => {
|
||||
// Add entrypoint as GC root
|
||||
const global: SymbolWithLoc = zld.getEntryPoint();
|
||||
const global: SymbolWithLoc = macho_file.getEntryPoint();
|
||||
if (global.getFile()) |file| {
|
||||
try addRoot(zld, roots, file, global);
|
||||
try addRoot(macho_file, roots, file, global);
|
||||
} else {
|
||||
assert(zld.getSymbol(global).undf()); // Stub as our entrypoint is in a dylib.
|
||||
assert(macho_file.getSymbol(global).undf()); // Stub as our entrypoint is in a dylib.
|
||||
}
|
||||
},
|
||||
else => |other| {
|
||||
assert(other == .Lib);
|
||||
// Add exports as GC roots
|
||||
for (zld.globals.items) |global| {
|
||||
const sym = zld.getSymbol(global);
|
||||
for (macho_file.globals.items) |global| {
|
||||
const sym = macho_file.getSymbol(global);
|
||||
if (sym.undf()) continue;
|
||||
|
||||
if (global.getFile()) |file| {
|
||||
try addRoot(zld, roots, file, global);
|
||||
try addRoot(macho_file, roots, file, global);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Add all symbols force-defined by the user.
|
||||
for (zld.options.force_undefined_symbols.keys()) |sym_name| {
|
||||
const global_index = zld.resolver.get(sym_name).?;
|
||||
const global = zld.globals.items[global_index];
|
||||
const sym = zld.getSymbol(global);
|
||||
for (macho_file.base.options.force_undefined_symbols.keys()) |sym_name| {
|
||||
const global_index = macho_file.resolver.get(sym_name).?;
|
||||
const global = macho_file.globals.items[global_index];
|
||||
const sym = macho_file.getSymbol(global);
|
||||
assert(!sym.undf());
|
||||
try addRoot(zld, roots, global.getFile().?, global);
|
||||
try addRoot(macho_file, roots, global.getFile().?, global);
|
||||
}
|
||||
|
||||
for (zld.objects.items) |object| {
|
||||
for (macho_file.objects.items) |object| {
|
||||
const has_subsections = object.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
|
||||
|
||||
for (object.atoms.items) |atom_index| {
|
||||
@ -92,7 +75,7 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
|
||||
// as a root.
|
||||
if (!has_subsections) break :blk true;
|
||||
|
||||
const atom = zld.getAtom(atom_index);
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
const sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym|
|
||||
source_sym.n_sect - 1
|
||||
else sect_id: {
|
||||
@ -115,39 +98,39 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
|
||||
|
||||
log.debug("root(ATOM({d}, %{d}, {?d}))", .{
|
||||
atom_index,
|
||||
zld.getAtom(atom_index).sym_index,
|
||||
zld.getAtom(atom_index).getFile(),
|
||||
macho_file.getAtom(atom_index).sym_index,
|
||||
macho_file.getAtom(atom_index).getFile(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn markLive(zld: *Zld, atom_index: Atom.Index, alive: *AtomTable) void {
|
||||
fn markLive(macho_file: *MachO, atom_index: Atom.Index, alive: *AtomTable) void {
|
||||
if (alive.contains(atom_index)) return;
|
||||
|
||||
const atom = zld.getAtom(atom_index);
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
const sym_loc = atom.getSymbolWithLoc();
|
||||
|
||||
log.debug("mark(ATOM({d}, %{d}, {?d}))", .{ atom_index, sym_loc.sym_index, sym_loc.getFile() });
|
||||
|
||||
alive.putAssumeCapacityNoClobber(atom_index, {});
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const cpu_arch = macho_file.options.target.cpu.arch;
|
||||
|
||||
const sym = zld.getSymbol(atom.getSymbolWithLoc());
|
||||
const header = zld.sections.items(.header)[sym.n_sect - 1];
|
||||
const sym = macho_file.getSymbol(atom.getSymbolWithLoc());
|
||||
const header = macho_file.sections.items(.header)[sym.n_sect - 1];
|
||||
if (header.isZerofill()) return;
|
||||
|
||||
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| {
|
||||
const target = switch (cpu_arch) {
|
||||
.aarch64 => switch (@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type))) {
|
||||
.ARM64_RELOC_ADDEND => continue,
|
||||
else => Atom.parseRelocTarget(zld, .{
|
||||
else => Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = atom.getFile().?,
|
||||
.rel = rel,
|
||||
.code = code,
|
||||
@ -155,7 +138,7 @@ fn markLive(zld: *Zld, atom_index: Atom.Index, alive: *AtomTable) void {
|
||||
.base_addr = ctx.base_addr,
|
||||
}),
|
||||
},
|
||||
.x86_64 => Atom.parseRelocTarget(zld, .{
|
||||
.x86_64 => Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = atom.getFile().?,
|
||||
.rel = rel,
|
||||
.code = code,
|
||||
@ -164,50 +147,50 @@ fn markLive(zld: *Zld, atom_index: Atom.Index, alive: *AtomTable) void {
|
||||
}),
|
||||
else => unreachable,
|
||||
};
|
||||
const target_sym = zld.getSymbol(target);
|
||||
const target_sym = macho_file.getSymbol(target);
|
||||
|
||||
if (target_sym.undf()) continue;
|
||||
if (target.getFile() == null) {
|
||||
const target_sym_name = zld.getSymbolName(target);
|
||||
const target_sym_name = macho_file.getSymbolName(target);
|
||||
if (mem.eql(u8, "__mh_execute_header", target_sym_name)) continue;
|
||||
if (mem.eql(u8, "___dso_handle", target_sym_name)) continue;
|
||||
|
||||
unreachable; // referenced symbol not found
|
||||
}
|
||||
|
||||
const object = zld.objects.items[target.getFile().?];
|
||||
const object = macho_file.objects.items[target.getFile().?];
|
||||
const target_atom_index = object.getAtomIndexForSymbol(target.sym_index).?;
|
||||
log.debug(" following ATOM({d}, %{d}, {?d})", .{
|
||||
target_atom_index,
|
||||
zld.getAtom(target_atom_index).sym_index,
|
||||
zld.getAtom(target_atom_index).getFile(),
|
||||
macho_file.getAtom(target_atom_index).sym_index,
|
||||
macho_file.getAtom(target_atom_index).getFile(),
|
||||
});
|
||||
|
||||
markLive(zld, target_atom_index, alive);
|
||||
markLive(macho_file, target_atom_index, alive);
|
||||
}
|
||||
}
|
||||
|
||||
fn refersLive(zld: *Zld, atom_index: Atom.Index, alive: AtomTable) bool {
|
||||
const atom = zld.getAtom(atom_index);
|
||||
fn refersLive(macho_file: *MachO, atom_index: Atom.Index, alive: AtomTable) bool {
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
const sym_loc = atom.getSymbolWithLoc();
|
||||
|
||||
log.debug("refersLive(ATOM({d}, %{d}, {?d}))", .{ atom_index, sym_loc.sym_index, sym_loc.getFile() });
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
|
||||
const sym = zld.getSymbol(sym_loc);
|
||||
const header = zld.sections.items(.header)[sym.n_sect - 1];
|
||||
const sym = macho_file.getSymbol(sym_loc);
|
||||
const header = macho_file.sections.items(.header)[sym.n_sect - 1];
|
||||
assert(!header.isZerofill());
|
||||
|
||||
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| {
|
||||
const target = switch (cpu_arch) {
|
||||
.aarch64 => switch (@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type))) {
|
||||
.ARM64_RELOC_ADDEND => continue,
|
||||
else => Atom.parseRelocTarget(zld, .{
|
||||
else => Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = atom.getFile().?,
|
||||
.rel = rel,
|
||||
.code = code,
|
||||
@ -215,7 +198,7 @@ fn refersLive(zld: *Zld, atom_index: Atom.Index, alive: AtomTable) bool {
|
||||
.base_addr = ctx.base_addr,
|
||||
}),
|
||||
},
|
||||
.x86_64 => Atom.parseRelocTarget(zld, .{
|
||||
.x86_64 => Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = atom.getFile().?,
|
||||
.rel = rel,
|
||||
.code = code,
|
||||
@ -225,16 +208,16 @@ fn refersLive(zld: *Zld, atom_index: Atom.Index, alive: AtomTable) bool {
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
const object = zld.objects.items[target.getFile().?];
|
||||
const object = macho_file.objects.items[target.getFile().?];
|
||||
const target_atom_index = object.getAtomIndexForSymbol(target.sym_index) orelse {
|
||||
log.debug("atom for symbol '{s}' not found; skipping...", .{zld.getSymbolName(target)});
|
||||
log.debug("atom for symbol '{s}' not found; skipping...", .{macho_file.getSymbolName(target)});
|
||||
continue;
|
||||
};
|
||||
if (alive.contains(target_atom_index)) {
|
||||
log.debug(" refers live ATOM({d}, %{d}, {?d})", .{
|
||||
target_atom_index,
|
||||
zld.getAtom(target_atom_index).sym_index,
|
||||
zld.getAtom(target_atom_index).getFile(),
|
||||
macho_file.getAtom(target_atom_index).sym_index,
|
||||
macho_file.getAtom(target_atom_index).getFile(),
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@ -243,21 +226,21 @@ fn refersLive(zld: *Zld, atom_index: Atom.Index, alive: AtomTable) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable) !void {
|
||||
fn mark(macho_file: *MachO, roots: AtomTable, alive: *AtomTable) !void {
|
||||
var it = roots.keyIterator();
|
||||
while (it.next()) |root| {
|
||||
markLive(zld, root.*, alive);
|
||||
markLive(macho_file, root.*, alive);
|
||||
}
|
||||
|
||||
var loop: bool = true;
|
||||
while (loop) {
|
||||
loop = false;
|
||||
|
||||
for (zld.objects.items) |object| {
|
||||
for (macho_file.objects.items) |object| {
|
||||
for (object.atoms.items) |atom_index| {
|
||||
if (alive.contains(atom_index)) continue;
|
||||
|
||||
const atom = zld.getAtom(atom_index);
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
const sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym|
|
||||
source_sym.n_sect - 1
|
||||
else blk: {
|
||||
@ -268,8 +251,8 @@ fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable) !void {
|
||||
const source_sect = object.getSourceSection(sect_id);
|
||||
|
||||
if (source_sect.isDontDeadStripIfReferencesLive()) {
|
||||
if (refersLive(zld, atom_index, alive.*)) {
|
||||
markLive(zld, atom_index, alive);
|
||||
if (refersLive(macho_file, atom_index, alive.*)) {
|
||||
markLive(macho_file, atom_index, alive);
|
||||
loop = true;
|
||||
}
|
||||
}
|
||||
@ -277,26 +260,26 @@ fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable) !void {
|
||||
}
|
||||
}
|
||||
|
||||
for (zld.objects.items, 0..) |_, object_id| {
|
||||
for (macho_file.objects.items, 0..) |_, object_id| {
|
||||
// Traverse unwind and eh_frame records noting if the source symbol has been marked, and if so,
|
||||
// marking all references as live.
|
||||
try markUnwindRecords(zld, @as(u32, @intCast(object_id)), alive);
|
||||
try markUnwindRecords(macho_file, @as(u32, @intCast(object_id)), alive);
|
||||
}
|
||||
}
|
||||
|
||||
fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
|
||||
const object = &zld.objects.items[object_id];
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
fn markUnwindRecords(macho_file: *MachO, object_id: u32, alive: *AtomTable) !void {
|
||||
const object = &macho_file.objects.items[object_id];
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
|
||||
const unwind_records = object.getUnwindRecords();
|
||||
|
||||
for (object.exec_atoms.items) |atom_index| {
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
|
||||
if (!object.hasUnwindRecords()) {
|
||||
if (alive.contains(atom_index)) {
|
||||
// Mark references live and continue.
|
||||
try markEhFrameRecords(zld, object_id, atom_index, alive);
|
||||
try markEhFrameRecords(macho_file, object_id, atom_index, alive);
|
||||
} else {
|
||||
while (inner_syms_it.next()) |sym| {
|
||||
if (object.eh_frame_records_lookup.get(sym)) |fde_offset| {
|
||||
@ -322,51 +305,51 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
|
||||
|
||||
const record = unwind_records[record_id];
|
||||
if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
|
||||
try markEhFrameRecords(zld, object_id, atom_index, alive);
|
||||
try markEhFrameRecords(macho_file, object_id, atom_index, alive);
|
||||
} else {
|
||||
if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| {
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
if (UnwindInfo.getPersonalityFunctionReloc(macho_file, object_id, record_id)) |rel| {
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = object_id,
|
||||
.rel = rel,
|
||||
.code = mem.asBytes(&record),
|
||||
.base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
|
||||
});
|
||||
const target_sym = zld.getSymbol(target);
|
||||
const target_sym = macho_file.getSymbol(target);
|
||||
if (!target_sym.undf()) {
|
||||
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).?;
|
||||
markLive(zld, target_atom_index, alive);
|
||||
markLive(macho_file, target_atom_index, alive);
|
||||
}
|
||||
}
|
||||
|
||||
if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| {
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
if (UnwindInfo.getLsdaReloc(macho_file, object_id, record_id)) |rel| {
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = object_id,
|
||||
.rel = rel,
|
||||
.code = mem.asBytes(&record),
|
||||
.base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
|
||||
});
|
||||
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).?;
|
||||
markLive(zld, target_atom_index, alive);
|
||||
markLive(macho_file, target_atom_index, alive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn markEhFrameRecords(zld: *Zld, object_id: u32, atom_index: Atom.Index, alive: *AtomTable) !void {
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const object = &zld.objects.items[object_id];
|
||||
fn markEhFrameRecords(macho_file: *MachO, object_id: u32, atom_index: Atom.Index, alive: *AtomTable) !void {
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
const object = &macho_file.objects.items[object_id];
|
||||
var it = object.getEhFrameRecordsIterator();
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
|
||||
while (inner_syms_it.next()) |sym| {
|
||||
const fde_offset = object.eh_frame_records_lookup.get(sym) orelse continue; // Continue in case we hit a temp symbol alias
|
||||
it.seekTo(fde_offset);
|
||||
const fde = (try it.next()).?;
|
||||
|
||||
const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset);
|
||||
const cie_ptr = fde.getCiePointerSource(object_id, macho_file, fde_offset);
|
||||
const cie_offset = fde_offset + 4 - cie_ptr;
|
||||
it.seekTo(cie_offset);
|
||||
const cie = (try it.next()).?;
|
||||
@ -374,20 +357,20 @@ fn markEhFrameRecords(zld: *Zld, object_id: u32, atom_index: Atom.Index, alive:
|
||||
switch (cpu_arch) {
|
||||
.aarch64 => {
|
||||
// Mark FDE references which should include any referenced LSDA record
|
||||
const relocs = eh_frame.getRelocs(zld, object_id, fde_offset);
|
||||
const relocs = eh_frame.getRelocs(macho_file, object_id, fde_offset);
|
||||
for (relocs) |rel| {
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = object_id,
|
||||
.rel = rel,
|
||||
.code = fde.data,
|
||||
.base_offset = @as(i32, @intCast(fde_offset)) + 4,
|
||||
});
|
||||
const target_sym = zld.getSymbol(target);
|
||||
const target_sym = macho_file.getSymbol(target);
|
||||
if (!target_sym.undf()) blk: {
|
||||
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) orelse
|
||||
break :blk;
|
||||
markLive(zld, target_atom_index, alive);
|
||||
markLive(macho_file, target_atom_index, alive);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -401,7 +384,7 @@ fn markEhFrameRecords(zld: *Zld, object_id: u32, atom_index: Atom.Index, alive:
|
||||
// Mark LSDA record as live
|
||||
const sym_index = object.getSymbolByAddress(lsda_address, null);
|
||||
const target_atom_index = object.getAtomIndexForSymbol(sym_index).?;
|
||||
markLive(zld, target_atom_index, alive);
|
||||
markLive(macho_file, target_atom_index, alive);
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
@ -409,20 +392,20 @@ fn markEhFrameRecords(zld: *Zld, object_id: u32, atom_index: Atom.Index, alive:
|
||||
|
||||
// Mark CIE references which should include any referenced personalities
|
||||
// that are defined locally.
|
||||
if (cie.getPersonalityPointerReloc(zld, object_id, cie_offset)) |target| {
|
||||
const target_sym = zld.getSymbol(target);
|
||||
if (cie.getPersonalityPointerReloc(macho_file, object_id, cie_offset)) |target| {
|
||||
const target_sym = macho_file.getSymbol(target);
|
||||
if (!target_sym.undf()) {
|
||||
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).?;
|
||||
markLive(zld, target_atom_index, alive);
|
||||
markLive(macho_file, target_atom_index, alive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prune(zld: *Zld, alive: AtomTable) void {
|
||||
fn prune(macho_file: *MachO, alive: AtomTable) void {
|
||||
log.debug("pruning dead atoms", .{});
|
||||
for (zld.objects.items) |*object| {
|
||||
for (macho_file.objects.items) |*object| {
|
||||
var i: usize = 0;
|
||||
while (i < object.atoms.items.len) {
|
||||
const atom_index = object.atoms.items[i];
|
||||
@ -431,7 +414,7 @@ fn prune(zld: *Zld, alive: AtomTable) void {
|
||||
continue;
|
||||
}
|
||||
|
||||
const atom = zld.getAtom(atom_index);
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
const sym_loc = atom.getSymbolWithLoc();
|
||||
|
||||
log.debug("prune(ATOM({d}, %{d}, {?d}))", .{
|
||||
@ -439,15 +422,15 @@ fn prune(zld: *Zld, alive: AtomTable) void {
|
||||
sym_loc.sym_index,
|
||||
sym_loc.getFile(),
|
||||
});
|
||||
log.debug(" {s} in {s}", .{ zld.getSymbolName(sym_loc), object.name });
|
||||
log.debug(" {s} in {s}", .{ macho_file.getSymbolName(sym_loc), object.name });
|
||||
|
||||
const sym = zld.getSymbolPtr(sym_loc);
|
||||
const sym = macho_file.getSymbolPtr(sym_loc);
|
||||
const sect_id = sym.n_sect - 1;
|
||||
var section = zld.sections.get(sect_id);
|
||||
var section = macho_file.sections.get(sect_id);
|
||||
section.header.size -= atom.size;
|
||||
|
||||
if (atom.prev_index) |prev_index| {
|
||||
const prev = zld.getAtomPtr(prev_index);
|
||||
const prev = macho_file.getAtomPtr(prev_index);
|
||||
prev.next_index = atom.next_index;
|
||||
} else {
|
||||
if (atom.next_index) |next_index| {
|
||||
@ -455,7 +438,7 @@ fn prune(zld: *Zld, alive: AtomTable) void {
|
||||
}
|
||||
}
|
||||
if (atom.next_index) |next_index| {
|
||||
const next = zld.getAtomPtr(next_index);
|
||||
const next = macho_file.getAtomPtr(next_index);
|
||||
next.prev_index = atom.prev_index;
|
||||
} else {
|
||||
if (atom.prev_index) |prev_index| {
|
||||
@ -467,21 +450,37 @@ fn prune(zld: *Zld, alive: AtomTable) void {
|
||||
}
|
||||
}
|
||||
|
||||
zld.sections.set(sect_id, section);
|
||||
macho_file.sections.set(sect_id, section);
|
||||
_ = object.atoms.swapRemove(i);
|
||||
|
||||
sym.n_desc = MachO.N_DEAD;
|
||||
|
||||
var inner_sym_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var inner_sym_it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
while (inner_sym_it.next()) |inner| {
|
||||
const inner_sym = zld.getSymbolPtr(inner);
|
||||
const inner_sym = macho_file.getSymbolPtr(inner);
|
||||
inner_sym.n_desc = MachO.N_DEAD;
|
||||
}
|
||||
|
||||
if (Atom.getSectionAlias(zld, atom_index)) |alias| {
|
||||
const alias_sym = zld.getSymbolPtr(alias);
|
||||
if (Atom.getSectionAlias(macho_file, atom_index)) |alias| {
|
||||
const alias_sym = macho_file.getSymbolPtr(alias);
|
||||
alias_sym.n_desc = MachO.N_DEAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const eh_frame = @import("eh_frame.zig");
|
||||
const log = std.log.scoped(.dead_strip);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const UnwindInfo = @import("UnwindInfo.zig");
|
||||
|
||||
const AtomTable = std.AutoHashMap(Atom.Index, void);
|
||||
|
||||
@ -1,14 +1,3 @@
|
||||
const Rebase = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.dyld_info);
|
||||
const macho = std.macho;
|
||||
const testing = std.testing;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
entries: std.ArrayListUnmanaged(Entry) = .{},
|
||||
buffer: std.ArrayListUnmanaged(u8) = .{},
|
||||
|
||||
@ -572,3 +561,14 @@ test "rebase - composite" {
|
||||
macho.REBASE_OPCODE_DONE,
|
||||
}, rebase.buffer.items);
|
||||
}
|
||||
|
||||
const Rebase = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.dyld_info);
|
||||
const macho = std.macho;
|
||||
const testing = std.testing;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
@ -1,12 +1,3 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.dyld_info);
|
||||
const macho = std.macho;
|
||||
const testing = std.testing;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub fn Bind(comptime Ctx: type, comptime Target: type) type {
|
||||
return struct {
|
||||
entries: std.ArrayListUnmanaged(Entry) = .{},
|
||||
@ -738,3 +729,12 @@ test "lazy bind" {
|
||||
macho.BIND_OPCODE_DONE,
|
||||
}, bind.buffer.items);
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.dyld_info);
|
||||
const macho = std.macho;
|
||||
const testing = std.testing;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
@ -1,68 +1,52 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.eh_frame);
|
||||
pub fn scanRelocs(macho_file: *MachO) !void {
|
||||
const gpa = macho_file.base.allocator;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Relocation = @import("Relocation.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const UnwindInfo = @import("UnwindInfo.zig");
|
||||
const Zld = @import("zld.zig").Zld;
|
||||
|
||||
pub fn scanRelocs(zld: *Zld) !void {
|
||||
const gpa = zld.gpa;
|
||||
|
||||
for (zld.objects.items, 0..) |*object, object_id| {
|
||||
for (macho_file.objects.items, 0..) |*object, object_id| {
|
||||
var cies = std.AutoHashMap(u32, void).init(gpa);
|
||||
defer cies.deinit();
|
||||
|
||||
var it = object.getEhFrameRecordsIterator();
|
||||
|
||||
for (object.exec_atoms.items) |atom_index| {
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
while (inner_syms_it.next()) |sym| {
|
||||
const fde_offset = object.eh_frame_records_lookup.get(sym) orelse continue;
|
||||
if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue;
|
||||
it.seekTo(fde_offset);
|
||||
const fde = (try it.next()).?;
|
||||
|
||||
const cie_ptr = fde.getCiePointerSource(@intCast(object_id), zld, fde_offset);
|
||||
const cie_ptr = fde.getCiePointerSource(@intCast(object_id), macho_file, fde_offset);
|
||||
const cie_offset = fde_offset + 4 - cie_ptr;
|
||||
|
||||
if (!cies.contains(cie_offset)) {
|
||||
try cies.putNoClobber(cie_offset, {});
|
||||
it.seekTo(cie_offset);
|
||||
const cie = (try it.next()).?;
|
||||
try cie.scanRelocs(zld, @as(u32, @intCast(object_id)), cie_offset);
|
||||
try cie.scanRelocs(macho_file, @as(u32, @intCast(object_id)), cie_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void {
|
||||
const sect_id = zld.eh_frame_section_index orelse return;
|
||||
const sect = &zld.sections.items(.header)[sect_id];
|
||||
pub fn calcSectionSize(macho_file: *MachO, unwind_info: *const UnwindInfo) !void {
|
||||
const sect_id = macho_file.eh_frame_section_index orelse return;
|
||||
const sect = &macho_file.sections.items(.header)[sect_id];
|
||||
sect.@"align" = 3;
|
||||
sect.size = 0;
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const gpa = zld.gpa;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
const gpa = macho_file.base.allocator;
|
||||
var size: u32 = 0;
|
||||
|
||||
for (zld.objects.items, 0..) |*object, object_id| {
|
||||
for (macho_file.objects.items, 0..) |*object, object_id| {
|
||||
var cies = std.AutoHashMap(u32, u32).init(gpa);
|
||||
defer cies.deinit();
|
||||
|
||||
var eh_it = object.getEhFrameRecordsIterator();
|
||||
|
||||
for (object.exec_atoms.items) |atom_index| {
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
while (inner_syms_it.next()) |sym| {
|
||||
const fde_record_offset = object.eh_frame_records_lookup.get(sym) orelse continue;
|
||||
if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue;
|
||||
@ -77,7 +61,7 @@ pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void {
|
||||
eh_it.seekTo(fde_record_offset);
|
||||
const source_fde_record = (try eh_it.next()).?;
|
||||
|
||||
const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset);
|
||||
const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), macho_file, fde_record_offset);
|
||||
const cie_offset = fde_record_offset + 4 - cie_ptr;
|
||||
|
||||
const gop = try cies.getOrPut(cie_offset);
|
||||
@ -96,14 +80,14 @@ pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
||||
const sect_id = zld.eh_frame_section_index orelse return;
|
||||
const sect = zld.sections.items(.header)[sect_id];
|
||||
const seg_id = zld.sections.items(.segment_index)[sect_id];
|
||||
const seg = zld.segments.items[seg_id];
|
||||
pub fn write(macho_file: *MachO, unwind_info: *UnwindInfo) !void {
|
||||
const sect_id = macho_file.eh_frame_section_index orelse return;
|
||||
const sect = macho_file.sections.items(.header)[sect_id];
|
||||
const seg_id = macho_file.sections.items(.segment_index)[sect_id];
|
||||
const seg = macho_file.segments.items[seg_id];
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const gpa = zld.gpa;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
const gpa = macho_file.base.allocator;
|
||||
|
||||
var eh_records = std.AutoArrayHashMap(u32, EhFrameRecord(true)).init(gpa);
|
||||
defer {
|
||||
@ -115,7 +99,7 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
||||
|
||||
var eh_frame_offset: u32 = 0;
|
||||
|
||||
for (zld.objects.items, 0..) |*object, object_id| {
|
||||
for (macho_file.objects.items, 0..) |*object, object_id| {
|
||||
try eh_records.ensureUnusedCapacity(2 * @as(u32, @intCast(object.exec_atoms.items.len)));
|
||||
|
||||
var cies = std.AutoHashMap(u32, u32).init(gpa);
|
||||
@ -124,7 +108,7 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
||||
var eh_it = object.getEhFrameRecordsIterator();
|
||||
|
||||
for (object.exec_atoms.items) |atom_index| {
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(macho_file, atom_index);
|
||||
while (inner_syms_it.next()) |target| {
|
||||
const fde_record_offset = object.eh_frame_records_lookup.get(target) orelse continue;
|
||||
if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue;
|
||||
@ -139,7 +123,7 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
||||
eh_it.seekTo(fde_record_offset);
|
||||
const source_fde_record = (try eh_it.next()).?;
|
||||
|
||||
const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset);
|
||||
const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), macho_file, fde_record_offset);
|
||||
const cie_offset = fde_record_offset + 4 - cie_ptr;
|
||||
|
||||
const gop = try cies.getOrPut(cie_offset);
|
||||
@ -147,7 +131,7 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
||||
eh_it.seekTo(cie_offset);
|
||||
const source_cie_record = (try eh_it.next()).?;
|
||||
var cie_record = try source_cie_record.toOwned(gpa);
|
||||
try cie_record.relocate(zld, @as(u32, @intCast(object_id)), .{
|
||||
try cie_record.relocate(macho_file, @as(u32, @intCast(object_id)), .{
|
||||
.source_offset = cie_offset,
|
||||
.out_offset = eh_frame_offset,
|
||||
.sect_addr = sect.addr,
|
||||
@ -158,7 +142,7 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
||||
}
|
||||
|
||||
var fde_record = try source_fde_record.toOwned(gpa);
|
||||
try fde_record.relocate(zld, @as(u32, @intCast(object_id)), .{
|
||||
try fde_record.relocate(macho_file, @as(u32, @intCast(object_id)), .{
|
||||
.source_offset = fde_record_offset,
|
||||
.out_offset = eh_frame_offset,
|
||||
.sect_addr = sect.addr,
|
||||
@ -169,7 +153,7 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
||||
.aarch64 => {}, // relocs take care of LSDA pointers
|
||||
.x86_64 => {
|
||||
// We need to relocate target symbol address ourselves.
|
||||
const atom_sym = zld.getSymbol(target);
|
||||
const atom_sym = macho_file.getSymbol(target);
|
||||
try fde_record.setTargetSymbolAddress(atom_sym.n_value, .{
|
||||
.base_addr = sect.addr,
|
||||
.base_offset = eh_frame_offset,
|
||||
@ -229,7 +213,7 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
||||
try buffer.appendSlice(record.data);
|
||||
}
|
||||
|
||||
try zld.file.pwriteAll(buffer.items, sect.offset);
|
||||
try macho_file.base.file.?.pwriteAll(buffer.items, sect.offset);
|
||||
}
|
||||
const EhFrameRecordTag = enum { cie, fde };
|
||||
|
||||
@ -261,12 +245,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
||||
|
||||
pub fn scanRelocs(
|
||||
rec: Record,
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
object_id: u32,
|
||||
source_offset: u32,
|
||||
) !void {
|
||||
if (rec.getPersonalityPointerReloc(zld, object_id, source_offset)) |target| {
|
||||
try zld.addGotEntry(target);
|
||||
if (rec.getPersonalityPointerReloc(macho_file, object_id, source_offset)) |target| {
|
||||
try macho_file.addGotEntry(target);
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,12 +274,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
||||
|
||||
pub fn getPersonalityPointerReloc(
|
||||
rec: Record,
|
||||
zld: *Zld,
|
||||
macho_file: *MachO,
|
||||
object_id: u32,
|
||||
source_offset: u32,
|
||||
) ?SymbolWithLoc {
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const relocs = getRelocs(zld, object_id, source_offset);
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
const relocs = getRelocs(macho_file, object_id, source_offset);
|
||||
for (relocs) |rel| {
|
||||
switch (cpu_arch) {
|
||||
.aarch64 => {
|
||||
@ -317,7 +301,7 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = object_id,
|
||||
.rel = rel,
|
||||
.code = rec.data,
|
||||
@ -328,18 +312,18 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn relocate(rec: *Record, zld: *Zld, object_id: u32, ctx: struct {
|
||||
pub fn relocate(rec: *Record, macho_file: *MachO, object_id: u32, ctx: struct {
|
||||
source_offset: u32,
|
||||
out_offset: u32,
|
||||
sect_addr: u64,
|
||||
}) !void {
|
||||
comptime assert(is_mutable);
|
||||
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const relocs = getRelocs(zld, object_id, ctx.source_offset);
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
const relocs = getRelocs(macho_file, object_id, ctx.source_offset);
|
||||
|
||||
for (relocs) |rel| {
|
||||
const target = Atom.parseRelocTarget(zld, .{
|
||||
const target = Atom.parseRelocTarget(macho_file, .{
|
||||
.object_id = object_id,
|
||||
.rel = rel,
|
||||
.code = rec.data,
|
||||
@ -356,14 +340,14 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
||||
// Address of the __eh_frame in the source object file
|
||||
},
|
||||
.ARM64_RELOC_POINTER_TO_GOT => {
|
||||
const target_addr = zld.getGotEntryAddress(target).?;
|
||||
const target_addr = macho_file.getGotEntryAddress(target).?;
|
||||
const result = math.cast(i32, @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr))) orelse
|
||||
return error.Overflow;
|
||||
mem.writeIntLittle(i32, rec.data[rel_offset..][0..4], result);
|
||||
},
|
||||
.ARM64_RELOC_UNSIGNED => {
|
||||
assert(rel.r_extern == 1);
|
||||
const target_addr = try Atom.getRelocTargetAddress(zld, target, false);
|
||||
const target_addr = try Atom.getRelocTargetAddress(macho_file, target, false);
|
||||
const result = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr));
|
||||
mem.writeIntLittle(i64, rec.data[rel_offset..][0..8], @as(i64, @intCast(result)));
|
||||
},
|
||||
@ -374,7 +358,7 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
||||
const rel_type = @as(macho.reloc_type_x86_64, @enumFromInt(rel.r_type));
|
||||
switch (rel_type) {
|
||||
.X86_64_RELOC_GOT => {
|
||||
const target_addr = zld.getGotEntryAddress(target).?;
|
||||
const target_addr = macho_file.getGotEntryAddress(target).?;
|
||||
const addend = mem.readIntLittle(i32, rec.data[rel_offset..][0..4]);
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
|
||||
const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
|
||||
@ -388,20 +372,20 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getCiePointerSource(rec: Record, object_id: u32, zld: *Zld, offset: u32) u32 {
|
||||
pub fn getCiePointerSource(rec: Record, object_id: u32, macho_file: *MachO, offset: u32) u32 {
|
||||
assert(rec.tag == .fde);
|
||||
const cpu_arch = zld.options.target.cpu.arch;
|
||||
const cpu_arch = macho_file.base.options.target.cpu.arch;
|
||||
const addend = mem.readIntLittle(u32, rec.data[0..4]);
|
||||
switch (cpu_arch) {
|
||||
.aarch64 => {
|
||||
const relocs = getRelocs(zld, object_id, offset);
|
||||
const relocs = getRelocs(macho_file, object_id, offset);
|
||||
const maybe_rel = for (relocs) |rel| {
|
||||
if (rel.r_address - @as(i32, @intCast(offset)) == 4 and
|
||||
@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type)) == .ARM64_RELOC_SUBTRACTOR)
|
||||
break rel;
|
||||
} else null;
|
||||
const rel = maybe_rel orelse return addend;
|
||||
const object = &zld.objects.items[object_id];
|
||||
const object = &macho_file.objects.items[object_id];
|
||||
const target_addr = object.in_symtab.?[rel.r_symbolnum].n_value;
|
||||
const sect = object.getSourceSection(object.eh_frame_sect_id.?);
|
||||
return @intCast(sect.addr + offset - target_addr + addend);
|
||||
@ -583,8 +567,8 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getRelocs(zld: *Zld, object_id: u32, source_offset: u32) []const macho.relocation_info {
|
||||
const object = &zld.objects.items[object_id];
|
||||
pub fn getRelocs(macho_file: *MachO, object_id: u32, source_offset: u32) []const macho.relocation_info {
|
||||
const object = &macho_file.objects.items[object_id];
|
||||
assert(object.hasEhFrameRecords());
|
||||
const urel = object.eh_frame_relocs_lookup.get(source_offset) orelse
|
||||
return &[0]macho.relocation_info{};
|
||||
@ -650,3 +634,18 @@ pub const EH_PE = struct {
|
||||
pub const indirect = 0x80;
|
||||
pub const omit = 0xFF;
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const leb = std.leb;
|
||||
const log = std.log.scoped(.eh_frame);
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Relocation = @import("Relocation.zig");
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const UnwindInfo = @import("UnwindInfo.zig");
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.archive);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
pub fn isFatLibrary(file: std.fs.File) bool {
|
||||
const reader = file.reader();
|
||||
const hdr = reader.readStructBig(macho.fat_header) catch return false;
|
||||
@ -38,3 +32,9 @@ pub fn parseArchs(file: std.fs.File, buffer: *[2]Arch) ![]const Arch {
|
||||
|
||||
return buffer[0..count];
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.archive);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
@ -1,12 +1,3 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const ThreadPool = std.Thread.Pool;
|
||||
const WaitGroup = std.Thread.WaitGroup;
|
||||
|
||||
pub fn ParallelHasher(comptime Hasher: type) type {
|
||||
const hash_size = Hasher.digest_length;
|
||||
|
||||
@ -69,3 +60,12 @@ pub fn ParallelHasher(comptime Hasher: type) type {
|
||||
const Self = @This();
|
||||
};
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const ThreadPool = std.Thread.Pool;
|
||||
const WaitGroup = std.Thread.WaitGroup;
|
||||
|
||||
@ -1,13 +1,3 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const link = @import("../../link.zig");
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Dylib = @import("Dylib.zig");
|
||||
|
||||
/// Default implicit entrypoint symbol name.
|
||||
pub const default_entry_point: []const u8 = "_main";
|
||||
|
||||
@ -374,3 +364,13 @@ test "parseSdkVersion" {
|
||||
|
||||
try expect(parseSdkVersion("11") == null);
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const link = @import("../../link.zig");
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Dylib = @import("Dylib.zig");
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
const std = @import("std");
|
||||
const aarch64 = @import("../../arch/aarch64/bits.zig");
|
||||
|
||||
const Relocation = @import("Relocation.zig");
|
||||
|
||||
pub inline fn stubHelperPreambleSize(cpu_arch: std.Target.Cpu.Arch) u8 {
|
||||
return switch (cpu_arch) {
|
||||
.x86_64 => 15,
|
||||
@ -167,3 +162,8 @@ pub fn writeStubCode(args: struct {
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const aarch64 = @import("../../arch/aarch64/bits.zig");
|
||||
|
||||
const Relocation = @import("Relocation.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;
|
||||
|
||||
@ -1,12 +1,3 @@
|
||||
const std = @import("std");
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Compilation = @import("../../Compilation.zig");
|
||||
const Md5 = std.crypto.hash.Md5;
|
||||
const Hasher = @import("hasher.zig").ParallelHasher;
|
||||
|
||||
/// Calculates Md5 hash of each chunk in parallel and then hashes all Md5 hashes to produce
|
||||
/// the final digest.
|
||||
/// While this is NOT a correct MD5 hash of the contents, this methodology is used by LLVM/LLD
|
||||
@ -43,3 +34,12 @@ inline fn conform(out: *[Md5.digest_length]u8) void {
|
||||
out[6] = (out[6] & 0x0F) | (3 << 4);
|
||||
out[8] = (out[8] & 0x3F) | 0x80;
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Compilation = @import("../../Compilation.zig");
|
||||
const Md5 = std.crypto.hash.Md5;
|
||||
const Hasher = @import("hasher.zig").ParallelHasher;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user