1 use std::mem; 2 use std::vec::Vec; 3 4 use crate::endian::*; 5 use crate::macho; 6 use crate::pod::{bytes_of, WritableBuffer}; 7 use crate::write::string::*; 8 use crate::write::util::*; 9 use crate::write::*; 10 11 #[derive(Default, Clone, Copy)] 12 struct SectionOffsets { 13 index: usize, 14 offset: usize, 15 address: u64, 16 reloc_offset: usize, 17 } 18 19 #[derive(Default, Clone, Copy)] 20 struct SymbolOffsets { 21 emit: bool, 22 index: usize, 23 str_id: Option<StringId>, 24 } 25 26 impl Object { macho_set_subsections_via_symbols(&mut self)27 pub(crate) fn macho_set_subsections_via_symbols(&mut self) { 28 let flags = match self.flags { 29 FileFlags::MachO { flags } => flags, 30 _ => 0, 31 }; 32 self.flags = FileFlags::MachO { 33 flags: flags | macho::MH_SUBSECTIONS_VIA_SYMBOLS, 34 }; 35 } 36 macho_segment_name(&self, segment: StandardSegment) -> &'static [u8]37 pub(crate) fn macho_segment_name(&self, segment: StandardSegment) -> &'static [u8] { 38 match segment { 39 StandardSegment::Text => &b"__TEXT"[..], 40 StandardSegment::Data => &b"__DATA"[..], 41 StandardSegment::Debug => &b"__DWARF"[..], 42 } 43 } 44 macho_section_info( &self, section: StandardSection, ) -> (&'static [u8], &'static [u8], SectionKind)45 pub(crate) fn macho_section_info( 46 &self, 47 section: StandardSection, 48 ) -> (&'static [u8], &'static [u8], SectionKind) { 49 match section { 50 StandardSection::Text => (&b"__TEXT"[..], &b"__text"[..], SectionKind::Text), 51 StandardSection::Data => (&b"__DATA"[..], &b"__data"[..], SectionKind::Data), 52 StandardSection::ReadOnlyData => { 53 (&b"__TEXT"[..], &b"__const"[..], SectionKind::ReadOnlyData) 54 } 55 StandardSection::ReadOnlyDataWithRel => { 56 (&b"__DATA"[..], &b"__const"[..], SectionKind::ReadOnlyData) 57 } 58 StandardSection::ReadOnlyString => ( 59 &b"__TEXT"[..], 60 &b"__cstring"[..], 61 SectionKind::ReadOnlyString, 62 ), 63 StandardSection::UninitializedData => ( 64 &b"__DATA"[..], 65 &b"__bss"[..], 66 SectionKind::UninitializedData, 67 ), 68 StandardSection::Tls => (&b"__DATA"[..], &b"__thread_data"[..], SectionKind::Tls), 69 StandardSection::UninitializedTls => ( 70 &b"__DATA"[..], 71 &b"__thread_bss"[..], 72 SectionKind::UninitializedTls, 73 ), 74 StandardSection::TlsVariables => ( 75 &b"__DATA"[..], 76 &b"__thread_vars"[..], 77 SectionKind::TlsVariables, 78 ), 79 StandardSection::Common => (&b"__DATA"[..], &b"__common"[..], SectionKind::Common), 80 } 81 } 82 macho_tlv_bootstrap(&mut self) -> SymbolId83 fn macho_tlv_bootstrap(&mut self) -> SymbolId { 84 match self.tlv_bootstrap { 85 Some(id) => id, 86 None => { 87 let id = self.add_symbol(Symbol { 88 name: b"_tlv_bootstrap".to_vec(), 89 value: 0, 90 size: 0, 91 kind: SymbolKind::Text, 92 scope: SymbolScope::Dynamic, 93 weak: false, 94 section: SymbolSection::Undefined, 95 flags: SymbolFlags::None, 96 }); 97 self.tlv_bootstrap = Some(id); 98 id 99 } 100 } 101 } 102 103 /// Create the `__thread_vars` entry for a TLS variable. 104 /// 105 /// The symbol given by `symbol_id` will be updated to point to this entry. 106 /// 107 /// A new `SymbolId` will be returned. The caller must update this symbol 108 /// to point to the initializer. 109 /// 110 /// If `symbol_id` is not for a TLS variable, then it is returned unchanged. macho_add_thread_var(&mut self, symbol_id: SymbolId) -> SymbolId111 pub(crate) fn macho_add_thread_var(&mut self, symbol_id: SymbolId) -> SymbolId { 112 let symbol = self.symbol_mut(symbol_id); 113 if symbol.kind != SymbolKind::Tls { 114 return symbol_id; 115 } 116 117 // Create the initializer symbol. 118 let mut name = symbol.name.clone(); 119 name.extend(b"$tlv$init"); 120 let init_symbol_id = self.add_raw_symbol(Symbol { 121 name, 122 value: 0, 123 size: 0, 124 kind: SymbolKind::Tls, 125 scope: SymbolScope::Compilation, 126 weak: false, 127 section: SymbolSection::Undefined, 128 flags: SymbolFlags::None, 129 }); 130 131 // Add the tlv entry. 132 // Three pointers in size: 133 // - __tlv_bootstrap - used to make sure support exists 134 // - spare pointer - used when mapped by the runtime 135 // - pointer to symbol initializer 136 let section = self.section_id(StandardSection::TlsVariables); 137 let address_size = self.architecture.address_size().unwrap().bytes(); 138 let size = u64::from(address_size) * 3; 139 let data = vec![0; size as usize]; 140 let offset = self.append_section_data(section, &data, u64::from(address_size)); 141 142 let tlv_bootstrap = self.macho_tlv_bootstrap(); 143 self.add_relocation( 144 section, 145 Relocation { 146 offset, 147 size: address_size * 8, 148 kind: RelocationKind::Absolute, 149 encoding: RelocationEncoding::Generic, 150 symbol: tlv_bootstrap, 151 addend: 0, 152 }, 153 ) 154 .unwrap(); 155 self.add_relocation( 156 section, 157 Relocation { 158 offset: offset + u64::from(address_size) * 2, 159 size: address_size * 8, 160 kind: RelocationKind::Absolute, 161 encoding: RelocationEncoding::Generic, 162 symbol: init_symbol_id, 163 addend: 0, 164 }, 165 ) 166 .unwrap(); 167 168 // Update the symbol to point to the tlv. 169 let symbol = self.symbol_mut(symbol_id); 170 symbol.value = offset; 171 symbol.size = size; 172 symbol.section = SymbolSection::Section(section); 173 174 init_symbol_id 175 } 176 macho_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64177 pub(crate) fn macho_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 { 178 let constant = match relocation.kind { 179 RelocationKind::Relative 180 | RelocationKind::GotRelative 181 | RelocationKind::PltRelative => relocation.addend + 4, 182 _ => relocation.addend, 183 }; 184 relocation.addend -= constant; 185 constant 186 } 187 macho_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()>188 pub(crate) fn macho_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { 189 let address_size = self.architecture.address_size().unwrap(); 190 let endian = self.endian; 191 let macho32 = MachO32 { endian }; 192 let macho64 = MachO64 { endian }; 193 let macho: &dyn MachO = match address_size { 194 AddressSize::U32 => &macho32, 195 AddressSize::U64 => &macho64, 196 }; 197 let pointer_align = address_size.bytes() as usize; 198 199 // Calculate offsets of everything, and build strtab. 200 let mut offset = 0; 201 202 // Calculate size of Mach-O header. 203 offset += macho.mach_header_size(); 204 205 // Calculate size of commands. 206 let mut ncmds = 0; 207 let command_offset = offset; 208 209 // Calculate size of segment command and section headers. 210 let segment_command_offset = offset; 211 let segment_command_len = 212 macho.segment_command_size() + self.sections.len() * macho.section_header_size(); 213 offset += segment_command_len; 214 ncmds += 1; 215 216 // Calculate size of symtab command. 217 let symtab_command_offset = offset; 218 let symtab_command_len = mem::size_of::<macho::SymtabCommand<Endianness>>(); 219 offset += symtab_command_len; 220 ncmds += 1; 221 222 let sizeofcmds = offset - command_offset; 223 224 // Calculate size of section data. 225 let segment_data_offset = offset; 226 let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; 227 let mut address = 0; 228 for (index, section) in self.sections.iter().enumerate() { 229 section_offsets[index].index = 1 + index; 230 if !section.is_bss() { 231 let len = section.data.len(); 232 if len != 0 { 233 offset = align(offset, section.align as usize); 234 section_offsets[index].offset = offset; 235 offset += len; 236 } else { 237 section_offsets[index].offset = offset; 238 } 239 address = align_u64(address, section.align); 240 section_offsets[index].address = address; 241 address += section.size; 242 } 243 } 244 for (index, section) in self.sections.iter().enumerate() { 245 if section.kind.is_bss() { 246 assert!(section.data.is_empty()); 247 address = align_u64(address, section.align); 248 section_offsets[index].address = address; 249 address += section.size; 250 } 251 } 252 let segment_data_size = offset - segment_data_offset; 253 254 // Count symbols and add symbol strings to strtab. 255 let mut strtab = StringTable::default(); 256 let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; 257 let mut nsyms = 0; 258 for (index, symbol) in self.symbols.iter().enumerate() { 259 // The unified API allows creating symbols that we don't emit, so filter 260 // them out here. 261 // 262 // Since we don't actually emit the symbol kind, we validate it here too. 263 match symbol.kind { 264 SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {} 265 SymbolKind::File | SymbolKind::Section => continue, 266 SymbolKind::Unknown => { 267 if symbol.section != SymbolSection::Undefined { 268 return Err(Error(format!( 269 "defined symbol `{}` with unknown kind", 270 symbol.name().unwrap_or(""), 271 ))); 272 } 273 } 274 SymbolKind::Null | SymbolKind::Label => { 275 return Err(Error(format!( 276 "unimplemented symbol `{}` kind {:?}", 277 symbol.name().unwrap_or(""), 278 symbol.kind 279 ))); 280 } 281 } 282 symbol_offsets[index].emit = true; 283 symbol_offsets[index].index = nsyms; 284 nsyms += 1; 285 if !symbol.name.is_empty() { 286 symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); 287 } 288 } 289 290 // Calculate size of symtab. 291 offset = align(offset, pointer_align); 292 let symtab_offset = offset; 293 let symtab_len = nsyms * macho.nlist_size(); 294 offset += symtab_len; 295 296 // Calculate size of strtab. 297 let strtab_offset = offset; 298 let mut strtab_data = Vec::new(); 299 // Null name. 300 strtab_data.push(0); 301 strtab.write(1, &mut strtab_data); 302 offset += strtab_data.len(); 303 304 // Calculate size of relocations. 305 for (index, section) in self.sections.iter().enumerate() { 306 let count = section.relocations.len(); 307 if count != 0 { 308 offset = align(offset, 4); 309 section_offsets[index].reloc_offset = offset; 310 let len = count * mem::size_of::<macho::Relocation<Endianness>>(); 311 offset += len; 312 } 313 } 314 315 // Start writing. 316 buffer 317 .reserve(offset) 318 .map_err(|_| Error(String::from("Cannot allocate buffer")))?; 319 320 // Write file header. 321 let (cputype, cpusubtype) = match self.architecture { 322 Architecture::Arm => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL), 323 Architecture::Aarch64 => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL), 324 Architecture::I386 => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL), 325 Architecture::X86_64 => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL), 326 _ => { 327 return Err(Error(format!( 328 "unimplemented architecture {:?}", 329 self.architecture 330 ))); 331 } 332 }; 333 334 let flags = match self.flags { 335 FileFlags::MachO { flags } => flags, 336 _ => 0, 337 }; 338 macho.write_mach_header( 339 buffer, 340 MachHeader { 341 cputype, 342 cpusubtype, 343 filetype: macho::MH_OBJECT, 344 ncmds, 345 sizeofcmds: sizeofcmds as u32, 346 flags, 347 }, 348 ); 349 350 // Write segment command. 351 debug_assert_eq!(segment_command_offset, buffer.len()); 352 macho.write_segment_command( 353 buffer, 354 SegmentCommand { 355 cmdsize: segment_command_len as u32, 356 segname: [0; 16], 357 vmaddr: 0, 358 vmsize: address, 359 fileoff: segment_data_offset as u64, 360 filesize: segment_data_size as u64, 361 maxprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE, 362 initprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE, 363 nsects: self.sections.len() as u32, 364 flags: 0, 365 }, 366 ); 367 368 // Write section headers. 369 for (index, section) in self.sections.iter().enumerate() { 370 let mut sectname = [0; 16]; 371 sectname[..section.name.len()].copy_from_slice(§ion.name); 372 let mut segname = [0; 16]; 373 segname[..section.segment.len()].copy_from_slice(§ion.segment); 374 let flags = if let SectionFlags::MachO { flags } = section.flags { 375 flags 376 } else { 377 match section.kind { 378 SectionKind::Text => { 379 macho::S_ATTR_PURE_INSTRUCTIONS | macho::S_ATTR_SOME_INSTRUCTIONS 380 } 381 SectionKind::Data => 0, 382 SectionKind::ReadOnlyData => 0, 383 SectionKind::ReadOnlyString => macho::S_CSTRING_LITERALS, 384 SectionKind::UninitializedData | SectionKind::Common => macho::S_ZEROFILL, 385 SectionKind::Tls => macho::S_THREAD_LOCAL_REGULAR, 386 SectionKind::UninitializedTls => macho::S_THREAD_LOCAL_ZEROFILL, 387 SectionKind::TlsVariables => macho::S_THREAD_LOCAL_VARIABLES, 388 SectionKind::Debug => macho::S_ATTR_DEBUG, 389 SectionKind::OtherString => macho::S_CSTRING_LITERALS, 390 SectionKind::Other | SectionKind::Linker | SectionKind::Metadata => 0, 391 SectionKind::Note | SectionKind::Unknown | SectionKind::Elf(_) => { 392 return Err(Error(format!( 393 "unimplemented section `{}` kind {:?}", 394 section.name().unwrap_or(""), 395 section.kind 396 ))); 397 } 398 } 399 }; 400 macho.write_section( 401 buffer, 402 SectionHeader { 403 sectname, 404 segname, 405 addr: section_offsets[index].address, 406 size: section.size, 407 offset: section_offsets[index].offset as u32, 408 align: section.align.trailing_zeros(), 409 reloff: section_offsets[index].reloc_offset as u32, 410 nreloc: section.relocations.len() as u32, 411 flags, 412 }, 413 ); 414 } 415 416 // Write symtab command. 417 debug_assert_eq!(symtab_command_offset, buffer.len()); 418 let symtab_command = macho::SymtabCommand { 419 cmd: U32::new(endian, macho::LC_SYMTAB), 420 cmdsize: U32::new(endian, symtab_command_len as u32), 421 symoff: U32::new(endian, symtab_offset as u32), 422 nsyms: U32::new(endian, nsyms as u32), 423 stroff: U32::new(endian, strtab_offset as u32), 424 strsize: U32::new(endian, strtab_data.len() as u32), 425 }; 426 buffer.extend(bytes_of(&symtab_command)); 427 428 // Write section data. 429 debug_assert_eq!(segment_data_offset, buffer.len()); 430 for (index, section) in self.sections.iter().enumerate() { 431 let len = section.data.len(); 432 if len != 0 { 433 write_align(buffer, section.align as usize); 434 debug_assert_eq!(section_offsets[index].offset, buffer.len()); 435 buffer.extend(section.data.as_slice()); 436 } 437 } 438 439 // Write symtab. 440 write_align(buffer, pointer_align); 441 debug_assert_eq!(symtab_offset, buffer.len()); 442 for (index, symbol) in self.symbols.iter().enumerate() { 443 if !symbol_offsets[index].emit { 444 continue; 445 } 446 // TODO: N_STAB 447 let (mut n_type, n_sect) = match symbol.section { 448 SymbolSection::Undefined => (macho::N_UNDF | macho::N_EXT, 0), 449 SymbolSection::Absolute => (macho::N_ABS, 0), 450 SymbolSection::Section(id) => (macho::N_SECT, id.0 + 1), 451 SymbolSection::None | SymbolSection::Common => { 452 return Err(Error(format!( 453 "unimplemented symbol `{}` section {:?}", 454 symbol.name().unwrap_or(""), 455 symbol.section 456 ))); 457 } 458 }; 459 match symbol.scope { 460 SymbolScope::Unknown | SymbolScope::Compilation => {} 461 SymbolScope::Linkage => { 462 n_type |= macho::N_EXT | macho::N_PEXT; 463 } 464 SymbolScope::Dynamic => { 465 n_type |= macho::N_EXT; 466 } 467 } 468 469 let n_desc = if let SymbolFlags::MachO { n_desc } = symbol.flags { 470 n_desc 471 } else { 472 let mut n_desc = 0; 473 if symbol.weak { 474 if symbol.is_undefined() { 475 n_desc |= macho::N_WEAK_REF; 476 } else { 477 n_desc |= macho::N_WEAK_DEF; 478 } 479 } 480 n_desc 481 }; 482 483 let n_value = match symbol.section.id() { 484 Some(section) => section_offsets[section.0].address + symbol.value, 485 None => symbol.value, 486 }; 487 488 let n_strx = symbol_offsets[index] 489 .str_id 490 .map(|id| strtab.get_offset(id)) 491 .unwrap_or(0); 492 493 macho.write_nlist( 494 buffer, 495 Nlist { 496 n_strx: n_strx as u32, 497 n_type, 498 n_sect: n_sect as u8, 499 n_desc, 500 n_value, 501 }, 502 ); 503 } 504 505 // Write strtab. 506 debug_assert_eq!(strtab_offset, buffer.len()); 507 buffer.extend(&strtab_data); 508 509 // Write relocations. 510 for (index, section) in self.sections.iter().enumerate() { 511 if !section.relocations.is_empty() { 512 write_align(buffer, 4); 513 debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); 514 for reloc in §ion.relocations { 515 let r_extern; 516 let r_symbolnum; 517 let symbol = &self.symbols[reloc.symbol.0]; 518 if symbol.kind == SymbolKind::Section { 519 r_symbolnum = section_offsets[symbol.section.id().unwrap().0].index as u32; 520 r_extern = false; 521 } else { 522 r_symbolnum = symbol_offsets[reloc.symbol.0].index as u32; 523 r_extern = true; 524 } 525 let r_length = match reloc.size { 526 8 => 0, 527 16 => 1, 528 32 => 2, 529 64 => 3, 530 _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))), 531 }; 532 let (r_pcrel, r_type) = match self.architecture { 533 Architecture::I386 => match reloc.kind { 534 RelocationKind::Absolute => (false, macho::GENERIC_RELOC_VANILLA), 535 _ => { 536 return Err(Error(format!("unimplemented relocation {:?}", reloc))); 537 } 538 }, 539 Architecture::X86_64 => match (reloc.kind, reloc.encoding, reloc.addend) { 540 (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => { 541 (false, macho::X86_64_RELOC_UNSIGNED) 542 } 543 (RelocationKind::Relative, RelocationEncoding::Generic, -4) => { 544 (true, macho::X86_64_RELOC_SIGNED) 545 } 546 (RelocationKind::Relative, RelocationEncoding::X86RipRelative, -4) => { 547 (true, macho::X86_64_RELOC_SIGNED) 548 } 549 (RelocationKind::Relative, RelocationEncoding::X86Branch, -4) => { 550 (true, macho::X86_64_RELOC_BRANCH) 551 } 552 (RelocationKind::PltRelative, RelocationEncoding::X86Branch, -4) => { 553 (true, macho::X86_64_RELOC_BRANCH) 554 } 555 (RelocationKind::GotRelative, RelocationEncoding::Generic, -4) => { 556 (true, macho::X86_64_RELOC_GOT) 557 } 558 ( 559 RelocationKind::GotRelative, 560 RelocationEncoding::X86RipRelativeMovq, 561 -4, 562 ) => (true, macho::X86_64_RELOC_GOT_LOAD), 563 (RelocationKind::MachO { value, relative }, _, _) => (relative, value), 564 _ => { 565 return Err(Error(format!("unimplemented relocation {:?}", reloc))); 566 } 567 }, 568 _ => { 569 return Err(Error(format!( 570 "unimplemented architecture {:?}", 571 self.architecture 572 ))); 573 } 574 }; 575 let reloc_info = macho::RelocationInfo { 576 r_address: reloc.offset as u32, 577 r_symbolnum, 578 r_pcrel, 579 r_length, 580 r_extern, 581 r_type, 582 }; 583 buffer.extend(bytes_of(&reloc_info.relocation(endian))); 584 } 585 } 586 } 587 588 debug_assert_eq!(offset, buffer.len()); 589 590 Ok(()) 591 } 592 } 593 594 struct MachHeader { 595 cputype: u32, 596 cpusubtype: u32, 597 filetype: u32, 598 ncmds: u32, 599 sizeofcmds: u32, 600 flags: u32, 601 } 602 603 struct SegmentCommand { 604 cmdsize: u32, 605 segname: [u8; 16], 606 vmaddr: u64, 607 vmsize: u64, 608 fileoff: u64, 609 filesize: u64, 610 maxprot: u32, 611 initprot: u32, 612 nsects: u32, 613 flags: u32, 614 } 615 616 pub struct SectionHeader { 617 sectname: [u8; 16], 618 segname: [u8; 16], 619 addr: u64, 620 size: u64, 621 offset: u32, 622 align: u32, 623 reloff: u32, 624 nreloc: u32, 625 flags: u32, 626 } 627 628 struct Nlist { 629 n_strx: u32, 630 n_type: u8, 631 n_sect: u8, 632 n_desc: u16, 633 n_value: u64, 634 } 635 636 trait MachO { mach_header_size(&self) -> usize637 fn mach_header_size(&self) -> usize; segment_command_size(&self) -> usize638 fn segment_command_size(&self) -> usize; section_header_size(&self) -> usize639 fn section_header_size(&self) -> usize; nlist_size(&self) -> usize640 fn nlist_size(&self) -> usize; write_mach_header(&self, buffer: &mut dyn WritableBuffer, section: MachHeader)641 fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, section: MachHeader); write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand)642 fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand); write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader)643 fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader); write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist)644 fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist); 645 } 646 647 struct MachO32<E> { 648 endian: E, 649 } 650 651 impl<E: Endian> MachO for MachO32<E> { mach_header_size(&self) -> usize652 fn mach_header_size(&self) -> usize { 653 mem::size_of::<macho::MachHeader32<E>>() 654 } 655 segment_command_size(&self) -> usize656 fn segment_command_size(&self) -> usize { 657 mem::size_of::<macho::SegmentCommand32<E>>() 658 } 659 section_header_size(&self) -> usize660 fn section_header_size(&self) -> usize { 661 mem::size_of::<macho::Section32<E>>() 662 } 663 nlist_size(&self) -> usize664 fn nlist_size(&self) -> usize { 665 mem::size_of::<macho::Nlist32<E>>() 666 } 667 write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader)668 fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) { 669 let endian = self.endian; 670 let magic = if endian.is_big_endian() { 671 macho::MH_MAGIC 672 } else { 673 macho::MH_CIGAM 674 }; 675 let header = macho::MachHeader32 { 676 magic: U32::new(BigEndian, magic), 677 cputype: U32::new(endian, header.cputype), 678 cpusubtype: U32::new(endian, header.cpusubtype), 679 filetype: U32::new(endian, header.filetype), 680 ncmds: U32::new(endian, header.ncmds), 681 sizeofcmds: U32::new(endian, header.sizeofcmds), 682 flags: U32::new(endian, header.flags), 683 }; 684 buffer.extend(bytes_of(&header)); 685 } 686 write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand)687 fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { 688 let endian = self.endian; 689 let segment = macho::SegmentCommand32 { 690 cmd: U32::new(endian, macho::LC_SEGMENT), 691 cmdsize: U32::new(endian, segment.cmdsize), 692 segname: segment.segname, 693 vmaddr: U32::new(endian, segment.vmaddr as u32), 694 vmsize: U32::new(endian, segment.vmsize as u32), 695 fileoff: U32::new(endian, segment.fileoff as u32), 696 filesize: U32::new(endian, segment.filesize as u32), 697 maxprot: U32::new(endian, segment.maxprot), 698 initprot: U32::new(endian, segment.initprot), 699 nsects: U32::new(endian, segment.nsects), 700 flags: U32::new(endian, segment.flags), 701 }; 702 buffer.extend(bytes_of(&segment)); 703 } 704 write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader)705 fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { 706 let endian = self.endian; 707 let section = macho::Section32 { 708 sectname: section.sectname, 709 segname: section.segname, 710 addr: U32::new(endian, section.addr as u32), 711 size: U32::new(endian, section.size as u32), 712 offset: U32::new(endian, section.offset), 713 align: U32::new(endian, section.align), 714 reloff: U32::new(endian, section.reloff), 715 nreloc: U32::new(endian, section.nreloc), 716 flags: U32::new(endian, section.flags), 717 reserved1: U32::default(), 718 reserved2: U32::default(), 719 }; 720 buffer.extend(bytes_of(§ion)); 721 } 722 write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist)723 fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { 724 let endian = self.endian; 725 let nlist = macho::Nlist32 { 726 n_strx: U32::new(endian, nlist.n_strx), 727 n_type: nlist.n_type, 728 n_sect: nlist.n_sect, 729 n_desc: U16::new(endian, nlist.n_desc), 730 n_value: U32::new(endian, nlist.n_value as u32), 731 }; 732 buffer.extend(bytes_of(&nlist)); 733 } 734 } 735 736 struct MachO64<E> { 737 endian: E, 738 } 739 740 impl<E: Endian> MachO for MachO64<E> { mach_header_size(&self) -> usize741 fn mach_header_size(&self) -> usize { 742 mem::size_of::<macho::MachHeader64<E>>() 743 } 744 segment_command_size(&self) -> usize745 fn segment_command_size(&self) -> usize { 746 mem::size_of::<macho::SegmentCommand64<E>>() 747 } 748 section_header_size(&self) -> usize749 fn section_header_size(&self) -> usize { 750 mem::size_of::<macho::Section64<E>>() 751 } 752 nlist_size(&self) -> usize753 fn nlist_size(&self) -> usize { 754 mem::size_of::<macho::Nlist64<E>>() 755 } 756 write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader)757 fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) { 758 let endian = self.endian; 759 let magic = if endian.is_big_endian() { 760 macho::MH_MAGIC_64 761 } else { 762 macho::MH_CIGAM_64 763 }; 764 let header = macho::MachHeader64 { 765 magic: U32::new(BigEndian, magic), 766 cputype: U32::new(endian, header.cputype), 767 cpusubtype: U32::new(endian, header.cpusubtype), 768 filetype: U32::new(endian, header.filetype), 769 ncmds: U32::new(endian, header.ncmds), 770 sizeofcmds: U32::new(endian, header.sizeofcmds), 771 flags: U32::new(endian, header.flags), 772 reserved: U32::default(), 773 }; 774 buffer.extend(bytes_of(&header)); 775 } 776 write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand)777 fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { 778 let endian = self.endian; 779 let segment = macho::SegmentCommand64 { 780 cmd: U32::new(endian, macho::LC_SEGMENT_64), 781 cmdsize: U32::new(endian, segment.cmdsize), 782 segname: segment.segname, 783 vmaddr: U64::new(endian, segment.vmaddr), 784 vmsize: U64::new(endian, segment.vmsize), 785 fileoff: U64::new(endian, segment.fileoff), 786 filesize: U64::new(endian, segment.filesize), 787 maxprot: U32::new(endian, segment.maxprot), 788 initprot: U32::new(endian, segment.initprot), 789 nsects: U32::new(endian, segment.nsects), 790 flags: U32::new(endian, segment.flags), 791 }; 792 buffer.extend(bytes_of(&segment)); 793 } 794 write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader)795 fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { 796 let endian = self.endian; 797 let section = macho::Section64 { 798 sectname: section.sectname, 799 segname: section.segname, 800 addr: U64::new(endian, section.addr), 801 size: U64::new(endian, section.size), 802 offset: U32::new(endian, section.offset), 803 align: U32::new(endian, section.align), 804 reloff: U32::new(endian, section.reloff), 805 nreloc: U32::new(endian, section.nreloc), 806 flags: U32::new(endian, section.flags), 807 reserved1: U32::default(), 808 reserved2: U32::default(), 809 reserved3: U32::default(), 810 }; 811 buffer.extend(bytes_of(§ion)); 812 } 813 write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist)814 fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { 815 let endian = self.endian; 816 let nlist = macho::Nlist64 { 817 n_strx: U32::new(endian, nlist.n_strx), 818 n_type: nlist.n_type, 819 n_sect: nlist.n_sect, 820 n_desc: U16::new(endian, nlist.n_desc), 821 n_value: U64Bytes::new(endian, nlist.n_value), 822 }; 823 buffer.extend(bytes_of(&nlist)); 824 } 825 } 826