Skip to content

Commit

Permalink
Always use llvm.used for coverage symbols
Browse files Browse the repository at this point in the history
This follows what clang does in CoverageMappingGen. Using just
llvm.compiler.used is insufficient at least for MSVC targets.
  • Loading branch information
nikic committed Aug 21, 2021
1 parent f3ae726 commit 306259c
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 35 deletions.
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_llvm/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
46 changes: 29 additions & 17 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>>,
Expand Down Expand Up @@ -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(),
Expand All @@ -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> {
Expand Down Expand Up @@ -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)
}
Expand All @@ -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> {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
}
18 changes: 8 additions & 10 deletions compiler/rustc_codegen_ssa/src/traits/statics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down

0 comments on commit 306259c

Please sign in to comment.