Skip to content

Initial MSVC support for the compiler #25350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
May 20, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
315750a
Very hacky MSVC hacks.
ricky26 Mar 4, 2015
4cc025d
Scale back changes made
alexcrichton May 8, 2015
2d5e577
rustc_trans: Abstract linker support behind a trait
alexcrichton May 8, 2015
40570eb
rustc_llvm: Expose setting more DLL storage classes
alexcrichton May 11, 2015
cb513c7
rt: Clean up to build with cl.exe
alexcrichton May 11, 2015
eb5bf15
mk: Remove generation of .d files
alexcrichton May 11, 2015
150663c
mk: Correct names of installed libs on windows
alexcrichton May 11, 2015
ee258c5
mk: Fix native LLVM deps for cross-host builds
alexcrichton May 11, 2015
7cf0b17
configure: Start adding MSVC support
alexcrichton May 11, 2015
b56d47c
mk: Enable building LLVM targeting MSVC
alexcrichton May 11, 2015
fcf7ecd
mk: Add build system support for cl.exe
alexcrichton May 11, 2015
ee64bab
mk: Don't add cross prefixes for MSVC
alexcrichton May 11, 2015
64412a4
mk: Fix building compiler-rt on MSVC
alexcrichton May 11, 2015
6122a5f
mk: Fix MSVC build for rustllvm.lib
alexcrichton May 11, 2015
a4ef308
mk: Add the ability to depend on native LLVM tools
alexcrichton May 11, 2015
f9846e9
rustc: Shorten MSVC metadata section name
alexcrichton May 11, 2015
839dcfd
rustc_back: Refactor Archive to better express intent
alexcrichton May 11, 2015
37659a1
rustc_back: Remove unneeded explicit variable
alexcrichton May 11, 2015
af56e2e
rustc_back: Tweak the MSVC target spec
alexcrichton May 11, 2015
d97b4af
mklldeps: Don't link stdc++/c++ on MSVC
alexcrichton May 11, 2015
e2854b3
libc: Add necessary libraries for MSVC
alexcrichton May 11, 2015
eb50ffd
rustc_trans: Clean up some style in back::link
alexcrichton May 11, 2015
181dbd7
rustc_trans: Add MSVC linker support
alexcrichton May 11, 2015
ce8b317
rustc_trans: Tidy up some style and line lengths
alexcrichton May 11, 2015
b538189
mk: Generate a .def file for rustc_llvm on MSVC
alexcrichton May 11, 2015
847c852
rustc_llvm: Don't export constants across dlls
alexcrichton May 12, 2015
f5222fb
std: Implement aborting stubs for MSVC unwinding
alexcrichton May 12, 2015
9a2415b
std: Mark rust_get_num_cpus as dllexport
alexcrichton May 12, 2015
3d32cf5
rustc_trans: Apply dllexport attributes for MSVC
alexcrichton May 12, 2015
74f4f39
std: Don't require rust_try as an exported symbol
alexcrichton May 12, 2015
cb3071b
mk: Update `make dist` for MSVC targets
alexcrichton May 13, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
std: Implement aborting stubs for MSVC unwinding
At this time unwinding support is not implemented for MSVC as
`libgcc_s_seh-1.dll` is not available by default (and this is used on MinGW),
but this should be investigated soon. For now this change is just aimed at
getting the compiler far enough to bootstrap everything instead of successfully
running tests.

This commit refactors the `std::rt::unwind` module a bit to prepare for SEH
support eventually by moving all GCC-specific functionality to its own submodule
and defining the interface needed.
  • Loading branch information
alexcrichton committed May 19, 2015
commit f5222fb892be00f2b3e4dd8b83c5277e94ebbbba
342 changes: 342 additions & 0 deletions src/libstd/rt/unwind/gcc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use prelude::v1::*;

use any::Any;
use boxed;
use libc::c_void;
use rt::libunwind as uw;

struct Exception {
uwe: uw::_Unwind_Exception,
cause: Option<Box<Any + Send + 'static>>,
}

pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
let exception: Box<_> = box Exception {
uwe: uw::_Unwind_Exception {
exception_class: rust_exception_class(),
exception_cleanup: exception_cleanup,
private: [0; uw::unwinder_private_data_size],
},
cause: Some(data),
};
let exception_param = boxed::into_raw(exception) as *mut uw::_Unwind_Exception;
let error = uw::_Unwind_RaiseException(exception_param);
rtabort!("Could not unwind stack, error = {}", error as isize);

extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
exception: *mut uw::_Unwind_Exception) {
rtdebug!("exception_cleanup()");
unsafe {
let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
}
}
}

pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
let my_ep = ptr as *mut Exception;
rtdebug!("caught {}", (*my_ep).uwe.exception_class);
let cause = (*my_ep).cause.take();
uw::_Unwind_DeleteException(ptr as *mut _);
cause.unwrap()
}

// Rust's exception class identifier. This is used by personality routines to
// determine whether the exception was thrown by their own runtime.
fn rust_exception_class() -> uw::_Unwind_Exception_Class {
// M O Z \0 R U S T -- vendor, language
0x4d4f5a_00_52555354
}

// We could implement our personality routine in pure Rust, however exception
// info decoding is tedious. More importantly, personality routines have to
// handle various platform quirks, which are not fun to maintain. For this
// reason, we attempt to reuse personality routine of the C language:
// __gcc_personality_v0.
//
// Since C does not support exception catching, __gcc_personality_v0 simply
// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
//
// This is pretty close to Rust's exception handling approach, except that Rust
// does have a single "catch-all" handler at the bottom of each thread's stack.
// So we have two versions of the personality routine:
// - rust_eh_personality, used by all cleanup landing pads, which never catches,
// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
// - rust_eh_personality_catch, used only by rust_try(), which always catches.
//
// Note, however, that for implementation simplicity, rust_eh_personality_catch
// lacks code to install a landing pad, so in order to obtain exception object
// pointer (which it needs to return upstream), rust_try() employs another trick:
// it calls into the nested rust_try_inner(), whose landing pad does not resume
// unwinds. Instead, it extracts the exception pointer and performs a "normal"
// return.
//
// See also: rt/rust_try.ll

#[cfg(all(not(target_arch = "arm"),
not(all(windows, target_arch = "x86_64")),
not(test)))]
pub mod eabi {
use rt::libunwind as uw;
use libc::c_int;

extern "C" {
fn __gcc_personality_v0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
}

#[lang="eh_personality"]
#[no_mangle] // referenced from rust_try.ll
#[allow(private_no_mangle_fns)]
extern fn rust_eh_personality(
version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{
unsafe {
__gcc_personality_v0(version, actions, exception_class, ue_header,
context)
}
}

#[no_mangle] // referenced from rust_try.ll
pub extern "C" fn rust_eh_personality_catch(
_version: c_int,
actions: uw::_Unwind_Action,
_exception_class: uw::_Unwind_Exception_Class,
_ue_header: *mut uw::_Unwind_Exception,
_context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{

if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
uw::_URC_HANDLER_FOUND // catch!
}
else { // cleanup phase
uw::_URC_INSTALL_CONTEXT
}
}
}

// iOS on armv7 is using SjLj exceptions and therefore requires to use
// a specialized personality routine: __gcc_personality_sj0

#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
pub mod eabi {
use rt::libunwind as uw;
use libc::c_int;

extern "C" {
fn __gcc_personality_sj0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
}

#[lang="eh_personality"]
#[no_mangle] // referenced from rust_try.ll
pub extern "C" fn rust_eh_personality(
version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{
unsafe {
__gcc_personality_sj0(version, actions, exception_class, ue_header,
context)
}
}

#[no_mangle] // referenced from rust_try.ll
pub extern "C" fn rust_eh_personality_catch(
_version: c_int,
actions: uw::_Unwind_Action,
_exception_class: uw::_Unwind_Exception_Class,
_ue_header: *mut uw::_Unwind_Exception,
_context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
uw::_URC_HANDLER_FOUND // catch!
}
else { // cleanup phase
unsafe {
__gcc_personality_sj0(_version, actions, _exception_class, _ue_header,
_context)
}
}
}
}


// ARM EHABI uses a slightly different personality routine signature,
// but otherwise works the same.
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
pub mod eabi {
use rt::libunwind as uw;
use libc::c_int;

extern "C" {
fn __gcc_personality_v0(state: uw::_Unwind_State,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
}

#[lang="eh_personality"]
#[no_mangle] // referenced from rust_try.ll
#[allow(private_no_mangle_fns)]
extern "C" fn rust_eh_personality(
state: uw::_Unwind_State,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{
unsafe {
__gcc_personality_v0(state, ue_header, context)
}
}

#[no_mangle] // referenced from rust_try.ll
pub extern "C" fn rust_eh_personality_catch(
state: uw::_Unwind_State,
_ue_header: *mut uw::_Unwind_Exception,
_context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{
if (state as c_int & uw::_US_ACTION_MASK as c_int)
== uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
uw::_URC_HANDLER_FOUND // catch!
}
else { // cleanup phase
uw::_URC_INSTALL_CONTEXT
}
}
}

// Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
//
// This looks a bit convoluted because rather than implementing a native SEH
// handler, GCC reuses the same personality routine as for the other
// architectures by wrapping it with an "API translator" layer
// (_GCC_specific_handler).

#[cfg(all(windows, target_arch = "x86_64", not(test)))]
#[doc(hidden)]
#[allow(non_camel_case_types, non_snake_case)]
pub mod eabi {
pub use self::EXCEPTION_DISPOSITION::*;
use rt::libunwind as uw;
use libc::{c_void, c_int};

#[repr(C)]
pub struct EXCEPTION_RECORD;
#[repr(C)]
pub struct CONTEXT;
#[repr(C)]
pub struct DISPATCHER_CONTEXT;

#[repr(C)]
#[derive(Copy, Clone)]
pub enum EXCEPTION_DISPOSITION {
ExceptionContinueExecution,
ExceptionContinueSearch,
ExceptionNestedException,
ExceptionCollidedUnwind
}

type _Unwind_Personality_Fn =
extern "C" fn(
version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code;

extern "C" {
fn __gcc_personality_seh0(
exceptionRecord: *mut EXCEPTION_RECORD,
establisherFrame: *mut c_void,
contextRecord: *mut CONTEXT,
dispatcherContext: *mut DISPATCHER_CONTEXT
) -> EXCEPTION_DISPOSITION;

fn _GCC_specific_handler(
exceptionRecord: *mut EXCEPTION_RECORD,
establisherFrame: *mut c_void,
contextRecord: *mut CONTEXT,
dispatcherContext: *mut DISPATCHER_CONTEXT,
personality: _Unwind_Personality_Fn
) -> EXCEPTION_DISPOSITION;
}

#[lang="eh_personality"]
#[no_mangle] // referenced from rust_try.ll
#[allow(private_no_mangle_fns)]
extern "C" fn rust_eh_personality(
exceptionRecord: *mut EXCEPTION_RECORD,
establisherFrame: *mut c_void,
contextRecord: *mut CONTEXT,
dispatcherContext: *mut DISPATCHER_CONTEXT
) -> EXCEPTION_DISPOSITION
{
unsafe {
__gcc_personality_seh0(exceptionRecord, establisherFrame,
contextRecord, dispatcherContext)
}
}

#[no_mangle] // referenced from rust_try.ll
pub extern "C" fn rust_eh_personality_catch(
exceptionRecord: *mut EXCEPTION_RECORD,
establisherFrame: *mut c_void,
contextRecord: *mut CONTEXT,
dispatcherContext: *mut DISPATCHER_CONTEXT
) -> EXCEPTION_DISPOSITION
{
extern "C" fn inner(
_version: c_int,
actions: uw::_Unwind_Action,
_exception_class: uw::_Unwind_Exception_Class,
_ue_header: *mut uw::_Unwind_Exception,
_context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
uw::_URC_HANDLER_FOUND // catch!
}
else { // cleanup phase
uw::_URC_INSTALL_CONTEXT
}
}

unsafe {
_GCC_specific_handler(exceptionRecord, establisherFrame,
contextRecord, dispatcherContext,
inner)
}
}
}

Loading