| ... | @@ -9,14 +9,15 @@ const math = std.math; | ... | @@ -9,14 +9,15 @@ const math = std.math; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | | 10 | |
| 11 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | 11 | const aarch64 = @import("../../arch/aarch64/bits.zig"); |
| | 12 | const calcUuid = @import("uuid.zig").calcUuid; |
| 12 | const dead_strip = @import("dead_strip.zig"); | 13 | const dead_strip = @import("dead_strip.zig"); |
| 13 | const eh_frame = @import("eh_frame.zig"); | 14 | const eh_frame = @import("eh_frame.zig"); |
| 14 | const fat = @import("fat.zig"); | 15 | const fat = @import("fat.zig"); |
| 15 | const link = @import("../../link.zig"); | 16 | const link = @import("../../link.zig"); |
| 16 | const load_commands = @import("load_commands.zig"); | 17 | const load_commands = @import("load_commands.zig"); |
| | 18 | const stub_helpers = @import("stubs.zig"); |
| 17 | const thunks = @import("thunks.zig"); | 19 | const thunks = @import("thunks.zig"); |
| 18 | const trace = @import("../../tracy.zig").trace; | 20 | const trace = @import("../../tracy.zig").trace; |
| 19 | const stub_helpers = @import("stubs.zig"); | | |
| 20 | | 21 | |
| 21 | const Allocator = mem.Allocator; | 22 | const Allocator = mem.Allocator; |
| 22 | const Archive = @import("Archive.zig"); | 23 | const Archive = @import("Archive.zig"); |
| ... | @@ -2575,150 +2576,12 @@ pub const Zld = struct { | ... | @@ -2575,150 +2576,12 @@ pub const Zld = struct { |
| 2575 | self.dysymtab_cmd.nindirectsyms = nindirectsyms; | 2576 | self.dysymtab_cmd.nindirectsyms = nindirectsyms; |
| 2576 | } | 2577 | } |
| 2577 | | 2578 | |
| 2578 | fn writeUuid(self: *Zld, comp: *const Compilation, args: struct { | 2579 | fn writeUuid(self: *Zld, comp: *const Compilation, uuid_cmd_offset: u32) !void { |
| 2579 | linkedit_cmd_offset: u32, | 2580 | const seg = self.getLinkeditSegmentPtr(); |
| 2580 | symtab_cmd_offset: u32, | 2581 | const file_size = seg.fileoff + seg.filesize; |
| 2581 | uuid_cmd_offset: u32, | 2582 | try calcUuid(comp, self.file, file_size, &self.uuid_cmd.uuid); |
| 2582 | codesig_cmd_offset: ?u32, | 2583 | const offset = uuid_cmd_offset + @sizeOf(macho.load_command); |
| 2583 | }) !void { | 2584 | try self.file.pwriteAll(&self.uuid_cmd.uuid, offset); |
| 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; | | |
| 2722 | } | 2585 | } |
| 2723 | | 2586 | |
| 2724 | fn writeCodeSignaturePadding(self: *Zld, code_sig: *CodeSignature) !void { | 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,16 +3904,11 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 4041 | const lc_writer = lc_buffer.writer(); | 3904 | const lc_writer = lc_buffer.writer(); |
| 4042 | | 3905 | |
| 4043 | try zld.writeSegmentHeaders(lc_writer); | 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 | try lc_writer.writeStruct(zld.dyld_info_cmd); | 3907 | try lc_writer.writeStruct(zld.dyld_info_cmd); |
| 4047 | try lc_writer.writeStruct(zld.function_starts_cmd); | 3908 | try lc_writer.writeStruct(zld.function_starts_cmd); |
| 4048 | try lc_writer.writeStruct(zld.data_in_code_cmd); | 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 | try lc_writer.writeStruct(zld.symtab_cmd); | 3910 | try lc_writer.writeStruct(zld.symtab_cmd); |
| 4052 | try lc_writer.writeStruct(zld.dysymtab_cmd); | 3911 | try lc_writer.writeStruct(zld.dysymtab_cmd); |
| 4053 | | | |
| 4054 | try load_commands.writeDylinkerLC(lc_writer); | 3912 | try load_commands.writeDylinkerLC(lc_writer); |
| 4055 | | 3913 | |
| 4056 | if (zld.options.output_mode == .Exe) { | 3914 | if (zld.options.output_mode == .Exe) { |
| ... | @@ -4088,22 +3946,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr | ... | @@ -4088,22 +3946,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 4088 | | 3946 | |
| 4089 | try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), lc_writer); | 3947 | try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), lc_writer); |
| 4090 | | 3948 | |
| 4091 | var codesig_cmd_offset: ?u32 = null; | | |
| 4092 | if (requires_codesig) { | 3949 | if (requires_codesig) { |
| 4093 | codesig_cmd_offset = @sizeOf(macho.mach_header_64) + @intCast(u32, lc_buffer.items.len); | | |
| 4094 | try lc_writer.writeStruct(zld.codesig_cmd); | 3950 | try lc_writer.writeStruct(zld.codesig_cmd); |
| 4095 | } | 3951 | } |
| 4096 | | 3952 | |
| 4097 | const ncmds = load_commands.calcNumOfLCs(lc_buffer.items); | 3953 | const ncmds = load_commands.calcNumOfLCs(lc_buffer.items); |
| 4098 | try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64)); | 3954 | try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64)); |
| 4099 | try zld.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len)); | 3955 | try zld.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len)); |
| 4100 | | 3956 | try zld.writeUuid(comp, uuid_cmd_offset); |
| 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 | }); | | |
| 4107 | | 3957 | |
| 4108 | if (codesig) |*csig| { | 3958 | if (codesig) |*csig| { |
| 4109 | try zld.writeCodeSignature(comp, csig); // code signing always comes last | 3959 | try zld.writeCodeSignature(comp, csig); // code signing always comes last |