@@ -42,6 +42,7 @@ use syntax_pos::MultiSpan;
4242use syntax_pos:: symbol:: Symbol ;
4343use type_:: Type ;
4444use context:: { is_pie_binary, get_reloc_model} ;
45+ use common:: { C_bytes_in_context , val_ty} ;
4546use jobserver:: { Client , Acquired } ;
4647use rustc_demangle;
4748
@@ -262,6 +263,8 @@ pub struct ModuleConfig {
262263 // emscripten's ecc compiler, when used as the linker.
263264 obj_is_bitcode : bool ,
264265 no_integrated_as : bool ,
266+ embed_bitcode : bool ,
267+ embed_bitcode_marker : bool ,
265268}
266269
267270impl ModuleConfig {
@@ -279,6 +282,8 @@ impl ModuleConfig {
279282 emit_asm : false ,
280283 emit_obj : false ,
281284 obj_is_bitcode : false ,
285+ embed_bitcode : false ,
286+ embed_bitcode_marker : false ,
282287 no_integrated_as : false ,
283288
284289 no_verify : false ,
@@ -299,6 +304,17 @@ impl ModuleConfig {
299304 self . time_passes = sess. time_passes ( ) ;
300305 self . inline_threshold = sess. opts . cg . inline_threshold ;
301306 self . obj_is_bitcode = sess. target . target . options . obj_is_bitcode ;
307+ let embed_bitcode = sess. target . target . options . embed_bitcode ||
308+ sess. opts . debugging_opts . embed_bitcode ;
309+ if embed_bitcode {
310+ match sess. opts . optimize {
311+ config:: OptLevel :: No |
312+ config:: OptLevel :: Less => {
313+ self . embed_bitcode_marker = embed_bitcode;
314+ }
315+ _ => self . embed_bitcode = embed_bitcode,
316+ }
317+ }
302318
303319 // Copy what clang does by turning on loop vectorization at O2 and
304320 // slp vectorization at O3. Otherwise configure other optimization aspects
@@ -662,7 +678,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
662678 let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
663679
664680
665- if write_bc || config. emit_bc_compressed {
681+ if write_bc || config. emit_bc_compressed || config . embed_bitcode {
666682 let thin;
667683 let old;
668684 let data = if llvm:: LLVMRustThinLTOAvailable ( ) {
@@ -681,6 +697,11 @@ unsafe fn codegen(cgcx: &CodegenContext,
681697 timeline. record ( "write-bc" ) ;
682698 }
683699
700+ if config. embed_bitcode {
701+ embed_bitcode ( cgcx, llcx, llmod, Some ( data) ) ;
702+ timeline. record ( "embed-bc" ) ;
703+ }
704+
684705 if config. emit_bc_compressed {
685706 let dst = bc_out. with_extension ( RLIB_BYTECODE_EXTENSION ) ;
686707 let data = bytecode:: encode ( & mtrans. llmod_id , data) ;
@@ -689,6 +710,8 @@ unsafe fn codegen(cgcx: &CodegenContext,
689710 }
690711 timeline. record ( "compress-bc" ) ;
691712 }
713+ } else if config. embed_bitcode_marker {
714+ embed_bitcode ( cgcx, llcx, llmod, None ) ;
692715 }
693716
694717 time_ext ( config. time_passes , None , & format ! ( "codegen passes [{}]" , module_name. unwrap( ) ) ,
@@ -796,6 +819,59 @@ unsafe fn codegen(cgcx: &CodegenContext,
796819 & cgcx. output_filenames ) )
797820}
798821
822+ /// Embed the bitcode of an LLVM module in the LLVM module itself.
823+ ///
824+ /// This is done primarily for iOS where it appears to be standard to compile C
825+ /// code at least with `-fembed-bitcode` which creates two sections in the
826+ /// executable:
827+ ///
828+ /// * __LLVM,__bitcode
829+ /// * __LLVM,__cmdline
830+ ///
831+ /// It appears *both* of these sections are necessary to get the linker to
832+ /// recognize what's going on. For us though we just always throw in an empty
833+ /// cmdline section.
834+ ///
835+ /// Furthermore debug/O1 builds don't actually embed bitcode but rather just
836+ /// embed an empty section.
837+ ///
838+ /// Basically all of this is us attempting to follow in the footsteps of clang
839+ /// on iOS. See #35968 for lots more info.
840+ unsafe fn embed_bitcode ( cgcx : & CodegenContext ,
841+ llcx : ContextRef ,
842+ llmod : ModuleRef ,
843+ bitcode : Option < & [ u8 ] > ) {
844+ let llconst = C_bytes_in_context ( llcx, bitcode. unwrap_or ( & [ ] ) ) ;
845+ let llglobal = llvm:: LLVMAddGlobal (
846+ llmod,
847+ val_ty ( llconst) . to_ref ( ) ,
848+ "rustc.embedded.module\0 " . as_ptr ( ) as * const _ ,
849+ ) ;
850+ llvm:: LLVMSetInitializer ( llglobal, llconst) ;
851+ let section = if cgcx. opts . target_triple . contains ( "-ios" ) {
852+ "__LLVM,__bitcode\0 "
853+ } else {
854+ ".llvmbc\0 "
855+ } ;
856+ llvm:: LLVMSetSection ( llglobal, section. as_ptr ( ) as * const _ ) ;
857+ llvm:: LLVMRustSetLinkage ( llglobal, llvm:: Linkage :: PrivateLinkage ) ;
858+
859+ let llconst = C_bytes_in_context ( llcx, & [ ] ) ;
860+ let llglobal = llvm:: LLVMAddGlobal (
861+ llmod,
862+ val_ty ( llconst) . to_ref ( ) ,
863+ "rustc.embedded.cmdline\0 " . as_ptr ( ) as * const _ ,
864+ ) ;
865+ llvm:: LLVMSetInitializer ( llglobal, llconst) ;
866+ let section = if cgcx. opts . target_triple . contains ( "-ios" ) {
867+ "__LLVM,__cmdline\0 "
868+ } else {
869+ ".llvmcmd\0 "
870+ } ;
871+ llvm:: LLVMSetSection ( llglobal, section. as_ptr ( ) as * const _ ) ;
872+ llvm:: LLVMRustSetLinkage ( llglobal, llvm:: Linkage :: PrivateLinkage ) ;
873+ }
874+
799875pub ( crate ) struct CompiledModules {
800876 pub modules : Vec < CompiledModule > ,
801877 pub metadata_module : CompiledModule ,
0 commit comments