diff options
Diffstat (limited to 'compiler/rustc_codegen_llvm/src')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/back/write.rs | 102 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/lib.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm_util.rs | 21 |
3 files changed, 74 insertions, 55 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index fa4fad30830..3fceb2ac4ed 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -950,6 +950,29 @@ pub(crate) unsafe fn codegen( )) } +fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: &[u8]) -> Vec<u8> { + let mut asm = format!(".section {},\"{}\"\n", section_name, section_flags).into_bytes(); + asm.extend_from_slice(b".ascii \""); + asm.reserve(data.len()); + for &byte in data { + if byte == b'\\' || byte == b'"' { + asm.push(b'\\'); + asm.push(byte); + } else if byte < 0x20 || byte >= 0x80 { + // Avoid non UTF-8 inline assembly. Use octal escape sequence, because it is fixed + // width, while hex escapes will consume following characters. + asm.push(b'\\'); + asm.push(b'0' + ((byte >> 6) & 0x7)); + asm.push(b'0' + ((byte >> 3) & 0x7)); + asm.push(b'0' + ((byte >> 0) & 0x7)); + } else { + asm.push(byte); + } + } + asm.extend_from_slice(b"\"\n"); + asm +} + /// Embed the bitcode of an LLVM module in the LLVM module itself. /// /// This is done primarily for iOS where it appears to be standard to compile C @@ -975,34 +998,6 @@ unsafe fn embed_bitcode( cmdline: &str, bitcode: &[u8], ) { - let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - "rustc.embedded.module\0".as_ptr().cast(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); - - let is_apple = cgcx.opts.target_triple.triple().contains("-ios") - || cgcx.opts.target_triple.triple().contains("-darwin") - || cgcx.opts.target_triple.triple().contains("-tvos"); - - let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" }; - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); - - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - "rustc.embedded.cmdline\0".as_ptr().cast(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); - let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" }; - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); - // We're adding custom sections to the output object file, but we definitely // do not want these custom sections to make their way into the final linked // executable. The purpose of these custom sections is for tooling @@ -1024,31 +1019,54 @@ unsafe fn embed_bitcode( // * COFF - if we don't do anything the linker will by default copy all // these sections to the output artifact, not what we want! To subvert // this we want to flag the sections we inserted here as - // `IMAGE_SCN_LNK_REMOVE`. Unfortunately though LLVM has no native way to - // do this. Thankfully though we can do this with some inline assembly, - // which is easy enough to add via module-level global inline asm. + // `IMAGE_SCN_LNK_REMOVE`. // // * ELF - this is very similar to COFF above. One difference is that these // sections are removed from the output linked artifact when // `--gc-sections` is passed, which we pass by default. If that flag isn't // passed though then these sections will show up in the final output. // Additionally the flag that we need to set here is `SHF_EXCLUDE`. + // + // Unfortunately, LLVM provides no way to set custom section flags. For ELF + // and COFF we emit the sections using module level inline assembly for that + // reason (see issue #90326 for historical background). + let is_apple = cgcx.opts.target_triple.triple().contains("-ios") + || cgcx.opts.target_triple.triple().contains("-darwin") + || cgcx.opts.target_triple.triple().contains("-tvos"); if is_apple || cgcx.opts.target_triple.triple().starts_with("wasm") || cgcx.opts.target_triple.triple().starts_with("asmjs") { - // nothing to do here - } else if cgcx.is_pe_coff { - let asm = " - .section .llvmbc,\"n\" - .section .llvmcmd,\"n\" - "; - llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + // We don't need custom section flags, create LLVM globals. + let llconst = common::bytes_in_context(llcx, bitcode); + let llglobal = llvm::LLVMAddGlobal( + llmod, + common::val_ty(llconst), + "rustc.embedded.module\0".as_ptr().cast(), + ); + llvm::LLVMSetInitializer(llglobal, llconst); + + let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" }; + llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llglobal = llvm::LLVMAddGlobal( + llmod, + common::val_ty(llconst), + "rustc.embedded.cmdline\0".as_ptr().cast(), + ); + llvm::LLVMSetInitializer(llglobal, llconst); + let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" }; + llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); } else { - let asm = " - .section .llvmbc,\"e\" - .section .llvmcmd,\"e\" - "; + // We need custom section flags, so emit module-level inline assembly. + let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; + let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); + llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); } } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 62c17e6a10f..476371b878d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -6,11 +6,9 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] -#![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] #![feature(extern_types)] #![feature(in_band_lifetimes)] -#![feature(iter_zip)] #![feature(nll)] #![recursion_limit = "256"] @@ -340,6 +338,7 @@ impl CodegenBackend for LlvmCodegenBackend { &self, ongoing_codegen: Box<dyn Any>, sess: &Session, + outputs: &OutputFilenames, ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> { let (codegen_results, work_products) = ongoing_codegen .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>() @@ -348,7 +347,8 @@ impl CodegenBackend for LlvmCodegenBackend { sess.time("llvm_dump_timing_file", || { if sess.opts.debugging_opts.llvm_time_trace { - llvm_util::time_trace_profiler_finish("llvm_timings.json"); + let file_name = outputs.with_extension("llvm_timings.json"); + llvm_util::time_trace_profiler_finish(&file_name); } }); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 3393c9baa28..e4935ac431c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -1,9 +1,10 @@ use crate::back::write::create_informational_target_machine; use crate::{llvm, llvm_util}; use libc::c_int; +use libloading::Library; use rustc_codegen_ssa::target_features::supported_target_features; use rustc_data_structures::fx::FxHashSet; -use rustc_metadata::dynamic_lib::DynamicLibrary; +use rustc_fs_util::path_to_c_string; use rustc_middle::bug; use rustc_session::config::PrintRequest; use rustc_session::Session; @@ -120,14 +121,14 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMInitializePasses(); + // Register LLVM plugins by loading them into the compiler process. for plugin in &sess.opts.debugging_opts.llvm_plugins { - let path = Path::new(plugin); - let res = DynamicLibrary::open(path); - match res { - Ok(_) => debug!("LLVM plugin loaded succesfully {} ({})", path.display(), plugin), - Err(e) => bug!("couldn't load plugin: {}", e), - } - mem::forget(res); + let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e)); + debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin); + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long. + mem::forget(lib); } rustc_llvm::initialize_available_targets(); @@ -135,9 +136,9 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); } -pub fn time_trace_profiler_finish(file_name: &str) { +pub fn time_trace_profiler_finish(file_name: &Path) { unsafe { - let file_name = CString::new(file_name).unwrap(); + let file_name = path_to_c_string(file_name); llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr()); } } |
