Skip to content

Commit 7c58ab6

Browse files
committed
rustc: Tweak visibility of some lang items
This commit tweaks the linker-level visibility of some lang items that rustc uses and defines. Notably this means that `#[panic_implementation]` and `#[alloc_error_handler]` functions are never marked as `internal`. It's up to the linker to eliminate these, not rustc. Additionally `#[global_allocator]` generated symbols are no longer forced to `Default` visibility (fully exported), but rather they're relaxed to `Hidden` visibility). This symbols are *not* needed across DLL boundaries, only as a local implementation detail of the compiler-injected allocator symbols, so `Hidden` should suffice. Closes #51342 Closes #52795
1 parent 38eeebd commit 7c58ab6

File tree

9 files changed

+238
-56
lines changed

9 files changed

+238
-56
lines changed

src/librustc/middle/reachable.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// makes all other generics or inline functions that it references
1616
// reachable as well.
1717

18-
use hir::CodegenFnAttrs;
18+
use hir::{CodegenFnAttrs, CodegenFnAttrFlags};
1919
use hir::map as hir_map;
2020
use hir::def::Def;
2121
use hir::def_id::{DefId, CrateNum};
@@ -28,7 +28,6 @@ use util::nodemap::{NodeSet, FxHashSet};
2828

2929
use rustc_target::spec::abi::Abi;
3030
use syntax::ast;
31-
use syntax::attr;
3231
use hir;
3332
use hir::def_id::LOCAL_CRATE;
3433
use hir::intravisit::{Visitor, NestedVisitorMap};
@@ -359,8 +358,12 @@ struct CollectPrivateImplItemsVisitor<'a, 'tcx: 'a> {
359358
impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
360359
fn visit_item(&mut self, item: &hir::Item) {
361360
// Anything which has custom linkage gets thrown on the worklist no
362-
// matter where it is in the crate.
363-
if attr::contains_name(&item.attrs, "linkage") {
361+
// matter where it is in the crate, along with "special std symbols"
362+
// which are currently akin to allocator symbols.
363+
let def_id = self.tcx.hir.local_def_id(item.id);
364+
let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
365+
if codegen_attrs.linkage.is_some() ||
366+
codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
364367
self.worklist.push(item.id);
365368
}
366369

src/librustc_allocator/expand.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_errors;
1313
use syntax::{
1414
ast::{
1515
self, Arg, Attribute, Crate, Expr, FnHeader, Generics, Ident, Item, ItemKind,
16-
LitKind, Mac, Mod, Mutability, StrStyle, Ty, TyKind, Unsafety, VisibilityKind,
16+
Mac, Mod, Mutability, Ty, TyKind, Unsafety, VisibilityKind,
1717
},
1818
attr,
1919
codemap::{
@@ -236,17 +236,12 @@ impl<'a> AllocFnFactory<'a> {
236236
}
237237

238238
fn attrs(&self) -> Vec<Attribute> {
239-
let key = Symbol::intern("linkage");
240-
let value = LitKind::Str(Symbol::intern("external"), StrStyle::Cooked);
241-
let linkage = self.cx.meta_name_value(self.span, key, value);
242-
243239
let no_mangle = Symbol::intern("no_mangle");
244240
let no_mangle = self.cx.meta_word(self.span, no_mangle);
245241

246242
let special = Symbol::intern("rustc_std_internal_symbol");
247243
let special = self.cx.meta_word(self.span, special);
248244
vec![
249-
self.cx.attribute(self.span, linkage),
250245
self.cx.attribute(self.span, no_mangle),
251246
self.cx.attribute(self.span, special),
252247
]

src/librustc_codegen_llvm/allocator.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,15 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind
6767
if tcx.sess.target.target.options.default_hidden_visibility {
6868
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
6969
}
70-
if tcx.sess.target.target.options.requires_uwtable {
71-
attributes::emit_uwtable(llfn, true);
72-
}
70+
if tcx.sess.target.target.options.requires_uwtable {
71+
attributes::emit_uwtable(llfn, true);
72+
}
7373

7474
let callee = CString::new(kind.fn_name(method.name)).unwrap();
7575
let callee = llvm::LLVMRustGetOrInsertFunction(llmod,
7676
callee.as_ptr(),
7777
ty);
78+
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
7879

7980
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx,
8081
llfn,

src/librustc_codegen_llvm/base.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -809,8 +809,28 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
809809
rx,
810810
codegen_units.len());
811811

812-
// Codegen an allocator shim, if any
813-
let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() {
812+
// Codegen an allocator shim, if necessary.
813+
//
814+
// If the crate doesn't have an `allocator_kind` set then there's definitely
815+
// no shim to generate. Otherwise we also check our dependency graph for all
816+
// our output crate types. If anything there looks like its a `Dynamic`
817+
// linkage, then it's already got an allocator shim and we'll be using that
818+
// one instead. If nothing exists then it's our job to generate the
819+
// allocator!
820+
let any_dynamic_crate = tcx.sess.dependency_formats.borrow()
821+
.iter()
822+
.any(|(_, list)| {
823+
use rustc::middle::dependency_format::Linkage;
824+
list.iter().any(|linkage| {
825+
match linkage {
826+
Linkage::Dynamic => true,
827+
_ => false,
828+
}
829+
})
830+
});
831+
let allocator_module = if any_dynamic_crate {
832+
None
833+
} else if let Some(kind) = *tcx.sess.allocator_kind.get() {
814834
unsafe {
815835
let llmod_id = "allocator";
816836
let modules = ModuleLlvm::new(tcx.sess, llmod_id);

src/librustc_mir/monomorphize/partitioning.rs

+95-41
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
105105
use monomorphize::collector::InliningMap;
106106
use rustc::dep_graph::WorkProductId;
107+
use rustc::hir::CodegenFnAttrFlags;
107108
use rustc::hir::def_id::DefId;
108109
use rustc::hir::map::DefPathData;
109110
use rustc::mir::mono::{Linkage, Visibility};
@@ -300,6 +301,13 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
300301
let is_incremental_build = tcx.sess.opts.incremental.is_some();
301302
let mut internalization_candidates = FxHashSet();
302303

304+
// Determine if monomorphizations instantiated in this crate will be made
305+
// available to downstream crates. This depends on whether we are in
306+
// share-generics mode and whether the current crate can even have
307+
// downstream crates.
308+
let export_generics = tcx.sess.opts.share_generics() &&
309+
tcx.local_crate_exports_generics();
310+
303311
for mono_item in mono_items {
304312
match mono_item.instantiation_mode(tcx) {
305313
InstantiationMode::GloballyShared { .. } => {}
@@ -323,29 +331,7 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
323331
tcx,
324332
&mono_item,
325333
&mut can_be_internalized,
326-
&|id, is_generic| {
327-
if !tcx.sess.target.target.options.default_hidden_visibility {
328-
return Visibility::Default
329-
}
330-
331-
// Generic functions never have export level C
332-
if is_generic {
333-
return Visibility::Hidden
334-
}
335-
336-
// Things with export level C don't get instantiated in
337-
// downstream crates
338-
if !id.is_local() {
339-
return Visibility::Hidden
340-
}
341-
342-
// C-export level items remain at `Default`, all other internal
343-
// items become `Hidden`
344-
match tcx.reachable_non_generics(id.krate).get(&id) {
345-
Some(SymbolExportLevel::C) => Visibility::Default,
346-
_ => Visibility::Hidden,
347-
}
348-
},
334+
export_generics,
349335
);
350336
if visibility == Visibility::Hidden && can_be_internalized {
351337
internalization_candidates.insert(mono_item);
@@ -376,20 +362,25 @@ fn mono_item_linkage_and_visibility(
376362
tcx: TyCtxt<'a, 'tcx, 'tcx>,
377363
mono_item: &MonoItem<'tcx>,
378364
can_be_internalized: &mut bool,
379-
default: &dyn Fn(DefId, bool) -> Visibility,
365+
export_generics: bool,
380366
) -> (Linkage, Visibility) {
381367
if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) {
382368
return (explicit_linkage, Visibility::Default)
383369
}
384-
let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, default);
370+
let vis = mono_item_visibility(
371+
tcx,
372+
mono_item,
373+
can_be_internalized,
374+
export_generics,
375+
);
385376
(Linkage::External, vis)
386377
}
387378

388379
fn mono_item_visibility(
389380
tcx: TyCtxt<'a, 'tcx, 'tcx>,
390381
mono_item: &MonoItem<'tcx>,
391382
can_be_internalized: &mut bool,
392-
default_visibility: &dyn Fn(DefId, bool) -> Visibility,
383+
export_generics: bool,
393384
) -> Visibility {
394385
let instance = match mono_item {
395386
// This is pretty complicated, go below
@@ -399,7 +390,7 @@ fn mono_item_visibility(
399390
MonoItem::Static(def_id) => {
400391
return if tcx.is_reachable_non_generic(*def_id) {
401392
*can_be_internalized = false;
402-
default_visibility(*def_id, false)
393+
default_visibility(tcx, *def_id, false)
403394
} else {
404395
Visibility::Hidden
405396
};
@@ -408,7 +399,7 @@ fn mono_item_visibility(
408399
let def_id = tcx.hir.local_def_id(*node_id);
409400
return if tcx.is_reachable_non_generic(def_id) {
410401
*can_be_internalized = false;
411-
default_visibility(def_id, false)
402+
default_visibility(tcx, def_id, false)
412403
} else {
413404
Visibility::Hidden
414405
};
@@ -440,18 +431,13 @@ fn mono_item_visibility(
440431
// hidden visibility, it should indeed be a candidate for
441432
// internalization, but we have to understand that it's referenced
442433
// from the `main` symbol we'll generate later.
434+
//
435+
// This may be fixable with a new `InstanceDef` perhaps? Unsure!
443436
if tcx.lang_items().start_fn() == Some(def_id) {
444437
*can_be_internalized = false;
445438
return Visibility::Hidden
446439
}
447440

448-
// Determine if monomorphizations instantiated in this crate will be made
449-
// available to downstream crates. This depends on whether we are in
450-
// share-generics mode and whether the current crate can even have
451-
// downstream crates.
452-
let export_generics = tcx.sess.opts.share_generics() &&
453-
tcx.local_crate_exports_generics();
454-
455441
let is_generic = instance.substs.types().next().is_some();
456442

457443
// Upstream `DefId` instances get different handling than local ones
@@ -461,7 +447,7 @@ fn mono_item_visibility(
461447
// and we export generics, we must make
462448
// it available to downstream crates.
463449
*can_be_internalized = false;
464-
default_visibility(def_id, true)
450+
default_visibility(tcx, def_id, true)
465451
} else {
466452
Visibility::Hidden
467453
}
@@ -477,7 +463,7 @@ fn mono_item_visibility(
477463
// This instance might be useful in
478464
// a downstream crate.
479465
*can_be_internalized = false;
480-
default_visibility(def_id, true)
466+
default_visibility(tcx, def_id, true)
481467
}
482468
} else {
483469
// We are not exporting generics or
@@ -487,14 +473,82 @@ fn mono_item_visibility(
487473
Visibility::Hidden
488474
}
489475
} else {
490-
// This isn't a generic function.
476+
477+
// If this isn't a generic function then we mark this a `Default` if
478+
// this is a reachable item, meaning that it's a symbol other crates may
479+
// access when they link to us.
491480
if tcx.is_reachable_non_generic(def_id) {
492481
*can_be_internalized = false;
493482
debug_assert!(!is_generic);
494-
default_visibility(def_id, false)
495-
} else {
496-
Visibility::Hidden
483+
return default_visibility(tcx, def_id, false)
484+
}
485+
486+
// If this isn't reachable then we're gonna tag this with `Hidden`
487+
// visibility. In some situations though we'll want to prevent this
488+
// symbol from being internalized.
489+
//
490+
// There's two categories of items here:
491+
//
492+
// * First is weak lang items. These are basically mechanisms for
493+
// libcore to forward-reference symbols defined later in crates like
494+
// the standard library or `#[panic_implementation]` definitions. The
495+
// definition of these weak lang items needs to be referenceable by
496+
// libcore, so we're no longer a candidate for internalization.
497+
// Removal of these functions can't be done by LLVM but rather must be
498+
// done by the linker as it's a non-local decision.
499+
//
500+
// * Second is "std internal symbols". Currently this is primarily used
501+
// for allocator symbols. Allocators are a little weird in their
502+
// implementation, but the idea is that the compiler, at the last
503+
// minute, defines an allocator with an injected object file. The
504+
// `alloc` crate references these symbols (`__rust_alloc`) and the
505+
// definition doesn't get hooked up until a linked crate artifact is
506+
// generated.
507+
//
508+
// The symbols synthesized by the compiler (`__rust_alloc`) are thin
509+
// veneers around the actual implementation, some other symbol which
510+
// implements the same ABI. These symbols (things like `__rg_alloc`,
511+
// `__rdl_alloc`, `__rde_alloc`, etc), are all tagged with "std
512+
// internal symbols".
513+
//
514+
// The std-internal symbols here **should not show up in a dll as an
515+
// exported interface**, so they return `false` from
516+
// `is_reachable_non_generic` above and we'll give them `Hidden`
517+
// visibility below. Like the weak lang items, though, we can't let
518+
// LLVM internalize them as this decision is left up to the linker to
519+
// omit them, so prevent them from being internalized.
520+
let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
521+
let std_internal_symbol = codegen_fn_attrs.flags
522+
.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
523+
if tcx.is_weak_lang_item(def_id) || std_internal_symbol {
524+
*can_be_internalized = false;
497525
}
526+
527+
Visibility::Hidden
528+
}
529+
}
530+
531+
fn default_visibility(tcx: TyCtxt, id: DefId, is_generic: bool) -> Visibility {
532+
if !tcx.sess.target.target.options.default_hidden_visibility {
533+
return Visibility::Default
534+
}
535+
536+
// Generic functions never have export level C
537+
if is_generic {
538+
return Visibility::Hidden
539+
}
540+
541+
// Things with export level C don't get instantiated in
542+
// downstream crates
543+
if !id.is_local() {
544+
return Visibility::Hidden
545+
}
546+
547+
// C-export level items remain at `Default`, all other internal
548+
// items become `Hidden`
549+
match tcx.reachable_non_generics(id.krate).get(&id) {
550+
Some(SymbolExportLevel::C) => Visibility::Default,
551+
_ => Visibility::Hidden,
498552
}
499553
}
500554

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-include ../../run-make-fulldeps/tools.mk
2+
3+
ifeq ($(TARGET),wasm32-unknown-unknown)
4+
all:
5+
$(RUSTC) foo.rs --target wasm32-unknown-unknown
6+
$(NODE) verify-exported-symbols.js $(TMPDIR)/foo.wasm
7+
$(RUSTC) foo.rs --target wasm32-unknown-unknown -O
8+
$(NODE) verify-exported-symbols.js $(TMPDIR)/foo.wasm
9+
$(RUSTC) bar.rs --target wasm32-unknown-unknown
10+
$(NODE) verify-exported-symbols.js $(TMPDIR)/bar.wasm
11+
$(RUSTC) bar.rs --target wasm32-unknown-unknown -O
12+
$(NODE) verify-exported-symbols.js $(TMPDIR)/bar.wasm
13+
else
14+
all:
15+
endif
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2018 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.
4+
//
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.
10+
11+
#![feature(panic_implementation, alloc_error_handler)]
12+
#![crate_type = "cdylib"]
13+
#![no_std]
14+
15+
use core::alloc::*;
16+
17+
struct B;
18+
19+
unsafe impl GlobalAlloc for B {
20+
unsafe fn alloc(&self, x: Layout) -> *mut u8 {
21+
1 as *mut u8
22+
}
23+
24+
unsafe fn dealloc(&self, ptr: *mut u8, x: Layout) {
25+
}
26+
}
27+
28+
#[global_allocator]
29+
static A: B = B;
30+
31+
#[no_mangle]
32+
pub extern fn foo(a: u32) -> u32 {
33+
assert_eq!(a, 3);
34+
a * 2
35+
}
36+
37+
#[alloc_error_handler]
38+
fn a(_: core::alloc::Layout) -> ! {
39+
loop {}
40+
}
41+
42+
#[panic_implementation]
43+
fn b(_: &core::panic::PanicInfo) -> ! {
44+
loop {}
45+
}

0 commit comments

Comments
 (0)