Skip to content

Commit ceded6a

Browse files
committed
Auto merge of #27210 - vadimcn:win64-eh-pers, r=alexcrichton
After this change, the only remaining symbol we are pulling from libgcc on Win64 is `__chkstk_ms` - the stack probing routine.
2 parents d877e65 + 96d1db2 commit ceded6a

File tree

25 files changed

+667
-237
lines changed

25 files changed

+667
-237
lines changed

src/doc/trpl/lang-items.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ fn main(argc: isize, argv: *const *const u8) -> isize {
5454
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
5555
#[lang = "eh_personality"] extern fn eh_personality() {}
5656
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
57+
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
5758
```
5859

5960
Note the use of `abort`: the `exchange_malloc` lang item is assumed to

src/doc/trpl/no-stdlib.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
3939
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
4040
#[lang = "eh_personality"] extern fn eh_personality() {}
4141
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
42+
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
4243
# // fn main() {} tricked you, rustdoc!
4344
```
4445

@@ -63,6 +64,7 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
6364
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
6465
#[lang = "eh_personality"] extern fn eh_personality() {}
6566
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
67+
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
6668
# // fn main() {} tricked you, rustdoc!
6769
```
6870

@@ -150,6 +152,7 @@ extern fn panic_fmt(args: &core::fmt::Arguments,
150152
151153
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
152154
#[lang = "eh_personality"] extern fn eh_personality() {}
155+
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
153156
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
154157
# fn main() {}
155158
```

src/librustc/middle/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ lets_do_this! {
327327

328328
EhPersonalityLangItem, "eh_personality", eh_personality;
329329
EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch;
330+
EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume;
330331
MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter;
331332

332333
ExchangeHeapLangItem, "exchange_heap", exchange_heap;

src/librustc/middle/weak_lang_items.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ pub fn check_crate(krate: &ast::Crate,
4545
if items.eh_personality().is_none() {
4646
items.missing.push(lang_items::EhPersonalityLangItem);
4747
}
48+
if sess.target.target.options.custom_unwind_resume &
49+
items.eh_unwind_resume().is_none() {
50+
items.missing.push(lang_items::EhUnwindResumeLangItem);
51+
}
4852

4953
{
5054
let mut cx = Context { sess: sess, items: items };
@@ -122,4 +126,5 @@ weak_lang_items! {
122126
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
123127
stack_exhausted, StackExhaustedLangItem, rust_stack_exhausted;
124128
eh_personality, EhPersonalityLangItem, rust_eh_personality;
129+
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
125130
}

src/librustc_back/target/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ pub struct TargetOptions {
171171
/// currently only "gnu" is used to fall into LLVM. Unknown strings cause
172172
/// the system linker to be used.
173173
pub archive_format: String,
174+
/// Whether the target uses a custom unwind resumption routine.
175+
/// By default LLVM lowers `resume` instructions into calls to `_Unwind_Resume`
176+
/// defined in libgcc. If this option is enabled, the target must provide
177+
/// `eh_unwind_resume` lang item.
178+
pub custom_unwind_resume: bool,
174179
}
175180

176181
impl Default for TargetOptions {
@@ -209,6 +214,7 @@ impl Default for TargetOptions {
209214
pre_link_objects: Vec::new(),
210215
post_link_objects: Vec::new(),
211216
archive_format: String::new(),
217+
custom_unwind_resume: false,
212218
}
213219
}
214220
}

src/librustc_back/target/x86_64_pc_windows_gnu.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub fn target() -> Target {
1616
// On Win64 unwinding is handled by the OS, so we can link libgcc statically.
1717
base.pre_link_args.push("-static-libgcc".to_string());
1818
base.pre_link_args.push("-m64".to_string());
19+
base.custom_unwind_resume = true;
1920

2021
Target {
2122
llvm_target: "x86_64-pc-windows-gnu".to_string(),

src/librustc_trans/trans/base.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,6 +2171,12 @@ fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId,
21712171
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
21722172
}
21732173
}
2174+
if ccx.tcx().lang_items.eh_unwind_resume() == Some(def) {
2175+
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
2176+
if ccx.use_dll_storage_attrs() {
2177+
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
2178+
}
2179+
}
21742180
}
21752181

21762182
fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,

src/librustc_trans/trans/cleanup.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,8 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
846846

847847
debug!("get_or_create_landing_pad");
848848

849+
self.inject_unwind_resume_hook();
850+
849851
// Check if a landing pad block exists; if not, create one.
850852
{
851853
let mut scopes = self.scopes.borrow_mut();

src/librustc_trans/trans/common.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,55 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
561561
}
562562
}
563563
}
564+
565+
/// By default, LLVM lowers `resume` instructions into calls to `_Unwind_Resume`
566+
/// defined in libgcc, however, unlike personality routines, there is no easy way to
567+
/// override that symbol. This method injects a local-scoped `_Unwind_Resume` function
568+
/// which immediately defers to the user-defined `eh_unwind_resume` lang item.
569+
pub fn inject_unwind_resume_hook(&self) {
570+
let ccx = self.ccx;
571+
if !ccx.sess().target.target.options.custom_unwind_resume ||
572+
ccx.unwind_resume_hooked().get() {
573+
return;
574+
}
575+
576+
let new_resume = match ccx.tcx().lang_items.eh_unwind_resume() {
577+
Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0), &self.param_substs).val,
578+
None => {
579+
let fty = Type::variadic_func(&[], &Type::void(self.ccx));
580+
declare::declare_cfn(self.ccx, "rust_eh_unwind_resume", fty,
581+
self.ccx.tcx().mk_nil())
582+
}
583+
};
584+
585+
unsafe {
586+
let resume_type = Type::func(&[Type::i8(ccx).ptr_to()], &Type::void(ccx));
587+
let old_resume = llvm::LLVMAddFunction(ccx.llmod(),
588+
"_Unwind_Resume\0".as_ptr() as *const _,
589+
resume_type.to_ref());
590+
llvm::SetLinkage(old_resume, llvm::InternalLinkage);
591+
let llbb = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(),
592+
old_resume,
593+
"\0".as_ptr() as *const _);
594+
let builder = ccx.builder();
595+
builder.position_at_end(llbb);
596+
builder.call(new_resume, &[llvm::LLVMGetFirstParam(old_resume)], None);
597+
builder.unreachable(); // it should never return
598+
599+
// Until DwarfEHPrepare pass has run, _Unwind_Resume is not referenced by any live code
600+
// and is subject to dead code elimination. Here we add _Unwind_Resume to @llvm.globals
601+
// to prevent that.
602+
let i8p_ty = Type::i8p(ccx);
603+
let used_ty = Type::array(&i8p_ty, 1);
604+
let used = llvm::LLVMAddGlobal(ccx.llmod(), used_ty.to_ref(),
605+
"llvm.used\0".as_ptr() as *const _);
606+
let old_resume = llvm::LLVMConstBitCast(old_resume, i8p_ty.to_ref());
607+
llvm::LLVMSetInitializer(used, C_array(i8p_ty, &[old_resume]));
608+
llvm::SetLinkage(used, llvm::AppendingLinkage);
609+
llvm::LLVMSetSection(used, "llvm.metadata\0".as_ptr() as *const _)
610+
}
611+
ccx.unwind_resume_hooked().set(true);
612+
}
564613
}
565614

566615
// Basic block context. We create a block context for each basic block

src/librustc_trans/trans/context.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ pub struct LocalCrateContext<'tcx> {
146146

147147
eh_personality: RefCell<Option<ValueRef>>,
148148
rust_try_fn: RefCell<Option<ValueRef>>,
149+
unwind_resume_hooked: Cell<bool>,
149150

150151
intrinsics: RefCell<FnvHashMap<&'static str, ValueRef>>,
151152

@@ -466,6 +467,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
466467
dbg_cx: dbg_cx,
467468
eh_personality: RefCell::new(None),
468469
rust_try_fn: RefCell::new(None),
470+
unwind_resume_hooked: Cell::new(false),
469471
intrinsics: RefCell::new(FnvHashMap()),
470472
n_llvm_insns: Cell::new(0),
471473
trait_cache: RefCell::new(FnvHashMap()),
@@ -735,6 +737,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
735737
&self.local.rust_try_fn
736738
}
737739

740+
pub fn unwind_resume_hooked<'a>(&'a self) -> &'a Cell<bool> {
741+
&self.local.unwind_resume_hooked
742+
}
743+
738744
fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> {
739745
&self.local.intrinsics
740746
}

0 commit comments

Comments
 (0)