| ... | ... | @@ -26,70 +26,51 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c |
| 26 | 26 | return; |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | | @panic("TODO -r mode"); |
| 30 | | |
| 31 | | // for (positionals.items) |obj| { |
| 32 | | // macho_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { |
| 33 | | // error.MalformedObject, |
| 34 | | // error.MalformedArchive, |
| 35 | | // error.InvalidCpuArch, |
| 36 | | // error.InvalidTarget, |
| 37 | | // => continue, // already reported |
| 38 | | // error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an object file", .{}), |
| 39 | | // else => |e| try macho_file.reportParseError( |
| 40 | | // obj.path, |
| 41 | | // "unexpected error: parsing input file failed with error {s}", |
| 42 | | // .{@errorName(e)}, |
| 43 | | // ), |
| 44 | | // }; |
| 45 | | // } |
| 29 | for (positionals.items) |obj| { |
| 30 | macho_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { |
| 31 | error.MalformedObject, |
| 32 | error.MalformedArchive, |
| 33 | error.InvalidCpuArch, |
| 34 | error.InvalidTarget, |
| 35 | => continue, // already reported |
| 36 | error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an object file", .{}), |
| 37 | else => |e| try macho_file.reportParseError( |
| 38 | obj.path, |
| 39 | "unexpected error: parsing input file failed with error {s}", |
| 40 | .{@errorName(e)}, |
| 41 | ), |
| 42 | }; |
| 43 | } |
| 46 | 44 | |
| 47 | | // if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 48 | | |
| 49 | | // try macho_file.addUndefinedGlobals(); |
| 50 | | // try macho_file.resolveSymbols(); |
| 51 | | // try macho_file.parseDebugInfo(); |
| 52 | | // try macho_file.dedupLiterals(); |
| 53 | | // markExports(macho_file); |
| 54 | | // claimUnresolved(macho_file); |
| 55 | | // try initOutputSections(macho_file); |
| 56 | | // try macho_file.sortSections(); |
| 57 | | // try macho_file.addAtomsToSections(); |
| 58 | | // try calcSectionSizes(macho_file); |
| 59 | | |
| 60 | | // try createSegment(macho_file); |
| 61 | | // try allocateSections(macho_file); |
| 62 | | // allocateSegment(macho_file); |
| 63 | | |
| 64 | | // var off = off: { |
| 65 | | // const seg = macho_file.segments.items[0]; |
| 66 | | // const off = math.cast(u32, seg.fileoff + seg.filesize) orelse return error.Overflow; |
| 67 | | // break :off mem.alignForward(u32, off, @alignOf(macho.relocation_info)); |
| 68 | | // }; |
| 69 | | // off = allocateSectionsRelocs(macho_file, off); |
| 70 | | |
| 71 | | // if (build_options.enable_logging) { |
| 72 | | // state_log.debug("{}", .{macho_file.dumpState()}); |
| 73 | | // } |
| 45 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 74 | 46 | |
| 75 | | // try macho_file.calcSymtabSize(); |
| 76 | | // try writeAtoms(macho_file); |
| 77 | | // try writeCompactUnwind(macho_file); |
| 78 | | // try writeEhFrame(macho_file); |
| 47 | try macho_file.resolveSymbols(); |
| 48 | try macho_file.dedupLiterals(); |
| 49 | markExports(macho_file); |
| 50 | claimUnresolved(macho_file); |
| 51 | try initOutputSections(macho_file); |
| 52 | try macho_file.sortSections(); |
| 53 | try macho_file.addAtomsToSections(); |
| 54 | try calcSectionSizes(macho_file); |
| 79 | 55 | |
| 80 | | // off = mem.alignForward(u32, off, @alignOf(u64)); |
| 81 | | // off = try macho_file.writeDataInCode(0, off); |
| 82 | | // off = mem.alignForward(u32, off, @alignOf(u64)); |
| 83 | | // off = try macho_file.writeSymtab(off); |
| 84 | | // off = mem.alignForward(u32, off, @alignOf(u64)); |
| 85 | | // off = try macho_file.writeStrtab(off); |
| 56 | try createSegment(macho_file); |
| 57 | try allocateSections(macho_file); |
| 58 | allocateSegment(macho_file); |
| 86 | 59 | |
| 87 | | // // In order to please Apple ld (and possibly other MachO linkers in the wild), |
| 88 | | // // we will now sanitize segment names of Zig-specific segments. |
| 89 | | // sanitizeZigSections(macho_file); |
| 60 | if (build_options.enable_logging) { |
| 61 | state_log.debug("{}", .{macho_file.dumpState()}); |
| 62 | } |
| 90 | 63 | |
| 91 | | // const ncmds, const sizeofcmds = try writeLoadCommands(macho_file); |
| 92 | | // try writeHeader(macho_file, ncmds, sizeofcmds); |
| 64 | try writeSections(macho_file); |
| 65 | sortRelocs(macho_file); |
| 66 | try writeSectionsToFile(macho_file); |
| 67 | |
| 68 | // In order to please Apple ld (and possibly other MachO linkers in the wild), |
| 69 | // we will now sanitize segment names of Zig-specific segments. |
| 70 | sanitizeZigSections(macho_file); |
| 71 | |
| 72 | const ncmds, const sizeofcmds = try writeLoadCommands(macho_file); |
| 73 | try writeHeader(macho_file, ncmds, sizeofcmds); |
| 93 | 74 | } |
| 94 | 75 | |
| 95 | 76 | pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { |
| ... | ... | @@ -353,9 +334,9 @@ pub fn claimUnresolved(macho_file: *MachO) void { |
| 353 | 334 | |
| 354 | 335 | fn initOutputSections(macho_file: *MachO) !void { |
| 355 | 336 | for (macho_file.objects.items) |index| { |
| 356 | | const object = macho_file.getFile(index).?.object; |
| 357 | | for (object.atoms.items) |atom_index| { |
| 358 | | const atom = macho_file.getAtom(atom_index) orelse continue; |
| 337 | const file = macho_file.getFile(index).?; |
| 338 | for (file.getAtoms()) |atom_index| { |
| 339 | const atom = file.getAtom(atom_index) orelse continue; |
| 359 | 340 | if (!atom.flags.alive) continue; |
| 360 | 341 | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file); |
| 361 | 342 | } |
| ... | ... | @@ -383,69 +364,141 @@ fn calcSectionSizes(macho_file: *MachO) !void { |
| 383 | 364 | const tracy = trace(@src()); |
| 384 | 365 | defer tracy.end(); |
| 385 | 366 | |
| 386 | | const slice = macho_file.sections.slice(); |
| 387 | | for (slice.items(.header), slice.items(.atoms)) |*header, atoms| { |
| 367 | for (macho_file.sections.items(.atoms), 0..) |atoms, i| { |
| 388 | 368 | if (atoms.items.len == 0) continue; |
| 389 | | for (atoms.items) |atom_index| { |
| 390 | | const atom = macho_file.getAtom(atom_index).?; |
| 391 | | const atom_alignment = atom.alignment.toByteUnits() orelse 1; |
| 392 | | const offset = mem.alignForward(u64, header.size, atom_alignment); |
| 393 | | const padding = offset - header.size; |
| 394 | | atom.value = offset; |
| 395 | | header.size += padding + atom.size; |
| 396 | | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 397 | | header.nreloc += atom.calcNumRelocs(macho_file); |
| 398 | | } |
| 369 | calcSectionSize(macho_file, @intCast(i)); |
| 399 | 370 | } |
| 400 | 371 | |
| 401 | | if (macho_file.unwind_info_sect_index) |index| { |
| 402 | | calcCompactUnwindSize(macho_file, index); |
| 372 | if (macho_file.eh_frame_sect_index) |_| { |
| 373 | try calcEhFrameSize(macho_file); |
| 403 | 374 | } |
| 404 | 375 | |
| 405 | | if (macho_file.eh_frame_sect_index) |index| { |
| 406 | | const sect = &macho_file.sections.items(.header)[index]; |
| 407 | | sect.size = try eh_frame.calcSize(macho_file); |
| 408 | | sect.@"align" = 3; |
| 409 | | sect.nreloc = eh_frame.calcNumRelocs(macho_file); |
| 376 | for (macho_file.objects.items) |index| { |
| 377 | if (macho_file.unwind_info_sect_index) |_| { |
| 378 | macho_file.getFile(index).?.object.calcCompactUnwindSizeRelocatable(macho_file); |
| 379 | } |
| 380 | macho_file.getFile(index).?.calcSymtabSize(macho_file); |
| 410 | 381 | } |
| 411 | 382 | |
| 412 | | if (macho_file.getZigObject()) |zo| { |
| 413 | | for (zo.atoms.items) |atom_index| { |
| 414 | | const atom = macho_file.getAtom(atom_index) orelse continue; |
| 415 | | if (!atom.flags.alive) continue; |
| 416 | | const header = &macho_file.sections.items(.header)[atom.out_n_sect]; |
| 417 | | if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; |
| 418 | | header.nreloc += atom.calcNumRelocs(macho_file); |
| 419 | | } |
| 383 | try macho_file.data_in_code.updateSize(macho_file); |
| 384 | |
| 385 | calcCompactUnwindSize(macho_file); |
| 386 | calcSymtabSize(macho_file); |
| 387 | |
| 388 | // TODO |
| 389 | // if (macho_file.getZigObject()) |zo| { |
| 390 | // for (zo.atoms.items) |atom_index| { |
| 391 | // const atom = macho_file.getAtom(atom_index) orelse continue; |
| 392 | // if (!atom.flags.alive) continue; |
| 393 | // const header = &macho_file.sections.items(.header)[atom.out_n_sect]; |
| 394 | // if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; |
| 395 | // header.nreloc += atom.calcNumRelocs(macho_file); |
| 396 | // } |
| 397 | // } |
| 398 | } |
| 399 | |
| 400 | fn calcSectionSize(macho_file: *MachO, sect_id: u8) void { |
| 401 | const tracy = trace(@src()); |
| 402 | defer tracy.end(); |
| 403 | |
| 404 | const slice = macho_file.sections.slice(); |
| 405 | const header = &slice.items(.header)[sect_id]; |
| 406 | const atoms = slice.items(.atoms)[sect_id].items; |
| 407 | for (atoms) |ref| { |
| 408 | const atom = ref.getAtom(macho_file).?; |
| 409 | const atom_alignment = atom.alignment.toByteUnits() orelse 1; |
| 410 | const offset = mem.alignForward(u64, header.size, atom_alignment); |
| 411 | const padding = offset - header.size; |
| 412 | atom.value = offset; |
| 413 | header.size += padding + atom.size; |
| 414 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 415 | const nreloc = atom.calcNumRelocs(macho_file); |
| 416 | atom.addExtra(.{ .rel_out_index = header.nreloc, .rel_out_count = nreloc }, macho_file); |
| 417 | header.nreloc += nreloc; |
| 420 | 418 | } |
| 421 | 419 | } |
| 422 | 420 | |
| 423 | | fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { |
| 424 | | var size: u32 = 0; |
| 421 | fn calcEhFrameSize(macho_file: *MachO) !void { |
| 422 | const tracy = trace(@src()); |
| 423 | defer tracy.end(); |
| 424 | |
| 425 | const header = &macho_file.sections.items(.header)[macho_file.eh_frame_sect_index.?]; |
| 426 | header.size = try eh_frame.calcSize(macho_file); |
| 427 | header.@"align" = 3; |
| 428 | header.nreloc = eh_frame.calcNumRelocs(macho_file); |
| 429 | } |
| 430 | |
| 431 | fn calcCompactUnwindSize(macho_file: *MachO) void { |
| 432 | const tracy = trace(@src()); |
| 433 | defer tracy.end(); |
| 434 | |
| 435 | var nrec: u32 = 0; |
| 425 | 436 | var nreloc: u32 = 0; |
| 426 | 437 | |
| 427 | 438 | for (macho_file.objects.items) |index| { |
| 428 | | const object = macho_file.getFile(index).?.object; |
| 429 | | for (object.unwind_records_indexes.items) |irec| { |
| 430 | | const rec = object.getUnwindRecord(irec); |
| 431 | | if (!rec.alive) continue; |
| 432 | | size += @sizeOf(macho.compact_unwind_entry); |
| 433 | | nreloc += 1; |
| 434 | | if (rec.getPersonality(macho_file)) |_| { |
| 435 | | nreloc += 1; |
| 436 | | } |
| 437 | | if (rec.getLsdaAtom(macho_file)) |_| { |
| 438 | | nreloc += 1; |
| 439 | | } |
| 440 | | } |
| 439 | const ctx = &macho_file.getFile(index).?.object.compact_unwind_ctx; |
| 440 | ctx.rec_index = nrec; |
| 441 | ctx.reloc_index = nreloc; |
| 442 | nrec += ctx.rec_count; |
| 443 | nreloc += ctx.reloc_count; |
| 441 | 444 | } |
| 442 | 445 | |
| 443 | | const sect = &macho_file.sections.items(.header)[sect_index]; |
| 444 | | sect.size = size; |
| 446 | const sect = &macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?]; |
| 447 | sect.size = nrec * @sizeOf(macho.compact_unwind_entry); |
| 445 | 448 | sect.nreloc = nreloc; |
| 446 | 449 | sect.@"align" = 3; |
| 447 | 450 | } |
| 448 | 451 | |
| 452 | fn calcSymtabSize(macho_file: *MachO) void { |
| 453 | const tracy = trace(@src()); |
| 454 | defer tracy.end(); |
| 455 | |
| 456 | var nlocals: u32 = 0; |
| 457 | var nstabs: u32 = 0; |
| 458 | var nexports: u32 = 0; |
| 459 | var nimports: u32 = 0; |
| 460 | var strsize: u32 = 1; |
| 461 | |
| 462 | for (macho_file.objects.items) |index| { |
| 463 | const object = macho_file.getFile(index).?.object; |
| 464 | const ctx = &object.output_symtab_ctx; |
| 465 | ctx.ilocal = nlocals; |
| 466 | ctx.istab = nstabs; |
| 467 | ctx.iexport = nexports; |
| 468 | ctx.iimport = nimports; |
| 469 | ctx.stroff = strsize; |
| 470 | nlocals += ctx.nlocals; |
| 471 | nstabs += ctx.nstabs; |
| 472 | nexports += ctx.nexports; |
| 473 | nimports += ctx.nimports; |
| 474 | strsize += ctx.strsize; |
| 475 | } |
| 476 | |
| 477 | for (macho_file.objects.items) |index| { |
| 478 | const object = macho_file.getFile(index).?.object; |
| 479 | const ctx = &object.output_symtab_ctx; |
| 480 | ctx.istab += nlocals; |
| 481 | ctx.iexport += nlocals + nstabs; |
| 482 | ctx.iimport += nlocals + nstabs + nexports; |
| 483 | } |
| 484 | |
| 485 | { |
| 486 | const cmd = &macho_file.symtab_cmd; |
| 487 | cmd.nsyms = nlocals + nstabs + nexports + nimports; |
| 488 | cmd.strsize = strsize; |
| 489 | } |
| 490 | |
| 491 | { |
| 492 | const cmd = &macho_file.dysymtab_cmd; |
| 493 | cmd.ilocalsym = 0; |
| 494 | cmd.nlocalsym = nlocals + nstabs; |
| 495 | cmd.iextdefsym = nlocals + nstabs; |
| 496 | cmd.nextdefsym = nexports; |
| 497 | cmd.iundefsym = nlocals + nstabs + nexports; |
| 498 | cmd.nundefsym = nimports; |
| 499 | } |
| 500 | } |
| 501 | |
| 449 | 502 | fn allocateSections(macho_file: *MachO) !void { |
| 450 | 503 | const slice = macho_file.sections.slice(); |
| 451 | 504 | for (slice.items(.header)) |*header| { |
| ... | ... | @@ -463,6 +516,37 @@ fn allocateSections(macho_file: *MachO) !void { |
| 463 | 516 | } |
| 464 | 517 | header.size = needed_size; |
| 465 | 518 | } |
| 519 | |
| 520 | var fileoff: u32 = 0; |
| 521 | for (slice.items(.header)) |header| { |
| 522 | fileoff = @max(fileoff, header.offset + @as(u32, @intCast(header.size))); |
| 523 | } |
| 524 | |
| 525 | for (slice.items(.header)) |*header| { |
| 526 | if (header.nreloc == 0) continue; |
| 527 | header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info)); |
| 528 | fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info); |
| 529 | } |
| 530 | |
| 531 | // In -r mode, there is no LINKEDIT segment and so we allocate required LINKEDIT commands |
| 532 | // as if they were detached or part of the single segment. |
| 533 | |
| 534 | // DATA_IN_CODE |
| 535 | { |
| 536 | const cmd = &macho_file.data_in_code_cmd; |
| 537 | cmd.dataoff = fileoff; |
| 538 | fileoff += cmd.datasize; |
| 539 | fileoff = mem.alignForward(u32, fileoff, @alignOf(u64)); |
| 540 | } |
| 541 | |
| 542 | // SYMTAB |
| 543 | { |
| 544 | const cmd = &macho_file.symtab_cmd; |
| 545 | cmd.symoff = fileoff; |
| 546 | fileoff += cmd.nsyms * @sizeOf(macho.nlist_64); |
| 547 | fileoff = mem.alignForward(u32, fileoff, @alignOf(u32)); |
| 548 | cmd.stroff = fileoff; |
| 549 | } |
| 466 | 550 | } |
| 467 | 551 | |
| 468 | 552 | /// Renames segment names in Zig sections to standard MachO segment names such as |
| ... | ... | @@ -525,232 +609,77 @@ fn allocateSegment(macho_file: *MachO) void { |
| 525 | 609 | seg.filesize = fileoff - seg.fileoff; |
| 526 | 610 | } |
| 527 | 611 | |
| 528 | | fn allocateSectionsRelocs(macho_file: *MachO, off: u32) u32 { |
| 529 | | var fileoff = off; |
| 530 | | const slice = macho_file.sections.slice(); |
| 531 | | for (slice.items(.header)) |*header| { |
| 532 | | if (header.nreloc == 0) continue; |
| 533 | | header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info)); |
| 534 | | fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info); |
| 535 | | } |
| 536 | | return fileoff; |
| 537 | | } |
| 538 | | |
| 539 | 612 | // We need to sort relocations in descending order to be compatible with Apple's linker. |
| 540 | 613 | fn sortReloc(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation_info) bool { |
| 541 | 614 | _ = ctx; |
| 542 | 615 | return lhs.r_address > rhs.r_address; |
| 543 | 616 | } |
| 544 | 617 | |
| 545 | | fn writeAtoms(macho_file: *MachO) !void { |
| 618 | fn sortRelocs(macho_file: *MachO) void { |
| 619 | const tracy = trace(@src()); |
| 620 | defer tracy.end(); |
| 621 | |
| 622 | for (macho_file.sections.items(.relocs)) |*relocs| { |
| 623 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | fn writeSections(macho_file: *MachO) !void { |
| 546 | 628 | const tracy = trace(@src()); |
| 547 | 629 | defer tracy.end(); |
| 548 | 630 | |
| 549 | 631 | const gpa = macho_file.base.comp.gpa; |
| 550 | 632 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 551 | 633 | const slice = macho_file.sections.slice(); |
| 552 | | |
| 553 | | var relocs = std.ArrayList(macho.relocation_info).init(gpa); |
| 554 | | defer relocs.deinit(); |
| 555 | | |
| 556 | | for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| { |
| 557 | | if (atoms.items.len == 0) continue; |
| 634 | for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, *out, *relocs| { |
| 558 | 635 | if (header.isZerofill()) continue; |
| 559 | | if (macho_file.isZigSection(@intCast(i)) or macho_file.isDebugSection(@intCast(i))) continue; |
| 560 | | |
| 561 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 562 | | const code = try gpa.alloc(u8, size); |
| 563 | | defer gpa.free(code); |
| 636 | try out.resize(gpa, header.size); |
| 564 | 637 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; |
| 565 | | @memset(code, padding_byte); |
| 566 | | |
| 567 | | try relocs.ensureTotalCapacity(header.nreloc); |
| 568 | | |
| 569 | | for (atoms.items) |atom_index| { |
| 570 | | const atom = macho_file.getAtom(atom_index).?; |
| 571 | | assert(atom.flags.alive); |
| 572 | | const off = math.cast(usize, atom.value) orelse return error.Overflow; |
| 573 | | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 574 | | try atom.getData(macho_file, code[off..][0..atom_size]); |
| 575 | | try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs); |
| 576 | | } |
| 577 | | |
| 578 | | assert(relocs.items.len == header.nreloc); |
| 579 | | |
| 580 | | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 581 | | |
| 582 | | // TODO scattered writes? |
| 583 | | try macho_file.base.file.?.pwriteAll(code, header.offset); |
| 584 | | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 585 | | |
| 586 | | relocs.clearRetainingCapacity(); |
| 638 | @memset(out.items, padding_byte); |
| 639 | try relocs.resize(gpa, header.nreloc); |
| 587 | 640 | } |
| 588 | 641 | |
| 589 | | if (macho_file.getZigObject()) |zo| { |
| 590 | | // TODO: this is ugly; perhaps we should aggregrate before? |
| 591 | | var zo_relocs = std.AutoArrayHashMap(u8, std.ArrayList(macho.relocation_info)).init(gpa); |
| 592 | | defer { |
| 593 | | for (zo_relocs.values()) |*list| { |
| 594 | | list.deinit(); |
| 595 | | } |
| 596 | | zo_relocs.deinit(); |
| 597 | | } |
| 598 | | |
| 599 | | for (macho_file.sections.items(.header), 0..) |header, n_sect| { |
| 600 | | if (header.isZerofill()) continue; |
| 601 | | if (!macho_file.isZigSection(@intCast(n_sect)) and !macho_file.isDebugSection(@intCast(n_sect))) continue; |
| 602 | | const gop = try zo_relocs.getOrPut(@intCast(n_sect)); |
| 603 | | if (gop.found_existing) continue; |
| 604 | | gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc); |
| 605 | | } |
| 642 | const cmd = macho_file.symtab_cmd; |
| 643 | try macho_file.symtab.resize(gpa, cmd.nsyms); |
| 644 | try macho_file.strtab.resize(gpa, cmd.strsize); |
| 645 | macho_file.strtab.items[0] = 0; |
| 606 | 646 | |
| 607 | | for (zo.atoms.items) |atom_index| { |
| 608 | | const atom = macho_file.getAtom(atom_index) orelse continue; |
| 609 | | if (!atom.flags.alive) continue; |
| 610 | | const header = macho_file.sections.items(.header)[atom.out_n_sect]; |
| 611 | | if (header.isZerofill()) continue; |
| 612 | | if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; |
| 613 | | if (atom.getRelocs(macho_file).len == 0) continue; |
| 614 | | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 615 | | const code = try gpa.alloc(u8, atom_size); |
| 616 | | defer gpa.free(code); |
| 617 | | atom.getData(macho_file, code) catch |err| switch (err) { |
| 618 | | error.InputOutput => { |
| 619 | | try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{ |
| 620 | | atom.getName(macho_file), |
| 621 | | }); |
| 622 | | return error.FlushFailure; |
| 623 | | }, |
| 624 | | else => |e| { |
| 625 | | try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{ |
| 626 | | atom.getName(macho_file), |
| 627 | | @errorName(e), |
| 628 | | }); |
| 629 | | return error.FlushFailure; |
| 630 | | }, |
| 631 | | }; |
| 632 | | const file_offset = header.offset + atom.value; |
| 633 | | const rels = zo_relocs.getPtr(atom.out_n_sect).?; |
| 634 | | try atom.writeRelocs(macho_file, code, rels); |
| 635 | | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 636 | | } |
| 637 | | |
| 638 | | for (zo_relocs.keys(), zo_relocs.values()) |sect_id, rels| { |
| 639 | | const header = macho_file.sections.items(.header)[sect_id]; |
| 640 | | assert(rels.items.len == header.nreloc); |
| 641 | | mem.sort(macho.relocation_info, rels.items, {}, sortReloc); |
| 642 | | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(rels.items), header.reloff); |
| 643 | | } |
| 644 | | } |
| 645 | | } |
| 646 | | |
| 647 | | fn writeCompactUnwind(macho_file: *MachO) !void { |
| 648 | | const sect_index = macho_file.unwind_info_sect_index orelse return; |
| 649 | | const gpa = macho_file.base.comp.gpa; |
| 650 | | const header = macho_file.sections.items(.header)[sect_index]; |
| 651 | | |
| 652 | | const nrecs = math.cast(usize, @divExact(header.size, @sizeOf(macho.compact_unwind_entry))) orelse return error.Overflow; |
| 653 | | var entries = try std.ArrayList(macho.compact_unwind_entry).initCapacity(gpa, nrecs); |
| 654 | | defer entries.deinit(); |
| 655 | | |
| 656 | | var relocs = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc); |
| 657 | | defer relocs.deinit(); |
| 658 | | |
| 659 | | const addReloc = struct { |
| 660 | | fn addReloc(offset: i32, cpu_arch: std.Target.Cpu.Arch) macho.relocation_info { |
| 661 | | return .{ |
| 662 | | .r_address = offset, |
| 663 | | .r_symbolnum = 0, |
| 664 | | .r_pcrel = 0, |
| 665 | | .r_length = 3, |
| 666 | | .r_extern = 0, |
| 667 | | .r_type = switch (cpu_arch) { |
| 668 | | .aarch64 => @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| 669 | | .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| 670 | | else => unreachable, |
| 671 | | }, |
| 672 | | }; |
| 673 | | } |
| 674 | | }.addReloc; |
| 675 | | |
| 676 | | var offset: i32 = 0; |
| 677 | 647 | for (macho_file.objects.items) |index| { |
| 678 | | const object = macho_file.getFile(index).?.object; |
| 679 | | for (object.unwind_records_indexes.items) |irec| { |
| 680 | | const rec = object.getUnwindRecord(irec); |
| 681 | | if (!rec.alive) continue; |
| 682 | | |
| 683 | | var out: macho.compact_unwind_entry = .{ |
| 684 | | .rangeStart = 0, |
| 685 | | .rangeLength = rec.length, |
| 686 | | .compactUnwindEncoding = rec.enc.enc, |
| 687 | | .personalityFunction = 0, |
| 688 | | .lsda = 0, |
| 689 | | }; |
| 690 | | |
| 691 | | { |
| 692 | | // Function address |
| 693 | | const atom = rec.getAtom(macho_file); |
| 694 | | const addr = rec.getAtomAddress(macho_file); |
| 695 | | out.rangeStart = addr; |
| 696 | | var reloc = addReloc(offset, macho_file.getTarget().cpu.arch); |
| 697 | | reloc.r_symbolnum = atom.out_n_sect + 1; |
| 698 | | relocs.appendAssumeCapacity(reloc); |
| 699 | | } |
| 700 | | |
| 701 | | // Personality function |
| 702 | | if (rec.getPersonality(macho_file)) |sym| { |
| 703 | | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; |
| 704 | | var reloc = addReloc(offset + 16, macho_file.getTarget().cpu.arch); |
| 705 | | reloc.r_symbolnum = r_symbolnum; |
| 706 | | reloc.r_extern = 1; |
| 707 | | relocs.appendAssumeCapacity(reloc); |
| 708 | | } |
| 648 | try macho_file.getFile(index).?.object.writeAtomsRelocatable(macho_file); |
| 649 | macho_file.getFile(index).?.writeSymtab(macho_file, macho_file); |
| 650 | } |
| 709 | 651 | |
| 710 | | // LSDA address |
| 711 | | if (rec.getLsdaAtom(macho_file)) |atom| { |
| 712 | | const addr = rec.getLsdaAddress(macho_file); |
| 713 | | out.lsda = addr; |
| 714 | | var reloc = addReloc(offset + 24, macho_file.getTarget().cpu.arch); |
| 715 | | reloc.r_symbolnum = atom.out_n_sect + 1; |
| 716 | | relocs.appendAssumeCapacity(reloc); |
| 717 | | } |
| 652 | if (macho_file.eh_frame_sect_index) |_| { |
| 653 | try writeEhFrame(macho_file); |
| 654 | } |
| 718 | 655 | |
| 719 | | entries.appendAssumeCapacity(out); |
| 720 | | offset += @sizeOf(macho.compact_unwind_entry); |
| 656 | if (macho_file.unwind_info_sect_index) |_| { |
| 657 | for (macho_file.objects.items) |index| { |
| 658 | try macho_file.getFile(index).?.object.writeCompactUnwindRelocatable(macho_file); |
| 721 | 659 | } |
| 722 | 660 | } |
| 723 | | |
| 724 | | assert(entries.items.len == nrecs); |
| 725 | | assert(relocs.items.len == header.nreloc); |
| 726 | | |
| 727 | | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 728 | | |
| 729 | | // TODO scattered writes? |
| 730 | | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(entries.items), header.offset); |
| 731 | | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 732 | 661 | } |
| 733 | 662 | |
| 734 | 663 | fn writeEhFrame(macho_file: *MachO) !void { |
| 735 | | const sect_index = macho_file.eh_frame_sect_index orelse return; |
| 736 | | const gpa = macho_file.base.comp.gpa; |
| 737 | | const header = macho_file.sections.items(.header)[sect_index]; |
| 738 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 739 | | |
| 740 | | const code = try gpa.alloc(u8, size); |
| 741 | | defer gpa.free(code); |
| 742 | | |
| 743 | | var relocs = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc); |
| 744 | | defer relocs.deinit(); |
| 664 | const sect_index = macho_file.eh_frame_sect_index.?; |
| 665 | const buffer = macho_file.sections.items(.out)[sect_index]; |
| 666 | const relocs = macho_file.sections.items(.relocs)[sect_index]; |
| 667 | try eh_frame.writeRelocs(macho_file, buffer.items, relocs.items); |
| 668 | } |
| 745 | 669 | |
| 746 | | try eh_frame.writeRelocs(macho_file, code, &relocs); |
| 747 | | assert(relocs.items.len == header.nreloc); |
| 670 | fn writeSectionsToFile(macho_file: *MachO) !void { |
| 671 | const tracy = trace(@src()); |
| 672 | defer tracy.end(); |
| 748 | 673 | |
| 749 | | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); |
| 674 | const slice = macho_file.sections.slice(); |
| 675 | for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, out, relocs| { |
| 676 | try macho_file.base.file.?.pwriteAll(out.items, header.offset); |
| 677 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 678 | } |
| 750 | 679 | |
| 751 | | // TODO scattered writes? |
| 752 | | try macho_file.base.file.?.pwriteAll(code, header.offset); |
| 753 | | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); |
| 680 | try macho_file.writeDataInCode(); |
| 681 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff); |
| 682 | try macho_file.base.file.?.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff); |
| 754 | 683 | } |
| 755 | 684 | |
| 756 | 685 | fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { |