diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 9e1b1f7db2f99..8f393a4c57371 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -77,7 +77,7 @@ pub fn find(build: &mut Build) { .collect::>(); for target in targets.into_iter() { let mut cfg = cc::Build::new(); - cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false) + cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false) .target(&target).host(&build.build); if target.contains("msvc") { cfg.static_crt(true); @@ -109,7 +109,7 @@ pub fn find(build: &mut Build) { let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::>(); for host in hosts.into_iter() { let mut cfg = cc::Build::new(); - cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true) + cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false).cpp(true) .target(&host).host(&build.build); let config = build.config.target_config.get(&host); if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 1c5cfa87ef46f..3e894abd17c9b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1288,6 +1288,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "run `dsymutil` and delete intermediate object files"), ui_testing: bool = (false, parse_bool, [UNTRACKED], "format compiler diagnostics in a way that's better suitable for UI testing"), + embed_bitcode: bool = (false, parse_bool, [TRACKED], + "embed LLVM bitcode in object files"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 250d85d45203e..f53eeb86a9c56 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -473,6 +473,9 @@ pub struct TargetOptions { /// The default visibility for symbols in this target should be "hidden" /// rather than "default" pub default_hidden_visibility: bool, + + /// Whether or not bitcode is embedded in object files + pub embed_bitcode: bool, } impl Default for TargetOptions { @@ -544,6 +547,7 @@ impl Default for TargetOptions { i128_lowering: false, codegen_backend: "llvm".to_string(), default_hidden_visibility: false, + embed_bitcode: false, } } } @@ -792,6 +796,7 @@ impl Target { key!(no_builtins, bool); key!(codegen_backend); key!(default_hidden_visibility, bool); + key!(embed_bitcode, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -990,6 +995,7 @@ impl ToJson for Target { target_option_val!(no_builtins); target_option_val!(codegen_backend); target_option_val!(default_hidden_visibility); + target_option_val!(embed_bitcode); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 7651a8e748e3c..3e7422557e9b6 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -42,6 +42,7 @@ use syntax_pos::MultiSpan; use syntax_pos::symbol::Symbol; use type_::Type; use context::{is_pie_binary, get_reloc_model}; +use common::{C_bytes_in_context, val_ty}; use jobserver::{Client, Acquired}; use rustc_demangle; @@ -262,6 +263,8 @@ pub struct ModuleConfig { // emscripten's ecc compiler, when used as the linker. obj_is_bitcode: bool, no_integrated_as: bool, + embed_bitcode: bool, + embed_bitcode_marker: bool, } impl ModuleConfig { @@ -279,6 +282,8 @@ impl ModuleConfig { emit_asm: false, emit_obj: false, obj_is_bitcode: false, + embed_bitcode: false, + embed_bitcode_marker: false, no_integrated_as: false, no_verify: false, @@ -299,6 +304,17 @@ impl ModuleConfig { self.time_passes = sess.time_passes(); self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; + let embed_bitcode = sess.target.target.options.embed_bitcode || + sess.opts.debugging_opts.embed_bitcode; + if embed_bitcode { + match sess.opts.optimize { + config::OptLevel::No | + config::OptLevel::Less => { + self.embed_bitcode_marker = embed_bitcode; + } + _ => self.embed_bitcode = embed_bitcode, + } + } // Copy what clang does by turning on loop vectorization at O2 and // slp vectorization at O3. Otherwise configure other optimization aspects @@ -662,7 +678,7 @@ unsafe fn codegen(cgcx: &CodegenContext, let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); - if write_bc || config.emit_bc_compressed { + if write_bc || config.emit_bc_compressed || config.embed_bitcode { let thin; let old; let data = if llvm::LLVMRustThinLTOAvailable() { @@ -681,6 +697,11 @@ unsafe fn codegen(cgcx: &CodegenContext, timeline.record("write-bc"); } + if config.embed_bitcode { + embed_bitcode(cgcx, llcx, llmod, Some(data)); + timeline.record("embed-bc"); + } + if config.emit_bc_compressed { let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); let data = bytecode::encode(&mtrans.llmod_id, data); @@ -689,6 +710,8 @@ unsafe fn codegen(cgcx: &CodegenContext, } timeline.record("compress-bc"); } + } else if config.embed_bitcode_marker { + embed_bitcode(cgcx, llcx, llmod, None); } time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), @@ -796,6 +819,59 @@ unsafe fn codegen(cgcx: &CodegenContext, &cgcx.output_filenames)) } +/// 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 +/// code at least with `-fembed-bitcode` which creates two sections in the +/// executable: +/// +/// * __LLVM,__bitcode +/// * __LLVM,__cmdline +/// +/// It appears *both* of these sections are necessary to get the linker to +/// recognize what's going on. For us though we just always throw in an empty +/// cmdline section. +/// +/// Furthermore debug/O1 builds don't actually embed bitcode but rather just +/// embed an empty section. +/// +/// Basically all of this is us attempting to follow in the footsteps of clang +/// on iOS. See #35968 for lots more info. +unsafe fn embed_bitcode(cgcx: &CodegenContext, + llcx: ContextRef, + llmod: ModuleRef, + bitcode: Option<&[u8]>) { + let llconst = C_bytes_in_context(llcx, bitcode.unwrap_or(&[])); + let llglobal = llvm::LLVMAddGlobal( + llmod, + val_ty(llconst).to_ref(), + "rustc.embedded.module\0".as_ptr() as *const _, + ); + llvm::LLVMSetInitializer(llglobal, llconst); + let section = if cgcx.opts.target_triple.contains("-ios") { + "__LLVM,__bitcode\0" + } else { + ".llvmbc\0" + }; + llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + + let llconst = C_bytes_in_context(llcx, &[]); + let llglobal = llvm::LLVMAddGlobal( + llmod, + val_ty(llconst).to_ref(), + "rustc.embedded.cmdline\0".as_ptr() as *const _, + ); + llvm::LLVMSetInitializer(llglobal, llconst); + let section = if cgcx.opts.target_triple.contains("-ios") { + "__LLVM,__cmdline\0" + } else { + ".llvmcmd\0" + }; + llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); +} + pub(crate) struct CompiledModules { pub modules: Vec, pub metadata_module: CompiledModule, diff --git a/src/libstd/build.rs b/src/libstd/build.rs index a41c155f3fb52..6652ff98201a0 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -86,6 +86,7 @@ fn main() { fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?; + let cflags = env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden -O2"; run(Command::new("sh") .current_dir(&native.out_dir) @@ -98,7 +99,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { .arg("--disable-host-shared") .arg(format!("--host={}", build_helper::gnu_target(target))) .arg(format!("--build={}", build_helper::gnu_target(host))) - .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden")); + .env("CFLAGS", cflags)); run(Command::new(build_helper::make(host)) .current_dir(&native.out_dir)