Skip to content

Commit

Permalink
macho: parse platform via LC_BUILD_VERSION or LC_VERSION_MIN_* commands
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Aug 8, 2023
1 parent 349179a commit 1a0034e
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 6 deletions.
32 changes: 31 additions & 1 deletion src/MachO.zig
Original file line number Diff line number Diff line change
Expand Up @@ -647,12 +647,42 @@ fn parseObject(self: *MachO, obj: LinkObject) !void {
break :blk self.options.cpu_arch.?;
};
if (self_cpu_arch != cpu_arch) {
self.base.fatal("{s}: invalid architecture '{s}', expected '{s}'", .{
return self.base.fatal("{s}: invalid architecture '{s}', expected '{s}'", .{
obj.path,
@tagName(cpu_arch),
@tagName(self_cpu_arch),
});
}

if (object.getPlatform()) |platform| {
const self_platform = self.options.platform orelse blk: {
self.options.platform = platform;
break :blk self.options.platform.?;
};
if (self_platform.platform != platform.platform) {
return self.base.fatal(
"{s}: object file was built for different platform: expected {s}, got {s}",
.{ obj.path, @tagName(self_platform.platform), @tagName(platform.platform) },
);
}
if (self_platform.min_version.major < platform.min_version.major or
self_platform.min_version.minor < platform.min_version.minor or
self_platform.min_version.patch < platform.min_version.patch)
{
return self.base.warn(
"{s}: object file was built for newer platform version: expected {d}.{d}.{d}, got {d}.{d}.{d}",
.{
obj.path,
self_platform.min_version.major,
self_platform.min_version.minor,
self_platform.min_version.patch,
platform.min_version.major,
platform.min_version.minor,
platform.min_version.patch,
},
);
}
}
}

fn parseLibrary(self: *MachO, obj: LinkObject, dependent_libs: anytype) !void {
Expand Down
63 changes: 58 additions & 5 deletions src/MachO/Object.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const AtomIndex = MachO.AtomIndex;
const DwarfInfo = @import("DwarfInfo.zig");
const LoadCommandIterator = macho.LoadCommandIterator;
const MachO = @import("../MachO.zig");
const Options = @import("Options.zig");
const SymbolWithLoc = MachO.SymbolWithLoc;
const UnwindInfo = @import("UnwindInfo.zig");
const Zld = @import("../Zld.zig");
Expand Down Expand Up @@ -418,7 +419,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
// Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
// have to infer the start of undef section in the symtab ourselves.
const iundefsym = blk: {
const dysymtab = self.parseDysymtab() orelse {
const dysymtab = self.getDysymtab() orelse {
var iundefsym: usize = self.in_symtab.?.len;
while (iundefsym > 0) : (iundefsym -= 1) {
const sym = self.symtab[iundefsym - 1];
Expand Down Expand Up @@ -889,16 +890,14 @@ fn diceLessThan(ctx: void, lhs: macho.data_in_code_entry, rhs: macho.data_in_cod
return lhs.offset < rhs.offset;
}

fn parseDysymtab(self: Object) ?macho.dysymtab_command {
fn getDysymtab(self: Object) ?macho.dysymtab_command {
var it = LoadCommandIterator{
.ncmds = self.header.ncmds,
.buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
};
while (it.next()) |cmd| {
switch (cmd.cmd()) {
.DYSYMTAB => {
return cmd.cast(macho.dysymtab_command).?;
},
.DYSYMTAB => return cmd.cast(macho.dysymtab_command).?,
else => {},
}
} else return null;
Expand All @@ -924,6 +923,60 @@ pub fn parseDwarfInfo(self: Object) DwarfInfo {
return di;
}

pub fn getPlatform(self: Object) ?Options.Platform {
var it = LoadCommandIterator{
.ncmds = self.header.ncmds,
.buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
};
while (it.next()) |cmd| {
switch (cmd.cmd()) {
.BUILD_VERSION => {
const lc = cmd.cast(macho.build_version_command).?;
return .{
.platform = lc.platform,
.min_version = .{
.major = @as(u16, @truncate(lc.minos >> 16)),
.minor = @as(u8, @truncate(lc.minos >> 8)),
.patch = @as(u8, @truncate(lc.minos)),
},
.sdk_version = .{
.major = @as(u16, @truncate(lc.sdk >> 16)),
.minor = @as(u8, @truncate(lc.sdk >> 8)),
.patch = @as(u8, @truncate(lc.sdk)),
},
};
},
.VERSION_MIN_MACOSX,
.VERSION_MIN_IPHONEOS,
.VERSION_MIN_TVOS,
.VERSION_MIN_WATCHOS,
=> {
const lc = cmd.cast(macho.version_min_command).?;
return .{
.platform = switch (cmd.cmd()) {
.VERSION_MIN_MACOSX => .MACOS,
.VERSION_MIN_IPHONEOS => .IOS,
.VERSION_MIN_TVOS => .TVOS,
.VERSION_MIN_WATCHOS => .WATCHOS,
else => unreachable,
},
.min_version = .{
.major = @as(u16, @truncate(lc.version >> 16)),
.minor = @as(u8, @truncate(lc.version >> 8)),
.patch = @as(u8, @truncate(lc.version)),
},
.sdk_version = .{
.major = @as(u16, @truncate(lc.sdk >> 16)),
.minor = @as(u8, @truncate(lc.sdk >> 8)),
.patch = @as(u8, @truncate(lc.sdk)),
},
};
},
else => {},
}
} else return null;
}

pub fn getSectionContents(self: Object, sect: macho.section_64) []const u8 {
const size = @as(usize, @intCast(sect.size));
return self.contents[sect.offset..][0..size];
Expand Down

0 comments on commit 1a0034e

Please sign in to comment.