stage2 MachO: add min OS version load cmd

master
Jakub Konka 2020-11-12 21:07:06 +01:00
parent 58365c4e79
commit 72310db1da
2 changed files with 39 additions and 4 deletions

View File

@ -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

View File

@ -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;