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 {
752752
753753 // At this stage, LLD has done its job. It is time to patch the resultant
754754 // 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 }
771769
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;
792807 }
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();
793830 }
794831 }
795832 }
......@@ -1925,18 +1962,18 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {
19251962 switch (cmd.cmd()) {
19261963 macho.LC_SEGMENT_64 => {
19271964 const x = cmd.Segment;
1928 if (isSegmentOrSection(&x.inner.segname, "__PAGEZERO")) {
1965 if (parseAndCmpName(x.inner.segname[0..], "__PAGEZERO")) {
19291966 self.pagezero_segment_cmd_index = i;
1930 } else if (isSegmentOrSection(&x.inner.segname, "__LINKEDIT")) {
1967 } else if (parseAndCmpName(x.inner.segname[0..], "__LINKEDIT")) {
19311968 self.linkedit_segment_cmd_index = i;
1932 } else if (isSegmentOrSection(&x.inner.segname, "__TEXT")) {
1969 } else if (parseAndCmpName(x.inner.segname[0..], "__TEXT")) {
19331970 self.text_segment_cmd_index = i;
19341971 for (x.sections.items) |sect, j| {
1935 if (isSegmentOrSection(&sect.sectname, "__text")) {
1972 if (parseAndCmpName(sect.sectname[0..], "__text")) {
19361973 self.text_section_index = @intCast(u16, j);
19371974 }
19381975 }
1939 } else if (isSegmentOrSection(&x.inner.segname, "__DATA")) {
1976 } else if (parseAndCmpName(x.inner.segname[0..], "__DATA")) {
19401977 self.data_segment_cmd_index = i;
19411978 }
19421979 },
......@@ -1962,7 +1999,10 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {
19621999 self.main_cmd_index = i;
19632000 },
19642001 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 }
19662006 },
19672007 macho.LC_FUNCTION_STARTS => {
19682008 self.function_starts_cmd_index = i;
......@@ -1983,9 +2023,10 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {
19832023 }
19842024 self.header = header;
19852025
1986 // TODO parse memory mapped segments
2026 // TODO Should we parse memory mapped segments here or as needed?
19872027}
19882028
1989fn isSegmentOrSection(name: *const [16]u8, needle: []const u8) bool {
1990 return mem.eql(u8, mem.trimRight(u8, name.*[0..], &[_]u8{0}), needle);
2029fn 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);
19912032}