1use anyhow::anyhow;
4use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc};
5use cranelift_codegen::entity::SecondaryMap;
6use cranelift_codegen::ir;
7use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
8use cranelift_control::ControlPlane;
9use cranelift_module::{
10 DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleDeclarations, ModuleError,
11 ModuleReloc, ModuleRelocTarget, ModuleResult,
12};
13use log::{info, warn};
14use object::write::{
15 Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection,
16};
17use object::{
18 BinaryFormat, RelocationEncoding, RelocationFlags, RelocationKind, SectionFlags, SectionKind,
19 SymbolFlags, SymbolKind, SymbolScope, elf, macho,
20};
21use std::collections::HashMap;
22use std::collections::hash_map::Entry;
23use std::fmt::Write as _;
24use std::mem;
25use target_lexicon::{PointerWidth, Triple};
26
27pub struct ObjectBuilder {
29 isa: OwnedTargetIsa,
30 binary_format: object::BinaryFormat,
31 architecture: object::Architecture,
32 flags: object::FileFlags,
33 endian: object::Endianness,
34 name: Vec<u8>,
35 libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
36 per_function_section: bool,
37 per_data_object_section: bool,
38 #[cfg(feature = "unwind")]
39 unwind_info: bool,
40}
41
42impl ObjectBuilder {
43 pub fn new<V: Into<Vec<u8>>>(
51 isa: OwnedTargetIsa,
52 name: V,
53 libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
54 ) -> ModuleResult<Self> {
55 let mut file_flags = object::FileFlags::None;
56 let binary_format = match isa.triple().binary_format {
57 target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
58 target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
59 target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
60 target_lexicon::BinaryFormat::Wasm => {
61 return Err(ModuleError::Backend(anyhow!(
62 "binary format wasm is unsupported",
63 )));
64 }
65 target_lexicon::BinaryFormat::Unknown => {
66 return Err(ModuleError::Backend(anyhow!("binary format is unknown")));
67 }
68 other => {
69 return Err(ModuleError::Backend(anyhow!(
70 "binary format {other} not recognized"
71 )));
72 }
73 };
74 let architecture = match isa.triple().architecture {
75 target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
76 target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
77 target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
78 target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
79 target_lexicon::Architecture::Riscv64(_) => {
80 if binary_format != object::BinaryFormat::Elf {
81 return Err(ModuleError::Backend(anyhow!(
82 "binary format {binary_format:?} is not supported for riscv64",
83 )));
84 }
85
86 let mut eflags = object::elf::EF_RISCV_FLOAT_ABI_DOUBLE;
88
89 let has_c = isa
91 .isa_flags()
92 .iter()
93 .filter(|f| f.name == "has_zca" || f.name == "has_zcd")
94 .all(|f| f.as_bool().unwrap_or_default());
95 if has_c {
96 eflags |= object::elf::EF_RISCV_RVC;
97 }
98
99 file_flags = object::FileFlags::Elf {
100 os_abi: object::elf::ELFOSABI_NONE,
101 abi_version: 0,
102 e_flags: eflags,
103 };
104 object::Architecture::Riscv64
105 }
106 target_lexicon::Architecture::S390x => object::Architecture::S390x,
107 architecture => {
108 return Err(ModuleError::Backend(anyhow!(
109 "target architecture {architecture:?} is unsupported",
110 )));
111 }
112 };
113 let endian = match isa.triple().endianness().unwrap() {
114 target_lexicon::Endianness::Little => object::Endianness::Little,
115 target_lexicon::Endianness::Big => object::Endianness::Big,
116 };
117 Ok(Self {
118 isa,
119 binary_format,
120 architecture,
121 flags: file_flags,
122 endian,
123 name: name.into(),
124 libcall_names,
125 per_function_section: false,
126 per_data_object_section: false,
127 #[cfg(feature = "unwind")]
128 unwind_info: false,
129 })
130 }
131
132 pub fn per_function_section(&mut self, per_function_section: bool) -> &mut Self {
134 self.per_function_section = per_function_section;
135 self
136 }
137
138 pub fn per_data_object_section(&mut self, per_data_object_section: bool) -> &mut Self {
140 self.per_data_object_section = per_data_object_section;
141 self
142 }
143
144 #[cfg(feature = "unwind")]
169 pub fn unwind_info(&mut self, unwind_info: bool) -> &mut Self {
170 self.unwind_info = unwind_info;
171 self
172 }
173}
174
175fn macho_build_version(triple: &Triple) -> Option<object::write::MachOBuildVersion> {
178 use target_lexicon::OperatingSystem::*;
179
180 match triple.operating_system {
181 Darwin(v) | MacOSX(v) | IOS(v) | TvOS(v) | VisionOS(v) | WatchOS(v) | XROS(v) => {
182 use object::macho::*;
183 use target_lexicon::Environment::*;
184 let platform = match (triple.operating_system, triple.environment) {
189 (Darwin(_), _) => PLATFORM_MACOS,
192 (MacOSX(_), _) => PLATFORM_MACOS,
193 (_, Macabi) => PLATFORM_MACCATALYST,
194 (IOS(_), Sim) => PLATFORM_IOSSIMULATOR,
195 (IOS(_), _) => PLATFORM_IOS,
196 (TvOS(_), Sim) => PLATFORM_TVOSSIMULATOR,
197 (TvOS(_), _) => PLATFORM_TVOS,
198 (VisionOS(_) | XROS(_), Sim) => PLATFORM_XROSSIMULATOR,
199 (VisionOS(_) | XROS(_), _) => PLATFORM_XROS,
200 (WatchOS(_), Sim) => PLATFORM_WATCHOSSIMULATOR,
201 (WatchOS(_), _) => PLATFORM_WATCHOS,
202 _ => {
203 warn!("unsupported OS/environment: {triple}");
204 PLATFORM_UNKNOWN
205 }
206 };
207
208 let mut build_version = object::write::MachOBuildVersion::default();
209 build_version.platform = platform;
210
211 build_version.minos = if let Some(v) = v {
212 macho::Version::new(v.major, v.minor, v.patch)
213 } else {
214 macho::Version(0)
222 };
223
224 build_version.sdk = macho::Version(0);
227
228 Some(build_version)
229 }
230 _ => None,
231 }
232}
233
234pub struct ObjectModule {
238 isa: OwnedTargetIsa,
239 object: Object<'static>,
240 declarations: ModuleDeclarations,
241 functions: SecondaryMap<FuncId, Option<(SymbolId, bool)>>,
242 data_objects: SecondaryMap<DataId, Option<(SymbolId, bool)>>,
243 relocs: Vec<SymbolRelocs>,
244 libcalls: HashMap<ir::LibCall, SymbolId>,
245 libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
246 known_symbols: HashMap<ir::KnownSymbol, SymbolId>,
247 known_labels: HashMap<(FuncId, CodeOffset), SymbolId>,
248 per_function_section: bool,
249 per_data_object_section: bool,
250 #[cfg(feature = "unwind")]
251 unwind: Option<crate::unwind::UnwindBuilder>,
252}
253
254impl ObjectModule {
255 pub fn new(builder: ObjectBuilder) -> Self {
257 let mut object = Object::new(builder.binary_format, builder.architecture, builder.endian);
258 object.flags = builder.flags;
259 object.set_subsections_via_symbols();
260 object.add_file_symbol(builder.name);
261 if let Some(info) = macho_build_version(builder.isa.triple()) {
262 object.set_macho_build_version(info);
267 }
268 #[cfg(feature = "unwind")]
269 let unwind = builder
270 .unwind_info
271 .then(|| crate::unwind::UnwindBuilder::new(builder.endian));
272 Self {
273 isa: builder.isa,
274 object,
275 declarations: ModuleDeclarations::default(),
276 functions: SecondaryMap::new(),
277 data_objects: SecondaryMap::new(),
278 relocs: Vec::new(),
279 libcalls: HashMap::new(),
280 libcall_names: builder.libcall_names,
281 known_symbols: HashMap::new(),
282 known_labels: HashMap::new(),
283 per_function_section: builder.per_function_section,
284 per_data_object_section: builder.per_data_object_section,
285 #[cfg(feature = "unwind")]
286 unwind,
287 }
288 }
289}
290
291fn validate_symbol(name: &str) -> ModuleResult<()> {
292 if name.contains("\0") {
295 return Err(ModuleError::Backend(anyhow::anyhow!(
296 "Symbol {name:?} has a null byte, which is disallowed"
297 )));
298 }
299 Ok(())
300}
301
302impl Module for ObjectModule {
303 fn isa(&self) -> &dyn TargetIsa {
304 &*self.isa
305 }
306
307 fn declarations(&self) -> &ModuleDeclarations {
308 &self.declarations
309 }
310
311 fn declare_function(
312 &mut self,
313 name: &str,
314 linkage: Linkage,
315 signature: &ir::Signature,
316 ) -> ModuleResult<FuncId> {
317 validate_symbol(name)?;
318
319 let (id, linkage) = self
320 .declarations
321 .declare_function(name, linkage, signature)?;
322
323 let (scope, weak) = translate_linkage(linkage);
324
325 if let Some((function, _defined)) = self.functions[id] {
326 let symbol = self.object.symbol_mut(function);
327 symbol.scope = scope;
328 symbol.weak = weak;
329 } else {
330 let symbol_id = self.object.add_symbol(Symbol {
331 name: name.as_bytes().to_vec(),
332 value: 0,
333 size: 0,
334 kind: SymbolKind::Text,
335 scope,
336 weak,
337 section: SymbolSection::Undefined,
338 flags: SymbolFlags::None,
339 });
340 self.functions[id] = Some((symbol_id, false));
341 }
342
343 Ok(id)
344 }
345
346 fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
347 let id = self.declarations.declare_anonymous_function(signature)?;
348
349 let symbol_id = self.object.add_symbol(Symbol {
350 name: self
351 .declarations
352 .get_function_decl(id)
353 .linkage_name(id)
354 .into_owned()
355 .into_bytes(),
356 value: 0,
357 size: 0,
358 kind: SymbolKind::Text,
359 scope: SymbolScope::Compilation,
360 weak: false,
361 section: SymbolSection::Undefined,
362 flags: SymbolFlags::None,
363 });
364 self.functions[id] = Some((symbol_id, false));
365
366 Ok(id)
367 }
368
369 fn declare_data(
370 &mut self,
371 name: &str,
372 linkage: Linkage,
373 writable: bool,
374 tls: bool,
375 ) -> ModuleResult<DataId> {
376 validate_symbol(name)?;
377
378 let (id, linkage) = self
379 .declarations
380 .declare_data(name, linkage, writable, tls)?;
381
382 let kind = if tls {
385 SymbolKind::Tls
386 } else {
387 SymbolKind::Data
388 };
389 let (scope, weak) = translate_linkage(linkage);
390
391 if let Some((data, _defined)) = self.data_objects[id] {
392 let symbol = self.object.symbol_mut(data);
393 symbol.kind = kind;
394 symbol.scope = scope;
395 symbol.weak = weak;
396 } else {
397 let symbol_id = self.object.add_symbol(Symbol {
398 name: name.as_bytes().to_vec(),
399 value: 0,
400 size: 0,
401 kind,
402 scope,
403 weak,
404 section: SymbolSection::Undefined,
405 flags: SymbolFlags::None,
406 });
407 self.data_objects[id] = Some((symbol_id, false));
408 }
409
410 Ok(id)
411 }
412
413 fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
414 let id = self.declarations.declare_anonymous_data(writable, tls)?;
415
416 let kind = if tls {
417 SymbolKind::Tls
418 } else {
419 SymbolKind::Data
420 };
421
422 let symbol_id = self.object.add_symbol(Symbol {
423 name: self
424 .declarations
425 .get_data_decl(id)
426 .linkage_name(id)
427 .into_owned()
428 .into_bytes(),
429 value: 0,
430 size: 0,
431 kind,
432 scope: SymbolScope::Compilation,
433 weak: false,
434 section: SymbolSection::Undefined,
435 flags: SymbolFlags::None,
436 });
437 self.data_objects[id] = Some((symbol_id, false));
438
439 Ok(id)
440 }
441
442 fn define_function_with_control_plane(
443 &mut self,
444 func_id: FuncId,
445 ctx: &mut cranelift_codegen::Context,
446 ctrl_plane: &mut ControlPlane,
447 ) -> ModuleResult<()> {
448 info!("defining function {}: {}", func_id, ctx.func.display());
449
450 let res = ctx.compile(self.isa(), ctrl_plane)?;
451 let alignment = res.buffer.alignment as u64;
452
453 let compiled = ctx.compiled_code().unwrap();
454 #[cfg(feature = "unwind")]
455 let unwind_info = if self.unwind.is_some() {
456 compiled.create_unwind_info(self.isa())?
457 } else {
458 None
459 };
460 let buffer = &compiled.buffer;
461 let relocs = buffer
462 .relocs()
463 .iter()
464 .map(|reloc| {
465 self.process_reloc(&ModuleReloc::from_mach_reloc(&reloc, &ctx.func, func_id))
466 })
467 .collect::<Vec<_>>();
468 self.define_function_inner(func_id, alignment, buffer.data(), relocs)?;
469 #[cfg(feature = "unwind")]
470 if let (Some(builder), Some(info)) = (self.unwind.as_mut(), unwind_info) {
471 let symbol = self.functions[func_id].unwrap().0;
472 builder.add_function(&*self.isa, symbol, info);
473 }
474 Ok(())
475 }
476
477 fn define_function_bytes(
478 &mut self,
479 func_id: FuncId,
480 alignment: u64,
481 bytes: &[u8],
482 relocs: &[ModuleReloc],
483 ) -> ModuleResult<()> {
484 let relocs = relocs
485 .iter()
486 .map(|reloc| self.process_reloc(reloc))
487 .collect();
488 self.define_function_inner(func_id, alignment, bytes, relocs)
489 }
490
491 fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> {
492 let decl = self.declarations.get_data_decl(data_id);
493 if !decl.linkage.is_definable() {
494 return Err(ModuleError::InvalidImportDefinition(
495 decl.linkage_name(data_id).into_owned(),
496 ));
497 }
498
499 let &mut (symbol, ref mut defined) = self.data_objects[data_id].as_mut().unwrap();
500 if *defined {
501 return Err(ModuleError::DuplicateDefinition(
502 decl.linkage_name(data_id).into_owned(),
503 ));
504 }
505 *defined = true;
506
507 let &DataDescription {
508 ref init,
509 function_decls: _,
510 data_decls: _,
511 function_relocs: _,
512 data_relocs: _,
513 ref custom_section,
514 align,
515 used,
516 } = data;
517
518 let pointer_reloc = match self.isa.triple().pointer_width().unwrap() {
519 PointerWidth::U16 => unimplemented!("16bit pointers"),
520 PointerWidth::U32 => Reloc::Abs4,
521 PointerWidth::U64 => Reloc::Abs8,
522 };
523 let relocs = data
524 .all_relocs(pointer_reloc)
525 .map(|record| self.process_reloc(&record))
526 .collect::<Vec<_>>();
527
528 let section = if custom_section.is_none() {
529 let section_kind = if let Init::Zeros { .. } = *init {
530 if decl.tls {
531 StandardSection::UninitializedTls
532 } else {
533 StandardSection::UninitializedData
534 }
535 } else if decl.tls {
536 StandardSection::Tls
537 } else if decl.writable {
538 StandardSection::Data
539 } else if relocs.is_empty() {
540 StandardSection::ReadOnlyData
541 } else {
542 StandardSection::ReadOnlyDataWithRel
543 };
544 if self.per_data_object_section || used {
545 self.object.add_subsection(section_kind, b"subsection")
550 } else {
551 self.object.section_id(section_kind)
552 }
553 } else {
554 if decl.tls {
555 return Err(cranelift_module::ModuleError::Backend(anyhow::anyhow!(
556 "Custom section not supported for TLS"
557 )));
558 }
559 let (segment, section, macho_flags) =
560 parse_section(custom_section.as_ref().unwrap(), self.object.format())
561 .map_err(ModuleError::Backend)?;
562 let section = self.object.add_section(
563 segment.to_string().into_bytes(),
564 section.to_string().into_bytes(),
565 if decl.writable {
566 SectionKind::Data
567 } else if relocs.is_empty() {
568 SectionKind::ReadOnlyData
569 } else {
570 SectionKind::ReadOnlyDataWithRel
571 },
572 );
573
574 match self.object.section_flags_mut(section) {
575 SectionFlags::MachO { flags, .. } => {
576 assert_eq!(flags.0, 0);
583 *flags = macho_flags;
584 }
585 _ => {
586 if macho_flags.0 != 0 {
587 unreachable!("unsupported Mach-O flags for this platform: {macho_flags:?}");
588 }
589 }
590 }
591
592 section
593 };
594
595 if used {
596 match self.object.format() {
597 object::BinaryFormat::Elf => match self.object.section_flags_mut(section) {
598 SectionFlags::Elf { sh_flags, .. } => *sh_flags |= elf::SHF_GNU_RETAIN,
599 _ => unreachable!(),
600 },
601 object::BinaryFormat::Coff => {}
602 object::BinaryFormat::MachO => match self.object.symbol_flags_mut(symbol) {
603 SymbolFlags::MachO { n_desc, .. } => *n_desc |= macho::N_NO_DEAD_STRIP,
604 _ => unreachable!(),
605 },
606 _ => unreachable!(),
607 }
608 }
609
610 let align = std::cmp::max(align.unwrap_or(1), self.isa.symbol_alignment());
611 let offset = match *init {
612 Init::Uninitialized => {
613 panic!("data is not initialized yet");
614 }
615 Init::Zeros { size } => self
616 .object
617 .add_symbol_bss(symbol, section, size as u64, align),
618 Init::Bytes { ref contents } => self
619 .object
620 .add_symbol_data(symbol, section, &contents, align),
621 };
622 if !relocs.is_empty() {
623 self.relocs.push(SymbolRelocs {
624 section,
625 offset,
626 relocs,
627 });
628 }
629 Ok(())
630 }
631}
632
633impl ObjectModule {
634 fn define_function_inner(
635 &mut self,
636 func_id: FuncId,
637 alignment: u64,
638 bytes: &[u8],
639 relocs: Vec<ObjectRelocRecord>,
640 ) -> Result<(), ModuleError> {
641 info!("defining function {func_id} with bytes");
642 let decl = self.declarations.get_function_decl(func_id);
643 let decl_name = decl.linkage_name(func_id);
644 if !decl.linkage.is_definable() {
645 return Err(ModuleError::InvalidImportDefinition(decl_name.into_owned()));
646 }
647
648 let &mut (symbol, ref mut defined) = self.functions[func_id].as_mut().unwrap();
649 if *defined {
650 return Err(ModuleError::DuplicateDefinition(decl_name.into_owned()));
651 }
652 *defined = true;
653
654 let align = alignment.max(self.isa.symbol_alignment());
655 let section = if self.per_function_section {
656 self.object
660 .add_subsection(StandardSection::Text, b"subsection")
661 } else {
662 self.object.section_id(StandardSection::Text)
663 };
664 let offset = self.object.add_symbol_data(symbol, section, bytes, align);
665
666 if !relocs.is_empty() {
667 self.relocs.push(SymbolRelocs {
668 section,
669 offset,
670 relocs,
671 });
672 }
673
674 Ok(())
675 }
676
677 pub fn finish(mut self) -> ObjectProduct {
679 if cfg!(debug_assertions) {
680 for (func_id, decl) in self.declarations.get_functions() {
681 if !decl.linkage.requires_definition() {
682 continue;
683 }
684
685 assert!(
686 self.functions[func_id].unwrap().1,
687 "function \"{}\" with linkage {:?} must be defined but is not",
688 decl.linkage_name(func_id),
689 decl.linkage,
690 );
691 }
692
693 for (data_id, decl) in self.declarations.get_data_objects() {
694 if !decl.linkage.requires_definition() {
695 continue;
696 }
697
698 assert!(
699 self.data_objects[data_id].unwrap().1,
700 "data object \"{}\" with linkage {:?} must be defined but is not",
701 decl.linkage_name(data_id),
702 decl.linkage,
703 );
704 }
705 }
706
707 let symbol_relocs = mem::take(&mut self.relocs);
708 for symbol in symbol_relocs {
709 for &ObjectRelocRecord {
710 offset,
711 ref name,
712 flags,
713 addend,
714 } in &symbol.relocs
715 {
716 let target_symbol = self.get_symbol(name);
717 self.object
718 .add_relocation(
719 symbol.section,
720 Relocation {
721 offset: symbol.offset + u64::from(offset),
722 flags,
723 symbol: target_symbol,
724 addend,
725 },
726 )
727 .unwrap();
728 }
729 }
730
731 if self.object.format() == object::BinaryFormat::Elf {
733 self.object.add_section(
734 vec![],
735 ".note.GNU-stack".as_bytes().to_vec(),
736 SectionKind::Linker,
737 );
738 }
739
740 #[cfg(feature = "unwind")]
741 if let Some(unwind) = self.unwind.take() {
742 unwind
743 .finish(&mut self.object, &*self.isa)
744 .expect("failed to emit .eh_frame section");
745 }
746
747 ObjectProduct {
748 object: self.object,
749 functions: self.functions,
750 data_objects: self.data_objects,
751 }
752 }
753
754 fn get_symbol(&mut self, name: &ModuleRelocTarget) -> SymbolId {
757 match *name {
758 ModuleRelocTarget::User { .. } => {
759 if ModuleDeclarations::is_function(name) {
760 let id = FuncId::from_name(name);
761 self.functions[id].unwrap().0
762 } else {
763 let id = DataId::from_name(name);
764 self.data_objects[id].unwrap().0
765 }
766 }
767 ModuleRelocTarget::LibCall(ref libcall) => {
768 let name = (self.libcall_names)(*libcall);
769 if let Some(symbol) = self.object.symbol_id(name.as_bytes()) {
770 symbol
771 } else if let Some(symbol) = self.libcalls.get(libcall) {
772 *symbol
773 } else {
774 let symbol = self.object.add_symbol(Symbol {
775 name: name.as_bytes().to_vec(),
776 value: 0,
777 size: 0,
778 kind: SymbolKind::Text,
779 scope: SymbolScope::Unknown,
780 weak: false,
781 section: SymbolSection::Undefined,
782 flags: SymbolFlags::None,
783 });
784 self.libcalls.insert(*libcall, symbol);
785 symbol
786 }
787 }
788 ModuleRelocTarget::KnownSymbol(ref known_symbol) => {
791 if let Some(symbol) = self.known_symbols.get(known_symbol) {
792 *symbol
793 } else {
794 let symbol = self.object.add_symbol(match known_symbol {
795 ir::KnownSymbol::ElfGlobalOffsetTable => Symbol {
796 name: b"_GLOBAL_OFFSET_TABLE_".to_vec(),
797 value: 0,
798 size: 0,
799 kind: SymbolKind::Data,
800 scope: SymbolScope::Unknown,
801 weak: false,
802 section: SymbolSection::Undefined,
803 flags: SymbolFlags::None,
804 },
805 ir::KnownSymbol::CoffTlsIndex => Symbol {
806 name: b"_tls_index".to_vec(),
807 value: 0,
808 size: 32,
809 kind: SymbolKind::Tls,
810 scope: SymbolScope::Unknown,
811 weak: false,
812 section: SymbolSection::Undefined,
813 flags: SymbolFlags::None,
814 },
815 });
816 self.known_symbols.insert(*known_symbol, symbol);
817 symbol
818 }
819 }
820
821 ModuleRelocTarget::FunctionOffset(func_id, offset) => {
822 match self.known_labels.entry((func_id, offset)) {
823 Entry::Occupied(o) => *o.get(),
824 Entry::Vacant(v) => {
825 let func_symbol_id = self.functions[func_id].unwrap().0;
826 let func_symbol = self.object.symbol(func_symbol_id);
827
828 let name = format!(".L{}_{}", func_id.as_u32(), offset);
829 let symbol_id = self.object.add_symbol(Symbol {
830 name: name.as_bytes().to_vec(),
831 value: func_symbol.value + offset as u64,
832 size: 0,
833 kind: SymbolKind::Label,
834 scope: SymbolScope::Compilation,
835 weak: false,
836 section: SymbolSection::Section(func_symbol.section.id().unwrap()),
837 flags: SymbolFlags::None,
838 });
839
840 v.insert(symbol_id);
841 symbol_id
842 }
843 }
844 }
845 }
846 }
847
848 fn process_reloc(&self, record: &ModuleReloc) -> ObjectRelocRecord {
849 let flags = match record.kind {
850 Reloc::Abs4 => RelocationFlags::Generic {
851 kind: RelocationKind::Absolute,
852 encoding: RelocationEncoding::Generic,
853 size: 32,
854 },
855 Reloc::Abs8 => RelocationFlags::Generic {
856 kind: RelocationKind::Absolute,
857 encoding: RelocationEncoding::Generic,
858 size: 64,
859 },
860 Reloc::X86PCRel4 => RelocationFlags::Generic {
861 kind: RelocationKind::Relative,
862 encoding: RelocationEncoding::Generic,
863 size: 32,
864 },
865 Reloc::X86CallPCRel4 => RelocationFlags::Generic {
866 kind: RelocationKind::Relative,
867 encoding: RelocationEncoding::X86Branch,
868 size: 32,
869 },
870 Reloc::X86CallPLTRel4 => RelocationFlags::Generic {
873 kind: RelocationKind::PltRelative,
874 encoding: RelocationEncoding::X86Branch,
875 size: 32,
876 },
877 Reloc::X86SecRel => RelocationFlags::Generic {
878 kind: RelocationKind::SectionOffset,
879 encoding: RelocationEncoding::Generic,
880 size: 32,
881 },
882 Reloc::X86GOTPCRel4 => RelocationFlags::Generic {
883 kind: RelocationKind::GotRelative,
884 encoding: RelocationEncoding::Generic,
885 size: 32,
886 },
887 Reloc::Arm64Call => RelocationFlags::Generic {
888 kind: RelocationKind::Relative,
889 encoding: RelocationEncoding::AArch64Call,
890 size: 26,
891 },
892 Reloc::ElfX86_64TlsGd => {
893 assert_eq!(
894 self.object.format(),
895 object::BinaryFormat::Elf,
896 "ElfX86_64TlsGd is not supported for this file format"
897 );
898 RelocationFlags::Elf {
899 r_type: object::elf::R_X86_64_TLSGD,
900 }
901 }
902 Reloc::MachOX86_64Tlv => {
903 assert_eq!(
904 self.object.format(),
905 object::BinaryFormat::MachO,
906 "MachOX86_64Tlv is not supported for this file format"
907 );
908 RelocationFlags::MachO {
909 r_type: object::macho::X86_64_RELOC_TLV,
910 r_pcrel: true,
911 r_length: 2,
912 }
913 }
914 Reloc::MachOAarch64TlsAdrPage21 => {
915 assert_eq!(
916 self.object.format(),
917 object::BinaryFormat::MachO,
918 "MachOAarch64TlsAdrPage21 is not supported for this file format"
919 );
920 RelocationFlags::MachO {
921 r_type: object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21,
922 r_pcrel: true,
923 r_length: 2,
924 }
925 }
926 Reloc::MachOAarch64TlsAdrPageOff12 => {
927 assert_eq!(
928 self.object.format(),
929 object::BinaryFormat::MachO,
930 "MachOAarch64TlsAdrPageOff12 is not supported for this file format"
931 );
932 RelocationFlags::MachO {
933 r_type: object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
934 r_pcrel: false,
935 r_length: 2,
936 }
937 }
938 Reloc::Aarch64TlsDescAdrPage21 => {
939 assert_eq!(
940 self.object.format(),
941 object::BinaryFormat::Elf,
942 "Aarch64TlsDescAdrPage21 is not supported for this file format"
943 );
944 RelocationFlags::Elf {
945 r_type: object::elf::R_AARCH64_TLSDESC_ADR_PAGE21,
946 }
947 }
948 Reloc::Aarch64TlsDescLd64Lo12 => {
949 assert_eq!(
950 self.object.format(),
951 object::BinaryFormat::Elf,
952 "Aarch64TlsDescLd64Lo12 is not supported for this file format"
953 );
954 RelocationFlags::Elf {
955 r_type: object::elf::R_AARCH64_TLSDESC_LD64_LO12,
956 }
957 }
958 Reloc::Aarch64TlsDescAddLo12 => {
959 assert_eq!(
960 self.object.format(),
961 object::BinaryFormat::Elf,
962 "Aarch64TlsDescAddLo12 is not supported for this file format"
963 );
964 RelocationFlags::Elf {
965 r_type: object::elf::R_AARCH64_TLSDESC_ADD_LO12,
966 }
967 }
968 Reloc::Aarch64TlsDescCall => {
969 assert_eq!(
970 self.object.format(),
971 object::BinaryFormat::Elf,
972 "Aarch64TlsDescCall is not supported for this file format"
973 );
974 RelocationFlags::Elf {
975 r_type: object::elf::R_AARCH64_TLSDESC_CALL,
976 }
977 }
978
979 Reloc::Aarch64AdrGotPage21 => match self.object.format() {
980 object::BinaryFormat::Elf => RelocationFlags::Elf {
981 r_type: object::elf::R_AARCH64_ADR_GOT_PAGE,
982 },
983 object::BinaryFormat::MachO => RelocationFlags::MachO {
984 r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21,
985 r_pcrel: true,
986 r_length: 2,
987 },
988 _ => unimplemented!("Aarch64AdrGotPage21 is not supported for this file format"),
989 },
990 Reloc::Aarch64Ld64GotLo12Nc => match self.object.format() {
991 object::BinaryFormat::Elf => RelocationFlags::Elf {
992 r_type: object::elf::R_AARCH64_LD64_GOT_LO12_NC,
993 },
994 object::BinaryFormat::MachO => RelocationFlags::MachO {
995 r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
996 r_pcrel: false,
997 r_length: 2,
998 },
999 _ => unimplemented!("Aarch64Ld64GotLo12Nc is not supported for this file format"),
1000 },
1001 Reloc::Aarch64AdrPrelPgHi21 => match self.object.format() {
1002 object::BinaryFormat::Elf => RelocationFlags::Elf {
1003 r_type: object::elf::R_AARCH64_ADR_PREL_PG_HI21,
1004 },
1005 object::BinaryFormat::MachO => RelocationFlags::MachO {
1006 r_type: object::macho::ARM64_RELOC_PAGE21,
1007 r_pcrel: true,
1008 r_length: 2,
1009 },
1010 _ => unimplemented!("Aarch64AdrPrelPgHi21 is not supported for this file format"),
1011 },
1012 Reloc::Aarch64AddAbsLo12Nc => match self.object.format() {
1013 object::BinaryFormat::Elf => RelocationFlags::Elf {
1014 r_type: object::elf::R_AARCH64_ADD_ABS_LO12_NC,
1015 },
1016 object::BinaryFormat::MachO => RelocationFlags::MachO {
1017 r_type: object::macho::ARM64_RELOC_PAGEOFF12,
1018 r_pcrel: false,
1019 r_length: 2,
1020 },
1021 _ => unimplemented!("Aarch64AddAbsLo12Nc is not supported for this file format"),
1022 },
1023 Reloc::S390xPCRel32Dbl => RelocationFlags::Generic {
1024 kind: RelocationKind::Relative,
1025 encoding: RelocationEncoding::S390xDbl,
1026 size: 32,
1027 },
1028 Reloc::S390xPLTRel32Dbl => RelocationFlags::Generic {
1029 kind: RelocationKind::PltRelative,
1030 encoding: RelocationEncoding::S390xDbl,
1031 size: 32,
1032 },
1033 Reloc::S390xTlsGd64 => {
1034 assert_eq!(
1035 self.object.format(),
1036 object::BinaryFormat::Elf,
1037 "S390xTlsGd64 is not supported for this file format"
1038 );
1039 RelocationFlags::Elf {
1040 r_type: object::elf::R_390_TLS_GD64,
1041 }
1042 }
1043 Reloc::S390xTlsGdCall => {
1044 assert_eq!(
1045 self.object.format(),
1046 object::BinaryFormat::Elf,
1047 "S390xTlsGdCall is not supported for this file format"
1048 );
1049 RelocationFlags::Elf {
1050 r_type: object::elf::R_390_TLS_GDCALL,
1051 }
1052 }
1053 Reloc::RiscvCallPlt => {
1054 assert_eq!(
1055 self.object.format(),
1056 object::BinaryFormat::Elf,
1057 "RiscvCallPlt is not supported for this file format"
1058 );
1059 RelocationFlags::Elf {
1060 r_type: object::elf::R_RISCV_CALL_PLT,
1061 }
1062 }
1063 Reloc::RiscvTlsGdHi20 => {
1064 assert_eq!(
1065 self.object.format(),
1066 object::BinaryFormat::Elf,
1067 "RiscvTlsGdHi20 is not supported for this file format"
1068 );
1069 RelocationFlags::Elf {
1070 r_type: object::elf::R_RISCV_TLS_GD_HI20,
1071 }
1072 }
1073 Reloc::RiscvPCRelLo12I => {
1074 assert_eq!(
1075 self.object.format(),
1076 object::BinaryFormat::Elf,
1077 "RiscvPCRelLo12I is not supported for this file format"
1078 );
1079 RelocationFlags::Elf {
1080 r_type: object::elf::R_RISCV_PCREL_LO12_I,
1081 }
1082 }
1083 Reloc::RiscvGotHi20 => {
1084 assert_eq!(
1085 self.object.format(),
1086 object::BinaryFormat::Elf,
1087 "RiscvGotHi20 is not supported for this file format"
1088 );
1089 RelocationFlags::Elf {
1090 r_type: object::elf::R_RISCV_GOT_HI20,
1091 }
1092 }
1093 Reloc::RiscvPCRelHi20 => {
1094 assert_eq!(
1095 self.object.format(),
1096 object::BinaryFormat::Elf,
1097 "RiscvPCRelHi20 is not supported for this file format"
1098 );
1099 RelocationFlags::Elf {
1100 r_type: object::elf::R_RISCV_PCREL_HI20,
1101 }
1102 }
1103 reloc => unimplemented!("{:?}", reloc),
1105 };
1106
1107 ObjectRelocRecord {
1108 offset: record.offset,
1109 name: record.name.clone(),
1110 flags,
1111 addend: record.addend,
1112 }
1113 }
1114}
1115
1116fn translate_linkage(linkage: Linkage) -> (SymbolScope, bool) {
1117 let scope = match linkage {
1118 Linkage::Import => SymbolScope::Unknown,
1119 Linkage::Local => SymbolScope::Compilation,
1120 Linkage::Hidden => SymbolScope::Linkage,
1121 Linkage::Export | Linkage::Preemptible => SymbolScope::Dynamic,
1122 };
1123 let weak = linkage == Linkage::Preemptible;
1125 (scope, weak)
1126}
1127
1128pub struct ObjectProduct {
1133 pub object: Object<'static>,
1135 pub functions: SecondaryMap<FuncId, Option<(SymbolId, bool)>>,
1137 pub data_objects: SecondaryMap<DataId, Option<(SymbolId, bool)>>,
1139}
1140
1141impl ObjectProduct {
1142 #[inline]
1144 pub fn function_symbol(&self, id: FuncId) -> SymbolId {
1145 self.functions[id].unwrap().0
1146 }
1147
1148 #[inline]
1150 pub fn data_symbol(&self, id: DataId) -> SymbolId {
1151 self.data_objects[id].unwrap().0
1152 }
1153
1154 #[inline]
1156 pub fn emit(self) -> Result<Vec<u8>, object::write::Error> {
1157 self.object.write()
1158 }
1159}
1160
1161#[derive(Clone)]
1162struct SymbolRelocs {
1163 section: SectionId,
1164 offset: u64,
1165 relocs: Vec<ObjectRelocRecord>,
1166}
1167
1168#[derive(Clone)]
1169struct ObjectRelocRecord {
1170 offset: CodeOffset,
1171 name: ModuleRelocTarget,
1172 flags: RelocationFlags,
1173 addend: Addend,
1174}
1175
1176fn parse_section(
1177 section: &str,
1178 binary_format: BinaryFormat,
1179) -> Result<(&str, &str, macho::SectionFlags), anyhow::Error> {
1180 match binary_format {
1181 BinaryFormat::MachO => {
1183 let mut parts = section.split(',');
1184
1185 let section_err = |msg| {
1186 Err(anyhow!(
1187 "section `{section}` is not valid for Mach-O target: {msg}"
1188 ))
1189 };
1190
1191 let segment_name = parts.next().unwrap();
1192 if segment_name.len() > 16 {
1193 return section_err("segment name larger than 16 bytes");
1194 }
1195
1196 let Some(section_name) = parts.next() else {
1197 return section_err("must be segment and section separated by comma");
1198 };
1199 if section_name.len() > 16 {
1200 return section_err("section name larger than 16 bytes");
1201 }
1202
1203 let section_type = parts.next().unwrap_or("regular");
1204
1205 let mut macho_flags = if let Some((_, val)) = MACHO_SECTION_TYPES
1208 .iter()
1209 .find(|(name, _)| *name == section_type)
1210 {
1211 (*val).into()
1212 } else {
1213 let types = list_valid_values(MACHO_SECTION_TYPES);
1214 return section_err(&format!(
1215 "unsupported section type `{section_type}`, valid values are {types}"
1216 ));
1217 };
1218
1219 if let Some(section_attributes) = parts.next() {
1220 for attr in section_attributes.split('+') {
1221 macho_flags |= if let Some((_, val)) = MACHO_SECTION_ATTRIBUTES
1222 .iter()
1223 .find(|(name, _)| *name == attr)
1224 {
1225 *val
1226 } else {
1227 let attributes = list_valid_values(MACHO_SECTION_ATTRIBUTES);
1228 return section_err(&format!(
1229 "unsupported section attribute `{attr}`, valid values are {attributes}"
1230 ));
1231 };
1232 }
1233 }
1234
1235 if parts.next().is_some() {
1236 return section_err("too many components");
1237 }
1238
1239 Ok((segment_name, section_name, macho_flags))
1240 }
1241 _ => Ok(("", section, macho::S_REGULAR.into())),
1243 }
1244}
1245
1246#[rustfmt::skip]
1253const MACHO_SECTION_TYPES: &[(&str, macho::SectionType)] = {
1254 use object::macho::*;
1255 &[
1256 ("regular", S_REGULAR),
1257 ("zerofill", S_ZEROFILL),
1258 ("cstring_literals", S_CSTRING_LITERALS),
1259 ("4byte_literals", S_4BYTE_LITERALS),
1260 ("8byte_literals", S_8BYTE_LITERALS),
1261 ("literal_pointers", S_LITERAL_POINTERS),
1262 ("non_lazy_symbol_pointers", S_NON_LAZY_SYMBOL_POINTERS),
1263 ("lazy_symbol_pointers", S_LAZY_SYMBOL_POINTERS),
1264 ("mod_init_funcs", S_MOD_INIT_FUNC_POINTERS),
1266 ("mod_term_funcs", S_MOD_TERM_FUNC_POINTERS),
1267 ("coalesced", S_COALESCED),
1268 ("interposing", S_INTERPOSING),
1270 ("16byte_literals", S_16BYTE_LITERALS),
1271 ("thread_local_regular", S_THREAD_LOCAL_REGULAR),
1274 ("thread_local_zerofill", S_THREAD_LOCAL_ZEROFILL),
1275 ("thread_local_variables", S_THREAD_LOCAL_VARIABLES),
1276 ("thread_local_variable_pointers", S_THREAD_LOCAL_VARIABLE_POINTERS),
1277 ("thread_local_init_function_pointers", S_THREAD_LOCAL_INIT_FUNCTION_POINTERS),
1278 ]
1280};
1281
1282const MACHO_SECTION_ATTRIBUTES: &[(&str, macho::SectionFlags)] = {
1283 use object::macho::*;
1284 &[
1285 ("pure_instructions", S_ATTR_PURE_INSTRUCTIONS),
1286 ("no_toc", S_ATTR_NO_TOC),
1287 ("strip_static_syms", S_ATTR_STRIP_STATIC_SYMS),
1288 ("no_dead_strip", S_ATTR_NO_DEAD_STRIP),
1289 ("live_support", S_ATTR_LIVE_SUPPORT),
1290 ("self_modifying_code", S_ATTR_SELF_MODIFYING_CODE),
1291 ("debug", S_ATTR_DEBUG),
1292 ]
1297};
1298
1299fn list_valid_values<T>(items: &[(&str, T)]) -> String {
1300 let mut items = items.iter().peekable();
1301 let mut result = String::new();
1302 if let Some((item, _)) = items.next() {
1303 write!(&mut result, "`{item}`").unwrap();
1304 }
1305 while let Some((item, _)) = items.next() {
1306 if items.peek().is_none() {
1307 write!(&mut result, " and `{item}`").unwrap();
1308 } else {
1309 write!(&mut result, ", `{item}`").unwrap();
1310 }
1311 }
1312 result
1313}
1314
1315#[cfg(test)]
1316mod tests {
1317 use super::*;
1318 use object::macho::*;
1319
1320 #[test]
1321 fn section() {
1322 assert_eq!(
1323 parse_section("__DATA,__mod_init_func,mod_init_funcs", BinaryFormat::MachO).unwrap(),
1324 ("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS.into()),
1325 );
1326 assert_eq!(
1327 parse_section(
1328 "__OBJC,__module_info,regular,no_dead_strip",
1329 BinaryFormat::MachO,
1330 )
1331 .unwrap(),
1332 ("__OBJC", "__module_info", S_REGULAR | S_ATTR_NO_DEAD_STRIP),
1333 );
1334
1335 assert_eq!(
1336 parse_section("__TEXT,__text", BinaryFormat::MachO).unwrap(),
1337 ("__TEXT", "__text", S_REGULAR.into()),
1338 );
1339 assert_eq!(
1340 parse_section("__TEXT,__text,regular", BinaryFormat::MachO).unwrap(),
1341 ("__TEXT", "__text", S_REGULAR.into()),
1342 );
1343 assert_eq!(
1344 parse_section(
1345 "foo,bar,literal_pointers,no_toc+no_dead_strip",
1346 BinaryFormat::MachO
1347 )
1348 .unwrap(),
1349 (
1350 "foo",
1351 "bar",
1352 S_LITERAL_POINTERS | S_ATTR_NO_TOC | S_ATTR_NO_DEAD_STRIP
1353 ),
1354 );
1355
1356 assert!(parse_section("foo", BinaryFormat::MachO).is_err());
1357 assert!(parse_section("12345678901234567,bar", BinaryFormat::MachO).is_err());
1358 assert!(parse_section("foo,12345678901234567", BinaryFormat::MachO).is_err());
1359 assert!(parse_section("foo,bar,unknown", BinaryFormat::MachO).is_err());
1360 assert!(parse_section("foo,bar,regular,unknown", BinaryFormat::MachO).is_err());
1361 assert!(
1362 parse_section("foo,bar,regular,no_dead_strip+unknown", BinaryFormat::MachO).is_err()
1363 );
1364 assert!(
1365 parse_section("foo,bar,regular,no_dead_strip,unknown", BinaryFormat::MachO).is_err()
1366 );
1367 }
1368}