| author | |
| committer | |
| log | a7e4d1722616ba9fabfae8b830902e3651c645e4 |
| tree | 8e43482601ef089420de83484f2d43f33e5e2ced |
| parent | 3c5e840732053318f5e722d6cc16f65d51cdc297 |
6 files changed, 157 insertions(+), 41 deletions(-)
src/link/MachO.zig+47| ... | ... | @@ -65,6 +65,7 @@ entry_index: ?Symbol.Index = null, |
| 65 | 65 | |
| 66 | 66 | /// List of atoms that are either synthetic or map directly to the Zig source program. |
| 67 | 67 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 68 | atoms_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 68 | 69 | thunks: std.ArrayListUnmanaged(Thunk) = .{}, |
| 69 | 70 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{}, |
| 70 | 71 | |
| ... | ... | @@ -246,6 +247,7 @@ pub fn createEmpty( |
| 246 | 247 | try self.files.append(gpa, .null); |
| 247 | 248 | // Atom at index 0 is reserved as null atom |
| 248 | 249 | try self.atoms.append(gpa, .{}); |
| 250 | try self.atoms_extra.append(gpa, 0); | |
| 249 | 251 | // Append empty string to string tables |
| 250 | 252 | try self.strings.buffer.append(gpa, 0); |
| 251 | 253 | try self.strtab.append(gpa, 0); |
| ... | ... | @@ -350,6 +352,7 @@ pub fn deinit(self: *MachO) void { |
| 350 | 352 | self.unwind_info.deinit(gpa); |
| 351 | 353 | |
| 352 | 354 | self.atoms.deinit(gpa); |
| 355 | self.atoms_extra.deinit(gpa); | |
| 353 | 356 | for (self.thunks.items) |*thunk| { |
| 354 | 357 | thunk.deinit(gpa); |
| 355 | 358 | } |
| ... | ... | @@ -3865,6 +3868,50 @@ pub fn getAtom(self: *MachO, index: Atom.Index) ?*Atom { |
| 3865 | 3868 | return &self.atoms.items[index]; |
| 3866 | 3869 | } |
| 3867 | 3870 | |
| 3871 | pub fn addAtomExtra(self: *MachO, extra: Atom.Extra) !u32 { | |
| 3872 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 3873 | try self.atoms_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len); | |
| 3874 | return self.addAtomExtraAssumeCapacity(extra); | |
| 3875 | } | |
| 3876 | ||
| 3877 | pub fn addAtomExtraAssumeCapacity(self: *MachO, extra: Atom.Extra) u32 { | |
| 3878 | const index = @as(u32, @intCast(self.atoms_extra.items.len)); | |
| 3879 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 3880 | inline for (fields) |field| { | |
| 3881 | self.atoms_extra.appendAssumeCapacity(switch (field.type) { | |
| 3882 | u32 => @field(extra, field.name), | |
| 3883 | else => @compileError("bad field type"), | |
| 3884 | }); | |
| 3885 | } | |
| 3886 | return index; | |
| 3887 | } | |
| 3888 | ||
| 3889 | pub fn getAtomExtra(self: *MachO, index: u32) ?Atom.Extra { | |
| 3890 | if (index == 0) return null; | |
| 3891 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 3892 | var i: usize = index; | |
| 3893 | var result: Atom.Extra = undefined; | |
| 3894 | inline for (fields) |field| { | |
| 3895 | @field(result, field.name) = switch (field.type) { | |
| 3896 | u32 => self.atoms_extra.items[i], | |
| 3897 | else => @compileError("bad field type"), | |
| 3898 | }; | |
| 3899 | i += 1; | |
| 3900 | } | |
| 3901 | return result; | |
| 3902 | } | |
| 3903 | ||
| 3904 | pub fn setAtomExtra(self: *MachO, index: u32, extra: Atom.Extra) void { | |
| 3905 | assert(index > 0); | |
| 3906 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 3907 | inline for (fields, 0..) |field, i| { | |
| 3908 | self.atoms_extra.items[index + i] = switch (field.type) { | |
| 3909 | u32 => @field(extra, field.name), | |
| 3910 | else => @compileError("bad field type"), | |
| 3911 | }; | |
| 3912 | } | |
| 3913 | } | |
| 3914 | ||
| 3868 | 3915 | pub fn addSymbol(self: *MachO) !Symbol.Index { |
| 3869 | 3916 | const index = @as(Symbol.Index, @intCast(self.symbols.items.len)); |
| 3870 | 3917 | const symbol = try self.symbols.addOne(self.base.comp.gpa); |
src/link/MachO/Atom.zig+80-26| ... | ... | @@ -23,18 +23,9 @@ out_n_sect: u8 = 0, |
| 23 | 23 | /// off + size <= parent section size. |
| 24 | 24 | off: u64 = 0, |
| 25 | 25 | |
| 26 | /// Relocations of this atom. | |
| 27 | relocs: Loc = .{}, | |
| 28 | ||
| 29 | 26 | /// Index of this atom in the linker's atoms table. |
| 30 | 27 | atom_index: Index = 0, |
| 31 | 28 | |
| 32 | /// Index of the thunk for this atom. | |
| 33 | thunk_index: Thunk.Index = 0, | |
| 34 | ||
| 35 | /// Unwind records associated with this atom. | |
| 36 | unwind_records: Loc = .{}, | |
| 37 | ||
| 38 | 29 | flags: Flags = .{}, |
| 39 | 30 | |
| 40 | 31 | /// Points to the previous and next neighbors, based on the `text_offset`. |
| ... | ... | @@ -42,6 +33,8 @@ flags: Flags = .{}, |
| 42 | 33 | prev_index: Index = 0, |
| 43 | 34 | next_index: Index = 0, |
| 44 | 35 | |
| 36 | extra: u32 = 0, | |
| 37 | ||
| 45 | 38 | pub fn getName(self: Atom, macho_file: *MachO) [:0]const u8 { |
| 46 | 39 | return switch (self.getFile(macho_file)) { |
| 47 | 40 | .dylib => unreachable, |
| ... | ... | @@ -67,7 +60,7 @@ pub fn getData(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 67 | 60 | pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation { |
| 68 | 61 | return switch (self.getFile(macho_file)) { |
| 69 | 62 | .dylib => unreachable, |
| 70 | inline else => |x| x.getAtomRelocs(self), | |
| 63 | inline else => |x| x.getAtomRelocs(self, macho_file), | |
| 71 | 64 | }; |
| 72 | 65 | } |
| 73 | 66 | |
| ... | ... | @@ -95,10 +88,11 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 { |
| 95 | 88 | } |
| 96 | 89 | |
| 97 | 90 | 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).?; | |
| 98 | 93 | return switch (self.getFile(macho_file)) { |
| 99 | .dylib => unreachable, | |
| 100 | .zig_object, .internal => &[0]UnwindInfo.Record.Index{}, | |
| 101 | .object => |x| x.unwind_records.items[self.unwind_records.pos..][0..self.unwind_records.len], | |
| 94 | .dylib, .zig_object, .internal => unreachable, | |
| 95 | .object => |x| x.unwind_records.items[extra.unwind_index..][0..extra.unwind_count], | |
| 102 | 96 | }; |
| 103 | 97 | } |
| 104 | 98 | |
| ... | ... | @@ -114,7 +108,38 @@ pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { |
| 114 | 108 | } |
| 115 | 109 | |
| 116 | 110 | pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { |
| 117 | return macho_file.getThunk(self.thunk_index); | |
| 111 | assert(self.flags.thunk); | |
| 112 | const extra = self.getExtra(macho_file).?; | |
| 113 | return macho_file.getThunk(extra.thunk); | |
| 114 | } | |
| 115 | ||
| 116 | const AddExtraOpts = struct { | |
| 117 | thunk: ?u32 = null, | |
| 118 | rel_index: ?u32 = null, | |
| 119 | rel_count: ?u32 = null, | |
| 120 | unwind_index: ?u32 = null, | |
| 121 | unwind_count: ?u32 = null, | |
| 122 | }; | |
| 123 | ||
| 124 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) !void { | |
| 125 | if (atom.getExtra(macho_file) == null) { | |
| 126 | atom.extra = try macho_file.addAtomExtra(.{}); | |
| 127 | } | |
| 128 | var extra = atom.getExtra(macho_file).?; | |
| 129 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { | |
| 130 | if (@field(opts, field.name)) |x| { | |
| 131 | @field(extra, field.name) = x; | |
| 132 | } | |
| 133 | } | |
| 134 | atom.setExtra(extra, macho_file); | |
| 135 | } | |
| 136 | ||
| 137 | pub inline fn getExtra(atom: Atom, macho_file: *MachO) ?Extra { | |
| 138 | return macho_file.getAtomExtra(atom.extra); | |
| 139 | } | |
| 140 | ||
| 141 | pub inline fn setExtra(atom: Atom, extra: Extra, macho_file: *MachO) void { | |
| 142 | macho_file.setAtomExtra(atom.extra, extra); | |
| 118 | 143 | } |
| 119 | 144 | |
| 120 | 145 | pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| ... | ... | @@ -403,14 +428,20 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void { |
| 403 | 428 | const gpa = macho_file.base.comp.gpa; |
| 404 | 429 | const file = self.getFile(macho_file); |
| 405 | 430 | assert(file == .zig_object); |
| 406 | const rels = &file.zig_object.relocs.items[self.relocs.pos]; | |
| 431 | assert(self.flags.relocs); | |
| 432 | var extra = self.getExtra(macho_file).?; | |
| 433 | const rels = &file.zig_object.relocs.items[extra.rel_index]; | |
| 407 | 434 | try rels.append(gpa, reloc); |
| 408 | self.relocs.len += 1; | |
| 435 | extra.rel_count += 1; | |
| 436 | self.setExtra(extra, macho_file); | |
| 409 | 437 | } |
| 410 | 438 | |
| 411 | 439 | pub fn freeRelocs(self: *Atom, macho_file: *MachO) void { |
| 412 | self.getFile(macho_file).zig_object.freeAtomRelocs(self.*); | |
| 413 | self.relocs.len = 0; | |
| 440 | if (!self.flags.relocs) return; | |
| 441 | self.getFile(macho_file).zig_object.freeAtomRelocs(self.*, macho_file); | |
| 442 | var extra = self.getExtra(macho_file).?; | |
| 443 | extra.rel_count = 0; | |
| 444 | self.setExtra(extra, macho_file); | |
| 414 | 445 | } |
| 415 | 446 | |
| 416 | 447 | pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| ... | ... | @@ -1117,19 +1148,21 @@ fn format2( |
| 1117 | 1148 | _ = unused_fmt_string; |
| 1118 | 1149 | const atom = ctx.atom; |
| 1119 | 1150 | const macho_file = ctx.macho_file; |
| 1120 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{ | |
| 1151 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{ | |
| 1121 | 1152 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), |
| 1122 | 1153 | atom.out_n_sect, atom.alignment, atom.size, |
| 1123 | atom.getRelocs(macho_file).len, atom.thunk_index, | |
| 1154 | atom.getRelocs(macho_file).len, | |
| 1124 | 1155 | }); |
| 1156 | if (atom.flags.thunk) try writer.print(" : thunk({d})", .{atom.getExtra(macho_file).?.thunk}); | |
| 1125 | 1157 | if (!atom.flags.alive) try writer.writeAll(" : [*]"); |
| 1126 | if (atom.unwind_records.len > 0) { | |
| 1158 | if (atom.flags.unwind) { | |
| 1127 | 1159 | try writer.writeAll(" : unwind{ "); |
| 1128 | for (atom.getUnwindRecords(macho_file), atom.unwind_records.pos..) |index, i| { | |
| 1160 | const extra = atom.getExtra(macho_file).?; | |
| 1161 | for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| { | |
| 1129 | 1162 | const rec = macho_file.getUnwindRecord(index); |
| 1130 | 1163 | try writer.print("{d}", .{index}); |
| 1131 | 1164 | if (!rec.alive) try writer.writeAll("([*])"); |
| 1132 | if (i < atom.unwind_records.pos + atom.unwind_records.len - 1) try writer.writeAll(", "); | |
| 1165 | if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", "); | |
| 1133 | 1166 | } |
| 1134 | 1167 | try writer.writeAll(" }"); |
| 1135 | 1168 | } |
| ... | ... | @@ -1143,11 +1176,32 @@ pub const Flags = packed struct { |
| 1143 | 1176 | |
| 1144 | 1177 | /// Specifies if the atom has been visited during garbage collection. |
| 1145 | 1178 | visited: bool = false, |
| 1179 | ||
| 1180 | /// Whether this atom has a range extension thunk. | |
| 1181 | thunk: bool = false, | |
| 1182 | ||
| 1183 | /// Whether this atom has any relocations. | |
| 1184 | relocs: bool = false, | |
| 1185 | ||
| 1186 | /// Whether this atom has any unwind records. | |
| 1187 | unwind: bool = false, | |
| 1146 | 1188 | }; |
| 1147 | 1189 | |
| 1148 | pub const Loc = struct { | |
| 1149 | pos: u32 = 0, | |
| 1150 | len: u32 = 0, | |
| 1190 | pub const Extra = struct { | |
| 1191 | /// Index of the range extension thunk of this atom. | |
| 1192 | thunk: u32 = 0, | |
| 1193 | ||
| 1194 | /// Start index of relocations belonging to this atom. | |
| 1195 | rel_index: u32 = 0, | |
| 1196 | ||
| 1197 | /// Count of relocations belonging to this atom. | |
| 1198 | rel_count: u32 = 0, | |
| 1199 | ||
| 1200 | /// Start index of relocations belonging to this atom. | |
| 1201 | unwind_index: u32 = 0, | |
| 1202 | ||
| 1203 | /// Count of relocations belonging to this atom. | |
| 1204 | unwind_count: u32 = 0, | |
| 1151 | 1205 | }; |
| 1152 | 1206 | |
| 1153 | 1207 | pub const Alignment = @import("../../InternPool.zig").Alignment; |
src/link/MachO/InternalObject.zig+6-3| ... | ... | @@ -115,7 +115,8 @@ fn addObjcSelrefsSection( |
| 115 | 115 | .has_subtractor = false, |
| 116 | 116 | }, |
| 117 | 117 | }); |
| 118 | atom.relocs = .{ .pos = 0, .len = 1 }; | |
| 118 | try atom.addExtra(.{ .rel_index = 0, .rel_count = 1 }, macho_file); | |
| 119 | atom.flags.relocs = true; | |
| 119 | 120 | self.num_rebase_relocs += 1; |
| 120 | 121 | |
| 121 | 122 | return atom_index; |
| ... | ... | @@ -183,9 +184,11 @@ pub fn getAtomData(self: *const InternalObject, atom: Atom, buffer: []u8) !void |
| 183 | 184 | @memcpy(buffer, data[off..][0..size]); |
| 184 | 185 | } |
| 185 | 186 | |
| 186 | pub fn getAtomRelocs(self: *const InternalObject, atom: Atom) []const Relocation { | |
| 187 | pub fn getAtomRelocs(self: *const InternalObject, atom: Atom, macho_file: *MachO) []const Relocation { | |
| 188 | if (!atom.flags.relocs) return &[0]Relocation{}; | |
| 189 | const extra = atom.getExtra(macho_file).?; | |
| 187 | 190 | const relocs = self.sections.items(.relocs)[atom.n_sect]; |
| 188 | return relocs.items[atom.relocs.pos..][0..atom.relocs.len]; | |
| 191 | return relocs.items[extra.rel_index..][0..extra.rel_count]; | |
| 189 | 192 | } |
| 190 | 193 | |
| 191 | 194 | fn addString(self: *InternalObject, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 { |
src/link/MachO/Object.zig+10-5| ... | ... | @@ -690,11 +690,13 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { |
| 690 | 690 | if (!atom.flags.alive) continue; |
| 691 | 691 | if (next_reloc >= relocs.items.len) break; |
| 692 | 692 | const end_addr = atom.off + atom.size; |
| 693 | atom.relocs.pos = next_reloc; | |
| 693 | const rel_index = next_reloc; | |
| 694 | 694 | |
| 695 | 695 | while (next_reloc < relocs.items.len and relocs.items[next_reloc].offset < end_addr) : (next_reloc += 1) {} |
| 696 | 696 | |
| 697 | atom.relocs.len = next_reloc - atom.relocs.pos; | |
| 697 | const rel_count = next_reloc - rel_index; | |
| 698 | try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, macho_file); | |
| 699 | atom.flags.relocs = true; | |
| 698 | 700 | } |
| 699 | 701 | } |
| 700 | 702 | } |
| ... | ... | @@ -1004,7 +1006,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1004 | 1006 | {} |
| 1005 | 1007 | |
| 1006 | 1008 | const atom = rec.getAtom(macho_file); |
| 1007 | atom.unwind_records = .{ .pos = start, .len = next_cu - start }; | |
| 1009 | try atom.addExtra(.{ .unwind_index = start, .unwind_count = next_cu - start }, macho_file); | |
| 1010 | atom.flags.unwind = true; | |
| 1008 | 1011 | } |
| 1009 | 1012 | } |
| 1010 | 1013 | |
| ... | ... | @@ -1724,9 +1727,11 @@ pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer: |
| 1724 | 1727 | if (amt != buffer.len) return error.InputOutput; |
| 1725 | 1728 | } |
| 1726 | 1729 | |
| 1727 | pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation { | |
| 1730 | pub fn getAtomRelocs(self: *const Object, atom: Atom, macho_file: *MachO) []const Relocation { | |
| 1731 | if (!atom.flags.relocs) return &[0]Relocation{}; | |
| 1732 | const extra = atom.getExtra(macho_file).?; | |
| 1728 | 1733 | const relocs = self.sections.items(.relocs)[atom.n_sect]; |
| 1729 | return relocs.items[atom.relocs.pos..][0..atom.relocs.len]; | |
| 1734 | return relocs.items[extra.rel_index..][0..extra.rel_count]; | |
| 1730 | 1735 | } |
| 1731 | 1736 | |
| 1732 | 1737 | fn addString(self: *Object, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 { |
src/link/MachO/ZigObject.zig+12-6| ... | ... | @@ -163,7 +163,8 @@ pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index { |
| 163 | 163 | const relocs_index = @as(u32, @intCast(self.relocs.items.len)); |
| 164 | 164 | const relocs = try self.relocs.addOne(gpa); |
| 165 | 165 | relocs.* = .{}; |
| 166 | atom.relocs = .{ .pos = relocs_index, .len = 0 }; | |
| 166 | try atom.addExtra(.{ .rel_index = relocs_index, .rel_count = 0 }, macho_file); | |
| 167 | atom.flags.relocs = true; | |
| 167 | 168 | |
| 168 | 169 | return symbol_index; |
| 169 | 170 | } |
| ... | ... | @@ -190,13 +191,18 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 190 | 191 | } |
| 191 | 192 | } |
| 192 | 193 | |
| 193 | pub fn getAtomRelocs(self: *ZigObject, atom: Atom) []const Relocation { | |
| 194 | const relocs = self.relocs.items[atom.relocs.pos]; | |
| 195 | return relocs.items[0..atom.relocs.len]; | |
| 194 | pub fn getAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) []const Relocation { | |
| 195 | if (!atom.flags.relocs) return &[0]Relocation{}; | |
| 196 | const extra = atom.getExtra(macho_file).?; | |
| 197 | const relocs = self.relocs.items[extra.rel_index]; | |
| 198 | return relocs.items[0..extra.rel_count]; | |
| 196 | 199 | } |
| 197 | 200 | |
| 198 | pub fn freeAtomRelocs(self: *ZigObject, atom: Atom) void { | |
| 199 | self.relocs.items[atom.relocs.pos].clearRetainingCapacity(); | |
| 201 | pub fn freeAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) void { | |
| 202 | if (atom.flags.relocs) { | |
| 203 | const extra = atom.getExtra(macho_file).?; | |
| 204 | self.relocs.items[extra.rel_index].clearRetainingCapacity(); | |
| 205 | } | |
| 200 | 206 | } |
| 201 | 207 | |
| 202 | 208 | pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void { |
src/link/MachO/thunks.zig+2-1| ... | ... | @@ -43,7 +43,8 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void { |
| 43 | 43 | if (isReachable(atom, rel, macho_file)) continue; |
| 44 | 44 | try thunk.symbols.put(gpa, rel.target, {}); |
| 45 | 45 | } |
| 46 | atom.thunk_index = thunk_index; | |
| 46 | try atom.addExtra(.{ .thunk = thunk_index }, macho_file); | |
| 47 | atom.flags.thunk = true; | |
| 47 | 48 | } |
| 48 | 49 | |
| 49 | 50 | thunk.value = try advance(header, thunk.size(), .@"4"); |