| ... | @@ -752,44 +752,81 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -752,44 +752,81 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 752 | | 752 | |
| 753 | // At this stage, LLD has done its job. It is time to patch the resultant | 753 | // At this stage, LLD has done its job. It is time to patch the resultant |
| 754 | // binaries up! | 754 | // binaries up! |
| 755 | // This is currently needed only for aarch64 targets. | 755 | const out_file = try directory.handle.openFile(self.base.options.emit.?.sub_path, .{ .write = true }); |
| 756 | if (target.cpu.arch == .aarch64) { | 756 | try self.parseFromFile(out_file); |
| 757 | const out_file = try directory.handle.openFile(self.base.options.emit.?.sub_path, .{ .write = true }); | 757 | if (self.libsystem_cmd_index == null) { |
| 758 | try self.parseFromFile(out_file); | 758 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 759 | if (self.code_signature_cmd_index == null) { | 759 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 760 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 760 | const after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64); |
| 761 | const text_section = text_segment.sections.items[self.text_section_index.?]; | 761 | const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den; |
| 762 | const after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64); | 762 | |
| 763 | const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den; | 763 | if (needed_size + after_last_cmd_offset > text_section.offset) { |
| 764 | | 764 | std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{}); |
| 765 | if (needed_size + after_last_cmd_offset > text_section.offset) { | 765 | std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); |
| 766 | std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{}); | 766 | std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); |
| 767 | std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); | 767 | return error.NotEnoughPadding; |
| 768 | std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); | 768 | } |
| 769 | return error.NotEnoughPadding; | | |
| 770 | } | | |
| 771 | | 769 | |
| 772 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 770 | // Add load dylib load command |
| 773 | // TODO This is clunky. | 771 | self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 774 | self.linkedit_segment_next_offset = @intCast(u32, mem.alignForwardGeneric(u64, linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize, @sizeOf(u64))); | 772 | const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), @sizeOf(u64)); |
| 775 | // Add code signature load command | 773 | // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. |
| 776 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | 774 | // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0. |
| 777 | try self.load_commands.append(self.base.allocator, .{ | 775 | const min_version = 0x0; |
| 778 | .LinkeditData = .{ | 776 | var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ |
| 779 | .cmd = macho.LC_CODE_SIGNATURE, | 777 | .cmd = macho.LC_LOAD_DYLIB, |
| 780 | .cmdsize = @sizeOf(macho.linkedit_data_command), | 778 | .cmdsize = @intCast(u32, cmdsize), |
| 781 | .dataoff = 0, | 779 | .dylib = .{ |
| 782 | .datasize = 0, | 780 | .name = @sizeOf(macho.dylib_command), |
| 783 | }, | 781 | .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files |
| 784 | }); | 782 | .current_version = min_version, |
| 785 | // Pad out space for code signature | 783 | .compatibility_version = min_version, |
| 786 | try self.writeCodeSignaturePadding(); | 784 | }, |
| 787 | // Write updated load commands and the header | 785 | }); |
| 788 | try self.writeLoadCommands(); | 786 | dylib_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); |
| 789 | try self.writeHeader(); | 787 | mem.set(u8, dylib_cmd.data, 0); |
| 790 | // Generate adhoc code signature | 788 | mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH)); |
| 791 | try self.writeCodeSignature(); | 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,18 +1962,18 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 1925 | switch (cmd.cmd()) { | 1962 | switch (cmd.cmd()) { |
| 1926 | macho.LC_SEGMENT_64 => { | 1963 | macho.LC_SEGMENT_64 => { |
| 1927 | const x = cmd.Segment; | 1964 | const x = cmd.Segment; |
| 1928 | if (isSegmentOrSection(&x.inner.segname, "__PAGEZERO")) { | 1965 | if (parseAndCmpName(x.inner.segname[0..], "__PAGEZERO")) { |
| 1929 | self.pagezero_segment_cmd_index = i; | 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 | self.linkedit_segment_cmd_index = i; | 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 | self.text_segment_cmd_index = i; | 1970 | self.text_segment_cmd_index = i; |
| 1934 | for (x.sections.items) |sect, j| { | 1971 | for (x.sections.items) |sect, j| { |
| 1935 | if (isSegmentOrSection(&sect.sectname, "__text")) { | 1972 | if (parseAndCmpName(sect.sectname[0..], "__text")) { |
| 1936 | self.text_section_index = @intCast(u16, j); | 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 | self.data_segment_cmd_index = i; | 1977 | self.data_segment_cmd_index = i; |
| 1941 | } | 1978 | } |
| 1942 | }, | 1979 | }, |
| ... | @@ -1962,7 +1999,10 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { | ... | @@ -1962,7 +1999,10 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 1962 | self.main_cmd_index = i; | 1999 | self.main_cmd_index = i; |
| 1963 | }, | 2000 | }, |
| 1964 | macho.LC_LOAD_DYLIB => { | 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 | macho.LC_FUNCTION_STARTS => { | 2007 | macho.LC_FUNCTION_STARTS => { |
| 1968 | self.function_starts_cmd_index = i; | 2008 | self.function_starts_cmd_index = i; |
| ... | @@ -1983,9 +2023,10 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { | ... | @@ -1983,9 +2023,10 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 1983 | } | 2023 | } |
| 1984 | self.header = header; | 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 { | 2029 | fn parseAndCmpName(name: []const u8, needle: []const u8) bool { |
| 1990 | return mem.eql(u8, mem.trimRight(u8, name.*[0..], &[_]u8{0}), needle); | 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 | } |