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;
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;
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 {} not recognized",
68                    other
69                )));
70            }
71        };
72        let architecture = match isa.triple().architecture {
73            target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
74            target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
75            target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
76            target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
77            target_lexicon::Architecture::Riscv64(_) => {
78                if binary_format != object::BinaryFormat::Elf {
79                    return Err(ModuleError::Backend(anyhow!(
80                        "binary format {:?} is not supported for riscv64",
81                        binary_format,
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 {:?} is unsupported",
109                    architecture,
110                )));
111            }
112        };
113        let endian = match isa.triple().endianness().unwrap() {
114            target_lexicon::Endianness::Little => object::Endianness::Little,
115            target_lexicon::Endianness::Big => object::Endianness::Big,
116        };
117        Ok(Self {
118            isa,
119            binary_format,
120            architecture,
121            flags: file_flags,
122            endian,
123            name: name.into(),
124            libcall_names,
125            per_function_section: false,
126            per_data_object_section: false,
127        })
128    }
129
130    /// Set if every function should end up in their own section.
131    pub fn per_function_section(&mut self, per_function_section: bool) -> &mut Self {
132        self.per_function_section = per_function_section;
133        self
134    }
135
136    /// Set if every data object should end up in their own section.
137    pub fn per_data_object_section(&mut self, per_data_object_section: bool) -> &mut Self {
138        self.per_data_object_section = per_data_object_section;
139        self
140    }
141}
142
143/// An `ObjectModule` implements `Module` and emits ".o" files using the `object` library.
144///
145/// See the `ObjectBuilder` for a convenient way to construct `ObjectModule` instances.
146pub struct ObjectModule {
147    isa: OwnedTargetIsa,
148    object: Object<'static>,
149    declarations: ModuleDeclarations,
150    functions: SecondaryMap<FuncId, Option<(SymbolId, bool)>>,
151    data_objects: SecondaryMap<DataId, Option<(SymbolId, bool)>>,
152    relocs: Vec<SymbolRelocs>,
153    libcalls: HashMap<ir::LibCall, SymbolId>,
154    libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
155    known_symbols: HashMap<ir::KnownSymbol, SymbolId>,
156    known_labels: HashMap<(FuncId, CodeOffset), SymbolId>,
157    per_function_section: bool,
158    per_data_object_section: bool,
159}
160
161impl ObjectModule {
162    /// Create a new `ObjectModule` using the given Cranelift target.
163    pub fn new(builder: ObjectBuilder) -> Self {
164        let mut object = Object::new(builder.binary_format, builder.architecture, builder.endian);
165        object.flags = builder.flags;
166        object.set_subsections_via_symbols();
167        object.add_file_symbol(builder.name);
168        Self {
169            isa: builder.isa,
170            object,
171            declarations: ModuleDeclarations::default(),
172            functions: SecondaryMap::new(),
173            data_objects: SecondaryMap::new(),
174            relocs: Vec::new(),
175            libcalls: HashMap::new(),
176            libcall_names: builder.libcall_names,
177            known_symbols: HashMap::new(),
178            known_labels: HashMap::new(),
179            per_function_section: builder.per_function_section,
180            per_data_object_section: builder.per_data_object_section,
181        }
182    }
183}
184
185fn validate_symbol(name: &str) -> ModuleResult<()> {
186    // null bytes are not allowed in symbol names and will cause the `object`
187    // crate to panic. Let's return a clean error instead.
188    if name.contains("\0") {
189        return Err(ModuleError::Backend(anyhow::anyhow!(
190            "Symbol {:?} has a null byte, which is disallowed",
191            name
192        )));
193    }
194    Ok(())
195}
196
197impl Module for ObjectModule {
198    fn isa(&self) -> &dyn TargetIsa {
199        &*self.isa
200    }
201
202    fn declarations(&self) -> &ModuleDeclarations {
203        &self.declarations
204    }
205
206    fn declare_function(
207        &mut self,
208        name: &str,
209        linkage: Linkage,
210        signature: &ir::Signature,
211    ) -> ModuleResult<FuncId> {
212        validate_symbol(name)?;
213
214        let (id, linkage) = self
215            .declarations
216            .declare_function(name, linkage, signature)?;
217
218        let (scope, weak) = translate_linkage(linkage);
219
220        if let Some((function, _defined)) = self.functions[id] {
221            let symbol = self.object.symbol_mut(function);
222            symbol.scope = scope;
223            symbol.weak = weak;
224        } else {
225            let symbol_id = self.object.add_symbol(Symbol {
226                name: name.as_bytes().to_vec(),
227                value: 0,
228                size: 0,
229                kind: SymbolKind::Text,
230                scope,
231                weak,
232                section: SymbolSection::Undefined,
233                flags: SymbolFlags::None,
234            });
235            self.functions[id] = Some((symbol_id, false));
236        }
237
238        Ok(id)
239    }
240
241    fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
242        let id = self.declarations.declare_anonymous_function(signature)?;
243
244        let symbol_id = self.object.add_symbol(Symbol {
245            name: self
246                .declarations
247                .get_function_decl(id)
248                .linkage_name(id)
249                .into_owned()
250                .into_bytes(),
251            value: 0,
252            size: 0,
253            kind: SymbolKind::Text,
254            scope: SymbolScope::Compilation,
255            weak: false,
256            section: SymbolSection::Undefined,
257            flags: SymbolFlags::None,
258        });
259        self.functions[id] = Some((symbol_id, false));
260
261        Ok(id)
262    }
263
264    fn declare_data(
265        &mut self,
266        name: &str,
267        linkage: Linkage,
268        writable: bool,
269        tls: bool,
270    ) -> ModuleResult<DataId> {
271        validate_symbol(name)?;
272
273        let (id, linkage) = self
274            .declarations
275            .declare_data(name, linkage, writable, tls)?;
276
277        // Merging declarations with conflicting values for tls is not allowed, so it is safe to use
278        // the passed in tls value here.
279        let kind = if tls {
280            SymbolKind::Tls
281        } else {
282            SymbolKind::Data
283        };
284        let (scope, weak) = translate_linkage(linkage);
285
286        if let Some((data, _defined)) = self.data_objects[id] {
287            let symbol = self.object.symbol_mut(data);
288            symbol.kind = kind;
289            symbol.scope = scope;
290            symbol.weak = weak;
291        } else {
292            let symbol_id = self.object.add_symbol(Symbol {
293                name: name.as_bytes().to_vec(),
294                value: 0,
295                size: 0,
296                kind,
297                scope,
298                weak,
299                section: SymbolSection::Undefined,
300                flags: SymbolFlags::None,
301            });
302            self.data_objects[id] = Some((symbol_id, false));
303        }
304
305        Ok(id)
306    }
307
308    fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
309        let id = self.declarations.declare_anonymous_data(writable, tls)?;
310
311        let kind = if tls {
312            SymbolKind::Tls
313        } else {
314            SymbolKind::Data
315        };
316
317        let symbol_id = self.object.add_symbol(Symbol {
318            name: self
319                .declarations
320                .get_data_decl(id)
321                .linkage_name(id)
322                .into_owned()
323                .into_bytes(),
324            value: 0,
325            size: 0,
326            kind,
327            scope: SymbolScope::Compilation,
328            weak: false,
329            section: SymbolSection::Undefined,
330            flags: SymbolFlags::None,
331        });
332        self.data_objects[id] = Some((symbol_id, false));
333
334        Ok(id)
335    }
336
337    fn define_function_with_control_plane(
338        &mut self,
339        func_id: FuncId,
340        ctx: &mut cranelift_codegen::Context,
341        ctrl_plane: &mut ControlPlane,
342    ) -> ModuleResult<()> {
343        info!("defining function {}: {}", func_id, ctx.func.display());
344
345        let res = ctx.compile(self.isa(), ctrl_plane)?;
346        let alignment = res.buffer.alignment as u64;
347
348        let buffer = &ctx.compiled_code().unwrap().buffer;
349        let relocs = buffer
350            .relocs()
351            .iter()
352            .map(|reloc| {
353                self.process_reloc(&ModuleReloc::from_mach_reloc(&reloc, &ctx.func, func_id))
354            })
355            .collect::<Vec<_>>();
356        self.define_function_inner(func_id, alignment, buffer.data(), relocs)
357    }
358
359    fn define_function_bytes(
360        &mut self,
361        func_id: FuncId,
362        alignment: u64,
363        bytes: &[u8],
364        relocs: &[ModuleReloc],
365    ) -> ModuleResult<()> {
366        let relocs = relocs
367            .iter()
368            .map(|reloc| self.process_reloc(reloc))
369            .collect();
370        self.define_function_inner(func_id, alignment, bytes, relocs)
371    }
372
373    fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> {
374        let decl = self.declarations.get_data_decl(data_id);
375        if !decl.linkage.is_definable() {
376            return Err(ModuleError::InvalidImportDefinition(
377                decl.linkage_name(data_id).into_owned(),
378            ));
379        }
380
381        let &mut (symbol, ref mut defined) = self.data_objects[data_id].as_mut().unwrap();
382        if *defined {
383            return Err(ModuleError::DuplicateDefinition(
384                decl.linkage_name(data_id).into_owned(),
385            ));
386        }
387        *defined = true;
388
389        let &DataDescription {
390            ref init,
391            function_decls: _,
392            data_decls: _,
393            function_relocs: _,
394            data_relocs: _,
395            ref custom_segment_section,
396            align,
397            used,
398        } = data;
399
400        let pointer_reloc = match self.isa.triple().pointer_width().unwrap() {
401            PointerWidth::U16 => unimplemented!("16bit pointers"),
402            PointerWidth::U32 => Reloc::Abs4,
403            PointerWidth::U64 => Reloc::Abs8,
404        };
405        let relocs = data
406            .all_relocs(pointer_reloc)
407            .map(|record| self.process_reloc(&record))
408            .collect::<Vec<_>>();
409
410        let section = if custom_segment_section.is_none() {
411            let section_kind = if let Init::Zeros { .. } = *init {
412                if decl.tls {
413                    StandardSection::UninitializedTls
414                } else {
415                    StandardSection::UninitializedData
416                }
417            } else if decl.tls {
418                StandardSection::Tls
419            } else if decl.writable {
420                StandardSection::Data
421            } else if relocs.is_empty() {
422                StandardSection::ReadOnlyData
423            } else {
424                StandardSection::ReadOnlyDataWithRel
425            };
426            if self.per_data_object_section || used {
427                // FIXME pass empty symbol name once add_subsection produces `.text` as section name
428                // instead of `.text.` when passed an empty symbol name. (object#748) Until then
429                // pass `subsection` to produce `.text.subsection` as section name to reduce
430                // confusion.
431                self.object.add_subsection(section_kind, b"subsection")
432            } else {
433                self.object.section_id(section_kind)
434            }
435        } else {
436            if decl.tls {
437                return Err(cranelift_module::ModuleError::Backend(anyhow::anyhow!(
438                    "Custom section not supported for TLS"
439                )));
440            }
441            let (seg, sec) = &custom_segment_section.as_ref().unwrap();
442            self.object.add_section(
443                seg.clone().into_bytes(),
444                sec.clone().into_bytes(),
445                if decl.writable {
446                    SectionKind::Data
447                } else if relocs.is_empty() {
448                    SectionKind::ReadOnlyData
449                } else {
450                    SectionKind::ReadOnlyDataWithRel
451                },
452            )
453        };
454
455        if used {
456            match self.object.format() {
457                object::BinaryFormat::Elf => {
458                    let section = self.object.section_mut(section);
459                    match &mut section.flags {
460                        SectionFlags::None => {
461                            // Explicitly specify default flags as SectionFlags::Elf overwrites them
462                            let sh_flags = if decl.tls {
463                                elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS
464                            } else if decl.writable || !relocs.is_empty() {
465                                elf::SHF_ALLOC | elf::SHF_WRITE
466                            } else {
467                                elf::SHF_ALLOC
468                            };
469                            section.flags = SectionFlags::Elf {
470                                sh_flags: u64::from(sh_flags | elf::SHF_GNU_RETAIN),
471                            }
472                        }
473                        SectionFlags::Elf { sh_flags } => {
474                            *sh_flags |= u64::from(elf::SHF_GNU_RETAIN)
475                        }
476                        _ => unreachable!(),
477                    }
478                }
479                object::BinaryFormat::Coff => {}
480                object::BinaryFormat::MachO => {
481                    let symbol = self.object.symbol_mut(symbol);
482                    assert!(matches!(symbol.flags, SymbolFlags::None));
483                    let n_desc = if decl.linkage == Linkage::Preemptible {
484                        object::macho::N_WEAK_DEF
485                    } else {
486                        0
487                    };
488                    symbol.flags = SymbolFlags::MachO {
489                        n_desc: n_desc | object::macho::N_NO_DEAD_STRIP,
490                    }
491                }
492                _ => unreachable!(),
493            }
494        }
495
496        let align = std::cmp::max(align.unwrap_or(1), self.isa.symbol_alignment());
497        let offset = match *init {
498            Init::Uninitialized => {
499                panic!("data is not initialized yet");
500            }
501            Init::Zeros { size } => self
502                .object
503                .add_symbol_bss(symbol, section, size as u64, align),
504            Init::Bytes { ref contents } => self
505                .object
506                .add_symbol_data(symbol, section, &contents, align),
507        };
508        if !relocs.is_empty() {
509            self.relocs.push(SymbolRelocs {
510                section,
511                offset,
512                relocs,
513            });
514        }
515        Ok(())
516    }
517}
518
519impl ObjectModule {
520    fn define_function_inner(
521        &mut self,
522        func_id: FuncId,
523        alignment: u64,
524        bytes: &[u8],
525        relocs: Vec<ObjectRelocRecord>,
526    ) -> Result<(), ModuleError> {
527        info!("defining function {func_id} with bytes");
528        let decl = self.declarations.get_function_decl(func_id);
529        let decl_name = decl.linkage_name(func_id);
530        if !decl.linkage.is_definable() {
531            return Err(ModuleError::InvalidImportDefinition(decl_name.into_owned()));
532        }
533
534        let &mut (symbol, ref mut defined) = self.functions[func_id].as_mut().unwrap();
535        if *defined {
536            return Err(ModuleError::DuplicateDefinition(decl_name.into_owned()));
537        }
538        *defined = true;
539
540        let align = alignment.max(self.isa.symbol_alignment());
541        let section = if self.per_function_section {
542            // FIXME pass empty symbol name once add_subsection produces `.text` as section name
543            // instead of `.text.` when passed an empty symbol name. (object#748) Until then pass
544            // `subsection` to produce `.text.subsection` as section name to reduce confusion.
545            self.object
546                .add_subsection(StandardSection::Text, b"subsection")
547        } else {
548            self.object.section_id(StandardSection::Text)
549        };
550        let offset = self.object.add_symbol_data(symbol, section, bytes, align);
551
552        if !relocs.is_empty() {
553            self.relocs.push(SymbolRelocs {
554                section,
555                offset,
556                relocs,
557            });
558        }
559
560        Ok(())
561    }
562
563    /// Finalize all relocations and output an object.
564    pub fn finish(mut self) -> ObjectProduct {
565        let symbol_relocs = mem::take(&mut self.relocs);
566        for symbol in symbol_relocs {
567            for &ObjectRelocRecord {
568                offset,
569                ref name,
570                flags,
571                addend,
572            } in &symbol.relocs
573            {
574                let target_symbol = self.get_symbol(name);
575                self.object
576                    .add_relocation(
577                        symbol.section,
578                        Relocation {
579                            offset: symbol.offset + u64::from(offset),
580                            flags,
581                            symbol: target_symbol,
582                            addend,
583                        },
584                    )
585                    .unwrap();
586            }
587        }
588
589        // Indicate that this object has a non-executable stack.
590        if self.object.format() == object::BinaryFormat::Elf {
591            self.object.add_section(
592                vec![],
593                ".note.GNU-stack".as_bytes().to_vec(),
594                SectionKind::Linker,
595            );
596        }
597
598        ObjectProduct {
599            object: self.object,
600            functions: self.functions,
601            data_objects: self.data_objects,
602        }
603    }
604
605    /// This should only be called during finish because it creates
606    /// symbols for missing libcalls.
607    fn get_symbol(&mut self, name: &ModuleRelocTarget) -> SymbolId {
608        match *name {
609            ModuleRelocTarget::User { .. } => {
610                if ModuleDeclarations::is_function(name) {
611                    let id = FuncId::from_name(name);
612                    self.functions[id].unwrap().0
613                } else {
614                    let id = DataId::from_name(name);
615                    self.data_objects[id].unwrap().0
616                }
617            }
618            ModuleRelocTarget::LibCall(ref libcall) => {
619                let name = (self.libcall_names)(*libcall);
620                if let Some(symbol) = self.object.symbol_id(name.as_bytes()) {
621                    symbol
622                } else if let Some(symbol) = self.libcalls.get(libcall) {
623                    *symbol
624                } else {
625                    let symbol = self.object.add_symbol(Symbol {
626                        name: name.as_bytes().to_vec(),
627                        value: 0,
628                        size: 0,
629                        kind: SymbolKind::Text,
630                        scope: SymbolScope::Unknown,
631                        weak: false,
632                        section: SymbolSection::Undefined,
633                        flags: SymbolFlags::None,
634                    });
635                    self.libcalls.insert(*libcall, symbol);
636                    symbol
637                }
638            }
639            // These are "magic" names well-known to the linker.
640            // They require special treatment.
641            ModuleRelocTarget::KnownSymbol(ref known_symbol) => {
642                if let Some(symbol) = self.known_symbols.get(known_symbol) {
643                    *symbol
644                } else {
645                    let symbol = self.object.add_symbol(match known_symbol {
646                        ir::KnownSymbol::ElfGlobalOffsetTable => Symbol {
647                            name: b"_GLOBAL_OFFSET_TABLE_".to_vec(),
648                            value: 0,
649                            size: 0,
650                            kind: SymbolKind::Data,
651                            scope: SymbolScope::Unknown,
652                            weak: false,
653                            section: SymbolSection::Undefined,
654                            flags: SymbolFlags::None,
655                        },
656                        ir::KnownSymbol::CoffTlsIndex => Symbol {
657                            name: b"_tls_index".to_vec(),
658                            value: 0,
659                            size: 32,
660                            kind: SymbolKind::Tls,
661                            scope: SymbolScope::Unknown,
662                            weak: false,
663                            section: SymbolSection::Undefined,
664                            flags: SymbolFlags::None,
665                        },
666                    });
667                    self.known_symbols.insert(*known_symbol, symbol);
668                    symbol
669                }
670            }
671
672            ModuleRelocTarget::FunctionOffset(func_id, offset) => {
673                match self.known_labels.entry((func_id, offset)) {
674                    Entry::Occupied(o) => *o.get(),
675                    Entry::Vacant(v) => {
676                        let func_symbol_id = self.functions[func_id].unwrap().0;
677                        let func_symbol = self.object.symbol(func_symbol_id);
678
679                        let name = format!(".L{}_{}", func_id.as_u32(), offset);
680                        let symbol_id = self.object.add_symbol(Symbol {
681                            name: name.as_bytes().to_vec(),
682                            value: func_symbol.value + offset as u64,
683                            size: 0,
684                            kind: SymbolKind::Label,
685                            scope: SymbolScope::Compilation,
686                            weak: false,
687                            section: SymbolSection::Section(func_symbol.section.id().unwrap()),
688                            flags: SymbolFlags::None,
689                        });
690
691                        v.insert(symbol_id);
692                        symbol_id
693                    }
694                }
695            }
696        }
697    }
698
699    fn process_reloc(&self, record: &ModuleReloc) -> ObjectRelocRecord {
700        let flags = match record.kind {
701            Reloc::Abs4 => RelocationFlags::Generic {
702                kind: RelocationKind::Absolute,
703                encoding: RelocationEncoding::Generic,
704                size: 32,
705            },
706            Reloc::Abs8 => RelocationFlags::Generic {
707                kind: RelocationKind::Absolute,
708                encoding: RelocationEncoding::Generic,
709                size: 64,
710            },
711            Reloc::X86PCRel4 => RelocationFlags::Generic {
712                kind: RelocationKind::Relative,
713                encoding: RelocationEncoding::Generic,
714                size: 32,
715            },
716            Reloc::X86CallPCRel4 => RelocationFlags::Generic {
717                kind: RelocationKind::Relative,
718                encoding: RelocationEncoding::X86Branch,
719                size: 32,
720            },
721            // TODO: Get Cranelift to tell us when we can use
722            // R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX.
723            Reloc::X86CallPLTRel4 => RelocationFlags::Generic {
724                kind: RelocationKind::PltRelative,
725                encoding: RelocationEncoding::X86Branch,
726                size: 32,
727            },
728            Reloc::X86SecRel => RelocationFlags::Generic {
729                kind: RelocationKind::SectionOffset,
730                encoding: RelocationEncoding::Generic,
731                size: 32,
732            },
733            Reloc::X86GOTPCRel4 => RelocationFlags::Generic {
734                kind: RelocationKind::GotRelative,
735                encoding: RelocationEncoding::Generic,
736                size: 32,
737            },
738            Reloc::Arm64Call => RelocationFlags::Generic {
739                kind: RelocationKind::Relative,
740                encoding: RelocationEncoding::AArch64Call,
741                size: 26,
742            },
743            Reloc::ElfX86_64TlsGd => {
744                assert_eq!(
745                    self.object.format(),
746                    object::BinaryFormat::Elf,
747                    "ElfX86_64TlsGd is not supported for this file format"
748                );
749                RelocationFlags::Elf {
750                    r_type: object::elf::R_X86_64_TLSGD,
751                }
752            }
753            Reloc::MachOX86_64Tlv => {
754                assert_eq!(
755                    self.object.format(),
756                    object::BinaryFormat::MachO,
757                    "MachOX86_64Tlv is not supported for this file format"
758                );
759                RelocationFlags::MachO {
760                    r_type: object::macho::X86_64_RELOC_TLV,
761                    r_pcrel: true,
762                    r_length: 2,
763                }
764            }
765            Reloc::MachOAarch64TlsAdrPage21 => {
766                assert_eq!(
767                    self.object.format(),
768                    object::BinaryFormat::MachO,
769                    "MachOAarch64TlsAdrPage21 is not supported for this file format"
770                );
771                RelocationFlags::MachO {
772                    r_type: object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21,
773                    r_pcrel: true,
774                    r_length: 2,
775                }
776            }
777            Reloc::MachOAarch64TlsAdrPageOff12 => {
778                assert_eq!(
779                    self.object.format(),
780                    object::BinaryFormat::MachO,
781                    "MachOAarch64TlsAdrPageOff12 is not supported for this file format"
782                );
783                RelocationFlags::MachO {
784                    r_type: object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
785                    r_pcrel: false,
786                    r_length: 2,
787                }
788            }
789            Reloc::Aarch64TlsDescAdrPage21 => {
790                assert_eq!(
791                    self.object.format(),
792                    object::BinaryFormat::Elf,
793                    "Aarch64TlsDescAdrPage21 is not supported for this file format"
794                );
795                RelocationFlags::Elf {
796                    r_type: object::elf::R_AARCH64_TLSDESC_ADR_PAGE21,
797                }
798            }
799            Reloc::Aarch64TlsDescLd64Lo12 => {
800                assert_eq!(
801                    self.object.format(),
802                    object::BinaryFormat::Elf,
803                    "Aarch64TlsDescLd64Lo12 is not supported for this file format"
804                );
805                RelocationFlags::Elf {
806                    r_type: object::elf::R_AARCH64_TLSDESC_LD64_LO12,
807                }
808            }
809            Reloc::Aarch64TlsDescAddLo12 => {
810                assert_eq!(
811                    self.object.format(),
812                    object::BinaryFormat::Elf,
813                    "Aarch64TlsDescAddLo12 is not supported for this file format"
814                );
815                RelocationFlags::Elf {
816                    r_type: object::elf::R_AARCH64_TLSDESC_ADD_LO12,
817                }
818            }
819            Reloc::Aarch64TlsDescCall => {
820                assert_eq!(
821                    self.object.format(),
822                    object::BinaryFormat::Elf,
823                    "Aarch64TlsDescCall is not supported for this file format"
824                );
825                RelocationFlags::Elf {
826                    r_type: object::elf::R_AARCH64_TLSDESC_CALL,
827                }
828            }
829
830            Reloc::Aarch64AdrGotPage21 => match self.object.format() {
831                object::BinaryFormat::Elf => RelocationFlags::Elf {
832                    r_type: object::elf::R_AARCH64_ADR_GOT_PAGE,
833                },
834                object::BinaryFormat::MachO => RelocationFlags::MachO {
835                    r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21,
836                    r_pcrel: true,
837                    r_length: 2,
838                },
839                _ => unimplemented!("Aarch64AdrGotPage21 is not supported for this file format"),
840            },
841            Reloc::Aarch64Ld64GotLo12Nc => match self.object.format() {
842                object::BinaryFormat::Elf => RelocationFlags::Elf {
843                    r_type: object::elf::R_AARCH64_LD64_GOT_LO12_NC,
844                },
845                object::BinaryFormat::MachO => RelocationFlags::MachO {
846                    r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
847                    r_pcrel: false,
848                    r_length: 2,
849                },
850                _ => unimplemented!("Aarch64Ld64GotLo12Nc is not supported for this file format"),
851            },
852            Reloc::S390xPCRel32Dbl => RelocationFlags::Generic {
853                kind: RelocationKind::Relative,
854                encoding: RelocationEncoding::S390xDbl,
855                size: 32,
856            },
857            Reloc::S390xPLTRel32Dbl => RelocationFlags::Generic {
858                kind: RelocationKind::PltRelative,
859                encoding: RelocationEncoding::S390xDbl,
860                size: 32,
861            },
862            Reloc::S390xTlsGd64 => {
863                assert_eq!(
864                    self.object.format(),
865                    object::BinaryFormat::Elf,
866                    "S390xTlsGd64 is not supported for this file format"
867                );
868                RelocationFlags::Elf {
869                    r_type: object::elf::R_390_TLS_GD64,
870                }
871            }
872            Reloc::S390xTlsGdCall => {
873                assert_eq!(
874                    self.object.format(),
875                    object::BinaryFormat::Elf,
876                    "S390xTlsGdCall is not supported for this file format"
877                );
878                RelocationFlags::Elf {
879                    r_type: object::elf::R_390_TLS_GDCALL,
880                }
881            }
882            Reloc::RiscvCallPlt => {
883                assert_eq!(
884                    self.object.format(),
885                    object::BinaryFormat::Elf,
886                    "RiscvCallPlt is not supported for this file format"
887                );
888                RelocationFlags::Elf {
889                    r_type: object::elf::R_RISCV_CALL_PLT,
890                }
891            }
892            Reloc::RiscvTlsGdHi20 => {
893                assert_eq!(
894                    self.object.format(),
895                    object::BinaryFormat::Elf,
896                    "RiscvTlsGdHi20 is not supported for this file format"
897                );
898                RelocationFlags::Elf {
899                    r_type: object::elf::R_RISCV_TLS_GD_HI20,
900                }
901            }
902            Reloc::RiscvPCRelLo12I => {
903                assert_eq!(
904                    self.object.format(),
905                    object::BinaryFormat::Elf,
906                    "RiscvPCRelLo12I is not supported for this file format"
907                );
908                RelocationFlags::Elf {
909                    r_type: object::elf::R_RISCV_PCREL_LO12_I,
910                }
911            }
912            Reloc::RiscvGotHi20 => {
913                assert_eq!(
914                    self.object.format(),
915                    object::BinaryFormat::Elf,
916                    "RiscvGotHi20 is not supported for this file format"
917                );
918                RelocationFlags::Elf {
919                    r_type: object::elf::R_RISCV_GOT_HI20,
920                }
921            }
922            // FIXME
923            reloc => unimplemented!("{:?}", reloc),
924        };
925
926        ObjectRelocRecord {
927            offset: record.offset,
928            name: record.name.clone(),
929            flags,
930            addend: record.addend,
931        }
932    }
933}
934
935fn translate_linkage(linkage: Linkage) -> (SymbolScope, bool) {
936    let scope = match linkage {
937        Linkage::Import => SymbolScope::Unknown,
938        Linkage::Local => SymbolScope::Compilation,
939        Linkage::Hidden => SymbolScope::Linkage,
940        Linkage::Export | Linkage::Preemptible => SymbolScope::Dynamic,
941    };
942    // TODO: this matches rustc_codegen_cranelift, but may be wrong.
943    let weak = linkage == Linkage::Preemptible;
944    (scope, weak)
945}
946
947/// This is the output of `ObjectModule`'s
948/// [`finish`](../struct.ObjectModule.html#method.finish) function.
949/// It contains the generated `Object` and other information produced during
950/// compilation.
951pub struct ObjectProduct {
952    /// Object artifact with all functions and data from the module defined.
953    pub object: Object<'static>,
954    /// Symbol IDs for functions (both declared and defined).
955    pub functions: SecondaryMap<FuncId, Option<(SymbolId, bool)>>,
956    /// Symbol IDs for data objects (both declared and defined).
957    pub data_objects: SecondaryMap<DataId, Option<(SymbolId, bool)>>,
958}
959
960impl ObjectProduct {
961    /// Return the `SymbolId` for the given function.
962    #[inline]
963    pub fn function_symbol(&self, id: FuncId) -> SymbolId {
964        self.functions[id].unwrap().0
965    }
966
967    /// Return the `SymbolId` for the given data object.
968    #[inline]
969    pub fn data_symbol(&self, id: DataId) -> SymbolId {
970        self.data_objects[id].unwrap().0
971    }
972
973    /// Write the object bytes in memory.
974    #[inline]
975    pub fn emit(self) -> Result<Vec<u8>, object::write::Error> {
976        self.object.write()
977    }
978}
979
980#[derive(Clone)]
981struct SymbolRelocs {
982    section: SectionId,
983    offset: u64,
984    relocs: Vec<ObjectRelocRecord>,
985}
986
987#[derive(Clone)]
988struct ObjectRelocRecord {
989    offset: CodeOffset,
990    name: ModuleRelocTarget,
991    flags: RelocationFlags,
992    addend: Addend,
993}