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