| author | |
| committer | |
| log | b9bac32a2562985ca7a67877169343975fd8f851 |
| tree | bf0f26530abc99fee00ba73d2e0a9de1e27f8dfc |
| parent | c59583e43de35e91ac194860cd1eb63e61c272aa |
5 files changed, 266 insertions(+), 163 deletions(-)
src/link/MachO.zig+139-32| ... | ... | @@ -22,16 +22,10 @@ dylibs: std.ArrayListUnmanaged(File.Index) = .{}, |
| 22 | 22 | segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{}, |
| 23 | 23 | sections: std.MultiArrayList(Section) = .{}, |
| 24 | 24 | |
| 25 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | |
| 26 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 27 | symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 28 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, | |
| 25 | resolver: SymbolResolver = .{}, | |
| 29 | 26 | /// This table will be populated after `scanRelocs` has run. |
| 30 | 27 | /// Key is symbol index. |
| 31 | undefs: std.AutoHashMapUnmanaged(Symbol.Index, std.ArrayListUnmanaged(Atom.Index)) = .{}, | |
| 32 | /// Global symbols we need to resolve for the link to succeed. | |
| 33 | undefined_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 34 | boundary_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 28 | undefs: std.AutoHashMapUnmanaged(Ref, std.ArrayListUnmanaged(Ref)) = .{}, | |
| 35 | 29 | |
| 36 | 30 | dyld_info_cmd: macho.dyld_info_command = .{}, |
| 37 | 31 | symtab_cmd: macho.symtab_command = .{}, |
| ... | ... | @@ -55,19 +49,8 @@ eh_frame_sect_index: ?u8 = null, |
| 55 | 49 | unwind_info_sect_index: ?u8 = null, |
| 56 | 50 | objc_stubs_sect_index: ?u8 = null, |
| 57 | 51 | |
| 58 | mh_execute_header_index: ?Symbol.Index = null, | |
| 59 | mh_dylib_header_index: ?Symbol.Index = null, | |
| 60 | dyld_private_index: ?Symbol.Index = null, | |
| 61 | dyld_stub_binder_index: ?Symbol.Index = null, | |
| 62 | dso_handle_index: ?Symbol.Index = null, | |
| 63 | objc_msg_send_index: ?Symbol.Index = null, | |
| 64 | entry_index: ?Symbol.Index = null, | |
| 65 | ||
| 66 | 52 | thunks: std.ArrayListUnmanaged(Thunk) = .{}, |
| 67 | 53 | |
| 68 | /// String interning table | |
| 69 | strings: StringTable = .{}, | |
| 70 | ||
| 71 | 54 | /// Output synthetic sections |
| 72 | 55 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 73 | 56 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| ... | ... | @@ -4196,7 +4179,7 @@ const Section = struct { |
| 4196 | 4179 | pub const LiteralPool = struct { |
| 4197 | 4180 | table: std.AutoArrayHashMapUnmanaged(void, void) = .{}, |
| 4198 | 4181 | keys: std.ArrayListUnmanaged(Key) = .{}, |
| 4199 | values: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 4182 | values: std.ArrayListUnmanaged(MachO.Ref) = .{}, | |
| 4200 | 4183 | data: std.ArrayListUnmanaged(u8) = .{}, |
| 4201 | 4184 | |
| 4202 | 4185 | pub fn deinit(lp: *LiteralPool, allocator: Allocator) void { |
| ... | ... | @@ -4206,17 +4189,21 @@ pub const LiteralPool = struct { |
| 4206 | 4189 | lp.data.deinit(allocator); |
| 4207 | 4190 | } |
| 4208 | 4191 | |
| 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 | 4192 | const InsertResult = struct { |
| 4215 | 4193 | found_existing: bool, |
| 4216 | 4194 | index: Index, |
| 4217 | atom: *Atom.Index, | |
| 4195 | ref: *MachO.Ref, | |
| 4218 | 4196 | }; |
| 4219 | 4197 | |
| 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 | 4207 | pub fn insert(lp: *LiteralPool, allocator: Allocator, @"type": u8, string: []const u8) !InsertResult { |
| 4221 | 4208 | const size: u32 = @intCast(string.len); |
| 4222 | 4209 | try lp.data.ensureUnusedCapacity(allocator, size); |
| ... | ... | @@ -4278,12 +4265,6 @@ const HotUpdateState = struct { |
| 4278 | 4265 | mach_task: ?std.c.MachTask = null, |
| 4279 | 4266 | }; |
| 4280 | 4267 | |
| 4281 | pub const DynamicRelocs = struct { | |
| 4282 | rebase_relocs: u32 = 0, | |
| 4283 | bind_relocs: u32 = 0, | |
| 4284 | weak_bind_relocs: u32 = 0, | |
| 4285 | }; | |
| 4286 | ||
| 4287 | 4268 | pub const SymtabCtx = struct { |
| 4288 | 4269 | ilocal: u32 = 0, |
| 4289 | 4270 | istab: u32 = 0, |
| ... | ... | @@ -4293,6 +4274,7 @@ pub const SymtabCtx = struct { |
| 4293 | 4274 | nstabs: u32 = 0, |
| 4294 | 4275 | nexports: u32 = 0, |
| 4295 | 4276 | nimports: u32 = 0, |
| 4277 | stroff: u32 = 0, | |
| 4296 | 4278 | strsize: u32 = 0, |
| 4297 | 4279 | }; |
| 4298 | 4280 | |
| ... | ... | @@ -4579,6 +4561,131 @@ const UndefinedTreatment = enum { |
| 4579 | 4561 | dynamic_lookup, |
| 4580 | 4562 | }; |
| 4581 | 4563 | |
| 4564 | /// A reference to atom or symbol in an input file. | |
| 4565 | /// If file == 0, symbol is an undefined global. | |
| 4566 | pub 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 | ||
| 4602 | pub 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 | ||
| 4582 | 4689 | const MachO = @This(); |
| 4583 | 4690 | |
| 4584 | 4691 | const std = @import("std"); |
src/link/MachO/Atom.zig+74-92| ... | ... | @@ -47,16 +47,6 @@ pub fn getFile(self: Atom, macho_file: *MachO) File { |
| 47 | 47 | return macho_file.getFile(self.file).?; |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | pub 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 | ||
| 60 | 50 | pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation { |
| 61 | 51 | return switch (self.getFile(macho_file)) { |
| 62 | 52 | .dylib => unreachable, |
| ... | ... | @@ -88,8 +78,7 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 { |
| 88 | 78 | } |
| 89 | 79 | |
| 90 | 80 | pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index { |
| 91 | if (!self.flags.unwind) return &[0]UnwindInfo.Record.Index{}; | |
| 92 | const extra = self.getExtra(macho_file).?; | |
| 81 | const extra = self.getExtra(macho_file); | |
| 93 | 82 | return switch (self.getFile(macho_file)) { |
| 94 | 83 | .dylib => unreachable, |
| 95 | 84 | .zig_object, .internal => &[0]UnwindInfo.Record.Index{}, |
| ... | ... | @@ -110,44 +99,39 @@ pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { |
| 110 | 99 | } |
| 111 | 100 | |
| 112 | 101 | pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { |
| 113 | assert(self.flags.thunk); | |
| 114 | const extra = self.getExtra(macho_file).?; | |
| 102 | const extra = self.getExtra(macho_file); | |
| 115 | 103 | return macho_file.getThunk(extra.thunk); |
| 116 | 104 | } |
| 117 | 105 | |
| 118 | pub 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 | ||
| 123 | 106 | const AddExtraOpts = struct { |
| 124 | 107 | thunk: ?u32 = null, |
| 125 | 108 | rel_index: ?u32 = null, |
| 126 | 109 | rel_count: ?u32 = null, |
| 110 | rel_out_index: ?u32 = null, | |
| 111 | rel_out_count: ?u32 = null, | |
| 127 | 112 | unwind_index: ?u32 = null, |
| 128 | 113 | unwind_count: ?u32 = null, |
| 129 | literal_index: ?u32 = null, | |
| 114 | literal_pool_index: ?u32 = null, | |
| 115 | literal_symbol_index: ?u32 = null, | |
| 130 | 116 | }; |
| 131 | 117 | |
| 132 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) !void { | |
| 133 | if (atom.getExtra(macho_file) == null) { | |
| 134 | atom.extra = try macho_file.addAtomExtra(.{}); | |
| 135 | } | |
| 136 | var extra = atom.getExtra(macho_file).?; | |
| 118 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) void { | |
| 119 | const file = atom.getFile(macho_file); | |
| 120 | var extra = file.getAtomExtra(atom.extra); | |
| 137 | 121 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { |
| 138 | 122 | if (@field(opts, field.name)) |x| { |
| 139 | 123 | @field(extra, field.name) = x; |
| 140 | 124 | } |
| 141 | 125 | } |
| 142 | atom.setExtra(extra, macho_file); | |
| 126 | file.setAtomExtra(atom.extra, extra); | |
| 143 | 127 | } |
| 144 | 128 | |
| 145 | pub inline fn getExtra(atom: Atom, macho_file: *MachO) ?Extra { | |
| 146 | return macho_file.getAtomExtra(atom.extra); | |
| 129 | pub inline fn getExtra(atom: Atom, macho_file: *MachO) Extra { | |
| 130 | return atom.getFile(macho_file).getAtomExtra(atom.extra); | |
| 147 | 131 | } |
| 148 | 132 | |
| 149 | 133 | pub 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 | } |
| 152 | 136 | |
| 153 | 137 | pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| ... | ... | @@ -467,7 +451,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 467 | 451 | |
| 468 | 452 | switch (rel.type) { |
| 469 | 453 | .branch => { |
| 470 | const symbol = rel.getTargetSymbol(macho_file); | |
| 454 | const symbol = rel.getTargetSymbol(self, macho_file); | |
| 471 | 455 | if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) { |
| 472 | 456 | symbol.flags.stubs = true; |
| 473 | 457 | if (symbol.flags.weak) { |
| ... | ... | @@ -482,7 +466,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 482 | 466 | .got_load_page, |
| 483 | 467 | .got_load_pageoff, |
| 484 | 468 | => { |
| 485 | const symbol = rel.getTargetSymbol(macho_file); | |
| 469 | const symbol = rel.getTargetSymbol(self, macho_file); | |
| 486 | 470 | if (symbol.flags.import or |
| 487 | 471 | (symbol.flags.@"export" and symbol.flags.weak) or |
| 488 | 472 | symbol.flags.interposable or |
| ... | ... | @@ -496,18 +480,18 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 496 | 480 | }, |
| 497 | 481 | |
| 498 | 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 | }, |
| 501 | 485 | |
| 502 | 486 | .got => { |
| 503 | rel.getTargetSymbol(macho_file).flags.needs_got = true; | |
| 487 | rel.getTargetSymbol(self, macho_file).flags.needs_got = true; | |
| 504 | 488 | }, |
| 505 | 489 | |
| 506 | 490 | .tlv, |
| 507 | 491 | .tlvp_page, |
| 508 | 492 | .tlvp_pageoff, |
| 509 | 493 | => { |
| 510 | const symbol = rel.getTargetSymbol(macho_file); | |
| 494 | const symbol = rel.getTargetSymbol(self, macho_file); | |
| 511 | 495 | if (!symbol.flags.tlv) { |
| 512 | 496 | try macho_file.reportParseError2( |
| 513 | 497 | self.getFile(macho_file).getIndex(), |
| ... | ... | @@ -526,7 +510,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 526 | 510 | .unsigned => { |
| 527 | 511 | if (rel.meta.length == 3) { // TODO this really should check if this is pointer width |
| 528 | 512 | if (rel.tag == .@"extern") { |
| 529 | const symbol = rel.getTargetSymbol(macho_file); | |
| 513 | const symbol = rel.getTargetSymbol(self, macho_file); | |
| 530 | 514 | if (symbol.isTlvInit(macho_file)) { |
| 531 | 515 | macho_file.has_tlv = true; |
| 532 | 516 | continue; |
| ... | ... | @@ -559,14 +543,15 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 559 | 543 | fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool { |
| 560 | 544 | if (rel.tag == .local) return false; |
| 561 | 545 | |
| 562 | const sym = rel.getTargetSymbol(macho_file); | |
| 563 | if (sym.getFile(macho_file) == null) { | |
| 546 | const file = self.getFile(macho_file); | |
| 547 | const ref = file.getSymbolRef(rel.target, macho_file); | |
| 548 | if (ref.getFile(macho_file) == null) { | |
| 564 | 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 | 551 | if (!gop.found_existing) { |
| 567 | 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 | 555 | return true; |
| 571 | 556 | } |
| 572 | 557 | |
| ... | ... | @@ -582,7 +567,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 582 | 567 | const name = self.getName(macho_file); |
| 583 | 568 | const relocs = self.getRelocs(macho_file); |
| 584 | 569 | |
| 585 | relocs_log.debug("{x}: {s}", .{ self.getAddress(macho_file), name }); | |
| 570 | relocs_log.debug("{x}: {s}", .{ self.value, name }); | |
| 586 | 571 | |
| 587 | 572 | var has_error = false; |
| 588 | 573 | var stream = std.io.fixedBufferStream(buffer); |
| ... | ... | @@ -593,7 +578,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 593 | 578 | const subtractor = if (rel.meta.has_subtractor) relocs[i - 1] else null; |
| 594 | 579 | |
| 595 | 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 | } |
| 598 | 583 | |
| 599 | 584 | try stream.seekTo(rel_offset); |
| ... | ... | @@ -601,8 +586,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 601 | 586 | switch (err) { |
| 602 | 587 | error.RelaxFail => { |
| 603 | 588 | const target = switch (rel.tag) { |
| 604 | .@"extern" => rel.getTargetSymbol(macho_file).getName(macho_file), | |
| 605 | .local => rel.getTargetAtom(macho_file).getName(macho_file), | |
| 589 | .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file), | |
| 590 | .local => rel.getTargetAtom(self, macho_file).getName(macho_file), | |
| 606 | 591 | }; |
| 607 | 592 | try macho_file.reportParseError2( |
| 608 | 593 | file.getIndex(), |
| ... | ... | @@ -642,12 +627,12 @@ fn resolveRelocInner( |
| 642 | 627 | const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; |
| 643 | 628 | const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset)); |
| 644 | 629 | const A = rel.addend + rel.getRelocAddend(cpu_arch); |
| 645 | const S: i64 = @intCast(rel.getTargetAddress(macho_file)); | |
| 646 | const G: i64 = @intCast(rel.getGotTargetAddress(macho_file)); | |
| 630 | const S: i64 = @intCast(rel.getTargetAddress(self, macho_file)); | |
| 631 | const G: i64 = @intCast(rel.getGotTargetAddress(self, macho_file)); | |
| 647 | 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 | 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))); | |
| 651 | 636 | |
| 652 | 637 | const divExact = struct { |
| 653 | 638 | fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 { |
| ... | ... | @@ -668,7 +653,7 @@ fn resolveRelocInner( |
| 668 | 653 | rel_offset, |
| 669 | 654 | @tagName(rel.type), |
| 670 | 655 | S + A - SUB, |
| 671 | rel.getTargetAtom(macho_file).atom_index, | |
| 656 | rel.getTargetAtom(self, macho_file).atom_index, | |
| 672 | 657 | }), |
| 673 | 658 | .@"extern" => relocs_log.debug(" {x}<+{d}>: {s}: [=> {x}] G({x}) ZG({x}) ({s})", .{ |
| 674 | 659 | P, |
| ... | ... | @@ -677,7 +662,7 @@ fn resolveRelocInner( |
| 677 | 662 | S + A - SUB, |
| 678 | 663 | G + A, |
| 679 | 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 | } |
| 683 | 668 | |
| ... | ... | @@ -688,7 +673,7 @@ fn resolveRelocInner( |
| 688 | 673 | assert(!rel.meta.pcrel); |
| 689 | 674 | if (rel.meta.length == 3) { |
| 690 | 675 | if (rel.tag == .@"extern") { |
| 691 | const sym = rel.getTargetSymbol(macho_file); | |
| 676 | const sym = rel.getTargetSymbol(self, macho_file); | |
| 692 | 677 | if (sym.isTlvInit(macho_file)) { |
| 693 | 678 | try writer.writeInt(u64, @intCast(S - TLS), .little); |
| 694 | 679 | return; |
| ... | ... | @@ -718,7 +703,7 @@ fn resolveRelocInner( |
| 718 | 703 | .aarch64 => { |
| 719 | 704 | const disp: i28 = math.cast(i28, S + A - P) orelse blk: { |
| 720 | 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 | 707 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; |
| 723 | 708 | }; |
| 724 | 709 | aarch64.writeBranchImm(disp, code[rel_offset..][0..4]); |
| ... | ... | @@ -731,7 +716,7 @@ fn resolveRelocInner( |
| 731 | 716 | assert(rel.tag == .@"extern"); |
| 732 | 717 | assert(rel.meta.length == 2); |
| 733 | 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 | 720 | try writer.writeInt(i32, @intCast(G + A - P), .little); |
| 736 | 721 | } else { |
| 737 | 722 | try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file); |
| ... | ... | @@ -754,7 +739,7 @@ fn resolveRelocInner( |
| 754 | 739 | assert(rel.tag == .@"extern"); |
| 755 | 740 | assert(rel.meta.length == 2); |
| 756 | 741 | assert(rel.meta.pcrel); |
| 757 | const sym = rel.getTargetSymbol(macho_file); | |
| 742 | const sym = rel.getTargetSymbol(self, macho_file); | |
| 758 | 743 | if (sym.flags.tlv_ptr) { |
| 759 | 744 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); |
| 760 | 745 | try writer.writeInt(i32, @intCast(S_ + A - P), .little); |
| ... | ... | @@ -777,7 +762,7 @@ fn resolveRelocInner( |
| 777 | 762 | assert(rel.tag == .@"extern"); |
| 778 | 763 | assert(rel.meta.length == 2); |
| 779 | 764 | assert(rel.meta.pcrel); |
| 780 | const sym = rel.getTargetSymbol(macho_file); | |
| 765 | const sym = rel.getTargetSymbol(self, macho_file); | |
| 781 | 766 | const source = math.cast(u64, P) orelse return error.Overflow; |
| 782 | 767 | const target = target: { |
| 783 | 768 | const target = switch (rel.type) { |
| ... | ... | @@ -836,7 +821,7 @@ fn resolveRelocInner( |
| 836 | 821 | assert(rel.meta.length == 2); |
| 837 | 822 | assert(!rel.meta.pcrel); |
| 838 | 823 | |
| 839 | const sym = rel.getTargetSymbol(macho_file); | |
| 824 | const sym = rel.getTargetSymbol(self, macho_file); | |
| 840 | 825 | const target = target: { |
| 841 | 826 | const target = if (sym.flags.tlv_ptr) blk: { |
| 842 | 827 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); |
| ... | ... | @@ -980,48 +965,47 @@ pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 { |
| 980 | 965 | } |
| 981 | 966 | } |
| 982 | 967 | |
| 983 | pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.ArrayList(macho.relocation_info)) !void { | |
| 968 | pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.relocation_info) !void { | |
| 984 | 969 | const tracy = trace(@src()); |
| 985 | 970 | defer tracy.end(); |
| 986 | 971 | |
| 987 | 972 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 988 | 973 | const relocs = self.getRelocs(macho_file); |
| 989 | var stream = std.io.fixedBufferStream(code); | |
| 990 | 974 | |
| 975 | var i: usize = 0; | |
| 991 | 976 | for (relocs) |rel| { |
| 977 | defer i += 1; | |
| 992 | 978 | const rel_offset = rel.offset - self.off; |
| 993 | 979 | const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow; |
| 994 | 980 | const r_symbolnum = r_symbolnum: { |
| 995 | 981 | const r_symbolnum: u32 = switch (rel.tag) { |
| 996 | .local => rel.getTargetAtom(macho_file).out_n_sect + 1, | |
| 997 | .@"extern" => rel.getTargetSymbol(macho_file).getOutputSymtabIndex(macho_file).?, | |
| 982 | .local => rel.getTargetAtom(self, macho_file).out_n_sect + 1, | |
| 983 | .@"extern" => rel.getTargetSymbol(self, macho_file).getOutputSymtabIndex(macho_file).?, | |
| 998 | 984 | }; |
| 999 | 985 | break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow; |
| 1000 | 986 | }; |
| 1001 | 987 | const r_extern = rel.tag == .@"extern"; |
| 1002 | 988 | var addend = rel.addend + rel.getRelocAddend(cpu_arch); |
| 1003 | 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 | 991 | addend += target; |
| 1006 | 992 | } |
| 1007 | 993 | |
| 1008 | try stream.seekTo(rel_offset); | |
| 1009 | ||
| 1010 | 994 | switch (cpu_arch) { |
| 1011 | 995 | .aarch64 => { |
| 1012 | 996 | if (rel.type == .unsigned) switch (rel.meta.length) { |
| 1013 | 997 | 0, 1 => unreachable, |
| 1014 | 2 => try stream.writer().writeInt(i32, @truncate(addend), .little), | |
| 1015 | 3 => try stream.writer().writeInt(i64, addend, .little), | |
| 998 | 2 => mem.writeInt(i32, code[rel_offset..][0..4], @truncate(addend), .little), | |
| 999 | 3 => mem.writeInt(i64, code[rel_offset..][0..8], addend, .little), | |
| 1016 | 1000 | } else if (addend > 0) { |
| 1017 | buffer.appendAssumeCapacity(.{ | |
| 1001 | buffer[i] = .{ | |
| 1018 | 1002 | .r_address = r_address, |
| 1019 | 1003 | .r_symbolnum = @bitCast(math.cast(i24, addend) orelse return error.Overflow), |
| 1020 | 1004 | .r_pcrel = 0, |
| 1021 | 1005 | .r_length = 2, |
| 1022 | 1006 | .r_extern = 0, |
| 1023 | 1007 | .r_type = @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_ADDEND), |
| 1024 | }); | |
| 1008 | }; | |
| 1025 | 1009 | } |
| 1026 | 1010 | |
| 1027 | 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 | 1029 | .tlv, |
| 1046 | 1030 | => unreachable, |
| 1047 | 1031 | }; |
| 1048 | buffer.appendAssumeCapacity(.{ | |
| 1032 | buffer[i] = .{ | |
| 1049 | 1033 | .r_address = r_address, |
| 1050 | 1034 | .r_symbolnum = r_symbolnum, |
| 1051 | 1035 | .r_pcrel = @intFromBool(rel.meta.pcrel), |
| 1052 | 1036 | .r_extern = @intFromBool(r_extern), |
| 1053 | 1037 | .r_length = rel.meta.length, |
| 1054 | 1038 | .r_type = @intFromEnum(r_type), |
| 1055 | }); | |
| 1039 | }; | |
| 1056 | 1040 | }, |
| 1057 | 1041 | .x86_64 => { |
| 1058 | 1042 | if (rel.meta.pcrel) { |
| ... | ... | @@ -1064,8 +1048,8 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1064 | 1048 | } |
| 1065 | 1049 | switch (rel.meta.length) { |
| 1066 | 1050 | 0, 1 => unreachable, |
| 1067 | 2 => try stream.writer().writeInt(i32, @truncate(addend), .little), | |
| 1068 | 3 => try stream.writer().writeInt(i64, addend, .little), | |
| 1051 | 2 => mem.writeInt(i32, code[rel_offset..][0..4], @truncate(addend), .little), | |
| 1052 | 3 => mem.writeInt(i64, code[rel_offset..][0..8], addend, .little), | |
| 1069 | 1053 | } |
| 1070 | 1054 | |
| 1071 | 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 | 1073 | .tlvp_pageoff, |
| 1090 | 1074 | => unreachable, |
| 1091 | 1075 | }; |
| 1092 | buffer.appendAssumeCapacity(.{ | |
| 1076 | buffer[i] = .{ | |
| 1093 | 1077 | .r_address = r_address, |
| 1094 | 1078 | .r_symbolnum = r_symbolnum, |
| 1095 | 1079 | .r_pcrel = @intFromBool(rel.meta.pcrel), |
| 1096 | 1080 | .r_extern = @intFromBool(r_extern), |
| 1097 | 1081 | .r_length = rel.meta.length, |
| 1098 | 1082 | .r_type = @intFromEnum(r_type), |
| 1099 | }); | |
| 1083 | }; | |
| 1100 | 1084 | }, |
| 1101 | 1085 | else => unreachable, |
| 1102 | 1086 | } |
| 1103 | 1087 | } |
| 1088 | ||
| 1089 | assert(i == buffer.len); | |
| 1104 | 1090 | } |
| 1105 | 1091 | |
| 1106 | 1092 | pub fn format( |
| ... | ... | @@ -1139,16 +1125,15 @@ fn format2( |
| 1139 | 1125 | const atom = ctx.atom; |
| 1140 | 1126 | const macho_file = ctx.macho_file; |
| 1141 | 1127 | const file = atom.getFile(macho_file); |
| 1142 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{ | |
| 1143 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), | |
| 1144 | atom.out_n_sect, atom.alignment, atom.size, | |
| 1145 | atom.getRelocs(macho_file).len, | |
| 1128 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{ | |
| 1129 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), | |
| 1130 | atom.out_n_sect, atom.alignment, atom.size, | |
| 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 | 1133 | if (!atom.flags.alive) try writer.writeAll(" : [*]"); |
| 1149 | if (atom.flags.unwind) { | |
| 1134 | if (atom.getUnwindRecords(macho_file).len > 0) { | |
| 1150 | 1135 | try writer.writeAll(" : unwind{ "); |
| 1151 | const extra = atom.getExtra(macho_file).?; | |
| 1136 | const extra = atom.getExtra(macho_file); | |
| 1152 | 1137 | for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| { |
| 1153 | 1138 | const rec = file.object.getUnwindRecord(index); |
| 1154 | 1139 | try writer.print("{d}", .{index}); |
| ... | ... | @@ -1167,18 +1152,6 @@ pub const Flags = packed struct { |
| 1167 | 1152 | |
| 1168 | 1153 | /// Specifies if this atom has been visited during garbage collection. |
| 1169 | 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 | }; |
| 1183 | 1156 | |
| 1184 | 1157 | pub const Extra = struct { |
| ... | ... | @@ -1191,6 +1164,12 @@ pub const Extra = struct { |
| 1191 | 1164 | /// Count of relocations belonging to this atom. |
| 1192 | 1165 | rel_count: u32 = 0, |
| 1193 | 1166 | |
| 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 | 1173 | /// Start index of relocations belonging to this atom. |
| 1195 | 1174 | unwind_index: u32 = 0, |
| 1196 | 1175 | |
| ... | ... | @@ -1198,7 +1177,10 @@ pub const Extra = struct { |
| 1198 | 1177 | unwind_count: u32 = 0, |
| 1199 | 1178 | |
| 1200 | 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 | }; |
| 1203 | 1185 | |
| 1204 | 1186 | pub const Alignment = @import("../../InternPool.zig").Alignment; |
src/link/MachO/InternalObject.zig+6| ... | ... | @@ -639,6 +639,12 @@ pub fn asFile(self: *InternalObject) File { |
| 639 | 639 | return .{ .internal = self }; |
| 640 | 640 | } |
| 641 | 641 | |
| 642 | pub 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 | ||
| 642 | 648 | fn addAtom(self: *InternalObject, allocator: Allocator) !Atom.Index { |
| 643 | 649 | const atom_index: Atom.Index = @intCast(self.atoms.items.len); |
| 644 | 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 | 1860 | const name = sym.getName(macho_file); |
| 1861 | 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 | 1864 | if (sect.isCode()) { |
| 1865 | 1865 | self.output_symtab_ctx.nstabs += 4; // N_BNSYM, N_FUN, N_FUN, N_ENSYM |
| 1866 | 1866 | } else if (sym.visibility == .global) { |
| ... | ... | @@ -2198,13 +2198,13 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void { |
| 2198 | 2198 | const name = sym.getName(macho_file); |
| 2199 | 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 | 2202 | const sym_n_strx = n_strx: { |
| 2203 | 2203 | const symtab_index = sym.getOutputSymtabIndex(macho_file).?; |
| 2204 | 2204 | const osym = macho_file.symtab.items[symtab_index]; |
| 2205 | 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 | 2208 | const sym_n_value = sym.getAddress(.{}, macho_file); |
| 2209 | 2209 | const sym_size = sym.getSize(macho_file); |
| 2210 | 2210 | if (sect.isCode()) { |
| ... | ... | @@ -2299,7 +2299,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void { |
| 2299 | 2299 | const osym = macho_file.symtab.items[symtab_index]; |
| 2300 | 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 | 2303 | const sym_n_value = sym.getAddress(.{}, macho_file); |
| 2304 | 2304 | const sym_size = sym.getSize(macho_file); |
| 2305 | 2305 | if (stab.is_func) { |
| ... | ... | @@ -2340,6 +2340,12 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void { |
| 2340 | 2340 | } |
| 2341 | 2341 | } |
| 2342 | 2342 | |
| 2343 | pub 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 | ||
| 2343 | 2349 | fn addString(self: *Object, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 { |
| 2344 | 2350 | const off: u32 = @intCast(self.strtab.items.len); |
| 2345 | 2351 | try self.strtab.ensureUnusedCapacity(allocator, name.len + 1); |
src/link/MachO/Symbol.zig+37-35| ... | ... | @@ -9,17 +9,16 @@ name: u32 = 0, |
| 9 | 9 | /// File where this symbol is defined. |
| 10 | 10 | file: File.Index = 0, |
| 11 | 11 | |
| 12 | /// Atom containing this symbol if any. | |
| 13 | /// Index of 0 means there is no associated atom with this symbol. | |
| 12 | /// Reference to Atom containing this symbol if any. | |
| 14 | 13 | /// Use `getAtom` to get the pointer to the atom. |
| 15 | atom: Atom.Index = 0, | |
| 14 | atom_ref: MachO.Ref = .{ .index = 0, .file = 0 }, | |
| 16 | 15 | |
| 17 | 16 | /// Assigned output section index for this symbol. |
| 18 | 17 | out_n_sect: u8 = 0, |
| 19 | 18 | |
| 20 | 19 | /// Index of the source nlist this symbol references. |
| 21 | 20 | /// Use `getNlist` to pull the nlist from the relevant file. |
| 22 | nlist_idx: Index = 0, | |
| 21 | nlist_idx: u32 = 0, | |
| 23 | 22 | |
| 24 | 23 | /// Misc flags for the symbol packaged as packed struct for compression. |
| 25 | 24 | flags: Flags = .{}, |
| ... | ... | @@ -55,16 +54,19 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool { |
| 55 | 54 | } |
| 56 | 55 | |
| 57 | 56 | pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 { |
| 58 | if (symbol.flags.global) return macho_file.strings.getAssumeExists(symbol.name); | |
| 59 | 57 | return switch (symbol.getFile(macho_file).?) { |
| 60 | .dylib => unreachable, // There are no local symbols for dylibs | |
| 61 | 58 | .zig_object => |x| x.strtab.getAssumeExists(symbol.name), |
| 62 | 59 | inline else => |x| x.getString(symbol.name), |
| 63 | 60 | }; |
| 64 | 61 | } |
| 65 | 62 | |
| 66 | 63 | pub 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 | ||
| 67 | pub 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 | } |
| 69 | 71 | |
| 70 | 72 | pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { |
| ... | ... | @@ -75,8 +77,10 @@ pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { |
| 75 | 77 | pub fn getNlist(symbol: Symbol, macho_file: *MachO) macho.nlist_64 { |
| 76 | 78 | const file = symbol.getFile(macho_file).?; |
| 77 | 79 | return switch (file) { |
| 80 | .dylib => unreachable, | |
| 81 | .zig_object => unreachable, | |
| 78 | 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 | } |
| 82 | 86 | |
| ... | ... | @@ -124,33 +128,35 @@ pub fn getAddress(symbol: Symbol, opts: struct { |
| 124 | 128 | |
| 125 | 129 | pub fn getGotAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 126 | 130 | if (!symbol.flags.has_got) return 0; |
| 127 | const extra = symbol.getExtra(macho_file).?; | |
| 131 | const extra = symbol.getExtra(macho_file); | |
| 128 | 132 | return macho_file.got.getAddress(extra.got, macho_file); |
| 129 | 133 | } |
| 130 | 134 | |
| 131 | 135 | pub fn getStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 132 | 136 | if (!symbol.flags.stubs) return 0; |
| 133 | const extra = symbol.getExtra(macho_file).?; | |
| 137 | const extra = symbol.getExtra(macho_file); | |
| 134 | 138 | return macho_file.stubs.getAddress(extra.stubs, macho_file); |
| 135 | 139 | } |
| 136 | 140 | |
| 137 | 141 | pub fn getObjcStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 138 | 142 | if (!symbol.flags.objc_stubs) return 0; |
| 139 | const extra = symbol.getExtra(macho_file).?; | |
| 143 | const extra = symbol.getExtra(macho_file); | |
| 140 | 144 | return macho_file.objc_stubs.getAddress(extra.objc_stubs, macho_file); |
| 141 | 145 | } |
| 142 | 146 | |
| 143 | 147 | pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 144 | 148 | if (!symbol.flags.objc_stubs) return 0; |
| 145 | const extra = symbol.getExtra(macho_file).?; | |
| 146 | const atom = macho_file.getAtom(extra.objc_selrefs).?; | |
| 147 | assert(atom.flags.alive); | |
| 148 | return atom.getAddress(macho_file); | |
| 149 | const extra = symbol.getExtra(macho_file); | |
| 150 | const file = symbol.getFile(macho_file).?; | |
| 151 | return switch (file) { | |
| 152 | .dylib, .zig_object => unreachable, | |
| 153 | .object, .internal => |x| x.symbols.items[extra.objc_selrefs].getAddress(.{}, macho_file), | |
| 154 | }; | |
| 149 | 155 | } |
| 150 | 156 | |
| 151 | 157 | pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 152 | 158 | if (!symbol.flags.tlv_ptr) return 0; |
| 153 | const extra = symbol.getExtra(macho_file).?; | |
| 159 | const extra = symbol.getExtra(macho_file); | |
| 154 | 160 | return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file); |
| 155 | 161 | } |
| 156 | 162 | |
| ... | ... | @@ -162,14 +168,14 @@ const GetOrCreateZigGotEntryResult = struct { |
| 162 | 168 | pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult { |
| 163 | 169 | assert(!macho_file.base.isRelocatable()); |
| 164 | 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 | 172 | const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file); |
| 167 | 173 | return .{ .found_existing = false, .index = index }; |
| 168 | 174 | } |
| 169 | 175 | |
| 170 | 176 | pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 171 | 177 | if (!symbol.flags.has_zig_got) return 0; |
| 172 | const extras = symbol.getExtra(macho_file).?; | |
| 178 | const extras = symbol.getExtra(macho_file); | |
| 173 | 179 | return macho_file.zig_got.entryAddress(extras.zig_got, macho_file); |
| 174 | 180 | } |
| 175 | 181 | |
| ... | ... | @@ -202,11 +208,8 @@ const AddExtraOpts = struct { |
| 202 | 208 | symtab: ?u32 = null, |
| 203 | 209 | }; |
| 204 | 210 | |
| 205 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void { | |
| 206 | if (symbol.getExtra(macho_file) == null) { | |
| 207 | symbol.extra = try macho_file.addSymbolExtra(.{}); | |
| 208 | } | |
| 209 | var extra = symbol.getExtra(macho_file).?; | |
| 211 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) void { | |
| 212 | var extra = symbol.getExtra(macho_file); | |
| 210 | 213 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { |
| 211 | 214 | if (@field(opts, field.name)) |x| { |
| 212 | 215 | @field(extra, field.name) = x; |
| ... | ... | @@ -215,18 +218,22 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void { |
| 215 | 218 | symbol.setExtra(extra, macho_file); |
| 216 | 219 | } |
| 217 | 220 | |
| 218 | pub inline fn getExtra(symbol: Symbol, macho_file: *MachO) ?Extra { | |
| 219 | return macho_file.getSymbolExtra(symbol.extra); | |
| 221 | pub inline fn getExtra(symbol: Symbol, macho_file: *MachO) Extra { | |
| 222 | return switch (symbol.getFile(macho_file).?) { | |
| 223 | inline else => |x| x.getSymbolExtra(symbol.extra), | |
| 224 | }; | |
| 220 | 225 | } |
| 221 | 226 | |
| 222 | 227 | pub 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 | } |
| 225 | 232 | |
| 226 | 233 | pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) void { |
| 227 | 234 | if (symbol.isLocal()) { |
| 228 | 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 | 237 | out.n_desc = 0; |
| 231 | 238 | out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file); |
| 232 | 239 | |
| ... | ... | @@ -238,7 +245,7 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo |
| 238 | 245 | assert(symbol.visibility == .global); |
| 239 | 246 | out.n_type = macho.N_EXT; |
| 240 | 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 | 249 | out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file); |
| 243 | 250 | out.n_desc = 0; |
| 244 | 251 | |
| ... | ... | @@ -318,8 +325,8 @@ fn format2( |
| 318 | 325 | symbol.getAddress(.{}, ctx.macho_file), |
| 319 | 326 | }); |
| 320 | 327 | if (symbol.getFile(ctx.macho_file)) |file| { |
| 321 | if (symbol.out_n_sect != 0) { | |
| 322 | try writer.print(" : sect({d})", .{symbol.out_n_sect}); | |
| 328 | if (symbol.getOutputSectionIndex(ctx.macho_file) != 0) { | |
| 329 | try writer.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)}); | |
| 323 | 330 | } |
| 324 | 331 | if (symbol.getAtom(ctx.macho_file)) |atom| { |
| 325 | 332 | try writer.print(" : atom({d})", .{atom.atom_index}); |
| ... | ... | @@ -346,11 +353,6 @@ pub const Flags = packed struct { |
| 346 | 353 | /// Whether the symbol is exported at runtime. |
| 347 | 354 | @"export": bool = false, |
| 348 | 355 | |
| 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 | 356 | /// Whether this symbol is weak. |
| 355 | 357 | weak: bool = false, |
| 356 | 358 |