From 342aad1d1b88a37361bf3a704750217b4fb4039d Mon Sep 17 00:00:00 2001 From: Tom Karpiniec Date: Thu, 7 May 2020 12:26:18 +1000 Subject: [PATCH 1/3] Force embed-bitcode on non-simulator iOS/tvOS targets At this time Apple recommends Bitcode be included for iOS apps, and requires it for tvOS. It is unlikely that a developer would want to disable bitcode when building for these targets, yet by default it will not be generated. This presents a papercut for developers on those platforms. Introduces a new TargetOption boolean key for specific triples to indicate that bitcode should be generated, even if cargo attempts to optimise with -Cembed-bitcode=no. --- src/librustc_codegen_ssa/back/write.rs | 2 ++ src/librustc_target/spec/aarch64_apple_ios.rs | 1 + src/librustc_target/spec/aarch64_apple_tvos.rs | 1 + src/librustc_target/spec/mod.rs | 5 +++++ 4 files changed, 9 insertions(+) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 5c3444eff0a11..72c4539e82908 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -147,6 +147,8 @@ impl ModuleConfig { || sess.opts.cg.linker_plugin_lto.enabled() { EmitObj::Bitcode + } else if sess.target.target.options.forces_embed_bitcode { + EmitObj::ObjectCode(BitcodeSection::Full) } else if need_crate_bitcode_for_rlib(sess) { let force_full = need_crate_bitcode_for_rlib(sess); match sess.opts.optimize { diff --git a/src/librustc_target/spec/aarch64_apple_ios.rs b/src/librustc_target/spec/aarch64_apple_ios.rs index e896b46da9a62..3ecedd769fae4 100644 --- a/src/librustc_target/spec/aarch64_apple_ios.rs +++ b/src/librustc_target/spec/aarch64_apple_ios.rs @@ -19,6 +19,7 @@ pub fn target() -> TargetResult { eliminate_frame_pointer: false, max_atomic_width: Some(128), abi_blacklist: super::arm_base::abi_blacklist(), + forces_embed_bitcode: true, ..base }, }) diff --git a/src/librustc_target/spec/aarch64_apple_tvos.rs b/src/librustc_target/spec/aarch64_apple_tvos.rs index 794bc7900e747..f1cd14ffd11a6 100644 --- a/src/librustc_target/spec/aarch64_apple_tvos.rs +++ b/src/librustc_target/spec/aarch64_apple_tvos.rs @@ -19,6 +19,7 @@ pub fn target() -> TargetResult { eliminate_frame_pointer: false, max_atomic_width: Some(128), abi_blacklist: super::arm_base::abi_blacklist(), + forces_embed_bitcode: true, ..base }, }) diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index e853c07632f90..8b319a0e38113 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -783,6 +783,8 @@ pub struct TargetOptions { // If we give emcc .o files that are actually .bc files it // will 'just work'. pub obj_is_bitcode: bool, + /// Whether the target requires that emitted object code includes bitcode. + pub forces_embed_bitcode: bool, /// Don't use this field; instead use the `.min_atomic_width()` method. pub min_atomic_width: Option, @@ -939,6 +941,7 @@ impl Default for TargetOptions { allow_asm: true, has_elf_tls: false, obj_is_bitcode: false, + forces_embed_bitcode: false, min_atomic_width: None, max_atomic_width: None, atomic_cas: true, @@ -1278,6 +1281,7 @@ impl Target { key!(main_needs_argc_argv, bool); key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); + key!(forces_embed_bitcode, bool); key!(max_atomic_width, Option); key!(min_atomic_width, Option); key!(atomic_cas, bool); @@ -1505,6 +1509,7 @@ impl ToJson for Target { target_option_val!(main_needs_argc_argv); target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); + target_option_val!(forces_embed_bitcode); target_option_val!(min_atomic_width); target_option_val!(max_atomic_width); target_option_val!(atomic_cas); From a390803782218807966b0999a698795b0fc5b281 Mon Sep 17 00:00:00 2001 From: Tom Karpiniec Date: Thu, 7 May 2020 15:34:31 +1000 Subject: [PATCH 2/3] Provide configurable LLVM cmdline section via target spec The App Store performs certain sanity checks on bitcode, including that an acceptable set of command line arguments was used when compiling a given module. For Rust code to be distributed on the app store with bitcode rustc must pretend to have the same command line arguments. --- src/librustc_codegen_llvm/back/write.rs | 14 ++++++++------ src/librustc_codegen_ssa/back/write.rs | 2 ++ src/librustc_target/spec/aarch64_apple_ios.rs | 11 +++++++++++ src/librustc_target/spec/mod.rs | 5 +++++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 394e2f332cb21..d8faa82a8944d 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -651,10 +651,10 @@ pub(crate) unsafe fn codegen( "LLVM_module_codegen_embed_bitcode", &module.name[..], ); - embed_bitcode(cgcx, llcx, llmod, Some(data)); + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, Some(data)); } } else if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Marker) { - embed_bitcode(cgcx, llcx, llmod, None); + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, None); } if config.emit_ir { @@ -777,8 +777,8 @@ pub(crate) unsafe fn codegen( /// * __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. +/// recognize what's going on. A suitable cmdline value is taken from the +/// target spec. /// /// Furthermore debug/O1 builds don't actually embed bitcode but rather just /// embed an empty section. @@ -789,6 +789,7 @@ unsafe fn embed_bitcode( cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module, + cmdline: &str, bitcode: Option<&[u8]>, ) { let llconst = common::bytes_in_context(llcx, bitcode.unwrap_or(&[])); @@ -800,14 +801,15 @@ unsafe fn embed_bitcode( 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("-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, &[]); + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 72c4539e82908..cae99f630c35b 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -101,6 +101,7 @@ pub struct ModuleConfig { pub emit_ir: bool, pub emit_asm: bool, pub emit_obj: EmitObj, + pub bc_cmdline: String, // Miscellaneous flags. These are mostly copied from command-line // options. @@ -213,6 +214,7 @@ impl ModuleConfig { false ), emit_obj, + bc_cmdline: sess.target.target.options.bitcode_llvm_cmdline.clone(), verify_llvm_ir: sess.verify_llvm_ir(), no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes, diff --git a/src/librustc_target/spec/aarch64_apple_ios.rs b/src/librustc_target/spec/aarch64_apple_ios.rs index 3ecedd769fae4..eac2c3e6aa40c 100644 --- a/src/librustc_target/spec/aarch64_apple_ios.rs +++ b/src/librustc_target/spec/aarch64_apple_ios.rs @@ -20,6 +20,17 @@ pub fn target() -> TargetResult { max_atomic_width: Some(128), abi_blacklist: super::arm_base::abi_blacklist(), forces_embed_bitcode: true, + // Taken from a clang build on Xcode 11.4.1. + // These arguments are not actually invoked - they just have + // to look right to pass App Store validation. + bitcode_llvm_cmdline: "-triple\0\ + arm64-apple-ios11.0.0\0\ + -emit-obj\0\ + -disable-llvm-passes\0\ + -target-abi\0\ + darwinpcs\0\ + -Os\0" + .to_string(), ..base }, }) diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 8b319a0e38113..51dce9e144caa 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -785,6 +785,8 @@ pub struct TargetOptions { pub obj_is_bitcode: bool, /// Whether the target requires that emitted object code includes bitcode. pub forces_embed_bitcode: bool, + /// Content of the LLVM cmdline section associated with embedded bitcode. + pub bitcode_llvm_cmdline: String, /// Don't use this field; instead use the `.min_atomic_width()` method. pub min_atomic_width: Option, @@ -942,6 +944,7 @@ impl Default for TargetOptions { has_elf_tls: false, obj_is_bitcode: false, forces_embed_bitcode: false, + bitcode_llvm_cmdline: String::new(), min_atomic_width: None, max_atomic_width: None, atomic_cas: true, @@ -1282,6 +1285,7 @@ impl Target { key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); key!(forces_embed_bitcode, bool); + key!(bitcode_llvm_cmdline); key!(max_atomic_width, Option); key!(min_atomic_width, Option); key!(atomic_cas, bool); @@ -1510,6 +1514,7 @@ impl ToJson for Target { target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); target_option_val!(forces_embed_bitcode); + target_option_val!(bitcode_llvm_cmdline); target_option_val!(min_atomic_width); target_option_val!(max_atomic_width); target_option_val!(atomic_cas); From 4fea9cdd2400f60439f96999f423f92a711b984d Mon Sep 17 00:00:00 2001 From: Tom Karpiniec Date: Fri, 8 May 2020 09:48:30 +1000 Subject: [PATCH 3/3] Simplify bitcode embedding - either None or Full --- src/librustc_codegen_llvm/back/write.rs | 8 +++----- src/librustc_codegen_ssa/back/write.rs | 22 ++++++---------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index d8faa82a8944d..e261ac6544679 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -651,10 +651,8 @@ pub(crate) unsafe fn codegen( "LLVM_module_codegen_embed_bitcode", &module.name[..], ); - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, Some(data)); + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); } - } else if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Marker) { - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, None); } if config.emit_ir { @@ -790,9 +788,9 @@ unsafe fn embed_bitcode( llcx: &llvm::Context, llmod: &llvm::Module, cmdline: &str, - bitcode: Option<&[u8]>, + bitcode: &[u8], ) { - let llconst = common::bytes_in_context(llcx, bitcode.unwrap_or(&[])); + let llconst = common::bytes_in_context(llcx, bitcode); let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index cae99f630c35b..21eb56f12b971 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -68,10 +68,6 @@ pub enum BitcodeSection { // No bitcode section. None, - // An empty bitcode section (to placate tools such as the iOS linker that - // require this section even if they don't use it). - Marker, - // A full, uncompressed bitcode section. Full, } @@ -148,16 +144,8 @@ impl ModuleConfig { || sess.opts.cg.linker_plugin_lto.enabled() { EmitObj::Bitcode - } else if sess.target.target.options.forces_embed_bitcode { + } else if need_bitcode_in_object(sess) { EmitObj::ObjectCode(BitcodeSection::Full) - } else if need_crate_bitcode_for_rlib(sess) { - let force_full = need_crate_bitcode_for_rlib(sess); - match sess.opts.optimize { - config::OptLevel::No | config::OptLevel::Less if !force_full => { - EmitObj::ObjectCode(BitcodeSection::Marker) - } - _ => EmitObj::ObjectCode(BitcodeSection::Full), - } } else { EmitObj::ObjectCode(BitcodeSection::None) }; @@ -376,10 +364,12 @@ pub struct CompiledModules { pub allocator_module: Option, } -fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { - sess.opts.cg.embed_bitcode +fn need_bitcode_in_object(sess: &Session) -> bool { + let requested_for_rlib = sess.opts.cg.embed_bitcode && sess.crate_types.borrow().contains(&CrateType::Rlib) - && sess.opts.output_types.contains_key(&OutputType::Exe) + && sess.opts.output_types.contains_key(&OutputType::Exe); + let forced_by_target = sess.target.target.options.forces_embed_bitcode; + requested_for_rlib || forced_by_target } fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool {