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