1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use llvm
::{SetUnnamedAddr}
;
14 use llvm
::{ValueRef, True}
;
15 use rustc
::hir
::def_id
::DefId
;
16 use rustc
::hir
::map
as hir_map
;
19 use monomorphize
::MonoItem
;
20 use common
::{CodegenCx, val_ty}
;
22 use monomorphize
::Instance
;
24 use syntax_pos
::symbol
::LocalInternedString
;
26 use type_of
::LayoutLlvmExt
;
27 use rustc
::ty
::{self, Ty}
;
28 use rustc
::ty
::layout
::{Align, LayoutOf}
;
30 use rustc
::hir
::{self, CodegenFnAttrs, CodegenFnAttrFlags}
;
32 use std
::ffi
::{CStr, CString}
;
34 pub fn ptrcast(val
: ValueRef
, ty
: Type
) -> ValueRef
{
36 llvm
::LLVMConstPointerCast(val
, ty
.to_ref())
40 pub fn bitcast(val
: ValueRef
, ty
: Type
) -> ValueRef
{
42 llvm
::LLVMConstBitCast(val
, ty
.to_ref())
46 fn set_global_alignment(cx
: &CodegenCx
,
49 // The target may require greater alignment for globals than the type does.
50 // Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
51 // which can force it to be smaller. Rust doesn't support this yet.
52 if let Some(min
) = cx
.sess().target
.target
.options
.min_global_align
{
53 match ty
::layout
::Align
::from_bits(min
, min
) {
54 Ok(min
) => align
= align
.max(min
),
56 cx
.sess().err(&format
!("invalid minimum global alignment: {}", err
));
61 llvm
::LLVMSetAlignment(gv
, align
.abi() as u32);
65 pub fn addr_of_mut(cx
: &CodegenCx
,
71 let name
= cx
.generate_local_symbol_name(kind
);
72 let gv
= declare
::define_global(cx
, &name
[..], val_ty(cv
)).unwrap_or_else(||{
73 bug
!("symbol `{}` is already defined", name
);
75 llvm
::LLVMSetInitializer(gv
, cv
);
76 set_global_alignment(cx
, gv
, align
);
77 llvm
::LLVMRustSetLinkage(gv
, llvm
::Linkage
::PrivateLinkage
);
78 SetUnnamedAddr(gv
, true);
83 pub fn addr_of(cx
: &CodegenCx
,
88 if let Some(&gv
) = cx
.const_globals
.borrow().get(&cv
) {
90 // Upgrade the alignment in cases where the same constant is used with different
91 // alignment requirements
92 let llalign
= align
.abi() as u32;
93 if llalign
> llvm
::LLVMGetAlignment(gv
) {
94 llvm
::LLVMSetAlignment(gv
, llalign
);
99 let gv
= addr_of_mut(cx
, cv
, align
, kind
);
101 llvm
::LLVMSetGlobalConstant(gv
, True
);
103 cx
.const_globals
.borrow_mut().insert(cv
, gv
);
107 pub fn get_static(cx
: &CodegenCx
, def_id
: DefId
) -> ValueRef
{
108 let instance
= Instance
::mono(cx
.tcx
, def_id
);
109 if let Some(&g
) = cx
.instances
.borrow().get(&instance
) {
113 let defined_in_current_codegen_unit
= cx
.codegen_unit
115 .contains_key(&MonoItem
::Static(def_id
));
116 assert
!(!defined_in_current_codegen_unit
,
117 "consts::get_static() should always hit the cache for \
118 statics defined in the same CGU, but did not for `{:?}`",
121 let ty
= instance
.ty(cx
.tcx
);
122 let sym
= cx
.tcx
.symbol_name(instance
).as_str();
124 debug
!("get_static: sym={} instance={:?}", sym
, instance
);
126 let g
= if let Some(id
) = cx
.tcx
.hir
.as_local_node_id(def_id
) {
128 let llty
= cx
.layout_of(ty
).llvm_type(cx
);
129 let (g
, attrs
) = match cx
.tcx
.hir
.get(id
) {
130 hir_map
::NodeItem(&hir
::Item
{
131 ref attrs
, span
, node
: hir
::ItemKind
::Static(..), ..
133 if declare
::get_declared_value(cx
, &sym
[..]).is_some() {
134 span_bug
!(span
, "Conflicting symbol names for static?");
137 let g
= declare
::define_global(cx
, &sym
[..], llty
).unwrap();
139 if !cx
.tcx
.is_reachable_non_generic(def_id
) {
141 llvm
::LLVMRustSetVisibility(g
, llvm
::Visibility
::Hidden
);
148 hir_map
::NodeForeignItem(&hir
::ForeignItem
{
149 ref attrs
, span
, node
: hir
::ForeignItemKind
::Static(..), ..
151 let fn_attrs
= cx
.tcx
.codegen_fn_attrs(def_id
);
152 (check_and_apply_linkage(cx
, &fn_attrs
, ty
, sym
, Some(span
)), attrs
)
155 item
=> bug
!("get_static: expected static, found {:?}", item
)
158 debug
!("get_static: sym={} attrs={:?}", sym
, attrs
);
161 if attr
.check_name("thread_local") {
162 llvm
::set_thread_local_mode(g
, cx
.tls_model
);
168 // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
169 debug
!("get_static: sym={} item_attr={:?}", sym
, cx
.tcx
.item_attrs(def_id
));
171 let attrs
= cx
.tcx
.codegen_fn_attrs(def_id
);
172 let g
= check_and_apply_linkage(cx
, &attrs
, ty
, sym
, None
);
174 // Thread-local statics in some other crate need to *always* be linked
175 // against in a thread-local fashion, so we need to be sure to apply the
176 // thread-local attribute locally if it was present remotely. If we
177 // don't do this then linker errors can be generated where the linker
178 // complains that one object files has a thread local version of the
179 // symbol and another one doesn't.
180 if attrs
.flags
.contains(CodegenFnAttrFlags
::THREAD_LOCAL
) {
181 llvm
::set_thread_local_mode(g
, cx
.tls_model
);
184 if cx
.use_dll_storage_attrs
&& !cx
.tcx
.is_foreign_item(def_id
) {
185 // This item is external but not foreign, i.e. it originates from an external Rust
186 // crate. Since we don't know whether this crate will be linked dynamically or
187 // statically in the final application, we always mark such symbols as 'dllimport'.
188 // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to
191 // However, in some scenarios we defer emission of statics to downstream
192 // crates, so there are cases where a static with an upstream DefId
193 // is actually present in the current crate. We can find out via the
194 // is_codegened_item query.
195 if !cx
.tcx
.is_codegened_item(def_id
) {
197 llvm
::LLVMSetDLLStorageClass(g
, llvm
::DLLStorageClass
::DllImport
);
204 if cx
.use_dll_storage_attrs
&& cx
.tcx
.is_dllimport_foreign_item(def_id
) {
205 // For foreign (native) libs we know the exact storage type to use.
207 llvm
::LLVMSetDLLStorageClass(g
, llvm
::DLLStorageClass
::DllImport
);
211 cx
.instances
.borrow_mut().insert(instance
, g
);
212 cx
.statics
.borrow_mut().insert(g
, def_id
);
216 fn check_and_apply_linkage
<'tcx
>(
217 cx
: &CodegenCx
<'_
, 'tcx
>,
218 attrs
: &CodegenFnAttrs
,
220 sym
: LocalInternedString
,
223 let llty
= cx
.layout_of(ty
).llvm_type(cx
);
224 if let Some(linkage
) = attrs
.linkage
{
225 debug
!("get_static: sym={} linkage={:?}", sym
, linkage
);
227 // If this is a static with a linkage specified, then we need to handle
228 // it a little specially. The typesystem prevents things like &T and
229 // extern "C" fn() from being non-null, so we can't just declare a
230 // static and call it a day. Some linkages (like weak) will make it such
231 // that the static actually has a null value.
232 let llty2
= match ty
.sty
{
233 ty
::TyRawPtr(ref mt
) => cx
.layout_of(mt
.ty
).llvm_type(cx
),
236 cx
.sess().span_fatal(span
.unwrap(), "must have type `*const T` or `*mut T`")
238 bug
!("must have type `*const T` or `*mut T`")
243 // Declare a symbol `foo` with the desired linkage.
244 let g1
= declare
::declare_global(cx
, &sym
, llty2
);
245 llvm
::LLVMRustSetLinkage(g1
, base
::linkage_to_llvm(linkage
));
247 // Declare an internal global `extern_with_linkage_foo` which
248 // is initialized with the address of `foo`. If `foo` is
249 // discarded during linking (for example, if `foo` has weak
250 // linkage and there are no definitions), then
251 // `extern_with_linkage_foo` will instead be initialized to
253 let mut real_name
= "_rust_extern_with_linkage_".to_string();
254 real_name
.push_str(&sym
);
255 let g2
= declare
::define_global(cx
, &real_name
, llty
).unwrap_or_else(||{
257 cx
.sess().span_fatal(
259 &format
!("symbol `{}` is already defined", &sym
)
262 bug
!("symbol `{}` is already defined", &sym
)
265 llvm
::LLVMRustSetLinkage(g2
, llvm
::Linkage
::InternalLinkage
);
266 llvm
::LLVMSetInitializer(g2
, g1
);
270 // Generate an external declaration.
271 // FIXME(nagisa): investigate whether it can be changed into define_global
272 declare
::declare_global(cx
, &sym
, llty
)
276 pub fn codegen_static
<'a
, 'tcx
>(
277 cx
: &CodegenCx
<'a
, 'tcx
>,
282 let attrs
= cx
.tcx
.codegen_fn_attrs(def_id
);
284 let (v
, alloc
) = match ::mir
::codegen_static_initializer(cx
, def_id
) {
286 // Error has already been reported
290 let g
= get_static(cx
, def_id
);
292 // boolean SSA values are i1, but they have to be stored in i8 slots,
293 // otherwise some LLVM optimization passes don't work as expected
294 let mut val_llty
= val_ty(v
);
295 let v
= if val_llty
== Type
::i1(cx
) {
296 val_llty
= Type
::i8(cx
);
297 llvm
::LLVMConstZExt(v
, val_llty
.to_ref())
302 let instance
= Instance
::mono(cx
.tcx
, def_id
);
303 let ty
= instance
.ty(cx
.tcx
);
304 let llty
= cx
.layout_of(ty
).llvm_type(cx
);
305 let g
= if val_llty
== llty
{
308 // If we created the global with the wrong type,
310 let empty_string
= CString
::new("").unwrap();
311 let name_str_ref
= CStr
::from_ptr(llvm
::LLVMGetValueName(g
));
312 let name_string
= CString
::new(name_str_ref
.to_bytes()).unwrap();
313 llvm
::LLVMSetValueName(g
, empty_string
.as_ptr());
315 let linkage
= llvm
::LLVMRustGetLinkage(g
);
316 let visibility
= llvm
::LLVMRustGetVisibility(g
);
318 let new_g
= llvm
::LLVMRustGetOrInsertGlobal(
319 cx
.llmod
, name_string
.as_ptr(), val_llty
.to_ref());
321 llvm
::LLVMRustSetLinkage(new_g
, linkage
);
322 llvm
::LLVMRustSetVisibility(new_g
, visibility
);
324 // To avoid breaking any invariants, we leave around the old
325 // global for the moment; we'll replace all references to it
326 // with the new global later. (See base::codegen_backend.)
327 cx
.statics_to_rauw
.borrow_mut().push((g
, new_g
));
330 set_global_alignment(cx
, g
, cx
.align_of(ty
));
331 llvm
::LLVMSetInitializer(g
, v
);
333 // As an optimization, all shared statics which do not have interior
334 // mutability are placed into read-only memory.
336 if cx
.type_is_freeze(ty
) {
337 llvm
::LLVMSetGlobalConstant(g
, llvm
::True
);
341 debuginfo
::create_global_var_metadata(cx
, def_id
, g
);
343 if attrs
.flags
.contains(CodegenFnAttrFlags
::THREAD_LOCAL
) {
344 llvm
::set_thread_local_mode(g
, cx
.tls_model
);
346 // Do not allow LLVM to change the alignment of a TLS on macOS.
348 // By default a global's alignment can be freely increased.
349 // This allows LLVM to generate more performant instructions
350 // e.g. using load-aligned into a SIMD register.
352 // However, on macOS 10.10 or below, the dynamic linker does not
353 // respect any alignment given on the TLS (radar 24221680).
354 // This will violate the alignment assumption, and causing segfault at runtime.
356 // This bug is very easy to trigger. In `println!` and `panic!`,
357 // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS,
358 // which the values would be `mem::replace`d on initialization.
359 // The implementation of `mem::replace` will use SIMD
360 // whenever the size is 32 bytes or higher. LLVM notices SIMD is used
361 // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary,
362 // which macOS's dyld disregarded and causing crashes
363 // (see issues #51794, #51758, #50867, #48866 and #44056).
365 // To workaround the bug, we trick LLVM into not increasing
366 // the global's alignment by explicitly assigning a section to it
367 // (equivalent to automatically generating a `#[link_section]` attribute).
368 // See the comment in the `GlobalValue::canIncreaseAlignment()` function
369 // of `lib/IR/Globals.cpp` for why this works.
371 // When the alignment is not increased, the optimized `mem::replace`
372 // will use load-unaligned instructions instead, and thus avoiding the crash.
374 // We could remove this hack whenever we decide to drop macOS 10.10 support.
375 if cx
.tcx
.sess
.target
.target
.options
.is_like_osx
{
376 let sect_name
= if alloc
.bytes
.iter().all(|b
| *b
== 0) {
377 CStr
::from_bytes_with_nul_unchecked(b
"__DATA,__thread_bss\0")
379 CStr
::from_bytes_with_nul_unchecked(b
"__DATA,__thread_data\0")
381 llvm
::LLVMSetSection(g
, sect_name
.as_ptr());
386 // Wasm statics with custom link sections get special treatment as they
387 // go into custom sections of the wasm executable.
388 if cx
.tcx
.sess
.opts
.target_triple
.triple().starts_with("wasm32") {
389 if let Some(section
) = attrs
.link_section
{
390 let section
= llvm
::LLVMMDStringInContext(
392 section
.as_str().as_ptr() as *const _
,
393 section
.as_str().len() as c_uint
,
395 let alloc
= llvm
::LLVMMDStringInContext(
397 alloc
.bytes
.as_ptr() as *const _
,
398 alloc
.bytes
.len() as c_uint
,
400 let data
= [section
, alloc
];
401 let meta
= llvm
::LLVMMDNodeInContext(cx
.llcx
, data
.as_ptr(), 2);
402 llvm
::LLVMAddNamedMetadataOperand(
404 "wasm.custom_sections\0".as_ptr() as *const _
,
409 base
::set_link_section(g
, &attrs
);
412 if attrs
.flags
.contains(CodegenFnAttrFlags
::USED
) {
413 // This static will be stored in the llvm.used variable which is an array of i8*
414 let cast
= llvm
::LLVMConstPointerCast(g
, Type
::i8p(cx
).to_ref());
415 cx
.used_statics
.borrow_mut().push(cast
);