]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/link_guard.rs
453afa827e8f12218d2892076ab5b052c0140404
[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     if declare::get_defined_value(ccx, &guard_name[..]).is_some() {
53         ccx.sess().bug(
54             &format!("Link guard already defined"));
55     }
56     let guard_function = declare::declare_cfn(ccx, &guard_name[..], llfty);
57
58     attributes::emit_uwtable(guard_function, true);
59     attributes::unwind(guard_function, false);
60
61     let bld = ccx.raw_builder();
62     unsafe {
63         let llbb = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(),
64                                                        guard_function,
65                                                        "link_guard_top\0".as_ptr() as *const _);
66         llvm::LLVMPositionBuilderAtEnd(bld, llbb);
67
68         for crate_num in ccx.sess().cstore.crates() {
69             if !ccx.sess().cstore.is_explicitly_linked(crate_num) {
70                 continue;
71             }
72
73             let crate_name = ccx.sess().cstore.original_crate_name(crate_num);
74             let svh = ccx.sess().cstore.crate_hash(crate_num);
75
76             let dependency_guard_name = link_guard_name(&crate_name[..], &svh);
77
78             if declare::get_defined_value(ccx, &dependency_guard_name[..]).is_some() {
79                 ccx.sess().bug(
80                     &format!("Link guard already defined for dependency `{}`",
81                              crate_name));
82             }
83             let decl = declare::declare_cfn(ccx, &dependency_guard_name[..], llfty);
84             attributes::unwind(decl, false);
85
86             llvm::LLVMPositionBuilderAtEnd(bld, llbb);
87
88             let args: &[llvm::ValueRef] = &[];
89             llvm::LLVMRustBuildCall(bld,
90                                     decl,
91                                     args.as_ptr(),
92                                     args.len() as c_uint,
93                                     0 as *mut _,
94                                     builder::noname());
95         }
96
97         llvm::LLVMBuildRetVoid(bld);
98     }
99
100     guard_function
101 }
102
103 pub fn insert_reference_to_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
104                                                 llbb: llvm::BasicBlockRef) {
105     let guard_function = get_or_insert_link_guard(ccx);
106
107     unsafe {
108         llvm::LLVMPositionBuilderAtEnd(ccx.raw_builder(), llbb);
109         let args: &[llvm::ValueRef] = &[];
110         llvm::LLVMRustBuildCall(ccx.raw_builder(),
111                                 guard_function,
112                                 args.as_ptr(),
113                                 args.len() as c_uint,
114                                 0 as *mut _,
115                                 builder::noname());
116     }
117 }