diff options
| author | bors <bors@rust-lang.org> | 2021-05-14 12:58:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-05-14 12:58:58 +0000 |
| commit | 75da570d784a798a34ff1e5048cd9a6a2fb23170 (patch) | |
| tree | 7e2ffecffbd250a725092db3d0bc5190c52b4fdb /compiler/rustc_codegen_ssa | |
| parent | 36a4d14c7edba21bba14df00b9e6e4a111dfc6f2 (diff) | |
| parent | 6381aaf8ae2df01cdb70b6f3123153cf4f1e03cd (diff) | |
| download | rust-75da570d784a798a34ff1e5048cd9a6a2fb23170.tar.gz rust-75da570d784a798a34ff1e5048cd9a6a2fb23170.zip | |
Auto merge of #83640 - bjorn3:shared_metadata_reader, r=nagisa
Use the object crate for metadata reading This allows sharing the metadata reader between cg_llvm, cg_clif and other codegen backends. This is not currently useful for rlib reading with cg_spirv ([rust-gpu](https://github.com/EmbarkStudios/rust-gpu/)) as it uses tar rather than ar as .rlib format, but it is useful for dylib reading required for loading proc macros. (cc `@eddyb)` The object crate is already trusted as dependency of libstd through backtrace. As far as I know it supports reading all object file formats used by targets for which we support rust dylibs with crate metadata, but I am not certain. If this happens to not be the case, I could keep using LLVM for reading dylib metadata. Marked as WIP for a perf run and as it is based on #83637.
Diffstat (limited to 'compiler/rustc_codegen_ssa')
| -rw-r--r-- | compiler/rustc_codegen_ssa/Cargo.toml | 5 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/metadata.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/mod.rs | 1 |
3 files changed, 77 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index c6764662fa5..68f40d5f863 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -33,3 +33,8 @@ rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } + +[dependencies.object] +version = "0.22.0" +default-features = false +features = ["read_core", "elf", "macho", "pe", "unaligned", "archive"] diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs new file mode 100644 index 00000000000..37d1f8ecc83 --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -0,0 +1,71 @@ +//! Reading of the rustc metadata for rlibs and dylibs + +use std::fs::File; +use std::path::Path; + +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_target::spec::Target; + +use crate::METADATA_FILENAME; + +/// The default metadata loader. This is used by cg_llvm and cg_clif. +/// +/// # Metadata location +/// +/// <dl> +/// <dt>rlib</dt> +/// <dd>The metadata can be found in the `lib.rmeta` file inside of the ar archive.</dd> +/// <dt>dylib</dt> +/// <dd>The metadata can be found in the `.rustc` section of the shared library.</dd> +/// </dl> +pub struct DefaultMetadataLoader; + +fn load_metadata_with( + path: &Path, + f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>, +) -> Result<MetadataRef, String> { + let file = + File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?; + let data = unsafe { Mmap::map(file) } + .map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))?; + let metadata = OwningRef::new(data).try_map(f)?; + return Ok(rustc_erase_owner!(metadata.map_owner_box())); +} + +impl MetadataLoader for DefaultMetadataLoader { + fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { + load_metadata_with(path, |data| { + let archive = object::read::archive::ArchiveFile::parse(&*data) + .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; + + for entry_result in archive.members() { + let entry = entry_result + .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; + if entry.name() == METADATA_FILENAME.as_bytes() { + return Ok(entry.data()); + } + } + + Err(format!("metadata not found in rlib '{}'", path.display())) + }) + } + + fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { + use object::{Object, ObjectSection}; + + load_metadata_with(path, |data| { + let file = object::File::parse(&data) + .map_err(|e| format!("failed to parse dylib '{}': {}", path.display(), e))?; + file.section_by_name(".rustc") + .ok_or_else(|| format!("no .rustc section in '{}'", path.display()))? + .data() + .map_err(|e| { + format!("failed to read .rustc section in '{}': {}", path.display(), e) + }) + }) + } +} diff --git a/compiler/rustc_codegen_ssa/src/back/mod.rs b/compiler/rustc_codegen_ssa/src/back/mod.rs index 20ca503d43f..d11ed54eb20 100644 --- a/compiler/rustc_codegen_ssa/src/back/mod.rs +++ b/compiler/rustc_codegen_ssa/src/back/mod.rs @@ -3,6 +3,7 @@ pub mod command; pub mod link; pub mod linker; pub mod lto; +pub mod metadata; pub mod rpath; pub mod symbol_export; pub mod write; |
