| ... | ... | @@ -752,44 +752,81 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 752 | 752 | |
| 753 | 753 | // At this stage, LLD has done its job. It is time to patch the resultant |
| 754 | 754 | // binaries up! |
| 755 | | // This is currently needed only for aarch64 targets. |
| 756 | | if (target.cpu.arch == .aarch64) { |
| 757 | | const out_file = try directory.handle.openFile(self.base.options.emit.?.sub_path, .{ .write = true }); |
| 758 | | try self.parseFromFile(out_file); |
| 759 | | if (self.code_signature_cmd_index == null) { |
| 760 | | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 761 | | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 762 | | const after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64); |
| 763 | | const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den; |
| 764 | | |
| 765 | | if (needed_size + after_last_cmd_offset > text_section.offset) { |
| 766 | | std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{}); |
| 767 | | std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); |
| 768 | | std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); |
| 769 | | return error.NotEnoughPadding; |
| 770 | | } |
| 755 | const out_file = try directory.handle.openFile(self.base.options.emit.?.sub_path, .{ .write = true }); |
| 756 | try self.parseFromFile(out_file); |
| 757 | if (self.libsystem_cmd_index == null) { |
| 758 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 759 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 760 | const after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64); |
| 761 | const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den; |
| 762 | |
| 763 | if (needed_size + after_last_cmd_offset > text_section.offset) { |
| 764 | std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{}); |
| 765 | std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); |
| 766 | std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); |
| 767 | return error.NotEnoughPadding; |
| 768 | } |
| 771 | 769 | |
| 772 | | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 773 | | // TODO This is clunky. |
| 774 | | self.linkedit_segment_next_offset = @intCast(u32, mem.alignForwardGeneric(u64, linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize, @sizeOf(u64))); |
| 775 | | // Add code signature load command |
| 776 | | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 777 | | try self.load_commands.append(self.base.allocator, .{ |
| 778 | | .LinkeditData = .{ |
| 779 | | .cmd = macho.LC_CODE_SIGNATURE, |
| 780 | | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 781 | | .dataoff = 0, |
| 782 | | .datasize = 0, |
| 783 | | }, |
| 784 | | }); |
| 785 | | // Pad out space for code signature |
| 786 | | try self.writeCodeSignaturePadding(); |
| 787 | | // Write updated load commands and the header |
| 788 | | try self.writeLoadCommands(); |
| 789 | | try self.writeHeader(); |
| 790 | | // Generate adhoc code signature |
| 791 | | try self.writeCodeSignature(); |
| 770 | // Add load dylib load command |
| 771 | self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 772 | const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), @sizeOf(u64)); |
| 773 | // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. |
| 774 | // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0. |
| 775 | const min_version = 0x0; |
| 776 | var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ |
| 777 | .cmd = macho.LC_LOAD_DYLIB, |
| 778 | .cmdsize = @intCast(u32, cmdsize), |
| 779 | .dylib = .{ |
| 780 | .name = @sizeOf(macho.dylib_command), |
| 781 | .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files |
| 782 | .current_version = min_version, |
| 783 | .compatibility_version = min_version, |
| 784 | }, |
| 785 | }); |
| 786 | dylib_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); |
| 787 | mem.set(u8, dylib_cmd.data, 0); |
| 788 | mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH)); |
| 789 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); |
| 790 | // TODO Fixup linkedit data |
| 791 | // Write updated load commands and the header |
| 792 | try self.writeLoadCommands(); |
| 793 | try self.writeHeader(); |
| 794 | } |
| 795 | if (self.code_signature_cmd_index == null) { |
| 796 | if (target.cpu.arch != .aarch64) return; // This is currently needed only for aarch64 targets. |
| 797 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 798 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 799 | const after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64); |
| 800 | const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den; |
| 801 | |
| 802 | if (needed_size + after_last_cmd_offset > text_section.offset) { |
| 803 | std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{}); |
| 804 | std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); |
| 805 | std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); |
| 806 | return error.NotEnoughPadding; |
| 792 | 807 | } |
| 808 | |
| 809 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 810 | // TODO This is clunky. |
| 811 | self.linkedit_segment_next_offset = @intCast(u32, mem.alignForwardGeneric(u64, linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize, @sizeOf(u64))); |
| 812 | // Add code signature load command |
| 813 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 814 | try self.load_commands.append(self.base.allocator, .{ |
| 815 | .LinkeditData = .{ |
| 816 | .cmd = macho.LC_CODE_SIGNATURE, |
| 817 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 818 | .dataoff = 0, |
| 819 | .datasize = 0, |
| 820 | }, |
| 821 | }); |
| 822 | |
| 823 | // Pad out space for code signature |
| 824 | try self.writeCodeSignaturePadding(); |
| 825 | // Write updated load commands and the header |
| 826 | try self.writeLoadCommands(); |
| 827 | try self.writeHeader(); |
| 828 | // Generate adhoc code signature |
| 829 | try self.writeCodeSignature(); |
| 793 | 830 | } |
| 794 | 831 | } |
| 795 | 832 | } |
| ... | ... | @@ -1925,18 +1962,18 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 1925 | 1962 | switch (cmd.cmd()) { |
| 1926 | 1963 | macho.LC_SEGMENT_64 => { |
| 1927 | 1964 | const x = cmd.Segment; |
| 1928 | | if (isSegmentOrSection(&x.inner.segname, "__PAGEZERO")) { |
| 1965 | if (parseAndCmpName(x.inner.segname[0..], "__PAGEZERO")) { |
| 1929 | 1966 | self.pagezero_segment_cmd_index = i; |
| 1930 | | } else if (isSegmentOrSection(&x.inner.segname, "__LINKEDIT")) { |
| 1967 | } else if (parseAndCmpName(x.inner.segname[0..], "__LINKEDIT")) { |
| 1931 | 1968 | self.linkedit_segment_cmd_index = i; |
| 1932 | | } else if (isSegmentOrSection(&x.inner.segname, "__TEXT")) { |
| 1969 | } else if (parseAndCmpName(x.inner.segname[0..], "__TEXT")) { |
| 1933 | 1970 | self.text_segment_cmd_index = i; |
| 1934 | 1971 | for (x.sections.items) |sect, j| { |
| 1935 | | if (isSegmentOrSection(&sect.sectname, "__text")) { |
| 1972 | if (parseAndCmpName(sect.sectname[0..], "__text")) { |
| 1936 | 1973 | self.text_section_index = @intCast(u16, j); |
| 1937 | 1974 | } |
| 1938 | 1975 | } |
| 1939 | | } else if (isSegmentOrSection(&x.inner.segname, "__DATA")) { |
| 1976 | } else if (parseAndCmpName(x.inner.segname[0..], "__DATA")) { |
| 1940 | 1977 | self.data_segment_cmd_index = i; |
| 1941 | 1978 | } |
| 1942 | 1979 | }, |
| ... | ... | @@ -1962,7 +1999,10 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 1962 | 1999 | self.main_cmd_index = i; |
| 1963 | 2000 | }, |
| 1964 | 2001 | macho.LC_LOAD_DYLIB => { |
| 1965 | | self.libsystem_cmd_index = i; // TODO This is incorrect, but we'll fixup later. |
| 2002 | const x = cmd.Dylib; |
| 2003 | if (parseAndCmpName(x.data, mem.spanZ(LIB_SYSTEM_PATH))) { |
| 2004 | self.libsystem_cmd_index = i; |
| 2005 | } |
| 1966 | 2006 | }, |
| 1967 | 2007 | macho.LC_FUNCTION_STARTS => { |
| 1968 | 2008 | self.function_starts_cmd_index = i; |
| ... | ... | @@ -1983,9 +2023,10 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 1983 | 2023 | } |
| 1984 | 2024 | self.header = header; |
| 1985 | 2025 | |
| 1986 | | // TODO parse memory mapped segments |
| 2026 | // TODO Should we parse memory mapped segments here or as needed? |
| 1987 | 2027 | } |
| 1988 | 2028 | |
| 1989 | | fn isSegmentOrSection(name: *const [16]u8, needle: []const u8) bool { |
| 1990 | | return mem.eql(u8, mem.trimRight(u8, name.*[0..], &[_]u8{0}), needle); |
| 2029 | fn parseAndCmpName(name: []const u8, needle: []const u8) bool { |
| 2030 | const len = mem.indexOfScalar(u8, name[0..], @as(u8, 0)) orelse name.len; |
| 2031 | return mem.eql(u8, name[0..len], needle); |
| 1991 | 2032 | } |