Skip to content

Commit 4c7e277

Browse files
author
Jorge Aparicio
committed
add an #[used] attribute
similar to GCC's __attribute((used))__. This attribute prevents LLVM from optimizing away a non-exported symbol, within a compilation unit (object file), when there are no references to it. This is better explained with an example: ``` #[used] static LIVE: i32 = 0; static REFERENCED: i32 = 0; static DEAD: i32 = 0; fn internal() {} pub fn exported() -> &'static i32 { &REFERENCED } ``` Without optimizations, LLVM pretty much preserves all the static variables and functions within the compilation unit. ``` $ rustc --crate-type=lib --emit=obj symbols.rs && nm -C symbols.o 0000000000000000 t drop::h1be0f8f27a2ba94a 0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c 0000000000000000 r symbols::DEAD::hc2ea8f9bd06f380b 0000000000000000 r symbols::LIVE::h0970cf9889edb56e 0000000000000000 T symbols::exported::h6f096c2b1fc292b2 0000000000000000 t symbols::internal::h0ac1aadbc1e3a494 ``` With optimizations, LLVM will drop dead code. Here `internal` is dropped because it's not a exported function/symbol (i.e. not `pub`lic). `DEAD` is dropped for the same reason. `REFERENCED` is preserved, even though it's not exported, because it's referenced by the `exported` function. Finally, `LIVE` survives because of the `#[used]` attribute even though it's not exported or referenced. ``` $ rustc --crate-type=lib -C opt-level=3 --emit=obj symbols.rs && nm -C symbols.o 0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c 0000000000000000 r symbols::LIVE::h0970cf9889edb56e 0000000000000000 T symbols::exported::h6f096c2b1fc292b2 ``` Note that the linker knows nothing about `#[used]` and will drop `LIVE` because no other object references to it. ``` $ echo 'fn main() {}' >> symbols.rs $ rustc symbols.rs && nm -C symbols | grep LIVE ``` At this time, `#[used]` only works on `static` variables.
1 parent 2564711 commit 4c7e277

File tree

4 files changed

+38
-1
lines changed

4 files changed

+38
-1
lines changed

src/librustc_trans/base.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use builder::Builder;
5050
use callee;
5151
use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
5252
use collector::{self, TransItemCollectionMode};
53-
use common::{C_struct_in_context, C_u64, C_undef};
53+
use common::{C_struct_in_context, C_u64, C_undef, C_array};
5454
use common::CrateContext;
5555
use common::{type_is_zero_size, val_ty};
5656
use common;
@@ -1187,6 +1187,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
11871187
}
11881188
}
11891189

1190+
// Create llvm.used variable
1191+
if !ccx.used_statics().borrow().is_empty() {
1192+
debug!("llvm.used");
1193+
1194+
let name = CString::new("llvm.used").unwrap();
1195+
let section = CString::new("llvm.metadata").unwrap();
1196+
let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
1197+
1198+
unsafe {
1199+
let g = llvm::LLVMAddGlobal(ccx.llmod(),
1200+
val_ty(array).to_ref(),
1201+
name.as_ptr());
1202+
llvm::LLVMSetInitializer(g, array);
1203+
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
1204+
llvm::LLVMSetSection(g, section.as_ptr());
1205+
}
1206+
}
1207+
11901208
// Finalize debuginfo
11911209
if ccx.sess().opts.debuginfo != NoDebugInfo {
11921210
debuginfo::finalize(&ccx);

src/librustc_trans/consts.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
276276

277277
base::set_link_section(ccx, g, attrs);
278278

279+
if attr::contains_name(attrs, "used") {
280+
ccx.used_statics().borrow_mut().push(g);
281+
}
282+
279283
Ok(g)
280284
}
281285
}

src/librustc_trans/context.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ pub struct LocalCrateContext<'tcx> {
132132
/// to constants.)
133133
statics_to_rauw: RefCell<Vec<(ValueRef, ValueRef)>>,
134134

135+
used_statics: RefCell<Vec<ValueRef>>,
136+
135137
lltypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
136138
llsizingtypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
137139
type_hashcodes: RefCell<FxHashMap<Ty<'tcx>, String>>,
@@ -587,6 +589,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
587589
impl_method_cache: RefCell::new(FxHashMap()),
588590
closure_bare_wrapper_cache: RefCell::new(FxHashMap()),
589591
statics_to_rauw: RefCell::new(Vec::new()),
592+
used_statics: RefCell::new(Vec::new()),
590593
lltypes: RefCell::new(FxHashMap()),
591594
llsizingtypes: RefCell::new(FxHashMap()),
592595
type_hashcodes: RefCell::new(FxHashMap()),
@@ -754,6 +757,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
754757
&self.local().statics_to_rauw
755758
}
756759

760+
pub fn used_statics<'a>(&'a self) -> &'a RefCell<Vec<ValueRef>> {
761+
&self.local().used_statics
762+
}
763+
757764
pub fn lltypes<'a>(&'a self) -> &'a RefCell<FxHashMap<Ty<'tcx>, Type>> {
758765
&self.local().lltypes
759766
}

src/libsyntax/feature_gate.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,15 @@ declare_features! (
337337
// `extern "x86-interrupt" fn()`
338338
(active, abi_x86_interrupt, "1.17.0", Some(40180)),
339339

340+
340341
// Allows the `catch {...}` expression
341342
(active, catch_expr, "1.17.0", Some(31436)),
342343

343344
// See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
344345
(active, rvalue_static_promotion, "1.15.1", Some(38865)),
346+
347+
// Used to preserve symbols
348+
(active, used, "1.18.0", None),
345349
);
346350

347351
declare_features! (
@@ -748,6 +752,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
748752
"unwind_attributes",
749753
"#[unwind] is experimental",
750754
cfg_fn!(unwind_attributes))),
755+
("used", Whitelisted, Gated(
756+
Stability::Unstable, "used",
757+
"the `#[used]` attribute is an experimental feature",
758+
cfg_fn!(used))),
751759

752760
// used in resolve
753761
("prelude_import", Whitelisted, Gated(Stability::Unstable,

0 commit comments

Comments
 (0)