mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-30 20:44:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			255 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Declare various LLVM values.
 | ||
| //!
 | ||
| //! Prefer using functions and methods from this module rather than calling LLVM
 | ||
| //! functions directly. These functions do some additional work to ensure we do
 | ||
| //! the right thing given the preconceptions of codegen.
 | ||
| //!
 | ||
| //! Some useful guidelines:
 | ||
| //!
 | ||
| //! * Use declare_* family of methods if you are declaring, but are not
 | ||
| //!   interested in defining the Value they return.
 | ||
| //! * Use define_* family of methods when you might be defining the Value.
 | ||
| //! * When in doubt, define.
 | ||
| 
 | ||
| use std::borrow::Borrow;
 | ||
| 
 | ||
| use itertools::Itertools;
 | ||
| use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
 | ||
| use rustc_data_structures::fx::FxIndexSet;
 | ||
| use rustc_middle::ty::{Instance, Ty};
 | ||
| use rustc_sanitizers::{cfi, kcfi};
 | ||
| use rustc_target::callconv::FnAbi;
 | ||
| use smallvec::SmallVec;
 | ||
| use tracing::debug;
 | ||
| 
 | ||
| use crate::abi::FnAbiLlvmExt;
 | ||
| use crate::common::AsCCharPtr;
 | ||
| use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx};
 | ||
| use crate::llvm::AttributePlace::Function;
 | ||
| use crate::llvm::Visibility;
 | ||
| use crate::type_::Type;
 | ||
| use crate::value::Value;
 | ||
| use crate::{attributes, llvm};
 | ||
| 
 | ||
| /// Declare a function with a SimpleCx.
 | ||
| ///
 | ||
| /// If there’s a value with the same name already declared, the function will
 | ||
| /// update the declaration and return existing Value instead.
 | ||
| pub(crate) fn declare_simple_fn<'ll>(
 | ||
|     cx: &SimpleCx<'ll>,
 | ||
|     name: &str,
 | ||
|     callconv: llvm::CallConv,
 | ||
|     unnamed: llvm::UnnamedAddr,
 | ||
|     visibility: llvm::Visibility,
 | ||
|     ty: &'ll Type,
 | ||
| ) -> &'ll Value {
 | ||
|     debug!("declare_simple_fn(name={:?}, ty={:?})", name, ty);
 | ||
|     let llfn = unsafe {
 | ||
|         llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty)
 | ||
|     };
 | ||
| 
 | ||
|     llvm::SetFunctionCallConv(llfn, callconv);
 | ||
|     llvm::SetUnnamedAddress(llfn, unnamed);
 | ||
|     llvm::set_visibility(llfn, visibility);
 | ||
| 
 | ||
|     llfn
 | ||
| }
 | ||
| 
 | ||
| /// Declare a function.
 | ||
| ///
 | ||
| /// If there’s a value with the same name already declared, the function will
 | ||
| /// update the declaration and return existing Value instead.
 | ||
| pub(crate) fn declare_raw_fn<'ll, 'tcx>(
 | ||
|     cx: &CodegenCx<'ll, 'tcx>,
 | ||
|     name: &str,
 | ||
|     callconv: llvm::CallConv,
 | ||
|     unnamed: llvm::UnnamedAddr,
 | ||
|     visibility: llvm::Visibility,
 | ||
|     ty: &'ll Type,
 | ||
| ) -> &'ll Value {
 | ||
|     debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
 | ||
|     let llfn = declare_simple_fn(cx, name, callconv, unnamed, visibility, ty);
 | ||
| 
 | ||
|     let mut attrs = SmallVec::<[_; 4]>::new();
 | ||
| 
 | ||
|     if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
 | ||
|         attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx));
 | ||
|     }
 | ||
| 
 | ||
|     attrs.extend(attributes::non_lazy_bind_attr(cx));
 | ||
| 
 | ||
|     attributes::apply_to_llfn(llfn, Function, &attrs);
 | ||
| 
 | ||
|     llfn
 | ||
| }
 | ||
| 
 | ||
| impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
 | ||
|     /// Declare a global value.
 | ||
|     ///
 | ||
|     /// If there’s a value with the same name already declared, the function will
 | ||
|     /// return its Value instead.
 | ||
|     pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
 | ||
|         debug!("declare_global(name={:?})", name);
 | ||
|         unsafe {
 | ||
|             llvm::LLVMRustGetOrInsertGlobal(
 | ||
|                 (**self).borrow().llmod,
 | ||
|                 name.as_c_char_ptr(),
 | ||
|                 name.len(),
 | ||
|                 ty,
 | ||
|             )
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 | ||
|     /// Declare a C ABI function.
 | ||
|     ///
 | ||
|     /// Only use this for foreign function ABIs and glue. For Rust functions use
 | ||
|     /// `declare_fn` instead.
 | ||
|     ///
 | ||
|     /// If there’s a value with the same name already declared, the function will
 | ||
|     /// update the declaration and return existing Value instead.
 | ||
|     pub(crate) fn declare_cfn(
 | ||
|         &self,
 | ||
|         name: &str,
 | ||
|         unnamed: llvm::UnnamedAddr,
 | ||
|         fn_type: &'ll Type,
 | ||
|     ) -> &'ll Value {
 | ||
|         // Visibility should always be default for declarations, otherwise the linker may report an
 | ||
|         // error.
 | ||
|         declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type)
 | ||
|     }
 | ||
| 
 | ||
|     /// Declare an entry Function
 | ||
|     ///
 | ||
|     /// The ABI of this function can change depending on the target (although for now the same as
 | ||
|     /// `declare_cfn`)
 | ||
|     ///
 | ||
|     /// If there’s a value with the same name already declared, the function will
 | ||
|     /// update the declaration and return existing Value instead.
 | ||
|     pub(crate) fn declare_entry_fn(
 | ||
|         &self,
 | ||
|         name: &str,
 | ||
|         callconv: llvm::CallConv,
 | ||
|         unnamed: llvm::UnnamedAddr,
 | ||
|         fn_type: &'ll Type,
 | ||
|     ) -> &'ll Value {
 | ||
|         let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
 | ||
|         declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type)
 | ||
|     }
 | ||
| 
 | ||
|     /// Declare a Rust function.
 | ||
|     ///
 | ||
|     /// If there’s a value with the same name already declared, the function will
 | ||
|     /// update the declaration and return existing Value instead.
 | ||
|     pub(crate) fn declare_fn(
 | ||
|         &self,
 | ||
|         name: &str,
 | ||
|         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
 | ||
|         instance: Option<Instance<'tcx>>,
 | ||
|     ) -> &'ll Value {
 | ||
|         debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
 | ||
| 
 | ||
|         // Function addresses in Rust are never significant, allowing functions to
 | ||
|         // be merged.
 | ||
|         let llfn = declare_raw_fn(
 | ||
|             self,
 | ||
|             name,
 | ||
|             fn_abi.llvm_cconv(self),
 | ||
|             llvm::UnnamedAddr::Global,
 | ||
|             llvm::Visibility::Default,
 | ||
|             fn_abi.llvm_type(self),
 | ||
|         );
 | ||
|         fn_abi.apply_attrs_llfn(self, llfn, instance);
 | ||
| 
 | ||
|         if self.tcx.sess.is_sanitizer_cfi_enabled() {
 | ||
|             if let Some(instance) = instance {
 | ||
|                 let mut typeids = FxIndexSet::default();
 | ||
|                 for options in [
 | ||
|                     cfi::TypeIdOptions::GENERALIZE_POINTERS,
 | ||
|                     cfi::TypeIdOptions::NORMALIZE_INTEGERS,
 | ||
|                     cfi::TypeIdOptions::USE_CONCRETE_SELF,
 | ||
|                 ]
 | ||
|                 .into_iter()
 | ||
|                 .powerset()
 | ||
|                 .map(cfi::TypeIdOptions::from_iter)
 | ||
|                 {
 | ||
|                     let typeid = cfi::typeid_for_instance(self.tcx, instance, options);
 | ||
|                     if typeids.insert(typeid.clone()) {
 | ||
|                         self.add_type_metadata(llfn, typeid);
 | ||
|                     }
 | ||
|                 }
 | ||
|             } else {
 | ||
|                 for options in [
 | ||
|                     cfi::TypeIdOptions::GENERALIZE_POINTERS,
 | ||
|                     cfi::TypeIdOptions::NORMALIZE_INTEGERS,
 | ||
|                 ]
 | ||
|                 .into_iter()
 | ||
|                 .powerset()
 | ||
|                 .map(cfi::TypeIdOptions::from_iter)
 | ||
|                 {
 | ||
|                     let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options);
 | ||
|                     self.add_type_metadata(llfn, typeid);
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         if self.tcx.sess.is_sanitizer_kcfi_enabled() {
 | ||
|             // LLVM KCFI does not support multiple !kcfi_type attachments
 | ||
|             let mut options = kcfi::TypeIdOptions::empty();
 | ||
|             if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
 | ||
|                 options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS);
 | ||
|             }
 | ||
|             if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
 | ||
|                 options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS);
 | ||
|             }
 | ||
| 
 | ||
|             if let Some(instance) = instance {
 | ||
|                 let kcfi_typeid = kcfi::typeid_for_instance(self.tcx, instance, options);
 | ||
|                 self.set_kcfi_type_metadata(llfn, kcfi_typeid);
 | ||
|             } else {
 | ||
|                 let kcfi_typeid = kcfi::typeid_for_fnabi(self.tcx, fn_abi, options);
 | ||
|                 self.set_kcfi_type_metadata(llfn, kcfi_typeid);
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         llfn
 | ||
|     }
 | ||
| 
 | ||
|     /// Declare a global with an intention to define it.
 | ||
|     ///
 | ||
|     /// Use this function when you intend to define a global. This function will
 | ||
|     /// return `None` if the name already has a definition associated with it. In that
 | ||
|     /// case an error should be reported to the user, because it usually happens due
 | ||
|     /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes).
 | ||
|     pub(crate) fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> {
 | ||
|         if self.get_defined_value(name).is_some() {
 | ||
|             None
 | ||
|         } else {
 | ||
|             Some(self.declare_global(name, ty))
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /// Declare a private global
 | ||
|     ///
 | ||
|     /// Use this function when you intend to define a global without a name.
 | ||
|     pub(crate) fn define_private_global(&self, ty: &'ll Type) -> &'ll Value {
 | ||
|         unsafe { llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty) }
 | ||
|     }
 | ||
| 
 | ||
|     /// Gets declared value by name.
 | ||
|     pub(crate) fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
 | ||
|         debug!("get_declared_value(name={:?})", name);
 | ||
|         unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_c_char_ptr(), name.len()) }
 | ||
|     }
 | ||
| 
 | ||
|     /// Gets defined or externally defined (AvailableExternally linkage) value by
 | ||
|     /// name.
 | ||
|     pub(crate) fn get_defined_value(&self, name: &str) -> Option<&'ll Value> {
 | ||
|         self.get_declared_value(name).and_then(|val| {
 | ||
|             let declaration = llvm::is_declaration(val);
 | ||
|             if !declaration { Some(val) } else { None }
 | ||
|         })
 | ||
|     }
 | ||
| }
 | 
