| ... | ... | @@ -9,14 +9,15 @@ const math = std.math; |
| 9 | 9 | const mem = std.mem; |
| 10 | 10 | |
| 11 | 11 | const aarch64 = @import("../../arch/aarch64/bits.zig"); |
| 12 | const calcUuid = @import("uuid.zig").calcUuid; |
| 12 | 13 | const dead_strip = @import("dead_strip.zig"); |
| 13 | 14 | const eh_frame = @import("eh_frame.zig"); |
| 14 | 15 | const fat = @import("fat.zig"); |
| 15 | 16 | const link = @import("../../link.zig"); |
| 16 | 17 | const load_commands = @import("load_commands.zig"); |
| 18 | const stub_helpers = @import("stubs.zig"); |
| 17 | 19 | const thunks = @import("thunks.zig"); |
| 18 | 20 | const trace = @import("../../tracy.zig").trace; |
| 19 | | const stub_helpers = @import("stubs.zig"); |
| 20 | 21 | |
| 21 | 22 | const Allocator = mem.Allocator; |
| 22 | 23 | const Archive = @import("Archive.zig"); |
| ... | ... | @@ -2575,150 +2576,12 @@ pub const Zld = struct { |
| 2575 | 2576 | self.dysymtab_cmd.nindirectsyms = nindirectsyms; |
| 2576 | 2577 | } |
| 2577 | 2578 | |
| 2578 | | fn writeUuid(self: *Zld, comp: *const Compilation, args: struct { |
| 2579 | | linkedit_cmd_offset: u32, |
| 2580 | | symtab_cmd_offset: u32, |
| 2581 | | uuid_cmd_offset: u32, |
| 2582 | | codesig_cmd_offset: ?u32, |
| 2583 | | }) !void { |
| 2584 | | _ = comp; |
| 2585 | | switch (self.options.optimize_mode) { |
| 2586 | | .Debug => { |
| 2587 | | // In Debug we don't really care about reproducibility, so put in a random value |
| 2588 | | // and be done with it. |
| 2589 | | std.crypto.random.bytes(&self.uuid_cmd.uuid); |
| 2590 | | Md5.hash(&self.uuid_cmd.uuid, &self.uuid_cmd.uuid, .{}); |
| 2591 | | conformUuid(&self.uuid_cmd.uuid); |
| 2592 | | }, |
| 2593 | | else => { |
| 2594 | | // We set the max file size to the actual strtab buffer length to exclude any strtab padding. |
| 2595 | | const max_file_end = @intCast(u32, self.symtab_cmd.stroff + self.strtab.buffer.items.len); |
| 2596 | | |
| 2597 | | const FileSubsection = struct { |
| 2598 | | start: u32, |
| 2599 | | end: u32, |
| 2600 | | }; |
| 2601 | | |
| 2602 | | var subsections: [5]FileSubsection = undefined; |
| 2603 | | var count: usize = 0; |
| 2604 | | |
| 2605 | | // Exclude LINKEDIT segment command as it contains file size that includes stabs contribution |
| 2606 | | // and code signature. |
| 2607 | | subsections[count] = .{ |
| 2608 | | .start = 0, |
| 2609 | | .end = args.linkedit_cmd_offset, |
| 2610 | | }; |
| 2611 | | count += 1; |
| 2612 | | |
| 2613 | | // Exclude SYMTAB and DYSYMTAB commands for the same reason. |
| 2614 | | subsections[count] = .{ |
| 2615 | | .start = subsections[count - 1].end + @sizeOf(macho.segment_command_64), |
| 2616 | | .end = args.symtab_cmd_offset, |
| 2617 | | }; |
| 2618 | | count += 1; |
| 2619 | | |
| 2620 | | // Exclude CODE_SIGNATURE command (if present). |
| 2621 | | if (args.codesig_cmd_offset) |offset| { |
| 2622 | | subsections[count] = .{ |
| 2623 | | .start = subsections[count - 1].end + @sizeOf(macho.symtab_command) + @sizeOf(macho.dysymtab_command), |
| 2624 | | .end = offset, |
| 2625 | | }; |
| 2626 | | count += 1; |
| 2627 | | } |
| 2628 | | |
| 2629 | | if (!self.options.strip) { |
| 2630 | | // Exclude region comprising all symbol stabs. |
| 2631 | | const nlocals = self.dysymtab_cmd.nlocalsym; |
| 2632 | | |
| 2633 | | const locals = try self.gpa.alloc(macho.nlist_64, nlocals); |
| 2634 | | defer self.gpa.free(locals); |
| 2635 | | |
| 2636 | | const locals_buf = @ptrCast([*]u8, locals.ptr)[0 .. @sizeOf(macho.nlist_64) * nlocals]; |
| 2637 | | const amt = try self.file.preadAll(locals_buf, self.symtab_cmd.symoff); |
| 2638 | | if (amt != locals_buf.len) return error.InputOutput; |
| 2639 | | |
| 2640 | | const istab: usize = for (locals, 0..) |local, i| { |
| 2641 | | if (local.stab()) break i; |
| 2642 | | } else locals.len; |
| 2643 | | const nstabs = locals.len - istab; |
| 2644 | | |
| 2645 | | if (nstabs == 0) { |
| 2646 | | subsections[count] = .{ |
| 2647 | | .start = subsections[count - 1].end + if (args.codesig_cmd_offset == null) |
| 2648 | | @as(u32, @sizeOf(macho.symtab_command) + @sizeOf(macho.dysymtab_command)) |
| 2649 | | else |
| 2650 | | @sizeOf(macho.linkedit_data_command), |
| 2651 | | .end = max_file_end, |
| 2652 | | }; |
| 2653 | | count += 1; |
| 2654 | | } else { |
| 2655 | | // Exclude a subsection of the strtab with names of the stabs. |
| 2656 | | // We do not care about anything succeeding strtab as it is the code signature data which is |
| 2657 | | // not part of the UUID calculation anyway. |
| 2658 | | const stab_stroff = locals[istab].n_strx; |
| 2659 | | |
| 2660 | | subsections[count] = .{ |
| 2661 | | .start = subsections[count - 1].end + if (args.codesig_cmd_offset == null) |
| 2662 | | @as(u32, @sizeOf(macho.symtab_command) + @sizeOf(macho.dysymtab_command)) |
| 2663 | | else |
| 2664 | | @sizeOf(macho.linkedit_data_command), |
| 2665 | | .end = @intCast(u32, self.symtab_cmd.symoff + istab * @sizeOf(macho.nlist_64)), |
| 2666 | | }; |
| 2667 | | count += 1; |
| 2668 | | |
| 2669 | | subsections[count] = .{ |
| 2670 | | .start = subsections[count - 1].end + @intCast(u32, nstabs * @sizeOf(macho.nlist_64)), |
| 2671 | | .end = self.symtab_cmd.stroff + stab_stroff, |
| 2672 | | }; |
| 2673 | | count += 1; |
| 2674 | | } |
| 2675 | | } else { |
| 2676 | | subsections[count] = .{ |
| 2677 | | .start = subsections[count - 1].end + if (args.codesig_cmd_offset == null) |
| 2678 | | @as(u32, @sizeOf(macho.symtab_command) + @sizeOf(macho.dysymtab_command)) |
| 2679 | | else |
| 2680 | | @sizeOf(macho.linkedit_data_command), |
| 2681 | | .end = max_file_end, |
| 2682 | | }; |
| 2683 | | count += 1; |
| 2684 | | } |
| 2685 | | |
| 2686 | | const chunk_size = 0x4000; |
| 2687 | | |
| 2688 | | var hasher = Md5.init(.{}); |
| 2689 | | var buffer: [chunk_size]u8 = undefined; |
| 2690 | | |
| 2691 | | for (subsections[0..count]) |cut| { |
| 2692 | | const size = cut.end - cut.start; |
| 2693 | | const num_chunks = mem.alignForward(usize, size, chunk_size) / chunk_size; |
| 2694 | | |
| 2695 | | var i: usize = 0; |
| 2696 | | while (i < num_chunks) : (i += 1) { |
| 2697 | | const fstart = cut.start + i * chunk_size; |
| 2698 | | const fsize = if (fstart + chunk_size > cut.end) |
| 2699 | | cut.end - fstart |
| 2700 | | else |
| 2701 | | chunk_size; |
| 2702 | | const amt = try self.file.preadAll(buffer[0..fsize], fstart); |
| 2703 | | if (amt != fsize) return error.InputOutput; |
| 2704 | | |
| 2705 | | hasher.update(buffer[0..fsize]); |
| 2706 | | } |
| 2707 | | } |
| 2708 | | |
| 2709 | | hasher.final(&self.uuid_cmd.uuid); |
| 2710 | | conformUuid(&self.uuid_cmd.uuid); |
| 2711 | | }, |
| 2712 | | } |
| 2713 | | |
| 2714 | | const in_file = args.uuid_cmd_offset + @sizeOf(macho.load_command); |
| 2715 | | try self.file.pwriteAll(&self.uuid_cmd.uuid, in_file); |
| 2716 | | } |
| 2717 | | |
| 2718 | | inline fn conformUuid(out: *[Md5.digest_length]u8) void { |
| 2719 | | // LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats |
| 2720 | | out[6] = (out[6] & 0x0F) | (3 << 4); |
| 2721 | | out[8] = (out[8] & 0x3F) | 0x80; |
| 2579 | fn writeUuid(self: *Zld, comp: *const Compilation, uuid_cmd_offset: u32) !void { |
| 2580 | const seg = self.getLinkeditSegmentPtr(); |
| 2581 | const file_size = seg.fileoff + seg.filesize; |
| 2582 | try calcUuid(comp, self.file, file_size, &self.uuid_cmd.uuid); |
| 2583 | const offset = uuid_cmd_offset + @sizeOf(macho.load_command); |
| 2584 | try self.file.pwriteAll(&self.uuid_cmd.uuid, offset); |
| 2722 | 2585 | } |
| 2723 | 2586 | |
| 2724 | 2587 | fn writeCodeSignaturePadding(self: *Zld, code_sig: *CodeSignature) !void { |
| ... | ... | @@ -4041,16 +3904,11 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 4041 | 3904 | const lc_writer = lc_buffer.writer(); |
| 4042 | 3905 | |
| 4043 | 3906 | try zld.writeSegmentHeaders(lc_writer); |
| 4044 | | const linkedit_cmd_offset = @sizeOf(macho.mach_header_64) + @intCast(u32, lc_buffer.items.len - @sizeOf(macho.segment_command_64)); |
| 4045 | | |
| 4046 | 3907 | try lc_writer.writeStruct(zld.dyld_info_cmd); |
| 4047 | 3908 | try lc_writer.writeStruct(zld.function_starts_cmd); |
| 4048 | 3909 | try lc_writer.writeStruct(zld.data_in_code_cmd); |
| 4049 | | |
| 4050 | | const symtab_cmd_offset = @sizeOf(macho.mach_header_64) + @intCast(u32, lc_buffer.items.len); |
| 4051 | 3910 | try lc_writer.writeStruct(zld.symtab_cmd); |
| 4052 | 3911 | try lc_writer.writeStruct(zld.dysymtab_cmd); |
| 4053 | | |
| 4054 | 3912 | try load_commands.writeDylinkerLC(lc_writer); |
| 4055 | 3913 | |
| 4056 | 3914 | if (zld.options.output_mode == .Exe) { |
| ... | ... | @@ -4088,22 +3946,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 4088 | 3946 | |
| 4089 | 3947 | try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), lc_writer); |
| 4090 | 3948 | |
| 4091 | | var codesig_cmd_offset: ?u32 = null; |
| 4092 | 3949 | if (requires_codesig) { |
| 4093 | | codesig_cmd_offset = @sizeOf(macho.mach_header_64) + @intCast(u32, lc_buffer.items.len); |
| 4094 | 3950 | try lc_writer.writeStruct(zld.codesig_cmd); |
| 4095 | 3951 | } |
| 4096 | 3952 | |
| 4097 | 3953 | const ncmds = load_commands.calcNumOfLCs(lc_buffer.items); |
| 4098 | 3954 | try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64)); |
| 4099 | 3955 | try zld.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len)); |
| 4100 | | |
| 4101 | | try zld.writeUuid(comp, .{ |
| 4102 | | .linkedit_cmd_offset = linkedit_cmd_offset, |
| 4103 | | .symtab_cmd_offset = symtab_cmd_offset, |
| 4104 | | .uuid_cmd_offset = uuid_cmd_offset, |
| 4105 | | .codesig_cmd_offset = codesig_cmd_offset, |
| 4106 | | }); |
| 3956 | try zld.writeUuid(comp, uuid_cmd_offset); |
| 4107 | 3957 | |
| 4108 | 3958 | if (codesig) |*csig| { |
| 4109 | 3959 | try zld.writeCodeSignature(comp, csig); // code signing always comes last |