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.
12 use llvm
::{self, SetUnnamedAddr, True}
;
13 use rustc
::hir
::def_id
::DefId
;
17 use monomorphize
::MonoItem
;
18 use common
::{CodegenCx, val_ty}
;
20 use monomorphize
::Instance
;
22 use syntax_pos
::symbol
::LocalInternedString
;
24 use type_of
::LayoutLlvmExt
;
26 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
: &'ll Value
, ty
: &'ll Type
) -> &'ll Value
{
36 llvm
::LLVMConstPointerCast(val
, ty
)
40 pub fn bitcast(val
: &'ll Value
, ty
: &'ll Type
) -> &'ll Value
{
42 llvm
::LLVMConstBitCast(val
, ty
)
46 fn set_global_alignment(cx
: &CodegenCx
<'ll
, '_
>,
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);
66 cx
: &CodegenCx
<'ll
, '_
>,
73 Some(kind
) if !cx
.tcx
.sess
.fewer_names() => {
74 let name
= cx
.generate_local_symbol_name(kind
);
75 let gv
= declare
::define_global(cx
, &name
[..], val_ty(cv
)).unwrap_or_else(||{
76 bug
!("symbol `{}` is already defined", name
);
78 llvm
::LLVMRustSetLinkage(gv
, llvm
::Linkage
::PrivateLinkage
);
81 _
=> declare
::define_private_global(cx
, val_ty(cv
)),
83 llvm
::LLVMSetInitializer(gv
, cv
);
84 set_global_alignment(cx
, gv
, align
);
85 SetUnnamedAddr(gv
, true);
91 cx
: &CodegenCx
<'ll
, '_
>,
96 if let Some(&gv
) = cx
.const_globals
.borrow().get(&cv
) {
98 // Upgrade the alignment in cases where the same constant is used with different
99 // alignment requirements
100 let llalign
= align
.abi() as u32;
101 if llalign
> llvm
::LLVMGetAlignment(gv
) {
102 llvm
::LLVMSetAlignment(gv
, llalign
);
107 let gv
= addr_of_mut(cx
, cv
, align
, kind
);
109 llvm
::LLVMSetGlobalConstant(gv
, True
);
111 cx
.const_globals
.borrow_mut().insert(cv
, gv
);
115 pub fn get_static(cx
: &CodegenCx
<'ll
, '_
>, def_id
: DefId
) -> &'ll Value
{
116 let instance
= Instance
::mono(cx
.tcx
, def_id
);
117 if let Some(&g
) = cx
.instances
.borrow().get(&instance
) {
121 let defined_in_current_codegen_unit
= cx
.codegen_unit
123 .contains_key(&MonoItem
::Static(def_id
));
124 assert
!(!defined_in_current_codegen_unit
,
125 "consts::get_static() should always hit the cache for \
126 statics defined in the same CGU, but did not for `{:?}`",
129 let ty
= instance
.ty(cx
.tcx
);
130 let sym
= cx
.tcx
.symbol_name(instance
).as_str();
132 debug
!("get_static: sym={} instance={:?}", sym
, instance
);
134 let g
= if let Some(id
) = cx
.tcx
.hir
.as_local_node_id(def_id
) {
136 let llty
= cx
.layout_of(ty
).llvm_type(cx
);
137 let (g
, attrs
) = match cx
.tcx
.hir
.get(id
) {
138 Node
::Item(&hir
::Item
{
139 ref attrs
, span
, node
: hir
::ItemKind
::Static(..), ..
141 if declare
::get_declared_value(cx
, &sym
[..]).is_some() {
142 span_bug
!(span
, "Conflicting symbol names for static?");
145 let g
= declare
::define_global(cx
, &sym
[..], llty
).unwrap();
147 if !cx
.tcx
.is_reachable_non_generic(def_id
) {
149 llvm
::LLVMRustSetVisibility(g
, llvm
::Visibility
::Hidden
);
156 Node
::ForeignItem(&hir
::ForeignItem
{
157 ref attrs
, span
, node
: hir
::ForeignItemKind
::Static(..), ..
159 let fn_attrs
= cx
.tcx
.codegen_fn_attrs(def_id
);
160 (check_and_apply_linkage(cx
, &fn_attrs
, ty
, sym
, Some(span
)), attrs
)
163 item
=> bug
!("get_static: expected static, found {:?}", item
)
166 debug
!("get_static: sym={} attrs={:?}", sym
, attrs
);
169 if attr
.check_name("thread_local") {
170 llvm
::set_thread_local_mode(g
, cx
.tls_model
);
176 // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
177 debug
!("get_static: sym={} item_attr={:?}", sym
, cx
.tcx
.item_attrs(def_id
));
179 let attrs
= cx
.tcx
.codegen_fn_attrs(def_id
);
180 let g
= check_and_apply_linkage(cx
, &attrs
, ty
, sym
, None
);
182 // Thread-local statics in some other crate need to *always* be linked
183 // against in a thread-local fashion, so we need to be sure to apply the
184 // thread-local attribute locally if it was present remotely. If we
185 // don't do this then linker errors can be generated where the linker
186 // complains that one object files has a thread local version of the
187 // symbol and another one doesn't.
188 if attrs
.flags
.contains(CodegenFnAttrFlags
::THREAD_LOCAL
) {
189 llvm
::set_thread_local_mode(g
, cx
.tls_model
);
192 let needs_dll_storage_attr
=
193 cx
.use_dll_storage_attrs
&& !cx
.tcx
.is_foreign_item(def_id
) &&
194 // ThinLTO can't handle this workaround in all cases, so we don't
195 // emit the attrs. Instead we make them unnecessary by disallowing
196 // dynamic linking when cross-language LTO is enabled.
197 !cx
.tcx
.sess
.opts
.debugging_opts
.cross_lang_lto
.enabled();
199 // If this assertion triggers, there's something wrong with commandline
200 // argument validation.
201 debug_assert
!(!(cx
.tcx
.sess
.opts
.debugging_opts
.cross_lang_lto
.enabled() &&
202 cx
.tcx
.sess
.target
.target
.options
.is_like_msvc
&&
203 cx
.tcx
.sess
.opts
.cg
.prefer_dynamic
));
205 if needs_dll_storage_attr
{
206 // This item is external but not foreign, i.e. it originates from an external Rust
207 // crate. Since we don't know whether this crate will be linked dynamically or
208 // statically in the final application, we always mark such symbols as 'dllimport'.
209 // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to
212 // However, in some scenarios we defer emission of statics to downstream
213 // crates, so there are cases where a static with an upstream DefId
214 // is actually present in the current crate. We can find out via the
215 // is_codegened_item query.
216 if !cx
.tcx
.is_codegened_item(def_id
) {
218 llvm
::LLVMSetDLLStorageClass(g
, llvm
::DLLStorageClass
::DllImport
);
225 if cx
.use_dll_storage_attrs
&& cx
.tcx
.is_dllimport_foreign_item(def_id
) {
226 // For foreign (native) libs we know the exact storage type to use.
228 llvm
::LLVMSetDLLStorageClass(g
, llvm
::DLLStorageClass
::DllImport
);
232 cx
.instances
.borrow_mut().insert(instance
, g
);
236 fn check_and_apply_linkage(
237 cx
: &CodegenCx
<'ll
, 'tcx
>,
238 attrs
: &CodegenFnAttrs
,
240 sym
: LocalInternedString
,
243 let llty
= cx
.layout_of(ty
).llvm_type(cx
);
244 if let Some(linkage
) = attrs
.linkage
{
245 debug
!("get_static: sym={} linkage={:?}", sym
, linkage
);
247 // If this is a static with a linkage specified, then we need to handle
248 // it a little specially. The typesystem prevents things like &T and
249 // extern "C" fn() from being non-null, so we can't just declare a
250 // static and call it a day. Some linkages (like weak) will make it such
251 // that the static actually has a null value.
252 let llty2
= if let ty
::RawPtr(ref mt
) = ty
.sty
{
253 cx
.layout_of(mt
.ty
).llvm_type(cx
)
255 if let Some(span
) = span
{
256 cx
.sess().span_fatal(span
, "must have type `*const T` or `*mut T`")
258 bug
!("must have type `*const T` or `*mut T`")
262 // Declare a symbol `foo` with the desired linkage.
263 let g1
= declare
::declare_global(cx
, &sym
, llty2
);
264 llvm
::LLVMRustSetLinkage(g1
, base
::linkage_to_llvm(linkage
));
266 // Declare an internal global `extern_with_linkage_foo` which
267 // is initialized with the address of `foo`. If `foo` is
268 // discarded during linking (for example, if `foo` has weak
269 // linkage and there are no definitions), then
270 // `extern_with_linkage_foo` will instead be initialized to
272 let mut real_name
= "_rust_extern_with_linkage_".to_string();
273 real_name
.push_str(&sym
);
274 let g2
= declare
::define_global(cx
, &real_name
, llty
).unwrap_or_else(||{
275 if let Some(span
) = span
{
276 cx
.sess().span_fatal(
278 &format
!("symbol `{}` is already defined", &sym
)
281 bug
!("symbol `{}` is already defined", &sym
)
284 llvm
::LLVMRustSetLinkage(g2
, llvm
::Linkage
::InternalLinkage
);
285 llvm
::LLVMSetInitializer(g2
, g1
);
289 // Generate an external declaration.
290 // FIXME(nagisa): investigate whether it can be changed into define_global
291 declare
::declare_global(cx
, &sym
, llty
)
295 pub fn codegen_static
<'a
, 'tcx
>(
296 cx
: &CodegenCx
<'a
, 'tcx
>,
301 let attrs
= cx
.tcx
.codegen_fn_attrs(def_id
);
303 let (v
, alloc
) = match ::mir
::codegen_static_initializer(cx
, def_id
) {
305 // Error has already been reported
309 let g
= get_static(cx
, def_id
);
311 // boolean SSA values are i1, but they have to be stored in i8 slots,
312 // otherwise some LLVM optimization passes don't work as expected
313 let mut val_llty
= val_ty(v
);
314 let v
= if val_llty
== Type
::i1(cx
) {
315 val_llty
= Type
::i8(cx
);
316 llvm
::LLVMConstZExt(v
, val_llty
)
321 let instance
= Instance
::mono(cx
.tcx
, def_id
);
322 let ty
= instance
.ty(cx
.tcx
);
323 let llty
= cx
.layout_of(ty
).llvm_type(cx
);
324 let g
= if val_llty
== llty
{
327 // If we created the global with the wrong type,
329 let empty_string
= const_cstr
!("");
330 let name_str_ref
= CStr
::from_ptr(llvm
::LLVMGetValueName(g
));
331 let name_string
= CString
::new(name_str_ref
.to_bytes()).unwrap();
332 llvm
::LLVMSetValueName(g
, empty_string
.as_ptr());
334 let linkage
= llvm
::LLVMRustGetLinkage(g
);
335 let visibility
= llvm
::LLVMRustGetVisibility(g
);
337 let new_g
= llvm
::LLVMRustGetOrInsertGlobal(
338 cx
.llmod
, name_string
.as_ptr(), val_llty
);
340 llvm
::LLVMRustSetLinkage(new_g
, linkage
);
341 llvm
::LLVMRustSetVisibility(new_g
, visibility
);
343 // To avoid breaking any invariants, we leave around the old
344 // global for the moment; we'll replace all references to it
345 // with the new global later. (See base::codegen_backend.)
346 cx
.statics_to_rauw
.borrow_mut().push((g
, new_g
));
349 set_global_alignment(cx
, g
, cx
.align_of(ty
));
350 llvm
::LLVMSetInitializer(g
, v
);
352 // As an optimization, all shared statics which do not have interior
353 // mutability are placed into read-only memory.
355 if cx
.type_is_freeze(ty
) {
356 llvm
::LLVMSetGlobalConstant(g
, llvm
::True
);
360 debuginfo
::create_global_var_metadata(cx
, def_id
, g
);
362 if attrs
.flags
.contains(CodegenFnAttrFlags
::THREAD_LOCAL
) {
363 llvm
::set_thread_local_mode(g
, cx
.tls_model
);
365 // Do not allow LLVM to change the alignment of a TLS on macOS.
367 // By default a global's alignment can be freely increased.
368 // This allows LLVM to generate more performant instructions
369 // e.g. using load-aligned into a SIMD register.
371 // However, on macOS 10.10 or below, the dynamic linker does not
372 // respect any alignment given on the TLS (radar 24221680).
373 // This will violate the alignment assumption, and causing segfault at runtime.
375 // This bug is very easy to trigger. In `println!` and `panic!`,
376 // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS,
377 // which the values would be `mem::replace`d on initialization.
378 // The implementation of `mem::replace` will use SIMD
379 // whenever the size is 32 bytes or higher. LLVM notices SIMD is used
380 // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary,
381 // which macOS's dyld disregarded and causing crashes
382 // (see issues #51794, #51758, #50867, #48866 and #44056).
384 // To workaround the bug, we trick LLVM into not increasing
385 // the global's alignment by explicitly assigning a section to it
386 // (equivalent to automatically generating a `#[link_section]` attribute).
387 // See the comment in the `GlobalValue::canIncreaseAlignment()` function
388 // of `lib/IR/Globals.cpp` for why this works.
390 // When the alignment is not increased, the optimized `mem::replace`
391 // will use load-unaligned instructions instead, and thus avoiding the crash.
393 // We could remove this hack whenever we decide to drop macOS 10.10 support.
394 if cx
.tcx
.sess
.target
.target
.options
.is_like_osx
{
395 let sect_name
= if alloc
.bytes
.iter().all(|b
| *b
== 0) {
396 CStr
::from_bytes_with_nul_unchecked(b
"__DATA,__thread_bss\0")
398 CStr
::from_bytes_with_nul_unchecked(b
"__DATA,__thread_data\0")
400 llvm
::LLVMSetSection(g
, sect_name
.as_ptr());
405 // Wasm statics with custom link sections get special treatment as they
406 // go into custom sections of the wasm executable.
407 if cx
.tcx
.sess
.opts
.target_triple
.triple().starts_with("wasm32") {
408 if let Some(section
) = attrs
.link_section
{
409 let section
= llvm
::LLVMMDStringInContext(
411 section
.as_str().as_ptr() as *const _
,
412 section
.as_str().len() as c_uint
,
414 let alloc
= llvm
::LLVMMDStringInContext(
416 alloc
.bytes
.as_ptr() as *const _
,
417 alloc
.bytes
.len() as c_uint
,
419 let data
= [section
, alloc
];
420 let meta
= llvm
::LLVMMDNodeInContext(cx
.llcx
, data
.as_ptr(), 2);
421 llvm
::LLVMAddNamedMetadataOperand(
423 "wasm.custom_sections\0".as_ptr() as *const _
,
428 base
::set_link_section(g
, &attrs
);
431 if attrs
.flags
.contains(CodegenFnAttrFlags
::USED
) {
432 // This static will be stored in the llvm.used variable which is an array of i8*
433 let cast
= llvm
::LLVMConstPointerCast(g
, Type
::i8p(cx
));
434 cx
.used_statics
.borrow_mut().push(cast
);