| 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, |
| } |
| |
| #[derive(Default, Clone, Copy)] |
| struct SymbolOffsets { |
| emit: bool, |
| index: usize, |
| str_id: Option<StringId>, |
| } |
| |
| 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) { |
| match section { |
| StandardSection::Text => (&b"__TEXT"[..], &b"__text"[..], SectionKind::Text), |
| StandardSection::Data => (&b"__DATA"[..], &b"__data"[..], SectionKind::Data), |
| StandardSection::ReadOnlyData => { |
| (&b"__TEXT"[..], &b"__const"[..], SectionKind::ReadOnlyData) |
| } |
| StandardSection::ReadOnlyDataWithRel => { |
| (&b"__DATA"[..], &b"__const"[..], SectionKind::ReadOnlyData) |
| } |
| StandardSection::ReadOnlyString => ( |
| &b"__TEXT"[..], |
| &b"__cstring"[..], |
| SectionKind::ReadOnlyString, |
| ), |
| StandardSection::UninitializedData => ( |
| &b"__DATA"[..], |
| &b"__bss"[..], |
| SectionKind::UninitializedData, |
| ), |
| StandardSection::Tls => (&b"__DATA"[..], &b"__thread_data"[..], SectionKind::Tls), |
| StandardSection::UninitializedTls => ( |
| &b"__DATA"[..], |
| &b"__thread_bss"[..], |
| SectionKind::UninitializedTls, |
| ), |
| StandardSection::TlsVariables => ( |
| &b"__DATA"[..], |
| &b"__thread_vars"[..], |
| SectionKind::TlsVariables, |
| ), |
| StandardSection::Common => (&b"__DATA"[..], &b"__common"[..], SectionKind::Common), |
| } |
| } |
| |
| 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, mut relocation: &mut Relocation) -> i64 { |
| let constant = match relocation.kind { |
| RelocationKind::Relative |
| | RelocationKind::GotRelative |
| | RelocationKind::PltRelative => relocation.addend + 4, |
| _ => relocation.addend, |
| }; |
| relocation.addend -= constant; |
| 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 symtab command. |
| let symtab_command_offset = offset; |
| let symtab_command_len = mem::size_of::<macho::SymtabCommand<Endianness>>(); |
| offset += symtab_command_len; |
| ncmds += 1; |
| |
| let sizeofcmds = offset - command_offset; |
| |
| // Calculate size of section data. |
| let mut segment_file_offset = None; |
| 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() { |
| let len = section.data.len(); |
| if len != 0 { |
| offset = align(offset, section.align as usize); |
| section_offsets[index].offset = offset; |
| if segment_file_offset.is_none() { |
| segment_file_offset = Some(offset); |
| } |
| offset += len; |
| } else { |
| section_offsets[index].offset = offset; |
| } |
| address = align_u64(address, section.align); |
| section_offsets[index].address = address; |
| address += section.size; |
| } |
| } |
| for (index, section) in self.sections.iter().enumerate() { |
| if section.kind.is_bss() { |
| assert!(section.data.is_empty()); |
| address = align_u64(address, section.align); |
| section_offsets[index].address = address; |
| address += section.size; |
| } |
| } |
| let segment_file_offset = segment_file_offset.unwrap_or(offset); |
| let segment_file_size = offset - segment_file_offset; |
| debug_assert!(segment_file_size as u64 <= address); |
| |
| // Count symbols and add symbol strings to strtab. |
| let mut strtab = StringTable::default(); |
| let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; |
| let mut nsyms = 0; |
| 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::File | SymbolKind::Section => continue, |
| SymbolKind::Unknown => { |
| if symbol.section != SymbolSection::Undefined { |
| return Err(Error(format!( |
| "defined symbol `{}` with unknown kind", |
| symbol.name().unwrap_or(""), |
| ))); |
| } |
| } |
| SymbolKind::Null | SymbolKind::Label => { |
| return Err(Error(format!( |
| "unimplemented symbol `{}` kind {:?}", |
| symbol.name().unwrap_or(""), |
| symbol.kind |
| ))); |
| } |
| } |
| symbol_offsets[index].emit = true; |
| symbol_offsets[index].index = nsyms; |
| nsyms += 1; |
| if !symbol.name.is_empty() { |
| symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); |
| } |
| } |
| |
| // 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); |
| offset += strtab_data.len(); |
| |
| // Calculate size of relocations. |
| for (index, section) in self.sections.iter().enumerate() { |
| let count = section.relocations.len(); |
| if count != 0 { |
| offset = align(offset, 4); |
| section_offsets[index].reloc_offset = offset; |
| let len = count * mem::size_of::<macho::Relocation<Endianness>>(); |
| offset += len; |
| } |
| } |
| |
| // Start writing. |
| buffer |
| .reserve(offset) |
| .map_err(|_| Error(String::from("Cannot allocate buffer")))?; |
| |
| // Write file header. |
| let (cputype, cpusubtype) = match self.architecture { |
| Architecture::Arm => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL), |
| Architecture::Aarch64 => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL), |
| Architecture::I386 => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL), |
| Architecture::X86_64 => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL), |
| _ => { |
| return Err(Error(format!( |
| "unimplemented architecture {:?}", |
| self.architecture |
| ))); |
| } |
| }; |
| |
| 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 => 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.relocations.len() as u32, |
| flags, |
| }, |
| ); |
| } |
| |
| // 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 section data. |
| for (index, section) in self.sections.iter().enumerate() { |
| let len = section.data.len(); |
| if len != 0 { |
| write_align(buffer, section.align as usize); |
| debug_assert_eq!(section_offsets[index].offset, buffer.len()); |
| buffer.write_bytes(§ion.data); |
| } |
| } |
| debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len()); |
| |
| // Write symtab. |
| write_align(buffer, pointer_align); |
| debug_assert_eq!(symtab_offset, buffer.len()); |
| for (index, symbol) in self.symbols.iter().enumerate() { |
| if !symbol_offsets[index].emit { |
| continue; |
| } |
| // 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); |
| |
| // Write relocations. |
| for (index, section) in self.sections.iter().enumerate() { |
| if !section.relocations.is_empty() { |
| write_align(buffer, 4); |
| debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); |
| for reloc in §ion.relocations { |
| 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_length = match reloc.size { |
| 8 => 0, |
| 16 => 1, |
| 32 => 2, |
| 64 => 3, |
| _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))), |
| }; |
| 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, reloc.addend) { |
| (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => { |
| (false, macho::X86_64_RELOC_UNSIGNED) |
| } |
| (RelocationKind::Relative, RelocationEncoding::Generic, -4) => { |
| (true, macho::X86_64_RELOC_SIGNED) |
| } |
| (RelocationKind::Relative, RelocationEncoding::X86RipRelative, -4) => { |
| (true, macho::X86_64_RELOC_SIGNED) |
| } |
| (RelocationKind::Relative, RelocationEncoding::X86Branch, -4) => { |
| (true, macho::X86_64_RELOC_BRANCH) |
| } |
| (RelocationKind::PltRelative, RelocationEncoding::X86Branch, -4) => { |
| (true, macho::X86_64_RELOC_BRANCH) |
| } |
| (RelocationKind::GotRelative, RelocationEncoding::Generic, -4) => { |
| (true, macho::X86_64_RELOC_GOT) |
| } |
| ( |
| RelocationKind::GotRelative, |
| RelocationEncoding::X86RipRelativeMovq, |
| -4, |
| ) => (true, macho::X86_64_RELOC_GOT_LOAD), |
| (RelocationKind::MachO { value, relative }, _, _) => (relative, value), |
| _ => { |
| return Err(Error(format!("unimplemented relocation {:?}", reloc))); |
| } |
| }, |
| Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.addend) { |
| (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => { |
| (false, macho::ARM64_RELOC_UNSIGNED) |
| } |
| ( |
| RelocationKind::MachO { value, relative }, |
| RelocationEncoding::Generic, |
| 0, |
| ) => (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)); |
| } |
| } |
| } |
| |
| 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); |
| } |
| } |