| ... | @@ -26,70 +26,51 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c | ... | @@ -26,70 +26,51 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c |
| 26 | return; | 26 | return; |
| 27 | } | 27 | } |
| 28 | | 28 | |
| 29 | @panic("TODO -r mode"); | 29 | for (positionals.items) |obj| { |
| 30 | | 30 | macho_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { |
| 31 | // for (positionals.items) |obj| { | 31 | error.MalformedObject, |
| 32 | // macho_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | 32 | error.MalformedArchive, |
| 33 | // error.MalformedObject, | 33 | error.InvalidCpuArch, |
| 34 | // error.MalformedArchive, | 34 | error.InvalidTarget, |
| 35 | // error.InvalidCpuArch, | 35 | => continue, // already reported |
| 36 | // error.InvalidTarget, | 36 | error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an object file", .{}), |
| 37 | // => continue, // already reported | 37 | else => |e| try macho_file.reportParseError( |
| 38 | // error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an object file", .{}), | 38 | obj.path, |
| 39 | // else => |e| try macho_file.reportParseError( | 39 | "unexpected error: parsing input file failed with error {s}", |
| 40 | // obj.path, | 40 | .{@errorName(e)}, |
| 41 | // "unexpected error: parsing input file failed with error {s}", | 41 | ), |
| 42 | // .{@errorName(e)}, | 42 | }; |
| 43 | // ), | 43 | } |
| 44 | // }; | | |
| 45 | // } | | |
| 46 | | 44 | |
| 47 | // if (comp.link_errors.items.len > 0) return error.FlushFailure; | 45 | 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 | // } | | |
| 74 | | 46 | |
| 75 | // try macho_file.calcSymtabSize(); | 47 | try macho_file.resolveSymbols(); |
| 76 | // try writeAtoms(macho_file); | 48 | try macho_file.dedupLiterals(); |
| 77 | // try writeCompactUnwind(macho_file); | 49 | markExports(macho_file); |
| 78 | // try writeEhFrame(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)); | 56 | try createSegment(macho_file); |
| 81 | // off = try macho_file.writeDataInCode(0, off); | 57 | try allocateSections(macho_file); |
| 82 | // off = mem.alignForward(u32, off, @alignOf(u64)); | 58 | allocateSegment(macho_file); |
| 83 | // off = try macho_file.writeSymtab(off); | | |
| 84 | // off = mem.alignForward(u32, off, @alignOf(u64)); | | |
| 85 | // off = try macho_file.writeStrtab(off); | | |
| 86 | | 59 | |
| 87 | // // In order to please Apple ld (and possibly other MachO linkers in the wild), | 60 | if (build_options.enable_logging) { |
| 88 | // // we will now sanitize segment names of Zig-specific segments. | 61 | state_log.debug("{}", .{macho_file.dumpState()}); |
| 89 | // sanitizeZigSections(macho_file); | 62 | } |
| 90 | | 63 | |
| 91 | // const ncmds, const sizeofcmds = try writeLoadCommands(macho_file); | 64 | try writeSections(macho_file); |
| 92 | // try writeHeader(macho_file, ncmds, sizeofcmds); | 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 | pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { | 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,9 +334,9 @@ pub fn claimUnresolved(macho_file: *MachO) void { |
| 353 | | 334 | |
| 354 | fn initOutputSections(macho_file: *MachO) !void { | 335 | fn initOutputSections(macho_file: *MachO) !void { |
| 355 | for (macho_file.objects.items) |index| { | 336 | for (macho_file.objects.items) |index| { |
| 356 | const object = macho_file.getFile(index).?.object; | 337 | const file = macho_file.getFile(index).?; |
| 357 | for (object.atoms.items) |atom_index| { | 338 | for (file.getAtoms()) |atom_index| { |
| 358 | const atom = macho_file.getAtom(atom_index) orelse continue; | 339 | const atom = file.getAtom(atom_index) orelse continue; |
| 359 | if (!atom.flags.alive) continue; | 340 | if (!atom.flags.alive) continue; |
| 360 | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file); | 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,69 +364,141 @@ fn calcSectionSizes(macho_file: *MachO) !void { |
| 383 | const tracy = trace(@src()); | 364 | const tracy = trace(@src()); |
| 384 | defer tracy.end(); | 365 | defer tracy.end(); |
| 385 | | 366 | |
| 386 | const slice = macho_file.sections.slice(); | 367 | for (macho_file.sections.items(.atoms), 0..) |atoms, i| { |
| 387 | for (slice.items(.header), slice.items(.atoms)) |*header, atoms| { | | |
| 388 | if (atoms.items.len == 0) continue; | 368 | if (atoms.items.len == 0) continue; |
| 389 | for (atoms.items) |atom_index| { | 369 | calcSectionSize(macho_file, @intCast(i)); |
| 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 | } | | |
| 399 | } | 370 | } |
| 400 | | 371 | |
| 401 | if (macho_file.unwind_info_sect_index) |index| { | 372 | if (macho_file.eh_frame_sect_index) |_| { |
| 402 | calcCompactUnwindSize(macho_file, index); | 373 | try calcEhFrameSize(macho_file); |
| 403 | } | 374 | } |
| 404 | | 375 | |
| 405 | if (macho_file.eh_frame_sect_index) |index| { | 376 | for (macho_file.objects.items) |index| { |
| 406 | const sect = &macho_file.sections.items(.header)[index]; | 377 | if (macho_file.unwind_info_sect_index) |_| { |
| 407 | sect.size = try eh_frame.calcSize(macho_file); | 378 | macho_file.getFile(index).?.object.calcCompactUnwindSizeRelocatable(macho_file); |
| 408 | sect.@"align" = 3; | 379 | } |
| 409 | sect.nreloc = eh_frame.calcNumRelocs(macho_file); | 380 | macho_file.getFile(index).?.calcSymtabSize(macho_file); |
| 410 | } | 381 | } |
| 411 | | 382 | |
| 412 | if (macho_file.getZigObject()) |zo| { | 383 | try macho_file.data_in_code.updateSize(macho_file); |
| 413 | for (zo.atoms.items) |atom_index| { | 384 | |
| 414 | const atom = macho_file.getAtom(atom_index) orelse continue; | 385 | calcCompactUnwindSize(macho_file); |
| 415 | if (!atom.flags.alive) continue; | 386 | calcSymtabSize(macho_file); |
| 416 | const header = &macho_file.sections.items(.header)[atom.out_n_sect]; | 387 | |
| 417 | if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; | 388 | // TODO |
| 418 | header.nreloc += atom.calcNumRelocs(macho_file); | 389 | // if (macho_file.getZigObject()) |zo| { |
| 419 | } | 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 { | 421 | fn calcEhFrameSize(macho_file: *MachO) !void { |
| 424 | var size: u32 = 0; | 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 | var nreloc: u32 = 0; | 436 | var nreloc: u32 = 0; |
| 426 | | 437 | |
| 427 | for (macho_file.objects.items) |index| { | 438 | for (macho_file.objects.items) |index| { |
| 428 | const object = macho_file.getFile(index).?.object; | 439 | const ctx = &macho_file.getFile(index).?.object.compact_unwind_ctx; |
| 429 | for (object.unwind_records_indexes.items) |irec| { | 440 | ctx.rec_index = nrec; |
| 430 | const rec = object.getUnwindRecord(irec); | 441 | ctx.reloc_index = nreloc; |
| 431 | if (!rec.alive) continue; | 442 | nrec += ctx.rec_count; |
| 432 | size += @sizeOf(macho.compact_unwind_entry); | 443 | nreloc += ctx.reloc_count; |
| 433 | nreloc += 1; | | |
| 434 | if (rec.getPersonality(macho_file)) |_| { | | |
| 435 | nreloc += 1; | | |
| 436 | } | | |
| 437 | if (rec.getLsdaAtom(macho_file)) |_| { | | |
| 438 | nreloc += 1; | | |
| 439 | } | | |
| 440 | } | | |
| 441 | } | 444 | } |
| 442 | | 445 | |
| 443 | const sect = &macho_file.sections.items(.header)[sect_index]; | 446 | const sect = &macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?]; |
| 444 | sect.size = size; | 447 | sect.size = nrec * @sizeOf(macho.compact_unwind_entry); |
| 445 | sect.nreloc = nreloc; | 448 | sect.nreloc = nreloc; |
| 446 | sect.@"align" = 3; | 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 | fn allocateSections(macho_file: *MachO) !void { | 502 | fn allocateSections(macho_file: *MachO) !void { |
| 450 | const slice = macho_file.sections.slice(); | 503 | const slice = macho_file.sections.slice(); |
| 451 | for (slice.items(.header)) |*header| { | 504 | for (slice.items(.header)) |*header| { |
| ... | @@ -463,6 +516,37 @@ fn allocateSections(macho_file: *MachO) !void { | ... | @@ -463,6 +516,37 @@ fn allocateSections(macho_file: *MachO) !void { |
| 463 | } | 516 | } |
| 464 | header.size = needed_size; | 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 | /// Renames segment names in Zig sections to standard MachO segment names such as | 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,232 +609,77 @@ fn allocateSegment(macho_file: *MachO) void { |
| 525 | seg.filesize = fileoff - seg.fileoff; | 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 | // We need to sort relocations in descending order to be compatible with Apple's linker. | 612 | // We need to sort relocations in descending order to be compatible with Apple's linker. |
| 540 | fn sortReloc(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation_info) bool { | 613 | fn sortReloc(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation_info) bool { |
| 541 | _ = ctx; | 614 | _ = ctx; |
| 542 | return lhs.r_address > rhs.r_address; | 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 | const tracy = trace(@src()); | 628 | const tracy = trace(@src()); |
| 547 | defer tracy.end(); | 629 | defer tracy.end(); |
| 548 | | 630 | |
| 549 | const gpa = macho_file.base.comp.gpa; | 631 | const gpa = macho_file.base.comp.gpa; |
| 550 | const cpu_arch = macho_file.getTarget().cpu.arch; | 632 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 551 | const slice = macho_file.sections.slice(); | 633 | const slice = macho_file.sections.slice(); |
| 552 | | 634 | for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, *out, *relocs| { |
| 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; | | |
| 558 | if (header.isZerofill()) continue; | 635 | if (header.isZerofill()) continue; |
| 559 | if (macho_file.isZigSection(@intCast(i)) or macho_file.isDebugSection(@intCast(i))) continue; | 636 | try out.resize(gpa, header.size); |
| 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); | | |
| 564 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; | 637 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; |
| 565 | @memset(code, padding_byte); | 638 | @memset(out.items, padding_byte); |
| 566 | | 639 | try relocs.resize(gpa, header.nreloc); |
| 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(); | | |
| 587 | } | 640 | } |
| 588 | | 641 | |
| 589 | if (macho_file.getZigObject()) |zo| { | 642 | const cmd = macho_file.symtab_cmd; |
| 590 | // TODO: this is ugly; perhaps we should aggregrate before? | 643 | try macho_file.symtab.resize(gpa, cmd.nsyms); |
| 591 | var zo_relocs = std.AutoArrayHashMap(u8, std.ArrayList(macho.relocation_info)).init(gpa); | 644 | try macho_file.strtab.resize(gpa, cmd.strsize); |
| 592 | defer { | 645 | macho_file.strtab.items[0] = 0; |
| 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 | } | | |
| 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 | for (macho_file.objects.items) |index| { | 647 | for (macho_file.objects.items) |index| { |
| 678 | const object = macho_file.getFile(index).?.object; | 648 | try macho_file.getFile(index).?.object.writeAtomsRelocatable(macho_file); |
| 679 | for (object.unwind_records_indexes.items) |irec| { | 649 | macho_file.getFile(index).?.writeSymtab(macho_file, macho_file); |
| 680 | const rec = object.getUnwindRecord(irec); | 650 | } |
| 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 | } | | |
| 709 | | 651 | |
| 710 | // LSDA address | 652 | if (macho_file.eh_frame_sect_index) |_| { |
| 711 | if (rec.getLsdaAtom(macho_file)) |atom| { | 653 | try writeEhFrame(macho_file); |
| 712 | const addr = rec.getLsdaAddress(macho_file); | 654 | } |
| 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 | } | | |
| 718 | | 655 | |
| 719 | entries.appendAssumeCapacity(out); | 656 | if (macho_file.unwind_info_sect_index) |_| { |
| 720 | offset += @sizeOf(macho.compact_unwind_entry); | 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 | fn writeEhFrame(macho_file: *MachO) !void { | 663 | fn writeEhFrame(macho_file: *MachO) !void { |
| 735 | const sect_index = macho_file.eh_frame_sect_index orelse return; | 664 | const sect_index = macho_file.eh_frame_sect_index.?; |
| 736 | const gpa = macho_file.base.comp.gpa; | 665 | const buffer = macho_file.sections.items(.out)[sect_index]; |
| 737 | const header = macho_file.sections.items(.header)[sect_index]; | 666 | const relocs = macho_file.sections.items(.relocs)[sect_index]; |
| 738 | const size = math.cast(usize, header.size) orelse return error.Overflow; | 667 | try eh_frame.writeRelocs(macho_file, buffer.items, relocs.items); |
| 739 | | 668 | } |
| 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(); | | |
| 745 | | 669 | |
| 746 | try eh_frame.writeRelocs(macho_file, code, &relocs); | 670 | fn writeSectionsToFile(macho_file: *MachO) !void { |
| 747 | assert(relocs.items.len == header.nreloc); | 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? | 680 | try macho_file.writeDataInCode(); |
| 752 | try macho_file.base.file.?.pwriteAll(code, header.offset); | 681 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff); |
| 753 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | 682 | try macho_file.base.file.?.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff); |
| 754 | } | 683 | } |
| 755 | | 684 | |
| 756 | fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { | 685 | fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { |