From 72310db1da792aae05edffe96082d97bb04cf7e5 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 12 Nov 2020 21:07:06 +0100 Subject: stage2 MachO: add min OS version load cmd --- lib/std/macho.zig | 17 +++++++++++++++++ src/link/MachO.zig | 26 ++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/std/macho.zig b/lib/std/macho.zig index 4e4e648812..2dcc4b4b37 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -705,6 +705,23 @@ pub const relocation_info = packed struct { r_type: u4, }; +/// The version_min_command contains the min OS version on which this +/// binary was built to run. +pub const version_min_command = extern struct { + /// LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_WATCHOS + /// or LC_VERSION_MIN_TVOS + cmd: u32, + + /// sizeof(struct min_version_command) + cmdsize: u32, + + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + version: u32, + + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + sdk: u32, +}; + /// After MacOS X 10.1 when a new load command is added that is required to be /// understood by the dynamic linker for the image to execute properly the /// LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 799a94bb20..611f3af541 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -33,6 +33,7 @@ const LoadCommand = union(enum) { Dylinker: macho.dylinker_command, Dylib: macho.dylib_command, EntryPoint: macho.entry_point_command, + MinVersion: macho.version_min_command, pub fn cmdsize(self: LoadCommand) u32 { return switch (self) { @@ -44,6 +45,7 @@ const LoadCommand = union(enum) { .Dylinker => |x| x.cmdsize, .Dylib => |x| x.cmdsize, .EntryPoint => |x| x.cmdsize, + .MinVersion => |x| x.cmdsize, }; } @@ -57,6 +59,7 @@ const LoadCommand = union(enum) { .Dylinker => |cmd| writeGeneric(cmd, file, offset), .Dylib => |cmd| writeGeneric(cmd, file, offset), .EntryPoint => |cmd| writeGeneric(cmd, file, offset), + .MinVersion => |cmd| writeGeneric(cmd, file, offset), }; } @@ -96,6 +99,8 @@ function_starts_cmd_index: ?u16 = null, /// Specifies offset wrt __TEXT segment start address to the main entry point /// of the binary. main_cmd_index: ?u16 = null, +/// Minimum OS version +version_min_cmd_index: ?u16 = null, /// Table of all sections sections: std.ArrayListUnmanaged(macho.section_64) = .{}, @@ -317,8 +322,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { try self.writeAllGlobalSymbols(); try self.writeAllUndefSymbols(); - try self.writeStringTable(); - switch (self.base.options.output_mode) { .Exe => { // Write export trie. @@ -379,8 +382,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { const nundefs = @intCast(u32, self.undef_symbols.items.len); const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; symtab.nsyms = nlocals + nglobals + nundefs; + symtab.stroff = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64); } + try self.writeStringTable(); + if (self.cmd_table_dirty) { try self.writeCmdHeaders(); try self.writeMachOHeader(); @@ -1329,8 +1335,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), @sizeOf(u64)); // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. - // In the meantime, we're gonna hardcode to the minimum compatibility version of 1.0.0. - const min_version = 0x10000; + // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0. + const min_version = 0x0; const dylib = .{ .name = @sizeOf(macho.dylib_command), .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files @@ -1359,6 +1365,18 @@ pub fn populateMissingMetadata(self: *MachO) !void { }); self.cmd_table_dirty = true; } + if (self.version_min_cmd_index == null) { + self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len); + try self.load_commands.append(self.base.allocator, .{ + // TODO allow for different targets and different versions + .MinVersion = .{ + .cmd = macho.LC_VERSION_MIN_MACOSX, + .cmdsize = @sizeOf(macho.version_min_command), + .version = 0xB0001, // 11.0.1 BigSur + .sdk = 0xB0001, // 11.0.1 BigSur + }, + }); + } { const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; -- cgit v1.2.3