authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-05 10:57:05+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-17 10:04:53+01:00
logeb528a9cbc4baebe16dda686bdc55d0feee82087
tree900bfed0e3ea702ec15bb366113bbf940c7174ed
parent6dfe9cc83ea75a663b4f6dfa488b95950207a1cf

lld+macho: add missing LC_LOAD_DYLIB cmd


1 files changed, 86 insertions(+), 45 deletions(-)

src/link/MachO.zig+86-45
...@@ -752,44 +752,81 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -752,44 +752,81 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
752752
753 // At this stage, LLD has done its job. It is time to patch the resultant753 // 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) {
764764 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 }
771769
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 command773 // 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 signature783 .compatibility_version = min_version,
786 try self.writeCodeSignaturePadding();784 },
787 // Write updated load commands and the header785 });
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 signature788 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;
19852025
1986 // TODO parse memory mapped segments2026 // TODO Should we parse memory mapped segments here or as needed?
1987}2027}
19882028
1989fn isSegmentOrSection(name: *const [16]u8, needle: []const u8) bool {2029fn 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}