1use core::mem;
2
3use crate::endian::*;
4use crate::macho;
5use crate::write::string::*;
6use crate::write::util::*;
7use crate::write::*;
8
9#[derive(Default, Clone, Copy)]
10struct SectionOffsets {
11 index: usize,
12 offset: usize,
13 address: u64,
14 reloc_offset: usize,
15 reloc_count: usize,
16}
17
18#[derive(Default, Clone, Copy)]
19struct SymbolOffsets {
20 index: usize,
21 str_id: Option<StringId>,
22}
23
24#[derive(Debug, Default, Clone, Copy)]
26#[non_exhaustive] pub struct MachOBuildVersion {
28 pub platform: u32,
31 pub minos: u32,
34 pub sdk: u32,
37}
38
39impl MachOBuildVersion {
40 fn cmdsize(&self) -> u32 {
41 let sz = mem::size_of::<macho::BuildVersionCommand<Endianness>>();
43 debug_assert!(sz <= u32::MAX as usize);
44 sz as u32
45 }
46}
47
48impl<'a> Object<'a> {
50 #[inline]
54 pub fn set_macho_cpu_subtype(&mut self, cpu_subtype: u32) {
55 self.macho_cpu_subtype = Some(cpu_subtype);
56 }
57
58 #[inline]
62 pub fn set_macho_build_version(&mut self, info: MachOBuildVersion) {
63 self.macho_build_version = Some(info);
64 }
65}
66
67impl<'a> Object<'a> {
69 pub(crate) fn macho_segment_name(&self, segment: StandardSegment) -> &'static [u8] {
70 match segment {
71 StandardSegment::Text => &b"__TEXT"[..],
72 StandardSegment::Data => &b"__DATA"[..],
73 StandardSegment::Debug => &b"__DWARF"[..],
74 }
75 }
76
77 pub(crate) fn macho_section_info(
78 &self,
79 section: StandardSection,
80 ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
81 match section {
82 StandardSection::Text => (
83 &b"__TEXT"[..],
84 &b"__text"[..],
85 SectionKind::Text,
86 SectionFlags::None,
87 ),
88 StandardSection::Data => (
89 &b"__DATA"[..],
90 &b"__data"[..],
91 SectionKind::Data,
92 SectionFlags::None,
93 ),
94 StandardSection::ReadOnlyData => (
95 &b"__TEXT"[..],
96 &b"__const"[..],
97 SectionKind::ReadOnlyData,
98 SectionFlags::None,
99 ),
100 StandardSection::ReadOnlyDataWithRel => (
101 &b"__DATA"[..],
102 &b"__const"[..],
103 SectionKind::ReadOnlyDataWithRel,
104 SectionFlags::None,
105 ),
106 StandardSection::ReadOnlyString => (
107 &b"__TEXT"[..],
108 &b"__cstring"[..],
109 SectionKind::ReadOnlyString,
110 SectionFlags::None,
111 ),
112 StandardSection::UninitializedData => (
113 &b"__DATA"[..],
114 &b"__bss"[..],
115 SectionKind::UninitializedData,
116 SectionFlags::None,
117 ),
118 StandardSection::Tls => (
119 &b"__DATA"[..],
120 &b"__thread_data"[..],
121 SectionKind::Tls,
122 SectionFlags::None,
123 ),
124 StandardSection::UninitializedTls => (
125 &b"__DATA"[..],
126 &b"__thread_bss"[..],
127 SectionKind::UninitializedTls,
128 SectionFlags::None,
129 ),
130 StandardSection::TlsVariables => (
131 &b"__DATA"[..],
132 &b"__thread_vars"[..],
133 SectionKind::TlsVariables,
134 SectionFlags::None,
135 ),
136 StandardSection::Common => (
137 &b"__DATA"[..],
138 &b"__common"[..],
139 SectionKind::Common,
140 SectionFlags::None,
141 ),
142 StandardSection::GnuProperty => {
143 (&[], &[], SectionKind::Note, SectionFlags::None)
145 }
146 }
147 }
148
149 pub(crate) fn macho_section_flags(&self, section: &Section<'_>) -> SectionFlags {
150 let flags = match section.kind {
151 SectionKind::Text => macho::S_ATTR_PURE_INSTRUCTIONS | macho::S_ATTR_SOME_INSTRUCTIONS,
152 SectionKind::Data => 0,
153 SectionKind::ReadOnlyData | SectionKind::ReadOnlyDataWithRel => 0,
154 SectionKind::ReadOnlyString => macho::S_CSTRING_LITERALS,
155 SectionKind::UninitializedData | SectionKind::Common => macho::S_ZEROFILL,
156 SectionKind::Tls => macho::S_THREAD_LOCAL_REGULAR,
157 SectionKind::UninitializedTls => macho::S_THREAD_LOCAL_ZEROFILL,
158 SectionKind::TlsVariables => macho::S_THREAD_LOCAL_VARIABLES,
159 SectionKind::Debug | SectionKind::DebugString => macho::S_ATTR_DEBUG,
160 SectionKind::OtherString => macho::S_CSTRING_LITERALS,
161 SectionKind::Other | SectionKind::Linker | SectionKind::Metadata => 0,
162 SectionKind::Note | SectionKind::Unknown | SectionKind::Elf(_) => {
163 return SectionFlags::None;
164 }
165 };
166 SectionFlags::MachO { flags }
167 }
168
169 pub(crate) fn macho_symbol_flags(&self, symbol: &Symbol) -> SymbolFlags<SectionId, SymbolId> {
170 let mut n_desc = 0;
171 if symbol.weak {
172 if symbol.is_undefined() {
173 n_desc |= macho::N_WEAK_REF;
174 } else {
175 n_desc |= macho::N_WEAK_DEF;
176 }
177 }
178 SymbolFlags::MachO { n_desc }
180 }
181
182 fn macho_tlv_bootstrap(&mut self) -> SymbolId {
183 match self.tlv_bootstrap {
184 Some(id) => id,
185 None => {
186 let id = self.add_symbol(Symbol {
187 name: b"_tlv_bootstrap".to_vec(),
188 value: 0,
189 size: 0,
190 kind: SymbolKind::Text,
191 scope: SymbolScope::Dynamic,
192 weak: false,
193 section: SymbolSection::Undefined,
194 flags: SymbolFlags::None,
195 });
196 self.tlv_bootstrap = Some(id);
197 id
198 }
199 }
200 }
201
202 pub(crate) fn macho_add_thread_var(&mut self, symbol_id: SymbolId) -> SymbolId {
211 let symbol = self.symbol_mut(symbol_id);
212 if symbol.kind != SymbolKind::Tls {
213 return symbol_id;
214 }
215
216 let mut name = symbol.name.clone();
218 name.extend_from_slice(b"$tlv$init");
219 let init_symbol_id = self.add_raw_symbol(Symbol {
220 name,
221 value: 0,
222 size: 0,
223 kind: SymbolKind::Tls,
224 scope: SymbolScope::Compilation,
225 weak: false,
226 section: SymbolSection::Undefined,
227 flags: SymbolFlags::None,
228 });
229
230 let section = self.section_id(StandardSection::TlsVariables);
236 let address_size = self.architecture.address_size().unwrap().bytes();
237 let size = u64::from(address_size) * 3;
238 let data = vec![0; size as usize];
239 let offset = self.append_section_data(section, &data, u64::from(address_size));
240
241 let tlv_bootstrap = self.macho_tlv_bootstrap();
242 self.add_relocation(
243 section,
244 Relocation {
245 offset,
246 symbol: tlv_bootstrap,
247 addend: 0,
248 flags: RelocationFlags::Generic {
249 kind: RelocationKind::Absolute,
250 encoding: RelocationEncoding::Generic,
251 size: address_size * 8,
252 },
253 },
254 )
255 .unwrap();
256 self.add_relocation(
257 section,
258 Relocation {
259 offset: offset + u64::from(address_size) * 2,
260 symbol: init_symbol_id,
261 addend: 0,
262 flags: RelocationFlags::Generic {
263 kind: RelocationKind::Absolute,
264 encoding: RelocationEncoding::Generic,
265 size: address_size * 8,
266 },
267 },
268 )
269 .unwrap();
270
271 let symbol = self.symbol_mut(symbol_id);
273 symbol.value = offset;
274 symbol.size = size;
275 symbol.section = SymbolSection::Section(section);
276
277 init_symbol_id
278 }
279
280 pub(crate) fn macho_translate_relocation(&mut self, reloc: &mut Relocation) -> Result<()> {
281 use RelocationEncoding as E;
282 use RelocationKind as K;
283
284 let (kind, encoding, mut size) = if let RelocationFlags::Generic {
285 kind,
286 encoding,
287 size,
288 } = reloc.flags
289 {
290 (kind, encoding, size)
291 } else {
292 return Ok(());
293 };
294 if self.architecture == Architecture::Aarch64 && matches!(size, 12 | 21 | 26) {
296 size = 32;
297 }
298 let r_length = match size {
299 8 => 0,
300 16 => 1,
301 32 => 2,
302 64 => 3,
303 _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))),
304 };
305 let unsupported_reloc = || Err(Error(format!("unimplemented relocation {:?}", reloc)));
306 let (r_pcrel, r_type) = match self.architecture {
307 Architecture::I386 => match kind {
308 K::Absolute => (false, macho::GENERIC_RELOC_VANILLA),
309 _ => return unsupported_reloc(),
310 },
311 Architecture::Arm => match kind {
312 K::Absolute => (false, macho::ARM_RELOC_VANILLA),
313 _ => return unsupported_reloc(),
314 },
315 Architecture::X86_64 => match (kind, encoding) {
316 (K::Absolute, E::Generic) => (false, macho::X86_64_RELOC_UNSIGNED),
317 (K::Relative, E::Generic) => (true, macho::X86_64_RELOC_SIGNED),
318 (K::Relative, E::X86RipRelative) => (true, macho::X86_64_RELOC_SIGNED),
319 (K::Relative, E::X86Branch) => (true, macho::X86_64_RELOC_BRANCH),
320 (K::PltRelative, E::X86Branch) => (true, macho::X86_64_RELOC_BRANCH),
321 (K::GotRelative, E::Generic) => (true, macho::X86_64_RELOC_GOT),
322 (K::GotRelative, E::X86RipRelativeMovq) => (true, macho::X86_64_RELOC_GOT_LOAD),
323 _ => return unsupported_reloc(),
324 },
325 Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => match (kind, encoding) {
326 (K::Absolute, E::Generic) => (false, macho::ARM64_RELOC_UNSIGNED),
327 (K::Relative, E::AArch64Call) => (true, macho::ARM64_RELOC_BRANCH26),
328 _ => return unsupported_reloc(),
329 },
330 _ => {
331 return Err(Error(format!(
332 "unimplemented architecture {:?}",
333 self.architecture
334 )));
335 }
336 };
337 reloc.flags = RelocationFlags::MachO {
338 r_type,
339 r_pcrel,
340 r_length,
341 };
342 Ok(())
343 }
344
345 pub(crate) fn macho_adjust_addend(&mut self, relocation: &mut Relocation) -> Result<bool> {
346 let (r_type, r_pcrel) = if let RelocationFlags::MachO {
347 r_type, r_pcrel, ..
348 } = relocation.flags
349 {
350 (r_type, r_pcrel)
351 } else {
352 return Err(Error(format!("invalid relocation flags {:?}", relocation)));
353 };
354 if r_pcrel {
355 let pcrel_offset = match self.architecture {
361 Architecture::I386 => 4,
362 Architecture::X86_64 => match r_type {
363 macho::X86_64_RELOC_SIGNED_1 => 5,
364 macho::X86_64_RELOC_SIGNED_2 => 6,
365 macho::X86_64_RELOC_SIGNED_4 => 8,
366 _ => 4,
367 },
368 _ => 0,
370 };
371 relocation.addend += pcrel_offset;
372 }
373 let implicit = if self.architecture == Architecture::Aarch64 {
375 match r_type {
376 macho::ARM64_RELOC_BRANCH26
377 | macho::ARM64_RELOC_PAGE21
378 | macho::ARM64_RELOC_PAGEOFF12 => false,
379 _ => true,
380 }
381 } else {
382 true
383 };
384 Ok(implicit)
385 }
386
387 pub(crate) fn macho_relocation_size(&self, reloc: &Relocation) -> Result<u8> {
388 if let RelocationFlags::MachO { r_length, .. } = reloc.flags {
389 Ok(8 << r_length)
390 } else {
391 Err(Error("invalid relocation flags".into()))
392 }
393 }
394
395 pub(crate) fn macho_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
396 let address_size = self.architecture.address_size().unwrap();
397 let endian = self.endian;
398 let macho32 = MachO32 { endian };
399 let macho64 = MachO64 { endian };
400 let macho: &dyn MachO = match address_size {
401 AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => &macho32,
402 AddressSize::U64 => &macho64,
403 };
404 let pointer_align = address_size.bytes() as usize;
405
406 let mut offset = 0;
408
409 offset += macho.mach_header_size();
411
412 let mut ncmds = 0;
414 let command_offset = offset;
415
416 let segment_command_offset = offset;
418 let segment_command_len =
419 macho.segment_command_size() + self.sections.len() * macho.section_header_size();
420 offset += segment_command_len;
421 ncmds += 1;
422
423 let build_version_offset = offset;
425 if let Some(version) = &self.macho_build_version {
426 offset += version.cmdsize() as usize;
427 ncmds += 1;
428 }
429
430 let symtab_command_offset = offset;
432 let symtab_command_len = mem::size_of::<macho::SymtabCommand<Endianness>>();
433 offset += symtab_command_len;
434 ncmds += 1;
435
436 let dysymtab_command_offset = offset;
438 let dysymtab_command_len = mem::size_of::<macho::DysymtabCommand<Endianness>>();
439 offset += dysymtab_command_len;
440 ncmds += 1;
441
442 let sizeofcmds = offset - command_offset;
443
444 let segment_file_offset = offset;
447 let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
448 let mut address = 0;
449 for (index, section) in self.sections.iter().enumerate() {
450 section_offsets[index].index = 1 + index;
451 if !section.is_bss() {
452 address = align_u64(address, section.align);
453 section_offsets[index].address = address;
454 section_offsets[index].offset = segment_file_offset + address as usize;
455 address += section.size;
456 }
457 }
458 let segment_file_size = address as usize;
459 offset += address as usize;
460 for (index, section) in self.sections.iter().enumerate() {
461 if section.is_bss() {
462 debug_assert!(section.data.is_empty());
463 address = align_u64(address, section.align);
464 section_offsets[index].address = address;
465 address += section.size;
466 }
467 }
468
469 let mut strtab = StringTable::default();
471 let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
472 let mut local_symbols = vec![];
473 let mut external_symbols = vec![];
474 let mut undefined_symbols = vec![];
475 for (index, symbol) in self.symbols.iter().enumerate() {
476 match symbol.kind {
481 SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls | SymbolKind::Unknown => {}
482 SymbolKind::File | SymbolKind::Section => continue,
483 SymbolKind::Label => {
484 return Err(Error(format!(
485 "unimplemented symbol `{}` kind {:?}",
486 symbol.name().unwrap_or(""),
487 symbol.kind
488 )));
489 }
490 }
491 if !symbol.name.is_empty() {
492 symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
493 }
494 if symbol.is_undefined() {
495 undefined_symbols.push(index);
496 } else if symbol.is_local() {
497 local_symbols.push(index);
498 } else {
499 external_symbols.push(index);
500 }
501 }
502
503 external_symbols.sort_by_key(|index| &*self.symbols[*index].name);
504 undefined_symbols.sort_by_key(|index| &*self.symbols[*index].name);
505
506 let mut nsyms = 0;
508 for index in local_symbols
509 .iter()
510 .copied()
511 .chain(external_symbols.iter().copied())
512 .chain(undefined_symbols.iter().copied())
513 {
514 symbol_offsets[index].index = nsyms;
515 nsyms += 1;
516 }
517
518 for (index, section) in self.sections.iter().enumerate() {
520 let count: usize = section
521 .relocations
522 .iter()
523 .map(|reloc| 1 + usize::from(reloc.addend != 0))
524 .sum();
525 if count != 0 {
526 offset = align(offset, pointer_align);
527 section_offsets[index].reloc_offset = offset;
528 section_offsets[index].reloc_count = count;
529 let len = count * mem::size_of::<macho::Relocation<Endianness>>();
530 offset += len;
531 }
532 }
533
534 offset = align(offset, pointer_align);
536 let symtab_offset = offset;
537 let symtab_len = nsyms * macho.nlist_size();
538 offset += symtab_len;
539
540 let strtab_offset = offset;
542 let mut strtab_data = vec![0];
544 strtab.write(1, &mut strtab_data);
545 write_align(&mut strtab_data, pointer_align);
546 offset += strtab_data.len();
547
548 buffer
550 .reserve(offset)
551 .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
552
553 let (cputype, mut cpusubtype) = match (self.architecture, self.sub_architecture) {
555 (Architecture::Arm, None) => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL),
556 (Architecture::Aarch64, None) => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL),
557 (Architecture::Aarch64, Some(SubArchitecture::Arm64E)) => {
558 (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64E)
559 }
560 (Architecture::Aarch64_Ilp32, None) => {
561 (macho::CPU_TYPE_ARM64_32, macho::CPU_SUBTYPE_ARM64_32_V8)
562 }
563 (Architecture::I386, None) => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL),
564 (Architecture::X86_64, None) => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL),
565 (Architecture::PowerPc, None) => {
566 (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL)
567 }
568 (Architecture::PowerPc64, None) => {
569 (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL)
570 }
571 _ => {
572 return Err(Error(format!(
573 "unimplemented architecture {:?} with sub-architecture {:?}",
574 self.architecture, self.sub_architecture
575 )));
576 }
577 };
578
579 if let Some(cpu_subtype) = self.macho_cpu_subtype {
580 cpusubtype = cpu_subtype;
581 }
582
583 let mut flags = match self.flags {
584 FileFlags::MachO { flags } => flags,
585 _ => 0,
586 };
587 if self.macho_subsections_via_symbols {
588 flags |= macho::MH_SUBSECTIONS_VIA_SYMBOLS;
589 }
590 macho.write_mach_header(
591 buffer,
592 MachHeader {
593 cputype,
594 cpusubtype,
595 filetype: macho::MH_OBJECT,
596 ncmds,
597 sizeofcmds: sizeofcmds as u32,
598 flags,
599 },
600 );
601
602 debug_assert_eq!(segment_command_offset, buffer.len());
604 macho.write_segment_command(
605 buffer,
606 SegmentCommand {
607 cmdsize: segment_command_len as u32,
608 segname: [0; 16],
609 vmaddr: 0,
610 vmsize: address,
611 fileoff: segment_file_offset as u64,
612 filesize: segment_file_size as u64,
613 maxprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE,
614 initprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE,
615 nsects: self.sections.len() as u32,
616 flags: 0,
617 },
618 );
619
620 for (index, section) in self.sections.iter().enumerate() {
622 let mut sectname = [0; 16];
623 sectname
624 .get_mut(..section.name.len())
625 .ok_or_else(|| {
626 Error(format!(
627 "section name `{}` is too long",
628 section.name().unwrap_or(""),
629 ))
630 })?
631 .copy_from_slice(§ion.name);
632 let mut segname = [0; 16];
633 segname
634 .get_mut(..section.segment.len())
635 .ok_or_else(|| {
636 Error(format!(
637 "segment name `{}` is too long",
638 section.segment().unwrap_or(""),
639 ))
640 })?
641 .copy_from_slice(§ion.segment);
642 let SectionFlags::MachO { flags } = self.section_flags(section) else {
643 return Err(Error(format!(
644 "unimplemented section `{}` kind {:?}",
645 section.name().unwrap_or(""),
646 section.kind
647 )));
648 };
649 macho.write_section(
650 buffer,
651 SectionHeader {
652 sectname,
653 segname,
654 addr: section_offsets[index].address,
655 size: section.size,
656 offset: section_offsets[index].offset as u32,
657 align: section.align.trailing_zeros(),
658 reloff: section_offsets[index].reloc_offset as u32,
659 nreloc: section_offsets[index].reloc_count as u32,
660 flags,
661 },
662 );
663 }
664
665 if let Some(version) = &self.macho_build_version {
667 debug_assert_eq!(build_version_offset, buffer.len());
668 buffer.write(&macho::BuildVersionCommand {
669 cmd: U32::new(endian, macho::LC_BUILD_VERSION),
670 cmdsize: U32::new(endian, version.cmdsize()),
671 platform: U32::new(endian, version.platform),
672 minos: U32::new(endian, version.minos),
673 sdk: U32::new(endian, version.sdk),
674 ntools: U32::new(endian, 0),
675 });
676 }
677
678 debug_assert_eq!(symtab_command_offset, buffer.len());
680 let symtab_command = macho::SymtabCommand {
681 cmd: U32::new(endian, macho::LC_SYMTAB),
682 cmdsize: U32::new(endian, symtab_command_len as u32),
683 symoff: U32::new(endian, symtab_offset as u32),
684 nsyms: U32::new(endian, nsyms as u32),
685 stroff: U32::new(endian, strtab_offset as u32),
686 strsize: U32::new(endian, strtab_data.len() as u32),
687 };
688 buffer.write(&symtab_command);
689
690 debug_assert_eq!(dysymtab_command_offset, buffer.len());
692 let dysymtab_command = macho::DysymtabCommand {
693 cmd: U32::new(endian, macho::LC_DYSYMTAB),
694 cmdsize: U32::new(endian, dysymtab_command_len as u32),
695 ilocalsym: U32::new(endian, 0),
696 nlocalsym: U32::new(endian, local_symbols.len() as u32),
697 iextdefsym: U32::new(endian, local_symbols.len() as u32),
698 nextdefsym: U32::new(endian, external_symbols.len() as u32),
699 iundefsym: U32::new(
700 endian,
701 local_symbols.len() as u32 + external_symbols.len() as u32,
702 ),
703 nundefsym: U32::new(endian, undefined_symbols.len() as u32),
704 tocoff: U32::default(),
705 ntoc: U32::default(),
706 modtaboff: U32::default(),
707 nmodtab: U32::default(),
708 extrefsymoff: U32::default(),
709 nextrefsyms: U32::default(),
710 indirectsymoff: U32::default(),
711 nindirectsyms: U32::default(),
712 extreloff: U32::default(),
713 nextrel: U32::default(),
714 locreloff: U32::default(),
715 nlocrel: U32::default(),
716 };
717 buffer.write(&dysymtab_command);
718
719 for (index, section) in self.sections.iter().enumerate() {
721 if !section.is_bss() {
722 buffer.resize(section_offsets[index].offset);
723 buffer.write_bytes(§ion.data);
724 }
725 }
726 debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len());
727
728 for (index, section) in self.sections.iter().enumerate() {
730 if !section.relocations.is_empty() {
731 write_align(buffer, pointer_align);
732 debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
733
734 let mut write_reloc = |reloc: &Relocation| {
735 let (r_type, r_pcrel, r_length) = if let RelocationFlags::MachO {
736 r_type,
737 r_pcrel,
738 r_length,
739 } = reloc.flags
740 {
741 (r_type, r_pcrel, r_length)
742 } else {
743 return Err(Error("invalid relocation flags".into()));
744 };
745
746 if reloc.addend != 0 {
748 let r_type = match self.architecture {
749 Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => {
750 macho::ARM64_RELOC_ADDEND
751 }
752 _ => {
753 return Err(Error(format!("unimplemented relocation {:?}", reloc)))
754 }
755 };
756
757 let reloc_info = macho::RelocationInfo {
758 r_address: reloc.offset as u32,
759 r_symbolnum: reloc.addend as u32,
760 r_pcrel: false,
761 r_length,
762 r_extern: false,
763 r_type,
764 };
765 buffer.write(&reloc_info.relocation(endian));
766 }
767
768 let r_extern;
769 let r_symbolnum;
770 let symbol = &self.symbols[reloc.symbol.0];
771 if symbol.kind == SymbolKind::Section {
772 r_symbolnum = section_offsets[symbol.section.id().unwrap().0].index as u32;
773 r_extern = false;
774 } else {
775 r_symbolnum = symbol_offsets[reloc.symbol.0].index as u32;
776 r_extern = true;
777 }
778
779 let reloc_info = macho::RelocationInfo {
780 r_address: reloc.offset as u32,
781 r_symbolnum,
782 r_pcrel,
783 r_length,
784 r_extern,
785 r_type,
786 };
787 buffer.write(&reloc_info.relocation(endian));
788 Ok(())
789 };
790
791 let need_reverse = |relocs: &[Relocation]| {
795 let Some(first) = relocs.first() else {
796 return false;
797 };
798 let Some(last) = relocs.last() else {
799 return false;
800 };
801 first.offset < last.offset
802 };
803 if need_reverse(§ion.relocations) {
804 for reloc in section.relocations.iter().rev() {
805 write_reloc(reloc)?;
806 }
807 } else {
808 for reloc in §ion.relocations {
809 write_reloc(reloc)?;
810 }
811 }
812 }
813 }
814
815 write_align(buffer, pointer_align);
817 debug_assert_eq!(symtab_offset, buffer.len());
818 for index in local_symbols
819 .iter()
820 .copied()
821 .chain(external_symbols.iter().copied())
822 .chain(undefined_symbols.iter().copied())
823 {
824 let symbol = &self.symbols[index];
825 let (mut n_type, n_sect) = match symbol.section {
827 SymbolSection::Undefined => (macho::N_UNDF | macho::N_EXT, 0),
828 SymbolSection::Absolute => (macho::N_ABS, 0),
829 SymbolSection::Section(id) => (macho::N_SECT, id.0 + 1),
830 SymbolSection::None | SymbolSection::Common => {
831 return Err(Error(format!(
832 "unimplemented symbol `{}` section {:?}",
833 symbol.name().unwrap_or(""),
834 symbol.section
835 )));
836 }
837 };
838 match symbol.scope {
839 SymbolScope::Unknown | SymbolScope::Compilation => {}
840 SymbolScope::Linkage => {
841 n_type |= macho::N_EXT | macho::N_PEXT;
842 }
843 SymbolScope::Dynamic => {
844 n_type |= macho::N_EXT;
845 }
846 }
847
848 let SymbolFlags::MachO { n_desc } = self.symbol_flags(symbol) else {
849 return Err(Error(format!(
850 "unimplemented symbol `{}` kind {:?}",
851 symbol.name().unwrap_or(""),
852 symbol.kind
853 )));
854 };
855
856 let n_value = match symbol.section.id() {
857 Some(section) => section_offsets[section.0].address + symbol.value,
858 None => symbol.value,
859 };
860
861 let n_strx = symbol_offsets[index]
862 .str_id
863 .map(|id| strtab.get_offset(id))
864 .unwrap_or(0);
865
866 macho.write_nlist(
867 buffer,
868 Nlist {
869 n_strx: n_strx as u32,
870 n_type,
871 n_sect: n_sect as u8,
872 n_desc,
873 n_value,
874 },
875 );
876 }
877
878 debug_assert_eq!(strtab_offset, buffer.len());
880 buffer.write_bytes(&strtab_data);
881
882 debug_assert_eq!(offset, buffer.len());
883
884 Ok(())
885 }
886}
887
888struct MachHeader {
889 cputype: u32,
890 cpusubtype: u32,
891 filetype: u32,
892 ncmds: u32,
893 sizeofcmds: u32,
894 flags: u32,
895}
896
897struct SegmentCommand {
898 cmdsize: u32,
899 segname: [u8; 16],
900 vmaddr: u64,
901 vmsize: u64,
902 fileoff: u64,
903 filesize: u64,
904 maxprot: u32,
905 initprot: u32,
906 nsects: u32,
907 flags: u32,
908}
909
910pub struct SectionHeader {
911 sectname: [u8; 16],
912 segname: [u8; 16],
913 addr: u64,
914 size: u64,
915 offset: u32,
916 align: u32,
917 reloff: u32,
918 nreloc: u32,
919 flags: u32,
920}
921
922struct Nlist {
923 n_strx: u32,
924 n_type: u8,
925 n_sect: u8,
926 n_desc: u16,
927 n_value: u64,
928}
929
930trait MachO {
931 fn mach_header_size(&self) -> usize;
932 fn segment_command_size(&self) -> usize;
933 fn section_header_size(&self) -> usize;
934 fn nlist_size(&self) -> usize;
935 fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, section: MachHeader);
936 fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand);
937 fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader);
938 fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist);
939}
940
941struct MachO32<E> {
942 endian: E,
943}
944
945impl<E: Endian> MachO for MachO32<E> {
946 fn mach_header_size(&self) -> usize {
947 mem::size_of::<macho::MachHeader32<E>>()
948 }
949
950 fn segment_command_size(&self) -> usize {
951 mem::size_of::<macho::SegmentCommand32<E>>()
952 }
953
954 fn section_header_size(&self) -> usize {
955 mem::size_of::<macho::Section32<E>>()
956 }
957
958 fn nlist_size(&self) -> usize {
959 mem::size_of::<macho::Nlist32<E>>()
960 }
961
962 fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) {
963 let endian = self.endian;
964 let magic = if endian.is_big_endian() {
965 macho::MH_MAGIC
966 } else {
967 macho::MH_CIGAM
968 };
969 let header = macho::MachHeader32 {
970 magic: U32::new(BigEndian, magic),
971 cputype: U32::new(endian, header.cputype),
972 cpusubtype: U32::new(endian, header.cpusubtype),
973 filetype: U32::new(endian, header.filetype),
974 ncmds: U32::new(endian, header.ncmds),
975 sizeofcmds: U32::new(endian, header.sizeofcmds),
976 flags: U32::new(endian, header.flags),
977 };
978 buffer.write(&header);
979 }
980
981 fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) {
982 let endian = self.endian;
983 let segment = macho::SegmentCommand32 {
984 cmd: U32::new(endian, macho::LC_SEGMENT),
985 cmdsize: U32::new(endian, segment.cmdsize),
986 segname: segment.segname,
987 vmaddr: U32::new(endian, segment.vmaddr as u32),
988 vmsize: U32::new(endian, segment.vmsize as u32),
989 fileoff: U32::new(endian, segment.fileoff as u32),
990 filesize: U32::new(endian, segment.filesize as u32),
991 maxprot: U32::new(endian, segment.maxprot),
992 initprot: U32::new(endian, segment.initprot),
993 nsects: U32::new(endian, segment.nsects),
994 flags: U32::new(endian, segment.flags),
995 };
996 buffer.write(&segment);
997 }
998
999 fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
1000 let endian = self.endian;
1001 let section = macho::Section32 {
1002 sectname: section.sectname,
1003 segname: section.segname,
1004 addr: U32::new(endian, section.addr as u32),
1005 size: U32::new(endian, section.size as u32),
1006 offset: U32::new(endian, section.offset),
1007 align: U32::new(endian, section.align),
1008 reloff: U32::new(endian, section.reloff),
1009 nreloc: U32::new(endian, section.nreloc),
1010 flags: U32::new(endian, section.flags),
1011 reserved1: U32::default(),
1012 reserved2: U32::default(),
1013 };
1014 buffer.write(§ion);
1015 }
1016
1017 fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) {
1018 let endian = self.endian;
1019 let nlist = macho::Nlist32 {
1020 n_strx: U32::new(endian, nlist.n_strx),
1021 n_type: nlist.n_type,
1022 n_sect: nlist.n_sect,
1023 n_desc: U16::new(endian, nlist.n_desc),
1024 n_value: U32::new(endian, nlist.n_value as u32),
1025 };
1026 buffer.write(&nlist);
1027 }
1028}
1029
1030struct MachO64<E> {
1031 endian: E,
1032}
1033
1034impl<E: Endian> MachO for MachO64<E> {
1035 fn mach_header_size(&self) -> usize {
1036 mem::size_of::<macho::MachHeader64<E>>()
1037 }
1038
1039 fn segment_command_size(&self) -> usize {
1040 mem::size_of::<macho::SegmentCommand64<E>>()
1041 }
1042
1043 fn section_header_size(&self) -> usize {
1044 mem::size_of::<macho::Section64<E>>()
1045 }
1046
1047 fn nlist_size(&self) -> usize {
1048 mem::size_of::<macho::Nlist64<E>>()
1049 }
1050
1051 fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) {
1052 let endian = self.endian;
1053 let magic = if endian.is_big_endian() {
1054 macho::MH_MAGIC_64
1055 } else {
1056 macho::MH_CIGAM_64
1057 };
1058 let header = macho::MachHeader64 {
1059 magic: U32::new(BigEndian, magic),
1060 cputype: U32::new(endian, header.cputype),
1061 cpusubtype: U32::new(endian, header.cpusubtype),
1062 filetype: U32::new(endian, header.filetype),
1063 ncmds: U32::new(endian, header.ncmds),
1064 sizeofcmds: U32::new(endian, header.sizeofcmds),
1065 flags: U32::new(endian, header.flags),
1066 reserved: U32::default(),
1067 };
1068 buffer.write(&header);
1069 }
1070
1071 fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) {
1072 let endian = self.endian;
1073 let segment = macho::SegmentCommand64 {
1074 cmd: U32::new(endian, macho::LC_SEGMENT_64),
1075 cmdsize: U32::new(endian, segment.cmdsize),
1076 segname: segment.segname,
1077 vmaddr: U64::new(endian, segment.vmaddr),
1078 vmsize: U64::new(endian, segment.vmsize),
1079 fileoff: U64::new(endian, segment.fileoff),
1080 filesize: U64::new(endian, segment.filesize),
1081 maxprot: U32::new(endian, segment.maxprot),
1082 initprot: U32::new(endian, segment.initprot),
1083 nsects: U32::new(endian, segment.nsects),
1084 flags: U32::new(endian, segment.flags),
1085 };
1086 buffer.write(&segment);
1087 }
1088
1089 fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
1090 let endian = self.endian;
1091 let section = macho::Section64 {
1092 sectname: section.sectname,
1093 segname: section.segname,
1094 addr: U64::new(endian, section.addr),
1095 size: U64::new(endian, section.size),
1096 offset: U32::new(endian, section.offset),
1097 align: U32::new(endian, section.align),
1098 reloff: U32::new(endian, section.reloff),
1099 nreloc: U32::new(endian, section.nreloc),
1100 flags: U32::new(endian, section.flags),
1101 reserved1: U32::default(),
1102 reserved2: U32::default(),
1103 reserved3: U32::default(),
1104 };
1105 buffer.write(§ion);
1106 }
1107
1108 fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) {
1109 let endian = self.endian;
1110 let nlist = macho::Nlist64 {
1111 n_strx: U32::new(endian, nlist.n_strx),
1112 n_type: nlist.n_type,
1113 n_sect: nlist.n_sect,
1114 n_desc: U16::new(endian, nlist.n_desc),
1115 n_value: U64Bytes::new(endian, nlist.n_value),
1116 };
1117 buffer.write(&nlist);
1118 }
1119}