]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::base; |
dfeec247 XL |
2 | use crate::common::CodegenCx; |
3 | use crate::debuginfo; | |
ba9703b0 | 4 | use crate::llvm::{self, True}; |
9fa01778 XL |
5 | use crate::type_::Type; |
6 | use crate::type_of::LayoutLlvmExt; | |
7 | use crate::value::Value; | |
6a06907d | 8 | use cstr::cstr; |
8faf50e0 | 9 | use libc::c_uint; |
dfeec247 | 10 | use rustc_codegen_ssa::traits::*; |
dfeec247 | 11 | use rustc_hir::def_id::DefId; |
ba9703b0 XL |
12 | use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; |
13 | use rustc_middle::mir::interpret::{ | |
1b1a35ee | 14 | read_target_uint, Allocation, ErrorHandled, GlobalAlloc, Pointer, |
ba9703b0 XL |
15 | }; |
16 | use rustc_middle::mir::mono::MonoItem; | |
17 | use rustc_middle::ty::{self, Instance, Ty}; | |
18 | use rustc_middle::{bug, span_bug}; | |
3dfed10e XL |
19 | use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size}; |
20 | use tracing::debug; | |
e9174d1e | 21 | |
a1dfa0c6 | 22 | pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value { |
e1599b0c | 23 | let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); |
a1dfa0c6 XL |
24 | let dl = cx.data_layout(); |
25 | let pointer_size = dl.pointer_size.bytes() as usize; | |
26 | ||
27 | let mut next_offset = 0; | |
e1599b0c | 28 | for &(offset, ((), alloc_id)) in alloc.relocations().iter() { |
a1dfa0c6 XL |
29 | let offset = offset.bytes(); |
30 | assert_eq!(offset as usize as u64, offset); | |
31 | let offset = offset as usize; | |
32 | if offset > next_offset { | |
e1599b0c XL |
33 | // This `inspect` is okay since we have checked that it is not within a relocation, it |
34 | // is within the bounds of the allocation, and it doesn't affect interpreter execution | |
35 | // (we inspect the result after interpreter execution). Any undef byte is replaced with | |
36 | // some arbitrary byte value. | |
37 | // | |
38 | // FIXME: relay undef bytes to codegen as undef const bytes | |
3dfed10e | 39 | let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset); |
e1599b0c | 40 | llvals.push(cx.const_bytes(bytes)); |
a1dfa0c6 XL |
41 | } |
42 | let ptr_offset = read_target_uint( | |
43 | dl.endian, | |
e1599b0c XL |
44 | // This `inspect` is okay since it is within the bounds of the allocation, it doesn't |
45 | // affect interpreter execution (we inspect the result after interpreter execution), | |
46 | // and we properly interpret the relocation as a relocation pointer offset. | |
3dfed10e | 47 | alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), |
dfeec247 XL |
48 | ) |
49 | .expect("const_alloc_to_llvm: could not read relocation pointer") | |
50 | as u64; | |
3dfed10e XL |
51 | |
52 | let address_space = match cx.tcx.global_alloc(alloc_id) { | |
53 | GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, | |
54 | GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA, | |
55 | }; | |
56 | ||
a1dfa0c6 XL |
57 | llvals.push(cx.scalar_to_backend( |
58 | Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(), | |
ba9703b0 | 59 | &Scalar { value: Primitive::Pointer, valid_range: 0..=!0 }, |
3dfed10e | 60 | cx.type_i8p_ext(address_space), |
a1dfa0c6 XL |
61 | )); |
62 | next_offset = offset + pointer_size; | |
1a4d82fc | 63 | } |
e1599b0c XL |
64 | if alloc.len() >= next_offset { |
65 | let range = next_offset..alloc.len(); | |
66 | // This `inspect` is okay since we have check that it is after all relocations, it is | |
67 | // within the bounds of the allocation, and it doesn't affect interpreter execution (we | |
68 | // inspect the result after interpreter execution). Any undef byte is replaced with some | |
69 | // arbitrary byte value. | |
70 | // | |
71 | // FIXME: relay undef bytes to codegen as undef const bytes | |
3dfed10e | 72 | let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range); |
e1599b0c | 73 | llvals.push(cx.const_bytes(bytes)); |
a1dfa0c6 XL |
74 | } |
75 | ||
76 | cx.const_struct(&llvals, true) | |
1a4d82fc JJ |
77 | } |
78 | ||
a1dfa0c6 XL |
79 | pub fn codegen_static_initializer( |
80 | cx: &CodegenCx<'ll, 'tcx>, | |
81 | def_id: DefId, | |
82 | ) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { | |
1b1a35ee | 83 | let alloc = cx.tcx.eval_static_initializer(def_id)?; |
a1dfa0c6 | 84 | Ok((const_alloc_to_llvm(cx, alloc), alloc)) |
3b2f2976 XL |
85 | } |
86 | ||
dfeec247 | 87 | fn set_global_alignment(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) { |
ea8adc8c XL |
88 | // The target may require greater alignment for globals than the type does. |
89 | // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, | |
90 | // which can force it to be smaller. Rust doesn't support this yet. | |
29967ef6 | 91 | if let Some(min) = cx.sess().target.min_global_align { |
a1dfa0c6 | 92 | match Align::from_bits(min) { |
ff7c6d11 | 93 | Ok(min) => align = align.max(min), |
ea8adc8c | 94 | Err(err) => { |
2c00a5a8 | 95 | cx.sess().err(&format!("invalid minimum global alignment: {}", err)); |
ea8adc8c XL |
96 | } |
97 | } | |
98 | } | |
99 | unsafe { | |
a1dfa0c6 | 100 | llvm::LLVMSetAlignment(gv, align.bytes() as u32); |
ea8adc8c XL |
101 | } |
102 | } | |
103 | ||
b7449926 XL |
104 | fn check_and_apply_linkage( |
105 | cx: &CodegenCx<'ll, 'tcx>, | |
8faf50e0 XL |
106 | attrs: &CodegenFnAttrs, |
107 | ty: Ty<'tcx>, | |
3dfed10e | 108 | sym: &str, |
29967ef6 | 109 | span_def_id: DefId, |
b7449926 | 110 | ) -> &'ll Value { |
8faf50e0 XL |
111 | let llty = cx.layout_of(ty).llvm_type(cx); |
112 | if let Some(linkage) = attrs.linkage { | |
113 | debug!("get_static: sym={} linkage={:?}", sym, linkage); | |
114 | ||
115 | // If this is a static with a linkage specified, then we need to handle | |
116 | // it a little specially. The typesystem prevents things like &T and | |
117 | // extern "C" fn() from being non-null, so we can't just declare a | |
118 | // static and call it a day. Some linkages (like weak) will make it such | |
119 | // that the static actually has a null value. | |
1b1a35ee | 120 | let llty2 = if let ty::RawPtr(ref mt) = ty.kind() { |
0bf4aa26 XL |
121 | cx.layout_of(mt.ty).llvm_type(cx) |
122 | } else { | |
dc9dc135 | 123 | cx.sess().span_fatal( |
29967ef6 | 124 | cx.tcx.def_span(span_def_id), |
dfeec247 XL |
125 | "must have type `*const T` or `*mut T` due to `#[linkage]` attribute", |
126 | ) | |
8faf50e0 XL |
127 | }; |
128 | unsafe { | |
129 | // Declare a symbol `foo` with the desired linkage. | |
a1dfa0c6 | 130 | let g1 = cx.declare_global(&sym, llty2); |
8faf50e0 XL |
131 | llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); |
132 | ||
133 | // Declare an internal global `extern_with_linkage_foo` which | |
134 | // is initialized with the address of `foo`. If `foo` is | |
135 | // discarded during linking (for example, if `foo` has weak | |
136 | // linkage and there are no definitions), then | |
137 | // `extern_with_linkage_foo` will instead be initialized to | |
138 | // zero. | |
139 | let mut real_name = "_rust_extern_with_linkage_".to_string(); | |
140 | real_name.push_str(&sym); | |
dfeec247 | 141 | let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { |
29967ef6 XL |
142 | cx.sess().span_fatal( |
143 | cx.tcx.def_span(span_def_id), | |
144 | &format!("symbol `{}` is already defined", &sym), | |
145 | ) | |
8faf50e0 XL |
146 | }); |
147 | llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); | |
148 | llvm::LLVMSetInitializer(g2, g1); | |
149 | g2 | |
150 | } | |
151 | } else { | |
152 | // Generate an external declaration. | |
153 | // FIXME(nagisa): investigate whether it can be changed into define_global | |
a1dfa0c6 | 154 | cx.declare_global(&sym, llty) |
8faf50e0 XL |
155 | } |
156 | } | |
157 | ||
a1dfa0c6 | 158 | pub fn ptrcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value { |
dfeec247 | 159 | unsafe { llvm::LLVMConstPointerCast(val, ty) } |
a1dfa0c6 | 160 | } |
c1a9b12d | 161 | |
a1dfa0c6 XL |
162 | impl CodegenCx<'ll, 'tcx> { |
163 | crate fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { | |
dfeec247 | 164 | unsafe { llvm::LLVMConstBitCast(val, ty) } |
a1dfa0c6 | 165 | } |
c1a9b12d | 166 | |
a1dfa0c6 XL |
167 | crate fn static_addr_of_mut( |
168 | &self, | |
169 | cv: &'ll Value, | |
170 | align: Align, | |
171 | kind: Option<&str>, | |
172 | ) -> &'ll Value { | |
173 | unsafe { | |
174 | let gv = match kind { | |
175 | Some(kind) if !self.tcx.sess.fewer_names() => { | |
176 | let name = self.generate_local_symbol_name(kind); | |
dfeec247 XL |
177 | let gv = self.define_global(&name[..], self.val_ty(cv)).unwrap_or_else(|| { |
178 | bug!("symbol `{}` is already defined", name); | |
a1dfa0c6 XL |
179 | }); |
180 | llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage); | |
181 | gv | |
dfeec247 | 182 | } |
a1dfa0c6 XL |
183 | _ => self.define_private_global(self.val_ty(cv)), |
184 | }; | |
185 | llvm::LLVMSetInitializer(gv, cv); | |
186 | set_global_alignment(&self, gv, align); | |
ba9703b0 | 187 | llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); |
a1dfa0c6 XL |
188 | gv |
189 | } | |
190 | } | |
8faf50e0 | 191 | |
a1dfa0c6 XL |
192 | crate fn get_static(&self, def_id: DefId) -> &'ll Value { |
193 | let instance = Instance::mono(self.tcx, def_id); | |
194 | if let Some(&g) = self.instances.borrow().get(&instance) { | |
195 | return g; | |
196 | } | |
197 | ||
dfeec247 XL |
198 | let defined_in_current_codegen_unit = |
199 | self.codegen_unit.items().contains_key(&MonoItem::Static(def_id)); | |
200 | assert!( | |
201 | !defined_in_current_codegen_unit, | |
202 | "consts::get_static() should always hit the cache for \ | |
a1dfa0c6 | 203 | statics defined in the same CGU, but did not for `{:?}`", |
dfeec247 XL |
204 | def_id |
205 | ); | |
a1dfa0c6 | 206 | |
3dfed10e | 207 | let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); |
e74abb32 | 208 | let sym = self.tcx.symbol_name(instance).name; |
5869c6ff | 209 | let fn_attrs = self.tcx.codegen_fn_attrs(def_id); |
a1dfa0c6 | 210 | |
5869c6ff | 211 | debug!("get_static: sym={} instance={:?} fn_attrs={:?}", sym, instance, fn_attrs); |
a1dfa0c6 | 212 | |
5869c6ff | 213 | let g = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) { |
a1dfa0c6 | 214 | let llty = self.layout_of(ty).llvm_type(self); |
5869c6ff XL |
215 | if let Some(g) = self.get_declared_value(sym) { |
216 | if self.val_ty(g) != self.type_ptr_to(llty) { | |
217 | span_bug!(self.tcx.def_span(def_id), "Conflicting types for static"); | |
a1dfa0c6 | 218 | } |
5869c6ff | 219 | } |
a1dfa0c6 | 220 | |
5869c6ff | 221 | let g = self.declare_global(sym, llty); |
a1dfa0c6 | 222 | |
5869c6ff XL |
223 | if !self.tcx.is_reachable_non_generic(def_id) { |
224 | unsafe { | |
225 | llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); | |
a1dfa0c6 XL |
226 | } |
227 | } | |
c1a9b12d | 228 | |
9e0c209e | 229 | g |
c1a9b12d | 230 | } else { |
5869c6ff XL |
231 | check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id) |
232 | }; | |
a1dfa0c6 | 233 | |
5869c6ff XL |
234 | // Thread-local statics in some other crate need to *always* be linked |
235 | // against in a thread-local fashion, so we need to be sure to apply the | |
236 | // thread-local attribute locally if it was present remotely. If we | |
237 | // don't do this then linker errors can be generated where the linker | |
238 | // complains that one object files has a thread local version of the | |
239 | // symbol and another one doesn't. | |
240 | if fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { | |
241 | llvm::set_thread_local_mode(g, self.tls_model); | |
242 | } | |
a1dfa0c6 | 243 | |
5869c6ff | 244 | if !def_id.is_local() { |
dfeec247 | 245 | let needs_dll_storage_attr = self.use_dll_storage_attrs && !self.tcx.is_foreign_item(def_id) && |
a1dfa0c6 XL |
246 | // ThinLTO can't handle this workaround in all cases, so we don't |
247 | // emit the attrs. Instead we make them unnecessary by disallowing | |
9fa01778 XL |
248 | // dynamic linking when linker plugin based LTO is enabled. |
249 | !self.tcx.sess.opts.cg.linker_plugin_lto.enabled(); | |
a1dfa0c6 XL |
250 | |
251 | // If this assertion triggers, there's something wrong with commandline | |
252 | // argument validation. | |
dfeec247 XL |
253 | debug_assert!( |
254 | !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() | |
29967ef6 | 255 | && self.tcx.sess.target.is_like_windows |
dfeec247 XL |
256 | && self.tcx.sess.opts.cg.prefer_dynamic) |
257 | ); | |
a1dfa0c6 XL |
258 | |
259 | if needs_dll_storage_attr { | |
0731742a | 260 | // This item is external but not foreign, i.e., it originates from an external Rust |
a1dfa0c6 XL |
261 | // crate. Since we don't know whether this crate will be linked dynamically or |
262 | // statically in the final application, we always mark such symbols as 'dllimport'. | |
263 | // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs | |
264 | // to make things work. | |
265 | // | |
266 | // However, in some scenarios we defer emission of statics to downstream | |
267 | // crates, so there are cases where a static with an upstream DefId | |
268 | // is actually present in the current crate. We can find out via the | |
269 | // is_codegened_item query. | |
270 | if !self.tcx.is_codegened_item(def_id) { | |
271 | unsafe { | |
272 | llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); | |
273 | } | |
274 | } | |
275 | } | |
5869c6ff | 276 | } |
a1dfa0c6 XL |
277 | |
278 | if self.use_dll_storage_attrs && self.tcx.is_dllimport_foreign_item(def_id) { | |
279 | // For foreign (native) libs we know the exact storage type to use. | |
280 | unsafe { | |
281 | llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); | |
1a4d82fc JJ |
282 | } |
283 | } | |
c1a9b12d | 284 | |
a1dfa0c6 XL |
285 | self.instances.borrow_mut().insert(instance, g); |
286 | g | |
287 | } | |
288 | } | |
289 | ||
290 | impl StaticMethods for CodegenCx<'ll, 'tcx> { | |
dfeec247 | 291 | fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value { |
a1dfa0c6 XL |
292 | if let Some(&gv) = self.const_globals.borrow().get(&cv) { |
293 | unsafe { | |
294 | // Upgrade the alignment in cases where the same constant is used with different | |
295 | // alignment requirements | |
296 | let llalign = align.bytes() as u32; | |
297 | if llalign > llvm::LLVMGetAlignment(gv) { | |
298 | llvm::LLVMSetAlignment(gv, llalign); | |
299 | } | |
94b46f34 | 300 | } |
a1dfa0c6 XL |
301 | return gv; |
302 | } | |
303 | let gv = self.static_addr_of_mut(cv, align, kind); | |
304 | unsafe { | |
305 | llvm::LLVMSetGlobalConstant(gv, True); | |
c1a9b12d | 306 | } |
a1dfa0c6 XL |
307 | self.const_globals.borrow_mut().insert(cv, gv); |
308 | gv | |
309 | } | |
5bcae85e | 310 | |
dfeec247 | 311 | fn codegen_static(&self, def_id: DefId, is_mutable: bool) { |
a1dfa0c6 XL |
312 | unsafe { |
313 | let attrs = self.tcx.codegen_fn_attrs(def_id); | |
314 | ||
315 | let (v, alloc) = match codegen_static_initializer(&self, def_id) { | |
316 | Ok(v) => v, | |
317 | // Error has already been reported | |
318 | Err(_) => return, | |
319 | }; | |
320 | ||
321 | let g = self.get_static(def_id); | |
322 | ||
323 | // boolean SSA values are i1, but they have to be stored in i8 slots, | |
324 | // otherwise some LLVM optimization passes don't work as expected | |
325 | let mut val_llty = self.val_ty(v); | |
326 | let v = if val_llty == self.type_i1() { | |
327 | val_llty = self.type_i8(); | |
328 | llvm::LLVMConstZExt(v, val_llty) | |
329 | } else { | |
330 | v | |
331 | }; | |
332 | ||
333 | let instance = Instance::mono(self.tcx, def_id); | |
3dfed10e | 334 | let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); |
a1dfa0c6 XL |
335 | let llty = self.layout_of(ty).llvm_type(self); |
336 | let g = if val_llty == llty { | |
337 | g | |
338 | } else { | |
339 | // If we created the global with the wrong type, | |
340 | // correct the type. | |
60c5eb7d XL |
341 | let name = llvm::get_value_name(g).to_vec(); |
342 | llvm::set_value_name(g, b""); | |
a1dfa0c6 XL |
343 | |
344 | let linkage = llvm::LLVMRustGetLinkage(g); | |
345 | let visibility = llvm::LLVMRustGetVisibility(g); | |
346 | ||
347 | let new_g = llvm::LLVMRustGetOrInsertGlobal( | |
dfeec247 XL |
348 | self.llmod, |
349 | name.as_ptr().cast(), | |
350 | name.len(), | |
351 | val_llty, | |
352 | ); | |
a1dfa0c6 XL |
353 | |
354 | llvm::LLVMRustSetLinkage(new_g, linkage); | |
355 | llvm::LLVMRustSetVisibility(new_g, visibility); | |
356 | ||
357 | // To avoid breaking any invariants, we leave around the old | |
358 | // global for the moment; we'll replace all references to it | |
359 | // with the new global later. (See base::codegen_backend.) | |
360 | self.statics_to_rauw.borrow_mut().push((g, new_g)); | |
361 | new_g | |
362 | }; | |
363 | set_global_alignment(&self, g, self.align_of(ty)); | |
364 | llvm::LLVMSetInitializer(g, v); | |
365 | ||
366 | // As an optimization, all shared statics which do not have interior | |
367 | // mutability are placed into read-only memory. | |
29967ef6 XL |
368 | if !is_mutable && self.type_is_freeze(ty) { |
369 | llvm::LLVMSetGlobalConstant(g, llvm::True); | |
a1dfa0c6 | 370 | } |
5bcae85e | 371 | |
a1dfa0c6 XL |
372 | debuginfo::create_global_var_metadata(&self, def_id, g); |
373 | ||
374 | if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { | |
375 | llvm::set_thread_local_mode(g, self.tls_model); | |
376 | ||
377 | // Do not allow LLVM to change the alignment of a TLS on macOS. | |
378 | // | |
379 | // By default a global's alignment can be freely increased. | |
380 | // This allows LLVM to generate more performant instructions | |
0731742a | 381 | // e.g., using load-aligned into a SIMD register. |
a1dfa0c6 XL |
382 | // |
383 | // However, on macOS 10.10 or below, the dynamic linker does not | |
384 | // respect any alignment given on the TLS (radar 24221680). | |
385 | // This will violate the alignment assumption, and causing segfault at runtime. | |
386 | // | |
387 | // This bug is very easy to trigger. In `println!` and `panic!`, | |
388 | // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS, | |
389 | // which the values would be `mem::replace`d on initialization. | |
390 | // The implementation of `mem::replace` will use SIMD | |
391 | // whenever the size is 32 bytes or higher. LLVM notices SIMD is used | |
392 | // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary, | |
393 | // which macOS's dyld disregarded and causing crashes | |
394 | // (see issues #51794, #51758, #50867, #48866 and #44056). | |
395 | // | |
396 | // To workaround the bug, we trick LLVM into not increasing | |
397 | // the global's alignment by explicitly assigning a section to it | |
398 | // (equivalent to automatically generating a `#[link_section]` attribute). | |
399 | // See the comment in the `GlobalValue::canIncreaseAlignment()` function | |
400 | // of `lib/IR/Globals.cpp` for why this works. | |
401 | // | |
402 | // When the alignment is not increased, the optimized `mem::replace` | |
403 | // will use load-unaligned instructions instead, and thus avoiding the crash. | |
404 | // | |
405 | // We could remove this hack whenever we decide to drop macOS 10.10 support. | |
29967ef6 | 406 | if self.tcx.sess.target.is_like_osx { |
ba9703b0 XL |
407 | // The `inspect` method is okay here because we checked relocations, and |
408 | // because we are doing this access to inspect the final interpreter state | |
409 | // (not as part of the interpreter execution). | |
410 | // | |
411 | // FIXME: This check requires that the (arbitrary) value of undefined bytes | |
412 | // happens to be zero. Instead, we should only check the value of defined bytes | |
413 | // and set all undefined bytes to zero if this allocation is headed for the | |
414 | // BSS. | |
415 | let all_bytes_are_zero = alloc.relocations().is_empty() | |
416 | && alloc | |
3dfed10e | 417 | .inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()) |
e1599b0c | 418 | .iter() |
ba9703b0 XL |
419 | .all(|&byte| byte == 0); |
420 | ||
421 | let sect_name = if all_bytes_are_zero { | |
6a06907d | 422 | cstr!("__DATA,__thread_bss") |
a1dfa0c6 | 423 | } else { |
6a06907d | 424 | cstr!("__DATA,__thread_data") |
a1dfa0c6 XL |
425 | }; |
426 | llvm::LLVMSetSection(g, sect_name.as_ptr()); | |
427 | } | |
428 | } | |
429 | ||
a1dfa0c6 XL |
430 | // Wasm statics with custom link sections get special treatment as they |
431 | // go into custom sections of the wasm executable. | |
432 | if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") { | |
433 | if let Some(section) = attrs.link_section { | |
434 | let section = llvm::LLVMMDStringInContext( | |
435 | self.llcx, | |
e74abb32 | 436 | section.as_str().as_ptr().cast(), |
a1dfa0c6 XL |
437 | section.as_str().len() as c_uint, |
438 | ); | |
e1599b0c XL |
439 | assert!(alloc.relocations().is_empty()); |
440 | ||
441 | // The `inspect` method is okay here because we checked relocations, and | |
442 | // because we are doing this access to inspect the final interpreter state (not | |
443 | // as part of the interpreter execution). | |
dfeec247 | 444 | let bytes = |
3dfed10e | 445 | alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); |
a1dfa0c6 XL |
446 | let alloc = llvm::LLVMMDStringInContext( |
447 | self.llcx, | |
e74abb32 | 448 | bytes.as_ptr().cast(), |
e1599b0c | 449 | bytes.len() as c_uint, |
a1dfa0c6 XL |
450 | ); |
451 | let data = [section, alloc]; | |
452 | let meta = llvm::LLVMMDNodeInContext(self.llcx, data.as_ptr(), 2); | |
453 | llvm::LLVMAddNamedMetadataOperand( | |
454 | self.llmod, | |
e74abb32 | 455 | "wasm.custom_sections\0".as_ptr().cast(), |
a1dfa0c6 XL |
456 | meta, |
457 | ); | |
458 | } | |
459 | } else { | |
460 | base::set_link_section(g, &attrs); | |
8faf50e0 | 461 | } |
8faf50e0 | 462 | |
a1dfa0c6 | 463 | if attrs.flags.contains(CodegenFnAttrFlags::USED) { |
3dfed10e | 464 | self.add_used_global(g); |
a1dfa0c6 | 465 | } |
cc61c64b | 466 | } |
1a4d82fc | 467 | } |
3dfed10e XL |
468 | |
469 | /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*. | |
470 | fn add_used_global(&self, global: &'ll Value) { | |
471 | let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) }; | |
472 | self.used_statics.borrow_mut().push(cast); | |
473 | } | |
1a4d82fc | 474 | } |