authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-09 06:43:26+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-18 09:13:08+02:00
logc59583e43de35e91ac194860cd1eb63e61c272aa
tree5a6ea9b7847ee897e8bec59accccc05faa04c75a
parent9d5a900f4bf23fc3cf6e2848b9e9c370bba6c938

macho: migrate InternalObject and Dylib


3 files changed, 778 insertions(+), 344 deletions(-)

src/link/MachO.zig-139
......@@ -3823,145 +3823,6 @@ pub fn getFileHandle(self: MachO, index: File.HandleIndex) File.Handle {
38233823 return self.file_handles.items[index];
38243824}
38253825
3826pub fn addAtom(self: *MachO) error{OutOfMemory}!Atom.Index {
3827 const index = @as(Atom.Index, @intCast(self.atoms.items.len));
3828 const atom = try self.atoms.addOne(self.base.comp.gpa);
3829 atom.* = .{};
3830 return index;
3831}
3832
3833pub fn getAtom(self: *MachO, index: Atom.Index) ?*Atom {
3834 if (index == 0) return null;
3835 assert(index < self.atoms.items.len);
3836 return &self.atoms.items[index];
3837}
3838
3839pub fn addAtomExtra(self: *MachO, extra: Atom.Extra) !u32 {
3840 const fields = @typeInfo(Atom.Extra).Struct.fields;
3841 try self.atoms_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len);
3842 return self.addAtomExtraAssumeCapacity(extra);
3843}
3844
3845pub fn addAtomExtraAssumeCapacity(self: *MachO, extra: Atom.Extra) u32 {
3846 const index = @as(u32, @intCast(self.atoms_extra.items.len));
3847 const fields = @typeInfo(Atom.Extra).Struct.fields;
3848 inline for (fields) |field| {
3849 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
3850 u32 => @field(extra, field.name),
3851 else => @compileError("bad field type"),
3852 });
3853 }
3854 return index;
3855}
3856
3857pub fn getAtomExtra(self: *MachO, index: u32) ?Atom.Extra {
3858 if (index == 0) return null;
3859 const fields = @typeInfo(Atom.Extra).Struct.fields;
3860 var i: usize = index;
3861 var result: Atom.Extra = undefined;
3862 inline for (fields) |field| {
3863 @field(result, field.name) = switch (field.type) {
3864 u32 => self.atoms_extra.items[i],
3865 else => @compileError("bad field type"),
3866 };
3867 i += 1;
3868 }
3869 return result;
3870}
3871
3872pub fn setAtomExtra(self: *MachO, index: u32, extra: Atom.Extra) void {
3873 assert(index > 0);
3874 const fields = @typeInfo(Atom.Extra).Struct.fields;
3875 inline for (fields, 0..) |field, i| {
3876 self.atoms_extra.items[index + i] = switch (field.type) {
3877 u32 => @field(extra, field.name),
3878 else => @compileError("bad field type"),
3879 };
3880 }
3881}
3882
3883pub fn addSymbol(self: *MachO) !Symbol.Index {
3884 const index = @as(Symbol.Index, @intCast(self.symbols.items.len));
3885 const symbol = try self.symbols.addOne(self.base.comp.gpa);
3886 symbol.* = .{};
3887 return index;
3888}
3889
3890pub fn getSymbol(self: *MachO, index: Symbol.Index) *Symbol {
3891 assert(index < self.symbols.items.len);
3892 return &self.symbols.items[index];
3893}
3894
3895pub fn addSymbolExtra(self: *MachO, extra: Symbol.Extra) !u32 {
3896 const fields = @typeInfo(Symbol.Extra).Struct.fields;
3897 try self.symbols_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len);
3898 return self.addSymbolExtraAssumeCapacity(extra);
3899}
3900
3901pub fn addSymbolExtraAssumeCapacity(self: *MachO, extra: Symbol.Extra) u32 {
3902 const index = @as(u32, @intCast(self.symbols_extra.items.len));
3903 const fields = @typeInfo(Symbol.Extra).Struct.fields;
3904 inline for (fields) |field| {
3905 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
3906 u32 => @field(extra, field.name),
3907 else => @compileError("bad field type"),
3908 });
3909 }
3910 return index;
3911}
3912
3913pub fn getSymbolExtra(self: MachO, index: u32) ?Symbol.Extra {
3914 if (index == 0) return null;
3915 const fields = @typeInfo(Symbol.Extra).Struct.fields;
3916 var i: usize = index;
3917 var result: Symbol.Extra = undefined;
3918 inline for (fields) |field| {
3919 @field(result, field.name) = switch (field.type) {
3920 u32 => self.symbols_extra.items[i],
3921 else => @compileError("bad field type"),
3922 };
3923 i += 1;
3924 }
3925 return result;
3926}
3927
3928pub fn setSymbolExtra(self: *MachO, index: u32, extra: Symbol.Extra) void {
3929 assert(index > 0);
3930 const fields = @typeInfo(Symbol.Extra).Struct.fields;
3931 inline for (fields, 0..) |field, i| {
3932 self.symbols_extra.items[index + i] = switch (field.type) {
3933 u32 => @field(extra, field.name),
3934 else => @compileError("bad field type"),
3935 };
3936 }
3937}
3938
3939const GetOrCreateGlobalResult = struct {
3940 found_existing: bool,
3941 index: Symbol.Index,
3942};
3943
3944pub fn getOrCreateGlobal(self: *MachO, off: u32) !GetOrCreateGlobalResult {
3945 const gpa = self.base.comp.gpa;
3946 const gop = try self.globals.getOrPut(gpa, off);
3947 if (!gop.found_existing) {
3948 const index = try self.addSymbol();
3949 const global = self.getSymbol(index);
3950 global.name = off;
3951 global.flags.global = true;
3952 gop.value_ptr.* = index;
3953 }
3954 return .{
3955 .found_existing = gop.found_existing,
3956 .index = gop.value_ptr.*,
3957 };
3958}
3959
3960pub fn getGlobalByName(self: *MachO, name: []const u8) ?Symbol.Index {
3961 const off = self.strings.getOffset(name) orelse return null;
3962 return self.globals.get(off);
3963}
3964
39653826pub fn addThunk(self: *MachO) !Thunk.Index {
39663827 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
39673828 const thunk = try self.thunks.addOne(self.base.comp.gpa);
src/link/MachO/Dylib.zig+127-57
......@@ -7,6 +7,8 @@ id: ?Id = null,
77ordinal: u16 = 0,
88
99symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
10symbols_extra: std.ArrayListUnmanaged(u32) = .{},
11globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{},
1012dependents: std.ArrayListUnmanaged(Id) = .{},
1113rpaths: std.StringArrayHashMapUnmanaged(void) = .{},
1214umbrella: File.Index = 0,
......@@ -37,6 +39,8 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void {
3739 self.strtab.deinit(allocator);
3840 if (self.id) |*id| id.deinit(allocator);
3941 self.symbols.deinit(allocator);
42 self.symbols_extra.deinit(allocator);
43 self.globals.deinit(allocator);
4044 for (self.dependents.items) |*id| {
4145 id.deinit(allocator);
4246 }
......@@ -494,13 +498,21 @@ fn addObjCExport(
494498pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void {
495499 const gpa = macho_file.base.comp.gpa;
496500
497 try self.symbols.ensureTotalCapacityPrecise(gpa, self.exports.items(.name).len);
498
499 for (self.exports.items(.name)) |noff| {
500 const name = self.getString(noff);
501 const off = try macho_file.strings.insert(gpa, name);
502 const gop = try macho_file.getOrCreateGlobal(off);
503 self.symbols.addOneAssumeCapacity().* = gop.index;
501 const nsyms = self.exports.items(.name).len;
502 try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
503 try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
504 try self.globals.ensureTotalCapacityPrecise(gpa, nsyms);
505 self.globals.resize(gpa, nsyms) catch unreachable;
506 @memset(self.globals.items, 0);
507
508 for (self.exports.items(.name), self.exports.items(.flags)) |noff, flags| {
509 const index = self.addSymbolAssumeCapacity();
510 const symbol = &self.symbols.items[index];
511 symbol.name = noff;
512 symbol.extra = self.addSymbolExtraAssumeCapacity(.{});
513 symbol.flags.weak = flags.weak;
514 symbol.flags.tlv = flags.tlv;
515 symbol.visibility = .global;
504516 }
505517}
506518
......@@ -510,37 +522,31 @@ pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) void {
510522
511523 if (!self.explicit and !self.hoisted) return;
512524
513 for (self.symbols.items, self.exports.items(.flags)) |index, flags| {
514 const global = macho_file.getSymbol(index);
525 const gpa = macho_file.base.comp.gpa;
526
527 for (self.exports.items(.flags), self.globals.items, 0..) |flags, *global, i| {
528 const gop = try macho_file.resolver.getOrPut(gpa, .{
529 .index = @intCast(i),
530 .file = self.index,
531 }, macho_file);
532 if (!gop.found_existing) {
533 gop.ref.* = .{ .index = 0, .file = 0 };
534 }
535 global.* = gop.index;
536
537 if (gop.ref.getFile(macho_file) == null) {
538 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
539 continue;
540 }
541
515542 if (self.asFile().getSymbolRank(.{
516543 .weak = flags.weak,
517 }) < global.getSymbolRank(macho_file)) {
518 global.value = 0;
519 global.atom = 0;
520 global.nlist_idx = 0;
521 global.file = self.index;
522 global.flags.weak = flags.weak;
523 global.flags.tlv = flags.tlv;
524 global.flags.dyn_ref = false;
525 global.flags.tentative = false;
526 global.visibility = .global;
544 }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) {
545 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
527546 }
528547 }
529548}
530549
531pub fn resetGlobals(self: *Dylib, macho_file: *MachO) void {
532 for (self.symbols.items) |sym_index| {
533 const sym = macho_file.getSymbol(sym_index);
534 const name = sym.name;
535 const global = sym.flags.global;
536 const weak_ref = sym.flags.weak_ref;
537 sym.* = .{};
538 sym.name = name;
539 sym.flags.global = global;
540 sym.flags.weak_ref = weak_ref;
541 }
542}
543
544550pub fn isAlive(self: Dylib, macho_file: *MachO) bool {
545551 if (!macho_file.dead_strip_dylibs) return self.explicit or self.referenced or self.needed;
546552 return self.referenced or self.needed;
......@@ -550,48 +556,52 @@ pub fn markReferenced(self: *Dylib, macho_file: *MachO) void {
550556 const tracy = trace(@src());
551557 defer tracy.end();
552558
553 for (self.symbols.items) |global_index| {
554 const global = macho_file.getSymbol(global_index);
555 const file_ptr = global.getFile(macho_file) orelse continue;
556 if (file_ptr.getIndex() != self.index) continue;
559 for (0..self.symbols.items.len) |i| {
560 const ref = self.getSymbolRef(@intCast(i), macho_file);
561 const file = ref.getFile(macho_file) orelse continue;
562 if (file.getIndex() != self.index) continue;
563 const global = ref.getSymbol(macho_file).?;
557564 if (global.isLocal()) continue;
558565 self.referenced = true;
559566 break;
560567 }
561568}
562569
563pub fn calcSymtabSize(self: *Dylib, macho_file: *MachO) !void {
570pub fn calcSymtabSize(self: *Dylib, macho_file: *MachO) void {
564571 const tracy = trace(@src());
565572 defer tracy.end();
566573
567 for (self.symbols.items) |global_index| {
568 const global = macho_file.getSymbol(global_index);
569 const file_ptr = global.getFile(macho_file) orelse continue;
570 if (file_ptr.getIndex() != self.index) continue;
571 if (global.isLocal()) continue;
572 assert(global.flags.import);
573 global.flags.output_symtab = true;
574 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
574 for (self.symbols.items, 0..) |*sym, i| {
575 const ref = self.getSymbolRef(@intCast(i), macho_file);
576 const file = ref.getFile(macho_file) orelse continue;
577 if (file.getIndex() != self.index) continue;
578 if (sym.isLocal()) continue;
579 assert(sym.flags.import);
580 sym.flags.output_symtab = true;
581 sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
575582 self.output_symtab_ctx.nimports += 1;
576 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.getName(macho_file).len + 1));
583 self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1));
577584 }
578585}
579586
580pub fn writeSymtab(self: Dylib, macho_file: *MachO, ctx: anytype) void {
587pub fn writeSymtab(self: Dylib, macho_file: *MachO) void {
581588 const tracy = trace(@src());
582589 defer tracy.end();
583590
584 for (self.symbols.items) |global_index| {
585 const global = macho_file.getSymbol(global_index);
586 const file = global.getFile(macho_file) orelse continue;
591 var n_strx = self.output_symtab_ctx.stroff;
592 for (self.symbols.items, 0..) |sym, i| {
593 const ref = self.getSymbolRef(@intCast(i), macho_file);
594 const file = ref.getFile(macho_file) orelse continue;
587595 if (file.getIndex() != self.index) continue;
588 const idx = global.getOutputSymtabIndex(macho_file) orelse continue;
589 const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
590 ctx.strtab.appendSliceAssumeCapacity(global.getName(macho_file));
591 ctx.strtab.appendAssumeCapacity(0);
592 const out_sym = &ctx.symtab.items[idx];
596 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
597 const out_sym = &macho_file.symtab.items[idx];
593598 out_sym.n_strx = n_strx;
594 global.setOutputSym(macho_file, out_sym);
599 sym.setOutputSym(macho_file, out_sym);
600 const name = sym.getName(macho_file);
601 @memcpy(macho_file.strtab.items[n_strx..][0..name.len], name);
602 n_strx += @intCast(name.len);
603 macho_file.strtab.items[n_strx] = 0;
604 n_strx += 1;
595605 }
596606}
597607
......@@ -605,7 +615,7 @@ fn addString(self: *Dylib, allocator: Allocator, name: []const u8) !u32 {
605615 return off;
606616}
607617
608pub inline fn getString(self: Dylib, off: u32) [:0]const u8 {
618pub fn getString(self: Dylib, off: u32) [:0]const u8 {
609619 assert(off < self.strtab.items.len);
610620 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
611621}
......@@ -614,6 +624,66 @@ pub fn asFile(self: *Dylib) File {
614624 return .{ .dylib = self };
615625}
616626
627fn addSymbol(self: *Dylib, allocator: Allocator) !Symbol.Index {
628 try self.symbols.ensureUnusedCapacity(allocator, 1);
629 return self.addSymbolAssumeCapacity();
630}
631
632fn addSymbolAssumeCapacity(self: *Dylib) Symbol.Index {
633 const index: Symbol.Index = @intCast(self.symbols.items.len);
634 const symbol = self.symbols.addOneAssumeCapacity();
635 symbol.* = .{ .file = self.index };
636 return index;
637}
638
639pub fn getSymbolRef(self: Dylib, index: Symbol.Index, macho_file: *MachO) MachO.Ref {
640 const global_index = self.globals.items[index];
641 if (macho_file.resolver.get(global_index)) |ref| return ref;
642 return .{ .index = index, .file = self.index };
643}
644
645pub fn addSymbolExtra(self: *Dylib, allocator: Allocator, extra: Symbol.Extra) !u32 {
646 const fields = @typeInfo(Symbol.Extra).Struct.fields;
647 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
648 return self.addSymbolExtraAssumeCapacity(extra);
649}
650
651fn addSymbolExtraAssumeCapacity(self: *Dylib, extra: Symbol.Extra) u32 {
652 const index = @as(u32, @intCast(self.symbols_extra.items.len));
653 const fields = @typeInfo(Symbol.Extra).Struct.fields;
654 inline for (fields) |field| {
655 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
656 u32 => @field(extra, field.name),
657 else => @compileError("bad field type"),
658 });
659 }
660 return index;
661}
662
663pub fn getSymbolExtra(self: Dylib, index: u32) Symbol.Extra {
664 const fields = @typeInfo(Symbol.Extra).Struct.fields;
665 var i: usize = index;
666 var result: Symbol.Extra = undefined;
667 inline for (fields) |field| {
668 @field(result, field.name) = switch (field.type) {
669 u32 => self.symbols_extra.items[i],
670 else => @compileError("bad field type"),
671 };
672 i += 1;
673 }
674 return result;
675}
676
677pub fn setSymbolExtra(self: *Dylib, index: u32, extra: Symbol.Extra) void {
678 const fields = @typeInfo(Symbol.Extra).Struct.fields;
679 inline for (fields, 0..) |field, i| {
680 self.symbols_extra.items[index + i] = switch (field.type) {
681 u32 => @field(extra, field.name),
682 else => @compileError("bad field type"),
683 };
684 }
685}
686
617687pub fn format(
618688 self: *Dylib,
619689 comptime unused_fmt_string: []const u8,
src/link/MachO/InternalObject.zig+651-148
......@@ -1,12 +1,28 @@
11index: File.Index,
22
33sections: std.MultiArrayList(Section) = .{},
4atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
5symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
4atoms: std.ArrayListUnmanaged(Atom) = .{},
5atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
6atoms_extra: std.ArrayListUnmanaged(u32) = .{},
7symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
8strtab: std.ArrayListUnmanaged(u8) = .{},
9symbols: std.ArrayListUnmanaged(Symbol) = .{},
10symbols_extra: std.ArrayListUnmanaged(u32) = .{},
11globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{},
612
713objc_methnames: std.ArrayListUnmanaged(u8) = .{},
814objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64),
915
16force_undefined: std.ArrayListUnmanaged(Symbol.Index) = .{},
17entry_index: ?Symbol.Index = null,
18dyld_stub_binder_index: ?Symbol.Index = null,
19dyld_private: ?Symbol.Index = null,
20objc_msg_send_index: ?Symbol.Index = null,
21mh_execute_header_index: ?Symbol.Index = null,
22mh_dylib_header_index: ?Symbol.Index = null,
23dso_handle_index: ?Symbol.Index = null,
24boundary_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
25
1026output_symtab_ctx: MachO.SymtabCtx = .{},
1127
1228pub fn deinit(self: *InternalObject, allocator: Allocator) void {
......@@ -15,39 +31,224 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void {
1531 }
1632 self.sections.deinit(allocator);
1733 self.atoms.deinit(allocator);
34 self.atoms_indexes.deinit(allocator);
35 self.atoms_extra.deinit(allocator);
36 self.symtab.deinit(allocator);
37 self.strtab.deinit(allocator);
1838 self.symbols.deinit(allocator);
39 self.symbols_extra.deinit(allocator);
40 self.globals.deinit(allocator);
1941 self.objc_methnames.deinit(allocator);
42 self.force_undefined.deinit(allocator);
43 self.boundary_symbols.deinit(allocator);
44}
45
46pub fn init(self: *InternalObject, allocator: Allocator) !void {
47 // Atom at index 0 is reserved as null atom.
48 try self.atoms.append(allocator, .{});
49 try self.atoms_extra.append(allocator, 0);
50 // Null byte in strtab
51 try self.strtab.append(allocator, 0);
2052}
2153
22pub fn addSymbol(self: *InternalObject, name: [:0]const u8, macho_file: *MachO) !Symbol.Index {
54pub fn initSymbols(self: *InternalObject, macho_file: *MachO) !void {
55 const createSymbol = struct {
56 fn createSymbol(obj: *InternalObject, name: u32, args: struct {
57 type: u8 = macho.N_UNDF | macho.N_EXT,
58 desc: u16 = 0,
59 }) Symbol.Index {
60 const index = obj.addSymbolAssumeCapacity();
61 const symbol = &obj.symbols.items[index];
62 symbol.name = name;
63 symbol.extra = obj.addSymbolExtraAssumeCapacity(.{});
64 symbol.flags.dyn_ref = args.desc & macho.REFERENCED_DYNAMICALLY != 0;
65 symbol.visibility = if (args.type & macho.N_EXT != 0) blk: {
66 break :blk if (args.type & macho.N_PEXT != 0) .hidden else .global;
67 } else .local;
68
69 const nlist_idx: u32 = @intCast(obj.symtab.items.len);
70 const nlist = obj.symtab.addOneAssumeCapacity();
71 nlist.* = .{
72 .n_strx = name,
73 .n_type = args.type,
74 .n_sect = 0,
75 .n_desc = args.desc,
76 .n_value = 0,
77 };
78 symbol.nlist_idx = nlist_idx;
79 return index;
80 }
81 }.createSymbol;
82
2383 const gpa = macho_file.base.comp.gpa;
24 try self.symbols.ensureUnusedCapacity(gpa, 1);
25 const off = try macho_file.strings.insert(gpa, name);
26 const gop = try macho_file.getOrCreateGlobal(off);
27 self.symbols.addOneAssumeCapacity().* = gop.index;
28 const sym = macho_file.getSymbol(gop.index);
29 sym.file = self.index;
30 sym.value = 0;
31 sym.atom = 0;
32 sym.nlist_idx = 0;
33 sym.flags = .{ .global = true };
34 return gop.index;
84 var nsyms = macho_file.base.comp.force_undefined_symbols.keys().len;
85 nsyms += 1; // dyld_stub_binder
86 nsyms += 1; // _objc_msgSend
87 if (!macho_file.base.isDynLib()) {
88 nsyms += 1; // entry
89 nsyms += 1; // __mh_execute_header
90 } else {
91 nsyms += 1; // __mh_dylib_header
92 }
93 nsyms += 1; // ___dso_handle
94 nsyms += 1; // dyld_private
95
96 try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
97 try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
98 try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);
99 try self.globals.ensureTotalCapacityPrecise(gpa, nsyms);
100 self.globals.resize(gpa, nsyms) catch unreachable;
101 @memset(self.globals.items, 0);
102
103 try self.force_undefined.ensureTotalCapacityPrecise(gpa, macho_file.base.comp.force_undefined_symbols.keys().len);
104 for (macho_file.base.comp.force_undefined_symbols.keys()) |name| {
105 self.force_undefined.addOneAssumeCapacity().* = createSymbol(self, try self.addString(gpa, name), .{});
106 }
107
108 self.dyld_stub_binder_index = createSymbol(self, try self.addString(gpa, "dyld_stub_binder"), .{});
109 self.objc_msg_send_index = createSymbol(self, try self.addString(gpa, "_objc_msgSend"), .{});
110
111 if (!macho_file.base.isDynLib()) {
112 self.entry_index = createSymbol(self, try self.addString(gpa, macho_file.entry_name orelse "_main"), .{});
113 self.mh_execute_header_index = createSymbol(self, try self.addString(gpa, "__mh_execute_header"), .{
114 .type = macho.N_SECT | macho.N_EXT,
115 .desc = macho.REFERENCED_DYNAMICALLY,
116 });
117 } else {
118 self.mh_dylib_header_index = createSymbol(self, try self.addString(gpa, "__mh_dylib_header"), .{
119 .type = macho.N_SECT | macho.N_EXT,
120 });
121 }
122
123 self.dso_handle_index = createSymbol(self, try self.addString(gpa, "___dso_handle"), .{
124 .type = macho.N_SECT | macho.N_EXT,
125 });
126 self.dyld_private_index = createSymbol(self, try self.addString(gpa, "dyld_private"), .{
127 .type = macho.N_SECT,
128 });
35129}
36130
37/// Creates a fake input sections __TEXT,__objc_methname and __DATA,__objc_selrefs.
38pub fn addObjcMsgsendSections(self: *InternalObject, sym_name: []const u8, macho_file: *MachO) !Atom.Index {
39 const methname_atom_index = try self.addObjcMethnameSection(sym_name, macho_file);
40 return try self.addObjcSelrefsSection(methname_atom_index, macho_file);
131pub fn resolveSymbols(self: *InternalObject, macho_file: *MachO) !void {
132 const tracy = trace(@src());
133 defer tracy.end();
134
135 const gpa = macho_file.base.comp.gpa;
136
137 for (self.symtab.items, self.globals.items, 0..) |nlist, *global, i| {
138 const gop = try macho_file.resolver.getOrPut(gpa, .{
139 .index = @intCast(i),
140 .file = self.index,
141 }, macho_file);
142 if (!gop.found_existing) {
143 gop.ref.* = .{ .index = 0, .file = 0 };
144 }
145 global.* = gop.index;
146
147 if (nlist.undf()) continue;
148 if (gop.ref.getFile(macho_file) == null) {
149 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
150 continue;
151 }
152
153 if (self.asFile().getSymbolRank(.{
154 .archive = false,
155 .weak = false,
156 .tentative = false,
157 }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) {
158 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
159 }
160 }
41161}
42162
43fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_file: *MachO) !Atom.Index {
163pub fn resolveBoundarySymbols(self: *InternalObject, macho_file: *MachO) !void {
164 const tracy = trace(@src());
165 defer tracy.end();
166
44167 const gpa = macho_file.base.comp.gpa;
45 const atom_index = try macho_file.addAtom();
46 try self.atoms.append(gpa, atom_index);
168 var boundary_symbols = std.StringArrayHashMap(MachO.Ref).init(gpa);
169 defer boundary_symbols.deinit();
170
171 for (macho_file.objects.items) |index| {
172 const object = macho_file.getFile(index).?.object;
173 for (object.symbols.items, 0..) |sym, i| {
174 const nlist = object.symtab.items(.nlist)[i];
175 if (!nlist.undf() or !nlist.ext()) continue;
176 const ref = object.getSymbolRef(@intCast(i), macho_file);
177 if (ref.getFile(macho_file) != null) continue;
178 const name = sym.getName(macho_file);
179 if (mem.startsWith(u8, name, "segment$start$") or
180 mem.startsWith(u8, name, "segment$stop$") or
181 mem.startsWith(u8, name, "section$start$") or
182 mem.startsWith(u8, name, "section$stop$"))
183 {
184 const gop = try boundary_symbols.getOrPut(name);
185 if (!gop.found_existing) {
186 gop.value_ptr.* = .{ .index = @intCast(i), .file = index };
187 }
188 }
189 }
190 }
191
192 const nsyms = boundary_symbols.values().len;
193 try self.boundary_symbols.ensureTotalCapacityPrecise(gpa, nsyms);
194 try self.symbols.ensureUnusedCapacity(gpa, nsyms);
195 try self.symtab.ensureUnusedCapacity(gpa, nsyms);
196 try self.symbols_extra.ensureUnusedCapacity(gpa, nsyms * @sizeOf(Symbol.Extra));
197 try self.globals.ensureUnusedCapacity(gpa, nsyms);
198
199 for (boundary_symbols.keys(), boundary_symbols.values()) |name, ref| {
200 const name_off = try self.addString(gpa, name);
201 const sym_index = self.addSymbolAssumeCapacity();
202 self.boundary_symbols.appendAssumeCapacity(sym_index);
203 const sym = &self.symbols.items[sym_index];
204 sym.name = name_off;
205 sym.visibility = .local;
206 const nlist_idx: u32 = @intCast(self.symtab.items.len);
207 const nlist = self.symtab.addOneAssumeCapacity();
208 nlist.* = .{
209 .n_strx = name_off.pos,
210 .n_type = macho.N_SECT,
211 .n_sect = 0,
212 .n_desc = 0,
213 .n_value = 0,
214 };
215 sym.nlist_idx = nlist_idx;
216 sym.extra = self.addSymbolExtraAssumeCapacity(.{});
217
218 const idx = ref.getFile(macho_file).?.object.globals.items[ref.index];
219 self.globals.addOneAssumeCapacity().* = idx;
220 macho_file.resolver.values.items[idx - 1] = .{ .index = sym_index, .file = self.index };
221 }
222}
223
224pub fn markLive(self: *InternalObject, macho_file: *MachO) void {
225 const tracy = trace(@src());
226 defer tracy.end();
227
228 for (0..self.symbols.items.len) |i| {
229 const nlist = self.symtab.items[i];
230 if (!nlist.ext()) continue;
231
232 const ref = self.getSymbolRef(@intCast(i), macho_file);
233 const file = ref.getFile(macho_file) orelse continue;
234 if (file == .object and !file.object.alive) {
235 file.object.alive = true;
236 file.object.markLive(macho_file);
237 }
238 }
239}
47240
48 const atom = macho_file.getAtom(atom_index).?;
49 atom.atom_index = atom_index;
50 atom.file = self.index;
241/// Creates a fake input sections __TEXT,__objc_methname and __DATA,__objc_selrefs.
242pub fn addObjcMsgsendSections(self: *InternalObject, sym_name: []const u8, macho_file: *MachO) !Symbol.Index {
243 const methname_sym_index = try self.addObjcMethnameSection(sym_name, macho_file);
244 return try self.addObjcSelrefsSection(methname_sym_index, macho_file);
245}
246
247fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_file: *MachO) !Symbol.Index {
248 const gpa = macho_file.base.comp.gpa;
249 const atom_index = try self.addAtom(gpa);
250 try self.atoms_indexes.append(gpa, atom_index);
251 const atom = self.getAtom(atom_index).?;
51252 atom.size = methname.len + 1;
52253 atom.alignment = .@"1";
53254
......@@ -63,19 +264,34 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
63264 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);
64265 self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable;
65266
267 const name_str = try self.addString(gpa, "ltmp");
268 const sym_index = try self.addSymbol(gpa);
269 const sym = &self.symbols.items[sym_index];
270 sym.name = name_str;
271 sym.atom_ref = .{ .index = atom_index, .file = self.index };
272 sym.extra = try self.addSymbolExtra(gpa, .{});
273 const nlist_idx: u32 = @intCast(self.symtab.items.len);
274 const nlist = try self.symtab.addOne(gpa);
275 nlist.* = .{
276 .n_strx = name_str.pos,
277 .n_type = macho.N_SECT,
278 .n_sect = @intCast(n_sect + 1),
279 .n_desc = 0,
280 .n_value = 0,
281 };
282 sym.nlist_idx = nlist_idx;
283 try self.globals.append(gpa, 0);
284
66285 return atom_index;
67286}
68287
69fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, macho_file: *MachO) !Atom.Index {
70 const gpa = macho_file.base.comp.gpa;
71 const atom_index = try macho_file.addAtom();
72 try self.atoms.append(gpa, atom_index);
73
74 const atom = macho_file.getAtom(atom_index).?;
75 atom.atom_index = atom_index;
76 atom.file = self.index;
288fn addObjcSelrefsSection(self: *InternalObject, methname_sym_index: Symbol.Index, macho_file: *MachO) !Symbol.Index {
289 const gpa = macho_file.base.allocator;
290 const atom_index = try self.addAtom(gpa);
291 try self.atoms_indexes.append(gpa, atom_index);
292 const atom = self.getAtom(atom_index).?;
77293 atom.size = @sizeOf(u64);
78 atom.alignment = .@"8";
294 atom.alignment = 3;
79295
80296 const n_sect = try self.addSection(gpa, "__DATA", "__objc_selrefs");
81297 const sect = &self.sections.items(.header)[n_sect];
......@@ -89,9 +305,9 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index,
89305 const relocs = &self.sections.items(.relocs)[n_sect];
90306 try relocs.ensureUnusedCapacity(gpa, 1);
91307 relocs.appendAssumeCapacity(.{
92 .tag = .local,
308 .tag = .@"extern",
93309 .offset = 0,
94 .target = methname_atom_index,
310 .target = methname_sym_index,
95311 .addend = 0,
96312 .type = .unsigned,
97313 .meta = .{
......@@ -101,139 +317,283 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index,
101317 .has_subtractor = false,
102318 },
103319 });
104 try atom.addExtra(.{ .rel_index = 0, .rel_count = 1 }, macho_file);
105 atom.flags.relocs = true;
320 atom.addExtra(.{ .rel_index = 0, .rel_count = 1 }, macho_file);
321
322 const sym_index = try self.addSymbol(gpa);
323 const sym = &self.symbols.items[sym_index];
324 sym.atom_ref = .{ .index = atom_index, .file = self.index };
325 sym.extra = try self.addSymbolExtra(gpa, .{});
326 const nlist_idx: u32 = @intCast(self.symtab.items.len);
327 const nlist = try self.symtab.addOne(gpa);
328 nlist.* = .{
329 .n_strx = 0,
330 .n_type = macho.N_SECT,
331 .n_sect = @intCast(n_sect + 1),
332 .n_desc = 0,
333 .n_value = 0,
334 };
335 sym.nlist_idx = nlist_idx;
336 try self.globals.append(gpa, 0);
337 atom.addExtra(.{ .literal_symbol_index = sym_index }, macho_file);
106338
107 return atom_index;
339 return sym_index;
340}
341
342pub fn resolveObjcMsgSendSymbols(self: *InternalObject, macho_file: *MachO) !void {
343 const tracy = trace(@src());
344 defer tracy.end();
345
346 const gpa = macho_file.base.comp.gpa;
347
348 var objc_msgsend_syms = std.StringArrayHashMap(MachO.Ref).init(gpa);
349 defer objc_msgsend_syms.deinit();
350
351 for (macho_file.objects.items) |index| {
352 const object = macho_file.getFile(index).?.object;
353
354 for (object.symbols.items, 0..) |sym, i| {
355 const nlist = object.symtab.items(.nlist)[i];
356 if (!nlist.ext()) continue;
357 if (!nlist.undf()) continue;
358
359 const ref = object.getSymbolRef(@intCast(i), macho_file);
360 if (ref.getFile(macho_file) != null) continue;
361
362 const name = sym.getName(macho_file);
363 if (mem.startsWith(u8, name, "_objc_msgSend$")) {
364 const gop = try objc_msgsend_syms.getOrPut(name);
365 if (!gop.found_existing) {
366 gop.value_ptr.* = .{ .index = @intCast(i), .file = index };
367 }
368 }
369 }
370 }
371
372 for (objc_msgsend_syms.keys(), objc_msgsend_syms.values()) |sym_name, ref| {
373 const name = MachO.eatPrefix(sym_name, "_objc_msgSend$").?;
374 const selrefs_index = try self.addObjcMsgsendSections(name, macho_file);
375
376 const name_off = try self.addString(gpa, sym_name);
377 const sym_index = try self.addSymbol(gpa);
378 const sym = &self.symbols.items[sym_index];
379 sym.name = name_off;
380 sym.visibility = .hidden;
381 const nlist_idx: u32 = @intCast(self.symtab.items.len);
382 const nlist = try self.symtab.addOne(gpa);
383 nlist.* = .{
384 .n_strx = name_off,
385 .n_type = macho.N_SECT | macho.N_EXT | macho.N_PEXT,
386 .n_sect = 0,
387 .n_desc = 0,
388 .n_value = 0,
389 };
390 sym.nlist_idx = nlist_idx;
391 sym.extra = try self.addSymbolExtra(gpa, .{ .objc_selrefs = selrefs_index });
392 sym.setSectionFlags(.{ .objc_stubs = true });
393
394 const idx = ref.getFile(macho_file).?.object.globals.items[ref.index];
395 try self.globals.append(gpa, idx);
396 macho_file.resolver.values.items[idx - 1] = .{ .index = sym_index, .file = self.index };
397 }
108398}
109399
110pub fn resolveLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
400pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
401 const tracy = trace(@src());
402 defer tracy.end();
403
111404 const gpa = macho_file.base.comp.gpa;
112405
113406 var buffer = std.ArrayList(u8).init(gpa);
114407 defer buffer.deinit();
115408
116409 const slice = self.sections.slice();
117 for (slice.items(.header), self.atoms.items, 0..) |header, atom_index, n_sect| {
118 if (Object.isCstringLiteral(header) or Object.isFixedSizeLiteral(header)) {
119 const data = try self.getSectionData(@intCast(n_sect));
120 const atom = macho_file.getAtom(atom_index).?;
121 const res = try lp.insert(gpa, header.type(), data);
122 if (!res.found_existing) {
123 res.atom.* = atom_index;
124 }
125 atom.flags.literal_pool = true;
126 try atom.addExtra(.{ .literal_index = res.index }, macho_file);
127 } else if (Object.isPtrLiteral(header)) {
128 const atom = macho_file.getAtom(atom_index).?;
129 const relocs = atom.getRelocs(macho_file);
130 assert(relocs.len == 1);
131 const rel = relocs[0];
132 assert(rel.tag == .local);
133 const target = macho_file.getAtom(rel.target).?;
134 const addend = std.math.cast(u32, rel.addend) orelse return error.Overflow;
135 const target_size = std.math.cast(usize, target.size) orelse return error.Overflow;
136 try buffer.ensureUnusedCapacity(target_size);
137 buffer.resize(target_size) catch unreachable;
138 try target.getData(macho_file, buffer.items);
139 const res = try lp.insert(gpa, header.type(), buffer.items[addend..]);
140 buffer.clearRetainingCapacity();
141 if (!res.found_existing) {
142 res.atom.* = atom_index;
143 }
144 atom.flags.literal_pool = true;
145 try atom.addExtra(.{ .literal_index = res.index }, macho_file);
410 for (slice.items(.header), self.getAtoms()) |header, atom_index| {
411 if (!Object.isPtrLiteral(header)) continue;
412 const atom = self.getAtom(atom_index).?;
413 const relocs = atom.getRelocs(macho_file);
414 assert(relocs.len == 1);
415 const rel = relocs[0];
416 assert(rel.tag == .@"extern");
417 const target = rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?;
418 try buffer.ensureUnusedCapacity(target.size);
419 buffer.resize(target.size) catch unreachable;
420 @memcpy(buffer.items, self.getSectionData(target.n_sect));
421 const res = try lp.insert(gpa, header.type(), buffer.items);
422 buffer.clearRetainingCapacity();
423 if (!res.found_existing) {
424 res.ref.* = .{ .index = atom.getExtra(macho_file).literal_symbol_index, .file = self.index };
425 } else {
426 const lp_sym = lp.getSymbol(res.index, macho_file);
427 const lp_atom = lp_sym.getAtom(macho_file).?;
428 lp_atom.alignment = @max(lp_atom.alignment, atom.alignment);
429 atom.flags.alive = false;
146430 }
431 atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
147432 }
148433}
149434
150pub fn dedupLiterals(self: InternalObject, lp: MachO.LiteralPool, macho_file: *MachO) void {
151 for (self.atoms.items) |atom_index| {
152 const atom = macho_file.getAtom(atom_index) orelse continue;
153 if (!atom.flags.alive) continue;
154 if (!atom.flags.relocs) continue;
435pub fn dedupLiterals(self: *InternalObject, lp: MachO.LiteralPool, macho_file: *MachO) void {
436 const tracy = trace(@src());
437 defer tracy.end();
438
439 for (self.getAtoms()) |atom_index| {
440 const atom = self.getAtom(atom_index) orelse continue;
441 if (!atom.alive.load(.seq_cst)) continue;
155442
156443 const relocs = blk: {
157 const extra = atom.getExtra(macho_file).?;
444 const extra = atom.getExtra(macho_file);
158445 const relocs = self.sections.items(.relocs)[atom.n_sect].items;
159446 break :blk relocs[extra.rel_index..][0..extra.rel_count];
160447 };
161 for (relocs) |*rel| switch (rel.tag) {
162 .local => {
163 const target = macho_file.getAtom(rel.target).?;
164 if (target.getLiteralPoolIndex(macho_file)) |lp_index| {
165 const lp_atom = lp.getAtom(lp_index, macho_file);
166 if (target.atom_index != lp_atom.atom_index) {
167 lp_atom.alignment = lp_atom.alignment.max(target.alignment);
168 target.flags.alive = false;
169 rel.target = lp_atom.atom_index;
170 }
171 }
172 },
173 .@"extern" => {
174 const target_sym = rel.getTargetSymbol(macho_file);
175 if (target_sym.getAtom(macho_file)) |target_atom| {
176 if (target_atom.getLiteralPoolIndex(macho_file)) |lp_index| {
177 const lp_atom = lp.getAtom(lp_index, macho_file);
178 if (target_atom.atom_index != lp_atom.atom_index) {
179 lp_atom.alignment = lp_atom.alignment.max(target_atom.alignment);
180 target_atom.flags.alive = false;
181 target_sym.atom = lp_atom.atom_index;
182 }
183 }
184 }
185 },
448 for (relocs) |*rel| {
449 if (rel.tag != .@"extern") continue;
450 const target_sym_ref = rel.getTargetSymbolRef(atom.*, macho_file);
451 const file = target_sym_ref.getFile(macho_file) orelse continue;
452 if (file.getIndex() != self.index) continue;
453 const target_sym = target_sym_ref.getSymbol(macho_file).?;
454 const target_atom = target_sym.getAtom(macho_file) orelse continue;
455 if (!Object.isPtrLiteral(target_atom.getInputSection(macho_file))) continue;
456 const lp_index = target_atom.getExtra(macho_file).literal_pool_index;
457 const lp_sym = lp.getSymbol(lp_index, macho_file);
458 const lp_atom_ref = lp_sym.atom_ref;
459 if (target_atom.atom_index != lp_atom_ref.index or target_atom.file != lp_atom_ref.file) {
460 target_sym.atom_ref = lp_atom_ref;
461 }
462 }
463 }
464
465 for (self.symbols.items) |*sym| {
466 if (!sym.getSectionFlags().objc_stubs) continue;
467 const extra = sym.getExtra(macho_file);
468 const file = sym.getFile(macho_file).?;
469 if (file.getIndex() != self.index) continue;
470 const tsym = switch (file) {
471 .dylib => unreachable,
472 inline else => |x| &x.symbols.items[extra.objc_selrefs],
186473 };
474 const atom = tsym.getAtom(macho_file) orelse continue;
475 if (!Object.isPtrLiteral(atom.getInputSection(macho_file))) continue;
476 const lp_index = atom.getExtra(macho_file).literal_pool_index;
477 const lp_sym = lp.getSymbol(lp_index, macho_file);
478 const lp_atom_ref = lp_sym.atom_ref;
479 if (atom.atom_index != lp_atom_ref.index or atom.file != lp_atom_ref.file) {
480 tsym.atom_ref = lp_atom_ref;
481 }
187482 }
483}
484
485pub fn scanRelocs(self: *InternalObject, macho_file: *MachO) void {
486 const tracy = trace(@src());
487 defer tracy.end();
188488
189 for (self.symbols.items) |sym_index| {
190 const sym = macho_file.getSymbol(sym_index);
191 if (!sym.flags.objc_stubs) continue;
192 var extra = sym.getExtra(macho_file).?;
193 const atom = macho_file.getAtom(extra.objc_selrefs).?;
194 if (atom.getLiteralPoolIndex(macho_file)) |lp_index| {
195 const lp_atom = lp.getAtom(lp_index, macho_file);
196 if (atom.atom_index != lp_atom.atom_index) {
197 lp_atom.alignment = lp_atom.alignment.max(atom.alignment);
198 atom.flags.alive = false;
199 extra.objc_selrefs = lp_atom.atom_index;
200 sym.setExtra(extra, macho_file);
489 if (self.getEntryRef(macho_file)) |ref| {
490 if (ref.getFile(macho_file) != null) {
491 const sym = ref.getSymbol(macho_file).?;
492 if (sym.flags.import) sym.flags.stubs = true;
493 }
494 }
495 if (self.getDyldStubBinderRef(macho_file)) |ref| {
496 if (ref.getFile(macho_file) != null) {
497 const sym = ref.getSymbol(macho_file).?;
498 sym.flags.got = true;
499 }
500 }
501 if (self.getObjcMsgSendRef(macho_file)) |ref| {
502 if (ref.getFile(macho_file) != null) {
503 const sym = ref.getSymbol(macho_file).?;
504 // TODO is it always needed, or only if we are synthesising fast stubs
505 sym.flags.got = true;
506 }
507 }
508}
509
510pub fn allocateSyntheticSymbols(self: *InternalObject, macho_file: *MachO) void {
511 const text_seg = macho_file.getTextSegment();
512
513 if (self.mh_execute_header_index) |index| {
514 const ref = self.getSymbolRef(index, macho_file);
515 if (ref.getFile(macho_file)) |file| {
516 if (file.getIndex() == self.index) {
517 const sym = &self.symbols.items[index];
518 sym.value = text_seg.vmaddr;
519 }
520 }
521 }
522
523 if (macho_file.data_sect_index) |idx| {
524 const sect = macho_file.sections.items(.header)[idx];
525 for (&[_]?Symbol.Index{
526 self.dso_handle_index,
527 self.mh_dylib_header_index,
528 self.dyld_private_index,
529 }) |maybe_index| {
530 if (maybe_index) |index| {
531 const ref = self.getSymbolRef(index, macho_file);
532 if (ref.getFile(macho_file)) |file| {
533 if (file.getIndex() == self.index) {
534 const sym = &self.symbols.items[index];
535 sym.value = sect.addr;
536 sym.out_n_sect = idx;
537 }
538 }
201539 }
202540 }
203541 }
204542}
205543
206pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) !void {
207 for (self.symbols.items) |sym_index| {
208 const sym = macho_file.getSymbol(sym_index);
209 if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue;
544pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) void {
545 for (self.symbols.items, 0..) |*sym, i| {
546 const ref = self.getSymbolRef(@intCast(i), macho_file);
547 const file = ref.getFile(macho_file) orelse continue;
548 if (file.getIndex() != self.index) continue;
549 if (sym.getName(macho_file).len == 0) continue;
210550 sym.flags.output_symtab = true;
211551 if (sym.isLocal()) {
212 try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
552 sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
213553 self.output_symtab_ctx.nlocals += 1;
214554 } else if (sym.flags.@"export") {
215 try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file);
555 sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file);
216556 self.output_symtab_ctx.nexports += 1;
217557 } else {
218558 assert(sym.flags.import);
219 try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
559 sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
220560 self.output_symtab_ctx.nimports += 1;
221561 }
222562 self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1));
223563 }
224564}
225565
226pub fn writeSymtab(self: InternalObject, macho_file: *MachO, ctx: anytype) void {
227 for (self.symbols.items) |sym_index| {
228 const sym = macho_file.getSymbol(sym_index);
229 if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue;
566pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void {
567 const tracy = trace(@src());
568 defer tracy.end();
569
570 for (self.getAtoms()) |atom_index| {
571 const atom = self.getAtom(atom_index) orelse continue;
572 if (!atom.alive.load(.seq_cst)) continue;
573 const sect = atom.getInputSection(macho_file);
574 if (sect.isZerofill()) continue;
575 const off = atom.value;
576 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items[off..][0..atom.size];
577 @memcpy(buffer, self.getSectionData(atom.n_sect));
578 try atom.resolveRelocs(macho_file, buffer);
579 }
580}
581
582pub fn writeSymtab(self: InternalObject, macho_file: *MachO) void {
583 var n_strx = self.output_symtab_ctx.stroff;
584 for (self.symbols.items, 0..) |sym, i| {
585 const ref = self.getSymbolRef(@intCast(i), macho_file);
586 const file = ref.getFile(macho_file) orelse continue;
587 if (file.getIndex() != self.index) continue;
230588 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
231 const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
232 ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
233 ctx.strtab.appendAssumeCapacity(0);
234 const out_sym = &ctx.symtab.items[idx];
589 const out_sym = &macho_file.symtab.items[idx];
235590 out_sym.n_strx = n_strx;
236591 sym.setOutputSym(macho_file, out_sym);
592 const name = sym.getName(macho_file);
593 @memcpy(macho_file.strtab.items[n_strx..][0..name.len], name);
594 n_strx += @intCast(name.len);
595 macho_file.strtab.items[n_strx] = 0;
596 n_strx += 1;
237597 }
238598}
239599
......@@ -262,32 +622,167 @@ fn getSectionData(self: *const InternalObject, index: u32) error{Overflow}![]con
262622 @panic("ref to non-existent section");
263623}
264624
265pub fn getAtomData(self: *const InternalObject, atom: Atom, buffer: []u8) error{Overflow}!void {
266 assert(buffer.len == atom.size);
267 const data = try self.getSectionData(atom.n_sect);
268 const off = std.math.cast(usize, atom.off) orelse return error.Overflow;
269 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
270 @memcpy(buffer, data[off..][0..size]);
271}
272
273pub fn getAtomRelocs(self: *const InternalObject, atom: Atom, macho_file: *MachO) []const Relocation {
274 if (!atom.flags.relocs) return &[0]Relocation{};
275 const extra = atom.getExtra(macho_file).?;
276 const relocs = self.sections.items(.relocs)[atom.n_sect];
277 return relocs.items[extra.rel_index..][0..extra.rel_count];
625pub fn addString(self: *InternalObject, allocator: Allocator, name: []const u8) !u32 {
626 const off: u32 = @intCast(self.strtab.items.len);
627 try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);
628 self.strtab.appendSliceAssumeCapacity(name);
629 self.strtab.appendAssumeCapacity(0);
630 return off;
278631}
279632
280633pub fn getString(self: InternalObject, off: u32) [:0]const u8 {
281 _ = self;
282 _ = off;
283 // We don't have any local strings for synthetic atoms.
284 return "";
634 assert(off < self.strtab.items.len);
635 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
285636}
286637
287638pub fn asFile(self: *InternalObject) File {
288639 return .{ .internal = self };
289640}
290641
642fn addAtom(self: *InternalObject, allocator: Allocator) !Atom.Index {
643 const atom_index: Atom.Index = @intCast(self.atoms.items.len);
644 const atom = try self.atoms.addOne(allocator);
645 atom.* = .{
646 .file = self.index,
647 .atom_index = atom_index,
648 .extra = try self.addAtomExtra(allocator, .{}),
649 };
650 return atom_index;
651}
652
653pub fn getAtom(self: *InternalObject, atom_index: Atom.Index) ?*Atom {
654 if (atom_index == 0) return null;
655 assert(atom_index < self.atoms.items.len);
656 return &self.atoms.items[atom_index];
657}
658
659pub fn getAtoms(self: InternalObject) []const Atom.Index {
660 return self.atoms_indexes.items;
661}
662
663fn addAtomExtra(self: *InternalObject, allocator: Allocator, extra: Atom.Extra) !u32 {
664 const fields = @typeInfo(Atom.Extra).Struct.fields;
665 try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
666 return self.addAtomExtraAssumeCapacity(extra);
667}
668
669fn addAtomExtraAssumeCapacity(self: *InternalObject, extra: Atom.Extra) u32 {
670 const index = @as(u32, @intCast(self.atoms_extra.items.len));
671 const fields = @typeInfo(Atom.Extra).Struct.fields;
672 inline for (fields) |field| {
673 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
674 u32 => @field(extra, field.name),
675 else => @compileError("bad field type"),
676 });
677 }
678 return index;
679}
680
681pub fn getAtomExtra(self: InternalObject, index: u32) Atom.Extra {
682 const fields = @typeInfo(Atom.Extra).Struct.fields;
683 var i: usize = index;
684 var result: Atom.Extra = undefined;
685 inline for (fields) |field| {
686 @field(result, field.name) = switch (field.type) {
687 u32 => self.atoms_extra.items[i],
688 else => @compileError("bad field type"),
689 };
690 i += 1;
691 }
692 return result;
693}
694
695pub fn setAtomExtra(self: *InternalObject, index: u32, extra: Atom.Extra) void {
696 assert(index > 0);
697 const fields = @typeInfo(Atom.Extra).Struct.fields;
698 inline for (fields, 0..) |field, i| {
699 self.atoms_extra.items[index + i] = switch (field.type) {
700 u32 => @field(extra, field.name),
701 else => @compileError("bad field type"),
702 };
703 }
704}
705
706pub fn getEntryRef(self: InternalObject, macho_file: *MachO) ?MachO.Ref {
707 const index = self.entry_index orelse return null;
708 return self.getSymbolRef(index, macho_file);
709}
710
711pub fn getDyldStubBinderRef(self: InternalObject, macho_file: *MachO) ?MachO.Ref {
712 const index = self.dyld_stub_binder_index orelse return null;
713 return self.getSymbolRef(index, macho_file);
714}
715
716pub fn getDyldPrivateRef(self: InternalObject, macho_file: *MachO) ?MachO.Ref {
717 const index = self.dyld_private_index orelse return null;
718 return self.getSymbolRef(index, macho_file);
719}
720
721pub fn getObjcMsgSendRef(self: InternalObject, macho_file: *MachO) ?MachO.Ref {
722 const index = self.objc_msg_send_index orelse return null;
723 return self.getSymbolRef(index, macho_file);
724}
725
726pub fn addSymbol(self: *InternalObject, allocator: Allocator) !Symbol.Index {
727 try self.symbols.ensureUnusedCapacity(allocator, 1);
728 return self.addSymbolAssumeCapacity();
729}
730
731pub fn addSymbolAssumeCapacity(self: *InternalObject) Symbol.Index {
732 const index: Symbol.Index = @intCast(self.symbols.items.len);
733 const symbol = self.symbols.addOneAssumeCapacity();
734 symbol.* = .{ .file = self.index };
735 return index;
736}
737
738pub fn getSymbolRef(self: InternalObject, index: Symbol.Index, macho_file: *MachO) MachO.Ref {
739 const global_index = self.globals.items[index];
740 if (macho_file.resolver.get(global_index)) |ref| return ref;
741 return .{ .index = index, .file = self.index };
742}
743
744pub fn addSymbolExtra(self: *InternalObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
745 const fields = @typeInfo(Symbol.Extra).Struct.fields;
746 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
747 return self.addSymbolExtraAssumeCapacity(extra);
748}
749
750fn addSymbolExtraAssumeCapacity(self: *InternalObject, extra: Symbol.Extra) u32 {
751 const index = @as(u32, @intCast(self.symbols_extra.items.len));
752 const fields = @typeInfo(Symbol.Extra).Struct.fields;
753 inline for (fields) |field| {
754 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
755 u32 => @field(extra, field.name),
756 else => @compileError("bad field type"),
757 });
758 }
759 return index;
760}
761
762pub fn getSymbolExtra(self: InternalObject, index: u32) Symbol.Extra {
763 const fields = @typeInfo(Symbol.Extra).Struct.fields;
764 var i: usize = index;
765 var result: Symbol.Extra = undefined;
766 inline for (fields) |field| {
767 @field(result, field.name) = switch (field.type) {
768 u32 => self.symbols_extra.items[i],
769 else => @compileError("bad field type"),
770 };
771 i += 1;
772 }
773 return result;
774}
775
776pub fn setSymbolExtra(self: *InternalObject, index: u32, extra: Symbol.Extra) void {
777 const fields = @typeInfo(Symbol.Extra).Struct.fields;
778 inline for (fields, 0..) |field, i| {
779 self.symbols_extra.items[index + i] = switch (field.type) {
780 u32 => @field(extra, field.name),
781 else => @compileError("bad field type"),
782 };
783 }
784}
785
291786const FormatContext = struct {
292787 self: *InternalObject,
293788 macho_file: *MachO,
......@@ -309,8 +804,8 @@ fn formatAtoms(
309804 _ = unused_fmt_string;
310805 _ = options;
311806 try writer.writeAll(" atoms\n");
312 for (ctx.self.atoms.items) |atom_index| {
313 const atom = ctx.macho_file.getAtom(atom_index).?;
807 for (ctx.self.getAtoms()) |atom_index| {
808 const atom = ctx.self.getAtom(atom_index) orelse continue;
314809 try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)});
315810 }
316811}
......@@ -330,10 +825,17 @@ fn formatSymtab(
330825) !void {
331826 _ = unused_fmt_string;
332827 _ = options;
828 const macho_file = ctx.macho_file;
829 const self = ctx.self;
333830 try writer.writeAll(" symbols\n");
334 for (ctx.self.symbols.items) |index| {
335 const global = ctx.macho_file.getSymbol(index);
336 try writer.print(" {}\n", .{global.fmt(ctx.macho_file)});
831 for (self.symbols.items, 0..) |sym, i| {
832 const ref = self.getSymbolRef(@intCast(i), macho_file);
833 if (ref.getFile(macho_file) == null) {
834 // TODO any better way of handling this?
835 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
836 } else {
837 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
838 }
337839 }
338840}
339841
......@@ -352,6 +854,7 @@ const assert = std.debug.assert;
352854const macho = std.macho;
353855const mem = std.mem;
354856const std = @import("std");
857const trace = @import("../../tracy.zig").trace;
355858
356859const Allocator = std.mem.Allocator;
357860const Atom = @import("Atom.zig");