diff options
| author | bors <bors@rust-lang.org> | 2022-02-20 11:32:40 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-02-20 11:32:40 +0000 |
| commit | 3b186511f62b0ce20e72ede0e8e13f8787155f02 (patch) | |
| tree | 43beb306dece88a6b76b50d7b35c5ae518687bd0 /compiler/rustc_codegen_ssa/src/back | |
| parent | 6d7aa4763fe7f737d6add4261b9e050b36701089 (diff) | |
| parent | 932559cc21a2f0746012645f130956b81480cd86 (diff) | |
| download | rust-3b186511f62b0ce20e72ede0e8e13f8787155f02.tar.gz rust-3b186511f62b0ce20e72ede0e8e13f8787155f02.zip | |
Auto merge of #93816 - bjorn3:rlib_metadata_first, r=nagisa
Put crate metadata first in the rlib This should make metadata lookup faster Fixes https://github.com/rust-lang/rust/issues/93806
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 97 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/metadata.rs | 11 |
2 files changed, 68 insertions, 40 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 5a07b23f3f9..587453fd8e8 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -23,7 +23,7 @@ use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Ta use super::archive::{find_library, ArchiveBuilder}; use super::command::Command; use super::linker::{self, Linker}; -use super::metadata::create_rmeta_file; +use super::metadata::{create_rmeta_file, MetadataPosition}; use super::rpath::{self, RPathConfig}; use crate::{ looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib, @@ -267,6 +267,28 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None); + let trailing_metadata = match flavor { + RlibFlavor::Normal => { + let (metadata, metadata_position) = + create_rmeta_file(sess, codegen_results.metadata.raw_data()); + let metadata = emit_metadata(sess, &metadata, tmpdir); + match metadata_position { + MetadataPosition::First => { + // Most of the time metadata in rlib files is wrapped in a "dummy" object + // file for the target platform so the rlib can be processed entirely by + // normal linkers for the platform. Sometimes this is not possible however. + // If it is possible however, placing the metadata object first improves + // performance of getting metadata from rlibs. + ab.add_file(&metadata); + None + } + MetadataPosition::Last => Some(metadata), + } + } + + RlibFlavor::StaticlibBase => None, + }; + for m in &codegen_results.modules { if let Some(obj) = m.object.as_ref() { ab.add_file(obj); @@ -277,6 +299,16 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } } + match flavor { + RlibFlavor::Normal => {} + RlibFlavor::StaticlibBase => { + let obj = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref()); + if let Some(obj) = obj { + ab.add_file(obj); + } + } + } + // Note that in this loop we are ignoring the value of `lib.cfg`. That is, // we may not be configured to actually include a static library if we're // adding it here. That's because later when we consume this rlib we'll @@ -334,42 +366,33 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir); } - // Note that it is important that we add all of our non-object "magical - // files" *after* all of the object files in the archive. The reason for - // this is as follows: - // - // * When performing LTO, this archive will be modified to remove - // objects from above. The reason for this is described below. - // - // * When the system linker looks at an archive, it will attempt to - // determine the architecture of the archive in order to see whether its - // linkable. - // - // The algorithm for this detection is: iterate over the files in the - // archive. Skip magical SYMDEF names. Interpret the first file as an - // object file. Read architecture from the object file. - // - // * As one can probably see, if "metadata" and "foo.bc" were placed - // before all of the objects, then the architecture of this archive would - // not be correctly inferred once 'foo.o' is removed. - // - // Basically, all this means is that this code should not move above the - // code above. - match flavor { - RlibFlavor::Normal => { - // metadata in rlib files is wrapped in a "dummy" object file for - // the target platform so the rlib can be processed entirely by - // normal linkers for the platform. - let metadata = create_rmeta_file(sess, codegen_results.metadata.raw_data()); - ab.add_file(&emit_metadata(sess, &metadata, tmpdir)); - } - - RlibFlavor::StaticlibBase => { - let obj = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref()); - if let Some(obj) = obj { - ab.add_file(obj); - } - } + if let Some(trailing_metadata) = trailing_metadata { + // Note that it is important that we add all of our non-object "magical + // files" *after* all of the object files in the archive. The reason for + // this is as follows: + // + // * When performing LTO, this archive will be modified to remove + // objects from above. The reason for this is described below. + // + // * When the system linker looks at an archive, it will attempt to + // determine the architecture of the archive in order to see whether its + // linkable. + // + // The algorithm for this detection is: iterate over the files in the + // archive. Skip magical SYMDEF names. Interpret the first file as an + // object file. Read architecture from the object file. + // + // * As one can probably see, if "metadata" and "foo.bc" were placed + // before all of the objects, then the architecture of this archive would + // not be correctly inferred once 'foo.o' is removed. + // + // * Most of the time metadata in rlib files is wrapped in a "dummy" object + // file for the target platform so the rlib can be processed entirely by + // normal linkers for the platform. Sometimes this is not possible however. + // + // Basically, all this means is that this code should not move above the + // code above. + ab.add_file(&trailing_metadata); } return Ok(ab); diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 39d39ad1365..c52269805c4 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -166,6 +166,11 @@ fn create_object_file(sess: &Session) -> Option<write::Object<'static>> { Some(file) } +pub enum MetadataPosition { + First, + Last, +} + // For rlibs we "pack" rustc metadata into a dummy object file. When rustc // creates a dylib crate type it will pass `--whole-archive` (or the // platform equivalent) to include all object files from an rlib into the @@ -198,7 +203,7 @@ fn create_object_file(sess: &Session) -> Option<write::Object<'static>> { // * ELF - All other targets are similar to Windows in that there's a // `SHF_EXCLUDE` flag we can set on sections in an object file to get // automatically removed from the final output. -pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> { +pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> (Vec<u8>, MetadataPosition) { let Some(mut file) = create_object_file(sess) else { // This is used to handle all "other" targets. This includes targets // in two categories: @@ -216,7 +221,7 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> { // WebAssembly and for targets not supported by the `object` crate // yet it means that work will need to be done in the `object` crate // to add a case above. - return metadata.to_vec(); + return (metadata.to_vec(), MetadataPosition::Last); }; let section = file.add_section( file.segment_name(StandardSegment::Debug).to_vec(), @@ -235,7 +240,7 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> { _ => {} }; file.append_section_data(section, metadata, 1); - file.write().unwrap() + (file.write().unwrap(), MetadataPosition::First) } // Historical note: |
