authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-12 21:07:06+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-26 11:50:09+01:00
log72310db1da792aae05edffe96082d97bb04cf7e5
tree726c7c1d6d6c8692b784a1518868d9bc4b7780be
parent58365c4e79479157bb0b4c2d66ad96c9a394651d

stage2 MachO: add min OS version load cmd


2 files changed, 39 insertions(+), 4 deletions(-)

lib/std/macho.zig+17
...@@ -705,6 +705,23 @@ pub const relocation_info = packed struct {...@@ -705,6 +705,23 @@ pub const relocation_info = packed struct {
705 r_type: u4,705 r_type: u4,
706};706};
707707
708/// The version_min_command contains the min OS version on which this
709/// binary was built to run.
710pub const version_min_command = extern struct {
711 /// LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_WATCHOS
712 /// or LC_VERSION_MIN_TVOS
713 cmd: u32,
714
715 /// sizeof(struct min_version_command)
716 cmdsize: u32,
717
718 /// X.Y.Z is encoded in nibbles xxxx.yy.zz
719 version: u32,
720
721 /// X.Y.Z is encoded in nibbles xxxx.yy.zz
722 sdk: u32,
723};
724
708/// After MacOS X 10.1 when a new load command is added that is required to be725/// After MacOS X 10.1 when a new load command is added that is required to be
709/// understood by the dynamic linker for the image to execute properly the726/// understood by the dynamic linker for the image to execute properly the
710/// LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic727/// LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic
src/link/MachO.zig+22-4
...@@ -33,6 +33,7 @@ const LoadCommand = union(enum) {...@@ -33,6 +33,7 @@ const LoadCommand = union(enum) {
33 Dylinker: macho.dylinker_command,33 Dylinker: macho.dylinker_command,
34 Dylib: macho.dylib_command,34 Dylib: macho.dylib_command,
35 EntryPoint: macho.entry_point_command,35 EntryPoint: macho.entry_point_command,
36 MinVersion: macho.version_min_command,
3637
37 pub fn cmdsize(self: LoadCommand) u32 {38 pub fn cmdsize(self: LoadCommand) u32 {
38 return switch (self) {39 return switch (self) {
...@@ -44,6 +45,7 @@ const LoadCommand = union(enum) {...@@ -44,6 +45,7 @@ const LoadCommand = union(enum) {
44 .Dylinker => |x| x.cmdsize,45 .Dylinker => |x| x.cmdsize,
45 .Dylib => |x| x.cmdsize,46 .Dylib => |x| x.cmdsize,
46 .EntryPoint => |x| x.cmdsize,47 .EntryPoint => |x| x.cmdsize,
48 .MinVersion => |x| x.cmdsize,
47 };49 };
48 }50 }
4951
...@@ -57,6 +59,7 @@ const LoadCommand = union(enum) {...@@ -57,6 +59,7 @@ const LoadCommand = union(enum) {
57 .Dylinker => |cmd| writeGeneric(cmd, file, offset),59 .Dylinker => |cmd| writeGeneric(cmd, file, offset),
58 .Dylib => |cmd| writeGeneric(cmd, file, offset),60 .Dylib => |cmd| writeGeneric(cmd, file, offset),
59 .EntryPoint => |cmd| writeGeneric(cmd, file, offset),61 .EntryPoint => |cmd| writeGeneric(cmd, file, offset),
62 .MinVersion => |cmd| writeGeneric(cmd, file, offset),
60 };63 };
61 }64 }
6265
...@@ -96,6 +99,8 @@ function_starts_cmd_index: ?u16 = null,...@@ -96,6 +99,8 @@ function_starts_cmd_index: ?u16 = null,
96/// Specifies offset wrt __TEXT segment start address to the main entry point99/// Specifies offset wrt __TEXT segment start address to the main entry point
97/// of the binary.100/// of the binary.
98main_cmd_index: ?u16 = null,101main_cmd_index: ?u16 = null,
102/// Minimum OS version
103version_min_cmd_index: ?u16 = null,
99104
100/// Table of all sections105/// Table of all sections
101sections: std.ArrayListUnmanaged(macho.section_64) = .{},106sections: std.ArrayListUnmanaged(macho.section_64) = .{},
...@@ -317,8 +322,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -317,8 +322,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
317 try self.writeAllGlobalSymbols();322 try self.writeAllGlobalSymbols();
318 try self.writeAllUndefSymbols();323 try self.writeAllUndefSymbols();
319324
320 try self.writeStringTable();
321
322 switch (self.base.options.output_mode) {325 switch (self.base.options.output_mode) {
323 .Exe => {326 .Exe => {
324 // Write export trie.327 // Write export trie.
...@@ -379,8 +382,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -379,8 +382,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
379 const nundefs = @intCast(u32, self.undef_symbols.items.len);382 const nundefs = @intCast(u32, self.undef_symbols.items.len);
380 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;383 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
381 symtab.nsyms = nlocals + nglobals + nundefs;384 symtab.nsyms = nlocals + nglobals + nundefs;
385 symtab.stroff = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64);
382 }386 }
383387
388 try self.writeStringTable();
389
384 if (self.cmd_table_dirty) {390 if (self.cmd_table_dirty) {
385 try self.writeCmdHeaders();391 try self.writeCmdHeaders();
386 try self.writeMachOHeader();392 try self.writeMachOHeader();
...@@ -1329,8 +1335,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1329,8 +1335,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1329 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);1335 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
1330 const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), @sizeOf(u64));1336 const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), @sizeOf(u64));
1331 // TODO Find a way to work out runtime version from the OS version triple stored in std.Target.1337 // TODO Find a way to work out runtime version from the OS version triple stored in std.Target.
1332 // In the meantime, we're gonna hardcode to the minimum compatibility version of 1.0.0.1338 // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0.
1333 const min_version = 0x10000;1339 const min_version = 0x0;
1334 const dylib = .{1340 const dylib = .{
1335 .name = @sizeOf(macho.dylib_command),1341 .name = @sizeOf(macho.dylib_command),
1336 .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files1342 .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 {...@@ -1359,6 +1365,18 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1359 });1365 });
1360 self.cmd_table_dirty = true;1366 self.cmd_table_dirty = true;
1361 }1367 }
1368 if (self.version_min_cmd_index == null) {
1369 self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len);
1370 try self.load_commands.append(self.base.allocator, .{
1371 // TODO allow for different targets and different versions
1372 .MinVersion = .{
1373 .cmd = macho.LC_VERSION_MIN_MACOSX,
1374 .cmdsize = @sizeOf(macho.version_min_command),
1375 .version = 0xB0001, // 11.0.1 BigSur
1376 .sdk = 0xB0001, // 11.0.1 BigSur
1377 },
1378 });
1379 }
1362 {1380 {
1363 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;1381 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1364 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;1382 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;