authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-09 11:22:24+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-18 09:13:08+02:00
logb9bac32a2562985ca7a67877169343975fd8f851
treebf0f26530abc99fee00ba73d2e0a9de1e27f8dfc
parentc59583e43de35e91ac194860cd1eb63e61c272aa

macho: migrate Atom and Symbol


5 files changed, 266 insertions(+), 163 deletions(-)

src/link/MachO.zig+139-32
...@@ -22,16 +22,10 @@ dylibs: std.ArrayListUnmanaged(File.Index) = .{},...@@ -22,16 +22,10 @@ dylibs: std.ArrayListUnmanaged(File.Index) = .{},
22segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},22segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
23sections: std.MultiArrayList(Section) = .{},23sections: std.MultiArrayList(Section) = .{},
2424
25symbols: std.ArrayListUnmanaged(Symbol) = .{},25resolver: SymbolResolver = .{},
26symbols_extra: std.ArrayListUnmanaged(u32) = .{},
27symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
28globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
29/// This table will be populated after `scanRelocs` has run.26/// This table will be populated after `scanRelocs` has run.
30/// Key is symbol index.27/// Key is symbol index.
31undefs: std.AutoHashMapUnmanaged(Symbol.Index, std.ArrayListUnmanaged(Atom.Index)) = .{},28undefs: std.AutoHashMapUnmanaged(Ref, std.ArrayListUnmanaged(Ref)) = .{},
32/// Global symbols we need to resolve for the link to succeed.
33undefined_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
34boundary_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
3529
36dyld_info_cmd: macho.dyld_info_command = .{},30dyld_info_cmd: macho.dyld_info_command = .{},
37symtab_cmd: macho.symtab_command = .{},31symtab_cmd: macho.symtab_command = .{},
...@@ -55,19 +49,8 @@ eh_frame_sect_index: ?u8 = null,...@@ -55,19 +49,8 @@ eh_frame_sect_index: ?u8 = null,
55unwind_info_sect_index: ?u8 = null,49unwind_info_sect_index: ?u8 = null,
56objc_stubs_sect_index: ?u8 = null,50objc_stubs_sect_index: ?u8 = null,
5751
58mh_execute_header_index: ?Symbol.Index = null,
59mh_dylib_header_index: ?Symbol.Index = null,
60dyld_private_index: ?Symbol.Index = null,
61dyld_stub_binder_index: ?Symbol.Index = null,
62dso_handle_index: ?Symbol.Index = null,
63objc_msg_send_index: ?Symbol.Index = null,
64entry_index: ?Symbol.Index = null,
65
66thunks: std.ArrayListUnmanaged(Thunk) = .{},52thunks: std.ArrayListUnmanaged(Thunk) = .{},
6753
68/// String interning table
69strings: StringTable = .{},
70
71/// Output synthetic sections54/// Output synthetic sections
72symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},55symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
73strtab: std.ArrayListUnmanaged(u8) = .{},56strtab: std.ArrayListUnmanaged(u8) = .{},
...@@ -4196,7 +4179,7 @@ const Section = struct {...@@ -4196,7 +4179,7 @@ const Section = struct {
4196pub const LiteralPool = struct {4179pub const LiteralPool = struct {
4197 table: std.AutoArrayHashMapUnmanaged(void, void) = .{},4180 table: std.AutoArrayHashMapUnmanaged(void, void) = .{},
4198 keys: std.ArrayListUnmanaged(Key) = .{},4181 keys: std.ArrayListUnmanaged(Key) = .{},
4199 values: std.ArrayListUnmanaged(Atom.Index) = .{},4182 values: std.ArrayListUnmanaged(MachO.Ref) = .{},
4200 data: std.ArrayListUnmanaged(u8) = .{},4183 data: std.ArrayListUnmanaged(u8) = .{},
42014184
4202 pub fn deinit(lp: *LiteralPool, allocator: Allocator) void {4185 pub fn deinit(lp: *LiteralPool, allocator: Allocator) void {
...@@ -4206,17 +4189,21 @@ pub const LiteralPool = struct {...@@ -4206,17 +4189,21 @@ pub const LiteralPool = struct {
4206 lp.data.deinit(allocator);4189 lp.data.deinit(allocator);
4207 }4190 }
42084191
4209 pub fn getAtom(lp: LiteralPool, index: Index, macho_file: *MachO) *Atom {
4210 assert(index < lp.values.items.len);
4211 return macho_file.getAtom(lp.values.items[index]).?;
4212 }
4213
4214 const InsertResult = struct {4192 const InsertResult = struct {
4215 found_existing: bool,4193 found_existing: bool,
4216 index: Index,4194 index: Index,
4217 atom: *Atom.Index,4195 ref: *MachO.Ref,
4218 };4196 };
42194197
4198 pub fn getSymbolRef(lp: LiteralPool, index: Index) MachO.Ref {
4199 assert(index < lp.values.items.len);
4200 return lp.values.items[index];
4201 }
4202
4203 pub fn getSymbol(lp: LiteralPool, index: Index, macho_file: *MachO) *Symbol {
4204 return lp.getSymbolRef(index).getSymbol(macho_file).?;
4205 }
4206
4220 pub fn insert(lp: *LiteralPool, allocator: Allocator, @"type": u8, string: []const u8) !InsertResult {4207 pub fn insert(lp: *LiteralPool, allocator: Allocator, @"type": u8, string: []const u8) !InsertResult {
4221 const size: u32 = @intCast(string.len);4208 const size: u32 = @intCast(string.len);
4222 try lp.data.ensureUnusedCapacity(allocator, size);4209 try lp.data.ensureUnusedCapacity(allocator, size);
...@@ -4278,12 +4265,6 @@ const HotUpdateState = struct {...@@ -4278,12 +4265,6 @@ const HotUpdateState = struct {
4278 mach_task: ?std.c.MachTask = null,4265 mach_task: ?std.c.MachTask = null,
4279};4266};
42804267
4281pub const DynamicRelocs = struct {
4282 rebase_relocs: u32 = 0,
4283 bind_relocs: u32 = 0,
4284 weak_bind_relocs: u32 = 0,
4285};
4286
4287pub const SymtabCtx = struct {4268pub const SymtabCtx = struct {
4288 ilocal: u32 = 0,4269 ilocal: u32 = 0,
4289 istab: u32 = 0,4270 istab: u32 = 0,
...@@ -4293,6 +4274,7 @@ pub const SymtabCtx = struct {...@@ -4293,6 +4274,7 @@ pub const SymtabCtx = struct {
4293 nstabs: u32 = 0,4274 nstabs: u32 = 0,
4294 nexports: u32 = 0,4275 nexports: u32 = 0,
4295 nimports: u32 = 0,4276 nimports: u32 = 0,
4277 stroff: u32 = 0,
4296 strsize: u32 = 0,4278 strsize: u32 = 0,
4297};4279};
42984280
...@@ -4579,6 +4561,131 @@ const UndefinedTreatment = enum {...@@ -4579,6 +4561,131 @@ const UndefinedTreatment = enum {
4579 dynamic_lookup,4561 dynamic_lookup,
4580};4562};
45814563
4564/// A reference to atom or symbol in an input file.
4565/// If file == 0, symbol is an undefined global.
4566pub const Ref = struct {
4567 index: u32,
4568 file: File.Index,
4569
4570 pub fn eql(ref: Ref, other: Ref) bool {
4571 return ref.index == other.index and ref.file == other.file;
4572 }
4573
4574 pub fn getFile(ref: Ref, macho_file: *MachO) ?File {
4575 return macho_file.getFile(ref.file);
4576 }
4577
4578 pub fn getAtom(ref: Ref, macho_file: *MachO) ?*Atom {
4579 const file = ref.getFile(macho_file) orelse return null;
4580 return file.getAtom(ref.index);
4581 }
4582
4583 pub fn getSymbol(ref: Ref, macho_file: *MachO) ?*Symbol {
4584 const file = ref.getFile(macho_file) orelse return null;
4585 return switch (file) {
4586 inline else => |x| &x.symbols.items[ref.index],
4587 };
4588 }
4589
4590 pub fn format(
4591 ref: Ref,
4592 comptime unused_fmt_string: []const u8,
4593 options: std.fmt.FormatOptions,
4594 writer: anytype,
4595 ) !void {
4596 _ = unused_fmt_string;
4597 _ = options;
4598 try writer.print("%{d} in file({d})", .{ ref.index, ref.file });
4599 }
4600};
4601
4602pub const SymbolResolver = struct {
4603 keys: std.ArrayListUnmanaged(Key) = .{},
4604 values: std.ArrayListUnmanaged(Ref) = .{},
4605 table: std.AutoArrayHashMapUnmanaged(void, void) = .{},
4606
4607 const Result = struct {
4608 found_existing: bool,
4609 index: Index,
4610 ref: *Ref,
4611 };
4612
4613 pub fn deinit(resolver: *SymbolResolver, allocator: Allocator) void {
4614 resolver.keys.deinit(allocator);
4615 resolver.values.deinit(allocator);
4616 resolver.table.deinit(allocator);
4617 }
4618
4619 pub fn getOrPut(
4620 resolver: *SymbolResolver,
4621 allocator: Allocator,
4622 ref: Ref,
4623 macho_file: *MachO,
4624 ) !Result {
4625 const adapter = Adapter{ .keys = resolver.keys.items, .macho_file = macho_file };
4626 const key = Key{ .index = ref.index, .file = ref.file };
4627 const gop = try resolver.table.getOrPutAdapted(allocator, key, adapter);
4628 if (!gop.found_existing) {
4629 try resolver.keys.append(allocator, key);
4630 _ = try resolver.values.addOne(allocator);
4631 }
4632 return .{
4633 .found_existing = gop.found_existing,
4634 .index = @intCast(gop.index + 1),
4635 .ref = &resolver.values.items[gop.index],
4636 };
4637 }
4638
4639 pub fn get(resolver: SymbolResolver, index: Index) ?Ref {
4640 if (index == 0) return null;
4641 return resolver.values.items[index - 1];
4642 }
4643
4644 pub fn reset(resolver: *SymbolResolver) void {
4645 resolver.keys.clearRetainingCapacity();
4646 resolver.values.clearRetainingCapacity();
4647 resolver.table.clearRetainingCapacity();
4648 }
4649
4650 const Key = struct {
4651 index: Symbol.Index,
4652 file: File.Index,
4653
4654 fn getName(key: Key, macho_file: *MachO) [:0]const u8 {
4655 const ref = Ref{ .index = key.index, .file = key.file };
4656 return ref.getSymbol(macho_file).?.getName(macho_file);
4657 }
4658
4659 fn eql(key: Key, other: Key, macho_file: *MachO) bool {
4660 const key_name = key.getName(macho_file);
4661 const other_name = other.getName(macho_file);
4662 return mem.eql(u8, key_name, other_name);
4663 }
4664
4665 fn hash(key: Key, macho_file: *MachO) u32 {
4666 const name = key.getName(macho_file);
4667 return @truncate(Hash.hash(0, name));
4668 }
4669 };
4670
4671 const Adapter = struct {
4672 keys: []const Key,
4673 macho_file: *MachO,
4674
4675 pub fn eql(ctx: @This(), key: Key, b_void: void, b_map_index: usize) bool {
4676 _ = b_void;
4677 const other = ctx.keys[b_map_index];
4678 return key.eql(other, ctx.macho_file);
4679 }
4680
4681 pub fn hash(ctx: @This(), key: Key) u32 {
4682 return key.hash(ctx.macho_file);
4683 }
4684 };
4685
4686 pub const Index = u32;
4687};
4688
4582const MachO = @This();4689const MachO = @This();
45834690
4584const std = @import("std");4691const std = @import("std");
src/link/MachO/Atom.zig+74-92
...@@ -47,16 +47,6 @@ pub fn getFile(self: Atom, macho_file: *MachO) File {...@@ -47,16 +47,6 @@ pub fn getFile(self: Atom, macho_file: *MachO) File {
47 return macho_file.getFile(self.file).?;47 return macho_file.getFile(self.file).?;
48}48}
4949
50pub fn getData(self: Atom, macho_file: *MachO, buffer: []u8) !void {
51 assert(buffer.len == self.size);
52 switch (self.getFile(macho_file)) {
53 .internal => |x| try x.getAtomData(self, buffer),
54 .object => |x| try x.getAtomData(macho_file, self, buffer),
55 .zig_object => |x| try x.getAtomData(macho_file, self, buffer),
56 else => unreachable,
57 }
58}
59
60pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {50pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {
61 return switch (self.getFile(macho_file)) {51 return switch (self.getFile(macho_file)) {
62 .dylib => unreachable,52 .dylib => unreachable,
...@@ -88,8 +78,7 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 {...@@ -88,8 +78,7 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 {
88}78}
8979
90pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index {80pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index {
91 if (!self.flags.unwind) return &[0]UnwindInfo.Record.Index{};81 const extra = self.getExtra(macho_file);
92 const extra = self.getExtra(macho_file).?;
93 return switch (self.getFile(macho_file)) {82 return switch (self.getFile(macho_file)) {
94 .dylib => unreachable,83 .dylib => unreachable,
95 .zig_object, .internal => &[0]UnwindInfo.Record.Index{},84 .zig_object, .internal => &[0]UnwindInfo.Record.Index{},
...@@ -110,44 +99,39 @@ pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void {...@@ -110,44 +99,39 @@ pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void {
110}99}
111100
112pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk {101pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk {
113 assert(self.flags.thunk);102 const extra = self.getExtra(macho_file);
114 const extra = self.getExtra(macho_file).?;
115 return macho_file.getThunk(extra.thunk);103 return macho_file.getThunk(extra.thunk);
116}104}
117105
118pub fn getLiteralPoolIndex(self: Atom, macho_file: *MachO) ?MachO.LiteralPool.Index {
119 if (!self.flags.literal_pool) return null;
120 return self.getExtra(macho_file).?.literal_index;
121}
122
123const AddExtraOpts = struct {106const AddExtraOpts = struct {
124 thunk: ?u32 = null,107 thunk: ?u32 = null,
125 rel_index: ?u32 = null,108 rel_index: ?u32 = null,
126 rel_count: ?u32 = null,109 rel_count: ?u32 = null,
110 rel_out_index: ?u32 = null,
111 rel_out_count: ?u32 = null,
127 unwind_index: ?u32 = null,112 unwind_index: ?u32 = null,
128 unwind_count: ?u32 = null,113 unwind_count: ?u32 = null,
129 literal_index: ?u32 = null,114 literal_pool_index: ?u32 = null,
115 literal_symbol_index: ?u32 = null,
130};116};
131117
132pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) !void {118pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) void {
133 if (atom.getExtra(macho_file) == null) {119 const file = atom.getFile(macho_file);
134 atom.extra = try macho_file.addAtomExtra(.{});120 var extra = file.getAtomExtra(atom.extra);
135 }
136 var extra = atom.getExtra(macho_file).?;
137 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {121 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
138 if (@field(opts, field.name)) |x| {122 if (@field(opts, field.name)) |x| {
139 @field(extra, field.name) = x;123 @field(extra, field.name) = x;
140 }124 }
141 }125 }
142 atom.setExtra(extra, macho_file);126 file.setAtomExtra(atom.extra, extra);
143}127}
144128
145pub inline fn getExtra(atom: Atom, macho_file: *MachO) ?Extra {129pub inline fn getExtra(atom: Atom, macho_file: *MachO) Extra {
146 return macho_file.getAtomExtra(atom.extra);130 return atom.getFile(macho_file).getAtomExtra(atom.extra);
147}131}
148132
149pub inline fn setExtra(atom: Atom, extra: Extra, macho_file: *MachO) void {133pub inline fn setExtra(atom: Atom, extra: Extra, macho_file: *MachO) void {
150 macho_file.setAtomExtra(atom.extra, extra);134 atom.getFile(macho_file).setAtomExtra(atom.extra, extra);
151}135}
152136
153pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 {137pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 {
...@@ -467,7 +451,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {...@@ -467,7 +451,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
467451
468 switch (rel.type) {452 switch (rel.type) {
469 .branch => {453 .branch => {
470 const symbol = rel.getTargetSymbol(macho_file);454 const symbol = rel.getTargetSymbol(self, macho_file);
471 if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) {455 if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) {
472 symbol.flags.stubs = true;456 symbol.flags.stubs = true;
473 if (symbol.flags.weak) {457 if (symbol.flags.weak) {
...@@ -482,7 +466,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {...@@ -482,7 +466,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
482 .got_load_page,466 .got_load_page,
483 .got_load_pageoff,467 .got_load_pageoff,
484 => {468 => {
485 const symbol = rel.getTargetSymbol(macho_file);469 const symbol = rel.getTargetSymbol(self, macho_file);
486 if (symbol.flags.import or470 if (symbol.flags.import or
487 (symbol.flags.@"export" and symbol.flags.weak) or471 (symbol.flags.@"export" and symbol.flags.weak) or
488 symbol.flags.interposable or472 symbol.flags.interposable or
...@@ -496,18 +480,18 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {...@@ -496,18 +480,18 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
496 },480 },
497481
498 .zig_got_load => {482 .zig_got_load => {
499 assert(rel.getTargetSymbol(macho_file).flags.has_zig_got);483 assert(rel.getTargetSymbol(self, macho_file).flags.has_zig_got);
500 },484 },
501485
502 .got => {486 .got => {
503 rel.getTargetSymbol(macho_file).flags.needs_got = true;487 rel.getTargetSymbol(self, macho_file).flags.needs_got = true;
504 },488 },
505489
506 .tlv,490 .tlv,
507 .tlvp_page,491 .tlvp_page,
508 .tlvp_pageoff,492 .tlvp_pageoff,
509 => {493 => {
510 const symbol = rel.getTargetSymbol(macho_file);494 const symbol = rel.getTargetSymbol(self, macho_file);
511 if (!symbol.flags.tlv) {495 if (!symbol.flags.tlv) {
512 try macho_file.reportParseError2(496 try macho_file.reportParseError2(
513 self.getFile(macho_file).getIndex(),497 self.getFile(macho_file).getIndex(),
...@@ -526,7 +510,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {...@@ -526,7 +510,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
526 .unsigned => {510 .unsigned => {
527 if (rel.meta.length == 3) { // TODO this really should check if this is pointer width511 if (rel.meta.length == 3) { // TODO this really should check if this is pointer width
528 if (rel.tag == .@"extern") {512 if (rel.tag == .@"extern") {
529 const symbol = rel.getTargetSymbol(macho_file);513 const symbol = rel.getTargetSymbol(self, macho_file);
530 if (symbol.isTlvInit(macho_file)) {514 if (symbol.isTlvInit(macho_file)) {
531 macho_file.has_tlv = true;515 macho_file.has_tlv = true;
532 continue;516 continue;
...@@ -559,14 +543,15 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {...@@ -559,14 +543,15 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
559fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool {543fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool {
560 if (rel.tag == .local) return false;544 if (rel.tag == .local) return false;
561545
562 const sym = rel.getTargetSymbol(macho_file);546 const file = self.getFile(macho_file);
563 if (sym.getFile(macho_file) == null) {547 const ref = file.getSymbolRef(rel.target, macho_file);
548 if (ref.getFile(macho_file) == null) {
564 const gpa = macho_file.base.comp.gpa;549 const gpa = macho_file.base.comp.gpa;
565 const gop = try macho_file.undefs.getOrPut(gpa, rel.target);550 const gop = try macho_file.undefs.getOrPut(gpa, .{ .index = rel.target, .file = self.file });
566 if (!gop.found_existing) {551 if (!gop.found_existing) {
567 gop.value_ptr.* = .{};552 gop.value_ptr.* = .{};
568 }553 }
569 try gop.value_ptr.append(gpa, self.atom_index);554 try gop.value_ptr.append(gpa, .{ .index = self.atom_index, .file = self.file });
570 return true;555 return true;
571 }556 }
572557
...@@ -582,7 +567,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -582,7 +567,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
582 const name = self.getName(macho_file);567 const name = self.getName(macho_file);
583 const relocs = self.getRelocs(macho_file);568 const relocs = self.getRelocs(macho_file);
584569
585 relocs_log.debug("{x}: {s}", .{ self.getAddress(macho_file), name });570 relocs_log.debug("{x}: {s}", .{ self.value, name });
586571
587 var has_error = false;572 var has_error = false;
588 var stream = std.io.fixedBufferStream(buffer);573 var stream = std.io.fixedBufferStream(buffer);
...@@ -593,7 +578,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -593,7 +578,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
593 const subtractor = if (rel.meta.has_subtractor) relocs[i - 1] else null;578 const subtractor = if (rel.meta.has_subtractor) relocs[i - 1] else null;
594579
595 if (rel.tag == .@"extern") {580 if (rel.tag == .@"extern") {
596 if (rel.getTargetSymbol(macho_file).getFile(macho_file) == null) continue;581 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
597 }582 }
598583
599 try stream.seekTo(rel_offset);584 try stream.seekTo(rel_offset);
...@@ -601,8 +586,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -601,8 +586,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
601 switch (err) {586 switch (err) {
602 error.RelaxFail => {587 error.RelaxFail => {
603 const target = switch (rel.tag) {588 const target = switch (rel.tag) {
604 .@"extern" => rel.getTargetSymbol(macho_file).getName(macho_file),589 .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
605 .local => rel.getTargetAtom(macho_file).getName(macho_file),590 .local => rel.getTargetAtom(self, macho_file).getName(macho_file),
606 };591 };
607 try macho_file.reportParseError2(592 try macho_file.reportParseError2(
608 file.getIndex(),593 file.getIndex(),
...@@ -642,12 +627,12 @@ fn resolveRelocInner(...@@ -642,12 +627,12 @@ fn resolveRelocInner(
642 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;627 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
643 const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset));628 const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset));
644 const A = rel.addend + rel.getRelocAddend(cpu_arch);629 const A = rel.addend + rel.getRelocAddend(cpu_arch);
645 const S: i64 = @intCast(rel.getTargetAddress(macho_file));630 const S: i64 = @intCast(rel.getTargetAddress(self, macho_file));
646 const G: i64 = @intCast(rel.getGotTargetAddress(macho_file));631 const G: i64 = @intCast(rel.getGotTargetAddress(self, macho_file));
647 const TLS = @as(i64, @intCast(macho_file.getTlsAddress()));632 const TLS = @as(i64, @intCast(macho_file.getTlsAddress()));
648 const SUB = if (subtractor) |sub| @as(i64, @intCast(sub.getTargetAddress(macho_file))) else 0;633 const SUB = if (subtractor) |sub| @as(i64, @intCast(sub.getTargetAddress(self, macho_file))) else 0;
649 // Address of the __got_zig table entry if any.634 // Address of the __got_zig table entry if any.
650 const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(macho_file)));635 const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(self, macho_file)));
651636
652 const divExact = struct {637 const divExact = struct {
653 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {638 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
...@@ -668,7 +653,7 @@ fn resolveRelocInner(...@@ -668,7 +653,7 @@ fn resolveRelocInner(
668 rel_offset,653 rel_offset,
669 @tagName(rel.type),654 @tagName(rel.type),
670 S + A - SUB,655 S + A - SUB,
671 rel.getTargetAtom(macho_file).atom_index,656 rel.getTargetAtom(self, macho_file).atom_index,
672 }),657 }),
673 .@"extern" => relocs_log.debug(" {x}<+{d}>: {s}: [=> {x}] G({x}) ZG({x}) ({s})", .{658 .@"extern" => relocs_log.debug(" {x}<+{d}>: {s}: [=> {x}] G({x}) ZG({x}) ({s})", .{
674 P,659 P,
...@@ -677,7 +662,7 @@ fn resolveRelocInner(...@@ -677,7 +662,7 @@ fn resolveRelocInner(
677 S + A - SUB,662 S + A - SUB,
678 G + A,663 G + A,
679 ZIG_GOT + A,664 ZIG_GOT + A,
680 rel.getTargetSymbol(macho_file).getName(macho_file),665 rel.getTargetSymbol(self, macho_file).getName(macho_file),
681 }),666 }),
682 }667 }
683668
...@@ -688,7 +673,7 @@ fn resolveRelocInner(...@@ -688,7 +673,7 @@ fn resolveRelocInner(
688 assert(!rel.meta.pcrel);673 assert(!rel.meta.pcrel);
689 if (rel.meta.length == 3) {674 if (rel.meta.length == 3) {
690 if (rel.tag == .@"extern") {675 if (rel.tag == .@"extern") {
691 const sym = rel.getTargetSymbol(macho_file);676 const sym = rel.getTargetSymbol(self, macho_file);
692 if (sym.isTlvInit(macho_file)) {677 if (sym.isTlvInit(macho_file)) {
693 try writer.writeInt(u64, @intCast(S - TLS), .little);678 try writer.writeInt(u64, @intCast(S - TLS), .little);
694 return;679 return;
...@@ -718,7 +703,7 @@ fn resolveRelocInner(...@@ -718,7 +703,7 @@ fn resolveRelocInner(
718 .aarch64 => {703 .aarch64 => {
719 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {704 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
720 const thunk = self.getThunk(macho_file);705 const thunk = self.getThunk(macho_file);
721 const S_: i64 = @intCast(thunk.getTargetAddress(rel.target, macho_file));706 const S_: i64 = @intCast(thunk.getTargetAddress(rel.getTargetSymbolRef(self, macho_file), macho_file));
722 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;707 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
723 };708 };
724 aarch64.writeBranchImm(disp, code[rel_offset..][0..4]);709 aarch64.writeBranchImm(disp, code[rel_offset..][0..4]);
...@@ -731,7 +716,7 @@ fn resolveRelocInner(...@@ -731,7 +716,7 @@ fn resolveRelocInner(
731 assert(rel.tag == .@"extern");716 assert(rel.tag == .@"extern");
732 assert(rel.meta.length == 2);717 assert(rel.meta.length == 2);
733 assert(rel.meta.pcrel);718 assert(rel.meta.pcrel);
734 if (rel.getTargetSymbol(macho_file).flags.has_got) {719 if (rel.getTargetSymbol(self, macho_file).flags.has_got) {
735 try writer.writeInt(i32, @intCast(G + A - P), .little);720 try writer.writeInt(i32, @intCast(G + A - P), .little);
736 } else {721 } else {
737 try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);722 try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);
...@@ -754,7 +739,7 @@ fn resolveRelocInner(...@@ -754,7 +739,7 @@ fn resolveRelocInner(
754 assert(rel.tag == .@"extern");739 assert(rel.tag == .@"extern");
755 assert(rel.meta.length == 2);740 assert(rel.meta.length == 2);
756 assert(rel.meta.pcrel);741 assert(rel.meta.pcrel);
757 const sym = rel.getTargetSymbol(macho_file);742 const sym = rel.getTargetSymbol(self, macho_file);
758 if (sym.flags.tlv_ptr) {743 if (sym.flags.tlv_ptr) {
759 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));744 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
760 try writer.writeInt(i32, @intCast(S_ + A - P), .little);745 try writer.writeInt(i32, @intCast(S_ + A - P), .little);
...@@ -777,7 +762,7 @@ fn resolveRelocInner(...@@ -777,7 +762,7 @@ fn resolveRelocInner(
777 assert(rel.tag == .@"extern");762 assert(rel.tag == .@"extern");
778 assert(rel.meta.length == 2);763 assert(rel.meta.length == 2);
779 assert(rel.meta.pcrel);764 assert(rel.meta.pcrel);
780 const sym = rel.getTargetSymbol(macho_file);765 const sym = rel.getTargetSymbol(self, macho_file);
781 const source = math.cast(u64, P) orelse return error.Overflow;766 const source = math.cast(u64, P) orelse return error.Overflow;
782 const target = target: {767 const target = target: {
783 const target = switch (rel.type) {768 const target = switch (rel.type) {
...@@ -836,7 +821,7 @@ fn resolveRelocInner(...@@ -836,7 +821,7 @@ fn resolveRelocInner(
836 assert(rel.meta.length == 2);821 assert(rel.meta.length == 2);
837 assert(!rel.meta.pcrel);822 assert(!rel.meta.pcrel);
838823
839 const sym = rel.getTargetSymbol(macho_file);824 const sym = rel.getTargetSymbol(self, macho_file);
840 const target = target: {825 const target = target: {
841 const target = if (sym.flags.tlv_ptr) blk: {826 const target = if (sym.flags.tlv_ptr) blk: {
842 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));827 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
...@@ -980,48 +965,47 @@ pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {...@@ -980,48 +965,47 @@ pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
980 }965 }
981}966}
982967
983pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.ArrayList(macho.relocation_info)) !void {968pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.relocation_info) !void {
984 const tracy = trace(@src());969 const tracy = trace(@src());
985 defer tracy.end();970 defer tracy.end();
986971
987 const cpu_arch = macho_file.getTarget().cpu.arch;972 const cpu_arch = macho_file.getTarget().cpu.arch;
988 const relocs = self.getRelocs(macho_file);973 const relocs = self.getRelocs(macho_file);
989 var stream = std.io.fixedBufferStream(code);
990974
975 var i: usize = 0;
991 for (relocs) |rel| {976 for (relocs) |rel| {
977 defer i += 1;
992 const rel_offset = rel.offset - self.off;978 const rel_offset = rel.offset - self.off;
993 const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow;979 const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow;
994 const r_symbolnum = r_symbolnum: {980 const r_symbolnum = r_symbolnum: {
995 const r_symbolnum: u32 = switch (rel.tag) {981 const r_symbolnum: u32 = switch (rel.tag) {
996 .local => rel.getTargetAtom(macho_file).out_n_sect + 1,982 .local => rel.getTargetAtom(self, macho_file).out_n_sect + 1,
997 .@"extern" => rel.getTargetSymbol(macho_file).getOutputSymtabIndex(macho_file).?,983 .@"extern" => rel.getTargetSymbol(self, macho_file).getOutputSymtabIndex(macho_file).?,
998 };984 };
999 break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow;985 break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow;
1000 };986 };
1001 const r_extern = rel.tag == .@"extern";987 const r_extern = rel.tag == .@"extern";
1002 var addend = rel.addend + rel.getRelocAddend(cpu_arch);988 var addend = rel.addend + rel.getRelocAddend(cpu_arch);
1003 if (rel.tag == .local) {989 if (rel.tag == .local) {
1004 const target: i64 = @intCast(rel.getTargetAddress(macho_file));990 const target: i64 = @intCast(rel.getTargetAddress(self, macho_file));
1005 addend += target;991 addend += target;
1006 }992 }
1007993
1008 try stream.seekTo(rel_offset);
1009
1010 switch (cpu_arch) {994 switch (cpu_arch) {
1011 .aarch64 => {995 .aarch64 => {
1012 if (rel.type == .unsigned) switch (rel.meta.length) {996 if (rel.type == .unsigned) switch (rel.meta.length) {
1013 0, 1 => unreachable,997 0, 1 => unreachable,
1014 2 => try stream.writer().writeInt(i32, @truncate(addend), .little),998 2 => mem.writeInt(i32, code[rel_offset..][0..4], @truncate(addend), .little),
1015 3 => try stream.writer().writeInt(i64, addend, .little),999 3 => mem.writeInt(i64, code[rel_offset..][0..8], addend, .little),
1016 } else if (addend > 0) {1000 } else if (addend > 0) {
1017 buffer.appendAssumeCapacity(.{1001 buffer[i] = .{
1018 .r_address = r_address,1002 .r_address = r_address,
1019 .r_symbolnum = @bitCast(math.cast(i24, addend) orelse return error.Overflow),1003 .r_symbolnum = @bitCast(math.cast(i24, addend) orelse return error.Overflow),
1020 .r_pcrel = 0,1004 .r_pcrel = 0,
1021 .r_length = 2,1005 .r_length = 2,
1022 .r_extern = 0,1006 .r_extern = 0,
1023 .r_type = @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_ADDEND),1007 .r_type = @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_ADDEND),
1024 });1008 };
1025 }1009 }
10261010
1027 const r_type: macho.reloc_type_arm64 = switch (rel.type) {1011 const r_type: macho.reloc_type_arm64 = switch (rel.type) {
...@@ -1045,14 +1029,14 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra...@@ -1045,14 +1029,14 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra
1045 .tlv,1029 .tlv,
1046 => unreachable,1030 => unreachable,
1047 };1031 };
1048 buffer.appendAssumeCapacity(.{1032 buffer[i] = .{
1049 .r_address = r_address,1033 .r_address = r_address,
1050 .r_symbolnum = r_symbolnum,1034 .r_symbolnum = r_symbolnum,
1051 .r_pcrel = @intFromBool(rel.meta.pcrel),1035 .r_pcrel = @intFromBool(rel.meta.pcrel),
1052 .r_extern = @intFromBool(r_extern),1036 .r_extern = @intFromBool(r_extern),
1053 .r_length = rel.meta.length,1037 .r_length = rel.meta.length,
1054 .r_type = @intFromEnum(r_type),1038 .r_type = @intFromEnum(r_type),
1055 });1039 };
1056 },1040 },
1057 .x86_64 => {1041 .x86_64 => {
1058 if (rel.meta.pcrel) {1042 if (rel.meta.pcrel) {
...@@ -1064,8 +1048,8 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra...@@ -1064,8 +1048,8 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra
1064 }1048 }
1065 switch (rel.meta.length) {1049 switch (rel.meta.length) {
1066 0, 1 => unreachable,1050 0, 1 => unreachable,
1067 2 => try stream.writer().writeInt(i32, @truncate(addend), .little),1051 2 => mem.writeInt(i32, code[rel_offset..][0..4], @truncate(addend), .little),
1068 3 => try stream.writer().writeInt(i64, addend, .little),1052 3 => mem.writeInt(i64, code[rel_offset..][0..8], addend, .little),
1069 }1053 }
10701054
1071 const r_type: macho.reloc_type_x86_64 = switch (rel.type) {1055 const r_type: macho.reloc_type_x86_64 = switch (rel.type) {
...@@ -1089,18 +1073,20 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra...@@ -1089,18 +1073,20 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra
1089 .tlvp_pageoff,1073 .tlvp_pageoff,
1090 => unreachable,1074 => unreachable,
1091 };1075 };
1092 buffer.appendAssumeCapacity(.{1076 buffer[i] = .{
1093 .r_address = r_address,1077 .r_address = r_address,
1094 .r_symbolnum = r_symbolnum,1078 .r_symbolnum = r_symbolnum,
1095 .r_pcrel = @intFromBool(rel.meta.pcrel),1079 .r_pcrel = @intFromBool(rel.meta.pcrel),
1096 .r_extern = @intFromBool(r_extern),1080 .r_extern = @intFromBool(r_extern),
1097 .r_length = rel.meta.length,1081 .r_length = rel.meta.length,
1098 .r_type = @intFromEnum(r_type),1082 .r_type = @intFromEnum(r_type),
1099 });1083 };
1100 },1084 },
1101 else => unreachable,1085 else => unreachable,
1102 }1086 }
1103 }1087 }
1088
1089 assert(i == buffer.len);
1104}1090}
11051091
1106pub fn format(1092pub fn format(
...@@ -1139,16 +1125,15 @@ fn format2(...@@ -1139,16 +1125,15 @@ fn format2(
1139 const atom = ctx.atom;1125 const atom = ctx.atom;
1140 const macho_file = ctx.macho_file;1126 const macho_file = ctx.macho_file;
1141 const file = atom.getFile(macho_file);1127 const file = atom.getFile(macho_file);
1142 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{1128 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{
1143 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),1129 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),
1144 atom.out_n_sect, atom.alignment, atom.size,1130 atom.out_n_sect, atom.alignment, atom.size,
1145 atom.getRelocs(macho_file).len,1131 atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk,
1146 });1132 });
1147 if (atom.flags.thunk) try writer.print(" : thunk({d})", .{atom.getExtra(macho_file).?.thunk});
1148 if (!atom.flags.alive) try writer.writeAll(" : [*]");1133 if (!atom.flags.alive) try writer.writeAll(" : [*]");
1149 if (atom.flags.unwind) {1134 if (atom.getUnwindRecords(macho_file).len > 0) {
1150 try writer.writeAll(" : unwind{ ");1135 try writer.writeAll(" : unwind{ ");
1151 const extra = atom.getExtra(macho_file).?;1136 const extra = atom.getExtra(macho_file);
1152 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {1137 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {
1153 const rec = file.object.getUnwindRecord(index);1138 const rec = file.object.getUnwindRecord(index);
1154 try writer.print("{d}", .{index});1139 try writer.print("{d}", .{index});
...@@ -1167,18 +1152,6 @@ pub const Flags = packed struct {...@@ -1167,18 +1152,6 @@ pub const Flags = packed struct {
11671152
1168 /// Specifies if this atom has been visited during garbage collection.1153 /// Specifies if this atom has been visited during garbage collection.
1169 visited: bool = false,1154 visited: bool = false,
1170
1171 /// Whether this atom has a range extension thunk.
1172 thunk: bool = false,
1173
1174 /// Whether this atom has any relocations.
1175 relocs: bool = false,
1176
1177 /// Whether this atom has any unwind records.
1178 unwind: bool = false,
1179
1180 /// Whether this atom has LiteralPool entry.
1181 literal_pool: bool = false,
1182};1155};
11831156
1184pub const Extra = struct {1157pub const Extra = struct {
...@@ -1191,6 +1164,12 @@ pub const Extra = struct {...@@ -1191,6 +1164,12 @@ pub const Extra = struct {
1191 /// Count of relocations belonging to this atom.1164 /// Count of relocations belonging to this atom.
1192 rel_count: u32 = 0,1165 rel_count: u32 = 0,
11931166
1167 /// Start index of relocations being written out to file for this atom.
1168 rel_out_index: u32 = 0,
1169
1170 /// Count of relocations written out to file for this atom.
1171 rel_out_count: u32 = 0,
1172
1194 /// Start index of relocations belonging to this atom.1173 /// Start index of relocations belonging to this atom.
1195 unwind_index: u32 = 0,1174 unwind_index: u32 = 0,
11961175
...@@ -1198,7 +1177,10 @@ pub const Extra = struct {...@@ -1198,7 +1177,10 @@ pub const Extra = struct {
1198 unwind_count: u32 = 0,1177 unwind_count: u32 = 0,
11991178
1200 /// Index into LiteralPool entry for this atom.1179 /// Index into LiteralPool entry for this atom.
1201 literal_index: u32 = 0,1180 literal_pool_index: u32 = 0,
1181
1182 /// Index into the File's symbol table for local symbol representing this literal atom.
1183 literal_symbol_index: u32 = 0,
1202};1184};
12031185
1204pub const Alignment = @import("../../InternPool.zig").Alignment;1186pub const Alignment = @import("../../InternPool.zig").Alignment;
src/link/MachO/InternalObject.zig+6
...@@ -639,6 +639,12 @@ pub fn asFile(self: *InternalObject) File {...@@ -639,6 +639,12 @@ pub fn asFile(self: *InternalObject) File {
639 return .{ .internal = self };639 return .{ .internal = self };
640}640}
641641
642pub fn getAtomRelocs(self: *const InternalObject, atom: Atom, macho_file: *MachO) []const Relocation {
643 const extra = atom.getExtra(macho_file).?;
644 const relocs = self.sections.items(.relocs)[atom.n_sect];
645 return relocs.items[extra.rel_index..][0..extra.rel_count];
646}
647
642fn addAtom(self: *InternalObject, allocator: Allocator) !Atom.Index {648fn addAtom(self: *InternalObject, allocator: Allocator) !Atom.Index {
643 const atom_index: Atom.Index = @intCast(self.atoms.items.len);649 const atom_index: Atom.Index = @intCast(self.atoms.items.len);
644 const atom = try self.atoms.addOne(allocator);650 const atom = try self.atoms.addOne(allocator);
src/link/MachO/Object.zig+10-4
...@@ -1860,7 +1860,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {...@@ -1860,7 +1860,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
1860 const name = sym.getName(macho_file);1860 const name = sym.getName(macho_file);
1861 if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue;1861 if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue;
1862 }1862 }
1863 const sect = macho_file.sections.items(.header)[sym.out_n_sect];1863 const sect = macho_file.sections.items(.header)[sym.getOutputSectionIndex(macho_file)];
1864 if (sect.isCode()) {1864 if (sect.isCode()) {
1865 self.output_symtab_ctx.nstabs += 4; // N_BNSYM, N_FUN, N_FUN, N_ENSYM1865 self.output_symtab_ctx.nstabs += 4; // N_BNSYM, N_FUN, N_FUN, N_ENSYM
1866 } else if (sym.visibility == .global) {1866 } else if (sym.visibility == .global) {
...@@ -2198,13 +2198,13 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {...@@ -2198,13 +2198,13 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
2198 const name = sym.getName(macho_file);2198 const name = sym.getName(macho_file);
2199 if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue;2199 if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue;
2200 }2200 }
2201 const sect = macho_file.sections.items(.header)[sym.out_n_sect];2201 const sect = macho_file.sections.items(.header)[sym.getOutputSectionIndex(macho_file)];
2202 const sym_n_strx = n_strx: {2202 const sym_n_strx = n_strx: {
2203 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;2203 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
2204 const osym = macho_file.symtab.items[symtab_index];2204 const osym = macho_file.symtab.items[symtab_index];
2205 break :n_strx osym.n_strx;2205 break :n_strx osym.n_strx;
2206 };2206 };
2207 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;2207 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.getOutputSectionIndex(macho_file) + 1) else 0;
2208 const sym_n_value = sym.getAddress(.{}, macho_file);2208 const sym_n_value = sym.getAddress(.{}, macho_file);
2209 const sym_size = sym.getSize(macho_file);2209 const sym_size = sym.getSize(macho_file);
2210 if (sect.isCode()) {2210 if (sect.isCode()) {
...@@ -2299,7 +2299,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {...@@ -2299,7 +2299,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
2299 const osym = macho_file.symtab.items[symtab_index];2299 const osym = macho_file.symtab.items[symtab_index];
2300 break :n_strx osym.n_strx;2300 break :n_strx osym.n_strx;
2301 };2301 };
2302 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;2302 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.getOutputSectionIndex(macho_file) + 1) else 0;
2303 const sym_n_value = sym.getAddress(.{}, macho_file);2303 const sym_n_value = sym.getAddress(.{}, macho_file);
2304 const sym_size = sym.getSize(macho_file);2304 const sym_size = sym.getSize(macho_file);
2305 if (stab.is_func) {2305 if (stab.is_func) {
...@@ -2340,6 +2340,12 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {...@@ -2340,6 +2340,12 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
2340 }2340 }
2341}2341}
23422342
2343pub fn getAtomRelocs(self: *const Object, atom: Atom, macho_file: *MachO) []const Relocation {
2344 const extra = atom.getExtra(macho_file).?;
2345 const relocs = self.sections.items(.relocs)[atom.n_sect];
2346 return relocs.items[extra.rel_index..][0..extra.rel_count];
2347}
2348
2343fn addString(self: *Object, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 {2349fn addString(self: *Object, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 {
2344 const off: u32 = @intCast(self.strtab.items.len);2350 const off: u32 = @intCast(self.strtab.items.len);
2345 try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);2351 try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);
src/link/MachO/Symbol.zig+37-35
...@@ -9,17 +9,16 @@ name: u32 = 0,...@@ -9,17 +9,16 @@ name: u32 = 0,
9/// File where this symbol is defined.9/// File where this symbol is defined.
10file: File.Index = 0,10file: File.Index = 0,
1111
12/// Atom containing this symbol if any.12/// Reference to Atom containing this symbol if any.
13/// Index of 0 means there is no associated atom with this symbol.
14/// Use `getAtom` to get the pointer to the atom.13/// Use `getAtom` to get the pointer to the atom.
15atom: Atom.Index = 0,14atom_ref: MachO.Ref = .{ .index = 0, .file = 0 },
1615
17/// Assigned output section index for this symbol.16/// Assigned output section index for this symbol.
18out_n_sect: u8 = 0,17out_n_sect: u8 = 0,
1918
20/// Index of the source nlist this symbol references.19/// Index of the source nlist this symbol references.
21/// Use `getNlist` to pull the nlist from the relevant file.20/// Use `getNlist` to pull the nlist from the relevant file.
22nlist_idx: Index = 0,21nlist_idx: u32 = 0,
2322
24/// Misc flags for the symbol packaged as packed struct for compression.23/// Misc flags for the symbol packaged as packed struct for compression.
25flags: Flags = .{},24flags: Flags = .{},
...@@ -55,16 +54,19 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool {...@@ -55,16 +54,19 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool {
55}54}
5655
57pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 {56pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 {
58 if (symbol.flags.global) return macho_file.strings.getAssumeExists(symbol.name);
59 return switch (symbol.getFile(macho_file).?) {57 return switch (symbol.getFile(macho_file).?) {
60 .dylib => unreachable, // There are no local symbols for dylibs
61 .zig_object => |x| x.strtab.getAssumeExists(symbol.name),58 .zig_object => |x| x.strtab.getAssumeExists(symbol.name),
62 inline else => |x| x.getString(symbol.name),59 inline else => |x| x.getString(symbol.name),
63 };60 };
64}61}
6562
66pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom {63pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom {
67 return macho_file.getAtom(symbol.atom);64 return symbol.atom_ref.getAtom(macho_file);
65}
66
67pub fn getOutputSectionIndex(symbol: Symbol, macho_file: *MachO) u8 {
68 if (symbol.getAtom(macho_file)) |atom| return atom.out_n_sect;
69 return symbol.out_n_sect;
68}70}
6971
70pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File {72pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File {
...@@ -75,8 +77,10 @@ pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File {...@@ -75,8 +77,10 @@ pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File {
75pub fn getNlist(symbol: Symbol, macho_file: *MachO) macho.nlist_64 {77pub fn getNlist(symbol: Symbol, macho_file: *MachO) macho.nlist_64 {
76 const file = symbol.getFile(macho_file).?;78 const file = symbol.getFile(macho_file).?;
77 return switch (file) {79 return switch (file) {
80 .dylib => unreachable,
81 .zig_object => unreachable,
78 .object => |x| x.symtab.items(.nlist)[symbol.nlist_idx],82 .object => |x| x.symtab.items(.nlist)[symbol.nlist_idx],
79 else => unreachable,83 .internal => |x| x.symtab.items[symbol.nlist_idx],
80 };84 };
81}85}
8286
...@@ -124,33 +128,35 @@ pub fn getAddress(symbol: Symbol, opts: struct {...@@ -124,33 +128,35 @@ pub fn getAddress(symbol: Symbol, opts: struct {
124128
125pub fn getGotAddress(symbol: Symbol, macho_file: *MachO) u64 {129pub fn getGotAddress(symbol: Symbol, macho_file: *MachO) u64 {
126 if (!symbol.flags.has_got) return 0;130 if (!symbol.flags.has_got) return 0;
127 const extra = symbol.getExtra(macho_file).?;131 const extra = symbol.getExtra(macho_file);
128 return macho_file.got.getAddress(extra.got, macho_file);132 return macho_file.got.getAddress(extra.got, macho_file);
129}133}
130134
131pub fn getStubsAddress(symbol: Symbol, macho_file: *MachO) u64 {135pub fn getStubsAddress(symbol: Symbol, macho_file: *MachO) u64 {
132 if (!symbol.flags.stubs) return 0;136 if (!symbol.flags.stubs) return 0;
133 const extra = symbol.getExtra(macho_file).?;137 const extra = symbol.getExtra(macho_file);
134 return macho_file.stubs.getAddress(extra.stubs, macho_file);138 return macho_file.stubs.getAddress(extra.stubs, macho_file);
135}139}
136140
137pub fn getObjcStubsAddress(symbol: Symbol, macho_file: *MachO) u64 {141pub fn getObjcStubsAddress(symbol: Symbol, macho_file: *MachO) u64 {
138 if (!symbol.flags.objc_stubs) return 0;142 if (!symbol.flags.objc_stubs) return 0;
139 const extra = symbol.getExtra(macho_file).?;143 const extra = symbol.getExtra(macho_file);
140 return macho_file.objc_stubs.getAddress(extra.objc_stubs, macho_file);144 return macho_file.objc_stubs.getAddress(extra.objc_stubs, macho_file);
141}145}
142146
143pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 {147pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 {
144 if (!symbol.flags.objc_stubs) return 0;148 if (!symbol.flags.objc_stubs) return 0;
145 const extra = symbol.getExtra(macho_file).?;149 const extra = symbol.getExtra(macho_file);
146 const atom = macho_file.getAtom(extra.objc_selrefs).?;150 const file = symbol.getFile(macho_file).?;
147 assert(atom.flags.alive);151 return switch (file) {
148 return atom.getAddress(macho_file);152 .dylib, .zig_object => unreachable,
153 .object, .internal => |x| x.symbols.items[extra.objc_selrefs].getAddress(.{}, macho_file),
154 };
149}155}
150156
151pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 {157pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 {
152 if (!symbol.flags.tlv_ptr) return 0;158 if (!symbol.flags.tlv_ptr) return 0;
153 const extra = symbol.getExtra(macho_file).?;159 const extra = symbol.getExtra(macho_file);
154 return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file);160 return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file);
155}161}
156162
...@@ -162,14 +168,14 @@ const GetOrCreateZigGotEntryResult = struct {...@@ -162,14 +168,14 @@ const GetOrCreateZigGotEntryResult = struct {
162pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult {168pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult {
163 assert(!macho_file.base.isRelocatable());169 assert(!macho_file.base.isRelocatable());
164 assert(symbol.flags.needs_zig_got);170 assert(symbol.flags.needs_zig_got);
165 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).?.zig_got };171 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).zig_got };
166 const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file);172 const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file);
167 return .{ .found_existing = false, .index = index };173 return .{ .found_existing = false, .index = index };
168}174}
169175
170pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 {176pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 {
171 if (!symbol.flags.has_zig_got) return 0;177 if (!symbol.flags.has_zig_got) return 0;
172 const extras = symbol.getExtra(macho_file).?;178 const extras = symbol.getExtra(macho_file);
173 return macho_file.zig_got.entryAddress(extras.zig_got, macho_file);179 return macho_file.zig_got.entryAddress(extras.zig_got, macho_file);
174}180}
175181
...@@ -202,11 +208,8 @@ const AddExtraOpts = struct {...@@ -202,11 +208,8 @@ const AddExtraOpts = struct {
202 symtab: ?u32 = null,208 symtab: ?u32 = null,
203};209};
204210
205pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void {211pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) void {
206 if (symbol.getExtra(macho_file) == null) {212 var extra = symbol.getExtra(macho_file);
207 symbol.extra = try macho_file.addSymbolExtra(.{});
208 }
209 var extra = symbol.getExtra(macho_file).?;
210 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {213 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
211 if (@field(opts, field.name)) |x| {214 if (@field(opts, field.name)) |x| {
212 @field(extra, field.name) = x;215 @field(extra, field.name) = x;
...@@ -215,18 +218,22 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void {...@@ -215,18 +218,22 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void {
215 symbol.setExtra(extra, macho_file);218 symbol.setExtra(extra, macho_file);
216}219}
217220
218pub inline fn getExtra(symbol: Symbol, macho_file: *MachO) ?Extra {221pub inline fn getExtra(symbol: Symbol, macho_file: *MachO) Extra {
219 return macho_file.getSymbolExtra(symbol.extra);222 return switch (symbol.getFile(macho_file).?) {
223 inline else => |x| x.getSymbolExtra(symbol.extra),
224 };
220}225}
221226
222pub inline fn setExtra(symbol: Symbol, extra: Extra, macho_file: *MachO) void {227pub inline fn setExtra(symbol: Symbol, extra: Extra, macho_file: *MachO) void {
223 macho_file.setSymbolExtra(symbol.extra, extra);228 return switch (symbol.getFile(macho_file).?) {
229 inline else => |x| x.setSymbolExtra(symbol.extra, extra),
230 };
224}231}
225232
226pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) void {233pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) void {
227 if (symbol.isLocal()) {234 if (symbol.isLocal()) {
228 out.n_type = if (symbol.flags.abs) macho.N_ABS else macho.N_SECT;235 out.n_type = if (symbol.flags.abs) macho.N_ABS else macho.N_SECT;
229 out.n_sect = if (symbol.flags.abs) 0 else @intCast(symbol.out_n_sect + 1);236 out.n_sect = if (symbol.flags.abs) 0 else @intCast(symbol.getOutputSectionIndex(macho_file) + 1);
230 out.n_desc = 0;237 out.n_desc = 0;
231 out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file);238 out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file);
232239
...@@ -238,7 +245,7 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo...@@ -238,7 +245,7 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo
238 assert(symbol.visibility == .global);245 assert(symbol.visibility == .global);
239 out.n_type = macho.N_EXT;246 out.n_type = macho.N_EXT;
240 out.n_type |= if (symbol.flags.abs) macho.N_ABS else macho.N_SECT;247 out.n_type |= if (symbol.flags.abs) macho.N_ABS else macho.N_SECT;
241 out.n_sect = if (symbol.flags.abs) 0 else @intCast(symbol.out_n_sect + 1);248 out.n_sect = if (symbol.flags.abs) 0 else @intCast(symbol.getOutputSectionIndex(macho_file) + 1);
242 out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file);249 out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file);
243 out.n_desc = 0;250 out.n_desc = 0;
244251
...@@ -318,8 +325,8 @@ fn format2(...@@ -318,8 +325,8 @@ fn format2(
318 symbol.getAddress(.{}, ctx.macho_file),325 symbol.getAddress(.{}, ctx.macho_file),
319 });326 });
320 if (symbol.getFile(ctx.macho_file)) |file| {327 if (symbol.getFile(ctx.macho_file)) |file| {
321 if (symbol.out_n_sect != 0) {328 if (symbol.getOutputSectionIndex(ctx.macho_file) != 0) {
322 try writer.print(" : sect({d})", .{symbol.out_n_sect});329 try writer.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)});
323 }330 }
324 if (symbol.getAtom(ctx.macho_file)) |atom| {331 if (symbol.getAtom(ctx.macho_file)) |atom| {
325 try writer.print(" : atom({d})", .{atom.atom_index});332 try writer.print(" : atom({d})", .{atom.atom_index});
...@@ -346,11 +353,6 @@ pub const Flags = packed struct {...@@ -346,11 +353,6 @@ pub const Flags = packed struct {
346 /// Whether the symbol is exported at runtime.353 /// Whether the symbol is exported at runtime.
347 @"export": bool = false,354 @"export": bool = false,
348355
349 /// Whether the symbol is effectively an extern and takes part in global
350 /// symbol resolution. Then, its name will be saved in global string interning
351 /// table.
352 global: bool = false,
353
354 /// Whether this symbol is weak.356 /// Whether this symbol is weak.
355 weak: bool = false,357 weak: bool = false,
356358