Skip to content

Commit a737592

Browse files
committed
Auto merge of #91654 - nikic:llvmbc-section-flags, r=nagisa
Use module inline assembly to embed bitcode In LLVM 14, our current method of setting section flags to avoid embedding the `.llvmbc` section into final compilation artifacts will no longer work, see issue #90326. The upstream recommendation is to instead embed the entire bitcode using module-level inline assembly, which is what this change does. I've kept the existing code for platforms where we do not need to set section flags, but possibly we should always be using the inline asm approach (which would have to look a bit different for MachO). r? `@nagisa`
2 parents 6d6d089 + 509dedc commit a737592

File tree

1 file changed

+60
-42
lines changed
  • compiler/rustc_codegen_llvm/src/back

1 file changed

+60
-42
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+60-42
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,29 @@ pub(crate) unsafe fn codegen(
950950
))
951951
}
952952

953+
fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: &[u8]) -> Vec<u8> {
954+
let mut asm = format!(".section {},\"{}\"\n", section_name, section_flags).into_bytes();
955+
asm.extend_from_slice(b".ascii \"");
956+
asm.reserve(data.len());
957+
for &byte in data {
958+
if byte == b'\\' || byte == b'"' {
959+
asm.push(b'\\');
960+
asm.push(byte);
961+
} else if byte < 0x20 || byte >= 0x80 {
962+
// Avoid non UTF-8 inline assembly. Use octal escape sequence, because it is fixed
963+
// width, while hex escapes will consume following characters.
964+
asm.push(b'\\');
965+
asm.push(b'0' + ((byte >> 6) & 0x7));
966+
asm.push(b'0' + ((byte >> 3) & 0x7));
967+
asm.push(b'0' + ((byte >> 0) & 0x7));
968+
} else {
969+
asm.push(byte);
970+
}
971+
}
972+
asm.extend_from_slice(b"\"\n");
973+
asm
974+
}
975+
953976
/// Embed the bitcode of an LLVM module in the LLVM module itself.
954977
///
955978
/// This is done primarily for iOS where it appears to be standard to compile C
@@ -975,34 +998,6 @@ unsafe fn embed_bitcode(
975998
cmdline: &str,
976999
bitcode: &[u8],
9771000
) {
978-
let llconst = common::bytes_in_context(llcx, bitcode);
979-
let llglobal = llvm::LLVMAddGlobal(
980-
llmod,
981-
common::val_ty(llconst),
982-
"rustc.embedded.module\0".as_ptr().cast(),
983-
);
984-
llvm::LLVMSetInitializer(llglobal, llconst);
985-
986-
let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
987-
|| cgcx.opts.target_triple.triple().contains("-darwin")
988-
|| cgcx.opts.target_triple.triple().contains("-tvos");
989-
990-
let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" };
991-
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
992-
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
993-
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
994-
995-
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
996-
let llglobal = llvm::LLVMAddGlobal(
997-
llmod,
998-
common::val_ty(llconst),
999-
"rustc.embedded.cmdline\0".as_ptr().cast(),
1000-
);
1001-
llvm::LLVMSetInitializer(llglobal, llconst);
1002-
let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" };
1003-
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
1004-
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
1005-
10061001
// We're adding custom sections to the output object file, but we definitely
10071002
// do not want these custom sections to make their way into the final linked
10081003
// executable. The purpose of these custom sections is for tooling
@@ -1024,31 +1019,54 @@ unsafe fn embed_bitcode(
10241019
// * COFF - if we don't do anything the linker will by default copy all
10251020
// these sections to the output artifact, not what we want! To subvert
10261021
// this we want to flag the sections we inserted here as
1027-
// `IMAGE_SCN_LNK_REMOVE`. Unfortunately though LLVM has no native way to
1028-
// do this. Thankfully though we can do this with some inline assembly,
1029-
// which is easy enough to add via module-level global inline asm.
1022+
// `IMAGE_SCN_LNK_REMOVE`.
10301023
//
10311024
// * ELF - this is very similar to COFF above. One difference is that these
10321025
// sections are removed from the output linked artifact when
10331026
// `--gc-sections` is passed, which we pass by default. If that flag isn't
10341027
// passed though then these sections will show up in the final output.
10351028
// Additionally the flag that we need to set here is `SHF_EXCLUDE`.
1029+
//
1030+
// Unfortunately, LLVM provides no way to set custom section flags. For ELF
1031+
// and COFF we emit the sections using module level inline assembly for that
1032+
// reason (see issue #90326 for historical background).
1033+
let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
1034+
|| cgcx.opts.target_triple.triple().contains("-darwin")
1035+
|| cgcx.opts.target_triple.triple().contains("-tvos");
10361036
if is_apple
10371037
|| cgcx.opts.target_triple.triple().starts_with("wasm")
10381038
|| cgcx.opts.target_triple.triple().starts_with("asmjs")
10391039
{
1040-
// nothing to do here
1041-
} else if cgcx.is_pe_coff {
1042-
let asm = "
1043-
.section .llvmbc,\"n\"
1044-
.section .llvmcmd,\"n\"
1045-
";
1046-
llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
1040+
// We don't need custom section flags, create LLVM globals.
1041+
let llconst = common::bytes_in_context(llcx, bitcode);
1042+
let llglobal = llvm::LLVMAddGlobal(
1043+
llmod,
1044+
common::val_ty(llconst),
1045+
"rustc.embedded.module\0".as_ptr().cast(),
1046+
);
1047+
llvm::LLVMSetInitializer(llglobal, llconst);
1048+
1049+
let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" };
1050+
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
1051+
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
1052+
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
1053+
1054+
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
1055+
let llglobal = llvm::LLVMAddGlobal(
1056+
llmod,
1057+
common::val_ty(llconst),
1058+
"rustc.embedded.cmdline\0".as_ptr().cast(),
1059+
);
1060+
llvm::LLVMSetInitializer(llglobal, llconst);
1061+
let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" };
1062+
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
1063+
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
10471064
} else {
1048-
let asm = "
1049-
.section .llvmbc,\"e\"
1050-
.section .llvmcmd,\"e\"
1051-
";
1065+
// We need custom section flags, so emit module-level inline assembly.
1066+
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
1067+
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
1068+
llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
1069+
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
10521070
llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
10531071
}
10541072
}

0 commit comments

Comments
 (0)