Skip to main content

cranelift_object/
backend.rs

1//! Defines `ObjectModule`.
2
3use 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    RelocationEncoding, RelocationFlags, RelocationKind, SectionFlags, SectionKind, SymbolFlags,
19    SymbolKind, SymbolScope, elf,
20};
21use std::collections::HashMap;
22use std::collections::hash_map::Entry;
23use std::mem;
24use target_lexicon::{PointerWidth, Triple};
25
26/// A builder for `ObjectModule`.
27pub struct ObjectBuilder {
28    isa: OwnedTargetIsa,
29    binary_format: object::BinaryFormat,
30    architecture: object::Architecture,
31    flags: object::FileFlags,
32    endian: object::Endianness,
33    name: Vec<u8>,
34    libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
35    per_function_section: bool,
36    per_data_object_section: bool,
37    #[cfg(feature = "unwind")]
38    unwind_info: bool,
39}
40
41impl ObjectBuilder {
42    /// Create a new `ObjectBuilder` using the given Cranelift target, that
43    /// can be passed to [`ObjectModule::new`].
44    ///
45    /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s [`ir::LibCall`]
46    /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain
47    /// floating point instructions, and for stack probes. If you don't know what to use for this
48    /// argument, use [`cranelift_module::default_libcall_names`].
49    pub fn new<V: Into<Vec<u8>>>(
50        isa: OwnedTargetIsa,
51        name: V,
52        libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
53    ) -> ModuleResult<Self> {
54        let mut file_flags = object::FileFlags::None;
55        let binary_format = match isa.triple().binary_format {
56            target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
57            target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
58            target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
59            target_lexicon::BinaryFormat::Wasm => {
60                return Err(ModuleError::Backend(anyhow!(
61                    "binary format wasm is unsupported",
62                )));
63            }
64            target_lexicon::BinaryFormat::Unknown => {
65                return Err(ModuleError::Backend(anyhow!("binary format is unknown")));
66            }
67            other => {
68                return Err(ModuleError::Backend(anyhow!(
69                    "binary format {other} not recognized"
70                )));
71            }
72        };
73        let architecture = match isa.triple().architecture {
74            target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
75            target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
76            target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
77            target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
78            target_lexicon::Architecture::Riscv64(_) => {
79                if binary_format != object::BinaryFormat::Elf {
80                    return Err(ModuleError::Backend(anyhow!(
81                        "binary format {binary_format:?} is not supported for riscv64",
82                    )));
83                }
84
85                // FIXME(#4994): Get the right float ABI variant from the TargetIsa
86                let mut eflags = object::elf::EF_RISCV_FLOAT_ABI_DOUBLE;
87
88                // Set the RVC eflag if we have the C extension enabled.
89                let has_c = isa
90                    .isa_flags()
91                    .iter()
92                    .filter(|f| f.name == "has_zca" || f.name == "has_zcd")
93                    .all(|f| f.as_bool().unwrap_or_default());
94                if has_c {
95                    eflags |= object::elf::EF_RISCV_RVC;
96                }
97
98                file_flags = object::FileFlags::Elf {
99                    os_abi: object::elf::ELFOSABI_NONE,
100                    abi_version: 0,
101                    e_flags: eflags,
102                };
103                object::Architecture::Riscv64
104            }
105            target_lexicon::Architecture::S390x => object::Architecture::S390x,
106            architecture => {
107                return Err(ModuleError::Backend(anyhow!(
108                    "target architecture {architecture:?} is unsupported",
109                )));
110            }
111        };
112        let endian = match isa.triple().endianness().unwrap() {
113            target_lexicon::Endianness::Little => object::Endianness::Little,
114            target_lexicon::Endianness::Big => object::Endianness::Big,
115        };
116        Ok(Self {
117            isa,
118            binary_format,
119            architecture,
120            flags: file_flags,
121            endian,
122            name: name.into(),
123            libcall_names,
124            per_function_section: false,
125            per_data_object_section: false,
126            #[cfg(feature = "unwind")]
127            unwind_info: false,
128        })
129    }
130
131    /// Set if every function should end up in their own section.
132    pub fn per_function_section(&mut self, per_function_section: bool) -> &mut Self {
133        self.per_function_section = per_function_section;
134        self
135    }
136
137    /// Set if every data object should end up in their own section.
138    pub fn per_data_object_section(&mut self, per_data_object_section: bool) -> &mut Self {
139        self.per_data_object_section = per_data_object_section;
140        self
141    }
142
143    /// Emit a DWARF `.eh_frame` section describing the unwind information for
144    /// each compiled function.
145    ///
146    /// When enabled, ELF and COFF object files gain a `.eh_frame` section
147    /// containing one Common Information Entry and one Frame Description
148    /// Entry per function, suitable for unwinding by libgcc / libunwind.
149    ///
150    /// On Windows targets cranelift emits `.pdata`/`.xdata`-style info rather
151    /// than System V FDEs, so enabling this option is a silent no-op there.
152    /// Mach-O `__TEXT,__eh_frame` emission is not yet implemented; calling
153    /// `finish` on a Mach-O target with this enabled will panic with a
154    /// descriptive error.
155    ///
156    /// Only functions defined through [`Module::define_function`] are
157    /// captured. Functions provided as pre-compiled bytes through
158    /// [`Module::define_function_bytes`] are skipped, since their unwind
159    /// information is not available to the backend.
160    ///
161    /// Requires the `unwind` feature (enabled by default). Without it this
162    /// method does not exist, mirroring `cranelift-codegen`'s gating of
163    /// `CompiledCode::create_unwind_info`.
164    ///
165    /// [`Module::define_function`]: cranelift_module::Module::define_function
166    /// [`Module::define_function_bytes`]: cranelift_module::Module::define_function_bytes
167    #[cfg(feature = "unwind")]
168    pub fn unwind_info(&mut self, unwind_info: bool) -> &mut Self {
169        self.unwind_info = unwind_info;
170        self
171    }
172}
173
174/// See the following for details:
175/// <https://github.com/rust-lang/rust/blob/1.95.0/compiler/rustc_codegen_ssa/src/back/metadata.rs#L408-L425>
176fn macho_build_version(triple: &Triple) -> Option<object::write::MachOBuildVersion> {
177    use target_lexicon::{DeploymentTarget, OperatingSystem::*};
178
179    fn pack_version(v: DeploymentTarget) -> u32 {
180        let (major, minor, patch) = (v.major as u32, v.minor as u32, v.patch as u32);
181        (major << 16) | (minor << 8) | patch
182    }
183
184    match triple.operating_system {
185        Darwin(v) | MacOSX(v) | IOS(v) | TvOS(v) | VisionOS(v) | WatchOS(v) | XROS(v) => {
186            use object::macho::*;
187            use target_lexicon::Environment::*;
188            // Same as https://github.com/rust-lang/rust/blob/1.95.0/compiler/rustc_codegen_ssa/src/back/apple.rs#L36-L50.
189            //
190            // TODO(madsmtm): Properly support simulator after
191            // https://github.com/bytecodealliance/target-lexicon/pull/130
192            let platform = match (triple.operating_system, triple.environment) {
193                // Sometimes the target is macOS but the environment is Darwin,
194                // and sometimes it's the other way around. Support both.
195                (Darwin(_), _) => PLATFORM_MACOS,
196                (MacOSX(_), _) => PLATFORM_MACOS,
197                (_, Macabi) => PLATFORM_MACCATALYST,
198                (IOS(_), Sim) => PLATFORM_IOSSIMULATOR,
199                (IOS(_), _) => PLATFORM_IOS,
200                (TvOS(_), Sim) => PLATFORM_TVOSSIMULATOR,
201                (TvOS(_), _) => PLATFORM_TVOS,
202                (VisionOS(_) | XROS(_), Sim) => PLATFORM_XROSSIMULATOR,
203                (VisionOS(_) | XROS(_), _) => PLATFORM_XROS,
204                (WatchOS(_), Sim) => PLATFORM_WATCHOSSIMULATOR,
205                (WatchOS(_), _) => PLATFORM_WATCHOS,
206                _ => {
207                    warn!("unsupported OS/environment: {triple}");
208                    0
209                }
210            };
211
212            let mut build_version = object::write::MachOBuildVersion::default();
213            build_version.platform = platform;
214
215            build_version.minos = if let Some(v) = v {
216                pack_version(v)
217            } else {
218                // The `minos` in object files is useful for diagnostics, as
219                // it tells the linker whether the file supports a given OS -
220                // if the `minos` is higher than what you're linking against,
221                // that's a signal that something has gone wrong.
222                //
223                // Using `0.0.0` here should be fine if we don't have the data
224                // available.
225                0
226            };
227
228            // Setting a 0 SDK version is fine, it's only relevant for the
229            // final linked binary.
230            build_version.sdk = 0;
231
232            Some(build_version)
233        }
234        _ => None,
235    }
236}
237
238/// An `ObjectModule` implements `Module` and emits ".o" files using the `object` library.
239///
240/// See the `ObjectBuilder` for a convenient way to construct `ObjectModule` instances.
241pub struct ObjectModule {
242    isa: OwnedTargetIsa,
243    object: Object<'static>,
244    declarations: ModuleDeclarations,
245    functions: SecondaryMap<FuncId, Option<(SymbolId, bool)>>,
246    data_objects: SecondaryMap<DataId, Option<(SymbolId, bool)>>,
247    relocs: Vec<SymbolRelocs>,
248    libcalls: HashMap<ir::LibCall, SymbolId>,
249    libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
250    known_symbols: HashMap<ir::KnownSymbol, SymbolId>,
251    known_labels: HashMap<(FuncId, CodeOffset), SymbolId>,
252    per_function_section: bool,
253    per_data_object_section: bool,
254    #[cfg(feature = "unwind")]
255    unwind: Option<crate::unwind::UnwindBuilder>,
256}
257
258impl ObjectModule {
259    /// Create a new `ObjectModule` using the given Cranelift target.
260    pub fn new(builder: ObjectBuilder) -> Self {
261        let mut object = Object::new(builder.binary_format, builder.architecture, builder.endian);
262        object.flags = builder.flags;
263        object.set_subsections_via_symbols();
264        object.add_file_symbol(builder.name);
265        if let Some(info) = macho_build_version(builder.isa.triple()) {
266            // Set LC_BUILD_VERSION.
267            //
268            // Required when linking Apple targets to avoid warning, see:
269            // https://github.com/bytecodealliance/wasmtime/issues/8730
270            object.set_macho_build_version(info);
271        }
272        #[cfg(feature = "unwind")]
273        let unwind = builder
274            .unwind_info
275            .then(|| crate::unwind::UnwindBuilder::new(builder.endian));
276        Self {
277            isa: builder.isa,
278            object,
279            declarations: ModuleDeclarations::default(),
280            functions: SecondaryMap::new(),
281            data_objects: SecondaryMap::new(),
282            relocs: Vec::new(),
283            libcalls: HashMap::new(),
284            libcall_names: builder.libcall_names,
285            known_symbols: HashMap::new(),
286            known_labels: HashMap::new(),
287            per_function_section: builder.per_function_section,
288            per_data_object_section: builder.per_data_object_section,
289            #[cfg(feature = "unwind")]
290            unwind,
291        }
292    }
293}
294
295fn validate_symbol(name: &str) -> ModuleResult<()> {
296    // null bytes are not allowed in symbol names and will cause the `object`
297    // crate to panic. Let's return a clean error instead.
298    if name.contains("\0") {
299        return Err(ModuleError::Backend(anyhow::anyhow!(
300            "Symbol {name:?} has a null byte, which is disallowed"
301        )));
302    }
303    Ok(())
304}
305
306impl Module for ObjectModule {
307    fn isa(&self) -> &dyn TargetIsa {
308        &*self.isa
309    }
310
311    fn declarations(&self) -> &ModuleDeclarations {
312        &self.declarations
313    }
314
315    fn declare_function(
316        &mut self,
317        name: &str,
318        linkage: Linkage,
319        signature: &ir::Signature,
320    ) -> ModuleResult<FuncId> {
321        validate_symbol(name)?;
322
323        let (id, linkage) = self
324            .declarations
325            .declare_function(name, linkage, signature)?;
326
327        let (scope, weak) = translate_linkage(linkage);
328
329        if let Some((function, _defined)) = self.functions[id] {
330            let symbol = self.object.symbol_mut(function);
331            symbol.scope = scope;
332            symbol.weak = weak;
333        } else {
334            let symbol_id = self.object.add_symbol(Symbol {
335                name: name.as_bytes().to_vec(),
336                value: 0,
337                size: 0,
338                kind: SymbolKind::Text,
339                scope,
340                weak,
341                section: SymbolSection::Undefined,
342                flags: SymbolFlags::None,
343            });
344            self.functions[id] = Some((symbol_id, false));
345        }
346
347        Ok(id)
348    }
349
350    fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
351        let id = self.declarations.declare_anonymous_function(signature)?;
352
353        let symbol_id = self.object.add_symbol(Symbol {
354            name: self
355                .declarations
356                .get_function_decl(id)
357                .linkage_name(id)
358                .into_owned()
359                .into_bytes(),
360            value: 0,
361            size: 0,
362            kind: SymbolKind::Text,
363            scope: SymbolScope::Compilation,
364            weak: false,
365            section: SymbolSection::Undefined,
366            flags: SymbolFlags::None,
367        });
368        self.functions[id] = Some((symbol_id, false));
369
370        Ok(id)
371    }
372
373    fn declare_data(
374        &mut self,
375        name: &str,
376        linkage: Linkage,
377        writable: bool,
378        tls: bool,
379    ) -> ModuleResult<DataId> {
380        validate_symbol(name)?;
381
382        let (id, linkage) = self
383            .declarations
384            .declare_data(name, linkage, writable, tls)?;
385
386        // Merging declarations with conflicting values for tls is not allowed, so it is safe to use
387        // the passed in tls value here.
388        let kind = if tls {
389            SymbolKind::Tls
390        } else {
391            SymbolKind::Data
392        };
393        let (scope, weak) = translate_linkage(linkage);
394
395        if let Some((data, _defined)) = self.data_objects[id] {
396            let symbol = self.object.symbol_mut(data);
397            symbol.kind = kind;
398            symbol.scope = scope;
399            symbol.weak = weak;
400        } else {
401            let symbol_id = self.object.add_symbol(Symbol {
402                name: name.as_bytes().to_vec(),
403                value: 0,
404                size: 0,
405                kind,
406                scope,
407                weak,
408                section: SymbolSection::Undefined,
409                flags: SymbolFlags::None,
410            });
411            self.data_objects[id] = Some((symbol_id, false));
412        }
413
414        Ok(id)
415    }
416
417    fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
418        let id = self.declarations.declare_anonymous_data(writable, tls)?;
419
420        let kind = if tls {
421            SymbolKind::Tls
422        } else {
423            SymbolKind::Data
424        };
425
426        let symbol_id = self.object.add_symbol(Symbol {
427            name: self
428                .declarations
429                .get_data_decl(id)
430                .linkage_name(id)
431                .into_owned()
432                .into_bytes(),
433            value: 0,
434            size: 0,
435            kind,
436            scope: SymbolScope::Compilation,
437            weak: false,
438            section: SymbolSection::Undefined,
439            flags: SymbolFlags::None,
440        });
441        self.data_objects[id] = Some((symbol_id, false));
442
443        Ok(id)
444    }
445
446    fn define_function_with_control_plane(
447        &mut self,
448        func_id: FuncId,
449        ctx: &mut cranelift_codegen::Context,
450        ctrl_plane: &mut ControlPlane,
451    ) -> ModuleResult<()> {
452        info!("defining function {}: {}", func_id, ctx.func.display());
453
454        let res = ctx.compile(self.isa(), ctrl_plane)?;
455        let alignment = res.buffer.alignment as u64;
456
457        let compiled = ctx.compiled_code().unwrap();
458        #[cfg(feature = "unwind")]
459        let unwind_info = if self.unwind.is_some() {
460            compiled.create_unwind_info(self.isa())?
461        } else {
462            None
463        };
464        let buffer = &compiled.buffer;
465        let relocs = buffer
466            .relocs()
467            .iter()
468            .map(|reloc| {
469                self.process_reloc(&ModuleReloc::from_mach_reloc(&reloc, &ctx.func, func_id))
470            })
471            .collect::<Vec<_>>();
472        self.define_function_inner(func_id, alignment, buffer.data(), relocs)?;
473        #[cfg(feature = "unwind")]
474        if let (Some(builder), Some(info)) = (self.unwind.as_mut(), unwind_info) {
475            let symbol = self.functions[func_id].unwrap().0;
476            builder.add_function(&*self.isa, symbol, info);
477        }
478        Ok(())
479    }
480
481    fn define_function_bytes(
482        &mut self,
483        func_id: FuncId,
484        alignment: u64,
485        bytes: &[u8],
486        relocs: &[ModuleReloc],
487    ) -> ModuleResult<()> {
488        let relocs = relocs
489            .iter()
490            .map(|reloc| self.process_reloc(reloc))
491            .collect();
492        self.define_function_inner(func_id, alignment, bytes, relocs)
493    }
494
495    fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> {
496        let decl = self.declarations.get_data_decl(data_id);
497        if !decl.linkage.is_definable() {
498            return Err(ModuleError::InvalidImportDefinition(
499                decl.linkage_name(data_id).into_owned(),
500            ));
501        }
502
503        let &mut (symbol, ref mut defined) = self.data_objects[data_id].as_mut().unwrap();
504        if *defined {
505            return Err(ModuleError::DuplicateDefinition(
506                decl.linkage_name(data_id).into_owned(),
507            ));
508        }
509        *defined = true;
510
511        let &DataDescription {
512            ref init,
513            function_decls: _,
514            data_decls: _,
515            function_relocs: _,
516            data_relocs: _,
517            ref custom_segment_section,
518            align,
519            used,
520        } = data;
521
522        let pointer_reloc = match self.isa.triple().pointer_width().unwrap() {
523            PointerWidth::U16 => unimplemented!("16bit pointers"),
524            PointerWidth::U32 => Reloc::Abs4,
525            PointerWidth::U64 => Reloc::Abs8,
526        };
527        let relocs = data
528            .all_relocs(pointer_reloc)
529            .map(|record| self.process_reloc(&record))
530            .collect::<Vec<_>>();
531
532        let section = if custom_segment_section.is_none() {
533            let section_kind = if let Init::Zeros { .. } = *init {
534                if decl.tls {
535                    StandardSection::UninitializedTls
536                } else {
537                    StandardSection::UninitializedData
538                }
539            } else if decl.tls {
540                StandardSection::Tls
541            } else if decl.writable {
542                StandardSection::Data
543            } else if relocs.is_empty() {
544                StandardSection::ReadOnlyData
545            } else {
546                StandardSection::ReadOnlyDataWithRel
547            };
548            if self.per_data_object_section || used {
549                // FIXME pass empty symbol name once add_subsection produces `.text` as section name
550                // instead of `.text.` when passed an empty symbol name. (object#748) Until then
551                // pass `subsection` to produce `.text.subsection` as section name to reduce
552                // confusion.
553                self.object.add_subsection(section_kind, b"subsection")
554            } else {
555                self.object.section_id(section_kind)
556            }
557        } else {
558            if decl.tls {
559                return Err(cranelift_module::ModuleError::Backend(anyhow::anyhow!(
560                    "Custom section not supported for TLS"
561                )));
562            }
563            let (seg, sec, macho_flags) = &custom_segment_section.as_ref().unwrap();
564            let section = self.object.add_section(
565                seg.clone().into_bytes(),
566                sec.clone().into_bytes(),
567                if decl.writable {
568                    SectionKind::Data
569                } else if relocs.is_empty() {
570                    SectionKind::ReadOnlyData
571                } else {
572                    SectionKind::ReadOnlyDataWithRel
573                },
574            );
575
576            match self.object.section_flags_mut(section) {
577                SectionFlags::MachO { flags } => {
578                    // There are no default flags for the `SectionKind`s that
579                    // we've specified above, so it's fine to override.
580                    //
581                    // (If we don't want to override, we'll have to be careful
582                    // with how we set these, to ensure we set the section
583                    // type properly).
584                    assert_eq!(*flags, 0);
585                    *flags = *macho_flags;
586                }
587                _ => {
588                    if *macho_flags != 0 {
589                        return Err(cranelift_module::ModuleError::Backend(anyhow::anyhow!(
590                            "unsupported Mach-O flags for this platform: {macho_flags:?}"
591                        )));
592                    }
593                }
594            }
595
596            section
597        };
598
599        if used {
600            match self.object.format() {
601                object::BinaryFormat::Elf => match self.object.section_flags_mut(section) {
602                    SectionFlags::Elf { sh_flags } => *sh_flags |= u64::from(elf::SHF_GNU_RETAIN),
603                    _ => unreachable!(),
604                },
605                object::BinaryFormat::Coff => {}
606                object::BinaryFormat::MachO => match self.object.symbol_flags_mut(symbol) {
607                    SymbolFlags::MachO { n_desc } => *n_desc |= object::macho::N_NO_DEAD_STRIP,
608                    _ => unreachable!(),
609                },
610                _ => unreachable!(),
611            }
612        }
613
614        let align = std::cmp::max(align.unwrap_or(1), self.isa.symbol_alignment());
615        let offset = match *init {
616            Init::Uninitialized => {
617                panic!("data is not initialized yet");
618            }
619            Init::Zeros { size } => self
620                .object
621                .add_symbol_bss(symbol, section, size as u64, align),
622            Init::Bytes { ref contents } => self
623                .object
624                .add_symbol_data(symbol, section, &contents, align),
625        };
626        if !relocs.is_empty() {
627            self.relocs.push(SymbolRelocs {
628                section,
629                offset,
630                relocs,
631            });
632        }
633        Ok(())
634    }
635}
636
637impl ObjectModule {
638    fn define_function_inner(
639        &mut self,
640        func_id: FuncId,
641        alignment: u64,
642        bytes: &[u8],
643        relocs: Vec<ObjectRelocRecord>,
644    ) -> Result<(), ModuleError> {
645        info!("defining function {func_id} with bytes");
646        let decl = self.declarations.get_function_decl(func_id);
647        let decl_name = decl.linkage_name(func_id);
648        if !decl.linkage.is_definable() {
649            return Err(ModuleError::InvalidImportDefinition(decl_name.into_owned()));
650        }
651
652        let &mut (symbol, ref mut defined) = self.functions[func_id].as_mut().unwrap();
653        if *defined {
654            return Err(ModuleError::DuplicateDefinition(decl_name.into_owned()));
655        }
656        *defined = true;
657
658        let align = alignment.max(self.isa.symbol_alignment());
659        let section = if self.per_function_section {
660            // FIXME pass empty symbol name once add_subsection produces `.text` as section name
661            // instead of `.text.` when passed an empty symbol name. (object#748) Until then pass
662            // `subsection` to produce `.text.subsection` as section name to reduce confusion.
663            self.object
664                .add_subsection(StandardSection::Text, b"subsection")
665        } else {
666            self.object.section_id(StandardSection::Text)
667        };
668        let offset = self.object.add_symbol_data(symbol, section, bytes, align);
669
670        if !relocs.is_empty() {
671            self.relocs.push(SymbolRelocs {
672                section,
673                offset,
674                relocs,
675            });
676        }
677
678        Ok(())
679    }
680
681    /// Finalize all relocations and output an object.
682    pub fn finish(mut self) -> ObjectProduct {
683        if cfg!(debug_assertions) {
684            for (func_id, decl) in self.declarations.get_functions() {
685                if !decl.linkage.requires_definition() {
686                    continue;
687                }
688
689                assert!(
690                    self.functions[func_id].unwrap().1,
691                    "function \"{}\" with linkage {:?} must be defined but is not",
692                    decl.linkage_name(func_id),
693                    decl.linkage,
694                );
695            }
696
697            for (data_id, decl) in self.declarations.get_data_objects() {
698                if !decl.linkage.requires_definition() {
699                    continue;
700                }
701
702                assert!(
703                    self.data_objects[data_id].unwrap().1,
704                    "data object \"{}\" with linkage {:?} must be defined but is not",
705                    decl.linkage_name(data_id),
706                    decl.linkage,
707                );
708            }
709        }
710
711        let symbol_relocs = mem::take(&mut self.relocs);
712        for symbol in symbol_relocs {
713            for &ObjectRelocRecord {
714                offset,
715                ref name,
716                flags,
717                addend,
718            } in &symbol.relocs
719            {
720                let target_symbol = self.get_symbol(name);
721                self.object
722                    .add_relocation(
723                        symbol.section,
724                        Relocation {
725                            offset: symbol.offset + u64::from(offset),
726                            flags,
727                            symbol: target_symbol,
728                            addend,
729                        },
730                    )
731                    .unwrap();
732            }
733        }
734
735        // Indicate that this object has a non-executable stack.
736        if self.object.format() == object::BinaryFormat::Elf {
737            self.object.add_section(
738                vec![],
739                ".note.GNU-stack".as_bytes().to_vec(),
740                SectionKind::Linker,
741            );
742        }
743
744        #[cfg(feature = "unwind")]
745        if let Some(unwind) = self.unwind.take() {
746            unwind
747                .finish(&mut self.object, &*self.isa)
748                .expect("failed to emit .eh_frame section");
749        }
750
751        ObjectProduct {
752            object: self.object,
753            functions: self.functions,
754            data_objects: self.data_objects,
755        }
756    }
757
758    /// This should only be called during finish because it creates
759    /// symbols for missing libcalls.
760    fn get_symbol(&mut self, name: &ModuleRelocTarget) -> SymbolId {
761        match *name {
762            ModuleRelocTarget::User { .. } => {
763                if ModuleDeclarations::is_function(name) {
764                    let id = FuncId::from_name(name);
765                    self.functions[id].unwrap().0
766                } else {
767                    let id = DataId::from_name(name);
768                    self.data_objects[id].unwrap().0
769                }
770            }
771            ModuleRelocTarget::LibCall(ref libcall) => {
772                let name = (self.libcall_names)(*libcall);
773                if let Some(symbol) = self.object.symbol_id(name.as_bytes()) {
774                    symbol
775                } else if let Some(symbol) = self.libcalls.get(libcall) {
776                    *symbol
777                } else {
778                    let symbol = self.object.add_symbol(Symbol {
779                        name: name.as_bytes().to_vec(),
780                        value: 0,
781                        size: 0,
782                        kind: SymbolKind::Text,
783                        scope: SymbolScope::Unknown,
784                        weak: false,
785                        section: SymbolSection::Undefined,
786                        flags: SymbolFlags::None,
787                    });
788                    self.libcalls.insert(*libcall, symbol);
789                    symbol
790                }
791            }
792            // These are "magic" names well-known to the linker.
793            // They require special treatment.
794            ModuleRelocTarget::KnownSymbol(ref known_symbol) => {
795                if let Some(symbol) = self.known_symbols.get(known_symbol) {
796                    *symbol
797                } else {
798                    let symbol = self.object.add_symbol(match known_symbol {
799                        ir::KnownSymbol::ElfGlobalOffsetTable => Symbol {
800                            name: b"_GLOBAL_OFFSET_TABLE_".to_vec(),
801                            value: 0,
802                            size: 0,
803                            kind: SymbolKind::Data,
804                            scope: SymbolScope::Unknown,
805                            weak: false,
806                            section: SymbolSection::Undefined,
807                            flags: SymbolFlags::None,
808                        },
809                        ir::KnownSymbol::CoffTlsIndex => Symbol {
810                            name: b"_tls_index".to_vec(),
811                            value: 0,
812                            size: 32,
813                            kind: SymbolKind::Tls,
814                            scope: SymbolScope::Unknown,
815                            weak: false,
816                            section: SymbolSection::Undefined,
817                            flags: SymbolFlags::None,
818                        },
819                    });
820                    self.known_symbols.insert(*known_symbol, symbol);
821                    symbol
822                }
823            }
824
825            ModuleRelocTarget::FunctionOffset(func_id, offset) => {
826                match self.known_labels.entry((func_id, offset)) {
827                    Entry::Occupied(o) => *o.get(),
828                    Entry::Vacant(v) => {
829                        let func_symbol_id = self.functions[func_id].unwrap().0;
830                        let func_symbol = self.object.symbol(func_symbol_id);
831
832                        let name = format!(".L{}_{}", func_id.as_u32(), offset);
833                        let symbol_id = self.object.add_symbol(Symbol {
834                            name: name.as_bytes().to_vec(),
835                            value: func_symbol.value + offset as u64,
836                            size: 0,
837                            kind: SymbolKind::Label,
838                            scope: SymbolScope::Compilation,
839                            weak: false,
840                            section: SymbolSection::Section(func_symbol.section.id().unwrap()),
841                            flags: SymbolFlags::None,
842                        });
843
844                        v.insert(symbol_id);
845                        symbol_id
846                    }
847                }
848            }
849        }
850    }
851
852    fn process_reloc(&self, record: &ModuleReloc) -> ObjectRelocRecord {
853        let flags = match record.kind {
854            Reloc::Abs4 => RelocationFlags::Generic {
855                kind: RelocationKind::Absolute,
856                encoding: RelocationEncoding::Generic,
857                size: 32,
858            },
859            Reloc::Abs8 => RelocationFlags::Generic {
860                kind: RelocationKind::Absolute,
861                encoding: RelocationEncoding::Generic,
862                size: 64,
863            },
864            Reloc::X86PCRel4 => RelocationFlags::Generic {
865                kind: RelocationKind::Relative,
866                encoding: RelocationEncoding::Generic,
867                size: 32,
868            },
869            Reloc::X86CallPCRel4 => RelocationFlags::Generic {
870                kind: RelocationKind::Relative,
871                encoding: RelocationEncoding::X86Branch,
872                size: 32,
873            },
874            // TODO: Get Cranelift to tell us when we can use
875            // R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX.
876            Reloc::X86CallPLTRel4 => RelocationFlags::Generic {
877                kind: RelocationKind::PltRelative,
878                encoding: RelocationEncoding::X86Branch,
879                size: 32,
880            },
881            Reloc::X86SecRel => RelocationFlags::Generic {
882                kind: RelocationKind::SectionOffset,
883                encoding: RelocationEncoding::Generic,
884                size: 32,
885            },
886            Reloc::X86GOTPCRel4 => RelocationFlags::Generic {
887                kind: RelocationKind::GotRelative,
888                encoding: RelocationEncoding::Generic,
889                size: 32,
890            },
891            Reloc::Arm64Call => RelocationFlags::Generic {
892                kind: RelocationKind::Relative,
893                encoding: RelocationEncoding::AArch64Call,
894                size: 26,
895            },
896            Reloc::ElfX86_64TlsGd => {
897                assert_eq!(
898                    self.object.format(),
899                    object::BinaryFormat::Elf,
900                    "ElfX86_64TlsGd is not supported for this file format"
901                );
902                RelocationFlags::Elf {
903                    r_type: object::elf::R_X86_64_TLSGD,
904                }
905            }
906            Reloc::MachOX86_64Tlv => {
907                assert_eq!(
908                    self.object.format(),
909                    object::BinaryFormat::MachO,
910                    "MachOX86_64Tlv is not supported for this file format"
911                );
912                RelocationFlags::MachO {
913                    r_type: object::macho::X86_64_RELOC_TLV,
914                    r_pcrel: true,
915                    r_length: 2,
916                }
917            }
918            Reloc::MachOAarch64TlsAdrPage21 => {
919                assert_eq!(
920                    self.object.format(),
921                    object::BinaryFormat::MachO,
922                    "MachOAarch64TlsAdrPage21 is not supported for this file format"
923                );
924                RelocationFlags::MachO {
925                    r_type: object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21,
926                    r_pcrel: true,
927                    r_length: 2,
928                }
929            }
930            Reloc::MachOAarch64TlsAdrPageOff12 => {
931                assert_eq!(
932                    self.object.format(),
933                    object::BinaryFormat::MachO,
934                    "MachOAarch64TlsAdrPageOff12 is not supported for this file format"
935                );
936                RelocationFlags::MachO {
937                    r_type: object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
938                    r_pcrel: false,
939                    r_length: 2,
940                }
941            }
942            Reloc::Aarch64TlsDescAdrPage21 => {
943                assert_eq!(
944                    self.object.format(),
945                    object::BinaryFormat::Elf,
946                    "Aarch64TlsDescAdrPage21 is not supported for this file format"
947                );
948                RelocationFlags::Elf {
949                    r_type: object::elf::R_AARCH64_TLSDESC_ADR_PAGE21,
950                }
951            }
952            Reloc::Aarch64TlsDescLd64Lo12 => {
953                assert_eq!(
954                    self.object.format(),
955                    object::BinaryFormat::Elf,
956                    "Aarch64TlsDescLd64Lo12 is not supported for this file format"
957                );
958                RelocationFlags::Elf {
959                    r_type: object::elf::R_AARCH64_TLSDESC_LD64_LO12,
960                }
961            }
962            Reloc::Aarch64TlsDescAddLo12 => {
963                assert_eq!(
964                    self.object.format(),
965                    object::BinaryFormat::Elf,
966                    "Aarch64TlsDescAddLo12 is not supported for this file format"
967                );
968                RelocationFlags::Elf {
969                    r_type: object::elf::R_AARCH64_TLSDESC_ADD_LO12,
970                }
971            }
972            Reloc::Aarch64TlsDescCall => {
973                assert_eq!(
974                    self.object.format(),
975                    object::BinaryFormat::Elf,
976                    "Aarch64TlsDescCall is not supported for this file format"
977                );
978                RelocationFlags::Elf {
979                    r_type: object::elf::R_AARCH64_TLSDESC_CALL,
980                }
981            }
982
983            Reloc::Aarch64AdrGotPage21 => match self.object.format() {
984                object::BinaryFormat::Elf => RelocationFlags::Elf {
985                    r_type: object::elf::R_AARCH64_ADR_GOT_PAGE,
986                },
987                object::BinaryFormat::MachO => RelocationFlags::MachO {
988                    r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21,
989                    r_pcrel: true,
990                    r_length: 2,
991                },
992                _ => unimplemented!("Aarch64AdrGotPage21 is not supported for this file format"),
993            },
994            Reloc::Aarch64Ld64GotLo12Nc => match self.object.format() {
995                object::BinaryFormat::Elf => RelocationFlags::Elf {
996                    r_type: object::elf::R_AARCH64_LD64_GOT_LO12_NC,
997                },
998                object::BinaryFormat::MachO => RelocationFlags::MachO {
999                    r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
1000                    r_pcrel: false,
1001                    r_length: 2,
1002                },
1003                _ => unimplemented!("Aarch64Ld64GotLo12Nc is not supported for this file format"),
1004            },
1005            Reloc::Aarch64AdrPrelPgHi21 => match self.object.format() {
1006                object::BinaryFormat::Elf => RelocationFlags::Elf {
1007                    r_type: object::elf::R_AARCH64_ADR_PREL_PG_HI21,
1008                },
1009                object::BinaryFormat::MachO => RelocationFlags::MachO {
1010                    r_type: object::macho::ARM64_RELOC_PAGE21,
1011                    r_pcrel: true,
1012                    r_length: 2,
1013                },
1014                _ => unimplemented!("Aarch64AdrPrelPgHi21 is not supported for this file format"),
1015            },
1016            Reloc::Aarch64AddAbsLo12Nc => match self.object.format() {
1017                object::BinaryFormat::Elf => RelocationFlags::Elf {
1018                    r_type: object::elf::R_AARCH64_ADD_ABS_LO12_NC,
1019                },
1020                object::BinaryFormat::MachO => RelocationFlags::MachO {
1021                    r_type: object::macho::ARM64_RELOC_PAGEOFF12,
1022                    r_pcrel: false,
1023                    r_length: 2,
1024                },
1025                _ => unimplemented!("Aarch64AddAbsLo12Nc is not supported for this file format"),
1026            },
1027            Reloc::S390xPCRel32Dbl => RelocationFlags::Generic {
1028                kind: RelocationKind::Relative,
1029                encoding: RelocationEncoding::S390xDbl,
1030                size: 32,
1031            },
1032            Reloc::S390xPLTRel32Dbl => RelocationFlags::Generic {
1033                kind: RelocationKind::PltRelative,
1034                encoding: RelocationEncoding::S390xDbl,
1035                size: 32,
1036            },
1037            Reloc::S390xTlsGd64 => {
1038                assert_eq!(
1039                    self.object.format(),
1040                    object::BinaryFormat::Elf,
1041                    "S390xTlsGd64 is not supported for this file format"
1042                );
1043                RelocationFlags::Elf {
1044                    r_type: object::elf::R_390_TLS_GD64,
1045                }
1046            }
1047            Reloc::S390xTlsGdCall => {
1048                assert_eq!(
1049                    self.object.format(),
1050                    object::BinaryFormat::Elf,
1051                    "S390xTlsGdCall is not supported for this file format"
1052                );
1053                RelocationFlags::Elf {
1054                    r_type: object::elf::R_390_TLS_GDCALL,
1055                }
1056            }
1057            Reloc::RiscvCallPlt => {
1058                assert_eq!(
1059                    self.object.format(),
1060                    object::BinaryFormat::Elf,
1061                    "RiscvCallPlt is not supported for this file format"
1062                );
1063                RelocationFlags::Elf {
1064                    r_type: object::elf::R_RISCV_CALL_PLT,
1065                }
1066            }
1067            Reloc::RiscvTlsGdHi20 => {
1068                assert_eq!(
1069                    self.object.format(),
1070                    object::BinaryFormat::Elf,
1071                    "RiscvTlsGdHi20 is not supported for this file format"
1072                );
1073                RelocationFlags::Elf {
1074                    r_type: object::elf::R_RISCV_TLS_GD_HI20,
1075                }
1076            }
1077            Reloc::RiscvPCRelLo12I => {
1078                assert_eq!(
1079                    self.object.format(),
1080                    object::BinaryFormat::Elf,
1081                    "RiscvPCRelLo12I is not supported for this file format"
1082                );
1083                RelocationFlags::Elf {
1084                    r_type: object::elf::R_RISCV_PCREL_LO12_I,
1085                }
1086            }
1087            Reloc::RiscvGotHi20 => {
1088                assert_eq!(
1089                    self.object.format(),
1090                    object::BinaryFormat::Elf,
1091                    "RiscvGotHi20 is not supported for this file format"
1092                );
1093                RelocationFlags::Elf {
1094                    r_type: object::elf::R_RISCV_GOT_HI20,
1095                }
1096            }
1097            Reloc::RiscvPCRelHi20 => {
1098                assert_eq!(
1099                    self.object.format(),
1100                    object::BinaryFormat::Elf,
1101                    "RiscvPCRelHi20 is not supported for this file format"
1102                );
1103                RelocationFlags::Elf {
1104                    r_type: object::elf::R_RISCV_PCREL_HI20,
1105                }
1106            }
1107            // FIXME
1108            reloc => unimplemented!("{:?}", reloc),
1109        };
1110
1111        ObjectRelocRecord {
1112            offset: record.offset,
1113            name: record.name.clone(),
1114            flags,
1115            addend: record.addend,
1116        }
1117    }
1118}
1119
1120fn translate_linkage(linkage: Linkage) -> (SymbolScope, bool) {
1121    let scope = match linkage {
1122        Linkage::Import => SymbolScope::Unknown,
1123        Linkage::Local => SymbolScope::Compilation,
1124        Linkage::Hidden => SymbolScope::Linkage,
1125        Linkage::Export | Linkage::Preemptible => SymbolScope::Dynamic,
1126    };
1127    // TODO: this matches rustc_codegen_cranelift, but may be wrong.
1128    let weak = linkage == Linkage::Preemptible;
1129    (scope, weak)
1130}
1131
1132/// This is the output of `ObjectModule`'s
1133/// [`finish`](../struct.ObjectModule.html#method.finish) function.
1134/// It contains the generated `Object` and other information produced during
1135/// compilation.
1136pub struct ObjectProduct {
1137    /// Object artifact with all functions and data from the module defined.
1138    pub object: Object<'static>,
1139    /// Symbol IDs for functions (both declared and defined).
1140    pub functions: SecondaryMap<FuncId, Option<(SymbolId, bool)>>,
1141    /// Symbol IDs for data objects (both declared and defined).
1142    pub data_objects: SecondaryMap<DataId, Option<(SymbolId, bool)>>,
1143}
1144
1145impl ObjectProduct {
1146    /// Return the `SymbolId` for the given function.
1147    #[inline]
1148    pub fn function_symbol(&self, id: FuncId) -> SymbolId {
1149        self.functions[id].unwrap().0
1150    }
1151
1152    /// Return the `SymbolId` for the given data object.
1153    #[inline]
1154    pub fn data_symbol(&self, id: DataId) -> SymbolId {
1155        self.data_objects[id].unwrap().0
1156    }
1157
1158    /// Write the object bytes in memory.
1159    #[inline]
1160    pub fn emit(self) -> Result<Vec<u8>, object::write::Error> {
1161        self.object.write()
1162    }
1163}
1164
1165#[derive(Clone)]
1166struct SymbolRelocs {
1167    section: SectionId,
1168    offset: u64,
1169    relocs: Vec<ObjectRelocRecord>,
1170}
1171
1172#[derive(Clone)]
1173struct ObjectRelocRecord {
1174    offset: CodeOffset,
1175    name: ModuleRelocTarget,
1176    flags: RelocationFlags,
1177    addend: Addend,
1178}