Skip to content

Commit 267d55d

Browse files
committed
Use the object crate for metadata reading
1 parent e5f83d2 commit 267d55d

File tree

8 files changed

+79
-156
lines changed

8 files changed

+79
-156
lines changed

Cargo.lock

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,8 +2348,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
23482348
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
23492349
dependencies = [
23502350
"compiler_builtins",
2351+
"flate2",
23512352
"rustc-std-workspace-alloc",
23522353
"rustc-std-workspace-core",
2354+
"wasmparser",
23532355
]
23542356

23552357
[[package]]
@@ -3700,6 +3702,7 @@ dependencies = [
37003702
"itertools 0.9.0",
37013703
"jobserver",
37023704
"libc",
3705+
"object",
37033706
"pathdiff",
37043707
"rustc_apfloat",
37053708
"rustc_ast",
@@ -5618,6 +5621,12 @@ dependencies = [
56185621
"rustc-std-workspace-core",
56195622
]
56205623

5624+
[[package]]
5625+
name = "wasmparser"
5626+
version = "0.57.0"
5627+
source = "registry+https://github.com/rust-lang/crates.io-index"
5628+
checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6"
5629+
56215630
[[package]]
56225631
name = "winapi"
56235632
version = "0.2.8"

compiler/rustc_codegen_cranelift/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
165165
}
166166

167167
fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
168-
Box::new(crate::metadata::CraneliftMetadataLoader)
168+
Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
169169
}
170170

171171
fn provide(&self, _providers: &mut Providers) {}

compiler/rustc_codegen_cranelift/src/metadata.rs

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,9 @@
1-
//! Reading and writing of the rustc metadata for rlibs and dylibs
1+
//! Writing of the rustc metadata for dylibs
22
3-
use std::fs::File;
4-
use std::path::Path;
5-
6-
use rustc_codegen_ssa::METADATA_FILENAME;
7-
use rustc_data_structures::memmap::Mmap;
8-
use rustc_data_structures::owning_ref::OwningRef;
9-
use rustc_data_structures::rustc_erase_owner;
10-
use rustc_data_structures::sync::MetadataRef;
11-
use rustc_middle::middle::cstore::MetadataLoader;
123
use rustc_middle::ty::TyCtxt;
13-
use rustc_target::spec::Target;
144

155
use crate::backend::WriteMetadata;
166

17-
/// The metadata loader used by cg_clif.
18-
///
19-
/// The metadata is stored in the same format as cg_llvm.
20-
///
21-
/// # Metadata location
22-
///
23-
/// <dl>
24-
/// <dt>rlib</dt>
25-
/// <dd>The metadata can be found in the `lib.rmeta` file inside of the ar archive.</dd>
26-
/// <dt>dylib</dt>
27-
/// <dd>The metadata can be found in the `.rustc` section of the shared library.</dd>
28-
/// </dl>
29-
pub(crate) struct CraneliftMetadataLoader;
30-
31-
fn load_metadata_with(
32-
path: &Path,
33-
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
34-
) -> Result<MetadataRef, String> {
35-
let file = File::open(path).map_err(|e| format!("{:?}", e))?;
36-
let data = unsafe { Mmap::map(file) }.map_err(|e| format!("{:?}", e))?;
37-
let metadata = OwningRef::new(data).try_map(f)?;
38-
return Ok(rustc_erase_owner!(metadata.map_owner_box()));
39-
}
40-
41-
impl MetadataLoader for CraneliftMetadataLoader {
42-
fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
43-
load_metadata_with(path, |data| {
44-
let archive = object::read::archive::ArchiveFile::parse(&*data)
45-
.map_err(|e| format!("{:?}", e))?;
46-
47-
for entry_result in archive.members() {
48-
let entry = entry_result.map_err(|e| format!("{:?}", e))?;
49-
if entry.name() == METADATA_FILENAME.as_bytes() {
50-
return Ok(entry.data());
51-
}
52-
}
53-
54-
Err("couldn't find metadata entry".to_string())
55-
})
56-
}
57-
58-
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
59-
use object::{Object, ObjectSection};
60-
61-
load_metadata_with(path, |data| {
62-
let file = object::File::parse(&data).map_err(|e| format!("parse: {:?}", e))?;
63-
file.section_by_name(".rustc")
64-
.ok_or("no .rustc section")?
65-
.data()
66-
.map_err(|e| format!("failed to read .rustc section: {:?}", e))
67-
})
68-
}
69-
}
70-
717
// Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
728
pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
739
use snap::write::FrameEncoder;

compiler/rustc_codegen_llvm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ impl CodegenBackend for LlvmCodegenBackend {
250250
}
251251

252252
fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
253-
Box::new(metadata::LlvmMetadataLoader)
253+
Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
254254
}
255255

256256
fn provide(&self, providers: &mut ty::query::Providers) {
Lines changed: 0 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,9 @@
1-
use crate::llvm;
2-
use crate::llvm::archive_ro::ArchiveRO;
3-
use crate::llvm::{mk_section_iter, False, ObjectFile};
4-
use rustc_middle::middle::cstore::MetadataLoader;
51
use rustc_target::spec::Target;
62

7-
use rustc_codegen_ssa::METADATA_FILENAME;
8-
use rustc_data_structures::owning_ref::OwningRef;
9-
use rustc_data_structures::rustc_erase_owner;
10-
use tracing::debug;
11-
123
use rustc_fs_util::path_to_c_string;
134
use std::path::Path;
145
use std::slice;
156

16-
pub use rustc_data_structures::sync::MetadataRef;
17-
18-
pub struct LlvmMetadataLoader;
19-
20-
impl MetadataLoader for LlvmMetadataLoader {
21-
fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
22-
// Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
23-
// internally to read the file. We also avoid even using a memcpy by
24-
// just keeping the archive along while the metadata is in use.
25-
let archive =
26-
ArchiveRO::open(filename).map(|ar| OwningRef::new(Box::new(ar))).map_err(|e| {
27-
debug!("llvm didn't like `{}`: {}", filename.display(), e);
28-
format!("failed to read rlib metadata in '{}': {}", filename.display(), e)
29-
})?;
30-
let buf: OwningRef<_, [u8]> = archive.try_map(|ar| {
31-
ar.iter()
32-
.filter_map(|s| s.ok())
33-
.find(|sect| sect.name() == Some(METADATA_FILENAME))
34-
.map(|s| s.data())
35-
.ok_or_else(|| {
36-
debug!("didn't find '{}' in the archive", METADATA_FILENAME);
37-
format!("failed to read rlib metadata: '{}'", filename.display())
38-
})
39-
})?;
40-
Ok(rustc_erase_owner!(buf))
41-
}
42-
43-
fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
44-
unsafe {
45-
let buf = path_to_c_string(filename);
46-
let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
47-
.ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
48-
let of =
49-
ObjectFile::new(mb).map(|of| OwningRef::new(Box::new(of))).ok_or_else(|| {
50-
format!("provided path not an object file: '{}'", filename.display())
51-
})?;
52-
let buf = of.try_map(|of| search_meta_section(of, target, filename))?;
53-
Ok(rustc_erase_owner!(buf))
54-
}
55-
}
56-
}
57-
58-
fn search_meta_section<'a>(
59-
of: &'a ObjectFile,
60-
target: &Target,
61-
filename: &Path,
62-
) -> Result<&'a [u8], String> {
63-
unsafe {
64-
let si = mk_section_iter(of.llof);
65-
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
66-
let mut name_buf = None;
67-
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
68-
let name = name_buf.map_or_else(
69-
String::new, // We got a null ptr, ignore `name_len`.
70-
|buf| {
71-
String::from_utf8(
72-
slice::from_raw_parts(buf.as_ptr() as *const u8, name_len as usize)
73-
.to_vec(),
74-
)
75-
.unwrap()
76-
},
77-
);
78-
debug!("get_metadata_section: name {}", name);
79-
if read_metadata_section_name(target) == name {
80-
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
81-
let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
82-
// The buffer is valid while the object file is around
83-
let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz);
84-
return Ok(buf);
85-
}
86-
llvm::LLVMMoveToNextSection(si.llsi);
87-
}
88-
}
89-
Err(format!("metadata not found: '{}'", filename.display()))
90-
}
91-
927
pub fn metadata_section_name(target: &Target) -> &'static str {
938
// Historical note:
949
//
@@ -106,7 +21,3 @@ pub fn metadata_section_name(target: &Target) -> &'static str {
10621

10722
if target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
10823
}
109-
110-
fn read_metadata_section_name(_target: &Target) -> &'static str {
111-
".rustc"
112-
}

compiler/rustc_codegen_ssa/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ libc = "0.2.50"
1616
jobserver = "0.1.22"
1717
tempfile = "3.2"
1818
pathdiff = "0.2.0"
19+
object = "0.22.0"
1920

2021
rustc_serialize = { path = "../rustc_serialize" }
2122
rustc_ast = { path = "../rustc_ast" }
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! Reading of the rustc metadata for rlibs and dylibs
2+
3+
use std::fs::File;
4+
use std::path::Path;
5+
6+
use rustc_data_structures::memmap::Mmap;
7+
use rustc_data_structures::owning_ref::OwningRef;
8+
use rustc_data_structures::rustc_erase_owner;
9+
use rustc_data_structures::sync::MetadataRef;
10+
use rustc_middle::middle::cstore::MetadataLoader;
11+
use rustc_target::spec::Target;
12+
13+
use crate::METADATA_FILENAME;
14+
15+
/// The default metadata loader. This is used by cg_llvm and cg_clif.
16+
///
17+
/// # Metadata location
18+
///
19+
/// <dl>
20+
/// <dt>rlib</dt>
21+
/// <dd>The metadata can be found in the `lib.rmeta` file inside of the ar archive.</dd>
22+
/// <dt>dylib</dt>
23+
/// <dd>The metadata can be found in the `.rustc` section of the shared library.</dd>
24+
/// </dl>
25+
pub struct DefaultMetadataLoader;
26+
27+
fn load_metadata_with(
28+
path: &Path,
29+
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
30+
) -> Result<MetadataRef, String> {
31+
let file = File::open(path).map_err(|e| format!("{:?}", e))?;
32+
let data = unsafe { Mmap::map(file) }.map_err(|e| format!("{:?}", e))?;
33+
let metadata = OwningRef::new(data).try_map(f)?;
34+
return Ok(rustc_erase_owner!(metadata.map_owner_box()));
35+
}
36+
37+
impl MetadataLoader for DefaultMetadataLoader {
38+
fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
39+
load_metadata_with(path, |data| {
40+
let archive = object::read::archive::ArchiveFile::parse(&*data)
41+
.map_err(|e| format!("{:?}", e))?;
42+
43+
for entry_result in archive.members() {
44+
let entry = entry_result.map_err(|e| format!("{:?}", e))?;
45+
if entry.name() == METADATA_FILENAME.as_bytes() {
46+
return Ok(entry.data());
47+
}
48+
}
49+
50+
Err("couldn't find metadata entry".to_string())
51+
})
52+
}
53+
54+
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
55+
use object::{Object, ObjectSection};
56+
57+
load_metadata_with(path, |data| {
58+
let file = object::File::parse(&data).map_err(|e| format!("parse: {:?}", e))?;
59+
file.section_by_name(".rustc")
60+
.ok_or("no .rustc section")?
61+
.data()
62+
.map_err(|e| format!("failed to read .rustc section: {:?}", e))
63+
})
64+
}
65+
}

compiler/rustc_codegen_ssa/src/back/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod command;
33
pub mod link;
44
pub mod linker;
55
pub mod lto;
6+
pub mod metadata;
67
pub mod rpath;
78
pub mod symbol_export;
89
pub mod write;

0 commit comments

Comments
 (0)