]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/link_guard.rs
94606cafce5de25b2c319c6f757b7ebbf1de7d0c
[rust.git] / src / librustc_trans / trans / link_guard.rs
1 // Copyright 2012-2016 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 use back::svh::Svh;
12 use libc::c_uint;
13 use llvm;
14 use std::ffi::CString;
15 use std::ptr;
16 use trans::attributes;
17 use trans::builder;
18 use trans::CrateContext;
19 use trans::declare;
20 use trans::type_::Type;
21
22 const GUARD_PREFIX: &'static str = "__rustc_link_guard_";
23
24 pub fn link_guard_name(crate_name: &str, crate_svh: &Svh) -> String {
25
26     let mut guard_name = String::new();
27
28     guard_name.push_str(GUARD_PREFIX);
29     guard_name.push_str(crate_name);
30     guard_name.push_str("_");
31     guard_name.push_str(crate_svh.as_str());
32
33     guard_name
34 }
35
36 pub fn get_or_insert_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>)
37                                           -> llvm::ValueRef {
38
39     let guard_name = link_guard_name(&ccx.tcx().crate_name[..],
40                                      &ccx.link_meta().crate_hash);
41
42     let guard_function = unsafe {
43         let guard_name_c_string = CString::new(&guard_name[..]).unwrap();
44         llvm::LLVMGetNamedValue(ccx.llmod(), guard_name_c_string.as_ptr())
45     };
46
47     if guard_function != ptr::null_mut() {
48         return guard_function;
49     }
50
51     let llfty = Type::func(&[], &Type::void(ccx));
52     let guard_function = declare::define_cfn(ccx,
53                                              &guard_name[..],
54                                              llfty,
55                                              ccx.tcx().mk_nil()).unwrap_or_else(|| {
56         ccx.sess().bug("Link guard already defined.");
57     });
58
59     attributes::emit_uwtable(guard_function, true);
60     attributes::unwind(guard_function, false);
61
62     let bld = ccx.raw_builder();
63     unsafe {
64         let llbb = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(),
65                                                        guard_function,
66                                                        "link_guard_top\0".as_ptr() as *const _);
67         llvm::LLVMPositionBuilderAtEnd(bld, llbb);
68
69         for crate_num in ccx.sess().cstore.crates() {
70             if !ccx.sess().cstore.is_explicitly_linked(crate_num) {
71                 continue;
72             }
73
74             let crate_name = ccx.sess().cstore.original_crate_name(crate_num);
75             let svh = ccx.sess().cstore.crate_hash(crate_num);
76
77             let dependency_guard_name = link_guard_name(&crate_name[..], &svh);
78
79             let decl = declare::declare_cfn(ccx,
80                                             &dependency_guard_name[..],
81                                             llfty,
82                                             ccx.tcx().mk_nil());
83             attributes::unwind(decl, false);
84
85             llvm::LLVMPositionBuilderAtEnd(bld, llbb);
86
87             let args: &[llvm::ValueRef] = &[];
88             llvm::LLVMRustBuildCall(bld,
89                                     decl,
90                                     args.as_ptr(),
91                                     args.len() as c_uint,
92                                     0 as *mut _,
93                                     builder::noname());
94         }
95
96         llvm::LLVMBuildRetVoid(bld);
97     }
98
99     guard_function
100 }
101
102 pub fn insert_reference_to_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
103                                                 llbb: llvm::BasicBlockRef) {
104     let guard_function = get_or_insert_link_guard(ccx);
105
106     unsafe {
107         llvm::LLVMPositionBuilderAtEnd(ccx.raw_builder(), llbb);
108         let args: &[llvm::ValueRef] = &[];
109         llvm::LLVMRustBuildCall(ccx.raw_builder(),
110                                 guard_function,
111                                 args.as_ptr(),
112                                 args.len() as c_uint,
113                                 0 as *mut _,
114                                 builder::noname());
115     }
116 }