Skip to content

Commit

Permalink
write/macho: Add support for LC_BUILD_VERSION command (gimli-rs#524)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomcc authored Mar 27, 2023
1 parent 7a256e1 commit 09b295c
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/write/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@ struct SymbolOffsets {
str_id: Option<StringId>,
}

/// The customizable portion of a [`macho::BuildVersionCommand`].
#[derive(Debug, Default, Clone, Copy)]
#[non_exhaustive] // May want to add the tool list?
pub struct MachOBuildVersion {
/// One of the `PLATFORM_` constants (for example,
/// [`object::macho::PLATFORM_MACOS`](macho::PLATFORM_MACOS)).
pub platform: u32,
/// The minimum OS version, where `X.Y.Z` is encoded in nibbles as
/// `xxxx.yy.zz`.
pub minos: u32,
/// The SDK version as `X.Y.Z`, where `X.Y.Z` is encoded in nibbles as
/// `xxxx.yy.zz`.
pub sdk: u32,
}

impl MachOBuildVersion {
fn cmdsize(&self) -> u32 {
// Same size for both endianness, and we don't have `ntools`.
let sz = mem::size_of::<macho::BuildVersionCommand<Endianness>>();
debug_assert!(sz <= u32::MAX as usize);
sz as u32
}
}

impl<'a> Object<'a> {
pub(crate) fn macho_set_subsections_via_symbols(&mut self) {
let flags = match self.flags {
Expand Down Expand Up @@ -213,6 +237,12 @@ impl<'a> Object<'a> {
let mut ncmds = 0;
let command_offset = offset;

let build_version_offset = offset;
if let Some(version) = &self.macho_build_version {
offset += version.cmdsize() as usize;
ncmds += 1;
}

// Calculate size of segment command and section headers.
let segment_command_offset = offset;
let segment_command_len =
Expand Down Expand Up @@ -352,6 +382,18 @@ impl<'a> Object<'a> {
},
);

if let Some(version) = &self.macho_build_version {
debug_assert_eq!(build_version_offset, buffer.len());
buffer.write(&macho::BuildVersionCommand {
cmd: U32::new(endian, macho::LC_BUILD_VERSION),
cmdsize: U32::new(endian, version.cmdsize()),
platform: U32::new(endian, version.platform),
minos: U32::new(endian, version.minos),
sdk: U32::new(endian, version.sdk),
ntools: U32::new(endian, 0),
});
}

// Write segment command.
debug_assert_eq!(segment_command_offset, buffer.len());
macho.write_segment_command(
Expand Down
15 changes: 15 additions & 0 deletions src/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub mod elf;

#[cfg(feature = "macho")]
mod macho;
#[cfg(feature = "macho")]
pub use macho::MachOBuildVersion;

#[cfg(feature = "pe")]
pub mod pe;
Expand Down Expand Up @@ -70,6 +72,8 @@ pub struct Object<'a> {
pub mangling: Mangling,
/// Mach-O "_tlv_bootstrap" symbol.
tlv_bootstrap: Option<SymbolId>,
#[cfg(feature = "macho")]
macho_build_version: Option<MachOBuildVersion>,
}

impl<'a> Object<'a> {
Expand All @@ -88,6 +92,8 @@ impl<'a> Object<'a> {
flags: FileFlags::None,
mangling: Mangling::default(format, architecture),
tlv_bootstrap: None,
#[cfg(feature = "macho")]
macho_build_version: None,
}
}

Expand Down Expand Up @@ -115,6 +121,15 @@ impl<'a> Object<'a> {
self.mangling = mangling;
}

/// Specify information for a Mach-O `LC_BUILD_VERSION` command.
///
/// Requires `feature = "macho"`.
#[inline]
#[cfg(feature = "macho")]
pub fn set_macho_build_version(&mut self, info: MachOBuildVersion) {
self.macho_build_version = Some(info);
}

/// Return the name for a standard segment.
///
/// This will vary based on the file format.
Expand Down

0 comments on commit 09b295c

Please sign in to comment.