Skip to content

Commit a20262c

Browse files
committed
Properly set the linkage type on non-local statics
Fixes issue rust-lang#18804 Signed-off-by: Gabriel Smith <[email protected]>
1 parent e8bc064 commit a20262c

File tree

1 file changed

+53
-6
lines changed

1 file changed

+53
-6
lines changed

src/librustc_codegen_llvm/consts.rs

+53-6
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
119119
let ty = instance.ty(cx.tcx);
120120
let sym = cx.tcx.symbol_name(instance).as_str();
121121

122+
debug!("get_static: sym={} instance={:?}", sym, instance);
123+
122124
let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) {
123125

124126
let llty = cx.layout_of(ty).llvm_type(cx);
@@ -145,6 +147,8 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
145147
ref attrs, span, node: hir::ForeignItemKind::Static(..), ..
146148
}) => {
147149
let g = if let Some(linkage) = cx.tcx.codegen_fn_attrs(def_id).linkage {
150+
debug!("get_static: sym={} linkage={:?}", sym, linkage);
151+
148152
// If this is a static with a linkage specified, then we need to handle
149153
// it a little specially. The typesystem prevents things like &T and
150154
// extern "C" fn() from being non-null, so we can't just declare a
@@ -188,6 +192,8 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
188192
item => bug!("get_static: expected static, found {:?}", item)
189193
};
190194

195+
debug!("get_static: sym={} attrs={:?}", sym, attrs);
196+
191197
for attr in attrs {
192198
if attr.check_name("thread_local") {
193199
llvm::set_thread_local_mode(g, cx.tls_model);
@@ -197,19 +203,60 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
197203
g
198204
} else {
199205
// FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
200-
// FIXME(nagisa): investigate whether it can be changed into define_global
201-
let g = declare::declare_global(cx, &sym, cx.layout_of(ty).llvm_type(cx));
206+
debug!("get_static: sym={} item_attr={:?}", sym, cx.tcx.item_attrs(def_id));
207+
208+
let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(def_id);
209+
let llty = cx.layout_of(ty).llvm_type(cx);
210+
let g = if let Some(linkage) = codegen_fn_attrs.linkage {
211+
debug!("get_static: sym={} linkage={:?}", sym, linkage);
212+
213+
// If this is a static with a linkage specified, then we need to handle
214+
// it a little specially. The typesystem prevents things like &T and
215+
// extern "C" fn() from being non-null, so we can't just declare a
216+
// static and call it a day. Some linkages (like weak) will make it such
217+
// that the static actually has a null value.
218+
let llty2 = match ty.sty {
219+
ty::TyRawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx),
220+
_ => {
221+
bug!("must have type `*const T` or `*mut T`")
222+
}
223+
};
224+
unsafe {
225+
// Declare a symbol `foo` with the desired linkage.
226+
let g1 = declare::declare_global(cx, &sym, llty2);
227+
llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
228+
229+
// Declare an internal global `extern_with_linkage_foo` which
230+
// is initialized with the address of `foo`. If `foo` is
231+
// discarded during linking (for example, if `foo` has weak
232+
// linkage and there are no definitions), then
233+
// `extern_with_linkage_foo` will instead be initialized to
234+
// zero.
235+
let mut real_name = "_rust_extern_with_linkage_".to_string();
236+
real_name.push_str(&sym);
237+
let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{
238+
bug!("symbol `{}` is already defined", &sym)
239+
});
240+
llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
241+
llvm::LLVMSetInitializer(g2, g1);
242+
g2
243+
}
244+
} else {
245+
// Generate an external declaration.
246+
// FIXME(nagisa): investigate whether it can be changed into define_global
247+
declare::declare_global(cx, &sym, llty)
248+
};
249+
202250
// Thread-local statics in some other crate need to *always* be linked
203251
// against in a thread-local fashion, so we need to be sure to apply the
204252
// thread-local attribute locally if it was present remotely. If we
205253
// don't do this then linker errors can be generated where the linker
206254
// complains that one object files has a thread local version of the
207255
// symbol and another one doesn't.
208-
for attr in cx.tcx.get_attrs(def_id).iter() {
209-
if attr.check_name("thread_local") {
210-
llvm::set_thread_local_mode(g, cx.tls_model);
211-
}
256+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
257+
llvm::set_thread_local_mode(g, cx.tls_model);
212258
}
259+
213260
if cx.use_dll_storage_attrs && !cx.tcx.is_foreign_item(def_id) {
214261
// This item is external but not foreign, i.e. it originates from an external Rust
215262
// crate. Since we don't know whether this crate will be linked dynamically or

0 commit comments

Comments
 (0)