//! Reading and writing of the rustc metadata for rlibs and dylibs use std::fs::File; use std::path::Path; use rustc_codegen_ssa::METADATA_FILENAME; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::rustc_erase_owner; use rustc_data_structures::sync::MetadataRef; use rustc_middle::middle::cstore::MetadataLoader; use rustc_middle::ty::TyCtxt; use rustc_target::spec::Target; use crate::backend::WriteMetadata; pub(crate) struct CraneliftMetadataLoader; fn load_metadata_with( path: &Path, f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>, ) -> Result { let file = File::open(path).map_err(|e| format!("{:?}", e))?; let data = unsafe { Mmap::map(file) }.map_err(|e| format!("{:?}", e))?; let metadata = OwningRef::new(data).try_map(f)?; return Ok(rustc_erase_owner!(metadata.map_owner_box())); } impl MetadataLoader for CraneliftMetadataLoader { fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result { load_metadata_with(path, |data| { let archive = object::read::archive::ArchiveFile::parse(&*data) .map_err(|e| format!("{:?}", e))?; for entry_result in archive.members() { let entry = entry_result.map_err(|e| format!("{:?}", e))?; if entry.name() == METADATA_FILENAME.as_bytes() { return Ok(entry.data()); } } Err("couldn't find metadata entry".to_string()) }) } fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result { use object::{Object, ObjectSection}; load_metadata_with(path, |data| { let file = object::File::parse(&data).map_err(|e| format!("parse: {:?}", e))?; file.section_by_name(".rustc") .ok_or("no .rustc section")? .data() .map_err(|e| format!("failed to read .rustc section: {:?}", e)) }) } } // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112 pub(crate) fn write_metadata(tcx: TyCtxt<'_>, object: &mut O) { use snap::write::FrameEncoder; use std::io::Write; let metadata = tcx.encode_metadata(); let mut compressed = tcx.metadata_encoding_version(); FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); object.add_rustc_section( rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx), compressed, tcx.sess.target.is_like_osx, ); }