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(&section.name);
372             let mut segname = [0; 16];
373             segname[..section.segment.len()].copy_from_slice(&section.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 &section.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(&section));
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(&section));
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