//! Defines `ObjectModule`. use anyhow::anyhow; use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc}; use cranelift_codegen::entity::SecondaryMap; use cranelift_codegen::ir; use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa}; use cranelift_control::ControlPlane; use cranelift_module::{ DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleDeclarations, ModuleError, ModuleReloc, ModuleRelocTarget, ModuleResult, }; use log::info; use object::write::{ Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection, }; use object::{ RelocationEncoding, RelocationFlags, RelocationKind, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, elf, }; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::mem; use target_lexicon::PointerWidth; /// A builder for `ObjectModule`. pub struct ObjectBuilder { isa: OwnedTargetIsa, binary_format: object::BinaryFormat, architecture: object::Architecture, flags: object::FileFlags, endian: object::Endianness, name: Vec, libcall_names: Box String + Send + Sync>, per_function_section: bool, per_data_object_section: bool, } impl ObjectBuilder { /// Create a new `ObjectBuilder` using the given Cranelift target, that /// can be passed to [`ObjectModule::new`]. /// /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s [`ir::LibCall`] /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain /// floating point instructions, and for stack probes. If you don't know what to use for this /// argument, use [`cranelift_module::default_libcall_names`]. pub fn new>>( isa: OwnedTargetIsa, name: V, libcall_names: Box String + Send + Sync>, ) -> ModuleResult { let mut file_flags = object::FileFlags::None; let binary_format = match isa.triple().binary_format { target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf, target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff, target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO, target_lexicon::BinaryFormat::Wasm => { return Err(ModuleError::Backend(anyhow!( "binary format wasm is unsupported", ))); } target_lexicon::BinaryFormat::Unknown => { return Err(ModuleError::Backend(anyhow!("binary format is unknown"))); } other => { return Err(ModuleError::Backend(anyhow!( "binary format {other} not recognized" ))); } }; let architecture = match isa.triple().architecture { target_lexicon::Architecture::X86_32(_) => object::Architecture::I386, target_lexicon::Architecture::X86_64 => object::Architecture::X86_64, target_lexicon::Architecture::Arm(_) => object::Architecture::Arm, target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64, target_lexicon::Architecture::Riscv64(_) => { if binary_format != object::BinaryFormat::Elf { return Err(ModuleError::Backend(anyhow!( "binary format {binary_format:?} is not supported for riscv64", ))); } // FIXME(#4994): Get the right float ABI variant from the TargetIsa let mut eflags = object::elf::EF_RISCV_FLOAT_ABI_DOUBLE; // Set the RVC eflag if we have the C extension enabled. let has_c = isa .isa_flags() .iter() .filter(|f| f.name == "has_zca" || f.name == "has_zcd") .all(|f| f.as_bool().unwrap_or_default()); if has_c { eflags |= object::elf::EF_RISCV_RVC; } file_flags = object::FileFlags::Elf { os_abi: object::elf::ELFOSABI_NONE, abi_version: 0, e_flags: eflags, }; object::Architecture::Riscv64 } target_lexicon::Architecture::S390x => object::Architecture::S390x, architecture => { return Err(ModuleError::Backend(anyhow!( "target architecture {architecture:?} is unsupported", ))); } }; let endian = match isa.triple().endianness().unwrap() { target_lexicon::Endianness::Little => object::Endianness::Little, target_lexicon::Endianness::Big => object::Endianness::Big, }; Ok(Self { isa, binary_format, architecture, flags: file_flags, endian, name: name.into(), libcall_names, per_function_section: false, per_data_object_section: false, }) } /// Set if every function should end up in their own section. pub fn per_function_section(&mut self, per_function_section: bool) -> &mut Self { self.per_function_section = per_function_section; self } /// Set if every data object should end up in their own section. pub fn per_data_object_section(&mut self, per_data_object_section: bool) -> &mut Self { self.per_data_object_section = per_data_object_section; self } } /// An `ObjectModule` implements `Module` and emits ".o" files using the `object` library. /// /// See the `ObjectBuilder` for a convenient way to construct `ObjectModule` instances. pub struct ObjectModule { isa: OwnedTargetIsa, object: Object<'static>, declarations: ModuleDeclarations, functions: SecondaryMap>, data_objects: SecondaryMap>, relocs: Vec, libcalls: HashMap, libcall_names: Box String + Send + Sync>, known_symbols: HashMap, known_labels: HashMap<(FuncId, CodeOffset), SymbolId>, per_function_section: bool, per_data_object_section: bool, } impl ObjectModule { /// Create a new `ObjectModule` using the given Cranelift target. pub fn new(builder: ObjectBuilder) -> Self { let mut object = Object::new(builder.binary_format, builder.architecture, builder.endian); object.flags = builder.flags; object.set_subsections_via_symbols(); object.add_file_symbol(builder.name); Self { isa: builder.isa, object, declarations: ModuleDeclarations::default(), functions: SecondaryMap::new(), data_objects: SecondaryMap::new(), relocs: Vec::new(), libcalls: HashMap::new(), libcall_names: builder.libcall_names, known_symbols: HashMap::new(), known_labels: HashMap::new(), per_function_section: builder.per_function_section, per_data_object_section: builder.per_data_object_section, } } } fn validate_symbol(name: &str) -> ModuleResult<()> { // null bytes are not allowed in symbol names and will cause the `object` // crate to panic. Let's return a clean error instead. if name.contains("\0") { return Err(ModuleError::Backend(anyhow::anyhow!( "Symbol {name:?} has a null byte, which is disallowed" ))); } Ok(()) } impl Module for ObjectModule { fn isa(&self) -> &dyn TargetIsa { &*self.isa } fn declarations(&self) -> &ModuleDeclarations { &self.declarations } fn declare_function( &mut self, name: &str, linkage: Linkage, signature: &ir::Signature, ) -> ModuleResult { validate_symbol(name)?; let (id, linkage) = self .declarations .declare_function(name, linkage, signature)?; let (scope, weak) = translate_linkage(linkage); if let Some((function, _defined)) = self.functions[id] { let symbol = self.object.symbol_mut(function); symbol.scope = scope; symbol.weak = weak; } else { let symbol_id = self.object.add_symbol(Symbol { name: name.as_bytes().to_vec(), value: 0, size: 0, kind: SymbolKind::Text, scope, weak, section: SymbolSection::Undefined, flags: SymbolFlags::None, }); self.functions[id] = Some((symbol_id, false)); } Ok(id) } fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult { let id = self.declarations.declare_anonymous_function(signature)?; let symbol_id = self.object.add_symbol(Symbol { name: self .declarations .get_function_decl(id) .linkage_name(id) .into_owned() .into_bytes(), value: 0, size: 0, kind: SymbolKind::Text, scope: SymbolScope::Compilation, weak: false, section: SymbolSection::Undefined, flags: SymbolFlags::None, }); self.functions[id] = Some((symbol_id, false)); Ok(id) } fn declare_data( &mut self, name: &str, linkage: Linkage, writable: bool, tls: bool, ) -> ModuleResult { validate_symbol(name)?; let (id, linkage) = self .declarations .declare_data(name, linkage, writable, tls)?; // Merging declarations with conflicting values for tls is not allowed, so it is safe to use // the passed in tls value here. let kind = if tls { SymbolKind::Tls } else { SymbolKind::Data }; let (scope, weak) = translate_linkage(linkage); if let Some((data, _defined)) = self.data_objects[id] { let symbol = self.object.symbol_mut(data); symbol.kind = kind; symbol.scope = scope; symbol.weak = weak; } else { let symbol_id = self.object.add_symbol(Symbol { name: name.as_bytes().to_vec(), value: 0, size: 0, kind, scope, weak, section: SymbolSection::Undefined, flags: SymbolFlags::None, }); self.data_objects[id] = Some((symbol_id, false)); } Ok(id) } fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult { let id = self.declarations.declare_anonymous_data(writable, tls)?; let kind = if tls { SymbolKind::Tls } else { SymbolKind::Data }; let symbol_id = self.object.add_symbol(Symbol { name: self .declarations .get_data_decl(id) .linkage_name(id) .into_owned() .into_bytes(), value: 0, size: 0, kind, scope: SymbolScope::Compilation, weak: false, section: SymbolSection::Undefined, flags: SymbolFlags::None, }); self.data_objects[id] = Some((symbol_id, false)); Ok(id) } fn define_function_with_control_plane( &mut self, func_id: FuncId, ctx: &mut cranelift_codegen::Context, ctrl_plane: &mut ControlPlane, ) -> ModuleResult<()> { info!("defining function {}: {}", func_id, ctx.func.display()); let res = ctx.compile(self.isa(), ctrl_plane)?; let alignment = res.buffer.alignment as u64; let buffer = &ctx.compiled_code().unwrap().buffer; let relocs = buffer .relocs() .iter() .map(|reloc| { self.process_reloc(&ModuleReloc::from_mach_reloc(&reloc, &ctx.func, func_id)) }) .collect::>(); self.define_function_inner(func_id, alignment, buffer.data(), relocs) } fn define_function_bytes( &mut self, func_id: FuncId, alignment: u64, bytes: &[u8], relocs: &[ModuleReloc], ) -> ModuleResult<()> { let relocs = relocs .iter() .map(|reloc| self.process_reloc(reloc)) .collect(); self.define_function_inner(func_id, alignment, bytes, relocs) } fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> { let decl = self.declarations.get_data_decl(data_id); if !decl.linkage.is_definable() { return Err(ModuleError::InvalidImportDefinition( decl.linkage_name(data_id).into_owned(), )); } let &mut (symbol, ref mut defined) = self.data_objects[data_id].as_mut().unwrap(); if *defined { return Err(ModuleError::DuplicateDefinition( decl.linkage_name(data_id).into_owned(), )); } *defined = true; let &DataDescription { ref init, function_decls: _, data_decls: _, function_relocs: _, data_relocs: _, ref custom_segment_section, align, used, } = data; let pointer_reloc = match self.isa.triple().pointer_width().unwrap() { PointerWidth::U16 => unimplemented!("16bit pointers"), PointerWidth::U32 => Reloc::Abs4, PointerWidth::U64 => Reloc::Abs8, }; let relocs = data .all_relocs(pointer_reloc) .map(|record| self.process_reloc(&record)) .collect::>(); let section = if custom_segment_section.is_none() { let section_kind = if let Init::Zeros { .. } = *init { if decl.tls { StandardSection::UninitializedTls } else { StandardSection::UninitializedData } } else if decl.tls { StandardSection::Tls } else if decl.writable { StandardSection::Data } else if relocs.is_empty() { StandardSection::ReadOnlyData } else { StandardSection::ReadOnlyDataWithRel }; if self.per_data_object_section || used { // FIXME pass empty symbol name once add_subsection produces `.text` as section name // instead of `.text.` when passed an empty symbol name. (object#748) Until then // pass `subsection` to produce `.text.subsection` as section name to reduce // confusion. self.object.add_subsection(section_kind, b"subsection") } else { self.object.section_id(section_kind) } } else { if decl.tls { return Err(cranelift_module::ModuleError::Backend(anyhow::anyhow!( "Custom section not supported for TLS" ))); } let (seg, sec) = &custom_segment_section.as_ref().unwrap(); self.object.add_section( seg.clone().into_bytes(), sec.clone().into_bytes(), if decl.writable { SectionKind::Data } else if relocs.is_empty() { SectionKind::ReadOnlyData } else { SectionKind::ReadOnlyDataWithRel }, ) }; if used { match self.object.format() { object::BinaryFormat::Elf => match self.object.section_flags_mut(section) { SectionFlags::Elf { sh_flags } => *sh_flags |= u64::from(elf::SHF_GNU_RETAIN), _ => unreachable!(), }, object::BinaryFormat::Coff => {} object::BinaryFormat::MachO => match self.object.symbol_flags_mut(symbol) { SymbolFlags::MachO { n_desc } => *n_desc |= object::macho::N_NO_DEAD_STRIP, _ => unreachable!(), }, _ => unreachable!(), } } let align = std::cmp::max(align.unwrap_or(1), self.isa.symbol_alignment()); let offset = match *init { Init::Uninitialized => { panic!("data is not initialized yet"); } Init::Zeros { size } => self .object .add_symbol_bss(symbol, section, size as u64, align), Init::Bytes { ref contents } => self .object .add_symbol_data(symbol, section, &contents, align), }; if !relocs.is_empty() { self.relocs.push(SymbolRelocs { section, offset, relocs, }); } Ok(()) } } impl ObjectModule { fn define_function_inner( &mut self, func_id: FuncId, alignment: u64, bytes: &[u8], relocs: Vec, ) -> Result<(), ModuleError> { info!("defining function {func_id} with bytes"); let decl = self.declarations.get_function_decl(func_id); let decl_name = decl.linkage_name(func_id); if !decl.linkage.is_definable() { return Err(ModuleError::InvalidImportDefinition(decl_name.into_owned())); } let &mut (symbol, ref mut defined) = self.functions[func_id].as_mut().unwrap(); if *defined { return Err(ModuleError::DuplicateDefinition(decl_name.into_owned())); } *defined = true; let align = alignment.max(self.isa.symbol_alignment()); let section = if self.per_function_section { // FIXME pass empty symbol name once add_subsection produces `.text` as section name // instead of `.text.` when passed an empty symbol name. (object#748) Until then pass // `subsection` to produce `.text.subsection` as section name to reduce confusion. self.object .add_subsection(StandardSection::Text, b"subsection") } else { self.object.section_id(StandardSection::Text) }; let offset = self.object.add_symbol_data(symbol, section, bytes, align); if !relocs.is_empty() { self.relocs.push(SymbolRelocs { section, offset, relocs, }); } Ok(()) } /// Finalize all relocations and output an object. pub fn finish(mut self) -> ObjectProduct { if cfg!(debug_assertions) { for (func_id, decl) in self.declarations.get_functions() { if !decl.linkage.requires_definition() { continue; } assert!( self.functions[func_id].unwrap().1, "function \"{}\" with linkage {:?} must be defined but is not", decl.linkage_name(func_id), decl.linkage, ); } for (data_id, decl) in self.declarations.get_data_objects() { if !decl.linkage.requires_definition() { continue; } assert!( self.data_objects[data_id].unwrap().1, "data object \"{}\" with linkage {:?} must be defined but is not", decl.linkage_name(data_id), decl.linkage, ); } } let symbol_relocs = mem::take(&mut self.relocs); for symbol in symbol_relocs { for &ObjectRelocRecord { offset, ref name, flags, addend, } in &symbol.relocs { let target_symbol = self.get_symbol(name); self.object .add_relocation( symbol.section, Relocation { offset: symbol.offset + u64::from(offset), flags, symbol: target_symbol, addend, }, ) .unwrap(); } } // Indicate that this object has a non-executable stack. if self.object.format() == object::BinaryFormat::Elf { self.object.add_section( vec![], ".note.GNU-stack".as_bytes().to_vec(), SectionKind::Linker, ); } ObjectProduct { object: self.object, functions: self.functions, data_objects: self.data_objects, } } /// This should only be called during finish because it creates /// symbols for missing libcalls. fn get_symbol(&mut self, name: &ModuleRelocTarget) -> SymbolId { match *name { ModuleRelocTarget::User { .. } => { if ModuleDeclarations::is_function(name) { let id = FuncId::from_name(name); self.functions[id].unwrap().0 } else { let id = DataId::from_name(name); self.data_objects[id].unwrap().0 } } ModuleRelocTarget::LibCall(ref libcall) => { let name = (self.libcall_names)(*libcall); if let Some(symbol) = self.object.symbol_id(name.as_bytes()) { symbol } else if let Some(symbol) = self.libcalls.get(libcall) { *symbol } else { let symbol = self.object.add_symbol(Symbol { name: name.as_bytes().to_vec(), value: 0, size: 0, kind: SymbolKind::Text, scope: SymbolScope::Unknown, weak: false, section: SymbolSection::Undefined, flags: SymbolFlags::None, }); self.libcalls.insert(*libcall, symbol); symbol } } // These are "magic" names well-known to the linker. // They require special treatment. ModuleRelocTarget::KnownSymbol(ref known_symbol) => { if let Some(symbol) = self.known_symbols.get(known_symbol) { *symbol } else { let symbol = self.object.add_symbol(match known_symbol { ir::KnownSymbol::ElfGlobalOffsetTable => Symbol { name: b"_GLOBAL_OFFSET_TABLE_".to_vec(), value: 0, size: 0, kind: SymbolKind::Data, scope: SymbolScope::Unknown, weak: false, section: SymbolSection::Undefined, flags: SymbolFlags::None, }, ir::KnownSymbol::CoffTlsIndex => Symbol { name: b"_tls_index".to_vec(), value: 0, size: 32, kind: SymbolKind::Tls, scope: SymbolScope::Unknown, weak: false, section: SymbolSection::Undefined, flags: SymbolFlags::None, }, }); self.known_symbols.insert(*known_symbol, symbol); symbol } } ModuleRelocTarget::FunctionOffset(func_id, offset) => { match self.known_labels.entry((func_id, offset)) { Entry::Occupied(o) => *o.get(), Entry::Vacant(v) => { let func_symbol_id = self.functions[func_id].unwrap().0; let func_symbol = self.object.symbol(func_symbol_id); let name = format!(".L{}_{}", func_id.as_u32(), offset); let symbol_id = self.object.add_symbol(Symbol { name: name.as_bytes().to_vec(), value: func_symbol.value + offset as u64, size: 0, kind: SymbolKind::Label, scope: SymbolScope::Compilation, weak: false, section: SymbolSection::Section(func_symbol.section.id().unwrap()), flags: SymbolFlags::None, }); v.insert(symbol_id); symbol_id } } } } } fn process_reloc(&self, record: &ModuleReloc) -> ObjectRelocRecord { let flags = match record.kind { Reloc::Abs4 => RelocationFlags::Generic { kind: RelocationKind::Absolute, encoding: RelocationEncoding::Generic, size: 32, }, Reloc::Abs8 => RelocationFlags::Generic { kind: RelocationKind::Absolute, encoding: RelocationEncoding::Generic, size: 64, }, Reloc::X86PCRel4 => RelocationFlags::Generic { kind: RelocationKind::Relative, encoding: RelocationEncoding::Generic, size: 32, }, Reloc::X86CallPCRel4 => RelocationFlags::Generic { kind: RelocationKind::Relative, encoding: RelocationEncoding::X86Branch, size: 32, }, // TODO: Get Cranelift to tell us when we can use // R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX. Reloc::X86CallPLTRel4 => RelocationFlags::Generic { kind: RelocationKind::PltRelative, encoding: RelocationEncoding::X86Branch, size: 32, }, Reloc::X86SecRel => RelocationFlags::Generic { kind: RelocationKind::SectionOffset, encoding: RelocationEncoding::Generic, size: 32, }, Reloc::X86GOTPCRel4 => RelocationFlags::Generic { kind: RelocationKind::GotRelative, encoding: RelocationEncoding::Generic, size: 32, }, Reloc::Arm64Call => RelocationFlags::Generic { kind: RelocationKind::Relative, encoding: RelocationEncoding::AArch64Call, size: 26, }, Reloc::ElfX86_64TlsGd => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "ElfX86_64TlsGd is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_X86_64_TLSGD, } } Reloc::MachOX86_64Tlv => { assert_eq!( self.object.format(), object::BinaryFormat::MachO, "MachOX86_64Tlv is not supported for this file format" ); RelocationFlags::MachO { r_type: object::macho::X86_64_RELOC_TLV, r_pcrel: true, r_length: 2, } } Reloc::MachOAarch64TlsAdrPage21 => { assert_eq!( self.object.format(), object::BinaryFormat::MachO, "MachOAarch64TlsAdrPage21 is not supported for this file format" ); RelocationFlags::MachO { r_type: object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21, r_pcrel: true, r_length: 2, } } Reloc::MachOAarch64TlsAdrPageOff12 => { assert_eq!( self.object.format(), object::BinaryFormat::MachO, "MachOAarch64TlsAdrPageOff12 is not supported for this file format" ); RelocationFlags::MachO { r_type: object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12, r_pcrel: false, r_length: 2, } } Reloc::Aarch64TlsDescAdrPage21 => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "Aarch64TlsDescAdrPage21 is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_AARCH64_TLSDESC_ADR_PAGE21, } } Reloc::Aarch64TlsDescLd64Lo12 => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "Aarch64TlsDescLd64Lo12 is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_AARCH64_TLSDESC_LD64_LO12, } } Reloc::Aarch64TlsDescAddLo12 => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "Aarch64TlsDescAddLo12 is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_AARCH64_TLSDESC_ADD_LO12, } } Reloc::Aarch64TlsDescCall => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "Aarch64TlsDescCall is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_AARCH64_TLSDESC_CALL, } } Reloc::Aarch64AdrGotPage21 => match self.object.format() { object::BinaryFormat::Elf => RelocationFlags::Elf { r_type: object::elf::R_AARCH64_ADR_GOT_PAGE, }, object::BinaryFormat::MachO => RelocationFlags::MachO { r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21, r_pcrel: true, r_length: 2, }, _ => unimplemented!("Aarch64AdrGotPage21 is not supported for this file format"), }, Reloc::Aarch64Ld64GotLo12Nc => match self.object.format() { object::BinaryFormat::Elf => RelocationFlags::Elf { r_type: object::elf::R_AARCH64_LD64_GOT_LO12_NC, }, object::BinaryFormat::MachO => RelocationFlags::MachO { r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12, r_pcrel: false, r_length: 2, }, _ => unimplemented!("Aarch64Ld64GotLo12Nc is not supported for this file format"), }, Reloc::Aarch64AdrPrelPgHi21 => match self.object.format() { object::BinaryFormat::Elf => RelocationFlags::Elf { r_type: object::elf::R_AARCH64_ADR_PREL_PG_HI21, }, object::BinaryFormat::MachO => RelocationFlags::MachO { r_type: object::macho::ARM64_RELOC_PAGE21, r_pcrel: true, r_length: 2, }, _ => unimplemented!("Aarch64AdrPrelPgHi21 is not supported for this file format"), }, Reloc::Aarch64AddAbsLo12Nc => match self.object.format() { object::BinaryFormat::Elf => RelocationFlags::Elf { r_type: object::elf::R_AARCH64_ADD_ABS_LO12_NC, }, object::BinaryFormat::MachO => RelocationFlags::MachO { r_type: object::macho::ARM64_RELOC_PAGEOFF12, r_pcrel: false, r_length: 2, }, _ => unimplemented!("Aarch64AddAbsLo12Nc is not supported for this file format"), }, Reloc::S390xPCRel32Dbl => RelocationFlags::Generic { kind: RelocationKind::Relative, encoding: RelocationEncoding::S390xDbl, size: 32, }, Reloc::S390xPLTRel32Dbl => RelocationFlags::Generic { kind: RelocationKind::PltRelative, encoding: RelocationEncoding::S390xDbl, size: 32, }, Reloc::S390xTlsGd64 => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "S390xTlsGd64 is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_390_TLS_GD64, } } Reloc::S390xTlsGdCall => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "S390xTlsGdCall is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_390_TLS_GDCALL, } } Reloc::RiscvCallPlt => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "RiscvCallPlt is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_RISCV_CALL_PLT, } } Reloc::RiscvTlsGdHi20 => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "RiscvTlsGdHi20 is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_RISCV_TLS_GD_HI20, } } Reloc::RiscvPCRelLo12I => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "RiscvPCRelLo12I is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_RISCV_PCREL_LO12_I, } } Reloc::RiscvGotHi20 => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, "RiscvGotHi20 is not supported for this file format" ); RelocationFlags::Elf { r_type: object::elf::R_RISCV_GOT_HI20, } } // FIXME reloc => unimplemented!("{:?}", reloc), }; ObjectRelocRecord { offset: record.offset, name: record.name.clone(), flags, addend: record.addend, } } } fn translate_linkage(linkage: Linkage) -> (SymbolScope, bool) { let scope = match linkage { Linkage::Import => SymbolScope::Unknown, Linkage::Local => SymbolScope::Compilation, Linkage::Hidden => SymbolScope::Linkage, Linkage::Export | Linkage::Preemptible => SymbolScope::Dynamic, }; // TODO: this matches rustc_codegen_cranelift, but may be wrong. let weak = linkage == Linkage::Preemptible; (scope, weak) } /// This is the output of `ObjectModule`'s /// [`finish`](../struct.ObjectModule.html#method.finish) function. /// It contains the generated `Object` and other information produced during /// compilation. pub struct ObjectProduct { /// Object artifact with all functions and data from the module defined. pub object: Object<'static>, /// Symbol IDs for functions (both declared and defined). pub functions: SecondaryMap>, /// Symbol IDs for data objects (both declared and defined). pub data_objects: SecondaryMap>, } impl ObjectProduct { /// Return the `SymbolId` for the given function. #[inline] pub fn function_symbol(&self, id: FuncId) -> SymbolId { self.functions[id].unwrap().0 } /// Return the `SymbolId` for the given data object. #[inline] pub fn data_symbol(&self, id: DataId) -> SymbolId { self.data_objects[id].unwrap().0 } /// Write the object bytes in memory. #[inline] pub fn emit(self) -> Result, object::write::Error> { self.object.write() } } #[derive(Clone)] struct SymbolRelocs { section: SectionId, offset: u64, relocs: Vec, } #[derive(Clone)] struct ObjectRelocRecord { offset: CodeOffset, name: ModuleRelocTarget, flags: RelocationFlags, addend: Addend, }