diff options
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back')
-rw-r--r-- | compiler/rustc_codegen_ssa/src/back/archive.rs | 3 | ||||
-rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 67 | ||||
-rw-r--r-- | compiler/rustc_codegen_ssa/src/back/linker.rs | 131 | ||||
-rw-r--r-- | compiler/rustc_codegen_ssa/src/back/metadata.rs | 27 | ||||
-rw-r--r-- | compiler/rustc_codegen_ssa/src/back/symbol_export.rs | 36 | ||||
-rw-r--r-- | compiler/rustc_codegen_ssa/src/back/write.rs | 51 |
6 files changed, 207 insertions, 108 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 1c464b3ec..4dc28adf3 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -175,8 +175,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { ) -> io::Result<()> { let mut archive_path = archive_path.to_path_buf(); if self.sess.target.llvm_target.contains("-apple-macosx") { - if let Some(new_archive_path) = - try_extract_macho_fat_archive(&self.sess, &archive_path)? + if let Some(new_archive_path) = try_extract_macho_fat_archive(self.sess, &archive_path)? { archive_path = new_archive_path } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index dd9d277fb..b0d22ad0a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::{ErrorGuaranteed, Handler}; +use rustc_errors::{DiagCtxt, ErrorGuaranteed}; use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; @@ -44,7 +44,7 @@ use tempfile::Builder as TempFileBuilder; use itertools::Itertools; use std::cell::OnceCell; use std::collections::BTreeSet; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fs::{read, File, OpenOptions}; use std::io::{BufWriter, Write}; use std::ops::Deref; @@ -52,10 +52,10 @@ use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{env, fmt, fs, io, mem, str}; -pub fn ensure_removed(diag_handler: &Handler, path: &Path) { +pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) { if let Err(e) = fs::remove_file(path) { if e.kind() != io::ErrorKind::NotFound { - diag_handler.err(format!("failed to remove {}: {}", path.display(), e)); + dcx.err(format!("failed to remove {}: {}", path.display(), e)); } } } @@ -143,7 +143,7 @@ pub fn link_binary<'a>( } } if sess.opts.json_artifact_notifications { - sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link"); + sess.dcx().emit_artifact_notification(&out_filename, "link"); } if sess.prof.enabled() { @@ -183,13 +183,13 @@ pub fn link_binary<'a>( |preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| { if !preserve_objects { if let Some(ref obj) = module.object { - ensure_removed(sess.diagnostic(), obj); + ensure_removed(sess.dcx(), obj); } } if !preserve_dwarf_objects { if let Some(ref dwo_obj) = module.dwarf_object { - ensure_removed(sess.diagnostic(), dwo_obj); + ensure_removed(sess.dcx(), dwo_obj); } } }; @@ -208,7 +208,7 @@ pub fn link_binary<'a>( // Remove the temporary files if output goes to stdout for temp in tempfiles_for_stdout_output { - ensure_removed(sess.diagnostic(), &temp); + ensure_removed(sess.dcx(), &temp); } // If no requested outputs require linking, then the object temporaries should @@ -277,7 +277,7 @@ pub fn each_linked_rlib( let crate_name = info.crate_name[&cnum]; let used_crate_source = &info.used_crate_source[&cnum]; if let Some((path, _)) = &used_crate_source.rlib { - f(cnum, &path); + f(cnum, path); } else { if used_crate_source.rmeta.is_some() { return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name }); @@ -524,7 +524,7 @@ fn link_staticlib<'a>( && !ignored_for_lto(sess, &codegen_results.crate_info, cnum); let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter(); - let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, &lib)); + let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib)); let relevant_libs: FxHashSet<_> = relevant.filter_map(|lib| lib.filename).collect(); let bundled_libs: FxHashSet<_> = native_libs.filter_map(|lib| lib.filename).collect(); @@ -689,7 +689,7 @@ fn link_dwarf_object<'a>( // Adding an executable is primarily done to make `thorin` check that all the referenced // dwarf objects are found in the end. package.add_executable( - &executable_out_filename, + executable_out_filename, thorin::MissingReferencedObjectBehaviour::Skip, )?; @@ -928,7 +928,7 @@ fn link_natively<'a>( command: &cmd, escaped_output, }; - sess.diagnostic().emit_err(err); + sess.dcx().emit_err(err); // If MSVC's `link.exe` was expected but the return code // is not a Microsoft LNK error then suggest a way to fix or // install the Visual Studio build tools. @@ -945,7 +945,7 @@ fn link_natively<'a>( { let is_vs_installed = windows_registry::find_vs_version().is_ok(); let has_linker = windows_registry::find_tool( - &sess.opts.target_triple.triple(), + sess.opts.target_triple.triple(), "link.exe", ) .is_some(); @@ -1038,14 +1038,14 @@ fn link_natively<'a>( if sess.target.is_like_osx { match (strip, crate_type) { (Strip::Debuginfo, _) => { - strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-S")) + strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-S")) } // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988) (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => { - strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-x")) + strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-x")) } (Strip::Symbols, _) => { - strip_symbols_with_external_utility(sess, "strip", &out_filename, None) + strip_symbols_with_external_utility(sess, "strip", out_filename, None) } (Strip::None, _) => {} } @@ -1059,7 +1059,7 @@ fn link_natively<'a>( match strip { // Always preserve the symbol table (-x). Strip::Debuginfo => { - strip_symbols_with_external_utility(sess, stripcmd, &out_filename, Some("-x")) + strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-x")) } // Strip::Symbols is handled via the --strip-all linker option. Strip::Symbols => {} @@ -1245,13 +1245,13 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { // rpath to the library as well (the rpath should be absolute, see // PR #41352 for details). let filename = format!("rustc{channel}_rt.{name}"); - let path = find_sanitizer_runtime(&sess, &filename); + let path = find_sanitizer_runtime(sess, &filename); let rpath = path.to_str().expect("non-utf8 component in path"); linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); linker.link_dylib(&filename, false, true); } else { let filename = format!("librustc{channel}_rt.{name}.a"); - let path = find_sanitizer_runtime(&sess, &filename).join(&filename); + let path = find_sanitizer_runtime(sess, &filename).join(&filename); linker.link_whole_rlib(&path); } } @@ -1477,7 +1477,7 @@ fn print_native_static_libs( sess.emit_note(errors::StaticLibraryNativeArtifacts); // Prefix for greppability // Note: This must not be translated as tools are allowed to depend on this exact string. - sess.note_without_error(format!("native-static-libs: {}", &lib_args.join(" "))); + sess.note(format!("native-static-libs: {}", &lib_args.join(" "))); } } } @@ -1685,7 +1685,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { // Returns true if linker is located within sysroot fn detect_self_contained_mingw(sess: &Session) -> bool { - let (linker, _) = linker_and_flavor(&sess); + let (linker, _) = linker_and_flavor(sess); // Assume `-C linker=rust-lld` as self-contained mode if linker == Path::new("rust-lld") { return true; @@ -1737,7 +1737,7 @@ fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfC LinkSelfContainedDefault::InferredForMingw => { sess.host == sess.target && sess.target.vendor != "uwp" - && detect_self_contained_mingw(&sess) + && detect_self_contained_mingw(sess) } } }; @@ -2243,9 +2243,9 @@ fn linker_with_args<'a>( // ------------ Late order-dependent options ------------ // Doesn't really make sense. - // FIXME: In practice built-in target specs use this for arbitrary order-independent options, - // introduce a target spec option for order-independent linker options, migrate built-in specs - // to it and remove the option. + // FIXME: In practice built-in target specs use this for arbitrary order-independent options. + // Introduce a target spec option for order-independent linker options, migrate built-in specs + // to it and remove the option. Currently the last holdout is wasm32-unknown-emscripten. add_post_link_args(cmd, sess, flavor); Ok(cmd.take_cmd()) @@ -2378,6 +2378,11 @@ fn add_order_independent_options( cmd.control_flow_guard(); } + // OBJECT-FILES-NO, AUDIT-ORDER + if sess.opts.unstable_opts.ehcont_guard { + cmd.ehcont_guard(); + } + add_rpath_args(cmd, sess, codegen_results, out_filename); } @@ -2432,7 +2437,7 @@ fn add_native_libs_from_crate( // If rlib contains native libs as archives, unpack them to tmpdir. let rlib = &codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0; archive_builder_builder - .extract_bundled_libs(rlib, tmpdir, &bundled_libs) + .extract_bundled_libs(rlib, tmpdir, bundled_libs) .unwrap_or_else(|e| sess.emit_fatal(e)); } @@ -2485,7 +2490,7 @@ fn add_native_libs_from_crate( cmd.link_whole_staticlib( name, verbatim, - &search_paths.get_or_init(|| archive_search_paths(sess)), + search_paths.get_or_init(|| archive_search_paths(sess)), ); } else { cmd.link_staticlib(name, verbatim) @@ -2522,7 +2527,7 @@ fn add_native_libs_from_crate( NativeLibKind::WasmImportModule => {} NativeLibKind::LinkArg => { if link_static { - cmd.arg(name); + cmd.linker_arg(OsStr::new(name), verbatim); } } } @@ -2719,7 +2724,7 @@ fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf { // already had `fix_windows_verbatim_for_gcc()` applied if needed. sysroot_lib_path } else { - fix_windows_verbatim_for_gcc(&lib_dir) + fix_windows_verbatim_for_gcc(lib_dir) } } @@ -2756,7 +2761,7 @@ fn add_static_crate<'a>( let mut link_upstream = |path: &Path| { let rlib_path = if let Some(dir) = path.parent() { let file_name = path.file_name().expect("rlib path has no file name path component"); - rehome_sysroot_lib_dir(sess, &dir).join(file_name) + rehome_sysroot_lib_dir(sess, dir).join(file_name) } else { fix_windows_verbatim_for_gcc(path) }; @@ -2793,7 +2798,7 @@ fn add_static_crate<'a>( let canonical = f.replace('-', "_"); let is_rust_object = - canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f); + canonical.starts_with(&canonical_name) && looks_like_rust_object_file(f); // If we're performing LTO and this is a rust-generated object // file, then we don't need the object file as it's part of the diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 09434513e..eeb57d4d0 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -45,7 +45,7 @@ pub fn get_linker<'a>( self_contained: bool, target_cpu: &'a str, ) -> Box<dyn Linker + 'a> { - let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe"); + let msvc_tool = windows_registry::find_tool(sess.opts.target_triple.triple(), "link.exe"); // If our linker looks like a batch script on Windows then to execute this // we'll need to spawn `cmd` explicitly. This is primarily done to handle @@ -78,7 +78,7 @@ pub fn get_linker<'a>( if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" { if let Some(ref tool) = msvc_tool { let original_path = tool.path(); - if let Some(ref root_lib_path) = original_path.ancestors().nth(4) { + if let Some(root_lib_path) = original_path.ancestors().nth(4) { let arch = match t.arch.as_ref() { "x86_64" => Some("x64"), "x86" => Some("x86"), @@ -185,6 +185,7 @@ pub trait Linker { fn optimize(&mut self); fn pgo_gen(&mut self); fn control_flow_guard(&mut self); + fn ehcont_guard(&mut self); fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); @@ -195,6 +196,14 @@ pub trait Linker { fn add_no_exec(&mut self) {} fn add_as_needed(&mut self) {} fn reset_per_library_state(&mut self) {} + fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) { + self.linker_args(&[arg], verbatim); + } + fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) { + args.into_iter().for_each(|a| { + self.cmd().arg(a); + }); + } } impl dyn Linker + '_ { @@ -222,38 +231,12 @@ pub struct GccLinker<'a> { } impl<'a> GccLinker<'a> { - /// Passes an argument directly to the linker. - /// - /// When the linker is not ld-like such as when using a compiler as a linker, the argument is - /// prepended by `-Wl,`. - fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { - self.linker_args(&[arg]); - self + fn linker_arg(&mut self, arg: impl AsRef<OsStr>) { + Linker::linker_arg(self, arg.as_ref(), false); } - - /// Passes a series of arguments directly to the linker. - /// - /// When the linker is ld-like, the arguments are simply appended to the command. When the - /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by - /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a - /// single argument is appended to the command to ensure that the order of the arguments is - /// preserved by the compiler. - fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self { - if self.is_ld { - args.into_iter().for_each(|a| { - self.cmd.arg(a); - }); - } else { - if !args.is_empty() { - let mut s = OsString::from("-Wl"); - for a in args { - s.push(","); - s.push(a); - } - self.cmd.arg(s); - } - } - self + fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) { + let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect(); + Linker::linker_args(self, &args_vec, false); } fn takes_hints(&self) -> bool { @@ -360,6 +343,30 @@ impl<'a> GccLinker<'a> { } impl<'a> Linker for GccLinker<'a> { + /// Passes a series of arguments directly to the linker. + /// + /// When the linker is ld-like, the arguments are simply appended to the command. When the + /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by + /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a + /// single argument is appended to the command to ensure that the order of the arguments is + /// preserved by the compiler. + fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) { + if self.is_ld || verbatim { + args.into_iter().for_each(|a| { + self.cmd.arg(a); + }); + } else { + if !args.is_empty() { + let mut s = OsString::from("-Wl"); + for a in args { + s.push(","); + s.push(a); + } + self.cmd.arg(s); + } + } + } + fn cmd(&mut self) -> &mut Command { &mut self.cmd } @@ -519,7 +526,7 @@ impl<'a> Linker for GccLinker<'a> { // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. self.linker_arg("-force_load"); - let lib = find_native_static_library(lib, verbatim, search_path, &self.sess); + let lib = find_native_static_library(lib, verbatim, search_path, self.sess); self.linker_arg(&lib); } } @@ -530,7 +537,7 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("-force_load"); self.linker_arg(&lib); } else { - self.linker_arg("--whole-archive").cmd.arg(lib); + self.linker_args(&[OsString::from("--whole-archive"), lib.into()]); self.linker_arg("--no-whole-archive"); } } @@ -605,6 +612,8 @@ impl<'a> Linker for GccLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { // MacOS linker doesn't support stripping symbols directly anymore. if self.sess.target.is_like_osx { @@ -914,6 +923,12 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/guard:cf"); } + fn ehcont_guard(&mut self) { + if self.sess.target.pointer_width == 64 { + self.cmd.arg("/guard:ehcont"); + } + } + fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { match strip { Strip::None => { @@ -1127,6 +1142,8 @@ impl<'a> Linker for EmLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { // Preserve names or generate source maps depending on debug info // For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g @@ -1291,6 +1308,8 @@ impl<'a> Linker for WasmLd<'a> { } fn optimize(&mut self) { + // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and + // only differentiates -O0 and -O1. It does not apply to LTO. self.cmd.arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", @@ -1319,6 +1338,8 @@ impl<'a> Linker for WasmLd<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn no_crt_objects(&mut self) {} fn no_default_libraries(&mut self) {} @@ -1341,7 +1362,31 @@ impl<'a> Linker for WasmLd<'a> { fn subsystem(&mut self, _subsystem: &str) {} fn linker_plugin_lto(&mut self) { - // Do nothing for now + match self.sess.opts.cg.linker_plugin_lto { + LinkerPluginLto::Disabled => { + // Nothing to do + } + LinkerPluginLto::LinkerPluginAuto => { + self.push_linker_plugin_lto_args(); + } + LinkerPluginLto::LinkerPlugin(_) => { + self.push_linker_plugin_lto_args(); + } + } + } +} + +impl<'a> WasmLd<'a> { + fn push_linker_plugin_lto_args(&mut self) { + let opt_level = match self.sess.opts.optimize { + config::OptLevel::No => "O0", + config::OptLevel::Less => "O1", + config::OptLevel::Default => "O2", + config::OptLevel::Aggressive => "O3", + // wasm-ld only handles integer LTO opt levels. Use O2 + config::OptLevel::Size | config::OptLevel::SizeMin => "O2", + }; + self.cmd.arg(&format!("--lto-{opt_level}")); } } @@ -1472,6 +1517,8 @@ impl<'a> Linker for L4Bender<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn no_crt_objects(&mut self) {} } @@ -1590,7 +1637,7 @@ impl<'a> Linker for AixLinker<'a> { fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { self.hint_static(); - let lib = find_native_static_library(lib, verbatim, search_path, &self.sess); + let lib = find_native_static_library(lib, verbatim, search_path, self.sess); self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); } @@ -1613,6 +1660,8 @@ impl<'a> Linker for AixLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { match strip { Strip::None => {} @@ -1699,7 +1748,9 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) - let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { if info.level.is_below_threshold(export_threshold) { - symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum)); + symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate( + tcx, symbol, cnum, + )); } }); @@ -1835,6 +1886,8 @@ impl<'a> Linker for PtxLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {} fn subsystem(&mut self, _subsystem: &str) {} @@ -1931,6 +1984,8 @@ impl<'a> Linker for BpfLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { let path = tmpdir.join("symbols"); let res: io::Result<()> = try { diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index cb60ed729..b683e1b45 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -12,9 +12,9 @@ use object::{ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; +use rustc_metadata::creader::MetadataLoader; use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; -use rustc_session::cstore::MetadataLoader; use rustc_session::Session; use rustc_span::sym; use rustc_target::abi::Endian; @@ -158,11 +158,12 @@ pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a file.symbols().find(|sym| sym.name() == Ok(AIX_METADATA_SYMBOL_NAME)) { let offset = metadata_symbol.address() as usize; + // The offset specifies the location of rustc metadata in the .info section of XCOFF. + // Each string stored in .info section of XCOFF is preceded by a 4-byte length field. if offset < 4 { return Err(format!("Invalid metadata symbol offset: {offset}")); } - // The offset specifies the location of rustc metadata in the comment section. - // The metadata is preceded by a 4-byte length field. + // XCOFF format uses big-endian byte order. let len = u32::from_be_bytes(info_data[(offset - 4)..offset].try_into().unwrap()) as usize; if offset + len > (info_data.len() as usize) { return Err(format!( @@ -226,6 +227,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static let mut file = write::Object::new(binary_format, architecture, endianness); if sess.target.is_like_osx { + if macho_is_arm64e(&sess.target) { + file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E); + } + file.set_macho_build_version(macho_object_build_version_for_target(&sess.target)) } if binary_format == BinaryFormat::Coff { @@ -385,6 +390,11 @@ fn macho_object_build_version_for_target(target: &Target) -> object::write::Mach build_version } +/// Is Apple's CPU subtype `arm64e`s +fn macho_is_arm64e(target: &Target) -> bool { + return target.llvm_target.starts_with("arm64e"); +} + pub enum MetadataPosition { First, Last, @@ -469,8 +479,11 @@ pub fn create_wrapper_file( file.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text); file.section_mut(section).flags = SectionFlags::Xcoff { s_flags: xcoff::STYP_INFO as u32 }; - - let len = data.len() as u32; + // Encode string stored in .info section of XCOFF. + // FIXME: The length of data here is not guaranteed to fit in a u32. + // We may have to split the data into multiple pieces in order to + // store in .info section. + let len: u32 = data.len().try_into().unwrap(); let offset = file.append_section_data(section, &len.to_be_bytes(), 1); // Add a symbol referring to the data in .info section. file.add_symbol(Symbol { @@ -515,7 +528,7 @@ pub fn create_compressed_metadata_file( symbol_name: &str, ) -> Vec<u8> { let mut packed_metadata = rustc_metadata::METADATA_HEADER.to_vec(); - packed_metadata.write_all(&(metadata.raw_data().len() as u32).to_be_bytes()).unwrap(); + packed_metadata.write_all(&(metadata.raw_data().len() as u64).to_le_bytes()).unwrap(); packed_metadata.extend(metadata.raw_data()); let Some(mut file) = create_object_file(sess) else { @@ -590,7 +603,7 @@ pub fn create_compressed_metadata_file_for_xcoff( section: SymbolSection::Section(data_section), flags: SymbolFlags::None, }); - let len = data.len() as u32; + let len: u32 = data.len().try_into().unwrap(); let offset = file.append_section_data(section, &len.to_be_bytes(), 1); // Add a symbol referring to the rustc metadata. file.add_symbol(Symbol { diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 9cd439410..ff667eecf 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{self, SymbolName, TyCtxt}; use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; use rustc_middle::util::Providers; use rustc_session::config::{CrateType, OomStrategy}; -use rustc_target::spec::SanitizerSet; +use rustc_target::spec::{SanitizerSet, TlsModel}; pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(tcx.crate_types()) @@ -548,6 +548,12 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>( let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); + // thread local will not be a function call, + // so it is safe to return before windows symbol decoration check. + if let Some(name) = maybe_emutls_symbol_name(tcx, symbol, &undecorated) { + return name; + } + let target = &tcx.sess.target; if !target.is_like_windows { // Mach-O has a global "_" suffix and `object` crate will handle it. @@ -608,6 +614,32 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>( format!("{prefix}{undecorated}{suffix}{args_in_bytes}") } +pub fn exporting_symbol_name_for_instance_in_crate<'tcx>( + tcx: TyCtxt<'tcx>, + symbol: ExportedSymbol<'tcx>, + cnum: CrateNum, +) -> String { + let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, cnum); + maybe_emutls_symbol_name(tcx, symbol, &undecorated).unwrap_or(undecorated) +} + +fn maybe_emutls_symbol_name<'tcx>( + tcx: TyCtxt<'tcx>, + symbol: ExportedSymbol<'tcx>, + undecorated: &str, +) -> Option<String> { + if matches!(tcx.sess.tls_model(), TlsModel::Emulated) + && let ExportedSymbol::NonGeneric(def_id) = symbol + && tcx.is_thread_local_static(def_id) + { + // When using emutls, LLVM will add the `__emutls_v.` prefix to thread local symbols, + // and exported symbol name need to match this. + Some(format!("__emutls_v.{undecorated}")) + } else { + None + } +} + fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> { // Build up a map from DefId to a `NativeLib` structure, where // `NativeLib` internally contains information about @@ -621,7 +653,7 @@ fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, S let mut ret = FxHashMap::default(); for (def_id, lib) in tcx.foreign_modules(cnum).iter() { - let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module()); + let module = def_id_to_native_lib.get(def_id).and_then(|s| s.wasm_import_module()); let Some(module) = module else { continue }; ret.extend(lib.foreign_items.iter().map(|id| { assert_eq!(id.krate, cnum); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 3d6a21243..d80ef1eba 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -14,7 +14,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; -use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level}; +use rustc_errors::{translation::Translate, DiagCtxt, DiagnosticId, FatalError, Level}; use rustc_errors::{DiagnosticMessage, Style}; use rustc_fs_util::link_or_copy; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; @@ -355,7 +355,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { /// how to call the compiler with the same arguments. pub expanded_args: Vec<String>, - /// Handler to use for diagnostics produced during codegen. + /// Emitter to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, /// LLVM optimizations for which we want to print remarks. pub remark: Passes, @@ -370,8 +370,8 @@ pub struct CodegenContext<B: WriteBackendMethods> { } impl<B: WriteBackendMethods> CodegenContext<B> { - pub fn create_diag_handler(&self) -> Handler { - Handler::with_emitter(Box::new(self.diag_emitter.clone())) + pub fn create_dcx(&self) -> DiagCtxt { + DiagCtxt::with_emitter(Box::new(self.diag_emitter.clone())) } pub fn config(&self, kind: ModuleKind) -> &ModuleConfig { @@ -569,7 +569,7 @@ fn produce_final_output_artifacts( } if !sess.opts.cg.save_temps && !keep_numbered { // The user just wants `foo.x`, not `foo.#module-name#.x`. - ensure_removed(sess.diagnostic(), &path); + ensure_removed(sess.dcx(), &path); } } else { let extension = crate_output @@ -660,19 +660,19 @@ fn produce_final_output_artifacts( for module in compiled_modules.modules.iter() { if let Some(ref path) = module.object { if !keep_numbered_objects { - ensure_removed(sess.diagnostic(), path); + ensure_removed(sess.dcx(), path); } } if let Some(ref path) = module.dwarf_object { if !keep_numbered_objects { - ensure_removed(sess.diagnostic(), path); + ensure_removed(sess.dcx(), path); } } if let Some(ref path) = module.bytecode { if !keep_numbered_bitcode { - ensure_removed(sess.diagnostic(), path); + ensure_removed(sess.dcx(), path); } } } @@ -680,7 +680,7 @@ fn produce_final_output_artifacts( if !user_wants_bitcode { if let Some(ref allocator_module) = compiled_modules.allocator_module { if let Some(ref path) = allocator_module.bytecode { - ensure_removed(sess.diagnostic(), path); + ensure_removed(sess.dcx(), path); } } } @@ -836,10 +836,10 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>( module: ModuleCodegen<B::Module>, module_config: &ModuleConfig, ) -> Result<WorkItemResult<B>, FatalError> { - let diag_handler = cgcx.create_diag_handler(); + let dcx = cgcx.create_dcx(); unsafe { - B::optimize(cgcx, &diag_handler, &module, module_config)?; + B::optimize(cgcx, &dcx, &module, module_config)?; } // After we've done the initial round of optimizations we need to @@ -892,7 +892,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| { - let source_file = in_incr_comp_dir(&incr_comp_session_dir, saved_path); + let source_file = in_incr_comp_dir(incr_comp_session_dir, saved_path); debug!( "copying preexisting module `{}` from {:?} to {}", module.name, @@ -902,11 +902,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( match link_or_copy(&source_file, &output_path) { Ok(_) => Some(output_path), Err(error) => { - cgcx.create_diag_handler().emit_err(errors::CopyPathBuf { - source_file, - output_path, - error, - }); + cgcx.create_dcx().emit_err(errors::CopyPathBuf { source_file, output_path, error }); None } } @@ -914,7 +910,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( let object = load_from_incr_comp_dir( cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)), - &module.source.saved_files.get("o").expect("no saved object file in work product"), + module.source.saved_files.get("o").expect("no saved object file in work product"), ); let dwarf_object = module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| { @@ -924,7 +920,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( .expect( "saved dwarf object in work product but `split_dwarf_path` returned `None`", ); - load_from_incr_comp_dir(dwarf_obj_out, &saved_dwarf_object_file) + load_from_incr_comp_dir(dwarf_obj_out, saved_dwarf_object_file) }); WorkItemResult::Finished(CompiledModule { @@ -950,13 +946,13 @@ fn finish_intra_module_work<B: ExtraBackendMethods>( module: ModuleCodegen<B::Module>, module_config: &ModuleConfig, ) -> Result<WorkItemResult<B>, FatalError> { - let diag_handler = cgcx.create_diag_handler(); + let dcx = cgcx.create_dcx(); if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Metadata || module.kind == ModuleKind::Allocator { - let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; + let module = unsafe { B::codegen(cgcx, &dcx, module, module_config)? }; Ok(WorkItemResult::Finished(module)) } else { Ok(WorkItemResult::NeedsLink(module)) @@ -1609,11 +1605,10 @@ fn start_executing_work<B: ExtraBackendMethods>( let needs_link = mem::take(&mut needs_link); if !needs_link.is_empty() { assert!(compiled_modules.is_empty()); - let diag_handler = cgcx.create_diag_handler(); - let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?; + let dcx = cgcx.create_dcx(); + let module = B::run_link(&cgcx, &dcx, needs_link).map_err(|_| ())?; let module = unsafe { - B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular)) - .map_err(|_| ())? + B::codegen(&cgcx, &dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())? }; compiled_modules.push(module); } @@ -1856,13 +1851,13 @@ impl SharedEmitterMain { match message { Ok(SharedEmitterMessage::Diagnostic(diag)) => { - let handler = sess.diagnostic(); + let dcx = sess.dcx(); let mut d = rustc_errors::Diagnostic::new_with_messages(diag.lvl, diag.msg); if let Some(code) = diag.code { d.code(code); } d.replace_args(diag.args); - handler.emit_diagnostic(&mut d); + dcx.emit_diagnostic(d); } Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); @@ -1870,7 +1865,7 @@ impl SharedEmitterMain { let mut err = match level { Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(), Level::Warning(_) => sess.struct_warn(msg), - Level::Note => sess.struct_note_without_error(msg), + Level::Note => sess.struct_note(msg), _ => bug!("Invalid inline asm diagnostic level"), }; |