authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-15 20:34:50+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:40+01:00
log6d0ba6dd10b9ba9137b3ea9532789fcc5e971649
tree866c19c472a2142c4f9eb59995635a2583b984a6
parent03b33b0f0139129e649f57952209586db188cb79

macho: introduce ZigObject


8 files changed, 262 insertions(+), 31 deletions(-)

CMakeLists.txt+1
......@@ -608,6 +608,7 @@ set(ZIG_STAGE2_SOURCES
608608 "${CMAKE_SOURCE_DIR}/src/link/MachO/Relocation.zig"
609609 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
610610 "${CMAKE_SOURCE_DIR}/src/link/MachO/UnwindInfo.zig"
611 "${CMAKE_SOURCE_DIR}/src/link/MachO/ZigObject.zig"
611612 "${CMAKE_SOURCE_DIR}/src/link/MachO/dead_strip.zig"
612613 "${CMAKE_SOURCE_DIR}/src/link/MachO/dyld_info/bind.zig"
613614 "${CMAKE_SOURCE_DIR}/src/link/MachO/dyld_info/Rebase.zig"
src/link/MachO.zig+21-7
......@@ -10,6 +10,7 @@ d_sym: ?DebugSymbols = null,
1010/// Index of each input file also encodes the priority or precedence of one input file
1111/// over another.
1212files: std.MultiArrayList(File.Entry) = .{},
13zig_object: ?File.Index = null,
1314internal_object: ?File.Index = null,
1415objects: std.ArrayListUnmanaged(File.Index) = .{},
1516dylibs: std.ArrayListUnmanaged(File.Index) = .{},
......@@ -222,12 +223,19 @@ pub fn createEmpty(
222223 try self.symbols.append(gpa, .{});
223224 try self.symbols_extra.append(gpa, 0);
224225
225 // TODO: init
226
227226 if (opt_zcu) |zcu| {
228227 if (!use_llvm) {
229 _ = zcu;
230 // TODO: create .zig_object
228 const index: File.Index = @intCast(try self.files.addOne(gpa));
229 self.files.set(index, .{ .zig_object = .{
230 .index = index,
231 .path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(
232 zcu.main_mod.root_src_path,
233 )}),
234 } });
235 self.zig_object = index;
236 try self.getZigObject().?.init(self);
237
238 // TODO init metadata
231239
232240 if (comp.config.debug_format != .strip) {
233241 // Create dSYM bundle.
......@@ -281,6 +289,7 @@ pub fn deinit(self: *MachO) void {
281289
282290 for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {
283291 .null => {},
292 .zig_object => data.zig_object.deinit(gpa),
284293 .internal => data.internal.deinit(gpa),
285294 .object => data.object.deinit(gpa),
286295 .dylib => data.dylib.deinit(gpa),
......@@ -3109,9 +3118,7 @@ pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
31093118
31103119pub fn getDeclVAddr(self: *MachO, decl_index: InternPool.DeclIndex, reloc_info: link.File.RelocInfo) !u64 {
31113120 assert(self.llvm_object == null);
3112 _ = decl_index;
3113 _ = reloc_info;
3114 @panic("TODO getDeclVAddr");
3121 return self.getZigObject().?.getDeclVAddr(self, decl_index, reloc_info);
31153122}
31163123
31173124pub fn lowerAnonDecl(
......@@ -3297,12 +3304,18 @@ pub fn getFile(self: *MachO, index: File.Index) ?File {
32973304 const tag = self.files.items(.tags)[index];
32983305 return switch (tag) {
32993306 .null => null,
3307 .zig_object => .{ .zig_object = &self.files.items(.data)[index].zig_object },
33003308 .internal => .{ .internal = &self.files.items(.data)[index].internal },
33013309 .object => .{ .object = &self.files.items(.data)[index].object },
33023310 .dylib => .{ .dylib = &self.files.items(.data)[index].dylib },
33033311 };
33043312}
33053313
3314pub fn getZigObject(self: *MachO) ?*ZigObject {
3315 const index = self.zig_object orelse return null;
3316 return self.getFile(index).?.zig_object;
3317}
3318
33063319pub fn getInternalObject(self: *MachO) ?*InternalObject {
33073320 const index = self.internal_object orelse return null;
33083321 return self.getFile(index).?.internal;
......@@ -4123,3 +4136,4 @@ const TlvPtrSection = synthetic.TlvPtrSection;
41234136const TypedValue = @import("../TypedValue.zig");
41244137const UnwindInfo = @import("MachO/UnwindInfo.zig");
41254138const WeakBindSection = synthetic.WeakBindSection;
4139const ZigObject = @import("MachO/ZigObject.zig");
src/link/MachO/Atom.zig+25-23
......@@ -45,10 +45,27 @@ pub fn getFile(self: Atom, macho_file: *MachO) File {
4545 return macho_file.getFile(self.file).?;
4646}
4747
48pub fn getData(self: Atom, macho_file: *MachO) []const u8 {
49 return switch (self.getFile(macho_file)) {
50 .zig_object => @panic("TODO Atom.getData"),
51 .object => |x| x.getAtomData(self),
52 else => unreachable,
53 };
54}
55
56pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {
57 return switch (self.getFile(macho_file)) {
58 .zig_object => @panic("TODO Atom.getRelocs"),
59 .object => |x| x.getAtomRelocs(self),
60 else => unreachable,
61 };
62}
63
4864pub fn getInputSection(self: Atom, macho_file: *MachO) macho.section_64 {
4965 return switch (self.getFile(macho_file)) {
50 .dylib => unreachable,
51 inline else => |x| x.sections.items(.header)[self.n_sect],
66 .zig_object => |x| x.getInputSection(self, macho_file),
67 .object => |x| x.sections.items(.header)[self.n_sect],
68 else => unreachable,
5269 };
5370}
5471
......@@ -61,26 +78,10 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 {
6178 return (@as(u64, @intCast(file.getIndex())) << 32) | @as(u64, @intCast(self.n_sect));
6279}
6380
64pub fn getCode(self: Atom, macho_file: *MachO) []const u8 {
65 const code = switch (self.getFile(macho_file)) {
66 .dylib => unreachable,
67 inline else => |x| x.getSectionData(self.n_sect),
68 };
69 return code[self.off..][0..self.size];
70}
71
72pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {
73 const relocs = switch (self.getFile(macho_file)) {
74 .dylib => unreachable,
75 inline else => |x| x.sections.items(.relocs)[self.n_sect],
76 };
77 return relocs.items[self.relocs.pos..][0..self.relocs.len];
78}
79
8081pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index {
8182 return switch (self.getFile(macho_file)) {
8283 .dylib => unreachable,
83 .internal => &[0]UnwindInfo.Record.Index{},
84 .zig_object, .internal => &[0]UnwindInfo.Record.Index{},
8485 .object => |x| x.unwind_records.items[self.unwind_records.pos..][0..self.unwind_records.len],
8586 };
8687}
......@@ -290,10 +291,10 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
290291 defer tracy.end();
291292
292293 assert(!self.getInputSection(macho_file).isZerofill());
293 const relocs = self.getRelocs(macho_file);
294294 const file = self.getFile(macho_file);
295295 const name = self.getName(macho_file);
296 @memcpy(buffer, self.getCode(macho_file));
296 const relocs = self.getRelocs(macho_file);
297 @memcpy(buffer, self.getData(macho_file));
297298
298299 relocs_log.debug("{x}: {s}", .{ self.value, name });
299300
......@@ -683,10 +684,11 @@ const x86_64 = struct {
683684};
684685
685686pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
687 const relocs = self.getRelocs(macho_file);
686688 switch (macho_file.getTarget().cpu.arch) {
687689 .aarch64 => {
688690 var nreloc: u32 = 0;
689 for (self.getRelocs(macho_file)) |rel| {
691 for (relocs) |rel| {
690692 nreloc += 1;
691693 switch (rel.type) {
692694 .page, .pageoff => if (rel.addend > 0) {
......@@ -697,7 +699,7 @@ pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
697699 }
698700 return nreloc;
699701 },
700 .x86_64 => return @intCast(self.getRelocs(macho_file).len),
702 .x86_64 => return @intCast(relocs.len),
701703 else => unreachable,
702704 }
703705}
src/link/MachO/Object.zig+10
......@@ -1547,6 +1547,16 @@ pub fn getSectionData(self: *const Object, index: u32) []const u8 {
15471547 return self.data[sect.offset..][0..sect.size];
15481548}
15491549
1550pub fn getAtomData(self: *const Object, atom: Atom) []const u8 {
1551 const data = self.getSectionData(atom.n_sect);
1552 return data[atom.off..][0..atom.size];
1553}
1554
1555pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation {
1556 const relocs = self.sections.items(.relocs)[atom.n_sect];
1557 return relocs.items[atom.relocs.pos..][0..atom.relocs.len];
1558}
1559
15501560fn getString(self: Object, off: u32) [:0]const u8 {
15511561 assert(off < self.strtab.len);
15521562 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
src/link/MachO/Symbol.zig+1
......@@ -306,6 +306,7 @@ fn format2(
306306 if (symbol.flags.weak) try writer.writeAll(" : weak");
307307 if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab");
308308 switch (file) {
309 .zig_object => |x| try writer.print(" : zig_object({d})", .{x.index}),
309310 .internal => |x| try writer.print(" : internal({d})", .{x.index}),
310311 .object => |x| try writer.print(" : object({d})", .{x.index}),
311312 .dylib => |x| try writer.print(" : dylib({d})", .{x.index}),
src/link/MachO/ZigObject.zig created+199
......@@ -0,0 +1,199 @@
1/// Externally owned memory.
2path: []const u8,
3index: File.Index,
4
5symtab: std.MultiArrayList(Nlist) = .{},
6
7symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
8atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
9
10output_symtab_ctx: MachO.SymtabCtx = .{},
11
12pub fn init(self: *ZigObject, macho_file: *MachO) !void {
13 const comp = macho_file.base.comp;
14 const gpa = comp.gpa;
15
16 try self.atoms.append(gpa, 0); // null input section
17}
18
19pub fn deinit(self: *ZigObject, allocator: Allocator) void {
20 self.symtab.deinit(allocator);
21 self.symbols.deinit(allocator);
22 self.atoms.deinit(allocator);
23}
24
25fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index {
26 try self.symtab.ensureUnusedCapacity(allocator, 1);
27 const index = @as(Symbol.Index, @intCast(self.symtab.addOneAssumeCapacity()));
28 self.symtab.set(index, .{
29 .nlist = MachO.null_sym,
30 .size = 0,
31 .atom = 0,
32 });
33 return index;
34}
35
36pub fn getDeclVAddr(
37 self: *ZigObject,
38 macho_file: *MachO,
39 decl_index: InternPool.DeclIndex,
40 reloc_info: link.File.RelocInfo,
41) !u64 {
42 _ = self;
43 _ = macho_file;
44 _ = decl_index;
45 _ = reloc_info;
46 @panic("TODO getDeclVAddr");
47}
48
49pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void {
50 _ = self;
51 _ = macho_file;
52 @panic("TODO resolveSymbols");
53}
54
55pub fn resetGlobals(self: *ZigObject, macho_file: *MachO) void {
56 for (self.symbols.items, 0..) |sym_index, nlist_idx| {
57 if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue;
58 const sym = macho_file.getSymbol(sym_index);
59 const name = sym.name;
60 sym.* = .{};
61 sym.name = name;
62 }
63}
64
65pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) !void {
66 const tracy = trace(@src());
67 defer tracy.end();
68
69 for (self.symbols.items) |sym_index| {
70 const sym = macho_file.getSymbol(sym_index);
71 const file = sym.getFile(macho_file) orelse continue;
72 if (file.getIndex() != self.index) continue;
73 if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;
74 sym.flags.output_symtab = true;
75 if (sym.isLocal()) {
76 try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
77 self.output_symtab_ctx.nlocals += 1;
78 } else if (sym.flags.@"export") {
79 try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file);
80 self.output_symtab_ctx.nexports += 1;
81 } else {
82 assert(sym.flags.import);
83 try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
84 self.output_symtab_ctx.nimports += 1;
85 }
86 self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1));
87 }
88}
89
90pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {
91 const tracy = trace(@src());
92 defer tracy.end();
93
94 for (self.symbols.items) |sym_index| {
95 const sym = macho_file.getSymbol(sym_index);
96 const file = sym.getFile(macho_file) orelse continue;
97 if (file.getIndex() != self.index) continue;
98 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
99 const n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
100 macho_file.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
101 macho_file.strtab.appendAssumeCapacity(0);
102 const out_sym = &macho_file.symtab.items[idx];
103 out_sym.n_strx = n_strx;
104 sym.setOutputSym(macho_file, out_sym);
105 }
106}
107
108pub fn getInputSection(self: ZigObject, atom: Atom, macho_file: *MachO) macho.section_64 {
109 _ = self;
110 var sect = macho_file.sections.items(.header)[atom.out_n_sect];
111 sect.addr = 0;
112 sect.offset = 0;
113 sect.size = atom.size;
114 sect.@"align" = atom.alignment.toLog2Units();
115 return sect;
116}
117
118pub fn fmtSymtab(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
119 return .{ .data = .{
120 .self = self,
121 .macho_file = macho_file,
122 } };
123}
124
125const FormatContext = struct {
126 self: *ZigObject,
127 macho_file: *MachO,
128};
129
130fn formatSymtab(
131 ctx: FormatContext,
132 comptime unused_fmt_string: []const u8,
133 options: std.fmt.FormatOptions,
134 writer: anytype,
135) !void {
136 _ = unused_fmt_string;
137 _ = options;
138 try writer.writeAll(" symbols\n");
139 for (ctx.self.symbols.items) |index| {
140 const sym = ctx.macho_file.getSymbol(index);
141 try writer.print(" {}\n", .{sym.fmt(ctx.macho_file)});
142 }
143}
144
145pub fn fmtAtoms(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatAtoms) {
146 return .{ .data = .{
147 .self = self,
148 .macho_file = macho_file,
149 } };
150}
151
152fn formatAtoms(
153 ctx: FormatContext,
154 comptime unused_fmt_string: []const u8,
155 options: std.fmt.FormatOptions,
156 writer: anytype,
157) !void {
158 _ = unused_fmt_string;
159 _ = options;
160 try writer.writeAll(" atoms\n");
161 for (ctx.self.atoms.items) |atom_index| {
162 const atom = ctx.macho_file.getAtom(atom_index) orelse continue;
163 try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)});
164 }
165}
166
167const Nlist = struct {
168 nlist: macho.nlist_64,
169 size: u64,
170 atom: Atom.Index,
171};
172
173const assert = std.debug.assert;
174const builtin = @import("builtin");
175const codegen = @import("../../codegen.zig");
176const link = @import("../../link.zig");
177const log = std.log.scoped(.link);
178const macho = std.macho;
179const mem = std.mem;
180const trace = @import("../../tracy.zig").trace;
181const std = @import("std");
182
183const Air = @import("../../Air.zig");
184const Allocator = std.mem.Allocator;
185const Archive = @import("Archive.zig");
186const Atom = @import("Atom.zig");
187const Dwarf = @import("../Dwarf.zig");
188const File = @import("file.zig").File;
189const InternPool = @import("../../InternPool.zig");
190const Liveness = @import("../../Liveness.zig");
191const MachO = @import("../MachO.zig");
192const Module = @import("../../Module.zig");
193const Object = @import("Object.zig");
194const Symbol = @import("Symbol.zig");
195const StringTable = @import("../StringTable.zig");
196const Type = @import("../../type.zig").Type;
197const Value = @import("../../value.zig").Value;
198const TypedValue = @import("../../TypedValue.zig");
199const ZigObject = @This();
src/link/MachO/file.zig+4
......@@ -1,4 +1,5 @@
11pub const File = union(enum) {
2 zig_object: *ZigObject,
23 internal: *InternalObject,
34 object: *Object,
45 dylib: *Dylib,
......@@ -22,6 +23,7 @@ pub const File = union(enum) {
2223 _ = unused_fmt_string;
2324 _ = options;
2425 switch (file) {
26 .zig_object => |x| try writer.writeAll(x.path),
2527 .internal => try writer.writeAll(""),
2628 .object => |x| try writer.print("{}", .{x.fmtPath()}),
2729 .dylib => |x| try writer.writeAll(x.path),
......@@ -98,6 +100,7 @@ pub const File = union(enum) {
98100
99101 pub const Entry = union(enum) {
100102 null: void,
103 zig_object: ZigObject,
101104 internal: InternalObject,
102105 object: Object,
103106 dylib: Dylib,
......@@ -114,3 +117,4 @@ const MachO = @import("../MachO.zig");
114117const Object = @import("Object.zig");
115118const Dylib = @import("Dylib.zig");
116119const Symbol = @import("Symbol.zig");
120const ZigObject = @import("ZigObject.zig");
src/link/MachO/relocatable.zig+1-1
......@@ -274,7 +274,7 @@ fn writeAtoms(macho_file: *MachO) !void {
274274 const atom = macho_file.getAtom(atom_index).?;
275275 assert(atom.flags.alive);
276276 const off = atom.value - header.addr;
277 @memcpy(code[off..][0..atom.size], atom.getCode(macho_file));
277 @memcpy(code[off..][0..atom.size], atom.getData(macho_file));
278278 try atom.writeRelocs(macho_file, code[off..][0..atom.size], &relocs);
279279 }
280280