Auto merge of #57130 - VardhanThigle:Vardhan/x86_64-fortanix-unknown-sgx-tier2_support, r=alexcrichton

Upgrade x86_64-fortanix-unknown-sgx platform support to tier 2

## Overview
1. This PR upgrades x86_64-fortanix-unknown-sgx platform support to tier 2 (std only) by setting up build automation for this target.
1. For supporting unwinding, this target needs to link to a port of LLVM's libunwind (more details could be found in #56979), which will be distributed along with the Rust binaries (similar to the extra musl objects)

### Building and copying libunwind:
We have added a new build script  (`build-x86_64-fortanix-unknown-sgx-toolchain.sh`) that will run while the container is built. This will build `libunwind.a` from git source.
While the container is built, the persistent volumes where obj/ gets created aren't yet mapped. As a workaround, we copy the built `libunwind.a` to  `obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-fortanix-unknown-sgx/lib/` after x.py runs.
 If any reviewer knows of a better solution, please do tell.

r? @Mark-Simulacrum
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 8bc7c58..b581271 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -78,11 +78,8 @@
             builder.info(&format!("Uplifting stage1 std ({} -> {})", from.host, target));
 
             // Even if we're not building std this stage, the new sysroot must
-            // still contain the musl startup objects.
-            if target.contains("musl") {
-                let libdir = builder.sysroot_libdir(compiler, target);
-                copy_musl_third_party_objects(builder, target, &libdir);
-            }
+            // still contain the third party objects needed by various targets.
+            copy_third_party_objects(builder, &compiler, target);
 
             builder.ensure(StdLink {
                 compiler: from,
@@ -92,10 +89,7 @@
             return;
         }
 
-        if target.contains("musl") {
-            let libdir = builder.sysroot_libdir(compiler, target);
-            copy_musl_third_party_objects(builder, target, &libdir);
-        }
+        copy_third_party_objects(builder, &compiler, target);
 
         let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
         std_cargo(builder, &compiler, target, &mut cargo);
@@ -116,17 +110,36 @@
     }
 }
 
-/// Copies the crt(1,i,n).o startup objects
-///
-/// Since musl supports fully static linking, we can cross link for it even
-/// with a glibc-targeting toolchain, given we have the appropriate startup
-/// files. As those shipped with glibc won't work, copy the ones provided by
-/// musl so we have them on linux-gnu hosts.
-fn copy_musl_third_party_objects(builder: &Builder,
-                                 target: Interned<String>,
-                                 into: &Path) {
-    for &obj in &["crt1.o", "crti.o", "crtn.o"] {
-        builder.copy(&builder.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
+/// Copies third pary objects needed by various targets.
+fn copy_third_party_objects(builder: &Builder, compiler: &Compiler, target: Interned<String>) {
+    let libdir = builder.sysroot_libdir(*compiler, target);
+
+    // Copies the crt(1,i,n).o startup objects
+    //
+    // Since musl supports fully static linking, we can cross link for it even
+    // with a glibc-targeting toolchain, given we have the appropriate startup
+    // files. As those shipped with glibc won't work, copy the ones provided by
+    // musl so we have them on linux-gnu hosts.
+    if target.contains("musl") {
+        for &obj in &["crt1.o", "crti.o", "crtn.o"] {
+            builder.copy(
+                &builder.musl_root(target).unwrap().join("lib").join(obj),
+                &libdir.join(obj),
+            );
+        }
+    }
+
+    // Copies libunwind.a compiled to be linked wit x86_64-fortanix-unknown-sgx.
+    //
+    // This target needs to be linked to Fortanix's port of llvm's libunwind.
+    // libunwind requires support for rwlock and printing to stderr,
+    // which is provided by std for this target.
+    if target == "x86_64-fortanix-unknown-sgx" {
+        let src_path_env = "X86_FORTANIX_SGX_LIBS";
+        let obj = "libunwind.a";
+        let src = env::var(src_path_env).expect(&format!("{} not found in env", src_path_env));
+        let src = Path::new(&src).join(obj);
+        builder.copy(&src, &libdir.join(obj));
     }
 }
 
diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile
index 944c2a5..9062555 100644
--- a/src/ci/docker/dist-various-2/Dockerfile
+++ b/src/ci/docker/dist-various-2/Dockerfile
@@ -29,6 +29,10 @@
 COPY dist-various-2/build-solaris-toolchain.sh /tmp/
 RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386
 RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
+COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
+# We pass the commit id of the port of LLVM's libunwind to the build script.
+# Any update to the commit id here, should cause the container image to be re-built from this point on.
+RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "bbe23902411be88d7388f381becefadd6e3ef819"
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -65,6 +69,9 @@
 ENV TARGETS=$TARGETS,x86_64-sun-solaris
 ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
 ENV TARGETS=$TARGETS,x86_64-unknown-cloudabi
+ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx
+
+ENV X86_FORTANIX_SGX_LIBS="/x86_64-fortanix-unknown-sgx/lib/"
 
 ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs
 ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
diff --git a/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh b/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh
new file mode 100755
index 0000000..7692131
--- /dev/null
+++ b/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+set -eu
+source shared.sh
+
+if [ -z "$1" ]; then
+    echo "Usage: ${0} <commit_id>"
+    exit -1
+fi
+
+target="x86_64-fortanix-unknown-sgx"
+url="https://github.com/fortanix/llvm-project/archive/${1}.tar.gz"
+repo_name="llvm-project"
+
+install_prereq()
+{
+    apt-get update
+    apt-get install -y --no-install-recommends \
+            build-essential \
+            ca-certificates \
+            cmake \
+            git
+}
+
+# Clone Fortanix's port of llvm-project to build libunwind that would link with this target.
+# The below method to download a single commit from llvm-project is based on fetch_submodule
+# from init_repo.sh
+fetch_llvm_commit()
+{
+    cached="download-${repo_name}.tar.gz"
+    curl -f -sSL -o ${cached} ${url}
+    tar -xvzf ${cached}
+    mkdir "./${repo_name}" && tar -xf ${cached} -C ${repo_name} --strip-components 1
+}
+
+build_unwind()
+{
+    dir_name="${target}_temp"
+    rm -rf "./${dir_name}"
+    mkdir -p ${dir_name}
+    cd ${dir_name}
+
+    retry fetch_llvm_commit
+    cd "${repo_name}/libunwind"
+
+    # Build libunwind
+    mkdir -p build
+    cd build
+    cmake -DCMAKE_BUILD_TYPE="RELEASE" -DRUST_SGX=1 -G "Unix Makefiles" -DLLVM_PATH=../../llvm/ ../
+    make unwind_static
+    install -D "lib/libunwind.a" "/${target}/lib/libunwind.a"
+    rm -rf ${dir_name}
+}
+
+set -x
+hide_output install_prereq
+hide_output build_unwind
diff --git a/src/ci/docker/dist-various-2/shared.sh b/src/ci/docker/dist-various-2/shared.sh
index 2b5eccb..fb917b0 100644
--- a/src/ci/docker/dist-various-2/shared.sh
+++ b/src/ci/docker/dist-various-2/shared.sh
@@ -13,3 +13,21 @@
   kill $PING_LOOP_PID
   set -x
 }
+
+function retry {
+  echo "Attempting with retry:" "$@"
+  local n=1
+  local max=5
+  while true; do
+    "$@" && break || {
+      if [[ $n -lt $max ]]; then
+        sleep $n  # don't retry immediately
+        ((n++))
+        echo "Command failed. Attempt $n/$max:"
+      else
+        echo "The command has failed after $n attempts."
+        return 1
+      fi
+    }
+  done
+}
diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index 8dad6ee..ac7f95d 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -4,6 +4,16 @@
 .global IMAGE_BASE
 IMAGE_BASE:
 
+.section ".note.x86_64-fortanix-unknown-sgx", "", @note
+    .align 4
+    .long 1f - 0f              /* name length (not including padding) */
+    .long 3f - 2f              /* desc length (not including padding) */
+    .long 1                    /* type = NT_VERSION */
+0:  .asciz "toolchain-version" /* name */
+1:  .align 4
+2:  .long 0                    /* desc - toolchain version number, 32-bit LE */
+3:  .align 4
+
 .section .rodata
 /*  The XSAVE area needs to be a large chunk of readable memory, but since we are */
 /*  going to restore everything to its initial state (XSTATE_BV=0), only certain */
diff --git a/src/libstd/sys/sgx/time.rs b/src/libstd/sys/sgx/time.rs
index 10fe72d..407fe72 100644
--- a/src/libstd/sys/sgx/time.rs
+++ b/src/libstd/sys/sgx/time.rs
@@ -25,6 +25,14 @@
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
         Some(Instant(self.0.checked_sub(*other)?))
     }
+
+    pub fn actually_monotonic() -> bool {
+        false
+    }
+
+    pub const fn zero() -> Instant {
+        Instant(Duration::from_secs(0))
+    }
 }
 
 impl SystemTime {
diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs
index a473820..51c00a1 100644
--- a/src/libstd/sys/sgx/waitqueue.rs
+++ b/src/libstd/sys/sgx/waitqueue.rs
@@ -456,6 +456,7 @@
         }
     }
 
+    /// Lock the Mutex or return false.
     pub macro try_lock_or_false {
         ($e:expr) => {
             if let Some(v) = $e.try_lock() {