authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-31 10:26:21+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-01 09:06:56+02:00
logc30cc4dbbfe3e1494160ffac18ce6a9f9a5e5224
tree7c152b08e974f3769180a7aee9838470288b0060
parent1f95c50d9a0c4c057780d387d57ac2ac40df1720

macho: don't store allocator in Object

instead, pass it in functions that require it. Also, when parsing relocs, make Object part of the context struct where we pass in additional goodies such as `*MachO` or `*Allocator`.

4 files changed, 215 insertions(+), 222 deletions(-)

src/link/MachO.zig+11-11
...@@ -2004,21 +2004,21 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2004,21 +2004,21 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2004 if (symbolIsStab(sym)) {2004 if (symbolIsStab(sym)) {
2005 log.err("unhandled symbol type: stab", .{});2005 log.err("unhandled symbol type: stab", .{});
2006 log.err(" symbol '{s}'", .{sym_name});2006 log.err(" symbol '{s}'", .{sym_name});
2007 log.err(" first definition in '{s}'", .{object.name.?});2007 log.err(" first definition in '{s}'", .{object.name});
2008 return error.UnhandledSymbolType;2008 return error.UnhandledSymbolType;
2009 }2009 }
20102010
2011 if (symbolIsIndr(sym)) {2011 if (symbolIsIndr(sym)) {
2012 log.err("unhandled symbol type: indirect", .{});2012 log.err("unhandled symbol type: indirect", .{});
2013 log.err(" symbol '{s}'", .{sym_name});2013 log.err(" symbol '{s}'", .{sym_name});
2014 log.err(" first definition in '{s}'", .{object.name.?});2014 log.err(" first definition in '{s}'", .{object.name});
2015 return error.UnhandledSymbolType;2015 return error.UnhandledSymbolType;
2016 }2016 }
20172017
2018 if (symbolIsAbs(sym)) {2018 if (symbolIsAbs(sym)) {
2019 log.err("unhandled symbol type: absolute", .{});2019 log.err("unhandled symbol type: absolute", .{});
2020 log.err(" symbol '{s}'", .{sym_name});2020 log.err(" symbol '{s}'", .{sym_name});
2021 log.err(" first definition in '{s}'", .{object.name.?});2021 log.err(" first definition in '{s}'", .{object.name});
2022 return error.UnhandledSymbolType;2022 return error.UnhandledSymbolType;
2023 }2023 }
20242024
...@@ -2068,8 +2068,8 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2068,8 +2068,8 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2068 !(symbolIsWeakDef(global.*) or symbolIsPext(global.*)))2068 !(symbolIsWeakDef(global.*) or symbolIsPext(global.*)))
2069 {2069 {
2070 log.err("symbol '{s}' defined multiple times", .{sym_name});2070 log.err("symbol '{s}' defined multiple times", .{sym_name});
2071 log.err(" first definition in '{s}'", .{self.objects.items[resolv.file].name.?});2071 log.err(" first definition in '{s}'", .{self.objects.items[resolv.file].name});
2072 log.err(" next definition in '{s}'", .{object.name.?});2072 log.err(" next definition in '{s}'", .{object.name});
2073 return error.MultipleSymbolDefinitions;2073 return error.MultipleSymbolDefinitions;
2074 }2074 }
20752075
...@@ -2448,7 +2448,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2448,7 +2448,7 @@ fn resolveSymbols(self: *MachO) !void {
2448 const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable;2448 const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable;
24492449
2450 log.err("undefined reference to symbol '{s}'", .{sym_name});2450 log.err("undefined reference to symbol '{s}'", .{sym_name});
2451 log.err(" first referenced in '{s}'", .{self.objects.items[resolv.file].name.?});2451 log.err(" first referenced in '{s}'", .{self.objects.items[resolv.file].name});
2452 has_undefined = true;2452 has_undefined = true;
2453 }2453 }
24542454
...@@ -2457,7 +2457,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2457,7 +2457,7 @@ fn resolveSymbols(self: *MachO) !void {
24572457
2458fn parseTextBlocks(self: *MachO) !void {2458fn parseTextBlocks(self: *MachO) !void {
2459 for (self.objects.items) |object| {2459 for (self.objects.items) |object| {
2460 try object.parseTextBlocks(self);2460 try object.parseTextBlocks(self.base.allocator, self);
2461 }2461 }
2462}2462}
24632463
...@@ -3190,7 +3190,7 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -3190,7 +3190,7 @@ fn writeSymbolTable(self: *MachO) !void {
3190 .n_value = 0,3190 .n_value = 0,
3191 });3191 });
3192 locals.appendAssumeCapacity(.{3192 locals.appendAssumeCapacity(.{
3193 .n_strx = try self.makeString(object.name.?),3193 .n_strx = try self.makeString(object.name),
3194 .n_type = macho.N_OSO,3194 .n_type = macho.N_OSO,
3195 .n_sect = 0,3195 .n_sect = 0,
3196 .n_desc = 1,3196 .n_desc = 1,
...@@ -3334,7 +3334,7 @@ pub fn deinit(self: *MachO) void {...@@ -3334,7 +3334,7 @@ pub fn deinit(self: *MachO) void {
3334 self.symbol_resolver.deinit(self.base.allocator);3334 self.symbol_resolver.deinit(self.base.allocator);
33353335
3336 for (self.objects.items) |object| {3336 for (self.objects.items) |object| {
3337 object.deinit();3337 object.deinit(self.base.allocator);
3338 self.base.allocator.destroy(object);3338 self.base.allocator.destroy(object);
3339 }3339 }
3340 self.objects.deinit(self.base.allocator);3340 self.objects.deinit(self.base.allocator);
...@@ -3372,7 +3372,7 @@ pub fn deinit(self: *MachO) void {...@@ -3372,7 +3372,7 @@ pub fn deinit(self: *MachO) void {
33723372
3373pub fn closeFiles(self: MachO) void {3373pub fn closeFiles(self: MachO) void {
3374 for (self.objects.items) |object| {3374 for (self.objects.items) |object| {
3375 object.closeFile();3375 object.file.close();
3376 }3376 }
3377 for (self.archives.items) |archive| {3377 for (self.archives.items) |archive| {
3378 archive.closeFile();3378 archive.closeFile();
...@@ -5913,7 +5913,7 @@ fn printSymtabAndTextBlock(self: *MachO) void {...@@ -5913,7 +5913,7 @@ fn printSymtabAndTextBlock(self: *MachO) void {
59135913
5914 log.debug("mappings", .{});5914 log.debug("mappings", .{});
5915 for (self.objects.items) |object| {5915 for (self.objects.items) |object| {
5916 log.debug(" in object {s}", .{object.name.?});5916 log.debug(" in object {s}", .{object.name});
5917 for (object.symtab.items) |sym, sym_id| {5917 for (object.symtab.items) |sym, sym_id| {
5918 if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| {5918 if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| {
5919 log.debug(" | {d} => {d}", .{ sym_id, local_id });5919 log.debug(" | {d} => {d}", .{ sym_id, local_id });
src/link/MachO/Archive.zig+1-3
...@@ -264,14 +264,12 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {...@@ -264,14 +264,12 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {
264 errdefer self.allocator.destroy(object);264 errdefer self.allocator.destroy(object);
265265
266 object.* = .{266 object.* = .{
267 .allocator = self.allocator,
268 .arch = self.arch.?,
269 .file = try fs.cwd().openFile(self.name.?, .{}),267 .file = try fs.cwd().openFile(self.name.?, .{}),
270 .name = name,268 .name = name,
271 .file_offset = @intCast(u32, try reader.context.getPos()),269 .file_offset = @intCast(u32, try reader.context.getPos()),
272 .mtime = try self.header.?.date(),270 .mtime = try self.header.?.date(),
273 };271 };
274 try object.parse();272 try object.parse(self.allocator, self.arch.?);
275 try reader.context.seekTo(0);273 try reader.context.seekTo(0);
276274
277 return object;275 return object;
src/link/MachO/Object.zig+138-140
...@@ -10,20 +10,22 @@ const macho = std.macho;...@@ -10,20 +10,22 @@ const macho = std.macho;
10const math = std.math;10const math = std.math;
11const mem = std.mem;11const mem = std.mem;
12const sort = std.sort;12const sort = std.sort;
13const commands = @import("commands.zig");
14const segmentName = commands.segmentName;
15const sectionName = commands.sectionName;
1316
14const Allocator = mem.Allocator;17const Allocator = mem.Allocator;
15const Arch = std.Target.Cpu.Arch;18const Arch = std.Target.Cpu.Arch;
19const LoadCommand = commands.LoadCommand;
16const MachO = @import("../MachO.zig");20const MachO = @import("../MachO.zig");
17const TextBlock = @import("TextBlock.zig");21const TextBlock = @import("TextBlock.zig");
1822
19usingnamespace @import("commands.zig");23file: fs.File,
24name: []const u8,
2025
21allocator: *Allocator,
22arch: ?Arch = null,
23header: ?macho.mach_header_64 = null,
24file: ?fs.File = null,
25file_offset: ?u32 = null,26file_offset: ?u32 = null,
26name: ?[]const u8 = null,27
28header: ?macho.mach_header_64 = null,
2729
28load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},30load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
2931
...@@ -139,15 +141,13 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u...@@ -139,15 +141,13 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u
139 errdefer allocator.free(name);141 errdefer allocator.free(name);
140142
141 object.* = .{143 object.* = .{
142 .allocator = allocator,
143 .arch = arch,
144 .name = name,144 .name = name,
145 .file = file,145 .file = file,
146 };146 };
147147
148 object.parse() catch |err| switch (err) {148 object.parse(allocator, arch) catch |err| switch (err) {
149 error.EndOfStream, error.NotObject => {149 error.EndOfStream, error.NotObject => {
150 object.deinit();150 object.deinit(allocator);
151 allocator.destroy(object);151 allocator.destroy(object);
152 return null;152 return null;
153 },153 },
...@@ -157,44 +157,35 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u...@@ -157,44 +157,35 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u
157 return object;157 return object;
158}158}
159159
160pub fn deinit(self: *Object) void {160pub fn deinit(self: *Object, allocator: *Allocator) void {
161 for (self.load_commands.items) |*lc| {161 for (self.load_commands.items) |*lc| {
162 lc.deinit(self.allocator);162 lc.deinit(allocator);
163 }163 }
164 self.load_commands.deinit(self.allocator);164 self.load_commands.deinit(allocator);
165 self.data_in_code_entries.deinit(self.allocator);165 self.data_in_code_entries.deinit(allocator);
166 self.symtab.deinit(self.allocator);166 self.symtab.deinit(allocator);
167 self.strtab.deinit(self.allocator);167 self.strtab.deinit(allocator);
168 self.text_blocks.deinit(self.allocator);168 self.text_blocks.deinit(allocator);
169 self.sections_as_symbols.deinit(self.allocator);169 self.sections_as_symbols.deinit(allocator);
170 self.symbol_mapping.deinit(self.allocator);170 self.symbol_mapping.deinit(allocator);
171 self.reverse_symbol_mapping.deinit(self.allocator);171 self.reverse_symbol_mapping.deinit(allocator);
172 allocator.free(self.name);
172173
173 if (self.debug_info) |*db| {174 if (self.debug_info) |*db| {
174 db.deinit(self.allocator);175 db.deinit(allocator);
175 }176 }
176177
177 if (self.tu_name) |n| {178 if (self.tu_name) |n| {
178 self.allocator.free(n);179 allocator.free(n);
179 }180 }
180181
181 if (self.tu_comp_dir) |n| {182 if (self.tu_comp_dir) |n| {
182 self.allocator.free(n);183 allocator.free(n);
183 }
184
185 if (self.name) |n| {
186 self.allocator.free(n);
187 }
188}
189
190pub fn closeFile(self: Object) void {
191 if (self.file) |f| {
192 f.close();
193 }184 }
194}185}
195186
196pub fn parse(self: *Object) !void {187pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
197 var reader = self.file.?.reader();188 var reader = self.file.reader();
198 if (self.file_offset) |offset| {189 if (self.file_offset) |offset| {
199 try reader.context.seekTo(offset);190 try reader.context.seekTo(offset);
200 }191 }
...@@ -214,26 +205,28 @@ pub fn parse(self: *Object) !void {...@@ -214,26 +205,28 @@ pub fn parse(self: *Object) !void {
214 return error.UnsupportedCpuArchitecture;205 return error.UnsupportedCpuArchitecture;
215 },206 },
216 };207 };
217 if (this_arch != self.arch.?) {208 if (this_arch != arch) {
218 log.err("mismatched cpu architecture: expected {s}, found {s}", .{ self.arch.?, this_arch });209 log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch });
219 return error.MismatchedCpuArchitecture;210 return error.MismatchedCpuArchitecture;
220 }211 }
221212
222 self.header = header;213 self.header = header;
223214
224 try self.readLoadCommands(reader);215 try self.readLoadCommands(allocator, reader);
225 try self.parseSymtab();216 try self.parseSymtab(allocator);
226 try self.parseDataInCode();217 try self.parseDataInCode(allocator);
227 try self.parseDebugInfo();218 try self.parseDebugInfo(allocator);
228}219}
229220
230pub fn readLoadCommands(self: *Object, reader: anytype) !void {221pub fn readLoadCommands(self: *Object, allocator: *Allocator, reader: anytype) !void {
222 const header = self.header orelse unreachable; // Unreachable here signifies a fatal unexplored condition.
231 const offset = self.file_offset orelse 0;223 const offset = self.file_offset orelse 0;
232 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);224
225 try self.load_commands.ensureCapacity(allocator, header.ncmds);
233226
234 var i: u16 = 0;227 var i: u16 = 0;
235 while (i < self.header.?.ncmds) : (i += 1) {228 while (i < header.ncmds) : (i += 1) {
236 var cmd = try LoadCommand.read(self.allocator, reader);229 var cmd = try LoadCommand.read(allocator, reader);
237 switch (cmd.cmd()) {230 switch (cmd.cmd()) {
238 macho.LC_SEGMENT_64 => {231 macho.LC_SEGMENT_64 => {
239 self.segment_cmd_index = i;232 self.segment_cmd_index = i;
...@@ -347,26 +340,25 @@ fn filterDice(dices: []macho.data_in_code_entry, start_addr: u64, end_addr: u64)...@@ -347,26 +340,25 @@ fn filterDice(dices: []macho.data_in_code_entry, start_addr: u64, end_addr: u64)
347 return dices[start..end];340 return dices[start..end];
348}341}
349342
350const TextBlockParser = struct {343const Context = struct {
351 allocator: *Allocator,344 allocator: *Allocator,
345 object: *Object,
346 macho_file: *MachO,
347 match: MachO.MatchingSection,
348};
349
350const TextBlockParser = struct {
352 section: macho.section_64,351 section: macho.section_64,
353 code: []u8,352 code: []u8,
354 relocs: []macho.relocation_info,353 relocs: []macho.relocation_info,
355 object: *Object,
356 macho_file: *MachO,
357 nlists: []NlistWithIndex,354 nlists: []NlistWithIndex,
358 index: u32 = 0,355 index: u32 = 0,
359 match: MachO.MatchingSection,
360356
361 fn peek(self: *TextBlockParser) ?NlistWithIndex {357 fn peek(self: TextBlockParser) ?NlistWithIndex {
362 return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null;358 return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null;
363 }359 }
364360
365 const SeniorityContext = struct {361 fn lessThanBySeniority(context: Context, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
366 object: *Object,
367 };
368
369 fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
370 if (!MachO.symbolIsExt(rhs.nlist)) {362 if (!MachO.symbolIsExt(rhs.nlist)) {
371 return MachO.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx));363 return MachO.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx));
372 } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) {364 } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) {
...@@ -376,10 +368,10 @@ const TextBlockParser = struct {...@@ -376,10 +368,10 @@ const TextBlockParser = struct {
376 }368 }
377 }369 }
378370
379 pub fn next(self: *TextBlockParser) !?*TextBlock {371 pub fn next(self: *TextBlockParser, context: Context) !?*TextBlock {
380 if (self.index == self.nlists.len) return null;372 if (self.index == self.nlists.len) return null;
381373
382 var aliases = std.ArrayList(NlistWithIndex).init(self.allocator);374 var aliases = std.ArrayList(NlistWithIndex).init(context.allocator);
383 defer aliases.deinit();375 defer aliases.deinit();
384376
385 const next_nlist: ?NlistWithIndex = blk: while (true) {377 const next_nlist: ?NlistWithIndex = blk: while (true) {
...@@ -397,7 +389,7 @@ const TextBlockParser = struct {...@@ -397,7 +389,7 @@ const TextBlockParser = struct {
397 } else null;389 } else null;
398390
399 for (aliases.items) |*nlist_with_index| {391 for (aliases.items) |*nlist_with_index| {
400 nlist_with_index.index = self.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable;392 nlist_with_index.index = context.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable;
401 }393 }
402394
403 if (aliases.items.len > 1) {395 if (aliases.items.len > 1) {
...@@ -405,14 +397,14 @@ const TextBlockParser = struct {...@@ -405,14 +397,14 @@ const TextBlockParser = struct {
405 sort.sort(397 sort.sort(
406 NlistWithIndex,398 NlistWithIndex,
407 aliases.items,399 aliases.items,
408 SeniorityContext{ .object = self.object },400 context,
409 TextBlockParser.lessThanBySeniority,401 TextBlockParser.lessThanBySeniority,
410 );402 );
411 }403 }
412404
413 const senior_nlist = aliases.pop();405 const senior_nlist = aliases.pop();
414 const senior_sym = &self.macho_file.locals.items[senior_nlist.index];406 const senior_sym = &context.macho_file.locals.items[senior_nlist.index];
415 senior_sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable;407 senior_sym.n_sect = context.macho_file.section_to_ordinal.get(context.match) orelse unreachable;
416408
417 const start_addr = senior_nlist.nlist.n_value - self.section.addr;409 const start_addr = senior_nlist.nlist.n_value - self.section.addr;
418 const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;410 const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;
...@@ -426,7 +418,7 @@ const TextBlockParser = struct {...@@ -426,7 +418,7 @@ const TextBlockParser = struct {
426 else418 else
427 max_align;419 max_align;
428420
429 const stab: ?TextBlock.Stab = if (self.object.debug_info) |di| blk: {421 const stab: ?TextBlock.Stab = if (context.object.debug_info) |di| blk: {
430 // TODO there has to be a better to handle this.422 // TODO there has to be a better to handle this.
431 for (di.inner.func_list.items) |func| {423 for (di.inner.func_list.items) |func| {
432 if (func.pc_range) |range| {424 if (func.pc_range) |range| {
...@@ -442,35 +434,37 @@ const TextBlockParser = struct {...@@ -442,35 +434,37 @@ const TextBlockParser = struct {
442 break :blk .static;434 break :blk .static;
443 } else null;435 } else null;
444436
445 const block = try self.macho_file.base.allocator.create(TextBlock);437 const block = try context.allocator.create(TextBlock);
446 block.* = TextBlock.empty;438 block.* = TextBlock.empty;
447 block.local_sym_index = senior_nlist.index;439 block.local_sym_index = senior_nlist.index;
448 block.stab = stab;440 block.stab = stab;
449 block.size = size;441 block.size = size;
450 block.alignment = actual_align;442 block.alignment = actual_align;
451 try self.macho_file.managed_blocks.append(self.macho_file.base.allocator, block);443 try context.macho_file.managed_blocks.append(context.allocator, block);
452444
453 try block.code.appendSlice(self.macho_file.base.allocator, code);445 try block.code.appendSlice(context.allocator, code);
454446
455 try block.aliases.ensureTotalCapacity(self.macho_file.base.allocator, aliases.items.len);447 try block.aliases.ensureTotalCapacity(context.allocator, aliases.items.len);
456 for (aliases.items) |alias| {448 for (aliases.items) |alias| {
457 block.aliases.appendAssumeCapacity(alias.index);449 block.aliases.appendAssumeCapacity(alias.index);
458 const sym = &self.macho_file.locals.items[alias.index];450 const sym = &context.macho_file.locals.items[alias.index];
459 sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable;451 sym.n_sect = context.macho_file.section_to_ordinal.get(context.match) orelse unreachable;
460 }452 }
461453
462 try block.parseRelocsFromObject(self.macho_file.base.allocator, self.relocs, self.object, .{454 try block.parseRelocs(self.relocs, .{
463 .base_addr = start_addr,455 .base_addr = start_addr,
464 .macho_file = self.macho_file,456 .allocator = context.allocator,
457 .object = context.object,
458 .macho_file = context.macho_file,
465 });459 });
466460
467 if (self.macho_file.has_dices) {461 if (context.macho_file.has_dices) {
468 const dices = filterDice(462 const dices = filterDice(
469 self.object.data_in_code_entries.items,463 context.object.data_in_code_entries.items,
470 senior_nlist.nlist.n_value,464 senior_nlist.nlist.n_value,
471 senior_nlist.nlist.n_value + size,465 senior_nlist.nlist.n_value + size,
472 );466 );
473 try block.dices.ensureTotalCapacity(self.macho_file.base.allocator, dices.len);467 try block.dices.ensureTotalCapacity(context.allocator, dices.len);
474468
475 for (dices) |dice| {469 for (dices) |dice| {
476 block.dices.appendAssumeCapacity(.{470 block.dices.appendAssumeCapacity(.{
...@@ -487,16 +481,16 @@ const TextBlockParser = struct {...@@ -487,16 +481,16 @@ const TextBlockParser = struct {
487 }481 }
488};482};
489483
490pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {484pub fn parseTextBlocks(self: *Object, allocator: *Allocator, macho_file: *MachO) !void {
491 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;485 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
492486
493 log.debug("analysing {s}", .{self.name.?});487 log.debug("analysing {s}", .{self.name});
494488
495 // You would expect that the symbol table is at least pre-sorted based on symbol's type:489 // You would expect that the symbol table is at least pre-sorted based on symbol's type:
496 // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance,490 // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance,
497 // the GO compiler does not necessarily respect that therefore we sort immediately by type491 // the GO compiler does not necessarily respect that therefore we sort immediately by type
498 // and address within.492 // and address within.
499 var sorted_all_nlists = std.ArrayList(NlistWithIndex).init(self.allocator);493 var sorted_all_nlists = std.ArrayList(NlistWithIndex).init(allocator);
500 defer sorted_all_nlists.deinit();494 defer sorted_all_nlists.deinit();
501 try sorted_all_nlists.ensureTotalCapacity(self.symtab.items.len);495 try sorted_all_nlists.ensureTotalCapacity(self.symtab.items.len);
502496
...@@ -540,14 +534,14 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -540,14 +534,14 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
540 };534 };
541535
542 // Read section's code536 // Read section's code
543 var code = try self.allocator.alloc(u8, @intCast(usize, sect.size));537 var code = try allocator.alloc(u8, @intCast(usize, sect.size));
544 defer self.allocator.free(code);538 defer allocator.free(code);
545 _ = try self.file.?.preadAll(code, sect.offset);539 _ = try self.file.preadAll(code, sect.offset);
546540
547 // Read section's list of relocations541 // Read section's list of relocations
548 var raw_relocs = try self.allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));542 var raw_relocs = try allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
549 defer self.allocator.free(raw_relocs);543 defer allocator.free(raw_relocs);
550 _ = try self.file.?.preadAll(raw_relocs, sect.reloff);544 _ = try self.file.preadAll(raw_relocs, sect.reloff);
551 const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs);545 const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs);
552546
553 // Symbols within this section only.547 // Symbols within this section only.
...@@ -579,46 +573,48 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -579,46 +573,48 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
579 // as a temporary symbol and insert the matching TextBlock.573 // as a temporary symbol and insert the matching TextBlock.
580 const first_nlist = filtered_nlists[0].nlist;574 const first_nlist = filtered_nlists[0].nlist;
581 if (first_nlist.n_value > sect.addr) {575 if (first_nlist.n_value > sect.addr) {
582 const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{576 const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{
583 self.name.?,577 self.name,
584 segmentName(sect),578 segmentName(sect),
585 sectionName(sect),579 sectionName(sect),
586 });580 });
587 defer self.allocator.free(sym_name);581 defer allocator.free(sym_name);
588582
589 const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {583 const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {
590 const block_local_sym_index = @intCast(u32, macho_file.locals.items.len);584 const block_local_sym_index = @intCast(u32, macho_file.locals.items.len);
591 try macho_file.locals.append(macho_file.base.allocator, .{585 try macho_file.locals.append(allocator, .{
592 .n_strx = try macho_file.makeString(sym_name),586 .n_strx = try macho_file.makeString(sym_name),
593 .n_type = macho.N_SECT,587 .n_type = macho.N_SECT,
594 .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable,588 .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable,
595 .n_desc = 0,589 .n_desc = 0,
596 .n_value = sect.addr,590 .n_value = sect.addr,
597 });591 });
598 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, block_local_sym_index);592 try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index);
599 break :blk block_local_sym_index;593 break :blk block_local_sym_index;
600 };594 };
601595
602 const block_code = code[0 .. first_nlist.n_value - sect.addr];596 const block_code = code[0 .. first_nlist.n_value - sect.addr];
603 const block_size = block_code.len;597 const block_size = block_code.len;
604598
605 const block = try macho_file.base.allocator.create(TextBlock);599 const block = try allocator.create(TextBlock);
606 block.* = TextBlock.empty;600 block.* = TextBlock.empty;
607 block.local_sym_index = block_local_sym_index;601 block.local_sym_index = block_local_sym_index;
608 block.size = block_size;602 block.size = block_size;
609 block.alignment = sect.@"align";603 block.alignment = sect.@"align";
610 try macho_file.managed_blocks.append(macho_file.base.allocator, block);604 try macho_file.managed_blocks.append(allocator, block);
611605
612 try block.code.appendSlice(macho_file.base.allocator, block_code);606 try block.code.appendSlice(allocator, block_code);
613607
614 try block.parseRelocsFromObject(self.allocator, relocs, self, .{608 try block.parseRelocs(relocs, .{
615 .base_addr = 0,609 .base_addr = 0,
610 .allocator = allocator,
611 .object = self,
616 .macho_file = macho_file,612 .macho_file = macho_file,
617 });613 });
618614
619 if (macho_file.has_dices) {615 if (macho_file.has_dices) {
620 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);616 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
621 try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len);617 try block.dices.ensureTotalCapacity(allocator, dices.len);
622618
623 for (dices) |dice| {619 for (dices) |dice| {
624 block.dices.appendAssumeCapacity(.{620 block.dices.appendAssumeCapacity(.{
...@@ -645,24 +641,25 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -645,24 +641,25 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
645 block.prev = last.*;641 block.prev = last.*;
646 last.* = block;642 last.* = block;
647 } else {643 } else {
648 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);644 try macho_file.blocks.putNoClobber(allocator, match, block);
649 }645 }
650646
651 try self.text_blocks.append(self.allocator, block);647 try self.text_blocks.append(allocator, block);
652 }648 }
653649
654 var parser = TextBlockParser{650 var parser = TextBlockParser{
655 .allocator = self.allocator,
656 .section = sect,651 .section = sect,
657 .code = code,652 .code = code,
658 .relocs = relocs,653 .relocs = relocs,
659 .object = self,
660 .macho_file = macho_file,
661 .nlists = filtered_nlists,654 .nlists = filtered_nlists,
662 .match = match,
663 };655 };
664656
665 while (try parser.next()) |block| {657 while (try parser.next(.{
658 .allocator = allocator,
659 .object = self,
660 .macho_file = macho_file,
661 .match = match,
662 })) |block| {
666 const sym = macho_file.locals.items[block.local_sym_index];663 const sym = macho_file.locals.items[block.local_sym_index];
667 const is_ext = blk: {664 const is_ext = blk: {
668 const orig_sym_id = self.reverse_symbol_mapping.get(block.local_sym_index) orelse unreachable;665 const orig_sym_id = self.reverse_symbol_mapping.get(block.local_sym_index) orelse unreachable;
...@@ -675,9 +672,9 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -675,9 +672,9 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
675 if (global_object != self) {672 if (global_object != self) {
676 log.debug("deduping definition of {s} in {s}", .{673 log.debug("deduping definition of {s} in {s}", .{
677 macho_file.getString(sym.n_strx),674 macho_file.getString(sym.n_strx),
678 self.name.?,675 self.name,
679 });676 });
680 log.debug(" already defined in {s}", .{global_object.name.?});677 log.debug(" already defined in {s}", .{global_object.name});
681 continue;678 continue;
682 }679 }
683 }680 }
...@@ -688,7 +685,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -688,7 +685,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
688 // In x86_64 relocs, it can so happen that the compiler refers to the same685 // In x86_64 relocs, it can so happen that the compiler refers to the same
689 // atom by both the actual assigned symbol and the start of the section. In this686 // atom by both the actual assigned symbol and the start of the section. In this
690 // case, we need to link the two together so add an alias.687 // case, we need to link the two together so add an alias.
691 try block.aliases.append(macho_file.base.allocator, alias);688 try block.aliases.append(allocator, alias);
692 }689 }
693 }690 }
694691
...@@ -708,10 +705,10 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -708,10 +705,10 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
708 block.prev = last.*;705 block.prev = last.*;
709 last.* = block;706 last.* = block;
710 } else {707 } else {
711 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);708 try macho_file.blocks.putNoClobber(allocator, match, block);
712 }709 }
713710
714 try self.text_blocks.append(self.allocator, block);711 try self.text_blocks.append(allocator, block);
715 }712 }
716713
717 break :next;714 break :next;
...@@ -720,43 +717,45 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -720,43 +717,45 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
720 // Since there is no symbol to refer to this block, we create717 // Since there is no symbol to refer to this block, we create
721 // a temp one, unless we already did that when working out the relocations718 // a temp one, unless we already did that when working out the relocations
722 // of other text blocks.719 // of other text blocks.
723 const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{720 const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{
724 self.name.?,721 self.name,
725 segmentName(sect),722 segmentName(sect),
726 sectionName(sect),723 sectionName(sect),
727 });724 });
728 defer self.allocator.free(sym_name);725 defer allocator.free(sym_name);
729726
730 const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {727 const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {
731 const block_local_sym_index = @intCast(u32, macho_file.locals.items.len);728 const block_local_sym_index = @intCast(u32, macho_file.locals.items.len);
732 try macho_file.locals.append(macho_file.base.allocator, .{729 try macho_file.locals.append(allocator, .{
733 .n_strx = try macho_file.makeString(sym_name),730 .n_strx = try macho_file.makeString(sym_name),
734 .n_type = macho.N_SECT,731 .n_type = macho.N_SECT,
735 .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable,732 .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable,
736 .n_desc = 0,733 .n_desc = 0,
737 .n_value = sect.addr,734 .n_value = sect.addr,
738 });735 });
739 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, block_local_sym_index);736 try self.sections_as_symbols.putNoClobber(allocator, sect_id, block_local_sym_index);
740 break :blk block_local_sym_index;737 break :blk block_local_sym_index;
741 };738 };
742739
743 const block = try macho_file.base.allocator.create(TextBlock);740 const block = try allocator.create(TextBlock);
744 block.* = TextBlock.empty;741 block.* = TextBlock.empty;
745 block.local_sym_index = block_local_sym_index;742 block.local_sym_index = block_local_sym_index;
746 block.size = sect.size;743 block.size = sect.size;
747 block.alignment = sect.@"align";744 block.alignment = sect.@"align";
748 try macho_file.managed_blocks.append(macho_file.base.allocator, block);745 try macho_file.managed_blocks.append(allocator, block);
749746
750 try block.code.appendSlice(macho_file.base.allocator, code);747 try block.code.appendSlice(allocator, code);
751748
752 try block.parseRelocsFromObject(self.allocator, relocs, self, .{749 try block.parseRelocs(relocs, .{
753 .base_addr = 0,750 .base_addr = 0,
751 .allocator = allocator,
752 .object = self,
754 .macho_file = macho_file,753 .macho_file = macho_file,
755 });754 });
756755
757 if (macho_file.has_dices) {756 if (macho_file.has_dices) {
758 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size);757 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size);
759 try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len);758 try block.dices.ensureTotalCapacity(allocator, dices.len);
760759
761 for (dices) |dice| {760 for (dices) |dice| {
762 block.dices.appendAssumeCapacity(.{761 block.dices.appendAssumeCapacity(.{
...@@ -772,7 +771,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -772,7 +771,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
772 // the filtered symbols and note which symbol is contained within so that771 // the filtered symbols and note which symbol is contained within so that
773 // we can properly allocate addresses down the line.772 // we can properly allocate addresses down the line.
774 // While we're at it, we need to update segment,section mapping of each symbol too.773 // While we're at it, we need to update segment,section mapping of each symbol too.
775 try block.contained.ensureTotalCapacity(self.allocator, filtered_nlists.len);774 try block.contained.ensureTotalCapacity(allocator, filtered_nlists.len);
776775
777 for (filtered_nlists) |nlist_with_index| {776 for (filtered_nlists) |nlist_with_index| {
778 const nlist = nlist_with_index.nlist;777 const nlist = nlist_with_index.nlist;
...@@ -819,35 +818,35 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -819,35 +818,35 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
819 block.prev = last.*;818 block.prev = last.*;
820 last.* = block;819 last.* = block;
821 } else {820 } else {
822 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);821 try macho_file.blocks.putNoClobber(allocator, match, block);
823 }822 }
824823
825 try self.text_blocks.append(self.allocator, block);824 try self.text_blocks.append(allocator, block);
826 }825 }
827 }826 }
828}827}
829828
830fn parseSymtab(self: *Object) !void {829fn parseSymtab(self: *Object, allocator: *Allocator) !void {
831 const index = self.symtab_cmd_index orelse return;830 const index = self.symtab_cmd_index orelse return;
832 const symtab_cmd = self.load_commands.items[index].Symtab;831 const symtab_cmd = self.load_commands.items[index].Symtab;
833832
834 var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);833 var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
835 defer self.allocator.free(symtab);834 defer allocator.free(symtab);
836 _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff);835 _ = try self.file.preadAll(symtab, symtab_cmd.symoff);
837 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));836 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));
838 try self.symtab.appendSlice(self.allocator, slice);837 try self.symtab.appendSlice(allocator, slice);
839838
840 var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize);839 var strtab = try allocator.alloc(u8, symtab_cmd.strsize);
841 defer self.allocator.free(strtab);840 defer allocator.free(strtab);
842 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);841 _ = try self.file.preadAll(strtab, symtab_cmd.stroff);
843 try self.strtab.appendSlice(self.allocator, strtab);842 try self.strtab.appendSlice(allocator, strtab);
844}843}
845844
846pub fn parseDebugInfo(self: *Object) !void {845pub fn parseDebugInfo(self: *Object, allocator: *Allocator) !void {
847 log.debug("parsing debug info in '{s}'", .{self.name.?});846 log.debug("parsing debug info in '{s}'", .{self.name});
848847
849 var debug_info = blk: {848 var debug_info = blk: {
850 var di = try DebugInfo.parseFromObject(self.allocator, self);849 var di = try DebugInfo.parseFromObject(allocator, self);
851 break :blk di orelse return;850 break :blk di orelse return;
852 };851 };
853852
...@@ -855,7 +854,7 @@ pub fn parseDebugInfo(self: *Object) !void {...@@ -855,7 +854,7 @@ pub fn parseDebugInfo(self: *Object) !void {
855 const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) {854 const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) {
856 error.MissingDebugInfo => {855 error.MissingDebugInfo => {
857 // TODO audit cases with missing debug info and audit our dwarf.zig module.856 // TODO audit cases with missing debug info and audit our dwarf.zig module.
858 log.debug("invalid or missing debug info in {s}; skipping", .{self.name.?});857 log.debug("invalid or missing debug info in {s}; skipping", .{self.name});
859 return;858 return;
860 },859 },
861 else => |e| return e,860 else => |e| return e,
...@@ -864,26 +863,25 @@ pub fn parseDebugInfo(self: *Object) !void {...@@ -864,26 +863,25 @@ pub fn parseDebugInfo(self: *Object) !void {
864 const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir);863 const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir);
865864
866 self.debug_info = debug_info;865 self.debug_info = debug_info;
867 self.tu_name = try self.allocator.dupe(u8, name);866 self.tu_name = try allocator.dupe(u8, name);
868 self.tu_comp_dir = try self.allocator.dupe(u8, comp_dir);867 self.tu_comp_dir = try allocator.dupe(u8, comp_dir);
869868
870 if (self.mtime == null) {869 if (self.mtime == null) {
871 self.mtime = mtime: {870 self.mtime = mtime: {
872 const file = self.file orelse break :mtime 0;871 const stat = self.file.stat() catch break :mtime 0;
873 const stat = file.stat() catch break :mtime 0;
874 break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));872 break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
875 };873 };
876 }874 }
877}875}
878876
879pub fn parseDataInCode(self: *Object) !void {877pub fn parseDataInCode(self: *Object, allocator: *Allocator) !void {
880 const index = self.data_in_code_cmd_index orelse return;878 const index = self.data_in_code_cmd_index orelse return;
881 const data_in_code = self.load_commands.items[index].LinkeditData;879 const data_in_code = self.load_commands.items[index].LinkeditData;
882880
883 var buffer = try self.allocator.alloc(u8, data_in_code.datasize);881 var buffer = try allocator.alloc(u8, data_in_code.datasize);
884 defer self.allocator.free(buffer);882 defer allocator.free(buffer);
885883
886 _ = try self.file.?.preadAll(buffer, data_in_code.dataoff);884 _ = try self.file.preadAll(buffer, data_in_code.dataoff);
887885
888 var stream = io.fixedBufferStream(buffer);886 var stream = io.fixedBufferStream(buffer);
889 var reader = stream.reader();887 var reader = stream.reader();
...@@ -892,7 +890,7 @@ pub fn parseDataInCode(self: *Object) !void {...@@ -892,7 +890,7 @@ pub fn parseDataInCode(self: *Object) !void {
892 error.EndOfStream => break,890 error.EndOfStream => break,
893 else => |e| return e,891 else => |e| return e,
894 };892 };
895 try self.data_in_code_entries.append(self.allocator, dice);893 try self.data_in_code_entries.append(allocator, dice);
896 }894 }
897}895}
898896
...@@ -900,7 +898,7 @@ fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {...@@ -900,7 +898,7 @@ fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
900 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;898 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
901 const sect = seg.sections.items[index];899 const sect = seg.sections.items[index];
902 var buffer = try allocator.alloc(u8, @intCast(usize, sect.size));900 var buffer = try allocator.alloc(u8, @intCast(usize, sect.size));
903 _ = try self.file.?.preadAll(buffer, sect.offset);901 _ = try self.file.preadAll(buffer, sect.offset);
904 return buffer;902 return buffer;
905}903}
906904
src/link/MachO/TextBlock.zig+65-68
...@@ -606,12 +606,14 @@ pub fn freeListEligible(self: TextBlock, macho_file: MachO) bool {...@@ -606,12 +606,14 @@ pub fn freeListEligible(self: TextBlock, macho_file: MachO) bool {
606606
607const RelocContext = struct {607const RelocContext = struct {
608 base_addr: u64 = 0,608 base_addr: u64 = 0,
609 allocator: *Allocator,
610 object: *Object,
609 macho_file: *MachO,611 macho_file: *MachO,
610};612};
611613
612fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocContext) !Relocation {614fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Relocation {
613 var parsed_rel = Relocation{615 var parsed_rel = Relocation{
614 .offset = @intCast(u32, @intCast(u64, rel.r_address) - ctx.base_addr),616 .offset = @intCast(u32, @intCast(u64, rel.r_address) - context.base_addr),
615 .where = undefined,617 .where = undefined,
616 .where_index = undefined,618 .where_index = undefined,
617 .payload = undefined,619 .payload = undefined,
...@@ -620,44 +622,44 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo...@@ -620,44 +622,44 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo
620 if (rel.r_extern == 0) {622 if (rel.r_extern == 0) {
621 const sect_id = @intCast(u16, rel.r_symbolnum - 1);623 const sect_id = @intCast(u16, rel.r_symbolnum - 1);
622624
623 const local_sym_index = object.sections_as_symbols.get(sect_id) orelse blk: {625 const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: {
624 const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;626 const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment;
625 const sect = seg.sections.items[sect_id];627 const sect = seg.sections.items[sect_id];
626 const match = (try ctx.macho_file.getMatchingSection(sect)) orelse unreachable;628 const match = (try context.macho_file.getMatchingSection(sect)) orelse unreachable;
627 const local_sym_index = @intCast(u32, ctx.macho_file.locals.items.len);629 const local_sym_index = @intCast(u32, context.macho_file.locals.items.len);
628 const sym_name = try std.fmt.allocPrint(ctx.macho_file.base.allocator, "l_{s}_{s}_{s}", .{630 const sym_name = try std.fmt.allocPrint(context.allocator, "l_{s}_{s}_{s}", .{
629 object.name.?,631 context.object.name,
630 commands.segmentName(sect),632 commands.segmentName(sect),
631 commands.sectionName(sect),633 commands.sectionName(sect),
632 });634 });
633 defer ctx.macho_file.base.allocator.free(sym_name);635 defer context.allocator.free(sym_name);
634636
635 try ctx.macho_file.locals.append(ctx.macho_file.base.allocator, .{637 try context.macho_file.locals.append(context.allocator, .{
636 .n_strx = try ctx.macho_file.makeString(sym_name),638 .n_strx = try context.macho_file.makeString(sym_name),
637 .n_type = macho.N_SECT,639 .n_type = macho.N_SECT,
638 .n_sect = ctx.macho_file.section_to_ordinal.get(match) orelse unreachable,640 .n_sect = context.macho_file.section_to_ordinal.get(match) orelse unreachable,
639 .n_desc = 0,641 .n_desc = 0,
640 .n_value = sect.addr,642 .n_value = sect.addr,
641 });643 });
642 try object.sections_as_symbols.putNoClobber(object.allocator, sect_id, local_sym_index);644 try context.object.sections_as_symbols.putNoClobber(context.allocator, sect_id, local_sym_index);
643 break :blk local_sym_index;645 break :blk local_sym_index;
644 };646 };
645647
646 parsed_rel.where = .local;648 parsed_rel.where = .local;
647 parsed_rel.where_index = local_sym_index;649 parsed_rel.where_index = local_sym_index;
648 } else {650 } else {
649 const sym = object.symtab.items[rel.r_symbolnum];651 const sym = context.object.symtab.items[rel.r_symbolnum];
650 const sym_name = object.getString(sym.n_strx);652 const sym_name = context.object.getString(sym.n_strx);
651653
652 if (MachO.symbolIsSect(sym) and !MachO.symbolIsExt(sym)) {654 if (MachO.symbolIsSect(sym) and !MachO.symbolIsExt(sym)) {
653 const where_index = object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;655 const where_index = context.object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;
654 parsed_rel.where = .local;656 parsed_rel.where = .local;
655 parsed_rel.where_index = where_index;657 parsed_rel.where_index = where_index;
656 } else {658 } else {
657 const n_strx = ctx.macho_file.strtab_dir.getAdapted(@as([]const u8, sym_name), MachO.StringSliceAdapter{659 const n_strx = context.macho_file.strtab_dir.getAdapted(@as([]const u8, sym_name), MachO.StringSliceAdapter{
658 .strtab = &ctx.macho_file.strtab,660 .strtab = &context.macho_file.strtab,
659 }) orelse unreachable;661 }) orelse unreachable;
660 const resolv = ctx.macho_file.symbol_resolver.get(n_strx) orelse unreachable;662 const resolv = context.macho_file.symbol_resolver.get(n_strx) orelse unreachable;
661 switch (resolv.where) {663 switch (resolv.where) {
662 .global => {664 .global => {
663 parsed_rel.where = .local;665 parsed_rel.where = .local;
...@@ -675,29 +677,24 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo...@@ -675,29 +677,24 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo
675 return parsed_rel;677 return parsed_rel;
676}678}
677679
678pub fn parseRelocsFromObject(680pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: RelocContext) !void {
679 self: *TextBlock,681 const filtered_relocs = filterRelocs(relocs, context.base_addr, context.base_addr + self.size);
680 allocator: *Allocator,
681 relocs: []macho.relocation_info,
682 object: *Object,
683 ctx: RelocContext,
684) !void {
685 const filtered_relocs = filterRelocs(relocs, ctx.base_addr, ctx.base_addr + self.size);
686 var it = RelocIterator{682 var it = RelocIterator{
687 .buffer = filtered_relocs,683 .buffer = filtered_relocs,
688 };684 };
689685
690 var addend: u32 = 0;686 var addend: u32 = 0;
691 var subtractor: ?u32 = null;687 var subtractor: ?u32 = null;
688 const arch = context.macho_file.base.options.target.cpu.arch;
692689
693 while (it.next()) |rel| {690 while (it.next()) |rel| {
694 if (isAddend(rel, object.arch.?)) {691 if (isAddend(rel, arch)) {
695 // Addend is not a relocation with effect on the TextBlock, so692 // Addend is not a relocation with effect on the TextBlock, so
696 // parse it and carry on.693 // parse it and carry on.
697 assert(addend == 0); // Oh no, addend was not reset!694 assert(addend == 0); // Oh no, addend was not reset!
698 addend = rel.r_symbolnum;695 addend = rel.r_symbolnum;
699696
700 // Verify ADDEND is followed by a load.697 // Verify ADDEND is followed by a PAGE21 or PAGEOFF12.
701 const next = @intToEnum(macho.reloc_type_arm64, it.peek().r_type);698 const next = @intToEnum(macho.reloc_type_arm64, it.peek().r_type);
702 switch (next) {699 switch (next) {
703 .ARM64_RELOC_PAGE21, .ARM64_RELOC_PAGEOFF12 => {},700 .ARM64_RELOC_PAGE21, .ARM64_RELOC_PAGEOFF12 => {},
...@@ -709,28 +706,28 @@ pub fn parseRelocsFromObject(...@@ -709,28 +706,28 @@ pub fn parseRelocsFromObject(
709 continue;706 continue;
710 }707 }
711708
712 if (isSubtractor(rel, object.arch.?)) {709 if (isSubtractor(rel, arch)) {
713 // Subtractor is not a relocation with effect on the TextBlock, so710 // Subtractor is not a relocation with effect on the TextBlock, so
714 // parse it and carry on.711 // parse it and carry on.
715 assert(subtractor == null); // Oh no, subtractor was not reset!712 assert(subtractor == null); // Oh no, subtractor was not reset!
716 assert(rel.r_extern == 1);713 assert(rel.r_extern == 1);
717 const sym = object.symtab.items[rel.r_symbolnum];714 const sym = context.object.symtab.items[rel.r_symbolnum];
718 const sym_name = object.getString(sym.n_strx);715 const sym_name = context.object.getString(sym.n_strx);
719716
720 if (MachO.symbolIsSect(sym) and !MachO.symbolIsExt(sym)) {717 if (MachO.symbolIsSect(sym) and !MachO.symbolIsExt(sym)) {
721 const where_index = object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;718 const where_index = context.object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;
722 subtractor = where_index;719 subtractor = where_index;
723 } else {720 } else {
724 const n_strx = ctx.macho_file.strtab_dir.getAdapted(@as([]const u8, sym_name), MachO.StringSliceAdapter{721 const n_strx = context.macho_file.strtab_dir.getAdapted(@as([]const u8, sym_name), MachO.StringSliceAdapter{
725 .strtab = &ctx.macho_file.strtab,722 .strtab = &context.macho_file.strtab,
726 }) orelse unreachable;723 }) orelse unreachable;
727 const resolv = ctx.macho_file.symbol_resolver.get(n_strx) orelse unreachable;724 const resolv = context.macho_file.symbol_resolver.get(n_strx) orelse unreachable;
728 assert(resolv.where == .global);725 assert(resolv.where == .global);
729 subtractor = resolv.local_sym_index;726 subtractor = resolv.local_sym_index;
730 }727 }
731728
732 // Verify SUBTRACTOR is followed by UNSIGNED.729 // Verify SUBTRACTOR is followed by UNSIGNED.
733 switch (object.arch.?) {730 switch (arch) {
734 .aarch64 => {731 .aarch64 => {
735 const next = @intToEnum(macho.reloc_type_arm64, it.peek().r_type);732 const next = @intToEnum(macho.reloc_type_arm64, it.peek().r_type);
736 if (next != .ARM64_RELOC_UNSIGNED) {733 if (next != .ARM64_RELOC_UNSIGNED) {
...@@ -750,19 +747,19 @@ pub fn parseRelocsFromObject(...@@ -750,19 +747,19 @@ pub fn parseRelocsFromObject(
750 continue;747 continue;
751 }748 }
752749
753 var parsed_rel = try initRelocFromObject(rel, object, ctx);750 var parsed_rel = try initRelocFromObject(rel, context);
754751
755 switch (object.arch.?) {752 switch (arch) {
756 .aarch64 => {753 .aarch64 => {
757 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);754 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
758 switch (rel_type) {755 switch (rel_type) {
759 .ARM64_RELOC_ADDEND => unreachable,756 .ARM64_RELOC_ADDEND => unreachable,
760 .ARM64_RELOC_SUBTRACTOR => unreachable,757 .ARM64_RELOC_SUBTRACTOR => unreachable,
761 .ARM64_RELOC_BRANCH26 => {758 .ARM64_RELOC_BRANCH26 => {
762 self.parseBranch(rel, &parsed_rel, ctx);759 self.parseBranch(rel, &parsed_rel, context);
763 },760 },
764 .ARM64_RELOC_UNSIGNED => {761 .ARM64_RELOC_UNSIGNED => {
765 self.parseUnsigned(rel, &parsed_rel, subtractor, ctx);762 self.parseUnsigned(rel, &parsed_rel, subtractor, context);
766 subtractor = null;763 subtractor = null;
767 },764 },
768 .ARM64_RELOC_PAGE21,765 .ARM64_RELOC_PAGE21,
...@@ -790,10 +787,10 @@ pub fn parseRelocsFromObject(...@@ -790,10 +787,10 @@ pub fn parseRelocsFromObject(
790 switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {787 switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {
791 .X86_64_RELOC_SUBTRACTOR => unreachable,788 .X86_64_RELOC_SUBTRACTOR => unreachable,
792 .X86_64_RELOC_BRANCH => {789 .X86_64_RELOC_BRANCH => {
793 self.parseBranch(rel, &parsed_rel, ctx);790 self.parseBranch(rel, &parsed_rel, context);
794 },791 },
795 .X86_64_RELOC_UNSIGNED => {792 .X86_64_RELOC_UNSIGNED => {
796 self.parseUnsigned(rel, &parsed_rel, subtractor, ctx);793 self.parseUnsigned(rel, &parsed_rel, subtractor, context);
797 subtractor = null;794 subtractor = null;
798 },795 },
799 .X86_64_RELOC_SIGNED,796 .X86_64_RELOC_SIGNED,
...@@ -801,7 +798,7 @@ pub fn parseRelocsFromObject(...@@ -801,7 +798,7 @@ pub fn parseRelocsFromObject(
801 .X86_64_RELOC_SIGNED_2,798 .X86_64_RELOC_SIGNED_2,
802 .X86_64_RELOC_SIGNED_4,799 .X86_64_RELOC_SIGNED_4,
803 => {800 => {
804 self.parseSigned(rel, &parsed_rel, ctx);801 self.parseSigned(rel, &parsed_rel, context);
805 },802 },
806 .X86_64_RELOC_GOT_LOAD,803 .X86_64_RELOC_GOT_LOAD,
807 .X86_64_RELOC_GOT,804 .X86_64_RELOC_GOT,
...@@ -814,7 +811,7 @@ pub fn parseRelocsFromObject(...@@ -814,7 +811,7 @@ pub fn parseRelocsFromObject(
814 else => unreachable,811 else => unreachable,
815 }812 }
816813
817 try self.relocs.append(allocator, parsed_rel);814 try self.relocs.append(context.allocator, parsed_rel);
818815
819 const is_via_got = switch (parsed_rel.payload) {816 const is_via_got = switch (parsed_rel.payload) {
820 .pointer_to_got => true,817 .pointer_to_got => true,
...@@ -832,23 +829,23 @@ pub fn parseRelocsFromObject(...@@ -832,23 +829,23 @@ pub fn parseRelocsFromObject(
832 },829 },
833 .where_index = parsed_rel.where_index,830 .where_index = parsed_rel.where_index,
834 };831 };
835 if (ctx.macho_file.got_entries_map.contains(key)) break :blk;832 if (context.macho_file.got_entries_map.contains(key)) break :blk;
836833
837 const got_index = @intCast(u32, ctx.macho_file.got_entries.items.len);834 const got_index = @intCast(u32, context.macho_file.got_entries.items.len);
838 try ctx.macho_file.got_entries.append(ctx.macho_file.base.allocator, key);835 try context.macho_file.got_entries.append(context.allocator, key);
839 try ctx.macho_file.got_entries_map.putNoClobber(ctx.macho_file.base.allocator, key, got_index);836 try context.macho_file.got_entries_map.putNoClobber(context.allocator, key, got_index);
840 } else if (parsed_rel.payload == .unsigned) {837 } else if (parsed_rel.payload == .unsigned) {
841 switch (parsed_rel.where) {838 switch (parsed_rel.where) {
842 .import => {839 .import => {
843 try self.bindings.append(allocator, .{840 try self.bindings.append(context.allocator, .{
844 .local_sym_index = parsed_rel.where_index,841 .local_sym_index = parsed_rel.where_index,
845 .offset = parsed_rel.offset,842 .offset = parsed_rel.offset,
846 });843 });
847 },844 },
848 .local => {845 .local => {
849 const source_sym = ctx.macho_file.locals.items[self.local_sym_index];846 const source_sym = context.macho_file.locals.items[self.local_sym_index];
850 const match = ctx.macho_file.section_ordinals.items[source_sym.n_sect];847 const match = context.macho_file.section_ordinals.items[source_sym.n_sect];
851 const seg = ctx.macho_file.load_commands.items[match.seg].Segment;848 const seg = context.macho_file.load_commands.items[match.seg].Segment;
852 const sect = seg.sections.items[match.sect];849 const sect = seg.sections.items[match.sect];
853 const sect_type = commands.sectionType(sect);850 const sect_type = commands.sectionType(sect);
854851
...@@ -858,12 +855,12 @@ pub fn parseRelocsFromObject(...@@ -858,12 +855,12 @@ pub fn parseRelocsFromObject(
858 // TODO actually, a check similar to what dyld is doing, that is, verifying855 // TODO actually, a check similar to what dyld is doing, that is, verifying
859 // that the segment is writable should be enough here.856 // that the segment is writable should be enough here.
860 const is_right_segment = blk: {857 const is_right_segment = blk: {
861 if (ctx.macho_file.data_segment_cmd_index) |idx| {858 if (context.macho_file.data_segment_cmd_index) |idx| {
862 if (match.seg == idx) {859 if (match.seg == idx) {
863 break :blk true;860 break :blk true;
864 }861 }
865 }862 }
866 if (ctx.macho_file.data_const_segment_cmd_index) |idx| {863 if (context.macho_file.data_const_segment_cmd_index) |idx| {
867 if (match.seg == idx) {864 if (match.seg == idx) {
868 break :blk true;865 break :blk true;
869 }866 }
...@@ -884,17 +881,17 @@ pub fn parseRelocsFromObject(...@@ -884,17 +881,17 @@ pub fn parseRelocsFromObject(
884 };881 };
885882
886 if (should_rebase) {883 if (should_rebase) {
887 try self.rebases.append(allocator, parsed_rel.offset);884 try self.rebases.append(context.allocator, parsed_rel.offset);
888 }885 }
889 },886 },
890 }887 }
891 } else if (parsed_rel.payload == .branch) blk: {888 } else if (parsed_rel.payload == .branch) blk: {
892 if (parsed_rel.where != .import) break :blk;889 if (parsed_rel.where != .import) break :blk;
893 if (ctx.macho_file.stubs_map.contains(parsed_rel.where_index)) break :blk;890 if (context.macho_file.stubs_map.contains(parsed_rel.where_index)) break :blk;
894891
895 const stubs_index = @intCast(u32, ctx.macho_file.stubs.items.len);892 const stubs_index = @intCast(u32, context.macho_file.stubs.items.len);
896 try ctx.macho_file.stubs.append(ctx.macho_file.base.allocator, parsed_rel.where_index);893 try context.macho_file.stubs.append(context.allocator, parsed_rel.where_index);
897 try ctx.macho_file.stubs_map.putNoClobber(ctx.macho_file.base.allocator, parsed_rel.where_index, stubs_index);894 try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stubs_index);
898 }895 }
899 }896 }
900}897}
...@@ -917,7 +914,7 @@ fn parseUnsigned(...@@ -917,7 +914,7 @@ fn parseUnsigned(
917 rel: macho.relocation_info,914 rel: macho.relocation_info,
918 out: *Relocation,915 out: *Relocation,
919 subtractor: ?u32,916 subtractor: ?u32,
920 ctx: RelocContext,917 context: RelocContext,
921) void {918) void {
922 assert(rel.r_pcrel == 0);919 assert(rel.r_pcrel == 0);
923920
...@@ -934,7 +931,7 @@ fn parseUnsigned(...@@ -934,7 +931,7 @@ fn parseUnsigned(
934931
935 if (rel.r_extern == 0) {932 if (rel.r_extern == 0) {
936 assert(out.where == .local);933 assert(out.where == .local);
937 const target_sym = ctx.macho_file.locals.items[out.where_index];934 const target_sym = context.macho_file.locals.items[out.where_index];
938 addend -= @intCast(i64, target_sym.n_value);935 addend -= @intCast(i64, target_sym.n_value);
939 }936 }
940937
...@@ -947,14 +944,14 @@ fn parseUnsigned(...@@ -947,14 +944,14 @@ fn parseUnsigned(
947 };944 };
948}945}
949946
950fn parseBranch(self: TextBlock, rel: macho.relocation_info, out: *Relocation, ctx: RelocContext) void {947fn parseBranch(self: TextBlock, rel: macho.relocation_info, out: *Relocation, context: RelocContext) void {
951 _ = self;948 _ = self;
952 assert(rel.r_pcrel == 1);949 assert(rel.r_pcrel == 1);
953 assert(rel.r_length == 2);950 assert(rel.r_length == 2);
954951
955 out.payload = .{952 out.payload = .{
956 .branch = .{953 .branch = .{
957 .arch = ctx.macho_file.base.options.target.cpu.arch,954 .arch = context.macho_file.base.options.target.cpu.arch,
958 },955 },
959 };956 };
960}957}
...@@ -1015,7 +1012,7 @@ fn parsePointerToGot(self: TextBlock, rel: macho.relocation_info, out: *Relocati...@@ -1015,7 +1012,7 @@ fn parsePointerToGot(self: TextBlock, rel: macho.relocation_info, out: *Relocati
1015 };1012 };
1016}1013}
10171014
1018fn parseSigned(self: TextBlock, rel: macho.relocation_info, out: *Relocation, ctx: RelocContext) void {1015fn parseSigned(self: TextBlock, rel: macho.relocation_info, out: *Relocation, context: RelocContext) void {
1019 assert(rel.r_pcrel == 1);1016 assert(rel.r_pcrel == 1);
1020 assert(rel.r_length == 2);1017 assert(rel.r_length == 2);
10211018
...@@ -1030,10 +1027,10 @@ fn parseSigned(self: TextBlock, rel: macho.relocation_info, out: *Relocation, ct...@@ -1030,10 +1027,10 @@ fn parseSigned(self: TextBlock, rel: macho.relocation_info, out: *Relocation, ct
1030 var addend: i64 = mem.readIntLittle(i32, self.code.items[out.offset..][0..4]) + correction;1027 var addend: i64 = mem.readIntLittle(i32, self.code.items[out.offset..][0..4]) + correction;
10311028
1032 if (rel.r_extern == 0) {1029 if (rel.r_extern == 0) {
1033 const source_sym = ctx.macho_file.locals.items[self.local_sym_index];1030 const source_sym = context.macho_file.locals.items[self.local_sym_index];
1034 const target_sym = switch (out.where) {1031 const target_sym = switch (out.where) {
1035 .local => ctx.macho_file.locals.items[out.where_index],1032 .local => context.macho_file.locals.items[out.where_index],
1036 .import => ctx.macho_file.imports.items[out.where_index],1033 .import => context.macho_file.imports.items[out.where_index],
1037 };1034 };
1038 addend = @intCast(i64, source_sym.n_value + out.offset + 4) + addend - @intCast(i64, target_sym.n_value);1035 addend = @intCast(i64, source_sym.n_value + out.offset + 4) + addend - @intCast(i64, target_sym.n_value);
1039 }1036 }