about summary refs log tree commit diff
path: root/compiler/rustc_codegen_llvm/src
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-01-25 05:51:14 +0100
committerGitHub <noreply@github.com>2022-01-25 05:51:14 +0100
commit13b87d8cc73b8ac9cab1fa99b2b61820d4d483a6 (patch)
tree937d7106779ef49d1997a2178f187af99809a09a /compiler/rustc_codegen_llvm/src
parentc3ddca6d4a3cc36337101685f100e0ca9c5e9626 (diff)
parente02e9582d253ffaa04c9137f732efb0b80f98907 (diff)
downloadrust-13b87d8cc73b8ac9cab1fa99b2b61820d4d483a6.tar.gz
rust-13b87d8cc73b8ac9cab1fa99b2b61820d4d483a6.zip
Rollup merge of #93269 - jacobbramley:dev/pauth-option-1, r=petrochenkov
Use error-on-mismatch policy for PAuth module flags.

This agrees with Clang, and avoids an error when using LTO with mixed
C/Rust. LLVM considers different behaviour flags to be a mismatch,
even when the flag value itself is the same.

This also makes the flag setting explicit for all uses of
LLVMRustAddModuleFlag.

----

I believe that this fixes #92885, but have only reproduced it locally on Linux hosts so cannot confirm that it fixes the issue as reported.

I have not included a test for this because it is covered by an existing test (`src/test/run-make-fulldeps/cross-lang-lto-clang`). It is not without its problems, though:
* The test requires Clang and `--run-clang-based-tests-with=...` to run, and this is not the case on the CI.
   * Any test I add would have a similar requirement.
* With this patch applied, the test gets further, but it still fails (for other reasons). I don't think that affects #92885.
Diffstat (limited to 'compiler/rustc_codegen_llvm/src')
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs31
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs31
3 files changed, 67 insertions, 10 deletions
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index bb16bc5dccd..8672459b5da 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -215,16 +215,19 @@ pub unsafe fn create_module<'ll>(
     // to ensure intrinsic calls don't use it.
     if !sess.needs_plt() {
         let avoid_plt = "RtLibUseGOT\0".as_ptr().cast();
-        llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
+        llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
     }
 
     if sess.is_sanitizer_cfi_enabled() {
         // FIXME(rcvalle): Add support for non canonical jump tables.
         let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
-        // FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with
-        // Warning behavior flag. Add support for specifying the behavior flag to
-        // LLVMRustAddModuleFlag.
-        llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1);
+        // FIXME(rcvalle): Add it with Override behavior flag.
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            llvm::LLVMModFlagBehavior::Warning,
+            canonical_jump_tables,
+            1,
+        );
     }
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
@@ -233,11 +236,21 @@ pub unsafe fn create_module<'ll>(
             CFGuard::Disabled => {}
             CFGuard::NoChecks => {
                 // Set `cfguard=1` module flag to emit metadata only.
-                llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 1)
+                llvm::LLVMRustAddModuleFlag(
+                    llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "cfguard\0".as_ptr() as *const _,
+                    1,
+                )
             }
             CFGuard::Checks => {
                 // Set `cfguard=2` module flag to emit metadata and checks.
-                llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 2)
+                llvm::LLVMRustAddModuleFlag(
+                    llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "cfguard\0".as_ptr() as *const _,
+                    2,
+                )
             }
         }
     }
@@ -247,24 +260,28 @@ pub unsafe fn create_module<'ll>(
 
         llvm::LLVMRustAddModuleFlag(
             llmod,
+            llvm::LLVMModFlagBehavior::Error,
             "branch-target-enforcement\0".as_ptr().cast(),
             bti.into(),
         );
 
         llvm::LLVMRustAddModuleFlag(
             llmod,
+            llvm::LLVMModFlagBehavior::Error,
             "sign-return-address\0".as_ptr().cast(),
             pac.is_some().into(),
         );
         let pac_opts = pac.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
         llvm::LLVMRustAddModuleFlag(
             llmod,
+            llvm::LLVMModFlagBehavior::Error,
             "sign-return-address-all\0".as_ptr().cast(),
             pac_opts.leaf.into(),
         );
         let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true };
         llvm::LLVMRustAddModuleFlag(
             llmod,
+            llvm::LLVMModFlagBehavior::Error,
             "sign-return-address-with-bkey\0".as_ptr().cast(),
             is_bkey.into(),
         );
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 61e49fab6ff..28eb8e2a0a4 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -108,18 +108,29 @@ impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> {
             // This can be overridden using --llvm-opts -dwarf-version,N.
             // Android has the same issue (#22398)
             if let Some(version) = sess.target.dwarf_version {
-                llvm::LLVMRustAddModuleFlag(self.llmod, "Dwarf Version\0".as_ptr().cast(), version)
+                llvm::LLVMRustAddModuleFlag(
+                    self.llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "Dwarf Version\0".as_ptr().cast(),
+                    version,
+                )
             }
 
             // Indicate that we want CodeView debug information on MSVC
             if sess.target.is_like_msvc {
-                llvm::LLVMRustAddModuleFlag(self.llmod, "CodeView\0".as_ptr().cast(), 1)
+                llvm::LLVMRustAddModuleFlag(
+                    self.llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "CodeView\0".as_ptr().cast(),
+                    1,
+                )
             }
 
             // Prevent bitcode readers from deleting the debug info.
             let ptr = "Debug Info Version\0".as_ptr();
             llvm::LLVMRustAddModuleFlag(
                 self.llmod,
+                llvm::LLVMModFlagBehavior::Warning,
                 ptr.cast(),
                 llvm::LLVMRustDebugMetadataVersion(),
             );
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index a1c7d2b4f61..2b102188790 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -61,6 +61,26 @@ pub enum LLVMMachineType {
     ARM = 0x01c0,
 }
 
+/// LLVM's Module::ModFlagBehavior, defined in llvm/include/llvm/IR/Module.h.
+///
+/// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are
+/// resolved according to the merge behaviors specified here. Flags differing only in merge
+/// behavior are still considered to be in conflict.
+///
+/// In order for Rust-C LTO to work, we must specify behaviors compatible with Clang. Notably,
+/// 'Error' and 'Warning' cannot be mixed for a given flag.
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum LLVMModFlagBehavior {
+    Error = 1,
+    Warning = 2,
+    Require = 3,
+    Override = 4,
+    Append = 5,
+    AppendUnique = 6,
+    Max = 7,
+}
+
 // Consts for the LLVM CallConv type, pre-cast to usize.
 
 /// LLVM CallingConv::ID. Should we wrap this?
@@ -1895,7 +1915,16 @@ extern "C" {
 
     pub fn LLVMRustIsRustLLVM() -> bool;
 
-    pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32);
+    /// Add LLVM module flags.
+    ///
+    /// In order for Rust-C LTO to work, module flags must be compatible with Clang. What
+    /// "compatible" means depends on the merge behaviors involved.
+    pub fn LLVMRustAddModuleFlag(
+        M: &Module,
+        merge_behavior: LLVMModFlagBehavior,
+        name: *const c_char,
+        value: u32,
+    );
 
     pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;