Skip to content

Mach-O: Parse macOS version #514

@konstin

Description

@konstin

This is a quality-of-life feature request: Could goblin parse the minimum macOS version in Mach-O files?

We're currently using custom parsing logic for it (following https://github.com/matthew-brett/delocate/blob/a97bc907ea5fab9256e2c92b995b332605fcd98b/delocate/delocating.py#L468-L480). Parsing the xxxx.yy.zz format is something that sounds like it fits into the scope of a Mach-O reader.

let mut min_macos_version: Option<MacOSVersion> = None;

for cmd in &macho.load_commands {
    match cmd.command {
        load_command::CommandVariant::BuildVersion(ref build_ver) => {
            // LC_BUILD_VERSION is used in modern binaries; platform 1 = MACOS.
            if build_ver.platform == 1 {
                let version = MacOSVersion::from_packed(build_ver.minos);
                min_macos_version = Some(
                    min_macos_version
                        .map_or(version, |current| std::cmp::max(current, version)),
                );
            }
        }
        load_command::CommandVariant::VersionMinMacosx(ref ver) => {
            // LC_VERSION_MIN_MACOSX is used in older binaries.
            let version = MacOSVersion::from_packed(ver.version);
            min_macos_version = Some(
                min_macos_version.map_or(version, |current| std::cmp::max(current, version)),
            );
        }
        _ => {}
    }
}

// ...

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct MacOSVersion {
    pub major: u16,
    pub minor: u16,
}

impl MacOSVersion {
    /// Parse from a packed version (used in Mach-O `LC_BUILD_VERSION` and `LC_VERSION_MIN_MACOSX`).
    ///
    /// Format: `xxxx.yy.zz` where `x` is major, `y` is minor, `z` is patch (ignored).
    #[allow(clippy::cast_possible_truncation)]
    pub const fn from_packed(packed: u32) -> Self {
        Self {
            major: ((packed >> 16) & 0xFFFF) as u16,
            minor: ((packed >> 8) & 0xFF) as u16,
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions