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