Use the object crate for metadata reading
This commit is contained in:
parent
e5f83d24ae
commit
267d55d44a
@ -2348,8 +2348,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
|
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
|
"flate2",
|
||||||
"rustc-std-workspace-alloc",
|
"rustc-std-workspace-alloc",
|
||||||
"rustc-std-workspace-core",
|
"rustc-std-workspace-core",
|
||||||
|
"wasmparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3700,6 +3702,7 @@ dependencies = [
|
|||||||
"itertools 0.9.0",
|
"itertools 0.9.0",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
|
"object",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
"rustc_apfloat",
|
"rustc_apfloat",
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
@ -5618,6 +5621,12 @@ dependencies = [
|
|||||||
"rustc-std-workspace-core",
|
"rustc-std-workspace-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasmparser"
|
||||||
|
version = "0.57.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -165,7 +165,7 @@ fn init(&self, sess: &Session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
|
fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
|
||||||
Box::new(crate::metadata::CraneliftMetadataLoader)
|
Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn provide(&self, _providers: &mut Providers) {}
|
fn provide(&self, _providers: &mut Providers) {}
|
||||||
|
@ -1,73 +1,9 @@
|
|||||||
//! Reading and writing of the rustc metadata for rlibs and dylibs
|
//! Writing of the rustc metadata for 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_middle::ty::TyCtxt;
|
||||||
use rustc_target::spec::Target;
|
|
||||||
|
|
||||||
use crate::backend::WriteMetadata;
|
use crate::backend::WriteMetadata;
|
||||||
|
|
||||||
/// The metadata loader used by cg_clif.
|
|
||||||
///
|
|
||||||
/// The metadata is stored in the same format as cg_llvm.
|
|
||||||
///
|
|
||||||
/// # 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(crate) struct CraneliftMetadataLoader;
|
|
||||||
|
|
||||||
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!("{:?}", 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<MetadataRef, String> {
|
|
||||||
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<MetadataRef, String> {
|
|
||||||
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
|
// Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
|
||||||
pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
|
pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
|
||||||
use snap::write::FrameEncoder;
|
use snap::write::FrameEncoder;
|
||||||
|
@ -250,7 +250,7 @@ fn target_features(&self, sess: &Session) -> Vec<Symbol> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
|
fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
|
||||||
Box::new(metadata::LlvmMetadataLoader)
|
Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn provide(&self, providers: &mut ty::query::Providers) {
|
fn provide(&self, providers: &mut ty::query::Providers) {
|
||||||
|
@ -1,94 +1,9 @@
|
|||||||
use crate::llvm;
|
|
||||||
use crate::llvm::archive_ro::ArchiveRO;
|
|
||||||
use crate::llvm::{mk_section_iter, False, ObjectFile};
|
|
||||||
use rustc_middle::middle::cstore::MetadataLoader;
|
|
||||||
use rustc_target::spec::Target;
|
use rustc_target::spec::Target;
|
||||||
|
|
||||||
use rustc_codegen_ssa::METADATA_FILENAME;
|
|
||||||
use rustc_data_structures::owning_ref::OwningRef;
|
|
||||||
use rustc_data_structures::rustc_erase_owner;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
use rustc_fs_util::path_to_c_string;
|
use rustc_fs_util::path_to_c_string;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
pub use rustc_data_structures::sync::MetadataRef;
|
|
||||||
|
|
||||||
pub struct LlvmMetadataLoader;
|
|
||||||
|
|
||||||
impl MetadataLoader for LlvmMetadataLoader {
|
|
||||||
fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
|
|
||||||
// Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
|
|
||||||
// internally to read the file. We also avoid even using a memcpy by
|
|
||||||
// just keeping the archive along while the metadata is in use.
|
|
||||||
let archive =
|
|
||||||
ArchiveRO::open(filename).map(|ar| OwningRef::new(Box::new(ar))).map_err(|e| {
|
|
||||||
debug!("llvm didn't like `{}`: {}", filename.display(), e);
|
|
||||||
format!("failed to read rlib metadata in '{}': {}", filename.display(), e)
|
|
||||||
})?;
|
|
||||||
let buf: OwningRef<_, [u8]> = archive.try_map(|ar| {
|
|
||||||
ar.iter()
|
|
||||||
.filter_map(|s| s.ok())
|
|
||||||
.find(|sect| sect.name() == Some(METADATA_FILENAME))
|
|
||||||
.map(|s| s.data())
|
|
||||||
.ok_or_else(|| {
|
|
||||||
debug!("didn't find '{}' in the archive", METADATA_FILENAME);
|
|
||||||
format!("failed to read rlib metadata: '{}'", filename.display())
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
Ok(rustc_erase_owner!(buf))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
|
|
||||||
unsafe {
|
|
||||||
let buf = path_to_c_string(filename);
|
|
||||||
let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
|
|
||||||
.ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
|
|
||||||
let of =
|
|
||||||
ObjectFile::new(mb).map(|of| OwningRef::new(Box::new(of))).ok_or_else(|| {
|
|
||||||
format!("provided path not an object file: '{}'", filename.display())
|
|
||||||
})?;
|
|
||||||
let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
|
|
||||||
Ok(rustc_erase_owner!(buf))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn search_meta_section<'a>(
|
|
||||||
of: &'a ObjectFile,
|
|
||||||
target: &Target,
|
|
||||||
filename: &Path,
|
|
||||||
) -> Result<&'a [u8], String> {
|
|
||||||
unsafe {
|
|
||||||
let si = mk_section_iter(of.llof);
|
|
||||||
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
|
|
||||||
let mut name_buf = None;
|
|
||||||
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
|
|
||||||
let name = name_buf.map_or_else(
|
|
||||||
String::new, // We got a null ptr, ignore `name_len`.
|
|
||||||
|buf| {
|
|
||||||
String::from_utf8(
|
|
||||||
slice::from_raw_parts(buf.as_ptr() as *const u8, name_len as usize)
|
|
||||||
.to_vec(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
debug!("get_metadata_section: name {}", name);
|
|
||||||
if read_metadata_section_name(target) == name {
|
|
||||||
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
|
||||||
let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
|
|
||||||
// The buffer is valid while the object file is around
|
|
||||||
let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
|
|
||||||
return Ok(buf);
|
|
||||||
}
|
|
||||||
llvm::LLVMMoveToNextSection(si.llsi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(format!("metadata not found: '{}'", filename.display()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn metadata_section_name(target: &Target) -> &'static str {
|
pub fn metadata_section_name(target: &Target) -> &'static str {
|
||||||
// Historical note:
|
// Historical note:
|
||||||
//
|
//
|
||||||
@ -106,7 +21,3 @@ pub fn metadata_section_name(target: &Target) -> &'static str {
|
|||||||
|
|
||||||
if target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
|
if target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_metadata_section_name(_target: &Target) -> &'static str {
|
|
||||||
".rustc"
|
|
||||||
}
|
|
||||||
|
@ -16,6 +16,7 @@ libc = "0.2.50"
|
|||||||
jobserver = "0.1.22"
|
jobserver = "0.1.22"
|
||||||
tempfile = "3.2"
|
tempfile = "3.2"
|
||||||
pathdiff = "0.2.0"
|
pathdiff = "0.2.0"
|
||||||
|
object = "0.22.0"
|
||||||
|
|
||||||
rustc_serialize = { path = "../rustc_serialize" }
|
rustc_serialize = { path = "../rustc_serialize" }
|
||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
|
65
compiler/rustc_codegen_ssa/src/back/metadata.rs
Normal file
65
compiler/rustc_codegen_ssa/src/back/metadata.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
//! 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!("{:?}", 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 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!("{:?}", 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<MetadataRef, String> {
|
||||||
|
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))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
pub mod link;
|
pub mod link;
|
||||||
pub mod linker;
|
pub mod linker;
|
||||||
pub mod lto;
|
pub mod lto;
|
||||||
|
pub mod metadata;
|
||||||
pub mod rpath;
|
pub mod rpath;
|
||||||
pub mod symbol_export;
|
pub mod symbol_export;
|
||||||
pub mod write;
|
pub mod write;
|
||||||
|
Loading…
Reference in New Issue
Block a user