summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_llvm/src/back
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_codegen_llvm/src/back
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_codegen_llvm/src/back')
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs164
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs16
3 files changed, 104 insertions, 85 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 082665bba..2cf2f585f 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -1,27 +1,30 @@
//! A helper class for dealing with static archives
use std::env;
-use std::ffi::{CStr, CString, OsString};
-use std::fs;
-use std::io::{self, Write};
+use std::ffi::{c_char, c_void, CStr, CString, OsString};
+use std::io;
use std::mem;
use std::path::{Path, PathBuf};
use std::ptr;
use std::str;
-use object::read::macho::FatArch;
-
use crate::common;
+use crate::errors::{
+ DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
+};
use crate::llvm::archive_ro::{ArchiveRO, Child};
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
-use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
-use rustc_data_structures::memmap::Mmap;
+use rustc_codegen_ssa::back::archive::{
+ get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
+ ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
+};
+
use rustc_session::cstore::DllImport;
use rustc_session::Session;
/// Helper for adding many files to an archive.
#[must_use = "must call build() to finish building the archive"]
-pub struct LlvmArchiveBuilder<'a> {
+pub(crate) struct LlvmArchiveBuilder<'a> {
sess: &'a Session,
additions: Vec<Addition>,
}
@@ -57,57 +60,6 @@ fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
}
}
-fn try_filter_fat_archs(
- archs: object::read::Result<&[impl FatArch]>,
- target_arch: object::Architecture,
- archive_path: &Path,
- archive_map_data: &[u8],
-) -> io::Result<Option<PathBuf>> {
- let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
-
- let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
- Some(a) => a,
- None => return Ok(None),
- };
-
- let (mut new_f, extracted_path) = tempfile::Builder::new()
- .suffix(archive_path.file_name().unwrap())
- .tempfile()?
- .keep()
- .unwrap();
-
- new_f.write_all(
- desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
- )?;
-
- Ok(Some(extracted_path))
-}
-
-fn try_extract_macho_fat_archive(
- sess: &Session,
- archive_path: &Path,
-) -> io::Result<Option<PathBuf>> {
- let archive_map = unsafe { Mmap::map(fs::File::open(&archive_path)?)? };
- let target_arch = match sess.target.arch.as_ref() {
- "aarch64" => object::Architecture::Aarch64,
- "x86_64" => object::Architecture::X86_64,
- _ => return Ok(None),
- };
-
- match object::macho::FatHeader::parse(&*archive_map) {
- Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => {
- let archs = object::macho::FatHeader::parse_arch32(&*archive_map);
- try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
- }
- Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => {
- let archs = object::macho::FatHeader::parse_arch64(&*archive_map);
- try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
- }
- // Not a FatHeader at all, just return None.
- _ => Ok(None),
- }
-}
-
impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
fn add_archive(
&mut self,
@@ -147,7 +99,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
fn build(mut self: Box<Self>, output: &Path) -> bool {
match self.build_with_llvm(output) {
Ok(any_members) => any_members,
- Err(e) => self.sess.fatal(&format!("failed to build archive: {}", e)),
+ Err(e) => self.sess.emit_fatal(ArchiveBuildFailure { error: e }),
}
}
}
@@ -156,7 +108,13 @@ pub struct LlvmArchiveBuilderBuilder;
impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
- Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
+ // FIXME use ArArchiveBuilder on most targets again once reading thin archives is
+ // implemented
+ if true || sess.target.arch == "wasm32" || sess.target.arch == "wasm64" {
+ Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
+ } else {
+ Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))
+ }
}
fn create_dll_import_lib(
@@ -217,7 +175,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
match std::fs::write(&def_file_path, def_file_content) {
Ok(_) => {}
Err(e) => {
- sess.fatal(&format!("Error writing .DEF file: {}", e));
+ sess.emit_fatal(ErrorWritingDEFFile { error: e });
}
};
@@ -239,13 +197,14 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
match result {
Err(e) => {
- sess.fatal(&format!("Error calling dlltool: {}", e));
+ sess.emit_fatal(ErrorCallingDllTool { error: e });
+ }
+ Ok(output) if !output.status.success() => {
+ sess.emit_fatal(DlltoolFailImportLibrary {
+ stdout: String::from_utf8_lossy(&output.stdout),
+ stderr: String::from_utf8_lossy(&output.stderr),
+ })
}
- Ok(output) if !output.status.success() => sess.fatal(&format!(
- "Dlltool could not create import library: {}\n{}",
- String::from_utf8_lossy(&output.stdout),
- String::from_utf8_lossy(&output.stderr)
- )),
_ => {}
}
} else {
@@ -293,11 +252,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
};
if result == crate::llvm::LLVMRustResult::Failure {
- sess.fatal(&format!(
- "Error creating import library for {}: {}",
+ sess.emit_fatal(ErrorCreatingImportLibrary {
lib_name,
- llvm::last_error().unwrap_or("unknown LLVM error".to_string())
- ));
+ error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
+ });
}
};
@@ -305,12 +263,68 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
}
}
+// The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files.
+// As such we need to use LLVM for them.
+#[deny(unsafe_op_in_unsafe_fn)]
+fn get_llvm_object_symbols(
+ buf: &[u8],
+ f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
+) -> io::Result<bool> {
+ let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) };
+
+ // COFF bigobj file, msvc LTO file or import library. See
+ // https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51
+ let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF");
+
+ if is_bitcode || is_unsupported_windows_obj_file {
+ let mut state = Box::new(f);
+
+ let err = unsafe {
+ llvm::LLVMRustGetSymbols(
+ buf.as_ptr(),
+ buf.len(),
+ &mut *state as *mut &mut _ as *mut c_void,
+ callback,
+ error_callback,
+ )
+ };
+
+ if err.is_null() {
+ return Ok(true);
+ } else {
+ return Err(unsafe { *Box::from_raw(err as *mut io::Error) });
+ }
+
+ unsafe extern "C" fn callback(
+ state: *mut c_void,
+ symbol_name: *const c_char,
+ ) -> *mut c_void {
+ let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) };
+ match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) {
+ Ok(()) => std::ptr::null_mut(),
+ Err(err) => Box::into_raw(Box::new(err)) as *mut c_void,
+ }
+ }
+
+ unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void {
+ let error = unsafe { CStr::from_ptr(error) };
+ Box::into_raw(Box::new(io::Error::new(
+ io::ErrorKind::Other,
+ format!("LLVM error: {}", error.to_string_lossy()),
+ ))) as *mut c_void
+ }
+ } else {
+ get_native_object_symbols(buf, f)
+ }
+}
+
impl<'a> LlvmArchiveBuilder<'a> {
fn build_with_llvm(&mut self, output: &Path) -> io::Result<bool> {
let kind = &*self.sess.target.archive_format;
- let kind = kind.parse::<ArchiveKind>().map_err(|_| kind).unwrap_or_else(|kind| {
- self.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))
- });
+ let kind = kind
+ .parse::<ArchiveKind>()
+ .map_err(|_| kind)
+ .unwrap_or_else(|kind| self.sess.emit_fatal(UnknownArchiveKind { kind }));
let mut additions = mem::take(&mut self.additions);
let mut strings = Vec::new();
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index a49cc7f8d..3fa21355b 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -1,4 +1,5 @@
use crate::back::write::{self, save_temp_bitcode, DiagnosticHandlers};
+use crate::errors::DynamicLinkingWithLTO;
use crate::llvm::{self, build_string};
use crate::{LlvmCodegenBackend, ModuleLlvm};
use object::read::archive::ArchiveFile;
@@ -90,13 +91,7 @@ fn prepare_lto(
}
if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
- diag_handler
- .struct_err("cannot prefer dynamic linking when performing LTO")
- .note(
- "only 'staticlib', 'bin', and 'cdylib' outputs are \
- supported with LTO",
- )
- .emit();
+ diag_handler.emit_err(DynamicLinkingWithLTO);
return Err(FatalError);
}
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 11053a8f6..97d0de47b 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -765,11 +765,21 @@ pub(crate) unsafe fn codegen(
drop(handlers);
}
+ // `.dwo` files are only emitted if:
+ //
+ // - Object files are being emitted (i.e. bitcode only or metadata only compilations will not
+ // produce dwarf objects, even if otherwise enabled)
+ // - Target supports Split DWARF
+ // - Split debuginfo is enabled
+ // - Split DWARF kind is `split` (i.e. debuginfo is split into `.dwo` files, not different
+ // sections in the `.o` files).
+ let dwarf_object_emitted = matches!(config.emit_obj, EmitObj::ObjectCode(_))
+ && cgcx.target_can_use_split_dwarf
+ && cgcx.split_debuginfo != SplitDebuginfo::Off
+ && cgcx.split_dwarf_kind == SplitDwarfKind::Split;
Ok(module.into_compiled_module(
config.emit_obj != EmitObj::None,
- cgcx.target_can_use_split_dwarf
- && cgcx.split_debuginfo != SplitDebuginfo::Off
- && cgcx.split_dwarf_kind == SplitDwarfKind::Split,
+ dwarf_object_emitted,
config.emit_bc,
&cgcx.output_filenames,
))