1use std::borrow::Borrow;
4
5use libc::{c_char, c_uint};
6use rustc_abi::Primitive::Pointer;
7use rustc_abi::{self as abi, ExternAbi, HasDataLayout as _};
8use rustc_ast::Mutability;
9use rustc_codegen_ssa::common::TypeKind;
10use rustc_codegen_ssa::traits::*;
11use rustc_data_structures::stable_hash::{StableHash, StableHasher};
12use rustc_hashes::Hash128;
13use rustc_hir::def::DefKind;
14use rustc_hir::def_id::DefId;
15use rustc_middle::bug;
16use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
17use rustc_middle::ty::{Instance, TyCtxt};
18use rustc_session::cstore::DllImport;
19use rustc_session::{PointerAuthAddressDiscriminator, PointerAuthSchema};
20use tracing::debug;
21
22use crate::consts::{IsInitOrFini, IsStatic, const_alloc_to_llvm};
23pub(crate) use crate::context::CodegenCx;
24use crate::context::{GenericCx, SCx};
25use crate::llvm::{
26 self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value, const_ptr_auth,
27};
28
29pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>(
30 cx: &CodegenCx<'ll, '_>,
31 instance: Instance<'tcx>,
32 llfn: &'ll llvm::Value,
33 schema: &PointerAuthSchema,
34) -> &'ll llvm::Value {
35 if cx.tcx.sess.pointer_authentication_functions().is_none() {
36 return llfn;
37 }
38
39 let def_id = instance.def_id();
41 if !#[allow(non_exhaustive_omitted_patterns)] match cx.tcx.def_kind(def_id) {
DefKind::Fn | DefKind::AssocFn => true,
_ => false,
}matches!(cx.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
42 return llfn;
43 }
44 let abi = cx.tcx.fn_sig(def_id).skip_binder().abi();
46 if !#[allow(non_exhaustive_omitted_patterns)] match abi {
ExternAbi::C { .. } | ExternAbi::System { .. } => true,
_ => false,
}matches!(abi, ExternAbi::C { .. } | ExternAbi::System { .. }) {
47 return llfn;
48 }
49 if llvm::get_value_name(llfn).starts_with(b"llvm.") {
51 return llfn;
52 }
53 if Some(def_id) == cx.tcx.lang_items().eh_personality() {
54 return llfn;
55 }
56
57 let addr_diversity = match schema.is_address_discriminated {
58 PointerAuthAddressDiscriminator::HardwareAddress(true) => Some(llfn),
59 PointerAuthAddressDiscriminator::HardwareAddress(false) => None,
60 PointerAuthAddressDiscriminator::Synthetic(val) => {
61 let llval = cx.const_u64(val);
62 let llty = cx.val_ty(llfn);
63 Some(unsafe { llvm::LLVMConstIntToPtr(llval, llty) })
64 }
65 };
66 const_ptr_auth(llfn, schema.key as u32, schema.constant_discriminator as u64, addr_diversity)
67}
68
69pub(crate) struct Funclet<'ll> {
110 cleanuppad: &'ll Value,
111 operand: llvm::OperandBundleBox<'ll>,
112}
113
114impl<'ll> Funclet<'ll> {
115 pub(crate) fn new(cleanuppad: &'ll Value) -> Self {
116 Funclet { cleanuppad, operand: llvm::OperandBundleBox::new("funclet", &[cleanuppad]) }
117 }
118
119 pub(crate) fn cleanuppad(&self) -> &'ll Value {
120 self.cleanuppad
121 }
122
123 pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> {
124 self.operand.as_ref()
125 }
126}
127
128impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericCx<'ll, CX> {
129 type Function = &'ll Value;
131 type BasicBlock = &'ll BasicBlock;
132 type Funclet = Funclet<'ll>;
133
134 type Value = &'ll Value;
135 type Type = &'ll Type;
136 type FunctionSignature = &'ll Type;
137
138 type DIScope = &'ll llvm::debuginfo::DIScope;
139 type DILocation = &'ll llvm::debuginfo::DILocation;
140 type DIVariable = &'ll llvm::debuginfo::DIVariable;
141}
142
143impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
144 pub(crate) fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
145 let len = u64::try_from(elts.len()).expect("LLVMConstArray2 elements len overflow");
146 unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) }
147 }
148
149 pub(crate) fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
150 bytes_in_context(self.llcx(), bytes)
151 }
152
153 pub(crate) fn null_terminate_const_bytes(&self, bytes: &[u8]) -> &'ll Value {
154 null_terminate_bytes_in_context(self.llcx(), bytes)
155 }
156
157 pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
158 unsafe {
159 let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow");
160 let r = llvm::LLVMGetAggregateElement(v, idx).unwrap();
161
162 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/common.rs:162",
"rustc_codegen_llvm::common", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/common.rs"),
::tracing_core::__macro_support::Option::Some(162u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::common"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("const_get_elt(v={0:?}, idx={1}, r={2:?})",
v, idx, r) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("const_get_elt(v={:?}, idx={}, r={:?})", v, idx, r);
163
164 r
165 }
166 }
167
168 pub(crate) fn const_null(&self, t: &'ll Type) -> &'ll Value {
169 unsafe { llvm::LLVMConstNull(t) }
170 }
171
172 pub(crate) fn const_struct(&self, elts: &[&'ll Value], packed: bool) -> &'ll Value {
173 struct_in_context(self.llcx(), elts, packed)
174 }
175}
176
177impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
178 pub(crate) fn alloc_to_backend(
179 &self,
180 global_alloc: GlobalAlloc<'tcx>,
181 need_symbol_name: bool,
182 schema: Option<&PointerAuthSchema>,
183 ) -> Result<&'ll Value, u64> {
184 let alloc = match global_alloc {
185 GlobalAlloc::Function { instance, .. } => {
186 return Ok(self.get_fn_addr(instance, schema));
187 }
188 GlobalAlloc::Static(def_id) => {
189 if !self.tcx.is_static(def_id) {
::core::panicking::panic("assertion failed: self.tcx.is_static(def_id)")
};assert!(self.tcx.is_static(def_id));
190 if !!self.tcx.is_thread_local_static(def_id) {
::core::panicking::panic("assertion failed: !self.tcx.is_thread_local_static(def_id)")
};assert!(!self.tcx.is_thread_local_static(def_id));
191 return Ok(
192 self.renamed_statics
195 .borrow()
196 .get(&def_id)
197 .copied()
198 .unwrap_or_else(|| self.get_static(def_id)),
199 );
200 }
201 GlobalAlloc::TypeId { .. } => {
202 return Err(0);
205 }
206
207 GlobalAlloc::Memory(alloc) => {
208 if alloc.inner().len() == 0 {
209 return Err(alloc.inner().align.bytes());
213 }
214
215 alloc
216 }
217 GlobalAlloc::VTable(ty, dyn_ty) => {
218 self.tcx
219 .global_alloc(self.tcx.vtable_allocation((
220 ty,
221 dyn_ty.principal().map(|principal| {
222 self.tcx.instantiate_bound_regions_with_erased(principal)
223 }),
224 )))
225 .unwrap_memory()
226 }
227 };
228
229 let init = const_alloc_to_llvm(self, alloc.inner(), IsStatic::No, IsInitOrFini::No);
230 let alloc = alloc.inner();
231
232 if need_symbol_name {
233 let value = self.static_addr_of_mut(init, alloc.align, None);
235 if alloc.mutability.is_not() {
236 llvm::set_global_constant(value, true);
237 }
238
239 let name = self.generate_global_symbol_name();
243 llvm::set_value_name(value, name.as_bytes());
244 llvm::set_linkage(value, llvm::Linkage::InternalLinkage);
245 return Ok(value);
246 }
247
248 let value = match alloc.mutability {
249 Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
250 _ => self.static_addr_of_impl(init, alloc.align, None),
251 };
252 if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() {
253 let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
254 let mut hasher = StableHasher::new();
255 alloc.stable_hash(&mut hcx, &mut hasher);
256 hasher.finish::<Hash128>()
257 });
258 llvm::set_value_name(value, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("alloc_{0:032x}", hash))
})format!("alloc_{hash:032x}").as_bytes());
259 }
260
261 Ok(value)
262 }
263}
264
265impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
266 fn const_null(&self, t: &'ll Type) -> &'ll Value {
267 unsafe { llvm::LLVMConstNull(t) }
268 }
269
270 fn const_undef(&self, t: &'ll Type) -> &'ll Value {
271 unsafe { llvm::LLVMGetUndef(t) }
272 }
273
274 fn const_poison(&self, t: &'ll Type) -> &'ll Value {
275 unsafe { llvm::LLVMGetPoison(t) }
276 }
277
278 fn const_bool(&self, val: bool) -> &'ll Value {
279 self.const_uint(self.type_i1(), val as u64)
280 }
281
282 fn const_i8(&self, i: i8) -> &'ll Value {
283 self.const_int(self.type_i8(), i as i64)
284 }
285
286 fn const_i16(&self, i: i16) -> &'ll Value {
287 self.const_int(self.type_i16(), i as i64)
288 }
289
290 fn const_i32(&self, i: i32) -> &'ll Value {
291 self.const_int(self.type_i32(), i as i64)
292 }
293
294 fn const_i64(&self, i: i64) -> &'ll Value {
295 self.const_int(self.type_i64(), i as i64)
296 }
297
298 fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value {
299 if true {
if !(self.type_kind(t) == TypeKind::Integer) {
{
::core::panicking::panic_fmt(format_args!("only allows integer types in const_int"));
}
};
};debug_assert!(
300 self.type_kind(t) == TypeKind::Integer,
301 "only allows integer types in const_int"
302 );
303 unsafe { llvm::LLVMConstInt(t, i as u64, TRUE) }
304 }
305
306 fn const_u8(&self, i: u8) -> &'ll Value {
307 self.const_uint(self.type_i8(), i as u64)
308 }
309
310 fn const_u32(&self, i: u32) -> &'ll Value {
311 self.const_uint(self.type_i32(), i as u64)
312 }
313
314 fn const_u64(&self, i: u64) -> &'ll Value {
315 self.const_uint(self.type_i64(), i)
316 }
317
318 fn const_u128(&self, i: u128) -> &'ll Value {
319 self.const_uint_big(self.type_i128(), i)
320 }
321
322 fn const_usize(&self, i: u64) -> &'ll Value {
323 let bit_size = self.data_layout().pointer_size().bits();
324 if bit_size < 64 {
325 if !(i < (1 << bit_size)) {
::core::panicking::panic("assertion failed: i < (1 << bit_size)")
};assert!(i < (1 << bit_size));
327 }
328
329 self.const_uint(self.isize_ty, i)
330 }
331
332 fn const_uint(&self, t: &'ll Type, i: u64) -> &'ll Value {
333 if true {
if !(self.type_kind(t) == TypeKind::Integer) {
{
::core::panicking::panic_fmt(format_args!("only allows integer types in const_uint"));
}
};
};debug_assert!(
334 self.type_kind(t) == TypeKind::Integer,
335 "only allows integer types in const_uint"
336 );
337 unsafe { llvm::LLVMConstInt(t, i, FALSE) }
338 }
339
340 fn const_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value {
341 if true {
if !(self.type_kind(t) == TypeKind::Integer) {
{
::core::panicking::panic_fmt(format_args!("only allows integer types in const_uint_big"));
}
};
};debug_assert!(
342 self.type_kind(t) == TypeKind::Integer,
343 "only allows integer types in const_uint_big"
344 );
345 unsafe {
346 let words = [u as u64, (u >> 64) as u64];
347 llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr())
348 }
349 }
350
351 fn const_real(&self, t: &'ll Type, val: f64) -> &'ll Value {
352 unsafe { llvm::LLVMConstReal(t, val) }
353 }
354
355 fn const_str(&self, s: &str) -> (&'ll Value, &'ll Value) {
356 let mut const_str_cache = self.const_str_cache.borrow_mut();
357 let str_global = const_str_cache.get(s).copied().unwrap_or_else(|| {
358 let sc = self.const_bytes(s.as_bytes());
359 let sym = self.generate_local_symbol_name("str");
360 let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
361 ::rustc_middle::util::bug::bug_fmt(format_args!("symbol `{0}` is already defined",
sym));bug!("symbol `{}` is already defined", sym);
362 });
363 llvm::set_initializer(g, sc);
364
365 llvm::set_global_constant(g, true);
366 llvm::set_unnamed_address(g, llvm::UnnamedAddr::Global);
367
368 llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
369 let g = self.const_pointercast(g, self.type_ptr());
371 const_str_cache.insert(s.to_owned(), g);
372 g
373 });
374 let len = s.len();
375 (str_global, self.const_usize(len as u64))
376 }
377
378 fn const_struct(&self, elts: &[&'ll Value], packed: bool) -> &'ll Value {
379 struct_in_context(self.llcx, elts, packed)
380 }
381
382 fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
383 let len = c_uint::try_from(elts.len()).expect("LLVMConstVector elements len overflow");
384 unsafe { llvm::LLVMConstVector(elts.as_ptr(), len) }
385 }
386
387 fn const_to_opt_uint(&self, v: &'ll Value) -> Option<u64> {
388 try_as_const_integral(v).and_then(|v| unsafe {
389 let mut i = 0u64;
390 let success = llvm::LLVMRustConstIntGetZExtValue(v, &mut i);
391 success.then_some(i)
392 })
393 }
394
395 fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option<u128> {
396 try_as_const_integral(v).and_then(|v| unsafe {
397 let (mut lo, mut hi) = (0u64, 0u64);
398 let success = llvm::LLVMRustConstInt128Get(v, sign_ext, &mut hi, &mut lo);
399 success.then_some(hi_lo_to_u128(lo, hi))
400 })
401 }
402
403 fn scalar_to_backend_with_pac(
404 &self,
405 cv: Scalar,
406 layout: abi::Scalar,
407 llty: &'ll Type,
408 schema: Option<&PointerAuthSchema>,
409 ) -> &'ll Value {
410 let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
411 match cv {
412 Scalar::Int(int) => {
413 let data = int.to_bits(layout.size(self));
414 let llval = self.const_uint_big(self.type_ix(bitsize), data);
415 if #[allow(non_exhaustive_omitted_patterns)] match layout.primitive() {
Pointer(_) => true,
_ => false,
}matches!(layout.primitive(), Pointer(_)) {
416 unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
417 } else {
418 self.const_bitcast(llval, llty)
419 }
420 }
421 Scalar::Ptr(ptr, _size) => {
422 let (prov, offset) = ptr.prov_and_relative_offset();
423 let global_alloc = self.tcx.global_alloc(prov.alloc_id());
424 let base_addr_space = global_alloc.address_space(self);
425 let base_addr = match self.alloc_to_backend(global_alloc, false, schema) {
426 Ok(base_addr) => base_addr,
427 Err(base_addr) => {
428 let val = base_addr.wrapping_add(offset.bytes());
429 let llval = self.const_usize(self.tcx.truncate_to_target_usize(val));
430 return if #[allow(non_exhaustive_omitted_patterns)] match layout.primitive() {
Pointer(_) => true,
_ => false,
}matches!(layout.primitive(), Pointer(_)) {
431 unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
432 } else {
433 self.const_bitcast(llval, llty)
434 };
435 }
436 };
437 let llval = unsafe {
438 llvm::LLVMConstInBoundsGEP2(
439 self.type_i8(),
440 self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)),
442 &self.const_usize(offset.bytes()),
443 1,
444 )
445 };
446 if !#[allow(non_exhaustive_omitted_patterns)] match layout.primitive() {
Pointer(_) => true,
_ => false,
}matches!(layout.primitive(), Pointer(_)) {
447 unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
448 } else {
449 self.const_bitcast(llval, llty)
450 }
451 }
452 }
453 }
454
455 fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
456 unsafe {
457 llvm::LLVMConstInBoundsGEP2(
458 self.type_i8(),
459 base_addr,
460 &self.const_usize(offset.bytes()),
461 1,
462 )
463 }
464 }
465}
466
467pub(crate) fn val_ty(v: &Value) -> &Type {
469 unsafe { llvm::LLVMTypeOf(v) }
470}
471
472pub(crate) fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
473 unsafe {
474 let ptr = bytes.as_ptr() as *const c_char;
475 llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), TRUE)
476 }
477}
478
479pub(crate) fn null_terminate_bytes_in_context<'ll>(
480 llcx: &'ll llvm::Context,
481 bytes: &[u8],
482) -> &'ll Value {
483 unsafe {
484 let ptr = bytes.as_ptr() as *const c_char;
485 llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), FALSE)
486 }
487}
488
489pub(crate) fn named_struct<'ll>(ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
490 let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow");
491 unsafe { llvm::LLVMConstNamedStruct(ty, elts.as_ptr(), len) }
492}
493
494fn struct_in_context<'ll>(
495 llcx: &'ll llvm::Context,
496 elts: &[&'ll Value],
497 packed: bool,
498) -> &'ll Value {
499 let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow");
500 unsafe { llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), len, packed.to_llvm_bool()) }
501}
502
503#[inline]
504fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 {
505 ((hi as u128) << 64) | (lo as u128)
506}
507
508fn try_as_const_integral(v: &Value) -> Option<&ConstantInt> {
509 unsafe { llvm::LLVMIsAConstantInt(v) }
510}
511
512pub(crate) fn get_dllimport<'tcx>(
513 tcx: TyCtxt<'tcx>,
514 id: DefId,
515 name: &str,
516) -> Option<&'tcx DllImport> {
517 tcx.native_library(id)
518 .and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name))
519}
520
521pub(crate) trait AsCCharPtr {
523 fn as_c_char_ptr(&self) -> *const c_char;
525}
526
527impl AsCCharPtr for str {
528 fn as_c_char_ptr(&self) -> *const c_char {
529 self.as_ptr().cast()
530 }
531}
532
533impl AsCCharPtr for [u8] {
534 fn as_c_char_ptr(&self) -> *const c_char {
535 self.as_ptr().cast()
536 }
537}