aboutsummaryrefslogtreecommitdiff
path: root/vendor/object/src/write/macho.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/object/src/write/macho.rs')
-rw-r--r--vendor/object/src/write/macho.rs1095
1 files changed, 0 insertions, 1095 deletions
diff --git a/vendor/object/src/write/macho.rs b/vendor/object/src/write/macho.rs
deleted file mode 100644
index 1c61523..0000000
--- a/vendor/object/src/write/macho.rs
+++ /dev/null
@@ -1,1095 +0,0 @@
-use core::mem;
-
-use crate::endian::*;
-use crate::macho;
-use crate::write::string::*;
-use crate::write::util::*;
-use crate::write::*;
-use crate::AddressSize;
-
-#[derive(Default, Clone, Copy)]
-struct SectionOffsets {
- index: usize,
- offset: usize,
- address: u64,
- reloc_offset: usize,
- reloc_count: usize,
-}
-
-#[derive(Default, Clone, Copy)]
-struct SymbolOffsets {
- index: usize,
- 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
- }
-}
-
-// Public methods.
-impl<'a> Object<'a> {
- /// Specify the Mach-O CPU subtype.
- ///
- /// Requires `feature = "macho"`.
- #[inline]
- pub fn set_macho_cpu_subtype(&mut self, cpu_subtype: u32) {
- self.macho_cpu_subtype = Some(cpu_subtype);
- }
-
- /// Specify information for a Mach-O `LC_BUILD_VERSION` command.
- ///
- /// Requires `feature = "macho"`.
- #[inline]
- pub fn set_macho_build_version(&mut self, info: MachOBuildVersion) {
- self.macho_build_version = Some(info);
- }
-}
-
-// Private methods.
-impl<'a> Object<'a> {
- pub(crate) fn macho_set_subsections_via_symbols(&mut self) {
- let flags = match self.flags {
- FileFlags::MachO { flags } => flags,
- _ => 0,
- };
- self.flags = FileFlags::MachO {
- flags: flags | macho::MH_SUBSECTIONS_VIA_SYMBOLS,
- };
- }
-
- pub(crate) fn macho_segment_name(&self, segment: StandardSegment) -> &'static [u8] {
- match segment {
- StandardSegment::Text => &b"__TEXT"[..],
- StandardSegment::Data => &b"__DATA"[..],
- StandardSegment::Debug => &b"__DWARF"[..],
- }
- }
-
- pub(crate) fn macho_section_info(
- &self,
- section: StandardSection,
- ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
- match section {
- StandardSection::Text => (
- &b"__TEXT"[..],
- &b"__text"[..],
- SectionKind::Text,
- SectionFlags::None,
- ),
- StandardSection::Data => (
- &b"__DATA"[..],
- &b"__data"[..],
- SectionKind::Data,
- SectionFlags::None,
- ),
- StandardSection::ReadOnlyData => (
- &b"__TEXT"[..],
- &b"__const"[..],
- SectionKind::ReadOnlyData,
- SectionFlags::None,
- ),
- StandardSection::ReadOnlyDataWithRel => (
- &b"__DATA"[..],
- &b"__const"[..],
- SectionKind::ReadOnlyDataWithRel,
- SectionFlags::None,
- ),
- StandardSection::ReadOnlyString => (
- &b"__TEXT"[..],
- &b"__cstring"[..],
- SectionKind::ReadOnlyString,
- SectionFlags::None,
- ),
- StandardSection::UninitializedData => (
- &b"__DATA"[..],
- &b"__bss"[..],
- SectionKind::UninitializedData,
- SectionFlags::None,
- ),
- StandardSection::Tls => (
- &b"__DATA"[..],
- &b"__thread_data"[..],
- SectionKind::Tls,
- SectionFlags::None,
- ),
- StandardSection::UninitializedTls => (
- &b"__DATA"[..],
- &b"__thread_bss"[..],
- SectionKind::UninitializedTls,
- SectionFlags::None,
- ),
- StandardSection::TlsVariables => (
- &b"__DATA"[..],
- &b"__thread_vars"[..],
- SectionKind::TlsVariables,
- SectionFlags::None,
- ),
- StandardSection::Common => (
- &b"__DATA"[..],
- &b"__common"[..],
- SectionKind::Common,
- SectionFlags::None,
- ),
- StandardSection::GnuProperty => {
- // Unsupported section.
- (&[], &[], SectionKind::Note, SectionFlags::None)
- }
- }
- }
-
- fn macho_tlv_bootstrap(&mut self) -> SymbolId {
- match self.tlv_bootstrap {
- Some(id) => id,
- None => {
- let id = self.add_symbol(Symbol {
- name: b"_tlv_bootstrap".to_vec(),
- value: 0,
- size: 0,
- kind: SymbolKind::Text,
- scope: SymbolScope::Dynamic,
- weak: false,
- section: SymbolSection::Undefined,
- flags: SymbolFlags::None,
- });
- self.tlv_bootstrap = Some(id);
- id
- }
- }
- }
-
- /// Create the `__thread_vars` entry for a TLS variable.
- ///
- /// The symbol given by `symbol_id` will be updated to point to this entry.
- ///
- /// A new `SymbolId` will be returned. The caller must update this symbol
- /// to point to the initializer.
- ///
- /// If `symbol_id` is not for a TLS variable, then it is returned unchanged.
- pub(crate) fn macho_add_thread_var(&mut self, symbol_id: SymbolId) -> SymbolId {
- let symbol = self.symbol_mut(symbol_id);
- if symbol.kind != SymbolKind::Tls {
- return symbol_id;
- }
-
- // Create the initializer symbol.
- let mut name = symbol.name.clone();
- name.extend_from_slice(b"$tlv$init");
- let init_symbol_id = self.add_raw_symbol(Symbol {
- name,
- value: 0,
- size: 0,
- kind: SymbolKind::Tls,
- scope: SymbolScope::Compilation,
- weak: false,
- section: SymbolSection::Undefined,
- flags: SymbolFlags::None,
- });
-
- // Add the tlv entry.
- // Three pointers in size:
- // - __tlv_bootstrap - used to make sure support exists
- // - spare pointer - used when mapped by the runtime
- // - pointer to symbol initializer
- let section = self.section_id(StandardSection::TlsVariables);
- let address_size = self.architecture.address_size().unwrap().bytes();
- let size = u64::from(address_size) * 3;
- let data = vec![0; size as usize];
- let offset = self.append_section_data(section, &data, u64::from(address_size));
-
- let tlv_bootstrap = self.macho_tlv_bootstrap();
- self.add_relocation(
- section,
- Relocation {
- offset,
- size: address_size * 8,
- kind: RelocationKind::Absolute,
- encoding: RelocationEncoding::Generic,
- symbol: tlv_bootstrap,
- addend: 0,
- },
- )
- .unwrap();
- self.add_relocation(
- section,
- Relocation {
- offset: offset + u64::from(address_size) * 2,
- size: address_size * 8,
- kind: RelocationKind::Absolute,
- encoding: RelocationEncoding::Generic,
- symbol: init_symbol_id,
- addend: 0,
- },
- )
- .unwrap();
-
- // Update the symbol to point to the tlv.
- let symbol = self.symbol_mut(symbol_id);
- symbol.value = offset;
- symbol.size = size;
- symbol.section = SymbolSection::Section(section);
-
- init_symbol_id
- }
-
- pub(crate) fn macho_fixup_relocation(&mut self, relocation: &mut Relocation) -> i64 {
- let relative = match relocation.kind {
- RelocationKind::Relative
- | RelocationKind::GotRelative
- | RelocationKind::PltRelative
- | RelocationKind::MachO { relative: true, .. } => true,
- _ => false,
- };
- if relative {
- // For PC relative relocations on some architectures, the
- // addend does not include the offset required due to the
- // PC being different from the place of the relocation.
- // This differs from other file formats, so adjust the
- // addend here to account for this.
- let pcrel_offset = match self.architecture {
- Architecture::I386 => 4,
- Architecture::X86_64 => match relocation.kind {
- RelocationKind::MachO {
- value: macho::X86_64_RELOC_SIGNED_1,
- ..
- } => 5,
- RelocationKind::MachO {
- value: macho::X86_64_RELOC_SIGNED_2,
- ..
- } => 6,
- RelocationKind::MachO {
- value: macho::X86_64_RELOC_SIGNED_4,
- ..
- } => 8,
- _ => 4,
- },
- // TODO: maybe missing support for some architectures and relocations
- _ => 0,
- };
- relocation.addend += pcrel_offset;
- }
- // Aarch64 relocs of these sizes act as if they are double-word length
- if self.architecture == Architecture::Aarch64 && matches!(relocation.size, 12 | 21 | 26) {
- relocation.size = 32;
- }
- // Check for relocations that use an explicit addend.
- if self.architecture == Architecture::Aarch64 {
- if relocation.encoding == RelocationEncoding::AArch64Call {
- return 0;
- }
- if let RelocationKind::MachO { value, .. } = relocation.kind {
- match value {
- macho::ARM64_RELOC_BRANCH26
- | macho::ARM64_RELOC_PAGE21
- | macho::ARM64_RELOC_PAGEOFF12 => return 0,
- _ => {}
- }
- }
- }
- // Signify implicit addend.
- let constant = relocation.addend;
- relocation.addend = 0;
- constant
- }
-
- pub(crate) fn macho_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
- let address_size = self.architecture.address_size().unwrap();
- let endian = self.endian;
- let macho32 = MachO32 { endian };
- let macho64 = MachO64 { endian };
- let macho: &dyn MachO = match address_size {
- AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => &macho32,
- AddressSize::U64 => &macho64,
- };
- let pointer_align = address_size.bytes() as usize;
-
- // Calculate offsets of everything, and build strtab.
- let mut offset = 0;
-
- // Calculate size of Mach-O header.
- offset += macho.mach_header_size();
-
- // Calculate size of commands.
- let mut ncmds = 0;
- let command_offset = offset;
-
- // Calculate size of segment command and section headers.
- let segment_command_offset = offset;
- let segment_command_len =
- macho.segment_command_size() + self.sections.len() * macho.section_header_size();
- offset += segment_command_len;
- ncmds += 1;
-
- // Calculate size of build version.
- let build_version_offset = offset;
- if let Some(version) = &self.macho_build_version {
- offset += version.cmdsize() as usize;
- ncmds += 1;
- }
-
- // Calculate size of symtab command.
- let symtab_command_offset = offset;
- let symtab_command_len = mem::size_of::<macho::SymtabCommand<Endianness>>();
- offset += symtab_command_len;
- ncmds += 1;
-
- // Calculate size of dysymtab command.
- let dysymtab_command_offset = offset;
- let dysymtab_command_len = mem::size_of::<macho::DysymtabCommand<Endianness>>();
- offset += dysymtab_command_len;
- ncmds += 1;
-
- let sizeofcmds = offset - command_offset;
-
- // Calculate size of section data.
- // Section data can immediately follow the load commands without any alignment padding.
- let segment_file_offset = offset;
- let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
- let mut address = 0;
- for (index, section) in self.sections.iter().enumerate() {
- section_offsets[index].index = 1 + index;
- if !section.is_bss() {
- address = align_u64(address, section.align);
- section_offsets[index].address = address;
- section_offsets[index].offset = segment_file_offset + address as usize;
- address += section.size;
- }
- }
- let segment_file_size = address as usize;
- offset += address as usize;
- for (index, section) in self.sections.iter().enumerate() {
- if section.is_bss() {
- debug_assert!(section.data.is_empty());
- address = align_u64(address, section.align);
- section_offsets[index].address = address;
- address += section.size;
- }
- }
-
- // Partition symbols and add symbol strings to strtab.
- let mut strtab = StringTable::default();
- let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
- let mut local_symbols = vec![];
- let mut external_symbols = vec![];
- let mut undefined_symbols = vec![];
- for (index, symbol) in self.symbols.iter().enumerate() {
- // The unified API allows creating symbols that we don't emit, so filter
- // them out here.
- //
- // Since we don't actually emit the symbol kind, we validate it here too.
- match symbol.kind {
- SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls | SymbolKind::Unknown => {}
- SymbolKind::File | SymbolKind::Section => continue,
- SymbolKind::Null | SymbolKind::Label => {
- return Err(Error(format!(
- "unimplemented symbol `{}` kind {:?}",
- symbol.name().unwrap_or(""),
- symbol.kind
- )));
- }
- }
- if !symbol.name.is_empty() {
- symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
- }
- if symbol.is_undefined() {
- undefined_symbols.push(index);
- } else if symbol.is_local() {
- local_symbols.push(index);
- } else {
- external_symbols.push(index);
- }
- }
-
- external_symbols.sort_by_key(|index| &*self.symbols[*index].name);
- undefined_symbols.sort_by_key(|index| &*self.symbols[*index].name);
-
- // Count symbols.
- let mut nsyms = 0;
- for index in local_symbols
- .iter()
- .copied()
- .chain(external_symbols.iter().copied())
- .chain(undefined_symbols.iter().copied())
- {
- symbol_offsets[index].index = nsyms;
- nsyms += 1;
- }
-
- // Calculate size of relocations.
- for (index, section) in self.sections.iter().enumerate() {
- let count: usize = section
- .relocations
- .iter()
- .map(|reloc| 1 + usize::from(reloc.addend != 0))
- .sum();
- if count != 0 {
- offset = align(offset, pointer_align);
- section_offsets[index].reloc_offset = offset;
- section_offsets[index].reloc_count = count;
- let len = count * mem::size_of::<macho::Relocation<Endianness>>();
- offset += len;
- }
- }
-
- // Calculate size of symtab.
- offset = align(offset, pointer_align);
- let symtab_offset = offset;
- let symtab_len = nsyms * macho.nlist_size();
- offset += symtab_len;
-
- // Calculate size of strtab.
- let strtab_offset = offset;
- // Start with null name.
- let mut strtab_data = vec![0];
- strtab.write(1, &mut strtab_data);
- write_align(&mut strtab_data, pointer_align);
- offset += strtab_data.len();
-
- // Start writing.
- buffer
- .reserve(offset)
- .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
-
- // Write file header.
- let (cputype, mut cpusubtype) = match (self.architecture, self.sub_architecture) {
- (Architecture::Arm, None) => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL),
- (Architecture::Aarch64, None) => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL),
- (Architecture::Aarch64, Some(SubArchitecture::Arm64E)) => {
- (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64E)
- }
- (Architecture::Aarch64_Ilp32, None) => {
- (macho::CPU_TYPE_ARM64_32, macho::CPU_SUBTYPE_ARM64_32_V8)
- }
- (Architecture::I386, None) => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL),
- (Architecture::X86_64, None) => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL),
- (Architecture::PowerPc, None) => {
- (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL)
- }
- (Architecture::PowerPc64, None) => {
- (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL)
- }
- _ => {
- return Err(Error(format!(
- "unimplemented architecture {:?} with sub-architecture {:?}",
- self.architecture, self.sub_architecture
- )));
- }
- };
-
- if let Some(cpu_subtype) = self.macho_cpu_subtype {
- cpusubtype = cpu_subtype;
- }
-
- let flags = match self.flags {
- FileFlags::MachO { flags } => flags,
- _ => 0,
- };
- macho.write_mach_header(
- buffer,
- MachHeader {
- cputype,
- cpusubtype,
- filetype: macho::MH_OBJECT,
- ncmds,
- sizeofcmds: sizeofcmds as u32,
- flags,
- },
- );
-
- // Write segment command.
- debug_assert_eq!(segment_command_offset, buffer.len());
- macho.write_segment_command(
- buffer,
- SegmentCommand {
- cmdsize: segment_command_len as u32,
- segname: [0; 16],
- vmaddr: 0,
- vmsize: address,
- fileoff: segment_file_offset as u64,
- filesize: segment_file_size as u64,
- maxprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE,
- initprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE,
- nsects: self.sections.len() as u32,
- flags: 0,
- },
- );
-
- // Write section headers.
- for (index, section) in self.sections.iter().enumerate() {
- let mut sectname = [0; 16];
- sectname
- .get_mut(..section.name.len())
- .ok_or_else(|| {
- Error(format!(
- "section name `{}` is too long",
- section.name().unwrap_or(""),
- ))
- })?
- .copy_from_slice(&section.name);
- let mut segname = [0; 16];
- segname
- .get_mut(..section.segment.len())
- .ok_or_else(|| {
- Error(format!(
- "segment name `{}` is too long",
- section.segment().unwrap_or(""),
- ))
- })?
- .copy_from_slice(&section.segment);
- let flags = if let SectionFlags::MachO { flags } = section.flags {
- flags
- } else {
- match section.kind {
- SectionKind::Text => {
- macho::S_ATTR_PURE_INSTRUCTIONS | macho::S_ATTR_SOME_INSTRUCTIONS
- }
- SectionKind::Data => 0,
- SectionKind::ReadOnlyData | SectionKind::ReadOnlyDataWithRel => 0,
- SectionKind::ReadOnlyString => macho::S_CSTRING_LITERALS,
- SectionKind::UninitializedData | SectionKind::Common => macho::S_ZEROFILL,
- SectionKind::Tls => macho::S_THREAD_LOCAL_REGULAR,
- SectionKind::UninitializedTls => macho::S_THREAD_LOCAL_ZEROFILL,
- SectionKind::TlsVariables => macho::S_THREAD_LOCAL_VARIABLES,
- SectionKind::Debug => macho::S_ATTR_DEBUG,
- SectionKind::OtherString => macho::S_CSTRING_LITERALS,
- SectionKind::Other | SectionKind::Linker | SectionKind::Metadata => 0,
- SectionKind::Note | SectionKind::Unknown | SectionKind::Elf(_) => {
- return Err(Error(format!(
- "unimplemented section `{}` kind {:?}",
- section.name().unwrap_or(""),
- section.kind
- )));
- }
- }
- };
- macho.write_section(
- buffer,
- SectionHeader {
- sectname,
- segname,
- addr: section_offsets[index].address,
- size: section.size,
- offset: section_offsets[index].offset as u32,
- align: section.align.trailing_zeros(),
- reloff: section_offsets[index].reloc_offset as u32,
- nreloc: section_offsets[index].reloc_count as u32,
- flags,
- },
- );
- }
-
- // Write build version.
- 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 symtab command.
- debug_assert_eq!(symtab_command_offset, buffer.len());
- let symtab_command = macho::SymtabCommand {
- cmd: U32::new(endian, macho::LC_SYMTAB),
- cmdsize: U32::new(endian, symtab_command_len as u32),
- symoff: U32::new(endian, symtab_offset as u32),
- nsyms: U32::new(endian, nsyms as u32),
- stroff: U32::new(endian, strtab_offset as u32),
- strsize: U32::new(endian, strtab_data.len() as u32),
- };
- buffer.write(&symtab_command);
-
- // Write dysymtab command.
- debug_assert_eq!(dysymtab_command_offset, buffer.len());
- let dysymtab_command = macho::DysymtabCommand {
- cmd: U32::new(endian, macho::LC_DYSYMTAB),
- cmdsize: U32::new(endian, dysymtab_command_len as u32),
- ilocalsym: U32::new(endian, 0),
- nlocalsym: U32::new(endian, local_symbols.len() as u32),
- iextdefsym: U32::new(endian, local_symbols.len() as u32),
- nextdefsym: U32::new(endian, external_symbols.len() as u32),
- iundefsym: U32::new(
- endian,
- local_symbols.len() as u32 + external_symbols.len() as u32,
- ),
- nundefsym: U32::new(endian, undefined_symbols.len() as u32),
- tocoff: U32::default(),
- ntoc: U32::default(),
- modtaboff: U32::default(),
- nmodtab: U32::default(),
- extrefsymoff: U32::default(),
- nextrefsyms: U32::default(),
- indirectsymoff: U32::default(),
- nindirectsyms: U32::default(),
- extreloff: U32::default(),
- nextrel: U32::default(),
- locreloff: U32::default(),
- nlocrel: U32::default(),
- };
- buffer.write(&dysymtab_command);
-
- // Write section data.
- for (index, section) in self.sections.iter().enumerate() {
- if !section.is_bss() {
- buffer.resize(section_offsets[index].offset);
- buffer.write_bytes(&section.data);
- }
- }
- debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len());
-
- // Write relocations.
- for (index, section) in self.sections.iter().enumerate() {
- if !section.relocations.is_empty() {
- write_align(buffer, pointer_align);
- debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
- for reloc in &section.relocations {
- let r_length = match reloc.size {
- 8 => 0,
- 16 => 1,
- 32 => 2,
- 64 => 3,
- _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))),
- };
-
- // Write explicit addend.
- if reloc.addend != 0 {
- let r_type = match self.architecture {
- Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => {
- macho::ARM64_RELOC_ADDEND
- }
- _ => {
- return Err(Error(format!("unimplemented relocation {:?}", reloc)))
- }
- };
-
- let reloc_info = macho::RelocationInfo {
- r_address: reloc.offset as u32,
- r_symbolnum: reloc.addend as u32,
- r_pcrel: false,
- r_length,
- r_extern: false,
- r_type,
- };
- buffer.write(&reloc_info.relocation(endian));
- }
-
- let r_extern;
- let r_symbolnum;
- let symbol = &self.symbols[reloc.symbol.0];
- if symbol.kind == SymbolKind::Section {
- r_symbolnum = section_offsets[symbol.section.id().unwrap().0].index as u32;
- r_extern = false;
- } else {
- r_symbolnum = symbol_offsets[reloc.symbol.0].index as u32;
- r_extern = true;
- }
- let (r_pcrel, r_type) = match self.architecture {
- Architecture::I386 => match reloc.kind {
- RelocationKind::Absolute => (false, macho::GENERIC_RELOC_VANILLA),
- _ => {
- return Err(Error(format!("unimplemented relocation {:?}", reloc)));
- }
- },
- Architecture::X86_64 => match (reloc.kind, reloc.encoding) {
- (RelocationKind::Absolute, RelocationEncoding::Generic) => {
- (false, macho::X86_64_RELOC_UNSIGNED)
- }
- (RelocationKind::Relative, RelocationEncoding::Generic) => {
- (true, macho::X86_64_RELOC_SIGNED)
- }
- (RelocationKind::Relative, RelocationEncoding::X86RipRelative) => {
- (true, macho::X86_64_RELOC_SIGNED)
- }
- (RelocationKind::Relative, RelocationEncoding::X86Branch) => {
- (true, macho::X86_64_RELOC_BRANCH)
- }
- (RelocationKind::PltRelative, RelocationEncoding::X86Branch) => {
- (true, macho::X86_64_RELOC_BRANCH)
- }
- (RelocationKind::GotRelative, RelocationEncoding::Generic) => {
- (true, macho::X86_64_RELOC_GOT)
- }
- (
- RelocationKind::GotRelative,
- RelocationEncoding::X86RipRelativeMovq,
- ) => (true, macho::X86_64_RELOC_GOT_LOAD),
- (RelocationKind::MachO { value, relative }, _) => (relative, value),
- _ => {
- return Err(Error(format!("unimplemented relocation {:?}", reloc)));
- }
- },
- Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => {
- match (reloc.kind, reloc.encoding) {
- (RelocationKind::Absolute, RelocationEncoding::Generic) => {
- (false, macho::ARM64_RELOC_UNSIGNED)
- }
- (RelocationKind::Relative, RelocationEncoding::AArch64Call) => {
- (true, macho::ARM64_RELOC_BRANCH26)
- }
- (
- RelocationKind::MachO { value, relative },
- RelocationEncoding::Generic,
- ) => (relative, value),
- _ => {
- return Err(Error(format!(
- "unimplemented relocation {:?}",
- reloc
- )));
- }
- }
- }
- _ => {
- if let RelocationKind::MachO { value, relative } = reloc.kind {
- (relative, value)
- } else {
- return Err(Error(format!("unimplemented relocation {:?}", reloc)));
- }
- }
- };
- let reloc_info = macho::RelocationInfo {
- r_address: reloc.offset as u32,
- r_symbolnum,
- r_pcrel,
- r_length,
- r_extern,
- r_type,
- };
- buffer.write(&reloc_info.relocation(endian));
- }
- }
- }
-
- // Write symtab.
- write_align(buffer, pointer_align);
- debug_assert_eq!(symtab_offset, buffer.len());
- for index in local_symbols
- .iter()
- .copied()
- .chain(external_symbols.iter().copied())
- .chain(undefined_symbols.iter().copied())
- {
- let symbol = &self.symbols[index];
- // TODO: N_STAB
- let (mut n_type, n_sect) = match symbol.section {
- SymbolSection::Undefined => (macho::N_UNDF | macho::N_EXT, 0),
- SymbolSection::Absolute => (macho::N_ABS, 0),
- SymbolSection::Section(id) => (macho::N_SECT, id.0 + 1),
- SymbolSection::None | SymbolSection::Common => {
- return Err(Error(format!(
- "unimplemented symbol `{}` section {:?}",
- symbol.name().unwrap_or(""),
- symbol.section
- )));
- }
- };
- match symbol.scope {
- SymbolScope::Unknown | SymbolScope::Compilation => {}
- SymbolScope::Linkage => {
- n_type |= macho::N_EXT | macho::N_PEXT;
- }
- SymbolScope::Dynamic => {
- n_type |= macho::N_EXT;
- }
- }
-
- let n_desc = if let SymbolFlags::MachO { n_desc } = symbol.flags {
- n_desc
- } else {
- let mut n_desc = 0;
- if symbol.weak {
- if symbol.is_undefined() {
- n_desc |= macho::N_WEAK_REF;
- } else {
- n_desc |= macho::N_WEAK_DEF;
- }
- }
- n_desc
- };
-
- let n_value = match symbol.section.id() {
- Some(section) => section_offsets[section.0].address + symbol.value,
- None => symbol.value,
- };
-
- let n_strx = symbol_offsets[index]
- .str_id
- .map(|id| strtab.get_offset(id))
- .unwrap_or(0);
-
- macho.write_nlist(
- buffer,
- Nlist {
- n_strx: n_strx as u32,
- n_type,
- n_sect: n_sect as u8,
- n_desc,
- n_value,
- },
- );
- }
-
- // Write strtab.
- debug_assert_eq!(strtab_offset, buffer.len());
- buffer.write_bytes(&strtab_data);
-
- debug_assert_eq!(offset, buffer.len());
-
- Ok(())
- }
-}
-
-struct MachHeader {
- cputype: u32,
- cpusubtype: u32,
- filetype: u32,
- ncmds: u32,
- sizeofcmds: u32,
- flags: u32,
-}
-
-struct SegmentCommand {
- cmdsize: u32,
- segname: [u8; 16],
- vmaddr: u64,
- vmsize: u64,
- fileoff: u64,
- filesize: u64,
- maxprot: u32,
- initprot: u32,
- nsects: u32,
- flags: u32,
-}
-
-pub struct SectionHeader {
- sectname: [u8; 16],
- segname: [u8; 16],
- addr: u64,
- size: u64,
- offset: u32,
- align: u32,
- reloff: u32,
- nreloc: u32,
- flags: u32,
-}
-
-struct Nlist {
- n_strx: u32,
- n_type: u8,
- n_sect: u8,
- n_desc: u16,
- n_value: u64,
-}
-
-trait MachO {
- fn mach_header_size(&self) -> usize;
- fn segment_command_size(&self) -> usize;
- fn section_header_size(&self) -> usize;
- fn nlist_size(&self) -> usize;
- fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, section: MachHeader);
- fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand);
- fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader);
- fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist);
-}
-
-struct MachO32<E> {
- endian: E,
-}
-
-impl<E: Endian> MachO for MachO32<E> {
- fn mach_header_size(&self) -> usize {
- mem::size_of::<macho::MachHeader32<E>>()
- }
-
- fn segment_command_size(&self) -> usize {
- mem::size_of::<macho::SegmentCommand32<E>>()
- }
-
- fn section_header_size(&self) -> usize {
- mem::size_of::<macho::Section32<E>>()
- }
-
- fn nlist_size(&self) -> usize {
- mem::size_of::<macho::Nlist32<E>>()
- }
-
- fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) {
- let endian = self.endian;
- let magic = if endian.is_big_endian() {
- macho::MH_MAGIC
- } else {
- macho::MH_CIGAM
- };
- let header = macho::MachHeader32 {
- magic: U32::new(BigEndian, magic),
- cputype: U32::new(endian, header.cputype),
- cpusubtype: U32::new(endian, header.cpusubtype),
- filetype: U32::new(endian, header.filetype),
- ncmds: U32::new(endian, header.ncmds),
- sizeofcmds: U32::new(endian, header.sizeofcmds),
- flags: U32::new(endian, header.flags),
- };
- buffer.write(&header);
- }
-
- fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) {
- let endian = self.endian;
- let segment = macho::SegmentCommand32 {
- cmd: U32::new(endian, macho::LC_SEGMENT),
- cmdsize: U32::new(endian, segment.cmdsize),
- segname: segment.segname,
- vmaddr: U32::new(endian, segment.vmaddr as u32),
- vmsize: U32::new(endian, segment.vmsize as u32),
- fileoff: U32::new(endian, segment.fileoff as u32),
- filesize: U32::new(endian, segment.filesize as u32),
- maxprot: U32::new(endian, segment.maxprot),
- initprot: U32::new(endian, segment.initprot),
- nsects: U32::new(endian, segment.nsects),
- flags: U32::new(endian, segment.flags),
- };
- buffer.write(&segment);
- }
-
- fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
- let endian = self.endian;
- let section = macho::Section32 {
- sectname: section.sectname,
- segname: section.segname,
- addr: U32::new(endian, section.addr as u32),
- size: U32::new(endian, section.size as u32),
- offset: U32::new(endian, section.offset),
- align: U32::new(endian, section.align),
- reloff: U32::new(endian, section.reloff),
- nreloc: U32::new(endian, section.nreloc),
- flags: U32::new(endian, section.flags),
- reserved1: U32::default(),
- reserved2: U32::default(),
- };
- buffer.write(&section);
- }
-
- fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) {
- let endian = self.endian;
- let nlist = macho::Nlist32 {
- n_strx: U32::new(endian, nlist.n_strx),
- n_type: nlist.n_type,
- n_sect: nlist.n_sect,
- n_desc: U16::new(endian, nlist.n_desc),
- n_value: U32::new(endian, nlist.n_value as u32),
- };
- buffer.write(&nlist);
- }
-}
-
-struct MachO64<E> {
- endian: E,
-}
-
-impl<E: Endian> MachO for MachO64<E> {
- fn mach_header_size(&self) -> usize {
- mem::size_of::<macho::MachHeader64<E>>()
- }
-
- fn segment_command_size(&self) -> usize {
- mem::size_of::<macho::SegmentCommand64<E>>()
- }
-
- fn section_header_size(&self) -> usize {
- mem::size_of::<macho::Section64<E>>()
- }
-
- fn nlist_size(&self) -> usize {
- mem::size_of::<macho::Nlist64<E>>()
- }
-
- fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) {
- let endian = self.endian;
- let magic = if endian.is_big_endian() {
- macho::MH_MAGIC_64
- } else {
- macho::MH_CIGAM_64
- };
- let header = macho::MachHeader64 {
- magic: U32::new(BigEndian, magic),
- cputype: U32::new(endian, header.cputype),
- cpusubtype: U32::new(endian, header.cpusubtype),
- filetype: U32::new(endian, header.filetype),
- ncmds: U32::new(endian, header.ncmds),
- sizeofcmds: U32::new(endian, header.sizeofcmds),
- flags: U32::new(endian, header.flags),
- reserved: U32::default(),
- };
- buffer.write(&header);
- }
-
- fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) {
- let endian = self.endian;
- let segment = macho::SegmentCommand64 {
- cmd: U32::new(endian, macho::LC_SEGMENT_64),
- cmdsize: U32::new(endian, segment.cmdsize),
- segname: segment.segname,
- vmaddr: U64::new(endian, segment.vmaddr),
- vmsize: U64::new(endian, segment.vmsize),
- fileoff: U64::new(endian, segment.fileoff),
- filesize: U64::new(endian, segment.filesize),
- maxprot: U32::new(endian, segment.maxprot),
- initprot: U32::new(endian, segment.initprot),
- nsects: U32::new(endian, segment.nsects),
- flags: U32::new(endian, segment.flags),
- };
- buffer.write(&segment);
- }
-
- fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
- let endian = self.endian;
- let section = macho::Section64 {
- sectname: section.sectname,
- segname: section.segname,
- addr: U64::new(endian, section.addr),
- size: U64::new(endian, section.size),
- offset: U32::new(endian, section.offset),
- align: U32::new(endian, section.align),
- reloff: U32::new(endian, section.reloff),
- nreloc: U32::new(endian, section.nreloc),
- flags: U32::new(endian, section.flags),
- reserved1: U32::default(),
- reserved2: U32::default(),
- reserved3: U32::default(),
- };
- buffer.write(&section);
- }
-
- fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) {
- let endian = self.endian;
- let nlist = macho::Nlist64 {
- n_strx: U32::new(endian, nlist.n_strx),
- n_type: nlist.n_type,
- n_sect: nlist.n_sect,
- n_desc: U16::new(endian, nlist.n_desc),
- n_value: U64Bytes::new(endian, nlist.n_value),
- };
- buffer.write(&nlist);
- }
-}