diff --git a/.travis.yml b/.travis.yml
index 3f0ca8a016..137ae4fe66 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,8 +21,6 @@ env:
   - RUST_BACKTRACE=1
 
 before_script:
-# Linux: install extra stuff for cross-compilation
-- if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi
 # Compute the rust version we use. We do not use "language: rust" to have more control here.
 - |
   if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c673e107d5..573f9f6ef6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -52,18 +52,19 @@ all the same flags as `rustc` (though the ones only affecting code generation
 and linking obviously will have no effect) [and more][miri-flags].
 
 Running the Miri driver requires some fiddling with environment variables, so
-the `miri` script helps you do that.  For example, you can run the driver on a
-particular file by doing
+the `miri` script helps you do that.  For example, you can (cross-)run the
+driver on a particular file by doing
 
 ```sh
 ./miri run tests/run-pass/format.rs
 ./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu
 ```
 
-and you can run the test suite using:
+and you can (cross-)run the test suite using:
 
 ```
 ./miri test
+MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test
 ```
 
 `./miri test FILTER` only runs those tests that contain `FILTER` in their
@@ -104,7 +105,8 @@ and then you can use it as if it was installed by `rustup`.  Make sure you use
 the same toolchain when calling `cargo miri` that you used when installing Miri!
 
 There's a test for the cargo wrapper in the `test-cargo-miri` directory; run
-`./run-test.py` in there to execute it.
+`./run-test.py` in there to execute it. Like `./miri test`, this respects the
+`MIRI_TEST_TARGET` environment variable to execute the test for another target.
 
 ## Building Miri with a locally built rustc
 
diff --git a/README.md b/README.md
index e0e7df24fa..59394830d7 100644
--- a/README.md
+++ b/README.md
@@ -76,6 +76,11 @@ Now you can run your project in Miri:
 The first time you run Miri, it will perform some extra setup and install some
 dependencies.  It will ask you for confirmation before installing anything.
 
+Miri supports cross-execution: if you want to run the program as if it was a
+Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`.
+This is particularly useful if you are using Windows, as the Linux target is
+much better supported than Windows targets.
+
 You can pass arguments to Miri after the first `--`, and pass arguments to the
 interpreted program or test suite after the second `--`.  For example, `cargo
 miri run -- -Zmiri-disable-validation` runs the program without validation of
diff --git a/rust-version b/rust-version
index aaf176861b..29c1f3a2a8 100644
--- a/rust-version
+++ b/rust-version
@@ -1 +1 @@
-98803c182b2ba6ef5dccb6bf501958249295eac0
+38114ff16e7856f98b2b4be7ab4cd29b38bed59a
diff --git a/src/eval.rs b/src/eval.rs
index 898e1ff6e4..de6c9fac1d 100644
--- a/src/eval.rs
+++ b/src/eval.rs
@@ -190,7 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
 /// Returns `Some(return_code)` if program executed completed.
 /// Returns `None` if an evaluation error occured.
 pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
-    // FIXME: We always ignore leaks on some platforms where we do not
+    // FIXME: We always ignore leaks on some OSs where we do not
     // correctly implement TLS destructors.
     let target_os = tcx.sess.target.target.target_os.as_str();
     let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos";
diff --git a/src/helpers.rs b/src/helpers.rs
index 169bb42056..36d3181ce4 100644
--- a/src/helpers.rs
+++ b/src/helpers.rs
@@ -374,16 +374,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
         }
         Ok(())
     }
-    /// Helper function used inside the shims of foreign functions to assert that the target
-    /// platform is `platform`. It panics showing a message with the `name` of the foreign function
+    /// Helper function used inside the shims of foreign functions to assert that the target OS
+    /// is `target_os`. It panics showing a message with the `name` of the foreign function
     /// if this is not the case.
-    fn assert_platform(&self, platform: &str, name: &str) {
+    fn assert_target_os(&self, target_os: &str, name: &str) {
         assert_eq!(
             self.eval_context_ref().tcx.sess.target.target.target_os,
-            platform,
-            "`{}` is only available on the `{}` platform",
+            target_os,
+            "`{}` is only available on the `{}` target OS",
             name,
-            platform,
+            target_os,
         )
     }
 
diff --git a/src/machine.rs b/src/machine.rs
index 3cf0078133..693c80f7de 100644
--- a/src/machine.rs
+++ b/src/machine.rs
@@ -126,7 +126,7 @@ impl MemoryExtra {
                     .insert(Symbol::intern("environ"), this.machine.env_vars.environ.unwrap().ptr.assert_ptr().alloc_id)
                     .unwrap_none();
             }
-            _ => {} // No "extern statics" supported on this platform
+            _ => {} // No "extern statics" supported on this target
         }
         Ok(())
     }
diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs
index 60da1f1e6c..6827b72427 100644
--- a/src/shims/foreign_items.rs
+++ b/src/shims/foreign_items.rs
@@ -437,7 +437,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
             _ => match this.tcx.sess.target.target.target_os.as_str() {
                 "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
                 "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
-                target => throw_unsup_format!("the {} target platform is not supported", target),
+                target => throw_unsup_format!("the target `{}` is not supported", target),
             }
         };
 
diff --git a/src/shims/fs.rs b/src/shims/fs.rs
index a5aae5ed90..d799d8ed9a 100644
--- a/src/shims/fs.rs
+++ b/src/shims/fs.rs
@@ -66,9 +66,9 @@ impl FileHandler {
 
 impl<'mir, 'tcx> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
 trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
-    /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be
+    /// Emulate `stat` or `lstat` on `macos`. This function is not intended to be
     /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is
-    /// disabled or if the target platform is the correct one. Please use `macos_stat` or
+    /// disabled or if the target OS is the correct one. Please use `macos_stat` or
     /// `macos_lstat` instead.
     fn macos_stat_or_lstat(
         &mut self,
@@ -114,7 +114,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, '
         let blksize_t_layout = this.libc_ty_layout("blksize_t")?;
         let uint32_t_layout = this.libc_ty_layout("uint32_t")?;
 
-        // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform.
+        // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit target.
         let pad_layout = if this.tcx.sess.target.ptr_width == 64 {
             uint32_t_layout
         } else {
@@ -258,10 +258,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
         let o_wronly = this.eval_libc_i32("O_WRONLY")?;
         let o_rdwr = this.eval_libc_i32("O_RDWR")?;
         // The first two bits of the flag correspond to the access mode in linux, macOS and
-        // windows. We need to check that in fact the access mode flags for the current platform
-        // only use these two bits, otherwise we are in an unsupported platform and should error.
+        // windows. We need to check that in fact the access mode flags for the current target
+        // only use these two bits, otherwise we are in an unsupported target and should error.
         if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 {
-            throw_unsup_format!("access mode flags on this platform are unsupported");
+            throw_unsup_format!("access mode flags on this target are unsupported");
         }
         let mut writable = true;
 
@@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
         buf_op: OpTy<'tcx, Tag>,
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
-        this.assert_platform("macos", "stat");
+        this.assert_target_os("macos", "stat");
         this.check_no_isolation("stat")?;
         // `stat` always follows symlinks.
         this.macos_stat_or_lstat(true, path_op, buf_op)
@@ -587,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
         buf_op: OpTy<'tcx, Tag>,
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
-        this.assert_platform("macos", "lstat");
+        this.assert_target_os("macos", "lstat");
         this.check_no_isolation("lstat")?;
         this.macos_stat_or_lstat(false, path_op, buf_op)
     }
@@ -599,7 +599,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
-        this.assert_platform("macos", "fstat");
+        this.assert_target_os("macos", "fstat");
         this.check_no_isolation("fstat")?;
 
         let fd = this.read_scalar(fd_op)?.to_i32()?;
@@ -621,7 +621,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
-        this.assert_platform("linux", "statx");
+        this.assert_target_os("linux", "statx");
         this.check_no_isolation("statx")?;
 
         let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?;
@@ -685,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
         // the `_mask_op` paramter specifies the file information that the caller requested.
         // However `statx` is allowed to return information that was not requested or to not
         // return information that was requested. This `mask` represents the information we can
-        // actually provide in any host platform.
+        // actually provide for any target.
         let mut mask =
             this.eval_libc("STATX_TYPE")?.to_u32()? | this.eval_libc("STATX_SIZE")?.to_u32()?;
 
@@ -880,7 +880,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
-        this.assert_platform("linux", "readdir64_r");
+        this.assert_target_os("linux", "readdir64_r");
         this.check_no_isolation("readdir64_r")?;
 
         let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?;
@@ -967,7 +967,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
-        this.assert_platform("macos", "readdir_r");
+        this.assert_target_os("macos", "readdir_r");
         this.check_no_isolation("readdir_r")?;
 
         let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?;
diff --git a/src/shims/panic.rs b/src/shims/panic.rs
index 8dded8bf40..703e711972 100644
--- a/src/shims/panic.rs
+++ b/src/shims/panic.rs
@@ -32,11 +32,11 @@ pub struct CatchUnwindData<'tcx> {
 
 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
-    /// Check if panicking is supported on this platform, and give a good error otherwise.
+    /// Check if panicking is supported on this target, and give a good error otherwise.
     fn check_panic_supported(&self) -> InterpResult<'tcx> {
         match self.eval_context_ref().tcx.sess.target.target.target_os.as_str() {
             "linux" | "macos" => Ok(()),
-            _ => throw_unsup_format!("panicking is not supported on this platform"),
+            _ => throw_unsup_format!("panicking is not supported on this target"),
         }
     }
 
diff --git a/src/shims/time.rs b/src/shims/time.rs
index b270c9770f..58db60e516 100644
--- a/src/shims/time.rs
+++ b/src/shims/time.rs
@@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
-        this.assert_platform("linux", "clock_gettime");
+        this.assert_target_os("linux", "clock_gettime");
         this.check_no_isolation("clock_gettime")?;
 
         let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
@@ -58,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
     ) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
-        this.assert_platform("macos", "gettimeofday");
+        this.assert_target_os("macos", "gettimeofday");
         this.check_no_isolation("gettimeofday")?;
 
         // Using tz is obsolete and should always be null
@@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
     fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
         let this = self.eval_context_ref();
 
-        this.assert_platform("macos", "mach_absolute_time");
+        this.assert_target_os("macos", "mach_absolute_time");
         this.check_no_isolation("mach_absolute_time")?;
 
         // This returns a u64, with time units determined dynamically by `mach_timebase_info`.
diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py
index a4086bcc8c..57b23a6a2a 100755
--- a/test-cargo-miri/run-test.py
+++ b/test-cargo-miri/run-test.py
@@ -7,6 +7,10 @@
 
 import sys, subprocess, os
 
+CGREEN  = '\33[32m'
+CBOLD   = '\33[1m'
+CEND    = '\33[0m'
+
 def fail(msg):
     print("\nTEST FAIL: {}".format(msg))
     sys.exit(1)
@@ -67,6 +71,9 @@ def test_cargo_miri_test():
 
 os.chdir(os.path.dirname(os.path.realpath(__file__)))
 
+target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else ""
+print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND)
+
 if not 'MIRI_SYSROOT' in os.environ:
     # Make sure we got a working sysroot.
     # (If the sysroot gets built later when output is compared, that leads to test failures.)
diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs
index 0095802a59..68d5426802 100644
--- a/test-cargo-miri/tests/test.rs
+++ b/test-cargo-miri/tests/test.rs
@@ -45,7 +45,7 @@ fn num_cpus() {
 
 // FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059.
 // We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test
-// stdout does not depend on the platform.
+// stdout does not depend on the target.
 #[test]
 #[cfg_attr(not(windows), should_panic(expected="Explicit panic"))]
 fn do_panic() { // In large, friendly letters :)
diff --git a/tests/compile-fail/panic/windows1.rs b/tests/compile-fail/panic/windows1.rs
index 1d6faf1e75..142ba85c42 100644
--- a/tests/compile-fail/panic/windows1.rs
+++ b/tests/compile-fail/panic/windows1.rs
@@ -3,7 +3,7 @@
 
 // Test that panics on Windows give a reasonable error message.
 
-// error-pattern: panicking is not supported on this platform
+// error-pattern: panicking is not supported on this target
 fn main() {
     core::panic!("this is {}", "Windows");
 }
diff --git a/tests/compile-fail/panic/windows2.rs b/tests/compile-fail/panic/windows2.rs
index 023088a692..da2cfb5936 100644
--- a/tests/compile-fail/panic/windows2.rs
+++ b/tests/compile-fail/panic/windows2.rs
@@ -3,7 +3,7 @@
 
 // Test that panics on Windows give a reasonable error message.
 
-// error-pattern: panicking is not supported on this platform
+// error-pattern: panicking is not supported on this target
 fn main() {
     std::panic!("this is Windows");
 }
diff --git a/tests/compile-fail/panic/windows3.rs b/tests/compile-fail/panic/windows3.rs
index b96022fc4e..a2e7bf5a7d 100644
--- a/tests/compile-fail/panic/windows3.rs
+++ b/tests/compile-fail/panic/windows3.rs
@@ -3,7 +3,7 @@
 
 // Test that panics on Windows give a reasonable error message.
 
-// error-pattern: panicking is not supported on this platform
+// error-pattern: panicking is not supported on this target
 #[allow(unconditional_panic)]
 fn main() {
     let _val = 1/0;
diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs
index a30f0fb613..02031130b8 100644
--- a/tests/run-pass/bitop-beyond-alignment.rs
+++ b/tests/run-pass/bitop-beyond-alignment.rs
@@ -33,5 +33,5 @@ fn is_u64_aligned(u: &Tag<u64>) -> bool {
 
 pub fn main() {
     let x = mk_rec();
-    is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between platforms)
+    is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between targets)
 }
diff --git a/tests/run-pass/memchr.rs b/tests/run-pass/memchr.rs
index 2f5e2c4bb7..e92c37ff2a 100644
--- a/tests/run-pass/memchr.rs
+++ b/tests/run-pass/memchr.rs
@@ -2,7 +2,7 @@
 
 use core::slice::memchr::{memchr, memrchr};
 
-// test fallback implementations on all platforms
+// test fallback implementations on all targets
 fn matches_one() {
     assert_eq!(Some(0), memchr(b'a', b"a"));
 }
diff --git a/travis.sh b/travis.sh
index fec9145ab0..8b2453584b 100755
--- a/travis.sh
+++ b/travis.sh
@@ -2,9 +2,6 @@
 set -euo pipefail
 
 # Determine configuration
-if [ "$TRAVIS_OS_NAME" == linux ]; then
-  FOREIGN_TARGET=i686-unknown-linux-gnu
-fi
 export CARGO_EXTRA_FLAGS="--all-features"
 export RUSTC_EXTRA_FLAGS="-D warnings"
 
@@ -16,19 +13,35 @@ echo
 
 # Test
 function run_tests {
-    ./miri test --locked
+  if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
+    echo "Testing foreign architecture $MIRI_TEST_TARGET"
+  else
+    echo "Testing host architecture"
+  fi
+
+  ./miri test --locked
+  if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then
+    # Only for host architecture: tests with MIR optimizations
     MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test
-    # "miri test" has built the sysroot for us, now this should pass without
-    # any interactive questions.
-    test-cargo-miri/run-test.py
+  fi
+  # "miri test" has built the sysroot for us, now this should pass without
+  # any interactive questions.
+  test-cargo-miri/run-test.py
+
+  echo
 }
 
-echo "Test host architecture"
+# host
 run_tests
-echo
+# cross-test 32bit Linux from everywhere
+MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
 
-if [ -n "${FOREIGN_TARGET+exists}" ]; then
-  echo "Test foreign architecture ($FOREIGN_TARGET)"
-  MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests
-  echo
+if [ "$TRAVIS_OS_NAME" == linux ]; then
+  # cross-test 64bit macOS from Linux
+  MIRI_TEST_TARGET=x86_64-apple-darwin run_tests
+  # cross-test 32bit Windows from Linux
+  MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
+elif [ "$TRAVIS_OS_NAME" == osx ]; then
+  # cross-test 64bit Windows from macOS
+  MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests
 fi