diff options
Diffstat (limited to 'vendor/object/src/write/macho.rs')
-rw-r--r-- | vendor/object/src/write/macho.rs | 1095 |
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(§ion.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(§ion.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(§ion.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 §ion.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(§ion); - } - - 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(§ion); - } - - 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); - } -} |