macho: introduce ZigObject
This commit is contained in:
parent
03b33b0f01
commit
6d0ba6dd10
|
@ -608,6 +608,7 @@ set(ZIG_STAGE2_SOURCES
|
|||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Relocation.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/UnwindInfo.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/ZigObject.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/dead_strip.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/dyld_info/bind.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/dyld_info/Rebase.zig"
|
||||
|
|
|
@ -10,6 +10,7 @@ d_sym: ?DebugSymbols = null,
|
|||
/// Index of each input file also encodes the priority or precedence of one input file
|
||||
/// over another.
|
||||
files: std.MultiArrayList(File.Entry) = .{},
|
||||
zig_object: ?File.Index = null,
|
||||
internal_object: ?File.Index = null,
|
||||
objects: std.ArrayListUnmanaged(File.Index) = .{},
|
||||
dylibs: std.ArrayListUnmanaged(File.Index) = .{},
|
||||
|
@ -222,12 +223,19 @@ pub fn createEmpty(
|
|||
try self.symbols.append(gpa, .{});
|
||||
try self.symbols_extra.append(gpa, 0);
|
||||
|
||||
// TODO: init
|
||||
|
||||
if (opt_zcu) |zcu| {
|
||||
if (!use_llvm) {
|
||||
_ = zcu;
|
||||
// TODO: create .zig_object
|
||||
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
||||
self.files.set(index, .{ .zig_object = .{
|
||||
.index = index,
|
||||
.path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(
|
||||
zcu.main_mod.root_src_path,
|
||||
)}),
|
||||
} });
|
||||
self.zig_object = index;
|
||||
try self.getZigObject().?.init(self);
|
||||
|
||||
// TODO init metadata
|
||||
|
||||
if (comp.config.debug_format != .strip) {
|
||||
// Create dSYM bundle.
|
||||
|
@ -281,6 +289,7 @@ pub fn deinit(self: *MachO) void {
|
|||
|
||||
for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {
|
||||
.null => {},
|
||||
.zig_object => data.zig_object.deinit(gpa),
|
||||
.internal => data.internal.deinit(gpa),
|
||||
.object => data.object.deinit(gpa),
|
||||
.dylib => data.dylib.deinit(gpa),
|
||||
|
@ -3109,9 +3118,7 @@ pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
|
|||
|
||||
pub fn getDeclVAddr(self: *MachO, decl_index: InternPool.DeclIndex, reloc_info: link.File.RelocInfo) !u64 {
|
||||
assert(self.llvm_object == null);
|
||||
_ = decl_index;
|
||||
_ = reloc_info;
|
||||
@panic("TODO getDeclVAddr");
|
||||
return self.getZigObject().?.getDeclVAddr(self, decl_index, reloc_info);
|
||||
}
|
||||
|
||||
pub fn lowerAnonDecl(
|
||||
|
@ -3297,12 +3304,18 @@ pub fn getFile(self: *MachO, index: File.Index) ?File {
|
|||
const tag = self.files.items(.tags)[index];
|
||||
return switch (tag) {
|
||||
.null => null,
|
||||
.zig_object => .{ .zig_object = &self.files.items(.data)[index].zig_object },
|
||||
.internal => .{ .internal = &self.files.items(.data)[index].internal },
|
||||
.object => .{ .object = &self.files.items(.data)[index].object },
|
||||
.dylib => .{ .dylib = &self.files.items(.data)[index].dylib },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getZigObject(self: *MachO) ?*ZigObject {
|
||||
const index = self.zig_object orelse return null;
|
||||
return self.getFile(index).?.zig_object;
|
||||
}
|
||||
|
||||
pub fn getInternalObject(self: *MachO) ?*InternalObject {
|
||||
const index = self.internal_object orelse return null;
|
||||
return self.getFile(index).?.internal;
|
||||
|
@ -4123,3 +4136,4 @@ const TlvPtrSection = synthetic.TlvPtrSection;
|
|||
const TypedValue = @import("../TypedValue.zig");
|
||||
const UnwindInfo = @import("MachO/UnwindInfo.zig");
|
||||
const WeakBindSection = synthetic.WeakBindSection;
|
||||
const ZigObject = @import("MachO/ZigObject.zig");
|
||||
|
|
|
@ -45,10 +45,27 @@ pub fn getFile(self: Atom, macho_file: *MachO) File {
|
|||
return macho_file.getFile(self.file).?;
|
||||
}
|
||||
|
||||
pub fn getData(self: Atom, macho_file: *MachO) []const u8 {
|
||||
return switch (self.getFile(macho_file)) {
|
||||
.zig_object => @panic("TODO Atom.getData"),
|
||||
.object => |x| x.getAtomData(self),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {
|
||||
return switch (self.getFile(macho_file)) {
|
||||
.zig_object => @panic("TODO Atom.getRelocs"),
|
||||
.object => |x| x.getAtomRelocs(self),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getInputSection(self: Atom, macho_file: *MachO) macho.section_64 {
|
||||
return switch (self.getFile(macho_file)) {
|
||||
.dylib => unreachable,
|
||||
inline else => |x| x.sections.items(.header)[self.n_sect],
|
||||
.zig_object => |x| x.getInputSection(self, macho_file),
|
||||
.object => |x| x.sections.items(.header)[self.n_sect],
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -61,26 +78,10 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 {
|
|||
return (@as(u64, @intCast(file.getIndex())) << 32) | @as(u64, @intCast(self.n_sect));
|
||||
}
|
||||
|
||||
pub fn getCode(self: Atom, macho_file: *MachO) []const u8 {
|
||||
const code = switch (self.getFile(macho_file)) {
|
||||
.dylib => unreachable,
|
||||
inline else => |x| x.getSectionData(self.n_sect),
|
||||
};
|
||||
return code[self.off..][0..self.size];
|
||||
}
|
||||
|
||||
pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {
|
||||
const relocs = switch (self.getFile(macho_file)) {
|
||||
.dylib => unreachable,
|
||||
inline else => |x| x.sections.items(.relocs)[self.n_sect],
|
||||
};
|
||||
return relocs.items[self.relocs.pos..][0..self.relocs.len];
|
||||
}
|
||||
|
||||
pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index {
|
||||
return switch (self.getFile(macho_file)) {
|
||||
.dylib => unreachable,
|
||||
.internal => &[0]UnwindInfo.Record.Index{},
|
||||
.zig_object, .internal => &[0]UnwindInfo.Record.Index{},
|
||||
.object => |x| x.unwind_records.items[self.unwind_records.pos..][0..self.unwind_records.len],
|
||||
};
|
||||
}
|
||||
|
@ -290,10 +291,10 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
|
|||
defer tracy.end();
|
||||
|
||||
assert(!self.getInputSection(macho_file).isZerofill());
|
||||
const relocs = self.getRelocs(macho_file);
|
||||
const file = self.getFile(macho_file);
|
||||
const name = self.getName(macho_file);
|
||||
@memcpy(buffer, self.getCode(macho_file));
|
||||
const relocs = self.getRelocs(macho_file);
|
||||
@memcpy(buffer, self.getData(macho_file));
|
||||
|
||||
relocs_log.debug("{x}: {s}", .{ self.value, name });
|
||||
|
||||
|
@ -683,10 +684,11 @@ const x86_64 = struct {
|
|||
};
|
||||
|
||||
pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
|
||||
const relocs = self.getRelocs(macho_file);
|
||||
switch (macho_file.getTarget().cpu.arch) {
|
||||
.aarch64 => {
|
||||
var nreloc: u32 = 0;
|
||||
for (self.getRelocs(macho_file)) |rel| {
|
||||
for (relocs) |rel| {
|
||||
nreloc += 1;
|
||||
switch (rel.type) {
|
||||
.page, .pageoff => if (rel.addend > 0) {
|
||||
|
@ -697,7 +699,7 @@ pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
|
|||
}
|
||||
return nreloc;
|
||||
},
|
||||
.x86_64 => return @intCast(self.getRelocs(macho_file).len),
|
||||
.x86_64 => return @intCast(relocs.len),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1547,6 +1547,16 @@ pub fn getSectionData(self: *const Object, index: u32) []const u8 {
|
|||
return self.data[sect.offset..][0..sect.size];
|
||||
}
|
||||
|
||||
pub fn getAtomData(self: *const Object, atom: Atom) []const u8 {
|
||||
const data = self.getSectionData(atom.n_sect);
|
||||
return data[atom.off..][0..atom.size];
|
||||
}
|
||||
|
||||
pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation {
|
||||
const relocs = self.sections.items(.relocs)[atom.n_sect];
|
||||
return relocs.items[atom.relocs.pos..][0..atom.relocs.len];
|
||||
}
|
||||
|
||||
fn getString(self: Object, off: u32) [:0]const u8 {
|
||||
assert(off < self.strtab.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
|
||||
|
|
|
@ -306,6 +306,7 @@ fn format2(
|
|||
if (symbol.flags.weak) try writer.writeAll(" : weak");
|
||||
if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab");
|
||||
switch (file) {
|
||||
.zig_object => |x| try writer.print(" : zig_object({d})", .{x.index}),
|
||||
.internal => |x| try writer.print(" : internal({d})", .{x.index}),
|
||||
.object => |x| try writer.print(" : object({d})", .{x.index}),
|
||||
.dylib => |x| try writer.print(" : dylib({d})", .{x.index}),
|
||||
|
|
199
src/link/MachO/ZigObject.zig
Normal file
199
src/link/MachO/ZigObject.zig
Normal file
|
@ -0,0 +1,199 @@
|
|||
/// Externally owned memory.
|
||||
path: []const u8,
|
||||
index: File.Index,
|
||||
|
||||
symtab: std.MultiArrayList(Nlist) = .{},
|
||||
|
||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
|
||||
|
||||
output_symtab_ctx: MachO.SymtabCtx = .{},
|
||||
|
||||
pub fn init(self: *ZigObject, macho_file: *MachO) !void {
|
||||
const comp = macho_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
|
||||
try self.atoms.append(gpa, 0); // null input section
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ZigObject, allocator: Allocator) void {
|
||||
self.symtab.deinit(allocator);
|
||||
self.symbols.deinit(allocator);
|
||||
self.atoms.deinit(allocator);
|
||||
}
|
||||
|
||||
fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index {
|
||||
try self.symtab.ensureUnusedCapacity(allocator, 1);
|
||||
const index = @as(Symbol.Index, @intCast(self.symtab.addOneAssumeCapacity()));
|
||||
self.symtab.set(index, .{
|
||||
.nlist = MachO.null_sym,
|
||||
.size = 0,
|
||||
.atom = 0,
|
||||
});
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn getDeclVAddr(
|
||||
self: *ZigObject,
|
||||
macho_file: *MachO,
|
||||
decl_index: InternPool.DeclIndex,
|
||||
reloc_info: link.File.RelocInfo,
|
||||
) !u64 {
|
||||
_ = self;
|
||||
_ = macho_file;
|
||||
_ = decl_index;
|
||||
_ = reloc_info;
|
||||
@panic("TODO getDeclVAddr");
|
||||
}
|
||||
|
||||
pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void {
|
||||
_ = self;
|
||||
_ = macho_file;
|
||||
@panic("TODO resolveSymbols");
|
||||
}
|
||||
|
||||
pub fn resetGlobals(self: *ZigObject, macho_file: *MachO) void {
|
||||
for (self.symbols.items, 0..) |sym_index, nlist_idx| {
|
||||
if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue;
|
||||
const sym = macho_file.getSymbol(sym_index);
|
||||
const name = sym.name;
|
||||
sym.* = .{};
|
||||
sym.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
for (self.symbols.items) |sym_index| {
|
||||
const sym = macho_file.getSymbol(sym_index);
|
||||
const file = sym.getFile(macho_file) orelse continue;
|
||||
if (file.getIndex() != self.index) continue;
|
||||
if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;
|
||||
sym.flags.output_symtab = true;
|
||||
if (sym.isLocal()) {
|
||||
try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
|
||||
self.output_symtab_ctx.nlocals += 1;
|
||||
} else if (sym.flags.@"export") {
|
||||
try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file);
|
||||
self.output_symtab_ctx.nexports += 1;
|
||||
} else {
|
||||
assert(sym.flags.import);
|
||||
try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
|
||||
self.output_symtab_ctx.nimports += 1;
|
||||
}
|
||||
self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
for (self.symbols.items) |sym_index| {
|
||||
const sym = macho_file.getSymbol(sym_index);
|
||||
const file = sym.getFile(macho_file) orelse continue;
|
||||
if (file.getIndex() != self.index) continue;
|
||||
const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
|
||||
const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
|
||||
macho_file.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
|
||||
macho_file.strtab.appendAssumeCapacity(0);
|
||||
const out_sym = &macho_file.symtab.items[idx];
|
||||
out_sym.n_strx = n_strx;
|
||||
sym.setOutputSym(macho_file, out_sym);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getInputSection(self: ZigObject, atom: Atom, macho_file: *MachO) macho.section_64 {
|
||||
_ = self;
|
||||
var sect = macho_file.sections.items(.header)[atom.out_n_sect];
|
||||
sect.addr = 0;
|
||||
sect.offset = 0;
|
||||
sect.size = atom.size;
|
||||
sect.@"align" = atom.alignment.toLog2Units();
|
||||
return sect;
|
||||
}
|
||||
|
||||
pub fn fmtSymtab(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
|
||||
return .{ .data = .{
|
||||
.self = self,
|
||||
.macho_file = macho_file,
|
||||
} };
|
||||
}
|
||||
|
||||
const FormatContext = struct {
|
||||
self: *ZigObject,
|
||||
macho_file: *MachO,
|
||||
};
|
||||
|
||||
fn formatSymtab(
|
||||
ctx: FormatContext,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
try writer.writeAll(" symbols\n");
|
||||
for (ctx.self.symbols.items) |index| {
|
||||
const sym = ctx.macho_file.getSymbol(index);
|
||||
try writer.print(" {}\n", .{sym.fmt(ctx.macho_file)});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmtAtoms(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatAtoms) {
|
||||
return .{ .data = .{
|
||||
.self = self,
|
||||
.macho_file = macho_file,
|
||||
} };
|
||||
}
|
||||
|
||||
fn formatAtoms(
|
||||
ctx: FormatContext,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
try writer.writeAll(" atoms\n");
|
||||
for (ctx.self.atoms.items) |atom_index| {
|
||||
const atom = ctx.macho_file.getAtom(atom_index) orelse continue;
|
||||
try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)});
|
||||
}
|
||||
}
|
||||
|
||||
const Nlist = struct {
|
||||
nlist: macho.nlist_64,
|
||||
size: u64,
|
||||
atom: Atom.Index,
|
||||
};
|
||||
|
||||
const assert = std.debug.assert;
|
||||
const builtin = @import("builtin");
|
||||
const codegen = @import("../../codegen.zig");
|
||||
const link = @import("../../link.zig");
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
const std = @import("std");
|
||||
|
||||
const Air = @import("../../Air.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Archive = @import("Archive.zig");
|
||||
const Atom = @import("Atom.zig");
|
||||
const Dwarf = @import("../Dwarf.zig");
|
||||
const File = @import("file.zig").File;
|
||||
const InternPool = @import("../../InternPool.zig");
|
||||
const Liveness = @import("../../Liveness.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Module = @import("../../Module.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const StringTable = @import("../StringTable.zig");
|
||||
const Type = @import("../../type.zig").Type;
|
||||
const Value = @import("../../value.zig").Value;
|
||||
const TypedValue = @import("../../TypedValue.zig");
|
||||
const ZigObject = @This();
|
|
@ -1,4 +1,5 @@
|
|||
pub const File = union(enum) {
|
||||
zig_object: *ZigObject,
|
||||
internal: *InternalObject,
|
||||
object: *Object,
|
||||
dylib: *Dylib,
|
||||
|
@ -22,6 +23,7 @@ pub const File = union(enum) {
|
|||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
switch (file) {
|
||||
.zig_object => |x| try writer.writeAll(x.path),
|
||||
.internal => try writer.writeAll(""),
|
||||
.object => |x| try writer.print("{}", .{x.fmtPath()}),
|
||||
.dylib => |x| try writer.writeAll(x.path),
|
||||
|
@ -98,6 +100,7 @@ pub const File = union(enum) {
|
|||
|
||||
pub const Entry = union(enum) {
|
||||
null: void,
|
||||
zig_object: ZigObject,
|
||||
internal: InternalObject,
|
||||
object: Object,
|
||||
dylib: Dylib,
|
||||
|
@ -114,3 +117,4 @@ const MachO = @import("../MachO.zig");
|
|||
const Object = @import("Object.zig");
|
||||
const Dylib = @import("Dylib.zig");
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const ZigObject = @import("ZigObject.zig");
|
||||
|
|
|
@ -274,7 +274,7 @@ fn writeAtoms(macho_file: *MachO) !void {
|
|||
const atom = macho_file.getAtom(atom_index).?;
|
||||
assert(atom.flags.alive);
|
||||
const off = atom.value - header.addr;
|
||||
@memcpy(code[off..][0..atom.size], atom.getCode(macho_file));
|
||||
@memcpy(code[off..][0..atom.size], atom.getData(macho_file));
|
||||
try atom.writeRelocs(macho_file, code[off..][0..atom.size], &relocs);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user