Commit 6d0ba6dd10
Changed files (8)
src/link/MachO/Atom.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,
}
}
src/link/MachO/file.zig
@@ -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");
src/link/MachO/Object.zig
@@ -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);
src/link/MachO/relocatable.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);
}
src/link/MachO/Symbol.zig
@@ -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}),
src/link/MachO/ZigObject.zig
@@ -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();
src/link/MachO.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");
CMakeLists.txt
@@ -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"