Always use llvm.used for coverage symbols
This follows what clang does in CoverageMappingGen. Using just llvm.compiler.used is insufficient at least for MSVC targets.
This commit is contained in:
parent
f3ae726f30
commit
306259c645
@ -162,11 +162,13 @@ pub fn compile_codegen_unit(
|
||||
cx.coverageinfo_finalize();
|
||||
}
|
||||
|
||||
// Create the llvm.compiler.used variable
|
||||
// This variable has type [N x i8*] and is stored in the llvm.metadata section
|
||||
// Create the llvm.used and llvm.compiler.used variables.
|
||||
if !cx.used_statics().borrow().is_empty() {
|
||||
cx.create_used_variable()
|
||||
}
|
||||
if !cx.compiler_used_statics().borrow().is_empty() {
|
||||
cx.create_compiler_used_variable()
|
||||
}
|
||||
|
||||
// Finalize debuginfo
|
||||
if cx.sess().opts.debuginfo != DebugInfo::None {
|
||||
|
@ -474,14 +474,27 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
|
||||
}
|
||||
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
|
||||
self.add_used_global(g);
|
||||
// The semantics of #[used] in Rust only require the symbol to make it into the
|
||||
// object file. It is explicitly allowed for the linker to strip the symbol if it
|
||||
// is dead. As such, use llvm.compiler.used instead of llvm.used.
|
||||
// Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
|
||||
// sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
|
||||
// in some versions of the gold linker.
|
||||
self.add_compiler_used_global(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a global value to a list to be stored in the `llvm.compiler.used` variable, an array of i8*.
|
||||
/// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
|
||||
fn add_used_global(&self, global: &'ll Value) {
|
||||
let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
|
||||
self.used_statics.borrow_mut().push(cast);
|
||||
}
|
||||
|
||||
/// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
|
||||
/// an array of i8*.
|
||||
fn add_compiler_used_global(&self, global: &'ll Value) {
|
||||
let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
|
||||
self.compiler_used_statics.borrow_mut().push(cast);
|
||||
}
|
||||
}
|
||||
|
@ -71,9 +71,13 @@ pub struct CodegenCx<'ll, 'tcx> {
|
||||
/// to constants.)
|
||||
pub statics_to_rauw: RefCell<Vec<(&'ll Value, &'ll Value)>>,
|
||||
|
||||
/// Statics that will be placed in the llvm.used variable
|
||||
/// See <https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable> for details
|
||||
pub used_statics: RefCell<Vec<&'ll Value>>,
|
||||
|
||||
/// Statics that will be placed in the llvm.compiler.used variable
|
||||
/// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details
|
||||
pub used_statics: RefCell<Vec<&'ll Value>>,
|
||||
pub compiler_used_statics: RefCell<Vec<&'ll Value>>,
|
||||
|
||||
/// Mapping of non-scalar types to llvm types and field remapping if needed.
|
||||
pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), TypeLowering<'ll>>>,
|
||||
@ -325,6 +329,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
const_globals: Default::default(),
|
||||
statics_to_rauw: RefCell::new(Vec::new()),
|
||||
used_statics: RefCell::new(Vec::new()),
|
||||
compiler_used_statics: RefCell::new(Vec::new()),
|
||||
type_lowering: Default::default(),
|
||||
scalar_lltypes: Default::default(),
|
||||
pointee_infos: Default::default(),
|
||||
@ -347,6 +352,18 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
|
||||
self.coverage_cx.as_ref()
|
||||
}
|
||||
|
||||
fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
|
||||
let section = cstr!("llvm.metadata");
|
||||
let array = self.const_array(&self.type_ptr_to(self.type_i8()), values);
|
||||
|
||||
unsafe {
|
||||
let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
|
||||
llvm::LLVMSetInitializer(g, array);
|
||||
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
|
||||
llvm::LLVMSetSection(g, section.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
@ -437,6 +454,10 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
&self.used_statics
|
||||
}
|
||||
|
||||
fn compiler_used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
|
||||
&self.compiler_used_statics
|
||||
}
|
||||
|
||||
fn set_frame_pointer_type(&self, llfn: &'ll Value) {
|
||||
attributes::set_frame_pointer_type(self, llfn)
|
||||
}
|
||||
@ -447,23 +468,14 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
}
|
||||
|
||||
fn create_used_variable(&self) {
|
||||
// The semantics of #[used] in Rust only require the symbol to make it into the object
|
||||
// file. It is explicitly allowed for the linker to strip the symbol if it is dead.
|
||||
// As such, use llvm.compiler.used instead of llvm.used.
|
||||
// Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
|
||||
// sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs in
|
||||
// some versions of the gold linker.
|
||||
let name = cstr!("llvm.compiler.used");
|
||||
let section = cstr!("llvm.metadata");
|
||||
let array =
|
||||
self.const_array(&self.type_ptr_to(self.type_i8()), &*self.used_statics.borrow());
|
||||
self.create_used_variable_impl(cstr!("llvm.used"), &*self.used_statics.borrow());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
|
||||
llvm::LLVMSetInitializer(g, array);
|
||||
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
|
||||
llvm::LLVMSetSection(g, section.as_ptr());
|
||||
}
|
||||
fn create_compiler_used_variable(&self) {
|
||||
self.create_used_variable_impl(
|
||||
cstr!("llvm.compiler.used"),
|
||||
&*self.compiler_used_statics.borrow(),
|
||||
);
|
||||
}
|
||||
|
||||
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
|
||||
|
@ -16,9 +16,11 @@ pub trait MiscMethods<'tcx>: BackendTypes {
|
||||
fn sess(&self) -> &Session;
|
||||
fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>;
|
||||
fn used_statics(&self) -> &RefCell<Vec<Self::Value>>;
|
||||
fn compiler_used_statics(&self) -> &RefCell<Vec<Self::Value>>;
|
||||
fn set_frame_pointer_type(&self, llfn: Self::Function);
|
||||
fn apply_target_cpu_attr(&self, llfn: Self::Function);
|
||||
fn create_used_variable(&self);
|
||||
fn create_compiler_used_variable(&self);
|
||||
/// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists.
|
||||
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function>;
|
||||
}
|
||||
|
@ -6,17 +6,15 @@ pub trait StaticMethods: BackendTypes {
|
||||
fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
|
||||
fn codegen_static(&self, def_id: DefId, is_mutable: bool);
|
||||
|
||||
/// Mark the given global value as "used", to prevent a backend from potentially removing a
|
||||
/// static variable that may otherwise appear unused.
|
||||
///
|
||||
/// Static variables in Rust can be annotated with the `#[used]` attribute to direct the `rustc`
|
||||
/// compiler to mark the variable as a "used global".
|
||||
///
|
||||
/// ```no_run
|
||||
/// #[used]
|
||||
/// static FOO: u32 = 0;
|
||||
/// ```
|
||||
/// Mark the given global value as "used", to prevent the compiler and linker from potentially
|
||||
/// removing a static variable that may otherwise appear unused.
|
||||
fn add_used_global(&self, global: Self::Value);
|
||||
|
||||
/// Same as add_used_global(), but only prevent the compiler from potentially removing an
|
||||
/// otherwise unused symbol. The linker is still permitted to drop it.
|
||||
///
|
||||
/// This corresponds to the semantics of the `#[used]` attribute.
|
||||
fn add_compiler_used_global(&self, global: Self::Value);
|
||||
}
|
||||
|
||||
pub trait StaticBuilderMethods: BackendTypes {
|
||||
|
@ -28,11 +28,8 @@ CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
|
||||
CHECK: @__llvm_prf_nm = private constant
|
||||
CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1
|
||||
|
||||
CHECK: @llvm.compiler.used = appending global
|
||||
CHECK-SAME: i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*)
|
||||
WINDOWS-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*)
|
||||
CHECK-SAME: section "llvm.metadata"
|
||||
CHECK: @llvm.used = appending global
|
||||
CHECK-SAME: i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*)
|
||||
CHECK-SAME: i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0)
|
||||
CHECK-SAME: section "llvm.metadata"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user