Skip to content
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

Add support for 64-bit Windows builds #16261

Merged
merged 11 commits into from Aug 6, 2014
4 changes: 2 additions & 2 deletions mk/platform.mk
Expand Up @@ -377,7 +377,7 @@ RUSTC_CROSS_FLAGS_arm-unknown-linux-gnueabi :=
# mipsel-linux configuration
CC_mipsel-linux=mipsel-linux-gcc
CXX_mipsel-linux=mipsel-linux-g++
CPP_mipsel-linux=mipsel-linux-gcc
CPP_mipsel-linux=mipsel-linux-gcc
AR_mipsel-linux=mipsel-linux-ar
CFG_LIB_NAME_mipsel-linux=lib$(1).so
CFG_STATIC_LIB_NAME_mipsel-linux=lib$(1).a
Expand Down Expand Up @@ -641,7 +641,7 @@ define CFG_MAKE_TOOLCHAIN
CXX_$(1)=$(CROSS_PREFIX_$(1))$(CXX_$(1))
CPP_$(1)=$(CROSS_PREFIX_$(1))$(CPP_$(1))
AR_$(1)=$(CROSS_PREFIX_$(1))$(AR_$(1))
RUSTC_CROSS_FLAGS_$(1)=-C linker=$$(call FIND_COMPILER,$$(CXX_$(1))) \
RUSTC_CROSS_FLAGS_$(1)=-C linker=$$(call FIND_COMPILER,$$(CC_$(1))) \
-C ar=$$(call FIND_COMPILER,$$(AR_$(1))) $(RUSTC_CROSS_FLAGS_$(1))

RUSTC_FLAGS_$(1)=$$(RUSTC_CROSS_FLAGS_$(1)) $(RUSTC_FLAGS_$(1))
Expand Down
2 changes: 1 addition & 1 deletion src/etc/get-snapshot.py
Expand Up @@ -53,7 +53,7 @@ def unpack_snapshot(triple, dl_path):
dl_path = sys.argv[2]
else:
# There are no 64-bit Windows snapshots yet, so we'll use 32-bit ones instead, for now
snap_triple = triple if triple != "x86_64-w64-mingw32" else "i686-pc-mingw32"
snap_triple = triple if triple != "x86_64-w64-mingw32" else "i686-w64-mingw32"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is changed by the line? (was this causing problem on some environments?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Purely cosmetic. Since we are now on mingw64, I thought we should use its' triple for consistency.

snap = determine_curr_snapshot(snap_triple)
dl = os.path.join(download_dir_base, snap)
url = download_url_base + "/" + snap
Expand Down
44 changes: 31 additions & 13 deletions src/libgreen/context.rs
Expand Up @@ -13,6 +13,8 @@ use std::uint;
use std::mem::transmute;
use std::rt::stack;
use std::raw;
#[cfg(target_arch = "x86_64")]
use std::simd;

// FIXME #7761: Registers is boxed so that it is 16-byte aligned, for storing
// SSE regs. It would be marginally better not to do this. In C++ we
Expand Down Expand Up @@ -103,11 +105,11 @@ impl Context {
// invalid for the current task. Lucky for us `rust_swap_registers`
// is a C function so we don't have to worry about that!
match in_context.stack_bounds {
Some((lo, hi)) => stack::record_stack_bounds(lo, hi),
Some((lo, hi)) => stack::record_rust_managed_stack_bounds(lo, hi),
// If we're going back to one of the original contexts or
// something that's possibly not a "normal task", then reset
// the stack limit to 0 to make morestack never fail
None => stack::record_stack_bounds(0, uint::MAX),
None => stack::record_rust_managed_stack_bounds(0, uint::MAX),
}
rust_swap_registers(out_regs, in_regs)
}
Expand Down Expand Up @@ -186,14 +188,30 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
// windows requires saving more registers (both general and XMM), so the windows
// register context must be larger.
#[cfg(windows, target_arch = "x86_64")]
type Registers = [uint, ..34];
struct Registers {
gpr:[uint, ..14],
_xmm:[simd::u32x4, ..10]
}
#[cfg(not(windows), target_arch = "x86_64")]
type Registers = [uint, ..22];
struct Registers {
gpr:[uint, ..10],
_xmm:[simd::u32x4, ..6]
}

#[cfg(windows, target_arch = "x86_64")]
fn new_regs() -> Box<Registers> { box() ([0, .. 34]) }
fn new_regs() -> Box<Registers> {
box() Registers {
gpr:[0,..14],
_xmm:[simd::u32x4(0,0,0,0),..10]
}
}
#[cfg(not(windows), target_arch = "x86_64")]
fn new_regs() -> Box<Registers> { box() ([0, .. 22]) }
fn new_regs() -> Box<Registers> {
box() Registers {
gpr:[0,..10],
_xmm:[simd::u32x4(0,0,0,0),..6]
}
}

#[cfg(target_arch = "x86_64")]
fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
Expand Down Expand Up @@ -222,20 +240,20 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,

// These registers are frobbed by rust_bootstrap_green_task into the right
// location so we can invoke the "real init function", `fptr`.
regs[RUSTRT_R12] = arg as uint;
regs[RUSTRT_R13] = procedure.code as uint;
regs[RUSTRT_R14] = procedure.env as uint;
regs[RUSTRT_R15] = fptr as uint;
regs.gpr[RUSTRT_R12] = arg as uint;
regs.gpr[RUSTRT_R13] = procedure.code as uint;
regs.gpr[RUSTRT_R14] = procedure.env as uint;
regs.gpr[RUSTRT_R15] = fptr as uint;

// These registers are picked up by the regular context switch paths. These
// will put us in "mostly the right context" except for frobbing all the
// arguments to the right place. We have the small trampoline code inside of
// rust_bootstrap_green_task to do that.
regs[RUSTRT_RSP] = sp as uint;
regs[RUSTRT_IP] = rust_bootstrap_green_task as uint;
regs.gpr[RUSTRT_RSP] = sp as uint;
regs.gpr[RUSTRT_IP] = rust_bootstrap_green_task as uint;

// Last base pointer on the stack should be 0
regs[RUSTRT_RBP] = 0;
regs.gpr[RUSTRT_RBP] = 0;
}

#[cfg(target_arch = "arm")]
Expand Down
2 changes: 1 addition & 1 deletion src/libnative/lib.rs
Expand Up @@ -137,7 +137,7 @@ pub fn start(argc: int, argv: *const *const u8, main: proc()) -> int {
task.name = Some(str::Slice("<main>"));
drop(task.run(|| {
unsafe {
rt::stack::record_stack_bounds(my_stack_bottom, my_stack_top);
rt::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top);
}
exit_code = Some(run(main.take_unwrap()));
}).destroy());
Expand Down
2 changes: 1 addition & 1 deletion src/libnative/task.rs
Expand Up @@ -84,7 +84,7 @@ pub fn spawn_opts(opts: TaskOpts, f: proc():Send) {
let addr = &something_around_the_top_of_the_stack as *const int;
let my_stack = addr as uint;
unsafe {
stack::record_stack_bounds(my_stack - stack + 1024, my_stack);
stack::record_os_managed_stack_bounds(my_stack - stack + 1024, my_stack);
}
let mut ops = ops;
ops.stack_bounds = (my_stack - stack + 1024, my_stack);
Expand Down
2 changes: 1 addition & 1 deletion src/librustrt/libunwind.rs
Expand Up @@ -60,7 +60,7 @@ pub type _Unwind_Word = libc::uintptr_t;
pub static unwinder_private_data_size: uint = 5;

#[cfg(target_arch = "x86_64")]
pub static unwinder_private_data_size: uint = 2;
pub static unwinder_private_data_size: uint = 6;

#[cfg(target_arch = "arm", not(target_os = "ios"))]
pub static unwinder_private_data_size: uint = 20;
Expand Down
32 changes: 24 additions & 8 deletions src/librustrt/stack.rs
Expand Up @@ -124,8 +124,23 @@ extern fn stack_exhausted() {
}
}

// Windows maintains a record of upper and lower stack bounds in the Thread Information
// Block (TIB), and some syscalls do check that addresses which are supposed to be in
// the stack, indeed lie between these two values.
// (See https://github.com/rust-lang/rust/issues/3445#issuecomment-26114839)
//
// When using Rust-managed stacks (libgreen), we must maintain these values accordingly.
// For OS-managed stacks (libnative), we let the OS manage them for us.
//
// On all other platforms both variants behave identically.

#[inline(always)]
pub unsafe fn record_stack_bounds(stack_lo: uint, stack_hi: uint) {
pub unsafe fn record_os_managed_stack_bounds(stack_lo: uint, _stack_hi: uint) {
record_sp_limit(stack_lo + RED_ZONE);
}

#[inline(always)]
pub unsafe fn record_rust_managed_stack_bounds(stack_lo: uint, stack_hi: uint) {
// When the old runtime had segmented stacks, it used a calculation that was
// "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic
// symbol resolution, llvm function calls, etc. In theory this red zone
Expand All @@ -138,16 +153,17 @@ pub unsafe fn record_stack_bounds(stack_lo: uint, stack_hi: uint) {

return target_record_stack_bounds(stack_lo, stack_hi);

#[cfg(not(windows))] #[cfg(not(target_arch = "x86_64"))] #[inline(always)]
#[cfg(not(windows))] #[inline(always)]
unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {}

#[cfg(windows, target_arch = "x86")] #[inline(always)]
unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
// stack range is at TIB: %fs:0x04 (top) and %fs:0x08 (bottom)
asm!("mov $0, %fs:0x04" :: "r"(stack_hi) :: "volatile");
asm!("mov $0, %fs:0x08" :: "r"(stack_lo) :: "volatile");
}
#[cfg(windows, target_arch = "x86_64")] #[inline(always)]
unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
// Windows compiles C functions which may check the stack bounds. This
// means that if we want to perform valid FFI on windows, then we need
// to ensure that the stack bounds are what they truly are for this
// task. More info can be found at:
// https://github.com/rust-lang/rust/issues/3445#issuecomment-26114839
//
// stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile");
asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile");
Expand Down
2 changes: 1 addition & 1 deletion src/librustrt/thread.rs
Expand Up @@ -44,7 +44,7 @@ static DEFAULT_STACK_SIZE: uint = 1024 * 1024;
#[no_split_stack]
extern fn thread_start(main: *mut libc::c_void) -> imp::rust_thread_return {
unsafe {
stack::record_stack_bounds(0, uint::MAX);
stack::record_os_managed_stack_bounds(0, uint::MAX);
let f: Box<proc()> = mem::transmute(main);
(*f)();
mem::transmute(0 as imp::rust_thread_return)
Expand Down