authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-08 08:01:31+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-18 09:13:08+02:00
log9d5a900f4bf23fc3cf6e2848b9e9c370bba6c938
tree7409adf56a95d47ff6d7b86fde25584c75a6030f
parentf8cea21514ad18a2b47260783183d047f5a966c0

macho: migrate Object to self-ownership of atoms and symbols


2 files changed, 905 insertions(+), 387 deletions(-)

src/link/MachO.zig+8-10
...@@ -63,9 +63,6 @@ dso_handle_index: ?Symbol.Index = null,...@@ -63,9 +63,6 @@ dso_handle_index: ?Symbol.Index = null,
63objc_msg_send_index: ?Symbol.Index = null,63objc_msg_send_index: ?Symbol.Index = null,
64entry_index: ?Symbol.Index = null,64entry_index: ?Symbol.Index = null,
6565
66/// List of atoms that are either synthetic or map directly to the Zig source program.
67atoms: std.ArrayListUnmanaged(Atom) = .{},
68atoms_extra: std.ArrayListUnmanaged(u32) = .{},
69thunks: std.ArrayListUnmanaged(Thunk) = .{},66thunks: std.ArrayListUnmanaged(Thunk) = .{},
7067
71/// String interning table68/// String interning table
...@@ -549,13 +546,14 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -549,13 +546,14 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
549 try dead_strip.gcAtoms(self);546 try dead_strip.gcAtoms(self);
550 }547 }
551548
552 self.checkDuplicates() catch |err| switch (err) {549 // TODO
553 error.HasDuplicates => return error.FlushFailure,550 // self.checkDuplicates() catch |err| switch (err) {
554 else => |e| {551 // error.HasDuplicates => return error.FlushFailure,
555 try self.reportUnexpectedError("unexpected error while checking for duplicate symbol definitions", .{});552 // else => |e| {
556 return e;553 // try self.reportUnexpectedError("unexpected error while checking for duplicate symbol definitions", .{});
557 },554 // return e;
558 };555 // },
556 // };
559557
560 self.markImportsAndExports();558 self.markImportsAndExports();
561 self.deadStripDylibs();559 self.deadStripDylibs();
src/link/MachO/Object.zig+897-377
...@@ -12,7 +12,11 @@ symtab: std.MultiArrayList(Nlist) = .{},...@@ -12,7 +12,11 @@ symtab: std.MultiArrayList(Nlist) = .{},
12strtab: std.ArrayListUnmanaged(u8) = .{},12strtab: std.ArrayListUnmanaged(u8) = .{},
1313
14symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},14symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
15symbols_extra: std.ArrayListUnmanaged(u32) = .{},
16globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{},
15atoms: std.ArrayListUnmanaged(Atom.Index) = .{},17atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
18atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
19atoms_extra: std.ArrayListUnmanaged(u32) = .{},
1620
17platform: ?MachO.Platform = null,21platform: ?MachO.Platform = null,
18compile_unit: ?CompileUnit = null,22compile_unit: ?CompileUnit = null,
...@@ -30,6 +34,7 @@ data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},...@@ -30,6 +34,7 @@ data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
30alive: bool = true,34alive: bool = true,
31hidden: bool = false,35hidden: bool = false,
3236
37compact_unwind_ctx: CompactUnwindCtx = .{},
33output_symtab_ctx: MachO.SymtabCtx = .{},38output_symtab_ctx: MachO.SymtabCtx = .{},
34output_ar_state: Archive.ArState = .{},39output_ar_state: Archive.ArState = .{},
3540
...@@ -51,7 +56,11 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -51,7 +56,11 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
51 self.symtab.deinit(allocator);56 self.symtab.deinit(allocator);
52 self.strtab.deinit(allocator);57 self.strtab.deinit(allocator);
53 self.symbols.deinit(allocator);58 self.symbols.deinit(allocator);
59 self.symbols_extra.deinit(allocator);
60 self.globals.deinit(allocator);
54 self.atoms.deinit(allocator);61 self.atoms.deinit(allocator);
62 self.atoms_indexes.deinit(allocator);
63 self.atoms_extra.deinit(allocator);
55 self.cies.deinit(allocator);64 self.cies.deinit(allocator);
56 self.fdes.deinit(allocator);65 self.fdes.deinit(allocator);
57 self.eh_frame_data.deinit(allocator);66 self.eh_frame_data.deinit(allocator);
...@@ -70,6 +79,10 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -70,6 +79,10 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
7079
71 const gpa = macho_file.base.comp.gpa;80 const gpa = macho_file.base.comp.gpa;
72 const handle = macho_file.getFileHandle(self.file_handle);81 const handle = macho_file.getFileHandle(self.file_handle);
82 const cpu_arch = macho_file.getTarget().cpu.arch;
83
84 // Atom at index 0 is reserved as null atom
85 try self.atoms.append(gpa, .{ .extra = try self.addAtomExtra(gpa, .{}) });
7386
74 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;87 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
75 {88 {
...@@ -86,7 +99,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -86,7 +99,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
86 return error.InvalidCpuArch;99 return error.InvalidCpuArch;
87 },100 },
88 };101 };
89 if (macho_file.getTarget().cpu.arch != this_cpu_arch) {102 if (cpu_arch != this_cpu_arch) {
90 try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)});103 try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)});
91 return error.InvalidCpuArch;104 return error.InvalidCpuArch;
92 }105 }
...@@ -198,20 +211,20 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -198,20 +211,20 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
198 mem.sort(NlistIdx, nlists.items, self, NlistIdx.lessThan);211 mem.sort(NlistIdx, nlists.items, self, NlistIdx.lessThan);
199212
200 if (self.hasSubsections()) {213 if (self.hasSubsections()) {
201 try self.initSubsections(nlists.items, macho_file);214 try self.initSubsections(gpa, nlists.items);
202 } else {215 } else {
203 try self.initSections(nlists.items, macho_file);216 try self.initSections(gpa, nlists.items);
204 }217 }
205218
206 try self.initCstringLiterals(macho_file);219 try self.initCstringLiterals(gpa, handle, macho_file);
207 try self.initFixedSizeLiterals(macho_file);220 try self.initFixedSizeLiterals(gpa, macho_file);
208 try self.initPointerLiterals(macho_file);221 try self.initPointerLiterals(gpa, macho_file);
209 try self.linkNlistToAtom(macho_file);222 try self.linkNlistToAtom(macho_file);
210223
211 try self.sortAtoms(macho_file);224 try self.sortAtoms(macho_file);
212 try self.initSymbols(macho_file);225 try self.initSymbols(gpa, macho_file);
213 try self.initSymbolStabs(nlists.items, macho_file);226 try self.initSymbolStabs(gpa, nlists.items, macho_file);
214 try self.initRelocs(macho_file);227 try self.initRelocs(handle, cpu_arch, macho_file);
215228
216 // Parse DWARF __TEXT,__eh_frame section229 // Parse DWARF __TEXT,__eh_frame section
217 if (self.eh_frame_sect_index) |index| {230 if (self.eh_frame_sect_index) |index| {
...@@ -224,13 +237,13 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -224,13 +237,13 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
224 }237 }
225238
226 if (self.hasUnwindRecords() or self.hasEhFrameRecords()) {239 if (self.hasUnwindRecords() or self.hasEhFrameRecords()) {
227 try self.parseUnwindRecords(gpa, macho_file.getTarget().cpu.arch, macho_file);240 try self.parseUnwindRecords(gpa, cpu_arch, macho_file);
228 }241 }
229242
230 if (self.platform) |platform| {243 if (self.platform) |platform| {
231 if (!macho_file.platform.eqlTarget(platform)) {244 if (!macho_file.platform.eqlTarget(platform)) {
232 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{245 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{
233 platform.fmtTarget(macho_file.getTarget().cpu.arch),246 platform.fmtTarget(cpu_arch),
234 });247 });
235 return error.InvalidTarget;248 return error.InvalidTarget;
236 }249 }
...@@ -247,7 +260,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -247,7 +260,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
247 }260 }
248261
249 for (self.atoms.items) |atom_index| {262 for (self.atoms.items) |atom_index| {
250 const atom = macho_file.getAtom(atom_index).?;263 const atom = self.getAtom(atom_index) orelse continue;
251 const isec = atom.getInputSection(macho_file);264 const isec = atom.getInputSection(macho_file);
252 if (mem.eql(u8, isec.sectName(), "__eh_frame") or265 if (mem.eql(u8, isec.sectName(), "__eh_frame") or
253 mem.eql(u8, isec.sectName(), "__compact_unwind") or266 mem.eql(u8, isec.sectName(), "__compact_unwind") or
...@@ -276,10 +289,9 @@ pub fn isPtrLiteral(sect: macho.section_64) bool {...@@ -276,10 +289,9 @@ pub fn isPtrLiteral(sect: macho.section_64) bool {
276 return sect.type() == macho.S_LITERAL_POINTERS;289 return sect.type() == macho.S_LITERAL_POINTERS;
277}290}
278291
279fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {292fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
280 const tracy = trace(@src());293 const tracy = trace(@src());
281 defer tracy.end();294 defer tracy.end();
282 const gpa = macho_file.base.comp.gpa;
283 const slice = self.sections.slice();295 const slice = self.sections.slice();
284 for (slice.items(.header), slice.items(.subsections), 0..) |sect, *subsections, n_sect| {296 for (slice.items(.header), slice.items(.subsections), 0..) |sect, *subsections, n_sect| {
285 if (isCstringLiteral(sect)) continue;297 if (isCstringLiteral(sect)) continue;
...@@ -294,17 +306,18 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -294,17 +306,18 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
294 } else nlists.len;306 } else nlists.len;
295307
296 if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) {308 if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) {
297 const name = try std.fmt.allocPrintZ(gpa, "{s}${s}", .{ sect.segName(), sect.sectName() });309 const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() });
298 defer gpa.free(name);310 defer allocator.free(name);
299 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;311 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;
300 const atom_index = try self.addAtom(.{312 const atom_index = try self.addAtom(allocator, .{
301 .name = try self.addString(gpa, name),313 .name = try self.addString(allocator, name),
302 .n_sect = @intCast(n_sect),314 .n_sect = @intCast(n_sect),
303 .off = 0,315 .off = 0,
304 .size = size,316 .size = size,
305 .alignment = sect.@"align",317 .alignment = sect.@"align",
306 }, macho_file);318 });
307 try subsections.append(gpa, .{319 try self.atoms_indexes.append(allocator, atom_index);
320 try subsections.append(allocator, .{
308 .atom = atom_index,321 .atom = atom_index,
309 .off = 0,322 .off = 0,
310 });323 });
...@@ -327,14 +340,15 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -327,14 +340,15 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
327 @min(@ctz(nlist.nlist.n_value), sect.@"align")340 @min(@ctz(nlist.nlist.n_value), sect.@"align")
328 else341 else
329 sect.@"align";342 sect.@"align";
330 const atom_index = try self.addAtom(.{343 const atom_index = try self.addAtom(allocator, .{
331 .name = nlist.nlist.n_strx,344 .name = nlist.nlist.n_strx,
332 .n_sect = @intCast(n_sect),345 .n_sect = @intCast(n_sect),
333 .off = nlist.nlist.n_value - sect.addr,346 .off = nlist.nlist.n_value - sect.addr,
334 .size = size,347 .size = size,
335 .alignment = alignment,348 .alignment = alignment,
336 }, macho_file);349 });
337 try subsections.append(gpa, .{350 try self.atoms_indexes.append(allocator, atom_index);
351 try subsections.append(allocator, .{
338 .atom = atom_index,352 .atom = atom_index,
339 .off = nlist.nlist.n_value - sect.addr,353 .off = nlist.nlist.n_value - sect.addr,
340 });354 });
...@@ -346,30 +360,31 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -346,30 +360,31 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
346 }360 }
347}361}
348362
349fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void {363fn initSections(self: *Object, allocator: Allocator, nlists: anytype) !void {
350 const tracy = trace(@src());364 const tracy = trace(@src());
351 defer tracy.end();365 defer tracy.end();
352 const gpa = macho_file.base.comp.gpa;
353 const slice = self.sections.slice();366 const slice = self.sections.slice();
354367
355 try self.atoms.ensureUnusedCapacity(gpa, self.sections.items(.header).len);368 try self.atoms.ensureUnusedCapacity(allocator, self.sections.items(.header).len);
369 try self.atoms_indexes.ensureUnusedCapacity(allocator, self.sections.items(.header).len);
356370
357 for (slice.items(.header), 0..) |sect, n_sect| {371 for (slice.items(.header), 0..) |sect, n_sect| {
358 if (isCstringLiteral(sect)) continue;372 if (isCstringLiteral(sect)) continue;
359 if (isFixedSizeLiteral(sect)) continue;373 if (isFixedSizeLiteral(sect)) continue;
360 if (isPtrLiteral(sect)) continue;374 if (isPtrLiteral(sect)) continue;
361375
362 const name = try std.fmt.allocPrintZ(gpa, "{s}${s}", .{ sect.segName(), sect.sectName() });376 const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() });
363 defer gpa.free(name);377 defer allocator.free(name);
364378
365 const atom_index = try self.addAtom(.{379 const atom_index = try self.addAtom(allocator, .{
366 .name = try self.addString(gpa, name),380 .name = try self.addString(allocator, name),
367 .n_sect = @intCast(n_sect),381 .n_sect = @intCast(n_sect),
368 .off = 0,382 .off = 0,
369 .size = sect.size,383 .size = sect.size,
370 .alignment = sect.@"align",384 .alignment = sect.@"align",
371 }, macho_file);385 });
372 try slice.items(.subsections)[n_sect].append(gpa, .{ .atom = atom_index, .off = 0 });386 try self.atoms_indexes.append(allocator, atom_index);
387 try slice.items(.subsections)[n_sect].append(allocator, .{ .atom = atom_index, .off = 0 });
373388
374 const nlist_start = for (nlists, 0..) |nlist, i| {389 const nlist_start = for (nlists, 0..) |nlist, i| {
375 if (nlist.nlist.n_sect - 1 == n_sect) break i;390 if (nlist.nlist.n_sect - 1 == n_sect) break i;
...@@ -398,21 +413,25 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -398,21 +413,25 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
398 }413 }
399}414}
400415
401fn initCstringLiterals(self: *Object, macho_file: *MachO) !void {416fn initCstringLiterals(self: *Object, allocator: Allocator, file: File.Handle, macho_file: *MachO) !void {
402 const tracy = trace(@src());417 const tracy = trace(@src());
403 defer tracy.end();418 defer tracy.end();
404419
405 const gpa = macho_file.base.comp.gpa;
406 const slice = self.sections.slice();420 const slice = self.sections.slice();
407421
408 for (slice.items(.header), 0..) |sect, n_sect| {422 for (slice.items(.header), 0..) |sect, n_sect| {
409 if (!isCstringLiteral(sect)) continue;423 if (!isCstringLiteral(sect)) continue;
410424
411 const data = try self.getSectionData(@intCast(n_sect), macho_file);425 const sect_size = math.cast(usize, sect.size) orelse return error.Overflow;
412 defer gpa.free(data);426 const data = try allocator.alloc(u8, sect_size);
427 defer allocator.free(data);
428 const amt = try file.preadAll(data, sect.offset + self.offset);
429 if (amt != data.len) return error.InputOutput;
413430
431 var count: u32 = 0;
414 var start: u32 = 0;432 var start: u32 = 0;
415 while (start < data.len) {433 while (start < data.len) {
434 defer count += 1;
416 var end = start;435 var end = start;
417 while (end < data.len - 1 and data[end] != 0) : (end += 1) {}436 while (end < data.len - 1 and data[end] != 0) : (end += 1) {}
418 if (data[end] != 0) {437 if (data[end] != 0) {
...@@ -425,32 +444,52 @@ fn initCstringLiterals(self: *Object, macho_file: *MachO) !void {...@@ -425,32 +444,52 @@ fn initCstringLiterals(self: *Object, macho_file: *MachO) !void {
425 }444 }
426 end += 1;445 end += 1;
427446
428 const atom_index = try self.addAtom(.{447 const name = try std.fmt.allocPrintZ(allocator, "l._str{d}", .{count});
429 .name = 0,448 defer allocator.free(name);
449 const name_str = try self.addString(allocator, name);
450
451 const atom_index = try self.addAtom(allocator, .{
452 .name = name_str,
430 .n_sect = @intCast(n_sect),453 .n_sect = @intCast(n_sect),
431 .off = start,454 .off = start,
432 .size = end - start,455 .size = end - start,
433 .alignment = sect.@"align",456 .alignment = sect.@"align",
434 }, macho_file);457 });
435 try slice.items(.subsections)[n_sect].append(gpa, .{458 try self.atoms_indexes.append(allocator, atom_index);
459 try slice.items(.subsections)[n_sect].append(allocator, .{
436 .atom = atom_index,460 .atom = atom_index,
437 .off = start,461 .off = start,
438 });462 });
439463
464 const atom = self.getAtom(atom_index).?;
465 const nlist_index: u32 = @intCast(try self.symtab.addOne(allocator));
466 self.symtab.set(nlist_index, .{
467 .nlist = .{
468 .n_strx = name_str,
469 .n_type = macho.N_SECT,
470 .n_sect = @intCast(atom.n_sect + 1),
471 .n_desc = 0,
472 .n_value = atom.getInputAddress(macho_file),
473 },
474 .size = atom.size,
475 .atom = atom_index,
476 });
477 atom.addExtra(.{ .literal_symbol_index = nlist_index }, macho_file);
478
440 start = end;479 start = end;
441 }480 }
442 }481 }
443}482}
444483
445fn initFixedSizeLiterals(self: *Object, macho_file: *MachO) !void {484fn initFixedSizeLiterals(self: *Object, allocator: Allocator, macho_file: *MachO) !void {
446 const tracy = trace(@src());485 const tracy = trace(@src());
447 defer tracy.end();486 defer tracy.end();
448487
449 const gpa = macho_file.base.comp.gpa;
450 const slice = self.sections.slice();488 const slice = self.sections.slice();
451489
452 for (slice.items(.header), 0..) |sect, n_sect| {490 for (slice.items(.header), 0..) |sect, n_sect| {
453 if (!isFixedSizeLiteral(sect)) continue;491 if (!isFixedSizeLiteral(sect)) continue;
492
454 const rec_size: u8 = switch (sect.type()) {493 const rec_size: u8 = switch (sect.type()) {
455 macho.S_4BYTE_LITERALS => 4,494 macho.S_4BYTE_LITERALS => 4,
456 macho.S_8BYTE_LITERALS => 8,495 macho.S_8BYTE_LITERALS => 8,
...@@ -465,28 +504,52 @@ fn initFixedSizeLiterals(self: *Object, macho_file: *MachO) !void {...@@ -465,28 +504,52 @@ fn initFixedSizeLiterals(self: *Object, macho_file: *MachO) !void {
465 );504 );
466 return error.MalformedObject;505 return error.MalformedObject;
467 }506 }
507
468 var pos: u32 = 0;508 var pos: u32 = 0;
469 while (pos < sect.size) : (pos += rec_size) {509 var count: u32 = 0;
470 const atom_index = try self.addAtom(.{510 while (pos < sect.size) : ({
471 .name = 0,511 pos += rec_size;
512 count += 1;
513 }) {
514 const name = try std.fmt.allocPrintZ(allocator, "l._literal{d}", .{count});
515 defer allocator.free(name);
516 const name_str = try self.addString(allocator, name);
517
518 const atom_index = try self.addAtom(allocator, .{
519 .name = name_str,
472 .n_sect = @intCast(n_sect),520 .n_sect = @intCast(n_sect),
473 .off = pos,521 .off = pos,
474 .size = rec_size,522 .size = rec_size,
475 .alignment = sect.@"align",523 .alignment = sect.@"align",
476 }, macho_file);524 });
477 try slice.items(.subsections)[n_sect].append(gpa, .{525 try self.atoms_indexes.append(allocator, atom_index);
526 try slice.items(.subsections)[n_sect].append(allocator, .{
478 .atom = atom_index,527 .atom = atom_index,
479 .off = pos,528 .off = pos,
480 });529 });
530
531 const atom = self.getAtom(atom_index).?;
532 const nlist_index: u32 = @intCast(try self.symtab.addOne(allocator));
533 self.symtab.set(nlist_index, .{
534 .nlist = .{
535 .n_strx = name_str,
536 .n_type = macho.N_SECT,
537 .n_sect = @intCast(atom.n_sect + 1),
538 .n_desc = 0,
539 .n_value = atom.getInputAddress(macho_file),
540 },
541 .size = atom.size,
542 .atom = atom_index,
543 });
544 atom.addExtra(.{ .literal_symbol_index = nlist_index }, macho_file);
481 }545 }
482 }546 }
483}547}
484548
485fn initPointerLiterals(self: *Object, macho_file: *MachO) !void {549fn initPointerLiterals(self: *Object, allocator: Allocator, macho_file: *MachO) !void {
486 const tracy = trace(@src());550 const tracy = trace(@src());
487 defer tracy.end();551 defer tracy.end();
488552
489 const gpa = macho_file.base.comp.gpa;
490 const slice = self.sections.slice();553 const slice = self.sections.slice();
491554
492 for (slice.items(.header), 0..) |sect, n_sect| {555 for (slice.items(.header), 0..) |sect, n_sect| {
...@@ -505,134 +568,171 @@ fn initPointerLiterals(self: *Object, macho_file: *MachO) !void {...@@ -505,134 +568,171 @@ fn initPointerLiterals(self: *Object, macho_file: *MachO) !void {
505568
506 for (0..num_ptrs) |i| {569 for (0..num_ptrs) |i| {
507 const pos: u32 = @as(u32, @intCast(i)) * rec_size;570 const pos: u32 = @as(u32, @intCast(i)) * rec_size;
508 const atom_index = try self.addAtom(.{571
509 .name = 0,572 const name = try std.fmt.allocPrintZ(allocator, "l._ptr{d}", .{i});
573 defer allocator.free(name);
574 const name_str = try self.addString(allocator, name);
575
576 const atom_index = try self.addAtom(allocator, .{
577 .name = name_str,
510 .n_sect = @intCast(n_sect),578 .n_sect = @intCast(n_sect),
511 .off = pos,579 .off = pos,
512 .size = rec_size,580 .size = rec_size,
513 .alignment = sect.@"align",581 .alignment = sect.@"align",
514 }, macho_file);582 });
515 try slice.items(.subsections)[n_sect].append(gpa, .{583 try self.atoms_indexes.append(allocator, atom_index);
584 try slice.items(.subsections)[n_sect].append(allocator, .{
516 .atom = atom_index,585 .atom = atom_index,
517 .off = pos,586 .off = pos,
518 });587 });
588
589 const atom = self.getAtom(atom_index).?;
590 const nlist_index: u32 = @intCast(try self.symtab.addOne(allocator));
591 self.symtab.set(nlist_index, .{
592 .nlist = .{
593 .n_strx = name_str,
594 .n_type = macho.N_SECT,
595 .n_sect = @intCast(atom.n_sect + 1),
596 .n_desc = 0,
597 .n_value = atom.getInputAddress(macho_file),
598 },
599 .size = atom.size,
600 .atom = atom_index,
601 });
602 atom.addExtra(.{ .literal_symbol_index = nlist_index }, macho_file);
519 }603 }
520 }604 }
521}605}
522606
523pub fn resolveLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) !void {607pub fn resolveLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
608 const tracy = trace(@src());
609 defer tracy.end();
610
524 const gpa = macho_file.base.comp.gpa;611 const gpa = macho_file.base.comp.gpa;
612 const file = macho_file.getFileHandle(self.file_handle);
525613
526 var buffer = std.ArrayList(u8).init(gpa);614 var buffer = std.ArrayList(u8).init(gpa);
527 defer buffer.deinit();615 defer buffer.deinit();
528616
617 var sections_data = std.AutoHashMap(u32, []const u8).init(gpa);
618 try sections_data.ensureTotalCapacity(@intCast(self.sections.items(.header).len));
619 defer {
620 var it = sections_data.iterator();
621 while (it.next()) |entry| {
622 gpa.free(entry.value_ptr.*);
623 }
624 sections_data.deinit();
625 }
626
529 const slice = self.sections.slice();627 const slice = self.sections.slice();
530 for (slice.items(.header), slice.items(.subsections), 0..) |header, subs, n_sect| {628 for (slice.items(.header), slice.items(.subsections)) |header, subs| {
531 if (isCstringLiteral(header) or isFixedSizeLiteral(header)) {629 if (isCstringLiteral(header) or isFixedSizeLiteral(header)) {
532 const data = try self.getSectionData(@intCast(n_sect), macho_file);630 const sect_size = math.cast(usize, header.size) orelse return error.Overflow;
631 const data = try gpa.alloc(u8, sect_size);
533 defer gpa.free(data);632 defer gpa.free(data);
633 const amt = try file.preadAll(data, header.offset + self.offset);
634 if (amt != data.len) return error.InputOutput;
534635
535 for (subs.items) |sub| {636 for (subs.items) |sub| {
536 const atom = macho_file.getAtom(sub.atom).?;637 const atom = self.getAtom(sub.atom).?;
537 const atom_off = math.cast(usize, atom.off) orelse return error.Overflow;638 const atom_off = math.cast(usize, atom.off) orelse return error.Overflow;
538 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;639 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
539 const atom_data = data[atom_off..][0..atom_size];640 const atom_data = data[atom_off..][0..atom_size];
540 const res = try lp.insert(gpa, header.type(), atom_data);641 const res = try lp.insert(gpa, header.type(), atom_data);
541 if (!res.found_existing) {642 if (!res.found_existing) {
542 res.atom.* = sub.atom;643 res.ref.* = .{ .index = atom.getExtra(macho_file).literal_symbol_index, .file = self.index };
644 } else {
645 const lp_sym = lp.getSymbol(res.index, macho_file);
646 const lp_atom = lp_sym.getAtom(macho_file).?;
647 lp_atom.alignment = @max(lp_atom.alignment, atom.alignment);
648 atom.flags.alive = false;
543 }649 }
544 atom.flags.literal_pool = true;650 atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
545 try atom.addExtra(.{ .literal_index = res.index }, macho_file);
546 }651 }
547 } else if (isPtrLiteral(header)) {652 } else if (isPtrLiteral(header)) {
548 for (subs.items) |sub| {653 for (subs.items) |sub| {
549 const atom = macho_file.getAtom(sub.atom).?;654 const atom = self.getAtom(sub.atom).?;
550 const relocs = atom.getRelocs(macho_file);655 const relocs = atom.getRelocs(macho_file);
551 assert(relocs.len == 1);656 assert(relocs.len == 1);
552 const rel = relocs[0];657 const rel = relocs[0];
553 const target = switch (rel.tag) {658 const target = switch (rel.tag) {
554 .local => rel.target,659 .local => rel.getTargetAtom(atom.*, macho_file),
555 .@"extern" => rel.getTargetSymbol(macho_file).atom,660 .@"extern" => rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?,
556 };661 };
557 const addend = math.cast(u32, rel.addend) orelse return error.Overflow;662 const addend = math.cast(u32, rel.addend) orelse return error.Overflow;
558 const target_atom = macho_file.getAtom(target).?;663 const target_size = math.cast(usize, target.size) orelse return error.Overflow;
559 const target_atom_size = math.cast(usize, target_atom.size) orelse return error.Overflow;664 try buffer.ensureUnusedCapacity(target_size);
560 try buffer.ensureUnusedCapacity(target_atom_size);665 buffer.resize(target_size) catch unreachable;
561 buffer.resize(target_atom_size) catch unreachable;666 const gop = try sections_data.getOrPut(target.n_sect);
562 try target_atom.getData(macho_file, buffer.items);667 if (!gop.found_existing) {
668 const target_sect = slice.items(.header)[target.n_sect];
669 const target_sect_size = math.cast(usize, target_sect.size) orelse return error.Overflow;
670 const data = try gpa.alloc(u8, target_sect_size);
671 const amt = try file.preadAll(data, target_sect.offset + self.offset);
672 if (amt != data.len) return error.InputOutput;
673 gop.value_ptr.* = data;
674 }
675 const data = gop.value_ptr.*;
676 const target_off = math.cast(usize, target.off) orelse return error.Overflow;
677 @memcpy(buffer.items, data[target_off..][0..target_size]);
563 const res = try lp.insert(gpa, header.type(), buffer.items[addend..]);678 const res = try lp.insert(gpa, header.type(), buffer.items[addend..]);
564 buffer.clearRetainingCapacity();679 buffer.clearRetainingCapacity();
565 if (!res.found_existing) {680 if (!res.found_existing) {
566 res.atom.* = sub.atom;681 res.ref.* = .{ .index = atom.getExtra(macho_file).literal_symbol_index, .file = self.index };
682 } else {
683 const lp_sym = lp.getSymbol(res.index, macho_file);
684 const lp_atom = lp_sym.getAtom(macho_file).?;
685 lp_atom.alignment = @max(lp_atom.alignment, atom.alignment);
686 atom.flags.alive = false;
567 }687 }
568 atom.flags.literal_pool = true;688 atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
569 try atom.addExtra(.{ .literal_index = res.index }, macho_file);
570 }689 }
571 }690 }
572 }691 }
573}692}
574693
575pub fn dedupLiterals(self: Object, lp: MachO.LiteralPool, macho_file: *MachO) void {694pub fn dedupLiterals(self: *Object, lp: MachO.LiteralPool, macho_file: *MachO) void {
576 for (self.atoms.items) |atom_index| {695 const tracy = trace(@src());
577 const atom = macho_file.getAtom(atom_index) orelse continue;696 defer tracy.end();
697
698 for (self.getAtoms()) |atom_index| {
699 const atom = self.getAtom(atom_index) orelse continue;
578 if (!atom.flags.alive) continue;700 if (!atom.flags.alive) continue;
579 if (!atom.flags.relocs) continue;
580701
581 const relocs = blk: {702 const relocs = blk: {
582 const extra = atom.getExtra(macho_file).?;703 const extra = atom.getExtra(macho_file);
583 const relocs = self.sections.items(.relocs)[atom.n_sect].items;704 const relocs = self.sections.items(.relocs)[atom.n_sect].items;
584 break :blk relocs[extra.rel_index..][0..extra.rel_count];705 break :blk relocs[extra.rel_index..][0..extra.rel_count];
585 };706 };
586 for (relocs) |*rel| switch (rel.tag) {707 for (relocs) |*rel| {
587 .local => {708 if (rel.tag != .@"extern") continue;
588 const target = macho_file.getAtom(rel.target).?;709 const target_sym_ref = rel.getTargetSymbolRef(atom.*, macho_file);
589 if (target.getLiteralPoolIndex(macho_file)) |lp_index| {710 const file = target_sym_ref.getFile(macho_file) orelse continue;
590 const lp_atom = lp.getAtom(lp_index, macho_file);711 if (file.getIndex() != self.index) continue;
591 if (target.atom_index != lp_atom.atom_index) {712 const target_sym = target_sym_ref.getSymbol(macho_file).?;
592 lp_atom.alignment = lp_atom.alignment.max(target.alignment);713 const target_atom = target_sym.getAtom(macho_file) orelse continue;
593 target.flags.alive = false;714 const isec = target_atom.getInputSection(macho_file);
594 rel.target = lp_atom.atom_index;715 if (!Object.isCstringLiteral(isec) and !Object.isFixedSizeLiteral(isec) and !Object.isPtrLiteral(isec)) continue;
595 }716 const lp_index = target_atom.getExtra(macho_file).literal_pool_index;
596 }717 const lp_sym = lp.getSymbol(lp_index, macho_file);
597 },718 const lp_atom_ref = lp_sym.atom_ref;
598 .@"extern" => {719 if (target_atom.atom_index != lp_atom_ref.index or target_atom.file != lp_atom_ref.file) {
599 const target_sym = rel.getTargetSymbol(macho_file);720 target_sym.atom_ref = lp_atom_ref;
600 if (target_sym.getAtom(macho_file)) |target_atom| {721 }
601 if (target_atom.getLiteralPoolIndex(macho_file)) |lp_index| {722 }
602 const lp_atom = lp.getAtom(lp_index, macho_file);
603 if (target_atom.atom_index != lp_atom.atom_index) {
604 lp_atom.alignment = lp_atom.alignment.max(target_atom.alignment);
605 target_atom.flags.alive = false;
606 target_sym.atom = lp_atom.atom_index;
607 }
608 }
609 }
610 },
611 };
612 }723 }
613}
614
615const AddAtomArgs = struct {
616 name: u32,
617 n_sect: u8,
618 off: u64,
619 size: u64,
620 alignment: u32,
621};
622724
623fn addAtom(self: *Object, args: AddAtomArgs, macho_file: *MachO) !Atom.Index {725 for (self.symbols.items) |*sym| {
624 const gpa = macho_file.base.comp.gpa;726 const atom = sym.getAtom(macho_file) orelse continue;
625 const atom_index = try macho_file.addAtom();727 const isec = atom.getInputSection(macho_file);
626 const atom = macho_file.getAtom(atom_index).?;728 if (!Object.isCstringLiteral(isec) and !Object.isFixedSizeLiteral(isec) and !Object.isPtrLiteral(isec)) continue;
627 atom.file = self.index;729 const lp_index = atom.getExtra(macho_file).literal_pool_index;
628 atom.atom_index = atom_index;730 const lp_sym = lp.getSymbol(lp_index, macho_file);
629 atom.name = args.name;731 const lp_atom_ref = lp_sym.atom_ref;
630 atom.n_sect = args.n_sect;732 if (atom.atom_index != lp_atom_ref.index or self.index != lp_atom_ref.file) {
631 atom.size = args.size;733 sym.atom_ref = lp_atom_ref;
632 atom.alignment = Atom.Alignment.fromLog2Units(args.alignment);734 }
633 atom.off = args.off;735 }
634 try self.atoms.append(gpa, atom_index);
635 return atom_index;
636}736}
637737
638pub fn findAtom(self: Object, addr: u64) ?Atom.Index {738pub fn findAtom(self: Object, addr: u64) ?Atom.Index {
...@@ -704,55 +804,59 @@ fn linkNlistToAtom(self: *Object, macho_file: *MachO) !void {...@@ -704,55 +804,59 @@ fn linkNlistToAtom(self: *Object, macho_file: *MachO) !void {
704 }804 }
705}805}
706806
707fn initSymbols(self: *Object, macho_file: *MachO) !void {807fn initSymbols(self: *Object, allocator: Allocator, macho_file: *MachO) !void {
708 const tracy = trace(@src());808 const tracy = trace(@src());
709 defer tracy.end();809 defer tracy.end();
710 const gpa = macho_file.base.comp.gpa;810
711 const slice = self.symtab.slice();811 const slice = self.symtab.slice();
812 const nsyms = slice.items(.nlist).len;
712813
713 try self.symbols.ensureUnusedCapacity(gpa, slice.items(.nlist).len);814 try self.symbols.ensureTotalCapacityPrecise(allocator, nsyms);
815 try self.symbols_extra.ensureTotalCapacityPrecise(allocator, nsyms * @sizeOf(Symbol.Extra));
816 try self.globals.ensureTotalCapacityPrecise(allocator, nsyms);
817 self.globals.resize(allocator, nsyms) catch unreachable;
818 @memset(self.globals.items, 0);
714819
715 for (slice.items(.nlist), slice.items(.atom), 0..) |nlist, atom_index, i| {820 for (slice.items(.nlist), slice.items(.atom), 0..) |nlist, atom_index, i| {
716 if (nlist.ext()) {821 const index = self.addSymbolAssumeCapacity();
717 const name = self.getString(nlist.n_strx);822 const symbol = &self.symbols.items[index];
718 const off = try macho_file.strings.insert(gpa, name);823 symbol.value = nlist.n_value;
719 const gop = try macho_file.getOrCreateGlobal(off);824 symbol.name = .{ .pos = nlist.n_strx, .len = @intCast(self.getNStrx(nlist.n_strx).len + 1) };
720 self.symbols.addOneAssumeCapacity().* = gop.index;825 symbol.nlist_idx = @intCast(i);
721 if (nlist.undf() and nlist.weakRef()) {826 symbol.extra = self.addSymbolExtraAssumeCapacity(.{});
722 macho_file.getSymbol(gop.index).flags.weak_ref = true;827
723 }828 if (self.getAtom(atom_index)) |atom| {
724 continue;
725 }
726
727 const index = try macho_file.addSymbol();
728 self.symbols.appendAssumeCapacity(index);
729 const symbol = macho_file.getSymbol(index);
730 symbol.* = .{
731 .value = nlist.n_value,
732 .name = nlist.n_strx,
733 .nlist_idx = @intCast(i),
734 .atom = 0,
735 .file = self.index,
736 };
737
738 if (macho_file.getAtom(atom_index)) |atom| {
739 assert(!nlist.abs());829 assert(!nlist.abs());
740 symbol.value -= atom.getInputAddress(macho_file);830 symbol.value -= atom.getInputAddress(macho_file);
741 symbol.atom = atom_index;831 symbol.atom_ref = .{ .index = atom_index, .file = self.index };
742 }832 }
743833
834 symbol.flags.weak = nlist.weakDef();
744 symbol.flags.abs = nlist.abs();835 symbol.flags.abs = nlist.abs();
836 symbol.flags.tentative = nlist.tentative();
745 symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip();837 symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip();
838 symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0;
839 symbol.flags.interposable = nlist.ext() and (nlist.sect() or nlist.abs()) and macho_file.options.dylib and macho_file.options.namespace == .flat and !nlist.pext();
746840
747 if (nlist.sect() and841 if (nlist.sect() and
748 self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES)842 self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES)
749 {843 {
750 symbol.flags.tlv = true;844 symbol.flags.tlv = true;
751 }845 }
846
847 if (nlist.ext()) {
848 if (nlist.undf()) {
849 symbol.flags.weak_ref = nlist.weakRef();
850 } else if (nlist.pext() or (nlist.weakDef() and nlist.weakRef()) or self.hidden) {
851 symbol.visibility = .hidden;
852 } else {
853 symbol.visibility = .global;
854 }
855 }
752 }856 }
753}857}
754858
755fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {859fn initSymbolStabs(self: *Object, allocator: Allocator, nlists: anytype, macho_file: *MachO) !void {
756 const tracy = trace(@src());860 const tracy = trace(@src());
757 defer tracy.end();861 defer tracy.end();
758862
...@@ -778,14 +882,13 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -778,14 +882,13 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
778882
779 if (start == end) return;883 if (start == end) return;
780884
781 const gpa = macho_file.base.comp.gpa;
782 const syms = self.symtab.items(.nlist);885 const syms = self.symtab.items(.nlist);
783 const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists };886 const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists };
784887
785 // We need to cache nlists by name so that we can properly resolve local N_GSYM stabs.888 // We need to cache nlists by name so that we can properly resolve local N_GSYM stabs.
786 // What happens is `ld -r` will emit an N_GSYM stab for a symbol that may be either an889 // What happens is `ld -r` will emit an N_GSYM stab for a symbol that may be either an
787 // external or private external.890 // external or private external.
788 var addr_lookup = std.StringHashMap(u64).init(gpa);891 var addr_lookup = std.StringHashMap(u64).init(allocator);
789 defer addr_lookup.deinit();892 defer addr_lookup.deinit();
790 for (syms) |sym| {893 for (syms) |sym| {
791 if (sym.sect() and (sym.ext() or sym.pext())) {894 if (sym.sect() and (sym.ext() or sym.pext())) {
...@@ -834,29 +937,35 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -834,29 +937,35 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
834 return error.MalformedObject;937 return error.MalformedObject;
835 },938 },
836 }939 }
837 try sf.stabs.append(gpa, stab);940 try sf.stabs.append(allocator, stab);
838 }941 }
839942
840 try self.stab_files.append(gpa, sf);943 try self.stab_files.append(allocator, sf);
841 }944 }
842}945}
843946
844fn sortAtoms(self: *Object, macho_file: *MachO) !void {947fn sortAtoms(self: *Object, macho_file: *MachO) !void {
845 const lessThanAtom = struct {948 const Ctx = struct {
846 fn lessThanAtom(ctx: *MachO, lhs: Atom.Index, rhs: Atom.Index) bool {949 object: *Object,
847 return ctx.getAtom(lhs).?.getInputAddress(ctx) < ctx.getAtom(rhs).?.getInputAddress(ctx);950 mfile: *MachO,
951
952 fn lessThanAtom(ctx: @This(), lhs: Atom.Index, rhs: Atom.Index) bool {
953 return ctx.object.getAtom(lhs).?.getInputAddress(ctx.mfile) <
954 ctx.object.getAtom(rhs).?.getInputAddress(ctx.mfile);
848 }955 }
849 }.lessThanAtom;956 };
850 mem.sort(Atom.Index, self.atoms.items, macho_file, lessThanAtom);957 mem.sort(Atom.Index, self.atoms_indexes.items, Ctx{
958 .object = self,
959 .mfile = macho_file,
960 }, Ctx.lessThanAtom);
851}961}
852962
853fn initRelocs(self: *Object, macho_file: *MachO) !void {963fn initRelocs(self: *Object, file: File.Handle, cpu_arch: std.Target.Cpu.Arch, macho_file: *MachO) !void {
854 const tracy = trace(@src());964 const tracy = trace(@src());
855 defer tracy.end();965 defer tracy.end();
856 const cpu_arch = macho_file.getTarget().cpu.arch;
857 const slice = self.sections.slice();966 const slice = self.sections.slice();
858967
859 for (slice.items(.header), slice.items(.relocs), 0..) |sect, *out, n_sect| {968 for (slice.items(.header), slice.items(.relocs)) |sect, *out| {
860 if (sect.nreloc == 0) continue;969 if (sect.nreloc == 0) continue;
861 // We skip relocs for __DWARF since even in -r mode, the linker is expected to emit970 // We skip relocs for __DWARF since even in -r mode, the linker is expected to emit
862 // debug symbol stabs in the relocatable. This made me curious why that is. For now,971 // debug symbol stabs in the relocatable. This made me curious why that is. For now,
...@@ -865,8 +974,8 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void {...@@ -865,8 +974,8 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void {
865 !mem.eql(u8, sect.sectName(), "__compact_unwind")) continue;974 !mem.eql(u8, sect.sectName(), "__compact_unwind")) continue;
866975
867 switch (cpu_arch) {976 switch (cpu_arch) {
868 .x86_64 => try x86_64.parseRelocs(self, @intCast(n_sect), sect, out, macho_file),977 .x86_64 => try x86_64.parseRelocs(self, sect, out, file, macho_file),
869 .aarch64 => try aarch64.parseRelocs(self, @intCast(n_sect), sect, out, macho_file),978 .aarch64 => try aarch64.parseRelocs(self, sect, out, file, macho_file),
870 else => unreachable,979 else => unreachable,
871 }980 }
872981
...@@ -878,7 +987,7 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void {...@@ -878,7 +987,7 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void {
878987
879 var next_reloc: u32 = 0;988 var next_reloc: u32 = 0;
880 for (subsections.items) |subsection| {989 for (subsections.items) |subsection| {
881 const atom = macho_file.getAtom(subsection.atom).?;990 const atom = self.getAtom(subsection.atom).?;
882 if (!atom.flags.alive) continue;991 if (!atom.flags.alive) continue;
883 if (next_reloc >= relocs.items.len) break;992 if (next_reloc >= relocs.items.len) break;
884 const end_addr = atom.off + atom.size;993 const end_addr = atom.off + atom.size;
...@@ -887,27 +996,22 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void {...@@ -887,27 +996,22 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void {
887 while (next_reloc < relocs.items.len and relocs.items[next_reloc].offset < end_addr) : (next_reloc += 1) {}996 while (next_reloc < relocs.items.len and relocs.items[next_reloc].offset < end_addr) : (next_reloc += 1) {}
888997
889 const rel_count = next_reloc - rel_index;998 const rel_count = next_reloc - rel_index;
890 try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, macho_file);999 atom.addExtra(.{ .rel_index = @intCast(rel_index), .rel_count = @intCast(rel_count) }, macho_file);
891 atom.flags.relocs = true;
892 }1000 }
893 }1001 }
894}1002}
8951003
896fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {1004fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: File.Handle, macho_file: *MachO) !void {
897 const tracy = trace(@src());1005 const tracy = trace(@src());
898 defer tracy.end();1006 defer tracy.end();
899 const gpa = macho_file.base.comp.gpa;
900 const nlists = self.symtab.items(.nlist);1007 const nlists = self.symtab.items(.nlist);
901 const slice = self.sections.slice();1008 const slice = self.sections.slice();
902 const sect = slice.items(.header)[sect_id];1009 const sect = slice.items(.header)[sect_id];
903 const relocs = slice.items(.relocs)[sect_id];1010 const relocs = slice.items(.relocs)[sect_id];
9041011
905 // TODO: read into buffer directly1012 try self.eh_frame_data.resize(allocator, sect.size);
906 const data = try self.getSectionData(sect_id, macho_file);1013 const amt = try file.preadAll(self.eh_frame_data.items, sect.offset + self.offset);
907 defer gpa.free(data);1014 if (amt != self.eh_frame_data.items.len) return error.InputOutput;
908
909 try self.eh_frame_data.ensureTotalCapacityPrecise(gpa, data.len);
910 self.eh_frame_data.appendSliceAssumeCapacity(data);
9111015
912 // Check for non-personality relocs in FDEs and apply them1016 // Check for non-personality relocs in FDEs and apply them
913 for (relocs.items, 0..) |rel, i| {1017 for (relocs.items, 0..) |rel, i| {
...@@ -939,12 +1043,12 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {...@@ -939,12 +1043,12 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
939 var it = eh_frame.Iterator{ .data = self.eh_frame_data.items };1043 var it = eh_frame.Iterator{ .data = self.eh_frame_data.items };
940 while (try it.next()) |rec| {1044 while (try it.next()) |rec| {
941 switch (rec.tag) {1045 switch (rec.tag) {
942 .cie => try self.cies.append(gpa, .{1046 .cie => try self.cies.append(allocator, .{
943 .offset = rec.offset,1047 .offset = rec.offset,
944 .size = rec.size,1048 .size = rec.size,
945 .file = self.index,1049 .file = self.index,
946 }),1050 }),
947 .fde => try self.fdes.append(gpa, .{1051 .fde => try self.fdes.append(allocator, .{
948 .offset = rec.offset,1052 .offset = rec.offset,
949 .size = rec.size,1053 .size = rec.size,
950 .cie = undefined,1054 .cie = undefined,
...@@ -1205,8 +1309,7 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target....@@ -1205,8 +1309,7 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target.
1205 {}1309 {}
12061310
1207 const atom = rec.getAtom(macho_file);1311 const atom = rec.getAtom(macho_file);
1208 try atom.addExtra(.{ .unwind_index = start, .unwind_count = next_cu - start }, macho_file);1312 atom.addExtra(.{ .unwind_index = start, .unwind_count = next_cu - start }, macho_file);
1209 atom.flags.unwind = true;
1210 }1313 }
1211}1314}
12121315
...@@ -1233,11 +1336,31 @@ pub fn parseDebugInfo(self: *Object, macho_file: *MachO) !void {...@@ -1233,11 +1336,31 @@ pub fn parseDebugInfo(self: *Object, macho_file: *MachO) !void {
12331336
1234 if (debug_info_index == null or debug_abbrev_index == null) return;1337 if (debug_info_index == null or debug_abbrev_index == null) return;
12351338
1236 const debug_info = try self.getSectionData(@intCast(debug_info_index.?), macho_file);1339 const slice = self.sections.slice();
1340 const file = macho_file.getFileHandle(self.file_handle);
1341 const debug_info = blk: {
1342 const sect = slice.items(.header)[debug_info_index.?];
1343 const data = try gpa.alloc(u8, sect.size);
1344 const amt = try file.preadAll(data, sect.offset + self.offset);
1345 if (amt != data.len) return error.InputOutput;
1346 break :blk data;
1347 };
1237 defer gpa.free(debug_info);1348 defer gpa.free(debug_info);
1238 const debug_abbrev = try self.getSectionData(@intCast(debug_abbrev_index.?), macho_file);1349 const debug_abbrev = blk: {
1350 const sect = slice.items(.header)[debug_abbrev_index.?];
1351 const data = try gpa.alloc(u8, sect.size);
1352 const amt = try file.preadAll(data, sect.offset + self.offset);
1353 if (amt != data.len) return error.InputOutput;
1354 break :blk data;
1355 };
1239 defer gpa.free(debug_abbrev);1356 defer gpa.free(debug_abbrev);
1240 const debug_str = if (debug_str_index) |index| try self.getSectionData(@intCast(index), macho_file) else &[0]u8{};1357 const debug_str = if (debug_str_index) |sid| blk: {
1358 const sect = slice.items(.header)[sid];
1359 const data = try gpa.alloc(u8, sect.size);
1360 const amt = try file.preadAll(data, sect.offset + self.offset);
1361 if (amt != data.len) return error.InputOutput;
1362 break :blk data;
1363 } else &[0]u8{};
1241 defer gpa.free(debug_str);1364 defer gpa.free(debug_str);
12421365
1243 self.compile_unit = self.findCompileUnit(.{1366 self.compile_unit = self.findCompileUnit(.{
...@@ -1347,83 +1470,51 @@ pub fn resolveSymbols(self: *Object, macho_file: *MachO) void {...@@ -1347,83 +1470,51 @@ pub fn resolveSymbols(self: *Object, macho_file: *MachO) void {
1347 const tracy = trace(@src());1470 const tracy = trace(@src());
1348 defer tracy.end();1471 defer tracy.end();
13491472
1350 for (self.symbols.items, 0..) |index, i| {1473 const gpa = macho_file.base.allocator;
1351 const nlist_idx = @as(Symbol.Index, @intCast(i));
1352 const nlist = self.symtab.items(.nlist)[nlist_idx];
1353 const atom_index = self.symtab.items(.atom)[nlist_idx];
13541474
1475 for (self.symtab.items(.nlist), self.symtab.items(.atom), self.globals.items, 0..) |nlist, atom_index, *global, i| {
1355 if (!nlist.ext()) continue;1476 if (!nlist.ext()) continue;
1356 if (nlist.undf() and !nlist.tentative()) continue;
1357 if (nlist.sect()) {1477 if (nlist.sect()) {
1358 const atom = macho_file.getAtom(atom_index).?;1478 const atom = self.getAtom(atom_index).?;
1359 if (!atom.flags.alive) continue;1479 if (!atom.alive.load(.seq_cst)) continue;
1480 }
1481
1482 const gop = try macho_file.resolver.getOrPut(gpa, .{
1483 .index = @intCast(i),
1484 .file = self.index,
1485 }, macho_file);
1486 if (!gop.found_existing) {
1487 gop.ref.* = .{ .index = 0, .file = 0 };
1488 }
1489 global.* = gop.index;
1490
1491 if (nlist.undf() and !nlist.tentative()) continue;
1492 if (gop.ref.getFile(macho_file) == null) {
1493 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
1494 continue;
1360 }1495 }
13611496
1362 const symbol = macho_file.getSymbol(index);
1363 if (self.asFile().getSymbolRank(.{1497 if (self.asFile().getSymbolRank(.{
1364 .archive = !self.alive,1498 .archive = !self.alive,
1365 .weak = nlist.weakDef(),1499 .weak = nlist.weakDef(),
1366 .tentative = nlist.tentative(),1500 .tentative = nlist.tentative(),
1367 }) < symbol.getSymbolRank(macho_file)) {1501 }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) {
1368 const value = if (nlist.sect()) blk: {1502 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
1369 const atom = macho_file.getAtom(atom_index).?;
1370 break :blk nlist.n_value - atom.getInputAddress(macho_file);
1371 } else nlist.n_value;
1372 symbol.value = value;
1373 symbol.atom = atom_index;
1374 symbol.nlist_idx = nlist_idx;
1375 symbol.file = self.index;
1376 symbol.flags.weak = nlist.weakDef();
1377 symbol.flags.abs = nlist.abs();
1378 symbol.flags.tentative = nlist.tentative();
1379 symbol.flags.weak_ref = false;
1380 symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0;
1381 symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip();
1382 // TODO: symbol.flags.interposable = macho_file.base.isDynLib() and macho_file.options.namespace == .flat and !nlist.pext();
1383 symbol.flags.interposable = false;
1384
1385 if (nlist.sect() and
1386 self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES)
1387 {
1388 symbol.flags.tlv = true;
1389 }
1390 }
1391
1392 // Regardless of who the winner is, we still merge symbol visibility here.
1393 if (nlist.pext() or (nlist.weakDef() and nlist.weakRef()) or self.hidden) {
1394 if (symbol.visibility != .global) {
1395 symbol.visibility = .hidden;
1396 }
1397 } else {
1398 symbol.visibility = .global;
1399 }1503 }
1400 }1504 }
1401}1505}
14021506
1403pub fn resetGlobals(self: *Object, macho_file: *MachO) void {
1404 for (self.symbols.items, 0..) |sym_index, nlist_idx| {
1405 if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue;
1406 const sym = macho_file.getSymbol(sym_index);
1407 const name = sym.name;
1408 const global = sym.flags.global;
1409 const weak_ref = sym.flags.weak_ref;
1410 sym.* = .{};
1411 sym.name = name;
1412 sym.flags.global = global;
1413 sym.flags.weak_ref = weak_ref;
1414 }
1415}
1416
1417pub fn markLive(self: *Object, macho_file: *MachO) void {1507pub fn markLive(self: *Object, macho_file: *MachO) void {
1418 const tracy = trace(@src());1508 const tracy = trace(@src());
1419 defer tracy.end();1509 defer tracy.end();
14201510
1421 for (self.symbols.items, 0..) |index, nlist_idx| {1511 for (0..self.symbols.items.len) |i| {
1422 const nlist = self.symtab.items(.nlist)[nlist_idx];1512 const nlist = self.symtab.items(.nlist)[i];
1423 if (!nlist.ext()) continue;1513 if (!nlist.ext()) continue;
14241514
1425 const sym = macho_file.getSymbol(index);1515 const ref = self.getSymbolRef(@intCast(i), macho_file);
1426 const file = sym.getFile(macho_file) orelse continue;1516 const file = ref.getFile(macho_file) orelse continue;
1517 const sym = ref.getSymbol(macho_file).?;
1427 const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative);1518 const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative);
1428 if (should_keep and file == .object and !file.object.alive) {1519 if (should_keep and file == .object and !file.object.alive) {
1429 file.object.alive = true;1520 file.object.alive = true;
...@@ -1432,30 +1523,47 @@ pub fn markLive(self: *Object, macho_file: *MachO) void {...@@ -1432,30 +1523,47 @@ pub fn markLive(self: *Object, macho_file: *MachO) void {
1432 }1523 }
1433}1524}
14341525
1435pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{OutOfMemory}!void {1526pub fn mergeSymbolVisibility(self: *Object, macho_file: *MachO) void {
1436 for (self.symbols.items, 0..) |index, nlist_idx| {1527 const tracy = trace(@src());
1437 const sym = macho_file.getSymbol(index);1528 defer tracy.end();
1438 if (sym.visibility != .global) continue;
1439 const file = sym.getFile(macho_file) orelse continue;
1440 if (file.getIndex() == self.index) continue;
14411529
1442 const nlist = self.symtab.items(.nlist)[nlist_idx];1530 for (self.symbols.items, 0..) |sym, i| {
1443 if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) {1531 const ref = self.getSymbolRef(@intCast(i), macho_file);
1444 const gop = try dupes.getOrPut(index);1532 const global = ref.getSymbol(macho_file) orelse continue;
1445 if (!gop.found_existing) {1533 if (global.visibility != .global) {
1446 gop.value_ptr.* = .{};1534 global.visibility = sym.visibility;
1447 }1535 }
1448 try gop.value_ptr.append(macho_file.base.comp.gpa, self.index);1536 if (sym.flags.weak_ref) {
1537 global.flags.weak_ref = true;
1449 }1538 }
1450 }1539 }
1451}1540}
14521541
1542// TODO
1543// pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{OutOfMemory}!void {
1544// for (self.symbols.items, 0..) |index, nlist_idx| {
1545// const sym = macho_file.getSymbol(index);
1546// if (sym.visibility != .global) continue;
1547// const file = sym.getFile(macho_file) orelse continue;
1548// if (file.getIndex() == self.index) continue;
1549
1550// const nlist = self.symtab.items(.nlist)[nlist_idx];
1551// if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) {
1552// const gop = try dupes.getOrPut(index);
1553// if (!gop.found_existing) {
1554// gop.value_ptr.* = .{};
1555// }
1556// try gop.value_ptr.append(macho_file.base.comp.gpa, self.index);
1557// }
1558// }
1559// }
1560
1453pub fn scanRelocs(self: *Object, macho_file: *MachO) !void {1561pub fn scanRelocs(self: *Object, macho_file: *MachO) !void {
1454 const tracy = trace(@src());1562 const tracy = trace(@src());
1455 defer tracy.end();1563 defer tracy.end();
14561564
1457 for (self.atoms.items) |atom_index| {1565 for (self.getAtoms()) |atom_index| {
1458 const atom = macho_file.getAtom(atom_index).?;1566 const atom = self.getAtom(atom_index) orelse continue;
1459 if (!atom.flags.alive) continue;1567 if (!atom.flags.alive) continue;
1460 const sect = atom.getInputSection(macho_file);1568 const sect = atom.getInputSection(macho_file);
1461 if (sect.isZerofill()) continue;1569 if (sect.isZerofill()) continue;
...@@ -1480,38 +1588,35 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {...@@ -1480,38 +1588,35 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {
1480 defer tracy.end();1588 defer tracy.end();
1481 const gpa = macho_file.base.comp.gpa;1589 const gpa = macho_file.base.comp.gpa;
14821590
1483 for (self.symbols.items, 0..) |index, i| {1591 for (self.symbols.items, self.globals.items, 0..) |*sym, off, i| {
1484 const sym = macho_file.getSymbol(index);
1485 if (!sym.flags.tentative) continue;1592 if (!sym.flags.tentative) continue;
1486 const sym_file = sym.getFile(macho_file).?;1593 if (macho_file.resolver.get(off).?.file != self.index) continue;
1487 if (sym_file.getIndex() != self.index) continue;
14881594
1489 const nlist_idx = @as(Symbol.Index, @intCast(i));1595 const nlist_idx = @as(Symbol.Index, @intCast(i));
1490 const nlist = &self.symtab.items(.nlist)[nlist_idx];1596 const nlist = &self.symtab.items(.nlist)[nlist_idx];
1491 const nlist_atom = &self.symtab.items(.atom)[nlist_idx];1597 const nlist_atom = &self.symtab.items(.atom)[nlist_idx];
14921598
1493 const atom_index = try macho_file.addAtom();
1494 try self.atoms.append(gpa, atom_index);
1495
1496 const name = try std.fmt.allocPrintZ(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)});1599 const name = try std.fmt.allocPrintZ(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)});
1497 defer gpa.free(name);1600 defer gpa.free(name);
1498 const atom = macho_file.getAtom(atom_index).?;
1499 atom.atom_index = atom_index;
1500 atom.name = try self.addString(gpa, name);
1501 atom.file = self.index;
1502 atom.size = nlist.n_value;
1503 atom.alignment = Atom.Alignment.fromLog2Units((nlist.n_desc >> 8) & 0x0f);
15041601
1602 const alignment = (nlist.n_desc >> 8) & 0x0f;
1505 const n_sect = try self.addSection(gpa, "__DATA", "__common");1603 const n_sect = try self.addSection(gpa, "__DATA", "__common");
1604 const atom_index = try self.addAtom(gpa, .{
1605 .name = try self.addString(gpa, name),
1606 .n_sect = n_sect,
1607 .off = 0,
1608 .size = nlist.n_value,
1609 .alignment = alignment,
1610 });
1611 try self.atoms_indexes.append(gpa, atom_index);
1612
1506 const sect = &self.sections.items(.header)[n_sect];1613 const sect = &self.sections.items(.header)[n_sect];
1507 sect.flags = macho.S_ZEROFILL;1614 sect.flags = macho.S_ZEROFILL;
1508 sect.size = atom.size;1615 sect.size = nlist.n_value;
1509 sect.@"align" = atom.alignment.toLog2Units();1616 sect.@"align" = alignment;
1510 atom.n_sect = n_sect;
15111617
1512 sym.value = 0;1618 sym.value = 0;
1513 sym.atom = atom_index;1619 sym.atom_ref = .{ .index = atom_index, .file = self.index };
1514 sym.flags.global = true;
1515 sym.flags.weak = false;1620 sym.flags.weak = false;
1516 sym.flags.weak_ref = false;1621 sym.flags.weak_ref = false;
1517 sym.flags.tentative = false;1622 sym.flags.tentative = false;
...@@ -1525,6 +1630,56 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {...@@ -1525,6 +1630,56 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {
1525 }1630 }
1526}1631}
15271632
1633pub fn claimUnresolved(self: *Object, macho_file: *MachO) void {
1634 const tracy = trace(@src());
1635 defer tracy.end();
1636
1637 for (self.symbols.items, 0..) |*sym, i| {
1638 const nlist = self.symtab.items(.nlist)[i];
1639 if (!nlist.ext()) continue;
1640 if (!nlist.undf()) continue;
1641
1642 if (self.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue;
1643
1644 const is_import = switch (macho_file.options.undefined_treatment) {
1645 .@"error" => false,
1646 .warn, .suppress => nlist.weakRef(),
1647 .dynamic_lookup => true,
1648 };
1649 if (is_import) {
1650 sym.value = 0;
1651 sym.atom_ref = .{ .index = 0, .file = 0 };
1652 sym.flags.weak = false;
1653 sym.flags.weak_ref = nlist.weakRef();
1654 sym.flags.import = is_import;
1655 sym.visibility = .global;
1656
1657 const idx = self.globals.items[i];
1658 macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = self.index };
1659 }
1660 }
1661}
1662
1663pub fn claimUnresolvedRelocatable(self: *Object, macho_file: *MachO) void {
1664 const tracy = trace(@src());
1665 defer tracy.end();
1666
1667 for (self.symbols.items, self.symtab.items(.nlist), 0..) |*sym, nlist, i| {
1668 if (!nlist.ext()) continue;
1669 if (!nlist.undf()) continue;
1670 if (self.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue;
1671
1672 sym.value = 0;
1673 sym.atom_ref = .{ .index = 0, .file = 0 };
1674 sym.flags.weak_ref = nlist.weakRef();
1675 sym.flags.import = true;
1676 sym.visibility = .global;
1677
1678 const idx = self.globals.items[i];
1679 macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = self.index };
1680 }
1681}
1682
1528fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname: []const u8) !u32 {1683fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname: []const u8) !u32 {
1529 const n_sect = @as(u32, @intCast(try self.sections.addOne(allocator)));1684 const n_sect = @as(u32, @intCast(try self.sections.addOne(allocator)));
1530 self.sections.set(n_sect, .{1685 self.sections.set(n_sect, .{
...@@ -1646,19 +1801,22 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) !void {...@@ -1646,19 +1801,22 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) !void {
1646 const tracy = trace(@src());1801 const tracy = trace(@src());
1647 defer tracy.end();1802 defer tracy.end();
16481803
1649 for (self.symbols.items) |sym_index| {1804 const is_obj = macho_file.base.isObject();
1650 const sym = macho_file.getSymbol(sym_index);1805
1651 const file = sym.getFile(macho_file) orelse continue;1806 for (self.symbols.items, 0..) |*sym, i| {
1807 const ref = self.getSymbolRef(@intCast(i), macho_file);
1808 const file = ref.getFile(macho_file) orelse continue;
1652 if (file.getIndex() != self.index) continue;1809 if (file.getIndex() != self.index) continue;
1653 if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;1810 if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;
1654 if (sym.isSymbolStab(macho_file)) continue;1811 if (sym.isSymbolStab(macho_file)) continue;
1655 const name = sym.getName(macho_file);1812 const name = sym.getName(macho_file);
1813 if (name.len == 0) continue;
1656 // TODO in -r mode, we actually want to merge symbol names and emit only one1814 // TODO in -r mode, we actually want to merge symbol names and emit only one
1657 // work it out when emitting relocs1815 // work it out when emitting relocs
1658 if (name.len > 0 and1816 if ((name[0] == 'L' or name[0] == 'l' or
1659 (name[0] == 'L' or name[0] == 'l' or
1660 mem.startsWith(u8, name, "_OBJC_SELECTOR_REFERENCES_")) and1817 mem.startsWith(u8, name, "_OBJC_SELECTOR_REFERENCES_")) and
1661 !macho_file.base.isObject()) continue;1818 !is_obj)
1819 continue;
1662 sym.flags.output_symtab = true;1820 sym.flags.output_symtab = true;
1663 if (sym.isLocal()) {1821 if (sym.isLocal()) {
1664 try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);1822 try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
...@@ -1693,9 +1851,9 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {...@@ -1693,9 +1851,9 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
1693 self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1));1851 self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1));
1694 }1852 }
16951853
1696 for (self.symbols.items) |sym_index| {1854 for (self.symbols.items, 0..) |sym, i| {
1697 const sym = macho_file.getSymbol(sym_index);1855 const ref = self.getSymbolRef(@intCast(i), macho_file);
1698 const file = sym.getFile(macho_file) orelse continue;1856 const file = ref.getFile(macho_file) orelse continue;
1699 if (file.getIndex() != self.index) continue;1857 if (file.getIndex() != self.index) continue;
1700 if (!sym.flags.output_symtab) continue;1858 if (!sym.flags.output_symtab) continue;
1701 if (macho_file.base.isObject()) {1859 if (macho_file.base.isObject()) {
...@@ -1732,28 +1890,204 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {...@@ -1732,28 +1890,204 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
1732 }1890 }
1733}1891}
17341892
1735pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) error{Overflow}!void {1893pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {
1894 const tracy = trace(@src());
1895 defer tracy.end();
1896
1897 const gpa = macho_file.base.comp.gpa;
1898 const headers = self.sections.items(.header);
1899 const sections_data = try gpa.alloc([]const u8, headers.len);
1900 defer {
1901 for (sections_data) |data| {
1902 gpa.free(data);
1903 }
1904 gpa.free(sections_data);
1905 }
1906 @memset(sections_data, &[0]u8{});
1907 const file = macho_file.getFileHandle(self.file_handle);
1908
1909 for (headers, 0..) |header, n_sect| {
1910 if (header.isZerofill()) continue;
1911 const data = try gpa.alloc(u8, header.size);
1912 const amt = try file.preadAll(data, header.offset + self.offset);
1913 if (amt != data.len) return error.InputOutput;
1914 sections_data[n_sect] = data;
1915 }
1916 for (self.getAtoms()) |atom_index| {
1917 const atom = self.getAtom(atom_index) orelse continue;
1918 if (!atom.flags.alive) continue;
1919 const sect = atom.getInputSection(macho_file);
1920 if (sect.isZerofill()) continue;
1921 const off = atom.value;
1922 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
1923 const data = sections_data[atom.n_sect];
1924 @memcpy(buffer[off..][0..atom.size], data[atom.off..][0..atom.size]);
1925 try atom.resolveRelocs(macho_file, buffer[off..][0..atom.size]);
1926 }
1927}
1928
1929pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
1930 const tracy = trace(@src());
1931 defer tracy.end();
1932
1933 const gpa = macho_file.base.allocator;
1934 const headers = self.sections.items(.header);
1935 const sections_data = try gpa.alloc([]const u8, headers.len);
1936 defer {
1937 for (sections_data) |data| {
1938 gpa.free(data);
1939 }
1940 gpa.free(sections_data);
1941 }
1942 @memset(sections_data, &[0]u8{});
1943 const file = macho_file.getFileHandle(self.file_handle);
1944
1945 for (headers, 0..) |header, n_sect| {
1946 if (header.isZerofill()) continue;
1947 const data = try gpa.alloc(u8, header.size);
1948 const amt = try file.preadAll(data, header.offset + self.offset);
1949 if (amt != data.len) return error.InputOutput;
1950 sections_data[n_sect] = data;
1951 }
1952 for (self.getAtoms()) |atom_index| {
1953 const atom = self.getAtom(atom_index) orelse continue;
1954 if (!atom.flags.alive) continue;
1955 const sect = atom.getInputSection(macho_file);
1956 if (sect.isZerofill()) continue;
1957 const off = atom.value;
1958 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
1959 const data = sections_data[atom.n_sect];
1960 @memcpy(buffer[off..][0..atom.size], data[atom.off..][0..atom.size]);
1961 const relocs = macho_file.sections.items(.relocs)[atom.out_n_sect].items;
1962 const extra = atom.getExtra(macho_file);
1963 try atom.writeRelocs(macho_file, buffer[off..][0..atom.size], relocs[extra.rel_out_index..][0..extra.rel_out_count]);
1964 }
1965}
1966
1967pub fn calcCompactUnwindSizeRelocatable(self: *Object, macho_file: *MachO) void {
1968 const tracy = trace(@src());
1969 defer tracy.end();
1970
1971 const ctx = &self.compact_unwind_ctx;
1972
1973 for (self.unwind_records_indexes.items) |irec| {
1974 const rec = self.getUnwindRecord(irec);
1975 if (!rec.alive) continue;
1976
1977 ctx.rec_count += 1;
1978 ctx.reloc_count += 1;
1979 if (rec.getPersonality(macho_file)) |_| {
1980 ctx.reloc_count += 1;
1981 }
1982 if (rec.getLsdaAtom(macho_file)) |_| {
1983 ctx.reloc_count += 1;
1984 }
1985 }
1986}
1987
1988pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
1736 const tracy = trace(@src());1989 const tracy = trace(@src());
1737 defer tracy.end();1990 defer tracy.end();
17381991
1739 for (self.symbols.items) |sym_index| {1992 const addReloc = struct {
1740 const sym = macho_file.getSymbol(sym_index);1993 fn addReloc(offset: u32, cpu_arch: std.Target.Cpu.Arch) !macho.relocation_info {
1741 const file = sym.getFile(macho_file) orelse continue;1994 return .{
1995 .r_address = math.cast(i32, offset) orelse return error.Overflow,
1996 .r_symbolnum = 0,
1997 .r_pcrel = 0,
1998 .r_length = 3,
1999 .r_extern = 0,
2000 .r_type = switch (cpu_arch) {
2001 .aarch64 => @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
2002 .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
2003 else => unreachable,
2004 },
2005 };
2006 }
2007 }.addReloc;
2008
2009 const nsect = macho_file.unwind_info_sect_index.?;
2010 const buffer = macho_file.sections.items(.out)[nsect].items;
2011 const relocs = macho_file.sections.items(.relocs)[nsect].items;
2012
2013 var rec_index: u32 = self.compact_unwind_ctx.rec_index;
2014 var reloc_index: u32 = self.compact_unwind_ctx.reloc_index;
2015
2016 for (self.unwind_records_indexes.items) |irec| {
2017 const rec = self.getUnwindRecord(irec);
2018 if (!rec.alive) continue;
2019
2020 var out: macho.compact_unwind_entry = .{
2021 .rangeStart = 0,
2022 .rangeLength = rec.length,
2023 .compactUnwindEncoding = rec.enc.enc,
2024 .personalityFunction = 0,
2025 .lsda = 0,
2026 };
2027 defer rec_index += 1;
2028
2029 const offset = rec_index * @sizeOf(macho.compact_unwind_entry);
2030
2031 {
2032 // Function address
2033 const atom = rec.getAtom(macho_file);
2034 const addr = rec.getAtomAddress(macho_file);
2035 out.rangeStart = addr;
2036 var reloc = try addReloc(offset, macho_file.options.cpu_arch.?);
2037 reloc.r_symbolnum = atom.out_n_sect + 1;
2038 relocs[reloc_index] = reloc;
2039 reloc_index += 1;
2040 }
2041
2042 // Personality function
2043 if (rec.getPersonality(macho_file)) |sym| {
2044 const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow;
2045 var reloc = try addReloc(offset + 16, macho_file.options.cpu_arch.?);
2046 reloc.r_symbolnum = r_symbolnum;
2047 reloc.r_extern = 1;
2048 relocs[reloc_index] = reloc;
2049 reloc_index += 1;
2050 }
2051
2052 // LSDA address
2053 if (rec.getLsdaAtom(macho_file)) |atom| {
2054 const addr = rec.getLsdaAddress(macho_file);
2055 out.lsda = addr;
2056 var reloc = try addReloc(offset + 24, macho_file.options.cpu_arch.?);
2057 reloc.r_symbolnum = atom.out_n_sect + 1;
2058 relocs[reloc_index] = reloc;
2059 reloc_index += 1;
2060 }
2061
2062 @memcpy(buffer[offset..][0..@sizeOf(macho.compact_unwind_entry)], mem.asBytes(&out));
2063 }
2064}
2065
2066pub fn writeSymtab(self: Object, macho_file: *MachO) void {
2067 const tracy = trace(@src());
2068 defer tracy.end();
2069
2070 var n_strx = self.output_symtab_ctx.stroff;
2071 for (self.symbols.items, 0..) |sym, i| {
2072 const ref = self.getSymbolRef(@intCast(i), macho_file);
2073 const file = ref.getFile(macho_file) orelse continue;
1742 if (file.getIndex() != self.index) continue;2074 if (file.getIndex() != self.index) continue;
1743 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;2075 const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
1744 const n_strx = @as(u32, @intCast(ctx.strtab.items.len));2076 const out_sym = &macho_file.symtab.items[idx];
1745 ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
1746 ctx.strtab.appendAssumeCapacity(0);
1747 const out_sym = &ctx.symtab.items[idx];
1748 out_sym.n_strx = n_strx;2077 out_sym.n_strx = n_strx;
1749 sym.setOutputSym(macho_file, out_sym);2078 sym.setOutputSym(macho_file, out_sym);
2079 const name = sym.getName(macho_file);
2080 @memcpy(macho_file.strtab.items[n_strx..][0..name.len], name);
2081 n_strx += @intCast(name.len);
2082 macho_file.strtab.items[n_strx] = 0;
2083 n_strx += 1;
1750 }2084 }
17512085
1752 if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo())2086 if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo())
1753 try self.writeStabs(macho_file, ctx);2087 try self.writeStabs(n_strx, macho_file);
1754}2088}
17552089
1756pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{Overflow}!void {2090pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
1757 const writeFuncStab = struct {2091 const writeFuncStab = struct {
1758 inline fn writeFuncStab(2092 inline fn writeFuncStab(
1759 n_strx: u32,2093 n_strx: u32,
...@@ -1761,7 +2095,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1761,7 +2095,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1761 n_value: u64,2095 n_value: u64,
1762 size: u64,2096 size: u64,
1763 index: u32,2097 index: u32,
1764 context: anytype,2098 context: *MachO,
1765 ) void {2099 ) void {
1766 context.symtab.items[index] = .{2100 context.symtab.items[index] = .{
1767 .n_strx = 0,2101 .n_strx = 0,
...@@ -1795,6 +2129,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1795,6 +2129,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1795 }.writeFuncStab;2129 }.writeFuncStab;
17962130
1797 var index = self.output_symtab_ctx.istab;2131 var index = self.output_symtab_ctx.istab;
2132 var n_strx = stroff;
17982133
1799 if (self.compile_unit) |cu| {2134 if (self.compile_unit) |cu| {
1800 const comp_dir = cu.getCompDir(self);2135 const comp_dir = cu.getCompDir(self);
...@@ -1802,10 +2137,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1802,10 +2137,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
18022137
1803 // Open scope2138 // Open scope
1804 // N_SO comp_dir2139 // N_SO comp_dir
1805 var n_strx = @as(u32, @intCast(ctx.strtab.items.len));2140 macho_file.symtab.items[index] = .{
1806 ctx.strtab.appendSliceAssumeCapacity(comp_dir);
1807 ctx.strtab.appendAssumeCapacity(0);
1808 ctx.symtab.items[index] = .{
1809 .n_strx = n_strx,2141 .n_strx = n_strx,
1810 .n_type = macho.N_SO,2142 .n_type = macho.N_SO,
1811 .n_sect = 0,2143 .n_sect = 0,
...@@ -1813,11 +2145,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1813,11 +2145,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1813 .n_value = 0,2145 .n_value = 0,
1814 };2146 };
1815 index += 1;2147 index += 1;
2148 @memcpy(macho_file.strtab.items[n_strx..][0..comp_dir.len], comp_dir);
2149 n_strx += @intCast(comp_dir.len);
2150 macho_file.strtab.items[n_strx] = 0;
2151 n_strx += 1;
1816 // N_SO tu_name2152 // N_SO tu_name
1817 n_strx = @as(u32, @intCast(ctx.strtab.items.len));2153 macho_file.symtab.items[index] = .{
1818 ctx.strtab.appendSliceAssumeCapacity(tu_name);
1819 ctx.strtab.appendAssumeCapacity(0);
1820 ctx.symtab.items[index] = .{
1821 .n_strx = n_strx,2154 .n_strx = n_strx,
1822 .n_type = macho.N_SO,2155 .n_type = macho.N_SO,
1823 .n_sect = 0,2156 .n_sect = 0,
...@@ -1825,19 +2158,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1825,19 +2158,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1825 .n_value = 0,2158 .n_value = 0,
1826 };2159 };
1827 index += 1;2160 index += 1;
2161 @memcpy(macho_file.strtab.items[n_strx..][0..tu_name.len], tu_name);
2162 n_strx += @intCast(tu_name.len);
2163 macho_file.strtab.items[n_strx] = 0;
2164 n_strx += 1;
1828 // N_OSO path2165 // N_OSO path
1829 n_strx = @as(u32, @intCast(ctx.strtab.items.len));2166 macho_file.symtab.items[index] = .{
1830 if (self.in_archive) |ar| {
1831 ctx.strtab.appendSliceAssumeCapacity(ar.path);
1832 ctx.strtab.appendAssumeCapacity('(');
1833 ctx.strtab.appendSliceAssumeCapacity(self.path);
1834 ctx.strtab.appendAssumeCapacity(')');
1835 ctx.strtab.appendAssumeCapacity(0);
1836 } else {
1837 ctx.strtab.appendSliceAssumeCapacity(self.path);
1838 ctx.strtab.appendAssumeCapacity(0);
1839 }
1840 ctx.symtab.items[index] = .{
1841 .n_strx = n_strx,2167 .n_strx = n_strx,
1842 .n_type = macho.N_OSO,2168 .n_type = macho.N_OSO,
1843 .n_sect = 0,2169 .n_sect = 0,
...@@ -1845,10 +2171,27 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1845,10 +2171,27 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1845 .n_value = self.mtime,2171 .n_value = self.mtime,
1846 };2172 };
1847 index += 1;2173 index += 1;
2174 if (self.in_archive) |ar| {
2175 @memcpy(macho_file.strtab.items[n_strx..][0..ar.path.len], ar.path);
2176 n_strx += @intCast(ar.path.len);
2177 macho_file.strtab.items[n_strx] = '(';
2178 n_strx += 1;
2179 @memcpy(macho_file.strtab.items[n_strx..][0..self.path.len], self.path);
2180 n_strx += @intCast(self.path.len);
2181 macho_file.strtab.items[n_strx] = ')';
2182 n_strx += 1;
2183 macho_file.strtab.items[n_strx] = 0;
2184 n_strx += 1;
2185 } else {
2186 @memcpy(macho_file.strtab.items[n_strx..][0..self.path.len], self.path);
2187 n_strx += @intCast(self.path.len);
2188 macho_file.strtab.items[n_strx] = 0;
2189 n_strx += 1;
2190 }
18482191
1849 for (self.symbols.items) |sym_index| {2192 for (self.symbols.items, 0..) |sym, i| {
1850 const sym = macho_file.getSymbol(sym_index);2193 const ref = self.getSymbolRef(@intCast(i), macho_file);
1851 const file = sym.getFile(macho_file) orelse continue;2194 const file = ref.getFile(macho_file) orelse continue;
1852 if (file.getIndex() != self.index) continue;2195 if (file.getIndex() != self.index) continue;
1853 if (!sym.flags.output_symtab) continue;2196 if (!sym.flags.output_symtab) continue;
1854 if (macho_file.base.isObject()) {2197 if (macho_file.base.isObject()) {
...@@ -1858,17 +2201,17 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1858,17 +2201,17 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1858 const sect = macho_file.sections.items(.header)[sym.out_n_sect];2201 const sect = macho_file.sections.items(.header)[sym.out_n_sect];
1859 const sym_n_strx = n_strx: {2202 const sym_n_strx = n_strx: {
1860 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;2203 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
1861 const osym = ctx.symtab.items[symtab_index];2204 const osym = macho_file.symtab.items[symtab_index];
1862 break :n_strx osym.n_strx;2205 break :n_strx osym.n_strx;
1863 };2206 };
1864 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.out_n_sect + 1) else 0;
1865 const sym_n_value = sym.getAddress(.{}, macho_file);2208 const sym_n_value = sym.getAddress(.{}, macho_file);
1866 const sym_size = sym.getSize(macho_file);2209 const sym_size = sym.getSize(macho_file);
1867 if (sect.isCode()) {2210 if (sect.isCode()) {
1868 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);2211 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, macho_file);
1869 index += 4;2212 index += 4;
1870 } else if (sym.visibility == .global) {2213 } else if (sym.visibility == .global) {
1871 ctx.symtab.items[index] = .{2214 macho_file.symtab.items[index] = .{
1872 .n_strx = sym_n_strx,2215 .n_strx = sym_n_strx,
1873 .n_type = macho.N_GSYM,2216 .n_type = macho.N_GSYM,
1874 .n_sect = sym_n_sect,2217 .n_sect = sym_n_sect,
...@@ -1877,7 +2220,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1877,7 +2220,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1877 };2220 };
1878 index += 1;2221 index += 1;
1879 } else {2222 } else {
1880 ctx.symtab.items[index] = .{2223 macho_file.symtab.items[index] = .{
1881 .n_strx = sym_n_strx,2224 .n_strx = sym_n_strx,
1882 .n_type = macho.N_STSYM,2225 .n_type = macho.N_STSYM,
1883 .n_sect = sym_n_sect,2226 .n_sect = sym_n_sect,
...@@ -1890,7 +2233,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1890,7 +2233,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
18902233
1891 // Close scope2234 // Close scope
1892 // N_SO2235 // N_SO
1893 ctx.symtab.items[index] = .{2236 macho_file.symtab.items[index] = .{
1894 .n_strx = 0,2237 .n_strx = 0,
1895 .n_type = macho.N_SO,2238 .n_type = macho.N_SO,
1896 .n_sect = 0,2239 .n_sect = 0,
...@@ -1901,12 +2244,13 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1901,12 +2244,13 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1901 assert(self.hasSymbolStabs());2244 assert(self.hasSymbolStabs());
19022245
1903 for (self.stab_files.items) |sf| {2246 for (self.stab_files.items) |sf| {
2247 const comp_dir = sf.getCombDir(self);
2248 const tu_name = sf.getTuName(self);
2249 const oso_path = sf.getOsoPath(self);
2250
1904 // Open scope2251 // Open scope
1905 // N_SO comp_dir2252 // N_SO comp_dir
1906 var n_strx = @as(u32, @intCast(ctx.strtab.items.len));2253 macho_file.symtab.items[index] = .{
1907 ctx.strtab.appendSliceAssumeCapacity(sf.getCompDir(self));
1908 ctx.strtab.appendAssumeCapacity(0);
1909 ctx.symtab.items[index] = .{
1910 .n_strx = n_strx,2254 .n_strx = n_strx,
1911 .n_type = macho.N_SO,2255 .n_type = macho.N_SO,
1912 .n_sect = 0,2256 .n_sect = 0,
...@@ -1914,11 +2258,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1914,11 +2258,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1914 .n_value = 0,2258 .n_value = 0,
1915 };2259 };
1916 index += 1;2260 index += 1;
2261 @memcpy(macho_file.strtab.items[n_strx..][0..comp_dir.len], comp_dir);
2262 n_strx += @intCast(comp_dir.len);
2263 macho_file.strtab.items[n_strx] = 0;
2264 n_strx += 1;
1917 // N_SO tu_name2265 // N_SO tu_name
1918 n_strx = @as(u32, @intCast(ctx.strtab.items.len));2266 macho_file.symtab.items[index] = .{
1919 ctx.strtab.appendSliceAssumeCapacity(sf.getTuName(self));
1920 ctx.strtab.appendAssumeCapacity(0);
1921 ctx.symtab.items[index] = .{
1922 .n_strx = n_strx,2267 .n_strx = n_strx,
1923 .n_type = macho.N_SO,2268 .n_type = macho.N_SO,
1924 .n_sect = 0,2269 .n_sect = 0,
...@@ -1926,11 +2271,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1926,11 +2271,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1926 .n_value = 0,2271 .n_value = 0,
1927 };2272 };
1928 index += 1;2273 index += 1;
2274 @memcpy(macho_file.strtab.items[n_strx..][0..tu_name.len], tu_name);
2275 n_strx += @intCast(tu_name.len);
2276 macho_file.strtab.items[n_strx] = 0;
2277 n_strx += 1;
1929 // N_OSO path2278 // N_OSO path
1930 n_strx = @as(u32, @intCast(ctx.strtab.items.len));2279 macho_file.symtab.items[index] = .{
1931 ctx.strtab.appendSliceAssumeCapacity(sf.getOsoPath(self));
1932 ctx.strtab.appendAssumeCapacity(0);
1933 ctx.symtab.items[index] = .{
1934 .n_strx = n_strx,2280 .n_strx = n_strx,
1935 .n_type = macho.N_OSO,2281 .n_type = macho.N_OSO,
1936 .n_sect = 0,2282 .n_sect = 0,
...@@ -1938,6 +2284,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1938,6 +2284,10 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1938 .n_value = sf.getOsoModTime(self),2284 .n_value = sf.getOsoModTime(self),
1939 };2285 };
1940 index += 1;2286 index += 1;
2287 @memcpy(macho_file.strtab.items[n_strx..][0..oso_path.len], oso_path);
2288 n_strx += @intCast(oso_path.len);
2289 macho_file.strtab.items[n_strx] = 0;
2290 n_strx += 1;
19412291
1942 for (sf.stabs.items) |stab| {2292 for (sf.stabs.items) |stab| {
1943 const sym = stab.getSymbol(macho_file) orelse continue;2293 const sym = stab.getSymbol(macho_file) orelse continue;
...@@ -1946,17 +2296,17 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1946,17 +2296,17 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1946 if (!sym.flags.output_symtab) continue;2296 if (!sym.flags.output_symtab) continue;
1947 const sym_n_strx = n_strx: {2297 const sym_n_strx = n_strx: {
1948 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;2298 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
1949 const osym = ctx.symtab.items[symtab_index];2299 const osym = macho_file.symtab.items[symtab_index];
1950 break :n_strx osym.n_strx;2300 break :n_strx osym.n_strx;
1951 };2301 };
1952 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.out_n_sect + 1) else 0;
1953 const sym_n_value = sym.getAddress(.{}, macho_file);2303 const sym_n_value = sym.getAddress(.{}, macho_file);
1954 const sym_size = sym.getSize(macho_file);2304 const sym_size = sym.getSize(macho_file);
1955 if (stab.is_func) {2305 if (stab.is_func) {
1956 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);2306 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, macho_file);
1957 index += 4;2307 index += 4;
1958 } else if (sym.visibility == .global) {2308 } else if (sym.visibility == .global) {
1959 ctx.symtab.items[index] = .{2309 macho_file.symtab.items[index] = .{
1960 .n_strx = sym_n_strx,2310 .n_strx = sym_n_strx,
1961 .n_type = macho.N_GSYM,2311 .n_type = macho.N_GSYM,
1962 .n_sect = sym_n_sect,2312 .n_sect = sym_n_sect,
...@@ -1965,7 +2315,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1965,7 +2315,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1965 };2315 };
1966 index += 1;2316 index += 1;
1967 } else {2317 } else {
1968 ctx.symtab.items[index] = .{2318 macho_file.symtab.items[index] = .{
1969 .n_strx = sym_n_strx,2319 .n_strx = sym_n_strx,
1970 .n_type = macho.N_STSYM,2320 .n_type = macho.N_STSYM,
1971 .n_sect = sym_n_sect,2321 .n_sect = sym_n_sect,
...@@ -1978,7 +2328,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1978,7 +2328,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
19782328
1979 // Close scope2329 // Close scope
1980 // N_SO2330 // N_SO
1981 ctx.symtab.items[index] = .{2331 macho_file.symtab.items[index] = .{
1982 .n_strx = 0,2332 .n_strx = 0,
1983 .n_type = macho.N_SO,2333 .n_type = macho.N_SO,
1984 .n_sect = 0,2334 .n_sect = 0,
...@@ -1990,36 +2340,6 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1990,36 +2340,6 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1990 }2340 }
1991}2341}
19922342
1993fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 {
1994 const gpa = macho_file.base.comp.gpa;
1995 const slice = self.sections.slice();
1996 assert(index < slice.items(.header).len);
1997 const sect = slice.items(.header)[index];
1998 const handle = macho_file.getFileHandle(self.file_handle);
1999 const size = math.cast(usize, sect.size) orelse return error.Overflow;
2000 const buffer = try gpa.alloc(u8, size);
2001 errdefer gpa.free(buffer);
2002 const amt = try handle.preadAll(buffer, sect.offset + self.offset);
2003 if (amt != buffer.len) return error.InputOutput;
2004 return buffer;
2005}
2006
2007pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer: []u8) !void {
2008 assert(buffer.len == atom.size);
2009 const slice = self.sections.slice();
2010 const handle = macho_file.getFileHandle(self.file_handle);
2011 const sect = slice.items(.header)[atom.n_sect];
2012 const amt = try handle.preadAll(buffer, sect.offset + self.offset + atom.off);
2013 if (amt != buffer.len) return error.InputOutput;
2014}
2015
2016pub fn getAtomRelocs(self: *const Object, atom: Atom, macho_file: *MachO) []const Relocation {
2017 if (!atom.flags.relocs) return &[0]Relocation{};
2018 const extra = atom.getExtra(macho_file).?;
2019 const relocs = self.sections.items(.relocs)[atom.n_sect];
2020 return relocs.items[extra.rel_index..][0..extra.rel_count];
2021}
2022
2023fn addString(self: *Object, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 {2343fn addString(self: *Object, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 {
2024 const off: u32 = @intCast(self.strtab.items.len);2344 const off: u32 = @intCast(self.strtab.items.len);
2025 try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);2345 try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);
...@@ -2073,6 +2393,143 @@ pub fn asFile(self: *Object) File {...@@ -2073,6 +2393,143 @@ pub fn asFile(self: *Object) File {
2073 return .{ .object = self };2393 return .{ .object = self };
2074}2394}
20752395
2396const AddAtomArgs = struct {
2397 name: MachO.String,
2398 n_sect: u8,
2399 off: u64,
2400 size: u64,
2401 alignment: u32,
2402};
2403
2404fn addAtom(self: *Object, allocator: Allocator, args: AddAtomArgs) !Atom.Index {
2405 const atom_index: Atom.Index = @intCast(self.atoms.items.len);
2406 const atom = try self.atoms.addOne(allocator);
2407 atom.* = .{
2408 .file = self.index,
2409 .atom_index = atom_index,
2410 .name = args.name,
2411 .n_sect = args.n_sect,
2412 .size = args.size,
2413 .off = args.off,
2414 .extra = try self.addAtomExtra(allocator, .{}),
2415 .alignment = args.alignment,
2416 };
2417 return atom_index;
2418}
2419
2420pub fn getAtom(self: *Object, atom_index: Atom.Index) ?*Atom {
2421 if (atom_index == 0) return null;
2422 assert(atom_index < self.atoms.items.len);
2423 return &self.atoms.items[atom_index];
2424}
2425
2426pub fn getAtoms(self: *Object) []const Atom.Index {
2427 return self.atoms_indexes.items;
2428}
2429
2430fn addAtomExtra(self: *Object, allocator: Allocator, extra: Atom.Extra) !u32 {
2431 const fields = @typeInfo(Atom.Extra).Struct.fields;
2432 try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
2433 return self.addAtomExtraAssumeCapacity(extra);
2434}
2435
2436fn addAtomExtraAssumeCapacity(self: *Object, extra: Atom.Extra) u32 {
2437 const index = @as(u32, @intCast(self.atoms_extra.items.len));
2438 const fields = @typeInfo(Atom.Extra).Struct.fields;
2439 inline for (fields) |field| {
2440 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
2441 u32 => @field(extra, field.name),
2442 else => @compileError("bad field type"),
2443 });
2444 }
2445 return index;
2446}
2447
2448pub fn getAtomExtra(self: Object, index: u32) Atom.Extra {
2449 const fields = @typeInfo(Atom.Extra).Struct.fields;
2450 var i: usize = index;
2451 var result: Atom.Extra = undefined;
2452 inline for (fields) |field| {
2453 @field(result, field.name) = switch (field.type) {
2454 u32 => self.atoms_extra.items[i],
2455 else => @compileError("bad field type"),
2456 };
2457 i += 1;
2458 }
2459 return result;
2460}
2461
2462pub fn setAtomExtra(self: *Object, index: u32, extra: Atom.Extra) void {
2463 assert(index > 0);
2464 const fields = @typeInfo(Atom.Extra).Struct.fields;
2465 inline for (fields, 0..) |field, i| {
2466 self.atoms_extra.items[index + i] = switch (field.type) {
2467 u32 => @field(extra, field.name),
2468 else => @compileError("bad field type"),
2469 };
2470 }
2471}
2472
2473fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index {
2474 try self.symbols.ensureUnusedCapacity(allocator, 1);
2475 return self.addSymbolAssumeCapacity();
2476}
2477
2478fn addSymbolAssumeCapacity(self: *Object) Symbol.Index {
2479 const index: Symbol.Index = @intCast(self.symbols.items.len);
2480 const symbol = self.symbols.addOneAssumeCapacity();
2481 symbol.* = .{ .file = self.index };
2482 return index;
2483}
2484
2485pub fn getSymbolRef(self: Object, index: Symbol.Index, macho_file: *MachO) MachO.Ref {
2486 const global_index = self.globals.items[index];
2487 if (macho_file.resolver.get(global_index)) |ref| return ref;
2488 return .{ .index = index, .file = self.index };
2489}
2490
2491pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 {
2492 const fields = @typeInfo(Symbol.Extra).Struct.fields;
2493 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
2494 return self.addSymbolExtraAssumeCapacity(extra);
2495}
2496
2497fn addSymbolExtraAssumeCapacity(self: *Object, extra: Symbol.Extra) u32 {
2498 const index = @as(u32, @intCast(self.symbols_extra.items.len));
2499 const fields = @typeInfo(Symbol.Extra).Struct.fields;
2500 inline for (fields) |field| {
2501 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
2502 u32 => @field(extra, field.name),
2503 else => @compileError("bad field type"),
2504 });
2505 }
2506 return index;
2507}
2508
2509pub fn getSymbolExtra(self: Object, index: u32) Symbol.Extra {
2510 const fields = @typeInfo(Symbol.Extra).Struct.fields;
2511 var i: usize = index;
2512 var result: Symbol.Extra = undefined;
2513 inline for (fields) |field| {
2514 @field(result, field.name) = switch (field.type) {
2515 u32 => self.symbols_extra.items[i],
2516 else => @compileError("bad field type"),
2517 };
2518 i += 1;
2519 }
2520 return result;
2521}
2522
2523pub fn setSymbolExtra(self: *Object, index: u32, extra: Symbol.Extra) void {
2524 const fields = @typeInfo(Symbol.Extra).Struct.fields;
2525 inline for (fields, 0..) |field, i| {
2526 self.symbols_extra.items[index + i] = switch (field.type) {
2527 u32 => @field(extra, field.name),
2528 else => @compileError("bad field type"),
2529 };
2530 }
2531}
2532
2076fn addUnwindRecord(self: *Object, allocator: Allocator) !UnwindInfo.Record.Index {2533fn addUnwindRecord(self: *Object, allocator: Allocator) !UnwindInfo.Record.Index {
2077 try self.unwind_records.ensureUnusedCapacity(allocator, 1);2534 try self.unwind_records.ensureUnusedCapacity(allocator, 1);
2078 return self.addUnwindRecordAssumeCapacity();2535 return self.addUnwindRecordAssumeCapacity();
...@@ -2124,10 +2581,11 @@ fn formatAtoms(...@@ -2124,10 +2581,11 @@ fn formatAtoms(
2124 _ = unused_fmt_string;2581 _ = unused_fmt_string;
2125 _ = options;2582 _ = options;
2126 const object = ctx.object;2583 const object = ctx.object;
2584 const macho_file = ctx.macho_file;
2127 try writer.writeAll(" atoms\n");2585 try writer.writeAll(" atoms\n");
2128 for (object.atoms.items) |atom_index| {2586 for (object.getAtoms()) |atom_index| {
2129 const atom = ctx.macho_file.getAtom(atom_index).?;2587 const atom = object.getAtom(atom_index) orelse continue;
2130 try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)});2588 try writer.print(" {}\n", .{atom.fmt(macho_file)});
2131 }2589 }
2132}2590}
21332591
...@@ -2214,10 +2672,26 @@ fn formatSymtab(...@@ -2214,10 +2672,26 @@ fn formatSymtab(
2214 _ = unused_fmt_string;2672 _ = unused_fmt_string;
2215 _ = options;2673 _ = options;
2216 const object = ctx.object;2674 const object = ctx.object;
2675 const macho_file = ctx.macho_file;
2217 try writer.writeAll(" symbols\n");2676 try writer.writeAll(" symbols\n");
2218 for (object.symbols.items) |index| {2677 for (object.symbols.items, 0..) |sym, i| {
2219 const sym = ctx.macho_file.getSymbol(index);2678 const ref = object.getSymbolRef(@intCast(i), macho_file);
2220 try writer.print(" {}\n", .{sym.fmt(ctx.macho_file)});2679 if (ref.getFile(macho_file) == null) {
2680 // TODO any better way of handling this?
2681 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
2682 } else {
2683 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
2684 }
2685 }
2686 for (object.stab_files.items) |sf| {
2687 try writer.print(" stabs({s},{s},{s})\n", .{
2688 sf.getCompDir(object),
2689 sf.getTuName(object),
2690 sf.getOsoPath(object),
2691 });
2692 for (sf.stabs.items) |stab| {
2693 try writer.print(" {}", .{stab.fmt(object)});
2694 }
2221 }2695 }
2222}2696}
22232697
...@@ -2286,8 +2760,47 @@ const StabFile = struct {...@@ -2286,8 +2760,47 @@ const StabFile = struct {
2286 is_func: bool = true,2760 is_func: bool = true,
2287 symbol: ?Symbol.Index = null,2761 symbol: ?Symbol.Index = null,
22882762
2289 fn getSymbol(stab: Stab, macho_file: *MachO) ?*Symbol {2763 fn getSymbol(stab: Stab, object: *const Object) ?*Symbol {
2290 return if (stab.symbol) |s| macho_file.getSymbol(s) else null;2764 const index = stab.index orelse return null;
2765 return &object.symbols.items[index];
2766 }
2767
2768 pub fn format(
2769 stab: Stab,
2770 comptime unused_fmt_string: []const u8,
2771 options: std.fmt.FormatOptions,
2772 writer: anytype,
2773 ) !void {
2774 _ = stab;
2775 _ = unused_fmt_string;
2776 _ = options;
2777 _ = writer;
2778 @compileError("do not format stabs directly");
2779 }
2780
2781 const StabFormatContext = struct { Stab, *const Object };
2782
2783 pub fn fmt(stab: Stab, object: *const Object) std.fmt.Formatter(format2) {
2784 return .{ .data = .{ stab, object } };
2785 }
2786
2787 fn format2(
2788 ctx: StabFormatContext,
2789 comptime unused_fmt_string: []const u8,
2790 options: std.fmt.FormatOptions,
2791 writer: anytype,
2792 ) !void {
2793 _ = unused_fmt_string;
2794 _ = options;
2795 const stab, const object = ctx;
2796 const sym = stab.getSymbol(object).?;
2797 if (stab.is_func) {
2798 try writer.print("func({d})", .{stab.index.?});
2799 } else if (sym.visibility == .global) {
2800 try writer.print("gsym({d})", .{stab.index.?});
2801 } else {
2802 try writer.print("stsym({d})", .{stab.index.?});
2803 }
2291 }2804 }
2292 };2805 };
2293};2806};
...@@ -2310,6 +2823,13 @@ const InArchive = struct {...@@ -2310,6 +2823,13 @@ const InArchive = struct {
2310 size: u32,2823 size: u32,
2311};2824};
23122825
2826const CompactUnwindCtx = struct {
2827 rec_index: u32 = 0,
2828 rec_count: u32 = 0,
2829 reloc_index: u32 = 0,
2830 reloc_count: u32 = 0,
2831};
2832
2313const x86_64 = struct {2833const x86_64 = struct {
2314 fn parseRelocs(2834 fn parseRelocs(
2315 self: *const Object,2835 self: *const Object,