about summary refs log tree commit diff
path: root/compiler/rustc_codegen_llvm/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-05-14 12:58:58 +0000
committerbors <bors@rust-lang.org>2021-05-14 12:58:58 +0000
commit75da570d784a798a34ff1e5048cd9a6a2fb23170 (patch)
tree7e2ffecffbd250a725092db3d0bc5190c52b4fdb /compiler/rustc_codegen_llvm/src
parent36a4d14c7edba21bba14df00b9e6e4a111dfc6f2 (diff)
parent6381aaf8ae2df01cdb70b6f3123153cf4f1e03cd (diff)
downloadrust-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_llvm/src')
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/metadata.rs112
3 files changed, 17 insertions, 116 deletions
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 6f6c649bb0b..893c909b204 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -18,7 +18,6 @@ use crate::builder::Builder;
 use crate::common;
 use crate::context::CodegenCx;
 use crate::llvm;
-use crate::metadata;
 use crate::value::Value;
 
 use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
@@ -47,6 +46,22 @@ pub fn write_compressed_metadata<'tcx>(
     use snap::write::FrameEncoder;
     use std::io::Write;
 
+    // Historical note:
+    //
+    // When using link.exe it was seen that the section name `.note.rustc`
+    // was getting shortened to `.note.ru`, and according to the PE and COFF
+    // specification:
+    //
+    // > Executable images do not use a string table and do not support
+    // > section names longer than 8 characters
+    //
+    // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+    //
+    // As a result, we choose a slightly shorter name! As to why
+    // `.note.rustc` works on MinGW, see
+    // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
+    let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
+
     let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
     let mut compressed = tcx.metadata_encoding_version();
     FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
@@ -59,7 +74,6 @@ pub fn write_compressed_metadata<'tcx>(
         unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) };
     unsafe {
         llvm::LLVMSetInitializer(llglobal, llconst);
-        let section_name = metadata::metadata_section_name(&tcx.sess.target);
         let name = SmallCStr::new(section_name);
         llvm::LLVMSetSection(llglobal, name.as_ptr());
 
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 91062926788..329458773ff 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -69,7 +69,6 @@ pub mod llvm {
 }
 
 mod llvm_util;
-mod metadata;
 mod mono_item;
 mod type_;
 mod type_of;
@@ -251,7 +250,7 @@ impl CodegenBackend for LlvmCodegenBackend {
     }
 
     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) {}
diff --git a/compiler/rustc_codegen_llvm/src/metadata.rs b/compiler/rustc_codegen_llvm/src/metadata.rs
deleted file mode 100644
index decc1e1f700..00000000000
--- a/compiler/rustc_codegen_llvm/src/metadata.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-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_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 std::path::Path;
-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 {
-    // Historical note:
-    //
-    // When using link.exe it was seen that the section name `.note.rustc`
-    // was getting shortened to `.note.ru`, and according to the PE and COFF
-    // specification:
-    //
-    // > Executable images do not use a string table and do not support
-    // > section names longer than 8 characters
-    //
-    // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
-    //
-    // As a result, we choose a slightly shorter name! As to why
-    // `.note.rustc` works on MinGW, that's another good question...
-
-    if target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
-}
-
-fn read_metadata_section_name(_target: &Target) -> &'static str {
-    ".rustc"
-}