Skip to content

Commit

Permalink
Unrolled build for rust-lang#132319
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#132319 - Zalathar:add-module-flag, r=jieyouxu

cg_llvm: Clean up FFI calls for setting module flags

This is a combination of several inter-related changes to how module flags are set:

- Remove some unnecessary code for setting an `"LTOPostLink"` flag, which has been obsolete since LLVM 17.
- Define our own enum instead of relying on enum values defined by LLVM's unstable C++ API.
- Use safe wrapper functions to set module flags, instead of direct `unsafe` calls.
- Consistently pass pointer/length strings instead of C strings.
- Remove or shrink some `unsafe` blocks.
  • Loading branch information
rust-timer authored Oct 29, 2024
2 parents e473783 + 8d2ed4f commit ca4307f
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 237 deletions.
21 changes: 3 additions & 18 deletions compiler/rustc_codegen_llvm/src/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use tracing::{debug, info};
use crate::back::write::{
self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, save_temp_bitcode,
};
use crate::common::AsCCharPtr;
use crate::errors::{
DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
};
Expand Down Expand Up @@ -602,23 +601,9 @@ pub(crate) fn run_pass_manager(
// This code is based off the code found in llvm's LTO code generator:
// llvm/lib/LTO/LTOCodeGenerator.cpp
debug!("running the pass manager");
unsafe {
if !llvm::LLVMRustHasModuleFlag(
module.module_llvm.llmod(),
"LTOPostLink".as_c_char_ptr(),
11,
) {
llvm::LLVMRustAddModuleFlagU32(
module.module_llvm.llmod(),
llvm::LLVMModFlagBehavior::Error,
c"LTOPostLink".as_ptr(),
1,
);
}
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage)?;
}
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
unsafe { write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }?;
debug!("lto done");
Ok(())
}
Expand Down
278 changes: 118 additions & 160 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,133 +210,111 @@ pub(crate) unsafe fn create_module<'ll>(
// If skipping the PLT is enabled, we need to add some module metadata
// to ensure intrinsic calls don't use it.
if !sess.needs_plt() {
let avoid_plt = c"RtLibUseGOT".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
}
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "RtLibUseGOT", 1);
}

// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
canonical_jump_tables,
1,
);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"CFI Canonical Jump Tables",
1,
);
}

// If we're normalizing integers with CFI, ensure LLVM generated functions do the same.
// See https://github.com/llvm/llvm-project/pull/104826
if sess.is_sanitizer_cfi_normalize_integers_enabled() {
let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
cfi_normalize_integers,
1,
);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"cfi-normalize-integers",
1,
);
}

// Enable LTO unit splitting if specified or if CFI is enabled. (See
// https://reviews.llvm.org/D53891.)
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
enable_split_lto_unit,
1,
);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"EnableSplitLTOUnit",
1,
);
}

// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
if sess.is_sanitizer_kcfi_enabled() {
let kcfi = c"kcfi".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
}
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Override, "kcfi", 1);

// Add "kcfi-offset" module flag with -Z patchable-function-entry (See
// https://reviews.llvm.org/D141172).
let pfe =
PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry);
if pfe.prefix() > 0 {
let kcfi_offset = c"kcfi-offset".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
kcfi_offset,
pfe.prefix().into(),
);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"kcfi-offset",
pfe.prefix().into(),
);
}
}

// Control Flow Guard is currently only supported by the MSVC linker on Windows.
if sess.target.is_like_msvc {
unsafe {
match sess.opts.cg.control_flow_guard {
CFGuard::Disabled => {}
CFGuard::NoChecks => {
// Set `cfguard=1` module flag to emit metadata only.
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"cfguard".as_ptr() as *const _,
1,
)
}
CFGuard::Checks => {
// Set `cfguard=2` module flag to emit metadata and checks.
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"cfguard".as_ptr() as *const _,
2,
)
}
match sess.opts.cg.control_flow_guard {
CFGuard::Disabled => {}
CFGuard::NoChecks => {
// Set `cfguard=1` module flag to emit metadata only.
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Warning,
"cfguard",
1,
);
}
CFGuard::Checks => {
// Set `cfguard=2` module flag to emit metadata and checks.
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Warning,
"cfguard",
2,
);
}
}
}

if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
if sess.target.arch == "aarch64" {
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"branch-target-enforcement".as_ptr(),
bti.into(),
);
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address".as_ptr(),
pac_ret.is_some().into(),
);
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address-all".as_ptr(),
pac_opts.leaf.into(),
);
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address-with-bkey".as_ptr(),
u32::from(pac_opts.key == PAuthKey::B),
);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Min,
"branch-target-enforcement",
bti.into(),
);
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Min,
"sign-return-address",
pac_ret.is_some().into(),
);
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Min,
"sign-return-address-all",
pac_opts.leaf.into(),
);
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Min,
"sign-return-address-with-bkey",
u32::from(pac_opts.key == PAuthKey::B),
);
} else {
bug!(
"branch-protection used on non-AArch64 target; \
Expand All @@ -347,75 +325,59 @@ pub(crate) unsafe fn create_module<'ll>(

// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"cf-protection-branch".as_ptr(),
1,
);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"cf-protection-branch",
1,
);
}
if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"cf-protection-return".as_ptr(),
1,
);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"cf-protection-return",
1,
);
}

if sess.opts.unstable_opts.virtual_function_elimination {
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Error,
c"Virtual Function Elim".as_ptr(),
1,
);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Error,
"Virtual Function Elim",
1,
);
}

// Set module flag to enable Windows EHCont Guard (/guard:ehcont).
if sess.opts.unstable_opts.ehcont_guard {
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Warning,
c"ehcontguard".as_ptr() as *const _,
1,
)
}
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "ehcontguard", 1);
}

match sess.opts.unstable_opts.function_return {
FunctionReturn::Keep => {}
FunctionReturn::ThunkExtern => unsafe {
llvm::LLVMRustAddModuleFlagU32(
FunctionReturn::ThunkExtern => {
llvm::add_module_flag_u32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"function_return_thunk_extern".as_ptr(),
llvm::ModuleFlagMergeBehavior::Override,
"function_return_thunk_extern",
1,
)
},
);
}
}

match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support())
{
// Set up the small-data optimization limit for architectures that use
// an LLVM module flag to control this.
(Some(threshold), SmallDataThresholdSupport::LlvmModuleFlag(flag)) => {
let flag = SmallCStr::new(flag.as_ref());
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Error,
flag.as_c_str().as_ptr(),
threshold as u32,
)
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Error,
&flag,
threshold as u32,
);
}
_ => (),
};
Expand Down Expand Up @@ -449,33 +411,29 @@ pub(crate) unsafe fn create_module<'ll>(
// If llvm_abiname is empty, emit nothing.
let llvm_abiname = &sess.target.options.llvm_abiname;
if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() {
unsafe {
llvm::LLVMRustAddModuleFlagString(
llmod,
llvm::LLVMModFlagBehavior::Error,
c"target-abi".as_ptr(),
llvm_abiname.as_c_char_ptr(),
llvm_abiname.len(),
);
}
llvm::add_module_flag_str(
llmod,
llvm::ModuleFlagMergeBehavior::Error,
"target-abi",
llvm_abiname,
);
}

// Add module flags specified via -Z llvm_module_flag
for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag {
let key = format!("{key}\0");
let behavior = match behavior.as_str() {
"error" => llvm::LLVMModFlagBehavior::Error,
"warning" => llvm::LLVMModFlagBehavior::Warning,
"require" => llvm::LLVMModFlagBehavior::Require,
"override" => llvm::LLVMModFlagBehavior::Override,
"append" => llvm::LLVMModFlagBehavior::Append,
"appendunique" => llvm::LLVMModFlagBehavior::AppendUnique,
"max" => llvm::LLVMModFlagBehavior::Max,
"min" => llvm::LLVMModFlagBehavior::Min,
for (key, value, merge_behavior) in &sess.opts.unstable_opts.llvm_module_flag {
let merge_behavior = match merge_behavior.as_str() {
"error" => llvm::ModuleFlagMergeBehavior::Error,
"warning" => llvm::ModuleFlagMergeBehavior::Warning,
"require" => llvm::ModuleFlagMergeBehavior::Require,
"override" => llvm::ModuleFlagMergeBehavior::Override,
"append" => llvm::ModuleFlagMergeBehavior::Append,
"appendunique" => llvm::ModuleFlagMergeBehavior::AppendUnique,
"max" => llvm::ModuleFlagMergeBehavior::Max,
"min" => llvm::ModuleFlagMergeBehavior::Min,
// We already checked this during option parsing
_ => unreachable!(),
};
unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_c_char_ptr(), *value) }
llvm::add_module_flag_u32(llmod, merge_behavior, key, *value);
}

llmod
Expand Down
Loading

0 comments on commit ca4307f

Please sign in to comment.