Support rust-nightly-2022-02-23
diff --git a/dockerfile/Dockerfile.1804.nightly b/dockerfile/Dockerfile.1804.nightly
index e3ea188..7618c98 100644
--- a/dockerfile/Dockerfile.1804.nightly
+++ b/dockerfile/Dockerfile.1804.nightly
@@ -31,7 +31,7 @@
 
 # Seventh, Rust
 
-ENV rust_toolchain  nightly-2021-11-01
+ENV rust_toolchain  nightly-2022-02-23
 ADD 05_rust.sh /root
 RUN bash /root/05_rust.sh
 
diff --git a/dockerfile/Dockerfile.2004.nightly b/dockerfile/Dockerfile.2004.nightly
index 2ffc20b..6203670 100644
--- a/dockerfile/Dockerfile.2004.nightly
+++ b/dockerfile/Dockerfile.2004.nightly
@@ -34,7 +34,7 @@
 
 # Seventh, Rust
 
-ENV rust_toolchain  nightly-2021-11-01
+ENV rust_toolchain  nightly-2022-02-23
 ADD 05_rust.sh /root
 RUN bash /root/05_rust.sh
 
diff --git a/dockerfile/Dockerfile.centos8.nightly b/dockerfile/Dockerfile.centos8.nightly
index bd107c2..939f948 100644
--- a/dockerfile/Dockerfile.centos8.nightly
+++ b/dockerfile/Dockerfile.centos8.nightly
@@ -22,7 +22,7 @@
 ADD 04_psw_rpm.sh /root
 RUN bash /root/04_psw_rpm.sh
 
-ENV rust_toolchain  nightly-2021-11-01
+ENV rust_toolchain  nightly-2022-02-23
 ADD 05_rust.sh /root
 RUN bash /root/05_rust.sh
 
diff --git a/edl/sgx_file.edl b/edl/sgx_file.edl
index 07fb1eb..c70ec59 100644
--- a/edl/sgx_file.edl
+++ b/edl/sgx_file.edl
@@ -27,6 +27,7 @@
     untrusted {
         int u_open_ocall([out] int *error, [in, string] const char *pathname, int flags);
         int u_open64_ocall([out] int *error, [in, string] const char *path, int oflag, int mode);
+        int u_openat_ocall([out] int *error, int dirfd, [in, string] const char *pathname, int flags);
 
         int u_fstat_ocall([out] int *error, int fd, [out] struct stat_t *buf);
         int u_fstat64_ocall([out] int *error, int fd, [out] struct stat64_t *buf);
@@ -46,6 +47,7 @@
         int u_fchmod_ocall([out] int *error, int fd, uint32_t mode);
         int u_unlink_ocall([out] int *error, [in, string] const char *pathname);
         int u_link_ocall([out] int *error, [in, string] const char *oldpath, [in, string] const char *newpath);
+        int u_unlinkat_ocall([out] int *error, int dirfd, [in, string] const char *pathname, int flags);
         int u_linkat_ocall([out] int *error, int olddirfd, [in, string] const char *oldpath, int newdirfd, [in, string] const char *newpath, int flags);
         int u_rename_ocall([out] int *error, [in, string] const char *oldpath, [in, string] const char *newpath);
         int u_chmod_ocall([out] int *error, [in, string] const char *path, uint32_t mode);
@@ -54,6 +56,7 @@
         char *u_realpath_ocall([out] int *error, [in, string] const char *pathname);
         int u_mkdir_ocall([out] int *error, [in, string] const char *pathname, uint32_t mode);
         int u_rmdir_ocall([out] int *error, [in, string] const char *pathname);
+        void *u_fdopendir_ocall([out] int *error, int fd);
         void *u_opendir_ocall([out] int *error, [in, string] const char *pathname);
         int u_readdir64_r_ocall([user_check] void *dirp, [in, out] struct dirent64_t *entry, [out] struct dirent64_t **result);
         int u_closedir_ocall([out] int *error, [user_check] void *dirp);
diff --git a/rust-toolchain b/rust-toolchain
index 7cc42ef..4e7e21b 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-nightly-2021-11-01
+nightly-2022-02-23
\ No newline at end of file
diff --git a/samplecode/backtrace/enclave/Cargo.toml b/samplecode/backtrace/enclave/Cargo.toml
index 00b1f7b..ef0574e 100644
--- a/samplecode/backtrace/enclave/Cargo.toml
+++ b/samplecode/backtrace/enclave/Cargo.toml
@@ -16,6 +16,7 @@
 sgx_backtrace = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -24,6 +25,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/backtrace/enclave/Xargo.toml b/samplecode/backtrace/enclave/Xargo.toml
index abb29c4..13d92c3 100644
--- a/samplecode/backtrace/enclave/Xargo.toml
+++ b/samplecode/backtrace/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/backtrace/enclave/x86_64-unknown-linux-sgx.json b/samplecode/backtrace/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/backtrace/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/backtrace/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/crypto/enclave/Cargo.toml b/samplecode/crypto/enclave/Cargo.toml
index b6839c3..7bc5264 100644
--- a/samplecode/crypto/enclave/Cargo.toml
+++ b/samplecode/crypto/enclave/Cargo.toml
@@ -17,6 +17,7 @@
 sgx_tcrypto = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -25,6 +26,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
@@ -41,6 +43,6 @@
 sgx_tstd = { path = "../../../sgx_tstd" }
 sgx_tunittest = { path = "../../../sgx_tunittest" }
 sgx_types = { path = "../../../sgx_types" }
-sgx_ucrypto = { path = "../../../sgx_ucrypto" }
+#sgx_ucrypto = { path = "../../../sgx_ucrypto" }
 sgx_unwind = { path = "../../../sgx_unwind" }
-sgx_urts = { path = "../../../sgx_urts" }
+#sgx_urts = { path = "../../../sgx_urts" }
diff --git a/samplecode/crypto/enclave/x86_64-unknown-linux-sgx.json b/samplecode/crypto/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/crypto/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/crypto/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/db-proxy/db-proxy/enclave/Cargo.toml b/samplecode/db-proxy/db-proxy/enclave/Cargo.toml
index 7c13f5d..9661fe8 100644
--- a/samplecode/db-proxy/db-proxy/enclave/Cargo.toml
+++ b/samplecode/db-proxy/db-proxy/enclave/Cargo.toml
@@ -15,6 +15,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -23,6 +24,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
@@ -41,4 +43,4 @@
 sgx_types = { path = "../../../../sgx_types" }
 #sgx_ucrypto = { path = "../../../../sgx_ucrypto" }
 sgx_unwind = { path = "../../../../sgx_unwind" }
-#sgx_urts = { path = "../../../../sgx_urts" }
+#sgx_urts = { path = "../../../../sgx_urts" }
\ No newline at end of file
diff --git a/samplecode/db-proxy/db-proxy/enclave/x86_64-unknown-linux-sgx.json b/samplecode/db-proxy/db-proxy/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/db-proxy/db-proxy/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/db-proxy/db-proxy/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/dcap-pckretrieval/enclave/x86_64-unknown-linux-sgx.json b/samplecode/dcap-pckretrieval/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/dcap-pckretrieval/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/dcap-pckretrieval/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/file/enclave/Cargo.toml b/samplecode/file/enclave/Cargo.toml
index 3bac2bf..09ece4c 100644
--- a/samplecode/file/enclave/Cargo.toml
+++ b/samplecode/file/enclave/Cargo.toml
@@ -20,6 +20,7 @@
 sgx_serialize_derive = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -28,6 +29,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/file/enclave/x86_64-unknown-linux-sgx.json b/samplecode/file/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/file/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/file/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/hello-regex/enclave/Cargo.toml b/samplecode/hello-regex/enclave/Cargo.toml
index 9e6cfc3..7a7da44 100644
--- a/samplecode/hello-regex/enclave/Cargo.toml
+++ b/samplecode/hello-regex/enclave/Cargo.toml
@@ -18,6 +18,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -26,6 +27,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/hello-regex/enclave/x86_64-unknown-linux-sgx.json b/samplecode/hello-regex/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/hello-regex/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/hello-regex/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/hello-rust-vscode-debug/Cargo.toml b/samplecode/hello-rust-vscode-debug/Cargo.toml
index 50897b4..f5ecf2c 100644
--- a/samplecode/hello-rust-vscode-debug/Cargo.toml
+++ b/samplecode/hello-rust-vscode-debug/Cargo.toml
@@ -4,29 +4,3 @@
     "app",
     "enclave",
 ]
-
-[patch.'https://github.com/apache/teaclave-sgx-sdk.git']
-sgx_alloc = { path = "../../sgx_alloc" }
-sgx_build_helper = { path = "../../sgx_build_helper" }
-sgx_cov = { path = "../../sgx_cov" }
-sgx_crypto_helper = { path = "../../sgx_crypto_helper" }
-sgx_libc = { path = "../../sgx_libc" }
-sgx_rand = { path = "../../sgx_rand" }
-sgx_rand_derive = { path = "../../sgx_rand_derive" }
-sgx_serialize = { path = "../../sgx_serialize" }
-sgx_serialize_derive = { path = "../../sgx_serialize_derive" }
-sgx_serialize_derive_internals = { path = "../../sgx_serialize_derive_internals" }
-sgx_tcrypto = { path = "../../sgx_tcrypto" }
-sgx_tcrypto_helper = { path = "../../sgx_tcrypto_helper" }
-sgx_tdh = { path = "../../sgx_tdh" }
-sgx_tkey_exchange = { path = "../../sgx_tkey_exchange" }
-sgx_tprotected_fs = { path = "../../sgx_tprotected_fs" }
-sgx_trts = { path = "../../sgx_trts" }
-sgx_tse = { path = "../../sgx_tse" }
-sgx_tseal = { path = "../../sgx_tseal" }
-sgx_tstd = { path = "../../sgx_tstd" }
-sgx_tunittest = { path = "../../sgx_tunittest" }
-sgx_types = { path = "../../sgx_types" }
-sgx_ucrypto = { path = "../../sgx_ucrypto" }
-sgx_unwind = { path = "../../sgx_unwind" }
-sgx_urts = { path = "../../sgx_urts" }
diff --git a/samplecode/hello-rust-vscode-debug/enclave/Cargo.toml b/samplecode/hello-rust-vscode-debug/enclave/Cargo.toml
index f4f3224..c547778 100644
--- a/samplecode/hello-rust-vscode-debug/enclave/Cargo.toml
+++ b/samplecode/hello-rust-vscode-debug/enclave/Cargo.toml
@@ -15,6 +15,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -23,6 +24,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/hello-rust-vscode-debug/enclave/x86_64-unknown-linux-sgx.json b/samplecode/hello-rust-vscode-debug/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/hello-rust-vscode-debug/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/hello-rust-vscode-debug/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/hello-rust/enclave/Cargo.toml b/samplecode/hello-rust/enclave/Cargo.toml
index 8e7afa9..fe0ebe3 100644
--- a/samplecode/hello-rust/enclave/Cargo.toml
+++ b/samplecode/hello-rust/enclave/Cargo.toml
@@ -12,14 +12,19 @@
 
 [target.'cfg(not(target_env = "sgx"))'.dependencies]
 sgx_types = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
-sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git", features = ["backtrace"] }
-sgx_trts = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
+sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
+
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
+sgx_backtrace = { path = "../../../sgx_backtrace" }
+sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
 sgx_build_helper = { path = "../../../sgx_build_helper" }
 sgx_cov = { path = "../../../sgx_cov" }
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
+sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
@@ -36,6 +41,6 @@
 sgx_tstd = { path = "../../../sgx_tstd" }
 sgx_tunittest = { path = "../../../sgx_tunittest" }
 sgx_types = { path = "../../../sgx_types" }
-sgx_ucrypto = { path = "../../../sgx_ucrypto" }
+#sgx_ucrypto = { path = "../../../sgx_ucrypto" }
 sgx_unwind = { path = "../../../sgx_unwind" }
-sgx_urts = { path = "../../../sgx_urts" }
+#sgx_urts = { path = "../../../sgx_urts" }
\ No newline at end of file
diff --git a/samplecode/hello-rust/enclave/x86_64-unknown-linux-sgx.json b/samplecode/hello-rust/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/hello-rust/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/hello-rust/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/helloworld/enclave/Cargo.toml b/samplecode/helloworld/enclave/Cargo.toml
index f4f3224..c547778 100644
--- a/samplecode/helloworld/enclave/Cargo.toml
+++ b/samplecode/helloworld/enclave/Cargo.toml
@@ -15,6 +15,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -23,6 +24,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/helloworld/enclave/x86_64-unknown-linux-sgx.json b/samplecode/helloworld/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/helloworld/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/helloworld/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/http_req/Makefile b/samplecode/http_req/Makefile
index fee080a..4d150cb 100644
--- a/samplecode/http_req/Makefile
+++ b/samplecode/http_req/Makefile
@@ -1,5 +1,4 @@
 ######## SGX SDK Settings ########
-SGX_SDK_RUST ?= $(HOME)/sgx
 SGX_SDK ?= /opt/sgxsdk
 SGX_MODE ?= HW
 SGX_ARCH ?= x64
@@ -46,8 +45,8 @@
 
 CUSTOM_LIBRARY_PATH := ./lib
 CUSTOM_BIN_PATH := ./bin
-CUSTOM_EDL_PATH := $(SGX_SDK_RUST)/edl
-CUSTOM_COMMON_PATH := $(SGX_SDK_RUST)/common
+CUSTOM_EDL_PATH := ../../edl
+CUSTOM_COMMON_PATH := ../../common
 
 ######## EDL Settings ########
 
diff --git a/samplecode/http_req/enclave/Cargo.toml b/samplecode/http_req/enclave/Cargo.toml
index e0cfa8c..9cca0f1 100644
--- a/samplecode/http_req/enclave/Cargo.toml
+++ b/samplecode/http_req/enclave/Cargo.toml
@@ -16,6 +16,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git",  features = ["net"] }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -24,6 +25,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/http_req/enclave/x86_64-unknown-linux-sgx.json b/samplecode/http_req/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/http_req/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/http_req/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/hugemem/enclave/Cargo.toml b/samplecode/hugemem/enclave/Cargo.toml
index 76f7695..548a28a 100644
--- a/samplecode/hugemem/enclave/Cargo.toml
+++ b/samplecode/hugemem/enclave/Cargo.toml
@@ -15,6 +15,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -23,6 +24,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/hugemem/enclave/x86_64-unknown-linux-sgx.json b/samplecode/hugemem/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/hugemem/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/hugemem/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/kvdb-memdb/enclave/Cargo.toml b/samplecode/kvdb-memdb/enclave/Cargo.toml
index 0bc002c..2f9d9a0 100644
--- a/samplecode/kvdb-memdb/enclave/Cargo.toml
+++ b/samplecode/kvdb-memdb/enclave/Cargo.toml
@@ -20,6 +20,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -28,6 +29,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/kvdb-memdb/enclave/x86_64-unknown-linux-sgx.json b/samplecode/kvdb-memdb/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/kvdb-memdb/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/kvdb-memdb/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/localattestation/attestation/Cargo.toml b/samplecode/localattestation/attestation/Cargo.toml
index 0fe7a53..a41ecb6 100644
--- a/samplecode/localattestation/attestation/Cargo.toml
+++ b/samplecode/localattestation/attestation/Cargo.toml
@@ -14,6 +14,7 @@
 sgx_tdh = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -22,6 +23,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/localattestation/enclave1/Cargo.toml b/samplecode/localattestation/enclave1/Cargo.toml
index 9da182e..8abbd2c 100644
--- a/samplecode/localattestation/enclave1/Cargo.toml
+++ b/samplecode/localattestation/enclave1/Cargo.toml
@@ -17,6 +17,7 @@
 attestation = {path = "../attestation/"}
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -25,6 +26,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/localattestation/enclave1/Xargo.toml b/samplecode/localattestation/enclave1/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/localattestation/enclave1/Xargo.toml
+++ b/samplecode/localattestation/enclave1/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/localattestation/enclave1/x86_64-unknown-linux-sgx.json b/samplecode/localattestation/enclave1/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/localattestation/enclave1/x86_64-unknown-linux-sgx.json
+++ b/samplecode/localattestation/enclave1/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/localattestation/enclave2/Cargo.toml b/samplecode/localattestation/enclave2/Cargo.toml
index 214479d..86ca0fb 100644
--- a/samplecode/localattestation/enclave2/Cargo.toml
+++ b/samplecode/localattestation/enclave2/Cargo.toml
@@ -17,6 +17,7 @@
 attestation = {path = "../attestation/"}
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -25,6 +26,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/localattestation/enclave2/Xargo.toml b/samplecode/localattestation/enclave2/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/localattestation/enclave2/Xargo.toml
+++ b/samplecode/localattestation/enclave2/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/localattestation/enclave2/x86_64-unknown-linux-sgx.json b/samplecode/localattestation/enclave2/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/localattestation/enclave2/x86_64-unknown-linux-sgx.json
+++ b/samplecode/localattestation/enclave2/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/localattestation/enclave3/Cargo.toml b/samplecode/localattestation/enclave3/Cargo.toml
index bf9a485..e9d06b4 100644
--- a/samplecode/localattestation/enclave3/Cargo.toml
+++ b/samplecode/localattestation/enclave3/Cargo.toml
@@ -17,6 +17,7 @@
 attestation = {path = "../attestation/"}
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -25,6 +26,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/localattestation/enclave3/Xargo.toml b/samplecode/localattestation/enclave3/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/localattestation/enclave3/Xargo.toml
+++ b/samplecode/localattestation/enclave3/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/localattestation/enclave3/x86_64-unknown-linux-sgx.json b/samplecode/localattestation/enclave3/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/localattestation/enclave3/x86_64-unknown-linux-sgx.json
+++ b/samplecode/localattestation/enclave3/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/logger/enclave/Cargo.toml b/samplecode/logger/enclave/Cargo.toml
index 4c7e6a7..ab40428 100644
--- a/samplecode/logger/enclave/Cargo.toml
+++ b/samplecode/logger/enclave/Cargo.toml
@@ -19,6 +19,7 @@
 env_logger = { git = "https://github.com/mesalock-linux/env_logger-sgx" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -27,6 +28,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/logger/enclave/Xargo.toml b/samplecode/logger/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/logger/enclave/Xargo.toml
+++ b/samplecode/logger/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/logger/enclave/x86_64-unknown-linux-sgx.json b/samplecode/logger/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/logger/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/logger/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/machine-learning/enclave/Cargo.toml b/samplecode/machine-learning/enclave/Cargo.toml
index 9c9f363..d8721b9 100644
--- a/samplecode/machine-learning/enclave/Cargo.toml
+++ b/samplecode/machine-learning/enclave/Cargo.toml
@@ -10,6 +10,9 @@
 [features]
 default = []
 
+[profile.release]
+lto = true
+
 [target.'cfg(not(target_env = "sgx"))'.dependencies]
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 sgx_types = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
@@ -25,6 +28,7 @@
 serde_json    = { git = "https://github.com/mesalock-linux/serde-json-sgx" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -33,6 +37,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/machine-learning/enclave/Xargo.toml b/samplecode/machine-learning/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/machine-learning/enclave/Xargo.toml
+++ b/samplecode/machine-learning/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/machine-learning/enclave/x86_64-unknown-linux-sgx.json b/samplecode/machine-learning/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/machine-learning/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/machine-learning/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/mio/client/enclave/Cargo.toml b/samplecode/mio/client/enclave/Cargo.toml
index 6c83e90..8aa09c6 100644
--- a/samplecode/mio/client/enclave/Cargo.toml
+++ b/samplecode/mio/client/enclave/Cargo.toml
@@ -20,11 +20,16 @@
 log = { git = "https://github.com/mesalock-linux/log-sgx" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
+sgx_backtrace = { path = "../../../../sgx_backtrace" }
+sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
 sgx_build_helper = { path = "../../../../sgx_build_helper" }
 sgx_cov = { path = "../../../../sgx_cov" }
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
+sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/mio/client/enclave/Xargo.toml b/samplecode/mio/client/enclave/Xargo.toml
index 989d796..795f1f0 100644
--- a/samplecode/mio/client/enclave/Xargo.toml
+++ b/samplecode/mio/client/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/mio/client/enclave/x86_64-unknown-linux-sgx.json b/samplecode/mio/client/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/mio/client/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/mio/client/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/mio/server/enclave/Cargo.toml b/samplecode/mio/server/enclave/Cargo.toml
index a703daf..9540bee 100644
--- a/samplecode/mio/server/enclave/Cargo.toml
+++ b/samplecode/mio/server/enclave/Cargo.toml
@@ -21,6 +21,7 @@
 log = { git = "https://github.com/mesalock-linux/log-sgx" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -29,6 +30,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/mio/server/enclave/Xargo.toml b/samplecode/mio/server/enclave/Xargo.toml
index 989d796..795f1f0 100644
--- a/samplecode/mio/server/enclave/Xargo.toml
+++ b/samplecode/mio/server/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/mio/server/enclave/x86_64-unknown-linux-sgx.json b/samplecode/mio/server/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/mio/server/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/mio/server/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/mutual-ra/enclave/Cargo.toml b/samplecode/mutual-ra/enclave/Cargo.toml
index 24aece4..009732b 100644
--- a/samplecode/mutual-ra/enclave/Cargo.toml
+++ b/samplecode/mutual-ra/enclave/Cargo.toml
@@ -37,6 +37,7 @@
 features = ["dangerous_configuration"]
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -45,6 +46,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/mutual-ra/enclave/Xargo.toml b/samplecode/mutual-ra/enclave/Xargo.toml
index 333a007..ec653df 100644
--- a/samplecode/mutual-ra/enclave/Xargo.toml
+++ b/samplecode/mutual-ra/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/mutual-ra/enclave/x86_64-unknown-linux-sgx.json b/samplecode/mutual-ra/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/mutual-ra/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/mutual-ra/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/net2/enclave/Cargo.toml b/samplecode/net2/enclave/Cargo.toml
index 5b89b2a..07e8b33 100644
--- a/samplecode/net2/enclave/Cargo.toml
+++ b/samplecode/net2/enclave/Cargo.toml
@@ -18,6 +18,7 @@
 sgx_types = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -26,6 +27,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/net2/enclave/Xargo.toml b/samplecode/net2/enclave/Xargo.toml
index 80745aa..26fd2ce 100644
--- a/samplecode/net2/enclave/Xargo.toml
+++ b/samplecode/net2/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/net2/enclave/x86_64-unknown-linux-sgx.json b/samplecode/net2/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/net2/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/net2/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/pcl/encrypted-hello/enclave/Cargo.toml b/samplecode/pcl/encrypted-hello/enclave/Cargo.toml
index abe33c0..9ab56c7 100644
--- a/samplecode/pcl/encrypted-hello/enclave/Cargo.toml
+++ b/samplecode/pcl/encrypted-hello/enclave/Cargo.toml
@@ -15,11 +15,16 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
+sgx_backtrace = { path = "../../../../sgx_backtrace" }
+sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
 sgx_build_helper = { path = "../../../../sgx_build_helper" }
 sgx_cov = { path = "../../../../sgx_cov" }
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
+sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
@@ -36,6 +41,6 @@
 sgx_tstd = { path = "../../../../sgx_tstd" }
 sgx_tunittest = { path = "../../../../sgx_tunittest" }
 sgx_types = { path = "../../../../sgx_types" }
-sgx_ucrypto = { path = "../../../../sgx_ucrypto" }
+#sgx_ucrypto = { path = "../../../../sgx_ucrypto" }
 sgx_unwind = { path = "../../../../sgx_unwind" }
-sgx_urts = { path = "../../../../sgx_urts" }
+#sgx_urts = { path = "../../../../sgx_urts" }
diff --git a/samplecode/pcl/encrypted-hello/enclave/Xargo.toml b/samplecode/pcl/encrypted-hello/enclave/Xargo.toml
index 29ccfac..c578b6c 100644
--- a/samplecode/pcl/encrypted-hello/enclave/Xargo.toml
+++ b/samplecode/pcl/encrypted-hello/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/pcl/encrypted-hello/enclave/x86_64-unknown-linux-sgx.json b/samplecode/pcl/encrypted-hello/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/pcl/encrypted-hello/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/pcl/encrypted-hello/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/pcl/pcl-seal/enclave/Cargo.toml b/samplecode/pcl/pcl-seal/enclave/Cargo.toml
index 57127e8..1b85d0a 100644
--- a/samplecode/pcl/pcl-seal/enclave/Cargo.toml
+++ b/samplecode/pcl/pcl-seal/enclave/Cargo.toml
@@ -32,11 +32,16 @@
 ue_send_recv    = { path = "ue_send_recv" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
+sgx_backtrace = { path = "../../../../sgx_backtrace" }
+sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
 sgx_build_helper = { path = "../../../../sgx_build_helper" }
 sgx_cov = { path = "../../../../sgx_cov" }
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
+sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
@@ -53,6 +58,6 @@
 sgx_tstd = { path = "../../../../sgx_tstd" }
 sgx_tunittest = { path = "../../../../sgx_tunittest" }
 sgx_types = { path = "../../../../sgx_types" }
-sgx_ucrypto = { path = "../../../../sgx_ucrypto" }
+#sgx_ucrypto = { path = "../../../../sgx_ucrypto" }
 sgx_unwind = { path = "../../../../sgx_unwind" }
-sgx_urts = { path = "../../../../sgx_urts" }
+#sgx_urts = { path = "../../../../sgx_urts" }
diff --git a/samplecode/pcl/pcl-seal/enclave/Xargo.toml b/samplecode/pcl/pcl-seal/enclave/Xargo.toml
index 989d796..795f1f0 100644
--- a/samplecode/pcl/pcl-seal/enclave/Xargo.toml
+++ b/samplecode/pcl/pcl-seal/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/pcl/pcl-seal/enclave/ue_send_recv/Cargo.toml b/samplecode/pcl/pcl-seal/enclave/ue_send_recv/Cargo.toml
index 4313441..0bc6a3e 100644
--- a/samplecode/pcl/pcl-seal/enclave/ue_send_recv/Cargo.toml
+++ b/samplecode/pcl/pcl-seal/enclave/ue_send_recv/Cargo.toml
@@ -20,11 +20,16 @@
 sgx_tstd    = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../../sgx_alloc" }
+sgx_backtrace = { path = "../../../../../sgx_backtrace" }
+sgx_backtrace_sys = { path = "../../../../../sgx_backtrace_sys" }
 sgx_build_helper = { path = "../../../../../sgx_build_helper" }
 sgx_cov = { path = "../../../../../sgx_cov" }
 sgx_crypto_helper = { path = "../../../../../sgx_crypto_helper" }
+sgx_demangle = { path = "../../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../../sgx_serialize" }
@@ -41,6 +46,6 @@
 sgx_tstd = { path = "../../../../../sgx_tstd" }
 sgx_tunittest = { path = "../../../../../sgx_tunittest" }
 sgx_types = { path = "../../../../../sgx_types" }
-sgx_ucrypto = { path = "../../../../../sgx_ucrypto" }
+#sgx_ucrypto = { path = "../../../../../sgx_ucrypto" }
 sgx_unwind = { path = "../../../../../sgx_unwind" }
-sgx_urts = { path = "../../../../../sgx_urts" }
+#sgx_urts = { path = "../../../../../sgx_urts" }
diff --git a/samplecode/pcl/pcl-seal/enclave/x86_64-unknown-linux-sgx.json b/samplecode/pcl/pcl-seal/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/pcl/pcl-seal/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/pcl/pcl-seal/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/project_template/app/rust-toolchain b/samplecode/project_template/app/rust-toolchain
index e966e30..4e7e21b 100644
--- a/samplecode/project_template/app/rust-toolchain
+++ b/samplecode/project_template/app/rust-toolchain
@@ -1 +1 @@
-nightly-2020-10-25
\ No newline at end of file
+nightly-2022-02-23
\ No newline at end of file
diff --git a/samplecode/project_template/enclave/rust-toolchain b/samplecode/project_template/enclave/rust-toolchain
index e966e30..4e7e21b 100644
--- a/samplecode/project_template/enclave/rust-toolchain
+++ b/samplecode/project_template/enclave/rust-toolchain
@@ -1 +1 @@
-nightly-2020-10-25
\ No newline at end of file
+nightly-2022-02-23
\ No newline at end of file
diff --git a/samplecode/prost-protobuf/enclave/Cargo.toml b/samplecode/prost-protobuf/enclave/Cargo.toml
index 120ec2c..ef0d256 100644
--- a/samplecode/prost-protobuf/enclave/Cargo.toml
+++ b/samplecode/prost-protobuf/enclave/Cargo.toml
@@ -23,11 +23,16 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
+sgx_backtrace = { path = "../../../sgx_backtrace" }
+sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
 sgx_build_helper = { path = "../../../sgx_build_helper" }
 sgx_cov = { path = "../../../sgx_cov" }
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
+sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/prost-protobuf/enclave/x86_64-unknown-linux-sgx.json b/samplecode/prost-protobuf/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/prost-protobuf/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/prost-protobuf/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/protobuf/enclave/Cargo.toml b/samplecode/protobuf/enclave/Cargo.toml
index e78579d..e31301c 100644
--- a/samplecode/protobuf/enclave/Cargo.toml
+++ b/samplecode/protobuf/enclave/Cargo.toml
@@ -18,6 +18,7 @@
 protobuf = { git = "https://github.com/mesalock-linux/rust-protobuf-sgx", branch = "v2.8" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -26,6 +27,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/protobuf/enclave/Xargo.toml b/samplecode/protobuf/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/protobuf/enclave/Xargo.toml
+++ b/samplecode/protobuf/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/protobuf/enclave/x86_64-unknown-linux-sgx.json b/samplecode/protobuf/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/protobuf/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/protobuf/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/psi/SMCServer/enclave/Cargo.toml b/samplecode/psi/SMCServer/enclave/Cargo.toml
index b6e7db2..d00ec7e 100644
--- a/samplecode/psi/SMCServer/enclave/Cargo.toml
+++ b/samplecode/psi/SMCServer/enclave/Cargo.toml
@@ -20,6 +20,7 @@
 sgx_rand = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -28,6 +29,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/psi/SMCServer/enclave/Xargo.toml b/samplecode/psi/SMCServer/enclave/Xargo.toml
index 29ccfac..c578b6c 100644
--- a/samplecode/psi/SMCServer/enclave/Xargo.toml
+++ b/samplecode/psi/SMCServer/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/psi/SMCServer/enclave/x86_64-unknown-linux-sgx.json b/samplecode/psi/SMCServer/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/psi/SMCServer/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/psi/SMCServer/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/remoteattestation/Application/Makefile b/samplecode/remoteattestation/Application/Makefile
index 57708fa..14f869a 100644
--- a/samplecode/remoteattestation/Application/Makefile
+++ b/samplecode/remoteattestation/Application/Makefile
@@ -17,7 +17,7 @@
 
 ######## SGX SDK Settings ########
 SGX_SDK ?= /opt/sgxsdk
-SGX_MODE = HW
+SGX_MODE ?= HW
 SGX_ARCH = x64
 SGX_PRERELEASE=1
 
diff --git a/samplecode/remoteattestation/Application/enclave/Cargo.toml b/samplecode/remoteattestation/Application/enclave/Cargo.toml
index 6d15c8a..c71fdcf 100644
--- a/samplecode/remoteattestation/Application/enclave/Cargo.toml
+++ b/samplecode/remoteattestation/Application/enclave/Cargo.toml
@@ -19,6 +19,7 @@
 sgx_tkey_exchange = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -27,6 +28,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/remoteattestation/Application/enclave/Xargo.toml b/samplecode/remoteattestation/Application/enclave/Xargo.toml
index 29ccfac..c578b6c 100644
--- a/samplecode/remoteattestation/Application/enclave/Xargo.toml
+++ b/samplecode/remoteattestation/Application/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/remoteattestation/Application/enclave/src/lib.rs b/samplecode/remoteattestation/Application/enclave/src/lib.rs
index 7c9f8b6..f9553bf 100644
--- a/samplecode/remoteattestation/Application/enclave/src/lib.rs
+++ b/samplecode/remoteattestation/Application/enclave/src/lib.rs
@@ -17,78 +17,71 @@
 
 #![crate_name = "raenclave"]
 #![crate_type = "staticlib"]
-
 #![cfg_attr(not(target_env = "sgx"), no_std)]
 #![cfg_attr(target_env = "sgx", feature(rustc_private))]
-
 #![allow(unused_variables)]
 
-extern crate sgx_types;
 extern crate sgx_trts;
+extern crate sgx_types;
 #[cfg(not(target_env = "sgx"))]
 #[macro_use]
 extern crate sgx_tstd as std;
-extern crate sgx_tdh;
 extern crate sgx_tcrypto;
+extern crate sgx_tdh;
 extern crate sgx_tkey_exchange;
 
-use sgx_types::*;
-use sgx_trts::memeq::ConsttimeMemEq;
 use sgx_tcrypto::*;
 use sgx_tkey_exchange::*;
+use sgx_trts::memeq::ConsttimeMemEq;
+use sgx_types::*;
 use std::slice;
 use std::vec::Vec;
 
-const G_SP_PUB_KEY : sgx_ec256_public_t = sgx_ec256_public_t {
-    gx : [0x72, 0x12, 0x8a, 0x7a, 0x17, 0x52, 0x6e, 0xbf,
-          0x85, 0xd0, 0x3a, 0x62, 0x37, 0x30, 0xae, 0xad,
-          0x3e, 0x3d, 0xaa, 0xee, 0x9c, 0x60, 0x73, 0x1d,
-          0xb0, 0x5b, 0xe8, 0x62, 0x1c, 0x4b, 0xeb, 0x38],
-    gy : [0xd4, 0x81, 0x40, 0xd9, 0x50, 0xe2, 0x57, 0x7b,
-          0x26, 0xee, 0xb7, 0x41, 0xe7, 0xc6, 0x14, 0xe2,
-          0x24, 0xb7, 0xbd, 0xc9, 0x03, 0xf2, 0x9a, 0x28,
-          0xa8, 0x3c, 0xc8, 0x10, 0x11, 0x14, 0x5e, 0x06]
+const G_SP_PUB_KEY: sgx_ec256_public_t = sgx_ec256_public_t {
+    gx: [
+        0x72, 0x12, 0x8a, 0x7a, 0x17, 0x52, 0x6e, 0xbf, 0x85, 0xd0, 0x3a, 0x62, 0x37, 0x30, 0xae,
+        0xad, 0x3e, 0x3d, 0xaa, 0xee, 0x9c, 0x60, 0x73, 0x1d, 0xb0, 0x5b, 0xe8, 0x62, 0x1c, 0x4b,
+        0xeb, 0x38,
+    ],
+    gy: [
+        0xd4, 0x81, 0x40, 0xd9, 0x50, 0xe2, 0x57, 0x7b, 0x26, 0xee, 0xb7, 0x41, 0xe7, 0xc6, 0x14,
+        0xe2, 0x24, 0xb7, 0xbd, 0xc9, 0x03, 0xf2, 0x9a, 0x28, 0xa8, 0x3c, 0xc8, 0x10, 0x11, 0x14,
+        0x5e, 0x06,
+    ],
 };
 
 #[no_mangle]
-pub extern "C"
-fn enclave_init_ra(b_pse: i32, p_context: &mut sgx_ra_context_t) -> sgx_status_t {
-    let mut ret: sgx_status_t = sgx_status_t::SGX_SUCCESS;
+pub extern "C" fn enclave_init_ra(b_pse: i32, p_context: &mut sgx_ra_context_t) -> sgx_status_t {
     match rsgx_ra_init(&G_SP_PUB_KEY, b_pse) {
         Ok(p) => {
             *p_context = p;
-            ret = sgx_status_t::SGX_SUCCESS;
-        },
-        Err(x) => {
-            ret = x;
-            return ret;
+            sgx_status_t::SGX_SUCCESS
         }
+        Err(x) => x,
     }
-    ret
 }
 
 #[no_mangle]
-pub extern "C"
-fn enclave_ra_close(context: sgx_ra_context_t) -> sgx_status_t {
+pub extern "C" fn enclave_ra_close(context: sgx_ra_context_t) -> sgx_status_t {
     match rsgx_ra_close(context) {
         Ok(()) => sgx_status_t::SGX_SUCCESS,
-        Err(x) => x
+        Err(x) => x,
     }
 }
 
 #[no_mangle]
-pub extern "C"
-fn verify_att_result_mac(context : sgx_ra_context_t,
-                         message : * const u8,
-                         msg_size: size_t,
-                         mac     : * const u8,
-                         mac_size: size_t) -> sgx_status_t {
-
-    let ret:sgx_status_t;
-    let mk_key:sgx_ec_key_128bit_t;
+pub extern "C" fn verify_att_result_mac(
+    context: sgx_ra_context_t,
+    message: *const u8,
+    msg_size: size_t,
+    mac: *const u8,
+    mac_size: size_t,
+) -> sgx_status_t {
+    let ret: sgx_status_t;
+    let mk_key: sgx_ec_key_128bit_t;
     let mac_slice;
     let message_slice;
-    let mac_result:sgx_cmac_128bit_tag_t;
+    let mac_result: sgx_cmac_128bit_tag_t;
 
     if mac_size != SGX_MAC_SIZE || msg_size > u32::max_value as usize {
         ret = sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
@@ -100,20 +93,19 @@
         message_slice = slice::from_raw_parts(message, msg_size as usize);
     }
 
-    if mac_slice.len() != SGX_MAC_SIZE as usize  ||
-       message_slice.len() != msg_size as usize {
+    if mac_slice.len() != SGX_MAC_SIZE as usize || message_slice.len() != msg_size as usize {
         ret = sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
         return ret;
     }
 
     match rsgx_ra_get_keys(context, sgx_ra_key_type_t::SGX_RA_KEY_MK) {
         Ok(k) => mk_key = k,
-        Err(x) => return x
+        Err(x) => return x,
     }
 
     match rsgx_rijndael128_cmac_slice(&mk_key, message_slice) {
         Ok(tag) => mac_result = tag,
-        Err(x) => return x
+        Err(x) => return x,
     }
 
     if mac_slice.consttime_memeq(&mac_result) == false {
@@ -124,25 +116,23 @@
 }
 
 #[no_mangle]
-pub extern "C"
-fn verify_secret_data(context : sgx_ra_context_t,
-                      p_secret: * const u8,
-                      sec_size: u32,
-                      gcm_mac : &[u8;16],
-                      max_vlen: u32,
-                      p_ret   : & mut [u8;16]) -> sgx_status_t {
-
-    let ret:sgx_status_t;
-    let sk_key:sgx_ec_key_128bit_t;
+pub extern "C" fn verify_secret_data(
+    context: sgx_ra_context_t,
+    p_secret: *const u8,
+    sec_size: u32,
+    gcm_mac: &[u8; 16],
+    max_vlen: u32,
+    p_ret: &mut [u8; 16],
+) -> sgx_status_t {
+    let ret: sgx_status_t;
+    let sk_key: sgx_ec_key_128bit_t;
 
     match rsgx_ra_get_keys(context, sgx_ra_key_type_t::SGX_RA_KEY_SK) {
         Ok(key) => sk_key = key,
-        Err(x) => return x
+        Err(x) => return x,
     }
 
-    let secret_slice = unsafe {
-        slice::from_raw_parts(p_secret, sec_size as usize)
-    };
+    let secret_slice = unsafe { slice::from_raw_parts(p_secret, sec_size as usize) };
 
     if secret_slice.len() != sec_size as usize {
         ret = sgx_status_t::SGX_ERROR_INVALID_PARAMETER;
@@ -151,27 +141,22 @@
 
     let mut decrypted_vec: Vec<u8> = vec![0; sec_size as usize];
     let decrypted_slice = &mut decrypted_vec[..];
-    let iv = [0;12];
-    let aad:[u8;0] = [0;0];
+    let iv = [0; 12];
+    let aad: [u8; 0] = [0; 0];
 
-    let ret = rsgx_rijndael128GCM_decrypt(&sk_key,
-                                          &secret_slice,
-                                          &iv,
-                                          &aad,
-                                          gcm_mac,
-                                          decrypted_slice);
+    let ret =
+        rsgx_rijndael128GCM_decrypt(&sk_key, &secret_slice, &iv, &aad, gcm_mac, decrypted_slice);
 
     match ret {
         Ok(()) => {
             if decrypted_slice[0] == 0 && decrypted_slice[1] != 1 {
-                return sgx_status_t::SGX_ERROR_INVALID_SIGNATURE;
+                sgx_status_t::SGX_ERROR_INVALID_SIGNATURE
+            } else {
+                sgx_status_t::SGX_SUCCESS
             }
-            else {
-                return sgx_status_t::SGX_SUCCESS;
-            }
-        },
+        }
         Err(_) => {
-            return sgx_status_t::SGX_ERROR_UNEXPECTED;
+            sgx_status_t::SGX_ERROR_UNEXPECTED
         }
     }
 }
diff --git a/samplecode/remoteattestation/Application/enclave/x86_64-unknown-linux-sgx.json b/samplecode/remoteattestation/Application/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/remoteattestation/Application/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/remoteattestation/Application/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/remoteattestation/GoogleMessages/Messages.pb.cc b/samplecode/remoteattestation/GoogleMessages/Messages.pb.cc
index c7ecd42..147dc4f 100644
--- a/samplecode/remoteattestation/GoogleMessages/Messages.pb.cc
+++ b/samplecode/remoteattestation/GoogleMessages/Messages.pb.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -38,13 +39,11 @@
 const ::google::protobuf::Descriptor* AttestationMessage_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   AttestationMessage_reflection_ = NULL;
-const ::google::protobuf::Descriptor* SecretMessage_descriptor_ = NULL;
-const ::google::protobuf::internal::GeneratedMessageReflection*
-  SecretMessage_reflection_ = NULL;
 
 }  // namespace
 
 
+void protobuf_AssignDesc_Messages_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_Messages_2eproto() {
   protobuf_AddDesc_Messages_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -57,16 +56,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InitialMessage, size_),
   };
   InitialMessage_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       InitialMessage_descriptor_,
       InitialMessage::default_instance_,
       InitialMessage_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InitialMessage, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InitialMessage, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(InitialMessage));
+      -1,
+      sizeof(InitialMessage),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InitialMessage, _internal_metadata_),
+      -1);
   MessageMsg0_descriptor_ = file->message_type(1);
   static const int MessageMsg0_offsets_[3] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMsg0, type_),
@@ -74,16 +73,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMsg0, status_),
   };
   MessageMsg0_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       MessageMsg0_descriptor_,
       MessageMsg0::default_instance_,
       MessageMsg0_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMsg0, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMsg0, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(MessageMsg0));
+      -1,
+      sizeof(MessageMsg0),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMsg0, _internal_metadata_),
+      -1);
   MessageMSG1_descriptor_ = file->message_type(2);
   static const int MessageMSG1_offsets_[4] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG1, type_),
@@ -92,16 +91,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG1, gid_),
   };
   MessageMSG1_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       MessageMSG1_descriptor_,
       MessageMSG1::default_instance_,
       MessageMSG1_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG1, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG1, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(MessageMSG1));
+      -1,
+      sizeof(MessageMSG1),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG1, _internal_metadata_),
+      -1);
   MessageMSG2_descriptor_ = file->message_type(3);
   static const int MessageMSG2_offsets_[12] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG2, type_),
@@ -118,16 +117,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG2, sigrl_),
   };
   MessageMSG2_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       MessageMSG2_descriptor_,
       MessageMSG2::default_instance_,
       MessageMSG2_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG2, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG2, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(MessageMSG2));
+      -1,
+      sizeof(MessageMSG2),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG2, _internal_metadata_),
+      -1);
   MessageMSG3_descriptor_ = file->message_type(4);
   static const int MessageMSG3_offsets_[7] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG3, type_),
@@ -139,16 +138,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG3, quote_),
   };
   MessageMSG3_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       MessageMSG3_descriptor_,
       MessageMSG3::default_instance_,
       MessageMSG3_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG3, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG3, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(MessageMSG3));
+      -1,
+      sizeof(MessageMSG3),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageMSG3, _internal_metadata_),
+      -1);
   AttestationMessage_descriptor_ = file->message_type(5);
   static const int AttestationMessage_offsets_[16] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttestationMessage, type_),
@@ -169,40 +168,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttestationMessage, payload_),
   };
   AttestationMessage_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       AttestationMessage_descriptor_,
       AttestationMessage::default_instance_,
       AttestationMessage_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttestationMessage, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttestationMessage, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(AttestationMessage));
-  SecretMessage_descriptor_ = file->message_type(6);
-  static const int SecretMessage_offsets_[10] = {
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, type_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, size_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, encryped_pkey_size_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, encryped_x509_size_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, encrypted_content_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, mac_smk_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, encrypted_pkey_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, encrypted_pkey_mac_smk_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, encrypted_x509_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, encrypted_x509_mac_smk_),
-  };
-  SecretMessage_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
-      SecretMessage_descriptor_,
-      SecretMessage::default_instance_,
-      SecretMessage_offsets_,
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SecretMessage, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(SecretMessage));
+      sizeof(AttestationMessage),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttestationMessage, _internal_metadata_),
+      -1);
 }
 
 namespace {
@@ -213,22 +188,21 @@
                  &protobuf_AssignDesc_Messages_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    InitialMessage_descriptor_, &InitialMessage::default_instance());
+      InitialMessage_descriptor_, &InitialMessage::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    MessageMsg0_descriptor_, &MessageMsg0::default_instance());
+      MessageMsg0_descriptor_, &MessageMsg0::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    MessageMSG1_descriptor_, &MessageMSG1::default_instance());
+      MessageMSG1_descriptor_, &MessageMSG1::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    MessageMSG2_descriptor_, &MessageMSG2::default_instance());
+      MessageMSG2_descriptor_, &MessageMSG2::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    MessageMSG3_descriptor_, &MessageMSG3::default_instance());
+      MessageMSG3_descriptor_, &MessageMSG3::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    AttestationMessage_descriptor_, &AttestationMessage::default_instance());
-  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    SecretMessage_descriptor_, &SecretMessage::default_instance());
+      AttestationMessage_descriptor_, &AttestationMessage::default_instance());
 }
 
 }  // namespace
@@ -246,10 +220,9 @@
   delete MessageMSG3_reflection_;
   delete AttestationMessage::default_instance_;
   delete AttestationMessage_reflection_;
-  delete SecretMessage::default_instance_;
-  delete SecretMessage_reflection_;
 }
 
+void protobuf_AddDesc_Messages_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_Messages_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -283,14 +256,7 @@
     "\030\n \003(\rB\002\020\001\022\030\n\014ec_sign256_y\030\013 \003(\rB\002\020\001\022\023\n\007"
     "mac_smk\030\014 \003(\rB\002\020\001\022\023\n\013result_size\030\r \001(\r\022\024"
     "\n\010reserved\030\016 \003(\rB\002\020\001\022\027\n\013payload_tag\030\017 \003("
-    "\rB\002\020\001\022\023\n\007payload\030\020 \003(\rB\002\020\001\"\227\002\n\rSecretMes"
-    "sage\022\014\n\004type\030\001 \002(\r\022\014\n\004size\030\002 \002(\r\022\032\n\022encr"
-    "yped_pkey_size\030\003 \001(\r\022\032\n\022encryped_x509_si"
-    "ze\030\004 \001(\r\022\035\n\021encrypted_content\030\005 \003(\rB\002\020\001\022"
-    "\023\n\007mac_smk\030\006 \003(\rB\002\020\001\022\032\n\016encrypted_pkey\030\007"
-    " \003(\rB\002\020\001\022\"\n\026encrypted_pkey_mac_smk\030\010 \003(\r"
-    "B\002\020\001\022\032\n\016encrypted_x509\030\t \003(\rB\002\020\001\022\"\n\026encr"
-    "ypted_x509_mac_smk\030\n \003(\rB\002\020\001", 1348);
+    "\rB\002\020\001\022\023\n\007payload\030\020 \003(\rB\002\020\001", 1066);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "Messages.proto", &protobuf_RegisterTypes);
   InitialMessage::default_instance_ = new InitialMessage();
@@ -299,14 +265,12 @@
   MessageMSG2::default_instance_ = new MessageMSG2();
   MessageMSG3::default_instance_ = new MessageMSG3();
   AttestationMessage::default_instance_ = new AttestationMessage();
-  SecretMessage::default_instance_ = new SecretMessage();
   InitialMessage::default_instance_->InitAsDefaultInstance();
   MessageMsg0::default_instance_->InitAsDefaultInstance();
   MessageMSG1::default_instance_->InitAsDefaultInstance();
   MessageMSG2::default_instance_->InitAsDefaultInstance();
   MessageMSG3::default_instance_->InitAsDefaultInstance();
   AttestationMessage::default_instance_->InitAsDefaultInstance();
-  SecretMessage::default_instance_->InitAsDefaultInstance();
   ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_Messages_2eproto);
 }
 
@@ -319,13 +283,13 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int InitialMessage::kTypeFieldNumber;
 const int InitialMessage::kSizeFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 InitialMessage::InitialMessage()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:Messages.InitialMessage)
 }
@@ -334,7 +298,8 @@
 }
 
 InitialMessage::InitialMessage(const InitialMessage& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:Messages.InitialMessage)
@@ -374,33 +339,46 @@
 
 InitialMessage* InitialMessage::default_instance_ = NULL;
 
-InitialMessage* InitialMessage::New() const {
-  return new InitialMessage;
+InitialMessage* InitialMessage::New(::google::protobuf::Arena* arena) const {
+  InitialMessage* n = new InitialMessage;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void InitialMessage::Clear() {
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<InitialMessage*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+// @@protoc_insertion_point(message_clear_start:Messages.InitialMessage)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(InitialMessage, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<InitialMessage*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&first, 0, n);                                \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
   ZR_(type_, size_);
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool InitialMessage::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:Messages.InitialMessage)
   for (;;) {
@@ -472,15 +450,15 @@
     ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->size(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
   // @@protoc_insertion_point(serialize_end:Messages.InitialMessage)
 }
 
-::google::protobuf::uint8* InitialMessage::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* InitialMessage::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:Messages.InitialMessage)
   // required uint32 type = 1;
   if (has_type()) {
@@ -492,7 +470,7 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->size(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -501,25 +479,23 @@
 }
 
 int InitialMessage::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:Messages.InitialMessage)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // required uint32 type = 1;
-    if (has_type()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->type());
-    }
-
-    // optional uint32 size = 2;
-    if (has_size()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->size());
-    }
-
+  // required uint32 type = 1;
+  if (has_type()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->type());
   }
-  if (!unknown_fields().empty()) {
+  // optional uint32 size = 2;
+  if (has_size()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->size());
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -531,19 +507,27 @@
 }
 
 void InitialMessage::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const InitialMessage* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const InitialMessage*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:Messages.InitialMessage)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
+  const InitialMessage* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const InitialMessage>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Messages.InitialMessage)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Messages.InitialMessage)
     MergeFrom(*source);
   }
 }
 
 void InitialMessage::MergeFrom(const InitialMessage& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:Messages.InitialMessage)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_type()) {
       set_type(from.type());
@@ -552,16 +536,20 @@
       set_size(from.size());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void InitialMessage::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Messages.InitialMessage)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void InitialMessage::CopyFrom(const InitialMessage& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Messages.InitialMessage)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -574,13 +562,15 @@
 }
 
 void InitialMessage::Swap(InitialMessage* other) {
-  if (other != this) {
-    std::swap(type_, other->type_);
-    std::swap(size_, other->size_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void InitialMessage::InternalSwap(InitialMessage* other) {
+  std::swap(type_, other->type_);
+  std::swap(size_, other->size_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata InitialMessage::GetMetadata() const {
@@ -591,17 +581,69 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// InitialMessage
+
+// required uint32 type = 1;
+bool InitialMessage::has_type() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void InitialMessage::set_has_type() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void InitialMessage::clear_has_type() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void InitialMessage::clear_type() {
+  type_ = 0u;
+  clear_has_type();
+}
+ ::google::protobuf::uint32 InitialMessage::type() const {
+  // @@protoc_insertion_point(field_get:Messages.InitialMessage.type)
+  return type_;
+}
+ void InitialMessage::set_type(::google::protobuf::uint32 value) {
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:Messages.InitialMessage.type)
+}
+
+// optional uint32 size = 2;
+bool InitialMessage::has_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void InitialMessage::set_has_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void InitialMessage::clear_has_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void InitialMessage::clear_size() {
+  size_ = 0u;
+  clear_has_size();
+}
+ ::google::protobuf::uint32 InitialMessage::size() const {
+  // @@protoc_insertion_point(field_get:Messages.InitialMessage.size)
+  return size_;
+}
+ void InitialMessage::set_size(::google::protobuf::uint32 value) {
+  set_has_size();
+  size_ = value;
+  // @@protoc_insertion_point(field_set:Messages.InitialMessage.size)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MessageMsg0::kTypeFieldNumber;
 const int MessageMsg0::kEpidFieldNumber;
 const int MessageMsg0::kStatusFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MessageMsg0::MessageMsg0()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:Messages.MessageMsg0)
 }
@@ -610,7 +652,8 @@
 }
 
 MessageMsg0::MessageMsg0(const MessageMsg0& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:Messages.MessageMsg0)
@@ -651,33 +694,46 @@
 
 MessageMsg0* MessageMsg0::default_instance_ = NULL;
 
-MessageMsg0* MessageMsg0::New() const {
-  return new MessageMsg0;
+MessageMsg0* MessageMsg0::New(::google::protobuf::Arena* arena) const {
+  MessageMsg0* n = new MessageMsg0;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void MessageMsg0::Clear() {
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<MessageMsg0*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+// @@protoc_insertion_point(message_clear_start:Messages.MessageMsg0)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(MessageMsg0, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<MessageMsg0*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&first, 0, n);                                \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
   ZR_(type_, status_);
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool MessageMsg0::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:Messages.MessageMsg0)
   for (;;) {
@@ -769,15 +825,15 @@
     ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->status(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
   // @@protoc_insertion_point(serialize_end:Messages.MessageMsg0)
 }
 
-::google::protobuf::uint8* MessageMsg0::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MessageMsg0::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:Messages.MessageMsg0)
   // required uint32 type = 1;
   if (has_type()) {
@@ -794,7 +850,7 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->status(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -802,33 +858,52 @@
   return target;
 }
 
-int MessageMsg0::ByteSize() const {
+int MessageMsg0::RequiredFieldsByteSizeFallback() const {
+// @@protoc_insertion_point(required_fields_byte_size_fallback_start:Messages.MessageMsg0)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (has_type()) {
     // required uint32 type = 1;
-    if (has_type()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->type());
-    }
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->type());
+  }
+
+  if (has_epid()) {
+    // required uint32 epid = 2;
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->epid());
+  }
+
+  return total_size;
+}
+int MessageMsg0::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:Messages.MessageMsg0)
+  int total_size = 0;
+
+  if (((_has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) {  // All required fields are present.
+    // required uint32 type = 1;
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->type());
 
     // required uint32 epid = 2;
-    if (has_epid()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->epid());
-    }
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->epid());
 
-    // optional uint32 status = 3;
-    if (has_status()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->status());
-    }
-
+  } else {
+    total_size += RequiredFieldsByteSizeFallback();
   }
-  if (!unknown_fields().empty()) {
+  // optional uint32 status = 3;
+  if (has_status()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->status());
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -840,19 +915,27 @@
 }
 
 void MessageMsg0::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const MessageMsg0* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MessageMsg0*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:Messages.MessageMsg0)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
+  const MessageMsg0* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MessageMsg0>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Messages.MessageMsg0)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Messages.MessageMsg0)
     MergeFrom(*source);
   }
 }
 
 void MessageMsg0::MergeFrom(const MessageMsg0& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:Messages.MessageMsg0)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_type()) {
       set_type(from.type());
@@ -864,16 +947,20 @@
       set_status(from.status());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void MessageMsg0::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Messages.MessageMsg0)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void MessageMsg0::CopyFrom(const MessageMsg0& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Messages.MessageMsg0)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -886,14 +973,16 @@
 }
 
 void MessageMsg0::Swap(MessageMsg0* other) {
-  if (other != this) {
-    std::swap(type_, other->type_);
-    std::swap(epid_, other->epid_);
-    std::swap(status_, other->status_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MessageMsg0::InternalSwap(MessageMsg0* other) {
+  std::swap(type_, other->type_);
+  std::swap(epid_, other->epid_);
+  std::swap(status_, other->status_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata MessageMsg0::GetMetadata() const {
@@ -904,18 +993,94 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MessageMsg0
+
+// required uint32 type = 1;
+bool MessageMsg0::has_type() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MessageMsg0::set_has_type() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MessageMsg0::clear_has_type() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MessageMsg0::clear_type() {
+  type_ = 0u;
+  clear_has_type();
+}
+ ::google::protobuf::uint32 MessageMsg0::type() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMsg0.type)
+  return type_;
+}
+ void MessageMsg0::set_type(::google::protobuf::uint32 value) {
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMsg0.type)
+}
+
+// required uint32 epid = 2;
+bool MessageMsg0::has_epid() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void MessageMsg0::set_has_epid() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void MessageMsg0::clear_has_epid() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void MessageMsg0::clear_epid() {
+  epid_ = 0u;
+  clear_has_epid();
+}
+ ::google::protobuf::uint32 MessageMsg0::epid() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMsg0.epid)
+  return epid_;
+}
+ void MessageMsg0::set_epid(::google::protobuf::uint32 value) {
+  set_has_epid();
+  epid_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMsg0.epid)
+}
+
+// optional uint32 status = 3;
+bool MessageMsg0::has_status() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void MessageMsg0::set_has_status() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void MessageMsg0::clear_has_status() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void MessageMsg0::clear_status() {
+  status_ = 0u;
+  clear_has_status();
+}
+ ::google::protobuf::uint32 MessageMsg0::status() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMsg0.status)
+  return status_;
+}
+ void MessageMsg0::set_status(::google::protobuf::uint32 value) {
+  set_has_status();
+  status_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMsg0.status)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MessageMSG1::kTypeFieldNumber;
 const int MessageMSG1::kGaXFieldNumber;
 const int MessageMSG1::kGaYFieldNumber;
 const int MessageMSG1::kGIDFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MessageMSG1::MessageMSG1()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:Messages.MessageMSG1)
 }
@@ -924,7 +1089,8 @@
 }
 
 MessageMSG1::MessageMSG1(const MessageMSG1& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:Messages.MessageMSG1)
@@ -963,22 +1129,29 @@
 
 MessageMSG1* MessageMSG1::default_instance_ = NULL;
 
-MessageMSG1* MessageMSG1::New() const {
-  return new MessageMSG1;
+MessageMSG1* MessageMSG1::New(::google::protobuf::Arena* arena) const {
+  MessageMSG1* n = new MessageMSG1;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void MessageMSG1::Clear() {
+// @@protoc_insertion_point(message_clear_start:Messages.MessageMSG1)
   type_ = 0u;
   gax_.Clear();
   gay_.Clear();
   gid_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool MessageMSG1::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:Messages.MessageMSG1)
   for (;;) {
@@ -1114,15 +1287,15 @@
       this->gid(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
   // @@protoc_insertion_point(serialize_end:Messages.MessageMSG1)
 }
 
-::google::protobuf::uint8* MessageMSG1::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MessageMSG1::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:Messages.MessageMSG1)
   // required uint32 type = 1;
   if (has_type()) {
@@ -1171,7 +1344,7 @@
       WriteUInt32NoTagToArray(this->gid(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -1180,16 +1353,14 @@
 }
 
 int MessageMSG1::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:Messages.MessageMSG1)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // required uint32 type = 1;
-    if (has_type()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->type());
-    }
-
+  // required uint32 type = 1;
+  if (has_type()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->type());
   }
   // repeated uint32 GaX = 2 [packed = true];
   {
@@ -1242,7 +1413,7 @@
     total_size += data_size;
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -1254,19 +1425,27 @@
 }
 
 void MessageMSG1::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const MessageMSG1* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MessageMSG1*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:Messages.MessageMSG1)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
+  const MessageMSG1* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MessageMSG1>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Messages.MessageMSG1)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Messages.MessageMSG1)
     MergeFrom(*source);
   }
 }
 
 void MessageMSG1::MergeFrom(const MessageMSG1& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:Messages.MessageMSG1)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   gax_.MergeFrom(from.gax_);
   gay_.MergeFrom(from.gay_);
   gid_.MergeFrom(from.gid_);
@@ -1275,16 +1454,20 @@
       set_type(from.type());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void MessageMSG1::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Messages.MessageMSG1)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void MessageMSG1::CopyFrom(const MessageMSG1& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Messages.MessageMSG1)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -1297,15 +1480,17 @@
 }
 
 void MessageMSG1::Swap(MessageMSG1* other) {
-  if (other != this) {
-    std::swap(type_, other->type_);
-    gax_.Swap(&other->gax_);
-    gay_.Swap(&other->gay_);
-    gid_.Swap(&other->gid_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MessageMSG1::InternalSwap(MessageMSG1* other) {
+  std::swap(type_, other->type_);
+  gax_.UnsafeArenaSwap(&other->gax_);
+  gay_.UnsafeArenaSwap(&other->gay_);
+  gid_.UnsafeArenaSwap(&other->gid_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata MessageMSG1::GetMetadata() const {
@@ -1316,10 +1501,128 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MessageMSG1
+
+// required uint32 type = 1;
+bool MessageMSG1::has_type() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MessageMSG1::set_has_type() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MessageMSG1::clear_has_type() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MessageMSG1::clear_type() {
+  type_ = 0u;
+  clear_has_type();
+}
+ ::google::protobuf::uint32 MessageMSG1::type() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG1.type)
+  return type_;
+}
+ void MessageMSG1::set_type(::google::protobuf::uint32 value) {
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG1.type)
+}
+
+// repeated uint32 GaX = 2 [packed = true];
+int MessageMSG1::gax_size() const {
+  return gax_.size();
+}
+void MessageMSG1::clear_gax() {
+  gax_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG1::gax(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG1.GaX)
+  return gax_.Get(index);
+}
+ void MessageMSG1::set_gax(int index, ::google::protobuf::uint32 value) {
+  gax_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG1.GaX)
+}
+ void MessageMSG1::add_gax(::google::protobuf::uint32 value) {
+  gax_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG1.GaX)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG1::gax() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG1.GaX)
+  return gax_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG1::mutable_gax() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG1.GaX)
+  return &gax_;
+}
+
+// repeated uint32 GaY = 3 [packed = true];
+int MessageMSG1::gay_size() const {
+  return gay_.size();
+}
+void MessageMSG1::clear_gay() {
+  gay_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG1::gay(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG1.GaY)
+  return gay_.Get(index);
+}
+ void MessageMSG1::set_gay(int index, ::google::protobuf::uint32 value) {
+  gay_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG1.GaY)
+}
+ void MessageMSG1::add_gay(::google::protobuf::uint32 value) {
+  gay_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG1.GaY)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG1::gay() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG1.GaY)
+  return gay_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG1::mutable_gay() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG1.GaY)
+  return &gay_;
+}
+
+// repeated uint32 GID = 4 [packed = true];
+int MessageMSG1::gid_size() const {
+  return gid_.size();
+}
+void MessageMSG1::clear_gid() {
+  gid_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG1::gid(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG1.GID)
+  return gid_.Get(index);
+}
+ void MessageMSG1::set_gid(int index, ::google::protobuf::uint32 value) {
+  gid_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG1.GID)
+}
+ void MessageMSG1::add_gid(::google::protobuf::uint32 value) {
+  gid_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG1.GID)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG1::gid() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG1.GID)
+  return gid_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG1::mutable_gid() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG1.GID)
+  return &gid_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MessageMSG2::kTypeFieldNumber;
 const int MessageMSG2::kSizeFieldNumber;
 const int MessageMSG2::kPublicKeyGxFieldNumber;
@@ -1332,10 +1635,10 @@
 const int MessageMSG2::kSmacFieldNumber;
 const int MessageMSG2::kSizeSigrlFieldNumber;
 const int MessageMSG2::kSigrlFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MessageMSG2::MessageMSG2()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:Messages.MessageMSG2)
 }
@@ -1344,7 +1647,8 @@
 }
 
 MessageMSG2::MessageMSG2(const MessageMSG2& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:Messages.MessageMSG2)
@@ -1387,26 +1691,37 @@
 
 MessageMSG2* MessageMSG2::default_instance_ = NULL;
 
-MessageMSG2* MessageMSG2::New() const {
-  return new MessageMSG2;
+MessageMSG2* MessageMSG2::New(::google::protobuf::Arena* arena) const {
+  MessageMSG2* n = new MessageMSG2;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void MessageMSG2::Clear() {
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<MessageMSG2*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+// @@protoc_insertion_point(message_clear_start:Messages.MessageMSG2)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(MessageMSG2, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<MessageMSG2*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&first, 0, n);                                \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
   ZR_(type_, size_);
   ZR_(quote_type_, cmac_kdf_id_);
   size_sigrl_ = 0u;
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   public_key_gx_.Clear();
@@ -1417,12 +1732,14 @@
   smac_.Clear();
   sigrl_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool MessageMSG2::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:Messages.MessageMSG2)
   for (;;) {
@@ -1750,15 +2067,15 @@
       this->sigrl(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
   // @@protoc_insertion_point(serialize_end:Messages.MessageMSG2)
 }
 
-::google::protobuf::uint8* MessageMSG2::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MessageMSG2::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:Messages.MessageMSG2)
   // required uint32 type = 1;
   if (has_type()) {
@@ -1883,7 +2200,7 @@
       WriteUInt32NoTagToArray(this->sigrl(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -1892,16 +2209,16 @@
 }
 
 int MessageMSG2::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:Messages.MessageMSG2)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // required uint32 type = 1;
-    if (has_type()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->type());
-    }
-
+  // required uint32 type = 1;
+  if (has_type()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->type());
+  }
+  if (_has_bits_[1 / 32] & 82u) {
     // optional uint32 size = 2;
     if (has_size()) {
       total_size += 1 +
@@ -1924,15 +2241,13 @@
     }
 
   }
-  if (_has_bits_[10 / 32] & (0xffu << (10 % 32))) {
-    // optional uint32 size_sigrl = 11;
-    if (has_size_sigrl()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->size_sigrl());
-    }
-
+  // optional uint32 size_sigrl = 11;
+  if (has_size_sigrl()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->size_sigrl());
   }
+
   // repeated uint32 public_key_gx = 3 [packed = true];
   {
     int data_size = 0;
@@ -2052,7 +2367,7 @@
     total_size += data_size;
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -2064,19 +2379,27 @@
 }
 
 void MessageMSG2::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const MessageMSG2* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MessageMSG2*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:Messages.MessageMSG2)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
+  const MessageMSG2* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MessageMSG2>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Messages.MessageMSG2)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Messages.MessageMSG2)
     MergeFrom(*source);
   }
 }
 
 void MessageMSG2::MergeFrom(const MessageMSG2& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:Messages.MessageMSG2)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   public_key_gx_.MergeFrom(from.public_key_gx_);
   public_key_gy_.MergeFrom(from.public_key_gy_);
   spid_.MergeFrom(from.spid_);
@@ -2103,16 +2426,20 @@
       set_size_sigrl(from.size_sigrl());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void MessageMSG2::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Messages.MessageMSG2)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void MessageMSG2::CopyFrom(const MessageMSG2& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Messages.MessageMSG2)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -2125,23 +2452,25 @@
 }
 
 void MessageMSG2::Swap(MessageMSG2* other) {
-  if (other != this) {
-    std::swap(type_, other->type_);
-    std::swap(size_, other->size_);
-    public_key_gx_.Swap(&other->public_key_gx_);
-    public_key_gy_.Swap(&other->public_key_gy_);
-    std::swap(quote_type_, other->quote_type_);
-    spid_.Swap(&other->spid_);
-    std::swap(cmac_kdf_id_, other->cmac_kdf_id_);
-    signature_x_.Swap(&other->signature_x_);
-    signature_y_.Swap(&other->signature_y_);
-    smac_.Swap(&other->smac_);
-    std::swap(size_sigrl_, other->size_sigrl_);
-    sigrl_.Swap(&other->sigrl_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MessageMSG2::InternalSwap(MessageMSG2* other) {
+  std::swap(type_, other->type_);
+  std::swap(size_, other->size_);
+  public_key_gx_.UnsafeArenaSwap(&other->public_key_gx_);
+  public_key_gy_.UnsafeArenaSwap(&other->public_key_gy_);
+  std::swap(quote_type_, other->quote_type_);
+  spid_.UnsafeArenaSwap(&other->spid_);
+  std::swap(cmac_kdf_id_, other->cmac_kdf_id_);
+  signature_x_.UnsafeArenaSwap(&other->signature_x_);
+  signature_y_.UnsafeArenaSwap(&other->signature_y_);
+  smac_.UnsafeArenaSwap(&other->smac_);
+  std::swap(size_sigrl_, other->size_sigrl_);
+  sigrl_.UnsafeArenaSwap(&other->sigrl_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata MessageMSG2::GetMetadata() const {
@@ -2152,10 +2481,344 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MessageMSG2
+
+// required uint32 type = 1;
+bool MessageMSG2::has_type() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MessageMSG2::set_has_type() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MessageMSG2::clear_has_type() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MessageMSG2::clear_type() {
+  type_ = 0u;
+  clear_has_type();
+}
+ ::google::protobuf::uint32 MessageMSG2::type() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.type)
+  return type_;
+}
+ void MessageMSG2::set_type(::google::protobuf::uint32 value) {
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.type)
+}
+
+// optional uint32 size = 2;
+bool MessageMSG2::has_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void MessageMSG2::set_has_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void MessageMSG2::clear_has_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void MessageMSG2::clear_size() {
+  size_ = 0u;
+  clear_has_size();
+}
+ ::google::protobuf::uint32 MessageMSG2::size() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.size)
+  return size_;
+}
+ void MessageMSG2::set_size(::google::protobuf::uint32 value) {
+  set_has_size();
+  size_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.size)
+}
+
+// repeated uint32 public_key_gx = 3 [packed = true];
+int MessageMSG2::public_key_gx_size() const {
+  return public_key_gx_.size();
+}
+void MessageMSG2::clear_public_key_gx() {
+  public_key_gx_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG2::public_key_gx(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.public_key_gx)
+  return public_key_gx_.Get(index);
+}
+ void MessageMSG2::set_public_key_gx(int index, ::google::protobuf::uint32 value) {
+  public_key_gx_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.public_key_gx)
+}
+ void MessageMSG2::add_public_key_gx(::google::protobuf::uint32 value) {
+  public_key_gx_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG2.public_key_gx)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG2::public_key_gx() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG2.public_key_gx)
+  return public_key_gx_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG2::mutable_public_key_gx() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG2.public_key_gx)
+  return &public_key_gx_;
+}
+
+// repeated uint32 public_key_gy = 4 [packed = true];
+int MessageMSG2::public_key_gy_size() const {
+  return public_key_gy_.size();
+}
+void MessageMSG2::clear_public_key_gy() {
+  public_key_gy_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG2::public_key_gy(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.public_key_gy)
+  return public_key_gy_.Get(index);
+}
+ void MessageMSG2::set_public_key_gy(int index, ::google::protobuf::uint32 value) {
+  public_key_gy_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.public_key_gy)
+}
+ void MessageMSG2::add_public_key_gy(::google::protobuf::uint32 value) {
+  public_key_gy_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG2.public_key_gy)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG2::public_key_gy() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG2.public_key_gy)
+  return public_key_gy_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG2::mutable_public_key_gy() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG2.public_key_gy)
+  return &public_key_gy_;
+}
+
+// optional uint32 quote_type = 5;
+bool MessageMSG2::has_quote_type() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void MessageMSG2::set_has_quote_type() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void MessageMSG2::clear_has_quote_type() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void MessageMSG2::clear_quote_type() {
+  quote_type_ = 0u;
+  clear_has_quote_type();
+}
+ ::google::protobuf::uint32 MessageMSG2::quote_type() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.quote_type)
+  return quote_type_;
+}
+ void MessageMSG2::set_quote_type(::google::protobuf::uint32 value) {
+  set_has_quote_type();
+  quote_type_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.quote_type)
+}
+
+// repeated uint32 spid = 6 [packed = true];
+int MessageMSG2::spid_size() const {
+  return spid_.size();
+}
+void MessageMSG2::clear_spid() {
+  spid_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG2::spid(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.spid)
+  return spid_.Get(index);
+}
+ void MessageMSG2::set_spid(int index, ::google::protobuf::uint32 value) {
+  spid_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.spid)
+}
+ void MessageMSG2::add_spid(::google::protobuf::uint32 value) {
+  spid_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG2.spid)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG2::spid() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG2.spid)
+  return spid_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG2::mutable_spid() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG2.spid)
+  return &spid_;
+}
+
+// optional uint32 cmac_kdf_id = 7;
+bool MessageMSG2::has_cmac_kdf_id() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void MessageMSG2::set_has_cmac_kdf_id() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void MessageMSG2::clear_has_cmac_kdf_id() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void MessageMSG2::clear_cmac_kdf_id() {
+  cmac_kdf_id_ = 0u;
+  clear_has_cmac_kdf_id();
+}
+ ::google::protobuf::uint32 MessageMSG2::cmac_kdf_id() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.cmac_kdf_id)
+  return cmac_kdf_id_;
+}
+ void MessageMSG2::set_cmac_kdf_id(::google::protobuf::uint32 value) {
+  set_has_cmac_kdf_id();
+  cmac_kdf_id_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.cmac_kdf_id)
+}
+
+// repeated uint32 signature_x = 8 [packed = true];
+int MessageMSG2::signature_x_size() const {
+  return signature_x_.size();
+}
+void MessageMSG2::clear_signature_x() {
+  signature_x_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG2::signature_x(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.signature_x)
+  return signature_x_.Get(index);
+}
+ void MessageMSG2::set_signature_x(int index, ::google::protobuf::uint32 value) {
+  signature_x_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.signature_x)
+}
+ void MessageMSG2::add_signature_x(::google::protobuf::uint32 value) {
+  signature_x_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG2.signature_x)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG2::signature_x() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG2.signature_x)
+  return signature_x_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG2::mutable_signature_x() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG2.signature_x)
+  return &signature_x_;
+}
+
+// repeated uint32 signature_y = 9 [packed = true];
+int MessageMSG2::signature_y_size() const {
+  return signature_y_.size();
+}
+void MessageMSG2::clear_signature_y() {
+  signature_y_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG2::signature_y(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.signature_y)
+  return signature_y_.Get(index);
+}
+ void MessageMSG2::set_signature_y(int index, ::google::protobuf::uint32 value) {
+  signature_y_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.signature_y)
+}
+ void MessageMSG2::add_signature_y(::google::protobuf::uint32 value) {
+  signature_y_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG2.signature_y)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG2::signature_y() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG2.signature_y)
+  return signature_y_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG2::mutable_signature_y() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG2.signature_y)
+  return &signature_y_;
+}
+
+// repeated uint32 smac = 10 [packed = true];
+int MessageMSG2::smac_size() const {
+  return smac_.size();
+}
+void MessageMSG2::clear_smac() {
+  smac_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG2::smac(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.smac)
+  return smac_.Get(index);
+}
+ void MessageMSG2::set_smac(int index, ::google::protobuf::uint32 value) {
+  smac_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.smac)
+}
+ void MessageMSG2::add_smac(::google::protobuf::uint32 value) {
+  smac_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG2.smac)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG2::smac() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG2.smac)
+  return smac_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG2::mutable_smac() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG2.smac)
+  return &smac_;
+}
+
+// optional uint32 size_sigrl = 11;
+bool MessageMSG2::has_size_sigrl() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void MessageMSG2::set_has_size_sigrl() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void MessageMSG2::clear_has_size_sigrl() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void MessageMSG2::clear_size_sigrl() {
+  size_sigrl_ = 0u;
+  clear_has_size_sigrl();
+}
+ ::google::protobuf::uint32 MessageMSG2::size_sigrl() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.size_sigrl)
+  return size_sigrl_;
+}
+ void MessageMSG2::set_size_sigrl(::google::protobuf::uint32 value) {
+  set_has_size_sigrl();
+  size_sigrl_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.size_sigrl)
+}
+
+// repeated uint32 sigrl = 12 [packed = true];
+int MessageMSG2::sigrl_size() const {
+  return sigrl_.size();
+}
+void MessageMSG2::clear_sigrl() {
+  sigrl_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG2::sigrl(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG2.sigrl)
+  return sigrl_.Get(index);
+}
+ void MessageMSG2::set_sigrl(int index, ::google::protobuf::uint32 value) {
+  sigrl_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG2.sigrl)
+}
+ void MessageMSG2::add_sigrl(::google::protobuf::uint32 value) {
+  sigrl_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG2.sigrl)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG2::sigrl() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG2.sigrl)
+  return sigrl_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG2::mutable_sigrl() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG2.sigrl)
+  return &sigrl_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MessageMSG3::kTypeFieldNumber;
 const int MessageMSG3::kSizeFieldNumber;
 const int MessageMSG3::kSgxMacFieldNumber;
@@ -2163,10 +2826,10 @@
 const int MessageMSG3::kGayMsg3FieldNumber;
 const int MessageMSG3::kSecPropertyFieldNumber;
 const int MessageMSG3::kQuoteFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MessageMSG3::MessageMSG3()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:Messages.MessageMSG3)
 }
@@ -2175,7 +2838,8 @@
 }
 
 MessageMSG3::MessageMSG3(const MessageMSG3& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:Messages.MessageMSG3)
@@ -2215,24 +2879,35 @@
 
 MessageMSG3* MessageMSG3::default_instance_ = NULL;
 
-MessageMSG3* MessageMSG3::New() const {
-  return new MessageMSG3;
+MessageMSG3* MessageMSG3::New(::google::protobuf::Arena* arena) const {
+  MessageMSG3* n = new MessageMSG3;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void MessageMSG3::Clear() {
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<MessageMSG3*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+// @@protoc_insertion_point(message_clear_start:Messages.MessageMSG3)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(MessageMSG3, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<MessageMSG3*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&first, 0, n);                                \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
   ZR_(type_, size_);
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   sgx_mac_.Clear();
@@ -2241,12 +2916,14 @@
   sec_property_.Clear();
   quote_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool MessageMSG3::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:Messages.MessageMSG3)
   for (;;) {
@@ -2458,15 +3135,15 @@
       this->quote(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
   // @@protoc_insertion_point(serialize_end:Messages.MessageMSG3)
 }
 
-::google::protobuf::uint8* MessageMSG3::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MessageMSG3::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:Messages.MessageMSG3)
   // required uint32 type = 1;
   if (has_type()) {
@@ -2548,7 +3225,7 @@
       WriteUInt32NoTagToArray(this->quote(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -2557,24 +3234,22 @@
 }
 
 int MessageMSG3::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:Messages.MessageMSG3)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // required uint32 type = 1;
-    if (has_type()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->type());
-    }
-
-    // optional uint32 size = 2;
-    if (has_size()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->size());
-    }
-
+  // required uint32 type = 1;
+  if (has_type()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->type());
   }
+  // optional uint32 size = 2;
+  if (has_size()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->size());
+  }
+
   // repeated uint32 sgx_mac = 3 [packed = true];
   {
     int data_size = 0;
@@ -2660,7 +3335,7 @@
     total_size += data_size;
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -2672,19 +3347,27 @@
 }
 
 void MessageMSG3::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const MessageMSG3* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MessageMSG3*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:Messages.MessageMSG3)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
+  const MessageMSG3* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MessageMSG3>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Messages.MessageMSG3)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Messages.MessageMSG3)
     MergeFrom(*source);
   }
 }
 
 void MessageMSG3::MergeFrom(const MessageMSG3& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:Messages.MessageMSG3)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   sgx_mac_.MergeFrom(from.sgx_mac_);
   gax_msg3_.MergeFrom(from.gax_msg3_);
   gay_msg3_.MergeFrom(from.gay_msg3_);
@@ -2698,16 +3381,20 @@
       set_size(from.size());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void MessageMSG3::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Messages.MessageMSG3)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void MessageMSG3::CopyFrom(const MessageMSG3& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Messages.MessageMSG3)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -2720,18 +3407,20 @@
 }
 
 void MessageMSG3::Swap(MessageMSG3* other) {
-  if (other != this) {
-    std::swap(type_, other->type_);
-    std::swap(size_, other->size_);
-    sgx_mac_.Swap(&other->sgx_mac_);
-    gax_msg3_.Swap(&other->gax_msg3_);
-    gay_msg3_.Swap(&other->gay_msg3_);
-    sec_property_.Swap(&other->sec_property_);
-    quote_.Swap(&other->quote_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MessageMSG3::InternalSwap(MessageMSG3* other) {
+  std::swap(type_, other->type_);
+  std::swap(size_, other->size_);
+  sgx_mac_.UnsafeArenaSwap(&other->sgx_mac_);
+  gax_msg3_.UnsafeArenaSwap(&other->gax_msg3_);
+  gay_msg3_.UnsafeArenaSwap(&other->gay_msg3_);
+  sec_property_.UnsafeArenaSwap(&other->sec_property_);
+  quote_.UnsafeArenaSwap(&other->quote_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata MessageMSG3::GetMetadata() const {
@@ -2742,10 +3431,212 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MessageMSG3
+
+// required uint32 type = 1;
+bool MessageMSG3::has_type() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MessageMSG3::set_has_type() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MessageMSG3::clear_has_type() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MessageMSG3::clear_type() {
+  type_ = 0u;
+  clear_has_type();
+}
+ ::google::protobuf::uint32 MessageMSG3::type() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG3.type)
+  return type_;
+}
+ void MessageMSG3::set_type(::google::protobuf::uint32 value) {
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG3.type)
+}
+
+// optional uint32 size = 2;
+bool MessageMSG3::has_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void MessageMSG3::set_has_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void MessageMSG3::clear_has_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void MessageMSG3::clear_size() {
+  size_ = 0u;
+  clear_has_size();
+}
+ ::google::protobuf::uint32 MessageMSG3::size() const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG3.size)
+  return size_;
+}
+ void MessageMSG3::set_size(::google::protobuf::uint32 value) {
+  set_has_size();
+  size_ = value;
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG3.size)
+}
+
+// repeated uint32 sgx_mac = 3 [packed = true];
+int MessageMSG3::sgx_mac_size() const {
+  return sgx_mac_.size();
+}
+void MessageMSG3::clear_sgx_mac() {
+  sgx_mac_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG3::sgx_mac(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG3.sgx_mac)
+  return sgx_mac_.Get(index);
+}
+ void MessageMSG3::set_sgx_mac(int index, ::google::protobuf::uint32 value) {
+  sgx_mac_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG3.sgx_mac)
+}
+ void MessageMSG3::add_sgx_mac(::google::protobuf::uint32 value) {
+  sgx_mac_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG3.sgx_mac)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG3::sgx_mac() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG3.sgx_mac)
+  return sgx_mac_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG3::mutable_sgx_mac() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG3.sgx_mac)
+  return &sgx_mac_;
+}
+
+// repeated uint32 gax_msg3 = 4 [packed = true];
+int MessageMSG3::gax_msg3_size() const {
+  return gax_msg3_.size();
+}
+void MessageMSG3::clear_gax_msg3() {
+  gax_msg3_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG3::gax_msg3(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG3.gax_msg3)
+  return gax_msg3_.Get(index);
+}
+ void MessageMSG3::set_gax_msg3(int index, ::google::protobuf::uint32 value) {
+  gax_msg3_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG3.gax_msg3)
+}
+ void MessageMSG3::add_gax_msg3(::google::protobuf::uint32 value) {
+  gax_msg3_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG3.gax_msg3)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG3::gax_msg3() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG3.gax_msg3)
+  return gax_msg3_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG3::mutable_gax_msg3() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG3.gax_msg3)
+  return &gax_msg3_;
+}
+
+// repeated uint32 gay_msg3 = 5 [packed = true];
+int MessageMSG3::gay_msg3_size() const {
+  return gay_msg3_.size();
+}
+void MessageMSG3::clear_gay_msg3() {
+  gay_msg3_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG3::gay_msg3(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG3.gay_msg3)
+  return gay_msg3_.Get(index);
+}
+ void MessageMSG3::set_gay_msg3(int index, ::google::protobuf::uint32 value) {
+  gay_msg3_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG3.gay_msg3)
+}
+ void MessageMSG3::add_gay_msg3(::google::protobuf::uint32 value) {
+  gay_msg3_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG3.gay_msg3)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG3::gay_msg3() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG3.gay_msg3)
+  return gay_msg3_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG3::mutable_gay_msg3() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG3.gay_msg3)
+  return &gay_msg3_;
+}
+
+// repeated uint32 sec_property = 6 [packed = true];
+int MessageMSG3::sec_property_size() const {
+  return sec_property_.size();
+}
+void MessageMSG3::clear_sec_property() {
+  sec_property_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG3::sec_property(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG3.sec_property)
+  return sec_property_.Get(index);
+}
+ void MessageMSG3::set_sec_property(int index, ::google::protobuf::uint32 value) {
+  sec_property_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG3.sec_property)
+}
+ void MessageMSG3::add_sec_property(::google::protobuf::uint32 value) {
+  sec_property_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG3.sec_property)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG3::sec_property() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG3.sec_property)
+  return sec_property_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG3::mutable_sec_property() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG3.sec_property)
+  return &sec_property_;
+}
+
+// repeated uint32 quote = 7 [packed = true];
+int MessageMSG3::quote_size() const {
+  return quote_.size();
+}
+void MessageMSG3::clear_quote() {
+  quote_.Clear();
+}
+ ::google::protobuf::uint32 MessageMSG3::quote(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.MessageMSG3.quote)
+  return quote_.Get(index);
+}
+ void MessageMSG3::set_quote(int index, ::google::protobuf::uint32 value) {
+  quote_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.MessageMSG3.quote)
+}
+ void MessageMSG3::add_quote(::google::protobuf::uint32 value) {
+  quote_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.MessageMSG3.quote)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+MessageMSG3::quote() const {
+  // @@protoc_insertion_point(field_list:Messages.MessageMSG3.quote)
+  return quote_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+MessageMSG3::mutable_quote() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.MessageMSG3.quote)
+  return &quote_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int AttestationMessage::kTypeFieldNumber;
 const int AttestationMessage::kSizeFieldNumber;
 const int AttestationMessage::kEpidGroupStatusFieldNumber;
@@ -2762,10 +3653,10 @@
 const int AttestationMessage::kReservedFieldNumber;
 const int AttestationMessage::kPayloadTagFieldNumber;
 const int AttestationMessage::kPayloadFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 AttestationMessage::AttestationMessage()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:Messages.AttestationMessage)
 }
@@ -2774,7 +3665,8 @@
 }
 
 AttestationMessage::AttestationMessage(const AttestationMessage& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:Messages.AttestationMessage)
@@ -2818,28 +3710,39 @@
 
 AttestationMessage* AttestationMessage::default_instance_ = NULL;
 
-AttestationMessage* AttestationMessage::New() const {
-  return new AttestationMessage;
+AttestationMessage* AttestationMessage::New(::google::protobuf::Arena* arena) const {
+  AttestationMessage* n = new AttestationMessage;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void AttestationMessage::Clear() {
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<AttestationMessage*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+// @@protoc_insertion_point(message_clear_start:Messages.AttestationMessage)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(AttestationMessage, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<AttestationMessage*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&first, 0, n);                                \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
-  if (_has_bits_[0 / 32] & 31) {
+  if (_has_bits_[0 / 32] & 31u) {
     ZR_(type_, tcb_evaluation_status_);
     pse_evaluation_status_ = 0u;
   }
   result_size_ = 0u;
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   latest_equivalent_tcb_psvn_.Clear();
@@ -2853,12 +3756,14 @@
   payload_tag_.Clear();
   payload_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool AttestationMessage::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:Messages.AttestationMessage)
   for (;;) {
@@ -3290,15 +4195,15 @@
       this->payload(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
   // @@protoc_insertion_point(serialize_end:Messages.AttestationMessage)
 }
 
-::google::protobuf::uint8* AttestationMessage::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* AttestationMessage::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:Messages.AttestationMessage)
   // required uint32 type = 1;
   if (has_type()) {
@@ -3470,7 +4375,7 @@
       WriteUInt32NoTagToArray(this->payload(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -3478,24 +4383,45 @@
   return target;
 }
 
-int AttestationMessage::ByteSize() const {
+int AttestationMessage::RequiredFieldsByteSizeFallback() const {
+// @@protoc_insertion_point(required_fields_byte_size_fallback_start:Messages.AttestationMessage)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (has_type()) {
     // required uint32 type = 1;
-    if (has_type()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->type());
-    }
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->type());
+  }
+
+  if (has_size()) {
+    // required uint32 size = 2;
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->size());
+  }
+
+  return total_size;
+}
+int AttestationMessage::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:Messages.AttestationMessage)
+  int total_size = 0;
+
+  if (((_has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) {  // All required fields are present.
+    // required uint32 type = 1;
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->type());
 
     // required uint32 size = 2;
-    if (has_size()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->size());
-    }
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->size());
 
+  } else {
+    total_size += RequiredFieldsByteSizeFallback();
+  }
+  if (_has_bits_[2 / 32] & 28u) {
     // optional uint32 epid_group_status = 3;
     if (has_epid_group_status()) {
       total_size += 1 +
@@ -3518,15 +4444,13 @@
     }
 
   }
-  if (_has_bits_[12 / 32] & (0xffu << (12 % 32))) {
-    // optional uint32 result_size = 13;
-    if (has_result_size()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->result_size());
-    }
-
+  // optional uint32 result_size = 13;
+  if (has_result_size()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->result_size());
   }
+
   // repeated uint32 latest_equivalent_tcb_psvn = 6 [packed = true];
   {
     int data_size = 0;
@@ -3697,7 +4621,7 @@
     total_size += data_size;
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -3709,19 +4633,27 @@
 }
 
 void AttestationMessage::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const AttestationMessage* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const AttestationMessage*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:Messages.AttestationMessage)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
+  const AttestationMessage* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const AttestationMessage>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Messages.AttestationMessage)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Messages.AttestationMessage)
     MergeFrom(*source);
   }
 }
 
 void AttestationMessage::MergeFrom(const AttestationMessage& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:Messages.AttestationMessage)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   latest_equivalent_tcb_psvn_.MergeFrom(from.latest_equivalent_tcb_psvn_);
   latest_pse_isvsvn_.MergeFrom(from.latest_pse_isvsvn_);
   latest_psda_svn_.MergeFrom(from.latest_psda_svn_);
@@ -3754,16 +4686,20 @@
       set_result_size(from.result_size());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void AttestationMessage::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Messages.AttestationMessage)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void AttestationMessage::CopyFrom(const AttestationMessage& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Messages.AttestationMessage)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -3776,27 +4712,29 @@
 }
 
 void AttestationMessage::Swap(AttestationMessage* other) {
-  if (other != this) {
-    std::swap(type_, other->type_);
-    std::swap(size_, other->size_);
-    std::swap(epid_group_status_, other->epid_group_status_);
-    std::swap(tcb_evaluation_status_, other->tcb_evaluation_status_);
-    std::swap(pse_evaluation_status_, other->pse_evaluation_status_);
-    latest_equivalent_tcb_psvn_.Swap(&other->latest_equivalent_tcb_psvn_);
-    latest_pse_isvsvn_.Swap(&other->latest_pse_isvsvn_);
-    latest_psda_svn_.Swap(&other->latest_psda_svn_);
-    performance_rekey_gid_.Swap(&other->performance_rekey_gid_);
-    ec_sign256_x_.Swap(&other->ec_sign256_x_);
-    ec_sign256_y_.Swap(&other->ec_sign256_y_);
-    mac_smk_.Swap(&other->mac_smk_);
-    std::swap(result_size_, other->result_size_);
-    reserved_.Swap(&other->reserved_);
-    payload_tag_.Swap(&other->payload_tag_);
-    payload_.Swap(&other->payload_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void AttestationMessage::InternalSwap(AttestationMessage* other) {
+  std::swap(type_, other->type_);
+  std::swap(size_, other->size_);
+  std::swap(epid_group_status_, other->epid_group_status_);
+  std::swap(tcb_evaluation_status_, other->tcb_evaluation_status_);
+  std::swap(pse_evaluation_status_, other->pse_evaluation_status_);
+  latest_equivalent_tcb_psvn_.UnsafeArenaSwap(&other->latest_equivalent_tcb_psvn_);
+  latest_pse_isvsvn_.UnsafeArenaSwap(&other->latest_pse_isvsvn_);
+  latest_psda_svn_.UnsafeArenaSwap(&other->latest_psda_svn_);
+  performance_rekey_gid_.UnsafeArenaSwap(&other->performance_rekey_gid_);
+  ec_sign256_x_.UnsafeArenaSwap(&other->ec_sign256_x_);
+  ec_sign256_y_.UnsafeArenaSwap(&other->ec_sign256_y_);
+  mac_smk_.UnsafeArenaSwap(&other->mac_smk_);
+  std::swap(result_size_, other->result_size_);
+  reserved_.UnsafeArenaSwap(&other->reserved_);
+  payload_tag_.UnsafeArenaSwap(&other->payload_tag_);
+  payload_.UnsafeArenaSwap(&other->payload_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata AttestationMessage::GetMetadata() const {
@@ -3807,735 +4745,454 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// AttestationMessage
 
-// ===================================================================
-
-#ifndef _MSC_VER
-const int SecretMessage::kTypeFieldNumber;
-const int SecretMessage::kSizeFieldNumber;
-const int SecretMessage::kEncrypedPkeySizeFieldNumber;
-const int SecretMessage::kEncrypedX509SizeFieldNumber;
-const int SecretMessage::kEncryptedContentFieldNumber;
-const int SecretMessage::kMacSmkFieldNumber;
-const int SecretMessage::kEncryptedPkeyFieldNumber;
-const int SecretMessage::kEncryptedPkeyMacSmkFieldNumber;
-const int SecretMessage::kEncryptedX509FieldNumber;
-const int SecretMessage::kEncryptedX509MacSmkFieldNumber;
-#endif  // !_MSC_VER
-
-SecretMessage::SecretMessage()
-  : ::google::protobuf::Message() {
-  SharedCtor();
-  // @@protoc_insertion_point(constructor:Messages.SecretMessage)
+// required uint32 type = 1;
+bool AttestationMessage::has_type() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
 }
-
-void SecretMessage::InitAsDefaultInstance() {
+void AttestationMessage::set_has_type() {
+  _has_bits_[0] |= 0x00000001u;
 }
-
-SecretMessage::SecretMessage(const SecretMessage& from)
-  : ::google::protobuf::Message() {
-  SharedCtor();
-  MergeFrom(from);
-  // @@protoc_insertion_point(copy_constructor:Messages.SecretMessage)
+void AttestationMessage::clear_has_type() {
+  _has_bits_[0] &= ~0x00000001u;
 }
-
-void SecretMessage::SharedCtor() {
-  _cached_size_ = 0;
+void AttestationMessage::clear_type() {
   type_ = 0u;
+  clear_has_type();
+}
+ ::google::protobuf::uint32 AttestationMessage::type() const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.type)
+  return type_;
+}
+ void AttestationMessage::set_type(::google::protobuf::uint32 value) {
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.type)
+}
+
+// required uint32 size = 2;
+bool AttestationMessage::has_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void AttestationMessage::set_has_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void AttestationMessage::clear_has_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void AttestationMessage::clear_size() {
   size_ = 0u;
-  encryped_pkey_size_ = 0u;
-  encryped_x509_size_ = 0u;
-  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  clear_has_size();
+}
+ ::google::protobuf::uint32 AttestationMessage::size() const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.size)
+  return size_;
+}
+ void AttestationMessage::set_size(::google::protobuf::uint32 value) {
+  set_has_size();
+  size_ = value;
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.size)
 }
 
-SecretMessage::~SecretMessage() {
-  // @@protoc_insertion_point(destructor:Messages.SecretMessage)
-  SharedDtor();
+// optional uint32 epid_group_status = 3;
+bool AttestationMessage::has_epid_group_status() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void AttestationMessage::set_has_epid_group_status() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void AttestationMessage::clear_has_epid_group_status() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void AttestationMessage::clear_epid_group_status() {
+  epid_group_status_ = 0u;
+  clear_has_epid_group_status();
+}
+ ::google::protobuf::uint32 AttestationMessage::epid_group_status() const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.epid_group_status)
+  return epid_group_status_;
+}
+ void AttestationMessage::set_epid_group_status(::google::protobuf::uint32 value) {
+  set_has_epid_group_status();
+  epid_group_status_ = value;
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.epid_group_status)
 }
 
-void SecretMessage::SharedDtor() {
-  if (this != default_instance_) {
-  }
+// optional uint32 tcb_evaluation_status = 4;
+bool AttestationMessage::has_tcb_evaluation_status() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void AttestationMessage::set_has_tcb_evaluation_status() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void AttestationMessage::clear_has_tcb_evaluation_status() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void AttestationMessage::clear_tcb_evaluation_status() {
+  tcb_evaluation_status_ = 0u;
+  clear_has_tcb_evaluation_status();
+}
+ ::google::protobuf::uint32 AttestationMessage::tcb_evaluation_status() const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.tcb_evaluation_status)
+  return tcb_evaluation_status_;
+}
+ void AttestationMessage::set_tcb_evaluation_status(::google::protobuf::uint32 value) {
+  set_has_tcb_evaluation_status();
+  tcb_evaluation_status_ = value;
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.tcb_evaluation_status)
 }
 
-void SecretMessage::SetCachedSize(int size) const {
-  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-  _cached_size_ = size;
-  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+// optional uint32 pse_evaluation_status = 5;
+bool AttestationMessage::has_pse_evaluation_status() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
 }
-const ::google::protobuf::Descriptor* SecretMessage::descriptor() {
-  protobuf_AssignDescriptorsOnce();
-  return SecretMessage_descriptor_;
+void AttestationMessage::set_has_pse_evaluation_status() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void AttestationMessage::clear_has_pse_evaluation_status() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void AttestationMessage::clear_pse_evaluation_status() {
+  pse_evaluation_status_ = 0u;
+  clear_has_pse_evaluation_status();
+}
+ ::google::protobuf::uint32 AttestationMessage::pse_evaluation_status() const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.pse_evaluation_status)
+  return pse_evaluation_status_;
+}
+ void AttestationMessage::set_pse_evaluation_status(::google::protobuf::uint32 value) {
+  set_has_pse_evaluation_status();
+  pse_evaluation_status_ = value;
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.pse_evaluation_status)
 }
 
-const SecretMessage& SecretMessage::default_instance() {
-  if (default_instance_ == NULL) protobuf_AddDesc_Messages_2eproto();
-  return *default_instance_;
+// repeated uint32 latest_equivalent_tcb_psvn = 6 [packed = true];
+int AttestationMessage::latest_equivalent_tcb_psvn_size() const {
+  return latest_equivalent_tcb_psvn_.size();
+}
+void AttestationMessage::clear_latest_equivalent_tcb_psvn() {
+  latest_equivalent_tcb_psvn_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::latest_equivalent_tcb_psvn(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.latest_equivalent_tcb_psvn)
+  return latest_equivalent_tcb_psvn_.Get(index);
+}
+ void AttestationMessage::set_latest_equivalent_tcb_psvn(int index, ::google::protobuf::uint32 value) {
+  latest_equivalent_tcb_psvn_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.latest_equivalent_tcb_psvn)
+}
+ void AttestationMessage::add_latest_equivalent_tcb_psvn(::google::protobuf::uint32 value) {
+  latest_equivalent_tcb_psvn_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.latest_equivalent_tcb_psvn)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::latest_equivalent_tcb_psvn() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.latest_equivalent_tcb_psvn)
+  return latest_equivalent_tcb_psvn_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_latest_equivalent_tcb_psvn() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.latest_equivalent_tcb_psvn)
+  return &latest_equivalent_tcb_psvn_;
 }
 
-SecretMessage* SecretMessage::default_instance_ = NULL;
-
-SecretMessage* SecretMessage::New() const {
-  return new SecretMessage;
+// repeated uint32 latest_pse_isvsvn = 7 [packed = true];
+int AttestationMessage::latest_pse_isvsvn_size() const {
+  return latest_pse_isvsvn_.size();
+}
+void AttestationMessage::clear_latest_pse_isvsvn() {
+  latest_pse_isvsvn_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::latest_pse_isvsvn(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.latest_pse_isvsvn)
+  return latest_pse_isvsvn_.Get(index);
+}
+ void AttestationMessage::set_latest_pse_isvsvn(int index, ::google::protobuf::uint32 value) {
+  latest_pse_isvsvn_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.latest_pse_isvsvn)
+}
+ void AttestationMessage::add_latest_pse_isvsvn(::google::protobuf::uint32 value) {
+  latest_pse_isvsvn_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.latest_pse_isvsvn)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::latest_pse_isvsvn() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.latest_pse_isvsvn)
+  return latest_pse_isvsvn_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_latest_pse_isvsvn() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.latest_pse_isvsvn)
+  return &latest_pse_isvsvn_;
 }
 
-void SecretMessage::Clear() {
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<SecretMessage*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+// repeated uint32 latest_psda_svn = 8 [packed = true];
+int AttestationMessage::latest_psda_svn_size() const {
+  return latest_psda_svn_.size();
+}
+void AttestationMessage::clear_latest_psda_svn() {
+  latest_psda_svn_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::latest_psda_svn(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.latest_psda_svn)
+  return latest_psda_svn_.Get(index);
+}
+ void AttestationMessage::set_latest_psda_svn(int index, ::google::protobuf::uint32 value) {
+  latest_psda_svn_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.latest_psda_svn)
+}
+ void AttestationMessage::add_latest_psda_svn(::google::protobuf::uint32 value) {
+  latest_psda_svn_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.latest_psda_svn)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::latest_psda_svn() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.latest_psda_svn)
+  return latest_psda_svn_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_latest_psda_svn() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.latest_psda_svn)
+  return &latest_psda_svn_;
+}
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&first, 0, n);                                \
-  } while (0)
+// repeated uint32 performance_rekey_gid = 9 [packed = true];
+int AttestationMessage::performance_rekey_gid_size() const {
+  return performance_rekey_gid_.size();
+}
+void AttestationMessage::clear_performance_rekey_gid() {
+  performance_rekey_gid_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::performance_rekey_gid(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.performance_rekey_gid)
+  return performance_rekey_gid_.Get(index);
+}
+ void AttestationMessage::set_performance_rekey_gid(int index, ::google::protobuf::uint32 value) {
+  performance_rekey_gid_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.performance_rekey_gid)
+}
+ void AttestationMessage::add_performance_rekey_gid(::google::protobuf::uint32 value) {
+  performance_rekey_gid_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.performance_rekey_gid)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::performance_rekey_gid() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.performance_rekey_gid)
+  return performance_rekey_gid_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_performance_rekey_gid() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.performance_rekey_gid)
+  return &performance_rekey_gid_;
+}
 
-  ZR_(type_, encryped_x509_size_);
+// repeated uint32 ec_sign256_x = 10 [packed = true];
+int AttestationMessage::ec_sign256_x_size() const {
+  return ec_sign256_x_.size();
+}
+void AttestationMessage::clear_ec_sign256_x() {
+  ec_sign256_x_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::ec_sign256_x(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.ec_sign256_x)
+  return ec_sign256_x_.Get(index);
+}
+ void AttestationMessage::set_ec_sign256_x(int index, ::google::protobuf::uint32 value) {
+  ec_sign256_x_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.ec_sign256_x)
+}
+ void AttestationMessage::add_ec_sign256_x(::google::protobuf::uint32 value) {
+  ec_sign256_x_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.ec_sign256_x)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::ec_sign256_x() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.ec_sign256_x)
+  return ec_sign256_x_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_ec_sign256_x() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.ec_sign256_x)
+  return &ec_sign256_x_;
+}
 
-#undef OFFSET_OF_FIELD_
-#undef ZR_
+// repeated uint32 ec_sign256_y = 11 [packed = true];
+int AttestationMessage::ec_sign256_y_size() const {
+  return ec_sign256_y_.size();
+}
+void AttestationMessage::clear_ec_sign256_y() {
+  ec_sign256_y_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::ec_sign256_y(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.ec_sign256_y)
+  return ec_sign256_y_.Get(index);
+}
+ void AttestationMessage::set_ec_sign256_y(int index, ::google::protobuf::uint32 value) {
+  ec_sign256_y_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.ec_sign256_y)
+}
+ void AttestationMessage::add_ec_sign256_y(::google::protobuf::uint32 value) {
+  ec_sign256_y_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.ec_sign256_y)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::ec_sign256_y() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.ec_sign256_y)
+  return ec_sign256_y_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_ec_sign256_y() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.ec_sign256_y)
+  return &ec_sign256_y_;
+}
 
-  encrypted_content_.Clear();
+// repeated uint32 mac_smk = 12 [packed = true];
+int AttestationMessage::mac_smk_size() const {
+  return mac_smk_.size();
+}
+void AttestationMessage::clear_mac_smk() {
   mac_smk_.Clear();
-  encrypted_pkey_.Clear();
-  encrypted_pkey_mac_smk_.Clear();
-  encrypted_x509_.Clear();
-  encrypted_x509_mac_smk_.Clear();
-  ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::mac_smk(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.mac_smk)
+  return mac_smk_.Get(index);
+}
+ void AttestationMessage::set_mac_smk(int index, ::google::protobuf::uint32 value) {
+  mac_smk_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.mac_smk)
+}
+ void AttestationMessage::add_mac_smk(::google::protobuf::uint32 value) {
+  mac_smk_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.mac_smk)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::mac_smk() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.mac_smk)
+  return mac_smk_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_mac_smk() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.mac_smk)
+  return &mac_smk_;
 }
 
-bool SecretMessage::MergePartialFromCodedStream(
-    ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
-  ::google::protobuf::uint32 tag;
-  // @@protoc_insertion_point(parse_start:Messages.SecretMessage)
-  for (;;) {
-    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
-    tag = p.first;
-    if (!p.second) goto handle_unusual;
-    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
-      // required uint32 type = 1;
-      case 1: {
-        if (tag == 8) {
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, &type_)));
-          set_has_type();
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(16)) goto parse_size;
-        break;
-      }
-
-      // required uint32 size = 2;
-      case 2: {
-        if (tag == 16) {
-         parse_size:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, &size_)));
-          set_has_size();
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(24)) goto parse_encryped_pkey_size;
-        break;
-      }
-
-      // optional uint32 encryped_pkey_size = 3;
-      case 3: {
-        if (tag == 24) {
-         parse_encryped_pkey_size:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, &encryped_pkey_size_)));
-          set_has_encryped_pkey_size();
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(32)) goto parse_encryped_x509_size;
-        break;
-      }
-
-      // optional uint32 encryped_x509_size = 4;
-      case 4: {
-        if (tag == 32) {
-         parse_encryped_x509_size:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, &encryped_x509_size_)));
-          set_has_encryped_x509_size();
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(42)) goto parse_encrypted_content;
-        break;
-      }
-
-      // repeated uint32 encrypted_content = 5 [packed = true];
-      case 5: {
-        if (tag == 42) {
-         parse_encrypted_content:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, this->mutable_encrypted_content())));
-        } else if (tag == 40) {
-          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 1, 42, input, this->mutable_encrypted_content())));
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(50)) goto parse_mac_smk;
-        break;
-      }
-
-      // repeated uint32 mac_smk = 6 [packed = true];
-      case 6: {
-        if (tag == 50) {
-         parse_mac_smk:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, this->mutable_mac_smk())));
-        } else if (tag == 48) {
-          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 1, 50, input, this->mutable_mac_smk())));
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(58)) goto parse_encrypted_pkey;
-        break;
-      }
-
-      // repeated uint32 encrypted_pkey = 7 [packed = true];
-      case 7: {
-        if (tag == 58) {
-         parse_encrypted_pkey:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, this->mutable_encrypted_pkey())));
-        } else if (tag == 56) {
-          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 1, 58, input, this->mutable_encrypted_pkey())));
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(66)) goto parse_encrypted_pkey_mac_smk;
-        break;
-      }
-
-      // repeated uint32 encrypted_pkey_mac_smk = 8 [packed = true];
-      case 8: {
-        if (tag == 66) {
-         parse_encrypted_pkey_mac_smk:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, this->mutable_encrypted_pkey_mac_smk())));
-        } else if (tag == 64) {
-          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 1, 66, input, this->mutable_encrypted_pkey_mac_smk())));
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(74)) goto parse_encrypted_x509;
-        break;
-      }
-
-      // repeated uint32 encrypted_x509 = 9 [packed = true];
-      case 9: {
-        if (tag == 74) {
-         parse_encrypted_x509:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, this->mutable_encrypted_x509())));
-        } else if (tag == 72) {
-          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 1, 74, input, this->mutable_encrypted_x509())));
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectTag(82)) goto parse_encrypted_x509_mac_smk;
-        break;
-      }
-
-      // repeated uint32 encrypted_x509_mac_smk = 10 [packed = true];
-      case 10: {
-        if (tag == 82) {
-         parse_encrypted_x509_mac_smk:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 input, this->mutable_encrypted_x509_mac_smk())));
-        } else if (tag == 80) {
-          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
-                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
-                 1, 82, input, this->mutable_encrypted_x509_mac_smk())));
-        } else {
-          goto handle_unusual;
-        }
-        if (input->ExpectAtEnd()) goto success;
-        break;
-      }
-
-      default: {
-      handle_unusual:
-        if (tag == 0 ||
-            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
-          goto success;
-        }
-        DO_(::google::protobuf::internal::WireFormat::SkipField(
-              input, tag, mutable_unknown_fields()));
-        break;
-      }
-    }
-  }
-success:
-  // @@protoc_insertion_point(parse_success:Messages.SecretMessage)
-  return true;
-failure:
-  // @@protoc_insertion_point(parse_failure:Messages.SecretMessage)
-  return false;
-#undef DO_
+// optional uint32 result_size = 13;
+bool AttestationMessage::has_result_size() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+void AttestationMessage::set_has_result_size() {
+  _has_bits_[0] |= 0x00001000u;
+}
+void AttestationMessage::clear_has_result_size() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+void AttestationMessage::clear_result_size() {
+  result_size_ = 0u;
+  clear_has_result_size();
+}
+ ::google::protobuf::uint32 AttestationMessage::result_size() const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.result_size)
+  return result_size_;
+}
+ void AttestationMessage::set_result_size(::google::protobuf::uint32 value) {
+  set_has_result_size();
+  result_size_ = value;
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.result_size)
 }
 
-void SecretMessage::SerializeWithCachedSizes(
-    ::google::protobuf::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:Messages.SecretMessage)
-  // required uint32 type = 1;
-  if (has_type()) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->type(), output);
-  }
-
-  // required uint32 size = 2;
-  if (has_size()) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->size(), output);
-  }
-
-  // optional uint32 encryped_pkey_size = 3;
-  if (has_encryped_pkey_size()) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->encryped_pkey_size(), output);
-  }
-
-  // optional uint32 encryped_x509_size = 4;
-  if (has_encryped_x509_size()) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->encryped_x509_size(), output);
-  }
-
-  // repeated uint32 encrypted_content = 5 [packed = true];
-  if (this->encrypted_content_size() > 0) {
-    ::google::protobuf::internal::WireFormatLite::WriteTag(5, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_encrypted_content_cached_byte_size_);
-  }
-  for (int i = 0; i < this->encrypted_content_size(); i++) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32NoTag(
-      this->encrypted_content(i), output);
-  }
-
-  // repeated uint32 mac_smk = 6 [packed = true];
-  if (this->mac_smk_size() > 0) {
-    ::google::protobuf::internal::WireFormatLite::WriteTag(6, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_mac_smk_cached_byte_size_);
-  }
-  for (int i = 0; i < this->mac_smk_size(); i++) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32NoTag(
-      this->mac_smk(i), output);
-  }
-
-  // repeated uint32 encrypted_pkey = 7 [packed = true];
-  if (this->encrypted_pkey_size() > 0) {
-    ::google::protobuf::internal::WireFormatLite::WriteTag(7, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_encrypted_pkey_cached_byte_size_);
-  }
-  for (int i = 0; i < this->encrypted_pkey_size(); i++) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32NoTag(
-      this->encrypted_pkey(i), output);
-  }
-
-  // repeated uint32 encrypted_pkey_mac_smk = 8 [packed = true];
-  if (this->encrypted_pkey_mac_smk_size() > 0) {
-    ::google::protobuf::internal::WireFormatLite::WriteTag(8, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_encrypted_pkey_mac_smk_cached_byte_size_);
-  }
-  for (int i = 0; i < this->encrypted_pkey_mac_smk_size(); i++) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32NoTag(
-      this->encrypted_pkey_mac_smk(i), output);
-  }
-
-  // repeated uint32 encrypted_x509 = 9 [packed = true];
-  if (this->encrypted_x509_size() > 0) {
-    ::google::protobuf::internal::WireFormatLite::WriteTag(9, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_encrypted_x509_cached_byte_size_);
-  }
-  for (int i = 0; i < this->encrypted_x509_size(); i++) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32NoTag(
-      this->encrypted_x509(i), output);
-  }
-
-  // repeated uint32 encrypted_x509_mac_smk = 10 [packed = true];
-  if (this->encrypted_x509_mac_smk_size() > 0) {
-    ::google::protobuf::internal::WireFormatLite::WriteTag(10, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_encrypted_x509_mac_smk_cached_byte_size_);
-  }
-  for (int i = 0; i < this->encrypted_x509_mac_smk_size(); i++) {
-    ::google::protobuf::internal::WireFormatLite::WriteUInt32NoTag(
-      this->encrypted_x509_mac_smk(i), output);
-  }
-
-  if (!unknown_fields().empty()) {
-    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
-        unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:Messages.SecretMessage)
+// repeated uint32 reserved = 14 [packed = true];
+int AttestationMessage::reserved_size() const {
+  return reserved_.size();
+}
+void AttestationMessage::clear_reserved() {
+  reserved_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::reserved(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.reserved)
+  return reserved_.Get(index);
+}
+ void AttestationMessage::set_reserved(int index, ::google::protobuf::uint32 value) {
+  reserved_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.reserved)
+}
+ void AttestationMessage::add_reserved(::google::protobuf::uint32 value) {
+  reserved_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.reserved)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::reserved() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.reserved)
+  return reserved_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_reserved() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.reserved)
+  return &reserved_;
 }
 
-::google::protobuf::uint8* SecretMessage::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
-  // @@protoc_insertion_point(serialize_to_array_start:Messages.SecretMessage)
-  // required uint32 type = 1;
-  if (has_type()) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->type(), target);
-  }
-
-  // required uint32 size = 2;
-  if (has_size()) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->size(), target);
-  }
-
-  // optional uint32 encryped_pkey_size = 3;
-  if (has_encryped_pkey_size()) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->encryped_pkey_size(), target);
-  }
-
-  // optional uint32 encryped_x509_size = 4;
-  if (has_encryped_x509_size()) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->encryped_x509_size(), target);
-  }
-
-  // repeated uint32 encrypted_content = 5 [packed = true];
-  if (this->encrypted_content_size() > 0) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
-      5,
-      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
-      _encrypted_content_cached_byte_size_, target);
-  }
-  for (int i = 0; i < this->encrypted_content_size(); i++) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      WriteUInt32NoTagToArray(this->encrypted_content(i), target);
-  }
-
-  // repeated uint32 mac_smk = 6 [packed = true];
-  if (this->mac_smk_size() > 0) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
-      6,
-      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
-      _mac_smk_cached_byte_size_, target);
-  }
-  for (int i = 0; i < this->mac_smk_size(); i++) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      WriteUInt32NoTagToArray(this->mac_smk(i), target);
-  }
-
-  // repeated uint32 encrypted_pkey = 7 [packed = true];
-  if (this->encrypted_pkey_size() > 0) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
-      7,
-      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
-      _encrypted_pkey_cached_byte_size_, target);
-  }
-  for (int i = 0; i < this->encrypted_pkey_size(); i++) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      WriteUInt32NoTagToArray(this->encrypted_pkey(i), target);
-  }
-
-  // repeated uint32 encrypted_pkey_mac_smk = 8 [packed = true];
-  if (this->encrypted_pkey_mac_smk_size() > 0) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
-      8,
-      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
-      _encrypted_pkey_mac_smk_cached_byte_size_, target);
-  }
-  for (int i = 0; i < this->encrypted_pkey_mac_smk_size(); i++) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      WriteUInt32NoTagToArray(this->encrypted_pkey_mac_smk(i), target);
-  }
-
-  // repeated uint32 encrypted_x509 = 9 [packed = true];
-  if (this->encrypted_x509_size() > 0) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
-      9,
-      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
-      _encrypted_x509_cached_byte_size_, target);
-  }
-  for (int i = 0; i < this->encrypted_x509_size(); i++) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      WriteUInt32NoTagToArray(this->encrypted_x509(i), target);
-  }
-
-  // repeated uint32 encrypted_x509_mac_smk = 10 [packed = true];
-  if (this->encrypted_x509_mac_smk_size() > 0) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
-      10,
-      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
-      _encrypted_x509_mac_smk_cached_byte_size_, target);
-  }
-  for (int i = 0; i < this->encrypted_x509_mac_smk_size(); i++) {
-    target = ::google::protobuf::internal::WireFormatLite::
-      WriteUInt32NoTagToArray(this->encrypted_x509_mac_smk(i), target);
-  }
-
-  if (!unknown_fields().empty()) {
-    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
-        unknown_fields(), target);
-  }
-  // @@protoc_insertion_point(serialize_to_array_end:Messages.SecretMessage)
-  return target;
+// repeated uint32 payload_tag = 15 [packed = true];
+int AttestationMessage::payload_tag_size() const {
+  return payload_tag_.size();
+}
+void AttestationMessage::clear_payload_tag() {
+  payload_tag_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::payload_tag(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.payload_tag)
+  return payload_tag_.Get(index);
+}
+ void AttestationMessage::set_payload_tag(int index, ::google::protobuf::uint32 value) {
+  payload_tag_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.payload_tag)
+}
+ void AttestationMessage::add_payload_tag(::google::protobuf::uint32 value) {
+  payload_tag_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.payload_tag)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::payload_tag() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.payload_tag)
+  return payload_tag_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_payload_tag() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.payload_tag)
+  return &payload_tag_;
 }
 
-int SecretMessage::ByteSize() const {
-  int total_size = 0;
-
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // required uint32 type = 1;
-    if (has_type()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->type());
-    }
-
-    // required uint32 size = 2;
-    if (has_size()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->size());
-    }
-
-    // optional uint32 encryped_pkey_size = 3;
-    if (has_encryped_pkey_size()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->encryped_pkey_size());
-    }
-
-    // optional uint32 encryped_x509_size = 4;
-    if (has_encryped_x509_size()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::UInt32Size(
-          this->encryped_x509_size());
-    }
-
-  }
-  // repeated uint32 encrypted_content = 5 [packed = true];
-  {
-    int data_size = 0;
-    for (int i = 0; i < this->encrypted_content_size(); i++) {
-      data_size += ::google::protobuf::internal::WireFormatLite::
-        UInt32Size(this->encrypted_content(i));
-    }
-    if (data_size > 0) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
-    }
-    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-    _encrypted_content_cached_byte_size_ = data_size;
-    GOOGLE_SAFE_CONCURRENT_WRITES_END();
-    total_size += data_size;
-  }
-
-  // repeated uint32 mac_smk = 6 [packed = true];
-  {
-    int data_size = 0;
-    for (int i = 0; i < this->mac_smk_size(); i++) {
-      data_size += ::google::protobuf::internal::WireFormatLite::
-        UInt32Size(this->mac_smk(i));
-    }
-    if (data_size > 0) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
-    }
-    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-    _mac_smk_cached_byte_size_ = data_size;
-    GOOGLE_SAFE_CONCURRENT_WRITES_END();
-    total_size += data_size;
-  }
-
-  // repeated uint32 encrypted_pkey = 7 [packed = true];
-  {
-    int data_size = 0;
-    for (int i = 0; i < this->encrypted_pkey_size(); i++) {
-      data_size += ::google::protobuf::internal::WireFormatLite::
-        UInt32Size(this->encrypted_pkey(i));
-    }
-    if (data_size > 0) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
-    }
-    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-    _encrypted_pkey_cached_byte_size_ = data_size;
-    GOOGLE_SAFE_CONCURRENT_WRITES_END();
-    total_size += data_size;
-  }
-
-  // repeated uint32 encrypted_pkey_mac_smk = 8 [packed = true];
-  {
-    int data_size = 0;
-    for (int i = 0; i < this->encrypted_pkey_mac_smk_size(); i++) {
-      data_size += ::google::protobuf::internal::WireFormatLite::
-        UInt32Size(this->encrypted_pkey_mac_smk(i));
-    }
-    if (data_size > 0) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
-    }
-    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-    _encrypted_pkey_mac_smk_cached_byte_size_ = data_size;
-    GOOGLE_SAFE_CONCURRENT_WRITES_END();
-    total_size += data_size;
-  }
-
-  // repeated uint32 encrypted_x509 = 9 [packed = true];
-  {
-    int data_size = 0;
-    for (int i = 0; i < this->encrypted_x509_size(); i++) {
-      data_size += ::google::protobuf::internal::WireFormatLite::
-        UInt32Size(this->encrypted_x509(i));
-    }
-    if (data_size > 0) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
-    }
-    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-    _encrypted_x509_cached_byte_size_ = data_size;
-    GOOGLE_SAFE_CONCURRENT_WRITES_END();
-    total_size += data_size;
-  }
-
-  // repeated uint32 encrypted_x509_mac_smk = 10 [packed = true];
-  {
-    int data_size = 0;
-    for (int i = 0; i < this->encrypted_x509_mac_smk_size(); i++) {
-      data_size += ::google::protobuf::internal::WireFormatLite::
-        UInt32Size(this->encrypted_x509_mac_smk(i));
-    }
-    if (data_size > 0) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
-    }
-    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-    _encrypted_x509_mac_smk_cached_byte_size_ = data_size;
-    GOOGLE_SAFE_CONCURRENT_WRITES_END();
-    total_size += data_size;
-  }
-
-  if (!unknown_fields().empty()) {
-    total_size +=
-      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
-        unknown_fields());
-  }
-  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-  _cached_size_ = total_size;
-  GOOGLE_SAFE_CONCURRENT_WRITES_END();
-  return total_size;
+// repeated uint32 payload = 16 [packed = true];
+int AttestationMessage::payload_size() const {
+  return payload_.size();
+}
+void AttestationMessage::clear_payload() {
+  payload_.Clear();
+}
+ ::google::protobuf::uint32 AttestationMessage::payload(int index) const {
+  // @@protoc_insertion_point(field_get:Messages.AttestationMessage.payload)
+  return payload_.Get(index);
+}
+ void AttestationMessage::set_payload(int index, ::google::protobuf::uint32 value) {
+  payload_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Messages.AttestationMessage.payload)
+}
+ void AttestationMessage::add_payload(::google::protobuf::uint32 value) {
+  payload_.Add(value);
+  // @@protoc_insertion_point(field_add:Messages.AttestationMessage.payload)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+AttestationMessage::payload() const {
+  // @@protoc_insertion_point(field_list:Messages.AttestationMessage.payload)
+  return payload_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+AttestationMessage::mutable_payload() {
+  // @@protoc_insertion_point(field_mutable_list:Messages.AttestationMessage.payload)
+  return &payload_;
 }
 
-void SecretMessage::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const SecretMessage* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const SecretMessage*>(
-      &from);
-  if (source == NULL) {
-    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
-  } else {
-    MergeFrom(*source);
-  }
-}
-
-void SecretMessage::MergeFrom(const SecretMessage& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  encrypted_content_.MergeFrom(from.encrypted_content_);
-  mac_smk_.MergeFrom(from.mac_smk_);
-  encrypted_pkey_.MergeFrom(from.encrypted_pkey_);
-  encrypted_pkey_mac_smk_.MergeFrom(from.encrypted_pkey_mac_smk_);
-  encrypted_x509_.MergeFrom(from.encrypted_x509_);
-  encrypted_x509_mac_smk_.MergeFrom(from.encrypted_x509_mac_smk_);
-  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    if (from.has_type()) {
-      set_type(from.type());
-    }
-    if (from.has_size()) {
-      set_size(from.size());
-    }
-    if (from.has_encryped_pkey_size()) {
-      set_encryped_pkey_size(from.encryped_pkey_size());
-    }
-    if (from.has_encryped_x509_size()) {
-      set_encryped_x509_size(from.encryped_x509_size());
-    }
-  }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
-}
-
-void SecretMessage::CopyFrom(const ::google::protobuf::Message& from) {
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
-void SecretMessage::CopyFrom(const SecretMessage& from) {
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
-bool SecretMessage::IsInitialized() const {
-  if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false;
-
-  return true;
-}
-
-void SecretMessage::Swap(SecretMessage* other) {
-  if (other != this) {
-    std::swap(type_, other->type_);
-    std::swap(size_, other->size_);
-    std::swap(encryped_pkey_size_, other->encryped_pkey_size_);
-    std::swap(encryped_x509_size_, other->encryped_x509_size_);
-    encrypted_content_.Swap(&other->encrypted_content_);
-    mac_smk_.Swap(&other->mac_smk_);
-    encrypted_pkey_.Swap(&other->encrypted_pkey_);
-    encrypted_pkey_mac_smk_.Swap(&other->encrypted_pkey_mac_smk_);
-    encrypted_x509_.Swap(&other->encrypted_x509_);
-    encrypted_x509_mac_smk_.Swap(&other->encrypted_x509_mac_smk_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
-}
-
-::google::protobuf::Metadata SecretMessage::GetMetadata() const {
-  protobuf_AssignDescriptorsOnce();
-  ::google::protobuf::Metadata metadata;
-  metadata.descriptor = SecretMessage_descriptor_;
-  metadata.reflection = SecretMessage_reflection_;
-  return metadata;
-}
-
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/samplecode/remoteattestation/GoogleMessages/Messages.pb.h b/samplecode/remoteattestation/GoogleMessages/Messages.pb.h
index 8c2e78f..3acdf98 100644
--- a/samplecode/remoteattestation/GoogleMessages/Messages.pb.h
+++ b/samplecode/remoteattestation/GoogleMessages/Messages.pb.h
@@ -8,18 +8,21 @@
 
 #include <google/protobuf/stubs/common.h>
 
-#if GOOGLE_PROTOBUF_VERSION < 2006000
+#if GOOGLE_PROTOBUF_VERSION < 3000000
 #error This file was generated by a newer version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please update
 #error your headers.
 #endif
-#if 2006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
 #error This file was generated by an older version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please
 #error regenerate this file with a newer version of protoc.
 #endif
 
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
 #include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
@@ -29,21 +32,20 @@
 namespace Messages {
 
 // Internal implementation detail -- do not call these.
-void  protobuf_AddDesc_Messages_2eproto();
+void protobuf_AddDesc_Messages_2eproto();
 void protobuf_AssignDesc_Messages_2eproto();
 void protobuf_ShutdownFile_Messages_2eproto();
 
+class AttestationMessage;
 class InitialMessage;
-class MessageMsg0;
 class MessageMSG1;
 class MessageMSG2;
 class MessageMSG3;
-class AttestationMessage;
-class SecretMessage;
+class MessageMsg0;
 
 // ===================================================================
 
-class InitialMessage : public ::google::protobuf::Message {
+class InitialMessage : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Messages.InitialMessage) */ {
  public:
   InitialMessage();
   virtual ~InitialMessage();
@@ -56,11 +58,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -70,7 +72,9 @@
 
   // implements Message ----------------------------------------------
 
-  InitialMessage* New() const;
+  inline InitialMessage* New() const { return New(NULL); }
+
+  InitialMessage* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const InitialMessage& from);
@@ -83,13 +87,26 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(InitialMessage* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -97,18 +114,18 @@
   // accessors -------------------------------------------------------
 
   // required uint32 type = 1;
-  inline bool has_type() const;
-  inline void clear_type();
+  bool has_type() const;
+  void clear_type();
   static const int kTypeFieldNumber = 1;
-  inline ::google::protobuf::uint32 type() const;
-  inline void set_type(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 type() const;
+  void set_type(::google::protobuf::uint32 value);
 
   // optional uint32 size = 2;
-  inline bool has_size() const;
-  inline void clear_size();
+  bool has_size() const;
+  void clear_size();
   static const int kSizeFieldNumber = 2;
-  inline ::google::protobuf::uint32 size() const;
-  inline void set_size(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 size() const;
+  void set_size(::google::protobuf::uint32 value);
 
   // @@protoc_insertion_point(class_scope:Messages.InitialMessage)
  private:
@@ -117,8 +134,7 @@
   inline void set_has_size();
   inline void clear_has_size();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::uint32 type_;
@@ -132,7 +148,7 @@
 };
 // -------------------------------------------------------------------
 
-class MessageMsg0 : public ::google::protobuf::Message {
+class MessageMsg0 : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Messages.MessageMsg0) */ {
  public:
   MessageMsg0();
   virtual ~MessageMsg0();
@@ -145,11 +161,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -159,7 +175,9 @@
 
   // implements Message ----------------------------------------------
 
-  MessageMsg0* New() const;
+  inline MessageMsg0* New() const { return New(NULL); }
+
+  MessageMsg0* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const MessageMsg0& from);
@@ -172,13 +190,26 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(MessageMsg0* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -186,25 +217,25 @@
   // accessors -------------------------------------------------------
 
   // required uint32 type = 1;
-  inline bool has_type() const;
-  inline void clear_type();
+  bool has_type() const;
+  void clear_type();
   static const int kTypeFieldNumber = 1;
-  inline ::google::protobuf::uint32 type() const;
-  inline void set_type(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 type() const;
+  void set_type(::google::protobuf::uint32 value);
 
   // required uint32 epid = 2;
-  inline bool has_epid() const;
-  inline void clear_epid();
+  bool has_epid() const;
+  void clear_epid();
   static const int kEpidFieldNumber = 2;
-  inline ::google::protobuf::uint32 epid() const;
-  inline void set_epid(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 epid() const;
+  void set_epid(::google::protobuf::uint32 value);
 
   // optional uint32 status = 3;
-  inline bool has_status() const;
-  inline void clear_status();
+  bool has_status() const;
+  void clear_status();
   static const int kStatusFieldNumber = 3;
-  inline ::google::protobuf::uint32 status() const;
-  inline void set_status(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 status() const;
+  void set_status(::google::protobuf::uint32 value);
 
   // @@protoc_insertion_point(class_scope:Messages.MessageMsg0)
  private:
@@ -215,8 +246,10 @@
   inline void set_has_status();
   inline void clear_has_status();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
+  // helper for ByteSize()
+  int RequiredFieldsByteSizeFallback() const;
 
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::uint32 type_;
@@ -231,7 +264,7 @@
 };
 // -------------------------------------------------------------------
 
-class MessageMSG1 : public ::google::protobuf::Message {
+class MessageMSG1 : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Messages.MessageMSG1) */ {
  public:
   MessageMSG1();
   virtual ~MessageMSG1();
@@ -244,11 +277,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -258,7 +291,9 @@
 
   // implements Message ----------------------------------------------
 
-  MessageMSG1* New() const;
+  inline MessageMSG1* New() const { return New(NULL); }
+
+  MessageMSG1* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const MessageMSG1& from);
@@ -271,13 +306,26 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(MessageMSG1* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -285,46 +333,46 @@
   // accessors -------------------------------------------------------
 
   // required uint32 type = 1;
-  inline bool has_type() const;
-  inline void clear_type();
+  bool has_type() const;
+  void clear_type();
   static const int kTypeFieldNumber = 1;
-  inline ::google::protobuf::uint32 type() const;
-  inline void set_type(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 type() const;
+  void set_type(::google::protobuf::uint32 value);
 
   // repeated uint32 GaX = 2 [packed = true];
-  inline int gax_size() const;
-  inline void clear_gax();
+  int gax_size() const;
+  void clear_gax();
   static const int kGaXFieldNumber = 2;
-  inline ::google::protobuf::uint32 gax(int index) const;
-  inline void set_gax(int index, ::google::protobuf::uint32 value);
-  inline void add_gax(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 gax(int index) const;
+  void set_gax(int index, ::google::protobuf::uint32 value);
+  void add_gax(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       gax() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_gax();
 
   // repeated uint32 GaY = 3 [packed = true];
-  inline int gay_size() const;
-  inline void clear_gay();
+  int gay_size() const;
+  void clear_gay();
   static const int kGaYFieldNumber = 3;
-  inline ::google::protobuf::uint32 gay(int index) const;
-  inline void set_gay(int index, ::google::protobuf::uint32 value);
-  inline void add_gay(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 gay(int index) const;
+  void set_gay(int index, ::google::protobuf::uint32 value);
+  void add_gay(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       gay() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_gay();
 
   // repeated uint32 GID = 4 [packed = true];
-  inline int gid_size() const;
-  inline void clear_gid();
+  int gid_size() const;
+  void clear_gid();
   static const int kGIDFieldNumber = 4;
-  inline ::google::protobuf::uint32 gid(int index) const;
-  inline void set_gid(int index, ::google::protobuf::uint32 value);
-  inline void add_gid(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 gid(int index) const;
+  void set_gid(int index, ::google::protobuf::uint32 value);
+  void add_gid(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       gid() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_gid();
 
   // @@protoc_insertion_point(class_scope:Messages.MessageMSG1)
@@ -332,8 +380,7 @@
   inline void set_has_type();
   inline void clear_has_type();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > gax_;
@@ -352,7 +399,7 @@
 };
 // -------------------------------------------------------------------
 
-class MessageMSG2 : public ::google::protobuf::Message {
+class MessageMSG2 : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Messages.MessageMSG2) */ {
  public:
   MessageMSG2();
   virtual ~MessageMSG2();
@@ -365,11 +412,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -379,7 +426,9 @@
 
   // implements Message ----------------------------------------------
 
-  MessageMSG2* New() const;
+  inline MessageMSG2* New() const { return New(NULL); }
+
+  MessageMSG2* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const MessageMSG2& from);
@@ -392,13 +441,26 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(MessageMSG2* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -406,122 +468,122 @@
   // accessors -------------------------------------------------------
 
   // required uint32 type = 1;
-  inline bool has_type() const;
-  inline void clear_type();
+  bool has_type() const;
+  void clear_type();
   static const int kTypeFieldNumber = 1;
-  inline ::google::protobuf::uint32 type() const;
-  inline void set_type(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 type() const;
+  void set_type(::google::protobuf::uint32 value);
 
   // optional uint32 size = 2;
-  inline bool has_size() const;
-  inline void clear_size();
+  bool has_size() const;
+  void clear_size();
   static const int kSizeFieldNumber = 2;
-  inline ::google::protobuf::uint32 size() const;
-  inline void set_size(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 size() const;
+  void set_size(::google::protobuf::uint32 value);
 
   // repeated uint32 public_key_gx = 3 [packed = true];
-  inline int public_key_gx_size() const;
-  inline void clear_public_key_gx();
+  int public_key_gx_size() const;
+  void clear_public_key_gx();
   static const int kPublicKeyGxFieldNumber = 3;
-  inline ::google::protobuf::uint32 public_key_gx(int index) const;
-  inline void set_public_key_gx(int index, ::google::protobuf::uint32 value);
-  inline void add_public_key_gx(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 public_key_gx(int index) const;
+  void set_public_key_gx(int index, ::google::protobuf::uint32 value);
+  void add_public_key_gx(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       public_key_gx() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_public_key_gx();
 
   // repeated uint32 public_key_gy = 4 [packed = true];
-  inline int public_key_gy_size() const;
-  inline void clear_public_key_gy();
+  int public_key_gy_size() const;
+  void clear_public_key_gy();
   static const int kPublicKeyGyFieldNumber = 4;
-  inline ::google::protobuf::uint32 public_key_gy(int index) const;
-  inline void set_public_key_gy(int index, ::google::protobuf::uint32 value);
-  inline void add_public_key_gy(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 public_key_gy(int index) const;
+  void set_public_key_gy(int index, ::google::protobuf::uint32 value);
+  void add_public_key_gy(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       public_key_gy() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_public_key_gy();
 
   // optional uint32 quote_type = 5;
-  inline bool has_quote_type() const;
-  inline void clear_quote_type();
+  bool has_quote_type() const;
+  void clear_quote_type();
   static const int kQuoteTypeFieldNumber = 5;
-  inline ::google::protobuf::uint32 quote_type() const;
-  inline void set_quote_type(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 quote_type() const;
+  void set_quote_type(::google::protobuf::uint32 value);
 
   // repeated uint32 spid = 6 [packed = true];
-  inline int spid_size() const;
-  inline void clear_spid();
+  int spid_size() const;
+  void clear_spid();
   static const int kSpidFieldNumber = 6;
-  inline ::google::protobuf::uint32 spid(int index) const;
-  inline void set_spid(int index, ::google::protobuf::uint32 value);
-  inline void add_spid(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 spid(int index) const;
+  void set_spid(int index, ::google::protobuf::uint32 value);
+  void add_spid(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       spid() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_spid();
 
   // optional uint32 cmac_kdf_id = 7;
-  inline bool has_cmac_kdf_id() const;
-  inline void clear_cmac_kdf_id();
+  bool has_cmac_kdf_id() const;
+  void clear_cmac_kdf_id();
   static const int kCmacKdfIdFieldNumber = 7;
-  inline ::google::protobuf::uint32 cmac_kdf_id() const;
-  inline void set_cmac_kdf_id(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 cmac_kdf_id() const;
+  void set_cmac_kdf_id(::google::protobuf::uint32 value);
 
   // repeated uint32 signature_x = 8 [packed = true];
-  inline int signature_x_size() const;
-  inline void clear_signature_x();
+  int signature_x_size() const;
+  void clear_signature_x();
   static const int kSignatureXFieldNumber = 8;
-  inline ::google::protobuf::uint32 signature_x(int index) const;
-  inline void set_signature_x(int index, ::google::protobuf::uint32 value);
-  inline void add_signature_x(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 signature_x(int index) const;
+  void set_signature_x(int index, ::google::protobuf::uint32 value);
+  void add_signature_x(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       signature_x() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_signature_x();
 
   // repeated uint32 signature_y = 9 [packed = true];
-  inline int signature_y_size() const;
-  inline void clear_signature_y();
+  int signature_y_size() const;
+  void clear_signature_y();
   static const int kSignatureYFieldNumber = 9;
-  inline ::google::protobuf::uint32 signature_y(int index) const;
-  inline void set_signature_y(int index, ::google::protobuf::uint32 value);
-  inline void add_signature_y(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 signature_y(int index) const;
+  void set_signature_y(int index, ::google::protobuf::uint32 value);
+  void add_signature_y(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       signature_y() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_signature_y();
 
   // repeated uint32 smac = 10 [packed = true];
-  inline int smac_size() const;
-  inline void clear_smac();
+  int smac_size() const;
+  void clear_smac();
   static const int kSmacFieldNumber = 10;
-  inline ::google::protobuf::uint32 smac(int index) const;
-  inline void set_smac(int index, ::google::protobuf::uint32 value);
-  inline void add_smac(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 smac(int index) const;
+  void set_smac(int index, ::google::protobuf::uint32 value);
+  void add_smac(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       smac() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_smac();
 
   // optional uint32 size_sigrl = 11;
-  inline bool has_size_sigrl() const;
-  inline void clear_size_sigrl();
+  bool has_size_sigrl() const;
+  void clear_size_sigrl();
   static const int kSizeSigrlFieldNumber = 11;
-  inline ::google::protobuf::uint32 size_sigrl() const;
-  inline void set_size_sigrl(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 size_sigrl() const;
+  void set_size_sigrl(::google::protobuf::uint32 value);
 
   // repeated uint32 sigrl = 12 [packed = true];
-  inline int sigrl_size() const;
-  inline void clear_sigrl();
+  int sigrl_size() const;
+  void clear_sigrl();
   static const int kSigrlFieldNumber = 12;
-  inline ::google::protobuf::uint32 sigrl(int index) const;
-  inline void set_sigrl(int index, ::google::protobuf::uint32 value);
-  inline void add_sigrl(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 sigrl(int index) const;
+  void set_sigrl(int index, ::google::protobuf::uint32 value);
+  void add_sigrl(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       sigrl() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_sigrl();
 
   // @@protoc_insertion_point(class_scope:Messages.MessageMSG2)
@@ -537,8 +599,7 @@
   inline void set_has_size_sigrl();
   inline void clear_has_size_sigrl();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::uint32 type_;
@@ -569,7 +630,7 @@
 };
 // -------------------------------------------------------------------
 
-class MessageMSG3 : public ::google::protobuf::Message {
+class MessageMSG3 : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Messages.MessageMSG3) */ {
  public:
   MessageMSG3();
   virtual ~MessageMSG3();
@@ -582,11 +643,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -596,7 +657,9 @@
 
   // implements Message ----------------------------------------------
 
-  MessageMSG3* New() const;
+  inline MessageMSG3* New() const { return New(NULL); }
+
+  MessageMSG3* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const MessageMSG3& from);
@@ -609,13 +672,26 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(MessageMSG3* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -623,77 +699,77 @@
   // accessors -------------------------------------------------------
 
   // required uint32 type = 1;
-  inline bool has_type() const;
-  inline void clear_type();
+  bool has_type() const;
+  void clear_type();
   static const int kTypeFieldNumber = 1;
-  inline ::google::protobuf::uint32 type() const;
-  inline void set_type(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 type() const;
+  void set_type(::google::protobuf::uint32 value);
 
   // optional uint32 size = 2;
-  inline bool has_size() const;
-  inline void clear_size();
+  bool has_size() const;
+  void clear_size();
   static const int kSizeFieldNumber = 2;
-  inline ::google::protobuf::uint32 size() const;
-  inline void set_size(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 size() const;
+  void set_size(::google::protobuf::uint32 value);
 
   // repeated uint32 sgx_mac = 3 [packed = true];
-  inline int sgx_mac_size() const;
-  inline void clear_sgx_mac();
+  int sgx_mac_size() const;
+  void clear_sgx_mac();
   static const int kSgxMacFieldNumber = 3;
-  inline ::google::protobuf::uint32 sgx_mac(int index) const;
-  inline void set_sgx_mac(int index, ::google::protobuf::uint32 value);
-  inline void add_sgx_mac(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 sgx_mac(int index) const;
+  void set_sgx_mac(int index, ::google::protobuf::uint32 value);
+  void add_sgx_mac(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       sgx_mac() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_sgx_mac();
 
   // repeated uint32 gax_msg3 = 4 [packed = true];
-  inline int gax_msg3_size() const;
-  inline void clear_gax_msg3();
+  int gax_msg3_size() const;
+  void clear_gax_msg3();
   static const int kGaxMsg3FieldNumber = 4;
-  inline ::google::protobuf::uint32 gax_msg3(int index) const;
-  inline void set_gax_msg3(int index, ::google::protobuf::uint32 value);
-  inline void add_gax_msg3(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 gax_msg3(int index) const;
+  void set_gax_msg3(int index, ::google::protobuf::uint32 value);
+  void add_gax_msg3(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       gax_msg3() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_gax_msg3();
 
   // repeated uint32 gay_msg3 = 5 [packed = true];
-  inline int gay_msg3_size() const;
-  inline void clear_gay_msg3();
+  int gay_msg3_size() const;
+  void clear_gay_msg3();
   static const int kGayMsg3FieldNumber = 5;
-  inline ::google::protobuf::uint32 gay_msg3(int index) const;
-  inline void set_gay_msg3(int index, ::google::protobuf::uint32 value);
-  inline void add_gay_msg3(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 gay_msg3(int index) const;
+  void set_gay_msg3(int index, ::google::protobuf::uint32 value);
+  void add_gay_msg3(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       gay_msg3() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_gay_msg3();
 
   // repeated uint32 sec_property = 6 [packed = true];
-  inline int sec_property_size() const;
-  inline void clear_sec_property();
+  int sec_property_size() const;
+  void clear_sec_property();
   static const int kSecPropertyFieldNumber = 6;
-  inline ::google::protobuf::uint32 sec_property(int index) const;
-  inline void set_sec_property(int index, ::google::protobuf::uint32 value);
-  inline void add_sec_property(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 sec_property(int index) const;
+  void set_sec_property(int index, ::google::protobuf::uint32 value);
+  void add_sec_property(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       sec_property() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_sec_property();
 
   // repeated uint32 quote = 7 [packed = true];
-  inline int quote_size() const;
-  inline void clear_quote();
+  int quote_size() const;
+  void clear_quote();
   static const int kQuoteFieldNumber = 7;
-  inline ::google::protobuf::uint32 quote(int index) const;
-  inline void set_quote(int index, ::google::protobuf::uint32 value);
-  inline void add_quote(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 quote(int index) const;
+  void set_quote(int index, ::google::protobuf::uint32 value);
+  void add_quote(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       quote() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_quote();
 
   // @@protoc_insertion_point(class_scope:Messages.MessageMSG3)
@@ -703,8 +779,7 @@
   inline void set_has_size();
   inline void clear_has_size();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::uint32 type_;
@@ -728,7 +803,7 @@
 };
 // -------------------------------------------------------------------
 
-class AttestationMessage : public ::google::protobuf::Message {
+class AttestationMessage : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Messages.AttestationMessage) */ {
  public:
   AttestationMessage();
   virtual ~AttestationMessage();
@@ -741,11 +816,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -755,7 +830,9 @@
 
   // implements Message ----------------------------------------------
 
-  AttestationMessage* New() const;
+  inline AttestationMessage* New() const { return New(NULL); }
+
+  AttestationMessage* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const AttestationMessage& from);
@@ -768,13 +845,26 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(AttestationMessage* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -782,165 +872,165 @@
   // accessors -------------------------------------------------------
 
   // required uint32 type = 1;
-  inline bool has_type() const;
-  inline void clear_type();
+  bool has_type() const;
+  void clear_type();
   static const int kTypeFieldNumber = 1;
-  inline ::google::protobuf::uint32 type() const;
-  inline void set_type(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 type() const;
+  void set_type(::google::protobuf::uint32 value);
 
   // required uint32 size = 2;
-  inline bool has_size() const;
-  inline void clear_size();
+  bool has_size() const;
+  void clear_size();
   static const int kSizeFieldNumber = 2;
-  inline ::google::protobuf::uint32 size() const;
-  inline void set_size(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 size() const;
+  void set_size(::google::protobuf::uint32 value);
 
   // optional uint32 epid_group_status = 3;
-  inline bool has_epid_group_status() const;
-  inline void clear_epid_group_status();
+  bool has_epid_group_status() const;
+  void clear_epid_group_status();
   static const int kEpidGroupStatusFieldNumber = 3;
-  inline ::google::protobuf::uint32 epid_group_status() const;
-  inline void set_epid_group_status(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 epid_group_status() const;
+  void set_epid_group_status(::google::protobuf::uint32 value);
 
   // optional uint32 tcb_evaluation_status = 4;
-  inline bool has_tcb_evaluation_status() const;
-  inline void clear_tcb_evaluation_status();
+  bool has_tcb_evaluation_status() const;
+  void clear_tcb_evaluation_status();
   static const int kTcbEvaluationStatusFieldNumber = 4;
-  inline ::google::protobuf::uint32 tcb_evaluation_status() const;
-  inline void set_tcb_evaluation_status(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 tcb_evaluation_status() const;
+  void set_tcb_evaluation_status(::google::protobuf::uint32 value);
 
   // optional uint32 pse_evaluation_status = 5;
-  inline bool has_pse_evaluation_status() const;
-  inline void clear_pse_evaluation_status();
+  bool has_pse_evaluation_status() const;
+  void clear_pse_evaluation_status();
   static const int kPseEvaluationStatusFieldNumber = 5;
-  inline ::google::protobuf::uint32 pse_evaluation_status() const;
-  inline void set_pse_evaluation_status(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 pse_evaluation_status() const;
+  void set_pse_evaluation_status(::google::protobuf::uint32 value);
 
   // repeated uint32 latest_equivalent_tcb_psvn = 6 [packed = true];
-  inline int latest_equivalent_tcb_psvn_size() const;
-  inline void clear_latest_equivalent_tcb_psvn();
+  int latest_equivalent_tcb_psvn_size() const;
+  void clear_latest_equivalent_tcb_psvn();
   static const int kLatestEquivalentTcbPsvnFieldNumber = 6;
-  inline ::google::protobuf::uint32 latest_equivalent_tcb_psvn(int index) const;
-  inline void set_latest_equivalent_tcb_psvn(int index, ::google::protobuf::uint32 value);
-  inline void add_latest_equivalent_tcb_psvn(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 latest_equivalent_tcb_psvn(int index) const;
+  void set_latest_equivalent_tcb_psvn(int index, ::google::protobuf::uint32 value);
+  void add_latest_equivalent_tcb_psvn(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       latest_equivalent_tcb_psvn() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_latest_equivalent_tcb_psvn();
 
   // repeated uint32 latest_pse_isvsvn = 7 [packed = true];
-  inline int latest_pse_isvsvn_size() const;
-  inline void clear_latest_pse_isvsvn();
+  int latest_pse_isvsvn_size() const;
+  void clear_latest_pse_isvsvn();
   static const int kLatestPseIsvsvnFieldNumber = 7;
-  inline ::google::protobuf::uint32 latest_pse_isvsvn(int index) const;
-  inline void set_latest_pse_isvsvn(int index, ::google::protobuf::uint32 value);
-  inline void add_latest_pse_isvsvn(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 latest_pse_isvsvn(int index) const;
+  void set_latest_pse_isvsvn(int index, ::google::protobuf::uint32 value);
+  void add_latest_pse_isvsvn(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       latest_pse_isvsvn() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_latest_pse_isvsvn();
 
   // repeated uint32 latest_psda_svn = 8 [packed = true];
-  inline int latest_psda_svn_size() const;
-  inline void clear_latest_psda_svn();
+  int latest_psda_svn_size() const;
+  void clear_latest_psda_svn();
   static const int kLatestPsdaSvnFieldNumber = 8;
-  inline ::google::protobuf::uint32 latest_psda_svn(int index) const;
-  inline void set_latest_psda_svn(int index, ::google::protobuf::uint32 value);
-  inline void add_latest_psda_svn(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 latest_psda_svn(int index) const;
+  void set_latest_psda_svn(int index, ::google::protobuf::uint32 value);
+  void add_latest_psda_svn(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       latest_psda_svn() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_latest_psda_svn();
 
   // repeated uint32 performance_rekey_gid = 9 [packed = true];
-  inline int performance_rekey_gid_size() const;
-  inline void clear_performance_rekey_gid();
+  int performance_rekey_gid_size() const;
+  void clear_performance_rekey_gid();
   static const int kPerformanceRekeyGidFieldNumber = 9;
-  inline ::google::protobuf::uint32 performance_rekey_gid(int index) const;
-  inline void set_performance_rekey_gid(int index, ::google::protobuf::uint32 value);
-  inline void add_performance_rekey_gid(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 performance_rekey_gid(int index) const;
+  void set_performance_rekey_gid(int index, ::google::protobuf::uint32 value);
+  void add_performance_rekey_gid(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       performance_rekey_gid() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_performance_rekey_gid();
 
   // repeated uint32 ec_sign256_x = 10 [packed = true];
-  inline int ec_sign256_x_size() const;
-  inline void clear_ec_sign256_x();
+  int ec_sign256_x_size() const;
+  void clear_ec_sign256_x();
   static const int kEcSign256XFieldNumber = 10;
-  inline ::google::protobuf::uint32 ec_sign256_x(int index) const;
-  inline void set_ec_sign256_x(int index, ::google::protobuf::uint32 value);
-  inline void add_ec_sign256_x(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 ec_sign256_x(int index) const;
+  void set_ec_sign256_x(int index, ::google::protobuf::uint32 value);
+  void add_ec_sign256_x(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       ec_sign256_x() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_ec_sign256_x();
 
   // repeated uint32 ec_sign256_y = 11 [packed = true];
-  inline int ec_sign256_y_size() const;
-  inline void clear_ec_sign256_y();
+  int ec_sign256_y_size() const;
+  void clear_ec_sign256_y();
   static const int kEcSign256YFieldNumber = 11;
-  inline ::google::protobuf::uint32 ec_sign256_y(int index) const;
-  inline void set_ec_sign256_y(int index, ::google::protobuf::uint32 value);
-  inline void add_ec_sign256_y(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 ec_sign256_y(int index) const;
+  void set_ec_sign256_y(int index, ::google::protobuf::uint32 value);
+  void add_ec_sign256_y(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       ec_sign256_y() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_ec_sign256_y();
 
   // repeated uint32 mac_smk = 12 [packed = true];
-  inline int mac_smk_size() const;
-  inline void clear_mac_smk();
+  int mac_smk_size() const;
+  void clear_mac_smk();
   static const int kMacSmkFieldNumber = 12;
-  inline ::google::protobuf::uint32 mac_smk(int index) const;
-  inline void set_mac_smk(int index, ::google::protobuf::uint32 value);
-  inline void add_mac_smk(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 mac_smk(int index) const;
+  void set_mac_smk(int index, ::google::protobuf::uint32 value);
+  void add_mac_smk(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       mac_smk() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_mac_smk();
 
   // optional uint32 result_size = 13;
-  inline bool has_result_size() const;
-  inline void clear_result_size();
+  bool has_result_size() const;
+  void clear_result_size();
   static const int kResultSizeFieldNumber = 13;
-  inline ::google::protobuf::uint32 result_size() const;
-  inline void set_result_size(::google::protobuf::uint32 value);
+  ::google::protobuf::uint32 result_size() const;
+  void set_result_size(::google::protobuf::uint32 value);
 
   // repeated uint32 reserved = 14 [packed = true];
-  inline int reserved_size() const;
-  inline void clear_reserved();
+  int reserved_size() const;
+  void clear_reserved();
   static const int kReservedFieldNumber = 14;
-  inline ::google::protobuf::uint32 reserved(int index) const;
-  inline void set_reserved(int index, ::google::protobuf::uint32 value);
-  inline void add_reserved(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 reserved(int index) const;
+  void set_reserved(int index, ::google::protobuf::uint32 value);
+  void add_reserved(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       reserved() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_reserved();
 
   // repeated uint32 payload_tag = 15 [packed = true];
-  inline int payload_tag_size() const;
-  inline void clear_payload_tag();
+  int payload_tag_size() const;
+  void clear_payload_tag();
   static const int kPayloadTagFieldNumber = 15;
-  inline ::google::protobuf::uint32 payload_tag(int index) const;
-  inline void set_payload_tag(int index, ::google::protobuf::uint32 value);
-  inline void add_payload_tag(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 payload_tag(int index) const;
+  void set_payload_tag(int index, ::google::protobuf::uint32 value);
+  void add_payload_tag(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       payload_tag() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_payload_tag();
 
   // repeated uint32 payload = 16 [packed = true];
-  inline int payload_size() const;
-  inline void clear_payload();
+  int payload_size() const;
+  void clear_payload();
   static const int kPayloadFieldNumber = 16;
-  inline ::google::protobuf::uint32 payload(int index) const;
-  inline void set_payload(int index, ::google::protobuf::uint32 value);
-  inline void add_payload(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+  ::google::protobuf::uint32 payload(int index) const;
+  void set_payload(int index, ::google::protobuf::uint32 value);
+  void add_payload(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
       payload() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
       mutable_payload();
 
   // @@protoc_insertion_point(class_scope:Messages.AttestationMessage)
@@ -958,8 +1048,10 @@
   inline void set_has_result_size();
   inline void clear_has_result_size();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
+  // helper for ByteSize()
+  int RequiredFieldsByteSizeFallback() const;
 
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::uint32 type_;
@@ -995,204 +1087,12 @@
   void InitAsDefaultInstance();
   static AttestationMessage* default_instance_;
 };
-// -------------------------------------------------------------------
-
-class SecretMessage : public ::google::protobuf::Message {
- public:
-  SecretMessage();
-  virtual ~SecretMessage();
-
-  SecretMessage(const SecretMessage& from);
-
-  inline SecretMessage& operator=(const SecretMessage& from) {
-    CopyFrom(from);
-    return *this;
-  }
-
-  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
-  }
-
-  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
-  }
-
-  static const ::google::protobuf::Descriptor* descriptor();
-  static const SecretMessage& default_instance();
-
-  void Swap(SecretMessage* other);
-
-  // implements Message ----------------------------------------------
-
-  SecretMessage* New() const;
-  void CopyFrom(const ::google::protobuf::Message& from);
-  void MergeFrom(const ::google::protobuf::Message& from);
-  void CopyFrom(const SecretMessage& from);
-  void MergeFrom(const SecretMessage& from);
-  void Clear();
-  bool IsInitialized() const;
-
-  int ByteSize() const;
-  bool MergePartialFromCodedStream(
-      ::google::protobuf::io::CodedInputStream* input);
-  void SerializeWithCachedSizes(
-      ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
-  int GetCachedSize() const { return _cached_size_; }
-  private:
-  void SharedCtor();
-  void SharedDtor();
-  void SetCachedSize(int size) const;
-  public:
-  ::google::protobuf::Metadata GetMetadata() const;
-
-  // nested types ----------------------------------------------------
-
-  // accessors -------------------------------------------------------
-
-  // required uint32 type = 1;
-  inline bool has_type() const;
-  inline void clear_type();
-  static const int kTypeFieldNumber = 1;
-  inline ::google::protobuf::uint32 type() const;
-  inline void set_type(::google::protobuf::uint32 value);
-
-  // required uint32 size = 2;
-  inline bool has_size() const;
-  inline void clear_size();
-  static const int kSizeFieldNumber = 2;
-  inline ::google::protobuf::uint32 size() const;
-  inline void set_size(::google::protobuf::uint32 value);
-
-  // optional uint32 encryped_pkey_size = 3;
-  inline bool has_encryped_pkey_size() const;
-  inline void clear_encryped_pkey_size();
-  static const int kEncrypedPkeySizeFieldNumber = 3;
-  inline ::google::protobuf::uint32 encryped_pkey_size() const;
-  inline void set_encryped_pkey_size(::google::protobuf::uint32 value);
-
-  // optional uint32 encryped_x509_size = 4;
-  inline bool has_encryped_x509_size() const;
-  inline void clear_encryped_x509_size();
-  static const int kEncrypedX509SizeFieldNumber = 4;
-  inline ::google::protobuf::uint32 encryped_x509_size() const;
-  inline void set_encryped_x509_size(::google::protobuf::uint32 value);
-
-  // repeated uint32 encrypted_content = 5 [packed = true];
-  inline int encrypted_content_size() const;
-  inline void clear_encrypted_content();
-  static const int kEncryptedContentFieldNumber = 5;
-  inline ::google::protobuf::uint32 encrypted_content(int index) const;
-  inline void set_encrypted_content(int index, ::google::protobuf::uint32 value);
-  inline void add_encrypted_content(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-      encrypted_content() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-      mutable_encrypted_content();
-
-  // repeated uint32 mac_smk = 6 [packed = true];
-  inline int mac_smk_size() const;
-  inline void clear_mac_smk();
-  static const int kMacSmkFieldNumber = 6;
-  inline ::google::protobuf::uint32 mac_smk(int index) const;
-  inline void set_mac_smk(int index, ::google::protobuf::uint32 value);
-  inline void add_mac_smk(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-      mac_smk() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-      mutable_mac_smk();
-
-  // repeated uint32 encrypted_pkey = 7 [packed = true];
-  inline int encrypted_pkey_size() const;
-  inline void clear_encrypted_pkey();
-  static const int kEncryptedPkeyFieldNumber = 7;
-  inline ::google::protobuf::uint32 encrypted_pkey(int index) const;
-  inline void set_encrypted_pkey(int index, ::google::protobuf::uint32 value);
-  inline void add_encrypted_pkey(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-      encrypted_pkey() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-      mutable_encrypted_pkey();
-
-  // repeated uint32 encrypted_pkey_mac_smk = 8 [packed = true];
-  inline int encrypted_pkey_mac_smk_size() const;
-  inline void clear_encrypted_pkey_mac_smk();
-  static const int kEncryptedPkeyMacSmkFieldNumber = 8;
-  inline ::google::protobuf::uint32 encrypted_pkey_mac_smk(int index) const;
-  inline void set_encrypted_pkey_mac_smk(int index, ::google::protobuf::uint32 value);
-  inline void add_encrypted_pkey_mac_smk(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-      encrypted_pkey_mac_smk() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-      mutable_encrypted_pkey_mac_smk();
-
-  // repeated uint32 encrypted_x509 = 9 [packed = true];
-  inline int encrypted_x509_size() const;
-  inline void clear_encrypted_x509();
-  static const int kEncryptedX509FieldNumber = 9;
-  inline ::google::protobuf::uint32 encrypted_x509(int index) const;
-  inline void set_encrypted_x509(int index, ::google::protobuf::uint32 value);
-  inline void add_encrypted_x509(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-      encrypted_x509() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-      mutable_encrypted_x509();
-
-  // repeated uint32 encrypted_x509_mac_smk = 10 [packed = true];
-  inline int encrypted_x509_mac_smk_size() const;
-  inline void clear_encrypted_x509_mac_smk();
-  static const int kEncryptedX509MacSmkFieldNumber = 10;
-  inline ::google::protobuf::uint32 encrypted_x509_mac_smk(int index) const;
-  inline void set_encrypted_x509_mac_smk(int index, ::google::protobuf::uint32 value);
-  inline void add_encrypted_x509_mac_smk(::google::protobuf::uint32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-      encrypted_x509_mac_smk() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-      mutable_encrypted_x509_mac_smk();
-
-  // @@protoc_insertion_point(class_scope:Messages.SecretMessage)
- private:
-  inline void set_has_type();
-  inline void clear_has_type();
-  inline void set_has_size();
-  inline void clear_has_size();
-  inline void set_has_encryped_pkey_size();
-  inline void clear_has_encryped_pkey_size();
-  inline void set_has_encryped_x509_size();
-  inline void clear_has_encryped_x509_size();
-
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
-  ::google::protobuf::uint32 _has_bits_[1];
-  mutable int _cached_size_;
-  ::google::protobuf::uint32 type_;
-  ::google::protobuf::uint32 size_;
-  ::google::protobuf::uint32 encryped_pkey_size_;
-  ::google::protobuf::uint32 encryped_x509_size_;
-  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > encrypted_content_;
-  mutable int _encrypted_content_cached_byte_size_;
-  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > mac_smk_;
-  mutable int _mac_smk_cached_byte_size_;
-  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > encrypted_pkey_;
-  mutable int _encrypted_pkey_cached_byte_size_;
-  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > encrypted_pkey_mac_smk_;
-  mutable int _encrypted_pkey_mac_smk_cached_byte_size_;
-  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > encrypted_x509_;
-  mutable int _encrypted_x509_cached_byte_size_;
-  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > encrypted_x509_mac_smk_;
-  mutable int _encrypted_x509_mac_smk_cached_byte_size_;
-  friend void  protobuf_AddDesc_Messages_2eproto();
-  friend void protobuf_AssignDesc_Messages_2eproto();
-  friend void protobuf_ShutdownFile_Messages_2eproto();
-
-  void InitAsDefaultInstance();
-  static SecretMessage* default_instance_;
-};
 // ===================================================================
 
 
 // ===================================================================
 
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
 // InitialMessage
 
 // required uint32 type = 1;
@@ -2421,300 +2321,22 @@
   return &payload_;
 }
 
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
 // -------------------------------------------------------------------
 
-// SecretMessage
+// -------------------------------------------------------------------
 
-// required uint32 type = 1;
-inline bool SecretMessage::has_type() const {
-  return (_has_bits_[0] & 0x00000001u) != 0;
-}
-inline void SecretMessage::set_has_type() {
-  _has_bits_[0] |= 0x00000001u;
-}
-inline void SecretMessage::clear_has_type() {
-  _has_bits_[0] &= ~0x00000001u;
-}
-inline void SecretMessage::clear_type() {
-  type_ = 0u;
-  clear_has_type();
-}
-inline ::google::protobuf::uint32 SecretMessage::type() const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.type)
-  return type_;
-}
-inline void SecretMessage::set_type(::google::protobuf::uint32 value) {
-  set_has_type();
-  type_ = value;
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.type)
-}
+// -------------------------------------------------------------------
 
-// required uint32 size = 2;
-inline bool SecretMessage::has_size() const {
-  return (_has_bits_[0] & 0x00000002u) != 0;
-}
-inline void SecretMessage::set_has_size() {
-  _has_bits_[0] |= 0x00000002u;
-}
-inline void SecretMessage::clear_has_size() {
-  _has_bits_[0] &= ~0x00000002u;
-}
-inline void SecretMessage::clear_size() {
-  size_ = 0u;
-  clear_has_size();
-}
-inline ::google::protobuf::uint32 SecretMessage::size() const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.size)
-  return size_;
-}
-inline void SecretMessage::set_size(::google::protobuf::uint32 value) {
-  set_has_size();
-  size_ = value;
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.size)
-}
+// -------------------------------------------------------------------
 
-// optional uint32 encryped_pkey_size = 3;
-inline bool SecretMessage::has_encryped_pkey_size() const {
-  return (_has_bits_[0] & 0x00000004u) != 0;
-}
-inline void SecretMessage::set_has_encryped_pkey_size() {
-  _has_bits_[0] |= 0x00000004u;
-}
-inline void SecretMessage::clear_has_encryped_pkey_size() {
-  _has_bits_[0] &= ~0x00000004u;
-}
-inline void SecretMessage::clear_encryped_pkey_size() {
-  encryped_pkey_size_ = 0u;
-  clear_has_encryped_pkey_size();
-}
-inline ::google::protobuf::uint32 SecretMessage::encryped_pkey_size() const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.encryped_pkey_size)
-  return encryped_pkey_size_;
-}
-inline void SecretMessage::set_encryped_pkey_size(::google::protobuf::uint32 value) {
-  set_has_encryped_pkey_size();
-  encryped_pkey_size_ = value;
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.encryped_pkey_size)
-}
-
-// optional uint32 encryped_x509_size = 4;
-inline bool SecretMessage::has_encryped_x509_size() const {
-  return (_has_bits_[0] & 0x00000008u) != 0;
-}
-inline void SecretMessage::set_has_encryped_x509_size() {
-  _has_bits_[0] |= 0x00000008u;
-}
-inline void SecretMessage::clear_has_encryped_x509_size() {
-  _has_bits_[0] &= ~0x00000008u;
-}
-inline void SecretMessage::clear_encryped_x509_size() {
-  encryped_x509_size_ = 0u;
-  clear_has_encryped_x509_size();
-}
-inline ::google::protobuf::uint32 SecretMessage::encryped_x509_size() const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.encryped_x509_size)
-  return encryped_x509_size_;
-}
-inline void SecretMessage::set_encryped_x509_size(::google::protobuf::uint32 value) {
-  set_has_encryped_x509_size();
-  encryped_x509_size_ = value;
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.encryped_x509_size)
-}
-
-// repeated uint32 encrypted_content = 5 [packed = true];
-inline int SecretMessage::encrypted_content_size() const {
-  return encrypted_content_.size();
-}
-inline void SecretMessage::clear_encrypted_content() {
-  encrypted_content_.Clear();
-}
-inline ::google::protobuf::uint32 SecretMessage::encrypted_content(int index) const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.encrypted_content)
-  return encrypted_content_.Get(index);
-}
-inline void SecretMessage::set_encrypted_content(int index, ::google::protobuf::uint32 value) {
-  encrypted_content_.Set(index, value);
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.encrypted_content)
-}
-inline void SecretMessage::add_encrypted_content(::google::protobuf::uint32 value) {
-  encrypted_content_.Add(value);
-  // @@protoc_insertion_point(field_add:Messages.SecretMessage.encrypted_content)
-}
-inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-SecretMessage::encrypted_content() const {
-  // @@protoc_insertion_point(field_list:Messages.SecretMessage.encrypted_content)
-  return encrypted_content_;
-}
-inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-SecretMessage::mutable_encrypted_content() {
-  // @@protoc_insertion_point(field_mutable_list:Messages.SecretMessage.encrypted_content)
-  return &encrypted_content_;
-}
-
-// repeated uint32 mac_smk = 6 [packed = true];
-inline int SecretMessage::mac_smk_size() const {
-  return mac_smk_.size();
-}
-inline void SecretMessage::clear_mac_smk() {
-  mac_smk_.Clear();
-}
-inline ::google::protobuf::uint32 SecretMessage::mac_smk(int index) const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.mac_smk)
-  return mac_smk_.Get(index);
-}
-inline void SecretMessage::set_mac_smk(int index, ::google::protobuf::uint32 value) {
-  mac_smk_.Set(index, value);
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.mac_smk)
-}
-inline void SecretMessage::add_mac_smk(::google::protobuf::uint32 value) {
-  mac_smk_.Add(value);
-  // @@protoc_insertion_point(field_add:Messages.SecretMessage.mac_smk)
-}
-inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-SecretMessage::mac_smk() const {
-  // @@protoc_insertion_point(field_list:Messages.SecretMessage.mac_smk)
-  return mac_smk_;
-}
-inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-SecretMessage::mutable_mac_smk() {
-  // @@protoc_insertion_point(field_mutable_list:Messages.SecretMessage.mac_smk)
-  return &mac_smk_;
-}
-
-// repeated uint32 encrypted_pkey = 7 [packed = true];
-inline int SecretMessage::encrypted_pkey_size() const {
-  return encrypted_pkey_.size();
-}
-inline void SecretMessage::clear_encrypted_pkey() {
-  encrypted_pkey_.Clear();
-}
-inline ::google::protobuf::uint32 SecretMessage::encrypted_pkey(int index) const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.encrypted_pkey)
-  return encrypted_pkey_.Get(index);
-}
-inline void SecretMessage::set_encrypted_pkey(int index, ::google::protobuf::uint32 value) {
-  encrypted_pkey_.Set(index, value);
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.encrypted_pkey)
-}
-inline void SecretMessage::add_encrypted_pkey(::google::protobuf::uint32 value) {
-  encrypted_pkey_.Add(value);
-  // @@protoc_insertion_point(field_add:Messages.SecretMessage.encrypted_pkey)
-}
-inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-SecretMessage::encrypted_pkey() const {
-  // @@protoc_insertion_point(field_list:Messages.SecretMessage.encrypted_pkey)
-  return encrypted_pkey_;
-}
-inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-SecretMessage::mutable_encrypted_pkey() {
-  // @@protoc_insertion_point(field_mutable_list:Messages.SecretMessage.encrypted_pkey)
-  return &encrypted_pkey_;
-}
-
-// repeated uint32 encrypted_pkey_mac_smk = 8 [packed = true];
-inline int SecretMessage::encrypted_pkey_mac_smk_size() const {
-  return encrypted_pkey_mac_smk_.size();
-}
-inline void SecretMessage::clear_encrypted_pkey_mac_smk() {
-  encrypted_pkey_mac_smk_.Clear();
-}
-inline ::google::protobuf::uint32 SecretMessage::encrypted_pkey_mac_smk(int index) const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.encrypted_pkey_mac_smk)
-  return encrypted_pkey_mac_smk_.Get(index);
-}
-inline void SecretMessage::set_encrypted_pkey_mac_smk(int index, ::google::protobuf::uint32 value) {
-  encrypted_pkey_mac_smk_.Set(index, value);
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.encrypted_pkey_mac_smk)
-}
-inline void SecretMessage::add_encrypted_pkey_mac_smk(::google::protobuf::uint32 value) {
-  encrypted_pkey_mac_smk_.Add(value);
-  // @@protoc_insertion_point(field_add:Messages.SecretMessage.encrypted_pkey_mac_smk)
-}
-inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-SecretMessage::encrypted_pkey_mac_smk() const {
-  // @@protoc_insertion_point(field_list:Messages.SecretMessage.encrypted_pkey_mac_smk)
-  return encrypted_pkey_mac_smk_;
-}
-inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-SecretMessage::mutable_encrypted_pkey_mac_smk() {
-  // @@protoc_insertion_point(field_mutable_list:Messages.SecretMessage.encrypted_pkey_mac_smk)
-  return &encrypted_pkey_mac_smk_;
-}
-
-// repeated uint32 encrypted_x509 = 9 [packed = true];
-inline int SecretMessage::encrypted_x509_size() const {
-  return encrypted_x509_.size();
-}
-inline void SecretMessage::clear_encrypted_x509() {
-  encrypted_x509_.Clear();
-}
-inline ::google::protobuf::uint32 SecretMessage::encrypted_x509(int index) const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.encrypted_x509)
-  return encrypted_x509_.Get(index);
-}
-inline void SecretMessage::set_encrypted_x509(int index, ::google::protobuf::uint32 value) {
-  encrypted_x509_.Set(index, value);
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.encrypted_x509)
-}
-inline void SecretMessage::add_encrypted_x509(::google::protobuf::uint32 value) {
-  encrypted_x509_.Add(value);
-  // @@protoc_insertion_point(field_add:Messages.SecretMessage.encrypted_x509)
-}
-inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-SecretMessage::encrypted_x509() const {
-  // @@protoc_insertion_point(field_list:Messages.SecretMessage.encrypted_x509)
-  return encrypted_x509_;
-}
-inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-SecretMessage::mutable_encrypted_x509() {
-  // @@protoc_insertion_point(field_mutable_list:Messages.SecretMessage.encrypted_x509)
-  return &encrypted_x509_;
-}
-
-// repeated uint32 encrypted_x509_mac_smk = 10 [packed = true];
-inline int SecretMessage::encrypted_x509_mac_smk_size() const {
-  return encrypted_x509_mac_smk_.size();
-}
-inline void SecretMessage::clear_encrypted_x509_mac_smk() {
-  encrypted_x509_mac_smk_.Clear();
-}
-inline ::google::protobuf::uint32 SecretMessage::encrypted_x509_mac_smk(int index) const {
-  // @@protoc_insertion_point(field_get:Messages.SecretMessage.encrypted_x509_mac_smk)
-  return encrypted_x509_mac_smk_.Get(index);
-}
-inline void SecretMessage::set_encrypted_x509_mac_smk(int index, ::google::protobuf::uint32 value) {
-  encrypted_x509_mac_smk_.Set(index, value);
-  // @@protoc_insertion_point(field_set:Messages.SecretMessage.encrypted_x509_mac_smk)
-}
-inline void SecretMessage::add_encrypted_x509_mac_smk(::google::protobuf::uint32 value) {
-  encrypted_x509_mac_smk_.Add(value);
-  // @@protoc_insertion_point(field_add:Messages.SecretMessage.encrypted_x509_mac_smk)
-}
-inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
-SecretMessage::encrypted_x509_mac_smk() const {
-  // @@protoc_insertion_point(field_list:Messages.SecretMessage.encrypted_x509_mac_smk)
-  return encrypted_x509_mac_smk_;
-}
-inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
-SecretMessage::mutable_encrypted_x509_mac_smk() {
-  // @@protoc_insertion_point(field_mutable_list:Messages.SecretMessage.encrypted_x509_mac_smk)
-  return &encrypted_x509_mac_smk_;
-}
+// -------------------------------------------------------------------
 
 
 // @@protoc_insertion_point(namespace_scope)
 
 }  // namespace Messages
 
-#ifndef SWIG
-namespace google {
-namespace protobuf {
-
-
-}  // namespace google
-}  // namespace protobuf
-#endif  // SWIG
-
 // @@protoc_insertion_point(global_scope)
 
 #endif  // PROTOBUF_Messages_2eproto__INCLUDED
diff --git a/samplecode/remoteattestation/GoogleMessages/Messages.proto b/samplecode/remoteattestation/GoogleMessages/Messages.proto
index c828cfd..73675ae 100644
--- a/samplecode/remoteattestation/GoogleMessages/Messages.proto
+++ b/samplecode/remoteattestation/GoogleMessages/Messages.proto
@@ -1,3 +1,4 @@
+syntax = "proto2";
 package Messages;
 
 message InitialMessage {
diff --git a/samplecode/remoteattestation/MessageHandler/MessageHandler.cpp b/samplecode/remoteattestation/MessageHandler/MessageHandler.cpp
index 4881348..9c80f2a 100644
--- a/samplecode/remoteattestation/MessageHandler/MessageHandler.cpp
+++ b/samplecode/remoteattestation/MessageHandler/MessageHandler.cpp
@@ -33,6 +33,7 @@
     this->nm->connectCallbackHandler([this](string v, int type) {
         return this->incomingHandler(v, type);
     });
+    return 1;
 }
 
 
@@ -396,7 +397,7 @@
 
 
 string MessageHandler::createInitMsg(int type, string msg) {
-    Messages::SecretMessage init_msg;
+    Messages::InitialMessage init_msg;
     init_msg.set_type(type);
     init_msg.set_size(msg.size());
 
diff --git a/samplecode/remoteattestation/ServiceProvider/isv_app/VerificationManager.cpp b/samplecode/remoteattestation/ServiceProvider/isv_app/VerificationManager.cpp
index 5d75209..029ac44 100644
--- a/samplecode/remoteattestation/ServiceProvider/isv_app/VerificationManager.cpp
+++ b/samplecode/remoteattestation/ServiceProvider/isv_app/VerificationManager.cpp
@@ -55,6 +55,7 @@
     this->nm->connectCallbackHandler([this](string v, int type) {
         return this->incomingHandler(v, type);
     });
+    return 1;
 }
 
 
@@ -178,10 +179,10 @@
         }
         break;
         case RA_APP_ATT_OK: {
-            Messages::SecretMessage sec_msg;
-            ret = sec_msg.ParseFromString(v);
+            Messages::InitialMessage msg;
+            ret = msg.ParseFromString(v);
             if (ret) {
-                if (sec_msg.type() == RA_APP_ATT_OK) {
+                if (msg.type() == RA_APP_ATT_OK) {
                     this->handleAppAttOk();
                 }
             }
diff --git a/samplecode/remoteattestation/ServiceProvider/service_provider/ServiceProvider.h b/samplecode/remoteattestation/ServiceProvider/service_provider/ServiceProvider.h
index 1228020..dd369be 100644
--- a/samplecode/remoteattestation/ServiceProvider/service_provider/ServiceProvider.h
+++ b/samplecode/remoteattestation/ServiceProvider/service_provider/ServiceProvider.h
@@ -78,7 +78,6 @@
     int sp_ra_proc_msg1_req(Messages::MessageMSG1 msg1, Messages::MessageMSG2 *msg2);
     int sp_ra_proc_msg3_req(Messages::MessageMSG3 msg, Messages::AttestationMessage *att_msg);
     sgx_ra_msg3_t* assembleMSG3(Messages::MessageMSG3 msg);
-    int sp_ra_proc_app_att_hmac(Messages::SecretMessage *new_msg, string hmac_key, string hmac_key_filename);
 
 private:
     WebService *ws = NULL;
diff --git a/samplecode/sealeddata/enclave/Cargo.toml b/samplecode/sealeddata/enclave/Cargo.toml
index 8bfce6b..64a6e56 100644
--- a/samplecode/sealeddata/enclave/Cargo.toml
+++ b/samplecode/sealeddata/enclave/Cargo.toml
@@ -22,6 +22,7 @@
 serde_cbor = { git = "https://github.com/mesalock-linux/cbor-sgx" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -30,6 +31,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/sealeddata/enclave/Xargo.toml b/samplecode/sealeddata/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/sealeddata/enclave/Xargo.toml
+++ b/samplecode/sealeddata/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/sealeddata/enclave/x86_64-unknown-linux-sgx.json b/samplecode/sealeddata/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/sealeddata/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/sealeddata/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/secretsharing/enclave/Cargo.toml b/samplecode/secretsharing/enclave/Cargo.toml
index ad50140..c5f9504 100644
--- a/samplecode/secretsharing/enclave/Cargo.toml
+++ b/samplecode/secretsharing/enclave/Cargo.toml
@@ -18,6 +18,7 @@
 threshold-secret-sharing = { git = "https://github.com/mesalock-linux/rust-threshold-secret-sharing-sgx" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -26,6 +27,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/secretsharing/enclave/Xargo.toml b/samplecode/secretsharing/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/secretsharing/enclave/Xargo.toml
+++ b/samplecode/secretsharing/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/secretsharing/enclave/x86_64-unknown-linux-sgx.json b/samplecode/secretsharing/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/secretsharing/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/secretsharing/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/serialize/enclave/Cargo.toml b/samplecode/serialize/enclave/Cargo.toml
index 8496a58..00b57a2 100644
--- a/samplecode/serialize/enclave/Cargo.toml
+++ b/samplecode/serialize/enclave/Cargo.toml
@@ -15,6 +15,7 @@
 sgx_serialize_derive = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -23,6 +24,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/serialize/enclave/Xargo.toml b/samplecode/serialize/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/serialize/enclave/Xargo.toml
+++ b/samplecode/serialize/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/serialize/enclave/x86_64-unknown-linux-sgx.json b/samplecode/serialize/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/serialize/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/serialize/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/sgx-cov/enclave/Cargo.toml b/samplecode/sgx-cov/enclave/Cargo.toml
index 9cd5c37..6653d1a 100644
--- a/samplecode/sgx-cov/enclave/Cargo.toml
+++ b/samplecode/sgx-cov/enclave/Cargo.toml
@@ -22,7 +22,9 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 sgx_trts = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 sgx_cov  = { git = "https://github.com/apache/teaclave-sgx-sdk.git", optional = true }
+
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -31,6 +33,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/sgx-cov/enclave/x86_64-unknown-linux-sgx.json b/samplecode/sgx-cov/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/sgx-cov/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/sgx-cov/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/static-data-distribution/app/Cargo.toml b/samplecode/static-data-distribution/app/Cargo.toml
index 3ceb7a9..e250741 100644
--- a/samplecode/static-data-distribution/app/Cargo.toml
+++ b/samplecode/static-data-distribution/app/Cargo.toml
@@ -11,30 +11,7 @@
 serde_json = "1.0"
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
-sgx_alloc = { path = "../../../sgx_alloc" }
-sgx_backtrace = { path = "../../../sgx_backtrace" }
-sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
-sgx_build_helper = { path = "../../../sgx_build_helper" }
-sgx_cov = { path = "../../../sgx_cov" }
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
-sgx_demangle = { path = "../../../sgx_demangle" }
-sgx_libc = { path = "../../../sgx_libc" }
-sgx_rand = { path = "../../../sgx_rand" }
-sgx_rand_derive = { path = "../../../sgx_rand_derive" }
-sgx_serialize = { path = "../../../sgx_serialize" }
-sgx_serialize_derive = { path = "../../../sgx_serialize_derive" }
-sgx_serialize_derive_internals = { path = "../../../sgx_serialize_derive_internals" }
-sgx_tcrypto = { path = "../../../sgx_tcrypto" }
-sgx_tcrypto_helper = { path = "../../../sgx_tcrypto_helper" }
-sgx_tdh = { path = "../../../sgx_tdh" }
-sgx_tkey_exchange = { path = "../../../sgx_tkey_exchange" }
-sgx_tprotected_fs = { path = "../../../sgx_tprotected_fs" }
-sgx_trts = { path = "../../../sgx_trts" }
-sgx_tse = { path = "../../../sgx_tse" }
-sgx_tseal = { path = "../../../sgx_tseal" }
-sgx_tstd = { path = "../../../sgx_tstd" }
-sgx_tunittest = { path = "../../../sgx_tunittest" }
 sgx_types = { path = "../../../sgx_types" }
 sgx_ucrypto = { path = "../../../sgx_ucrypto" }
-sgx_unwind = { path = "../../../sgx_unwind" }
 sgx_urts = { path = "../../../sgx_urts" }
diff --git a/samplecode/static-data-distribution/enclave/Cargo.toml b/samplecode/static-data-distribution/enclave/Cargo.toml
index 64117b6..fdaf73d 100644
--- a/samplecode/static-data-distribution/enclave/Cargo.toml
+++ b/samplecode/static-data-distribution/enclave/Cargo.toml
@@ -19,13 +19,16 @@
 serde_json = { git = "https://github.com/mesalock-linux/serde-json-sgx" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
 sgx_build_helper = { path = "../../../sgx_build_helper" }
 sgx_cov = { path = "../../../sgx_cov" }
+sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/static-data-distribution/enclave/Xargo.toml b/samplecode/static-data-distribution/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/static-data-distribution/enclave/Xargo.toml
+++ b/samplecode/static-data-distribution/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/static-data-distribution/enclave/x86_64-unknown-linux-sgx.json b/samplecode/static-data-distribution/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/static-data-distribution/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/static-data-distribution/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/switchless/enclave/Cargo.toml b/samplecode/switchless/enclave/Cargo.toml
index 24bf333..19f90bc 100644
--- a/samplecode/switchless/enclave/Cargo.toml
+++ b/samplecode/switchless/enclave/Cargo.toml
@@ -15,6 +15,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -23,6 +24,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/switchless/enclave/Xargo.toml b/samplecode/switchless/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/switchless/enclave/Xargo.toml
+++ b/samplecode/switchless/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/switchless/enclave/x86_64-unknown-linux-sgx.json b/samplecode/switchless/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/switchless/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/switchless/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/tcmalloc/enclave/Cargo.toml b/samplecode/tcmalloc/enclave/Cargo.toml
index f4f3224..c547778 100644
--- a/samplecode/tcmalloc/enclave/Cargo.toml
+++ b/samplecode/tcmalloc/enclave/Cargo.toml
@@ -15,6 +15,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -23,6 +24,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/tcmalloc/enclave/Xargo.toml b/samplecode/tcmalloc/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/tcmalloc/enclave/Xargo.toml
+++ b/samplecode/tcmalloc/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/tcmalloc/enclave/x86_64-unknown-linux-sgx.json b/samplecode/tcmalloc/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/tcmalloc/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/tcmalloc/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/thread/enclave/Cargo.toml b/samplecode/thread/enclave/Cargo.toml
index 4234637..7ee75d1 100644
--- a/samplecode/thread/enclave/Cargo.toml
+++ b/samplecode/thread/enclave/Cargo.toml
@@ -14,6 +14,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -22,6 +23,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
diff --git a/samplecode/thread/enclave/Xargo.toml b/samplecode/thread/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/thread/enclave/Xargo.toml
+++ b/samplecode/thread/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/thread/enclave/x86_64-unknown-linux-sgx.json b/samplecode/thread/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/thread/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/thread/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/tls/tlsclient/enclave/Cargo.toml b/samplecode/tls/tlsclient/enclave/Cargo.toml
index 2947296..842017b 100644
--- a/samplecode/tls/tlsclient/enclave/Cargo.toml
+++ b/samplecode/tls/tlsclient/enclave/Cargo.toml
@@ -22,6 +22,7 @@
 
 # Comment out these following lines to use rust-sgx-sdk from git
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -30,6 +31,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/tls/tlsclient/enclave/Xargo.toml b/samplecode/tls/tlsclient/enclave/Xargo.toml
index 989d796..795f1f0 100644
--- a/samplecode/tls/tlsclient/enclave/Xargo.toml
+++ b/samplecode/tls/tlsclient/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/tls/tlsclient/enclave/x86_64-unknown-linux-sgx.json b/samplecode/tls/tlsclient/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/tls/tlsclient/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/tls/tlsclient/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/tls/tlsserver/enclave/Cargo.toml b/samplecode/tls/tlsserver/enclave/Cargo.toml
index 5e9debe..6c34401 100644
--- a/samplecode/tls/tlsserver/enclave/Cargo.toml
+++ b/samplecode/tls/tlsserver/enclave/Cargo.toml
@@ -21,6 +21,7 @@
 lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -29,6 +30,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/tls/tlsserver/enclave/Xargo.toml b/samplecode/tls/tlsserver/enclave/Xargo.toml
index 989d796..795f1f0 100644
--- a/samplecode/tls/tlsserver/enclave/Xargo.toml
+++ b/samplecode/tls/tlsserver/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/tls/tlsserver/enclave/x86_64-unknown-linux-sgx.json b/samplecode/tls/tlsserver/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/tls/tlsserver/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/tls/tlsserver/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/tr-mpc/tr-mpc-server/enclave/Cargo.toml b/samplecode/tr-mpc/tr-mpc-server/enclave/Cargo.toml
index 0c9e9e6..9c73729 100644
--- a/samplecode/tr-mpc/tr-mpc-server/enclave/Cargo.toml
+++ b/samplecode/tr-mpc/tr-mpc-server/enclave/Cargo.toml
@@ -32,6 +32,7 @@
 
 # Comment out these following lines to use rust-sgx-sdk from git
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -40,6 +41,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/tr-mpc/tr-mpc-server/enclave/Xargo.toml b/samplecode/tr-mpc/tr-mpc-server/enclave/Xargo.toml
index 989d796..795f1f0 100644
--- a/samplecode/tr-mpc/tr-mpc-server/enclave/Xargo.toml
+++ b/samplecode/tr-mpc/tr-mpc-server/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/tr-mpc/tr-mpc-server/enclave/x86_64-unknown-linux-sgx.json b/samplecode/tr-mpc/tr-mpc-server/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/tr-mpc/tr-mpc-server/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/tr-mpc/tr-mpc-server/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/ue-ra/ue-ra-server/enclave/Cargo.toml b/samplecode/ue-ra/ue-ra-server/enclave/Cargo.toml
index 071e8ad..f768c19 100644
--- a/samplecode/ue-ra/ue-ra-server/enclave/Cargo.toml
+++ b/samplecode/ue-ra/ue-ra-server/enclave/Cargo.toml
@@ -31,6 +31,7 @@
 
 # Comment out these following lines to use rust-sgx-sdk from git
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -39,6 +40,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/ue-ra/ue-ra-server/enclave/Xargo.toml b/samplecode/ue-ra/ue-ra-server/enclave/Xargo.toml
index 989d796..795f1f0 100644
--- a/samplecode/ue-ra/ue-ra-server/enclave/Xargo.toml
+++ b/samplecode/ue-ra/ue-ra-server/enclave/Xargo.toml
@@ -89,6 +89,7 @@
 [dependencies.sgx_cov]
 path = "../../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../../sgx_signal"
 stage = 7
diff --git a/samplecode/ue-ra/ue-ra-server/enclave/x86_64-unknown-linux-sgx.json b/samplecode/ue-ra/ue-ra-server/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/ue-ra/ue-ra-server/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/ue-ra/ue-ra-server/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/unit-test/enclave/Xargo.toml b/samplecode/unit-test/enclave/Xargo.toml
index 61e97a9..e383be2 100644
--- a/samplecode/unit-test/enclave/Xargo.toml
+++ b/samplecode/unit-test/enclave/Xargo.toml
@@ -92,4 +92,4 @@
 
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
-stage = 7
\ No newline at end of file
+stage = 7
diff --git a/samplecode/unit-test/enclave/src/test_time.rs b/samplecode/unit-test/enclave/src/test_time.rs
index a0a3f1d..5d868e5 100644
--- a/samplecode/unit-test/enclave/src/test_time.rs
+++ b/samplecode/unit-test/enclave/src/test_time.rs
@@ -36,7 +36,7 @@
 
     {
         let a = Instant::now();
-        should_panic!((a - Duration::new(1, 0)).duration_since(a));
+        assert!((a - Duration::new(1, 0)).duration_since(a) == Duration::new(0, 0));
     }
 
     {
diff --git a/samplecode/unit-test/enclave/x86_64-unknown-linux-sgx.json b/samplecode/unit-test/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/unit-test/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/unit-test/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/wasmi/enclave/Cargo.toml b/samplecode/wasmi/enclave/Cargo.toml
index 410497e..2b9dba5 100644
--- a/samplecode/wasmi/enclave/Cargo.toml
+++ b/samplecode/wasmi/enclave/Cargo.toml
@@ -20,12 +20,18 @@
 [target.'cfg(not(target_env = "sgx"))'.dependencies]
 sgx_types = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
+
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
+sgx_backtrace = { path = "../../../sgx_backtrace" }
+sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
 sgx_build_helper = { path = "../../../sgx_build_helper" }
 sgx_cov = { path = "../../../sgx_cov" }
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
+sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
@@ -42,6 +48,6 @@
 sgx_tstd = { path = "../../../sgx_tstd" }
 sgx_tunittest = { path = "../../../sgx_tunittest" }
 sgx_types = { path = "../../../sgx_types" }
-sgx_ucrypto = { path = "../../../sgx_ucrypto" }
+#sgx_ucrypto = { path = "../../../sgx_ucrypto" }
 sgx_unwind = { path = "../../../sgx_unwind" }
-sgx_urts = { path = "../../../sgx_urts" }
+#sgx_urts = { path = "../../../sgx_urts" }
diff --git a/samplecode/wasmi/enclave/Xargo.toml b/samplecode/wasmi/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/wasmi/enclave/Xargo.toml
+++ b/samplecode/wasmi/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/wasmi/enclave/sgxwasm/Cargo.toml b/samplecode/wasmi/enclave/sgxwasm/Cargo.toml
index 36deb2d..853ed6e 100644
--- a/samplecode/wasmi/enclave/sgxwasm/Cargo.toml
+++ b/samplecode/wasmi/enclave/sgxwasm/Cargo.toml
@@ -14,6 +14,7 @@
 sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../../sgx_backtrace_sys" }
@@ -22,6 +23,7 @@
 sgx_crypto_helper = { path = "../../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../../sgx_demangle" }
 sgx_libc = { path = "../../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../../sgx_serialize" }
diff --git a/samplecode/wasmi/enclave/x86_64-unknown-linux-sgx.json b/samplecode/wasmi/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/wasmi/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/wasmi/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/samplecode/zlib-lazy-static-sample/enclave/Cargo.toml b/samplecode/zlib-lazy-static-sample/enclave/Cargo.toml
index a5ebcec..372d9e2 100644
--- a/samplecode/zlib-lazy-static-sample/enclave/Cargo.toml
+++ b/samplecode/zlib-lazy-static-sample/enclave/Cargo.toml
@@ -20,6 +20,7 @@
 lazy_static = { version = "1.1.0", features = ["spin_no_std"] }
 
 [patch.'https://github.com/apache/teaclave-sgx-sdk.git']
+sgx_align_struct_attribute = { path = "../../../sgx_align_struct_attribute" }
 sgx_alloc = { path = "../../../sgx_alloc" }
 sgx_backtrace = { path = "../../../sgx_backtrace" }
 sgx_backtrace_sys = { path = "../../../sgx_backtrace_sys" }
@@ -28,6 +29,7 @@
 sgx_crypto_helper = { path = "../../../sgx_crypto_helper" }
 sgx_demangle = { path = "../../../sgx_demangle" }
 sgx_libc = { path = "../../../sgx_libc" }
+sgx_no_tstd = { path = "../../../sgx_no_tstd" }
 sgx_rand = { path = "../../../sgx_rand" }
 sgx_rand_derive = { path = "../../../sgx_rand_derive" }
 sgx_serialize = { path = "../../../sgx_serialize" }
@@ -44,6 +46,6 @@
 sgx_tstd = { path = "../../../sgx_tstd" }
 sgx_tunittest = { path = "../../../sgx_tunittest" }
 sgx_types = { path = "../../../sgx_types" }
-sgx_ucrypto = { path = "../../../sgx_ucrypto" }
+#sgx_ucrypto = { path = "../../../sgx_ucrypto" }
 sgx_unwind = { path = "../../../sgx_unwind" }
-sgx_urts = { path = "../../../sgx_urts" }
+#sgx_urts = { path = "../../../sgx_urts" }
diff --git a/samplecode/zlib-lazy-static-sample/enclave/Xargo.toml b/samplecode/zlib-lazy-static-sample/enclave/Xargo.toml
index 31fb7d4..cd02285 100644
--- a/samplecode/zlib-lazy-static-sample/enclave/Xargo.toml
+++ b/samplecode/zlib-lazy-static-sample/enclave/Xargo.toml
@@ -88,6 +88,7 @@
 [dependencies.sgx_cov]
 path = "../../../sgx_cov"
 stage = 7
+
 [dependencies.sgx_signal]
 path = "../../../sgx_signal"
 stage = 7
diff --git a/samplecode/zlib-lazy-static-sample/enclave/x86_64-unknown-linux-sgx.json b/samplecode/zlib-lazy-static-sample/enclave/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/samplecode/zlib-lazy-static-sample/enclave/x86_64-unknown-linux-sgx.json
+++ b/samplecode/zlib-lazy-static-sample/enclave/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",
diff --git a/sgx_align_struct_attribute/Cargo.toml b/sgx_align_struct_attribute/Cargo.toml
index fb81633..46596bd 100644
--- a/sgx_align_struct_attribute/Cargo.toml
+++ b/sgx_align_struct_attribute/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_align_struct_attribute"
diff --git a/sgx_align_struct_attribute/src/align.rs b/sgx_align_struct_attribute/src/align.rs
index 9e3a523..2daf865 100644
--- a/sgx_align_struct_attribute/src/align.rs
+++ b/sgx_align_struct_attribute/src/align.rs
@@ -60,10 +60,7 @@
 
 impl AlignArgs {
     pub fn get_layout(&self) -> Result<Layout> {
-        let align_iter = self
-            .vars
-            .iter()
-            .find(|v| v.ident.to_string() == "align");
+        let align_iter = self.vars.iter().find(|v| v.ident == "align");
         let align: usize = if let Some(align_value) = align_iter {
             self.parse_align(&align_value.value)?
         } else {
@@ -73,10 +70,7 @@
             ));
         };
 
-        let size_iter = self
-            .vars
-            .iter()
-            .find(|v| v.ident.to_string() == "size");
+        let size_iter = self.vars.iter().find(|v| v.ident == "size");
         let size: usize = if let Some(size_value) = size_iter {
             self.parse_size(&size_value.value)?
         } else {
@@ -180,21 +174,22 @@
         quote! {
             #attrs
             #align_attr
-            #vis struct #name#generics {
+            #vis struct #name #generics {
             #pad_item,
             #fields
             }
         }
     }
 
+    #[allow(clippy::filter_next, clippy::collapsible_match)]
     fn is_contains_specified_attr(&self, atrr: &str) -> bool {
         let mut erxcept_attr = false;
         for attr in &self.input.attrs {
             let ident = attr.path.get_ident();
             let meta = attr.parse_meta();
-            if ident.map_or(false, |v| v.to_string() == "repr") && meta.is_ok() {
+            if ident.map_or(false, |v| *v == "repr") && meta.is_ok() {
                 if let Ok(Meta::List(ref m)) = meta {
-                    if m.nested.len() > 0 {
+                    if !m.nested.is_empty() {
                         erxcept_attr = m
                             .nested
                             .iter()
@@ -202,8 +197,7 @@
                                 let mut find = false;
                                 if let syn::NestedMeta::Meta(ref s) = x {
                                     if let syn::Meta::Path(p) = s {
-                                        find =
-                                            p.get_ident().map_or(false, |v| v.to_string() == atrr);
+                                        find = p.get_ident().map_or(false, |v| *v == atrr);
                                     }
                                 }
                                 find
@@ -226,7 +220,7 @@
 
     fn generate_align_attr(&self) -> proc_macro2::TokenStream {
         let align = self.align_layout.align();
-        let litint = LitInt::new(&format!("{}", align).to_string(), Span::call_site());
+        let litint = LitInt::new(&format!("{}", align), Span::call_site());
         quote! {
            #[repr(align(#litint))]
         }
diff --git a/sgx_align_struct_attribute/src/layout.rs b/sgx_align_struct_attribute/src/layout.rs
index 68150c4..861f9ee 100644
--- a/sgx_align_struct_attribute/src/layout.rs
+++ b/sgx_align_struct_attribute/src/layout.rs
@@ -72,24 +72,20 @@
     Ok(calc_algn(layout.align(), layout.size() + offset))
 }
 
+#[allow(clippy::overflow_check_conditional)]
 #[inline]
 fn check_overflow(buf: usize, len: usize) -> bool {
     (buf + len < len) || (buf + len < buf)
 }
 
 fn check_layout(layout: &Layout) -> bool {
-    if layout.size() == 0
+    !(layout.size() == 0
         || !layout.align().is_power_of_two()
-        || layout.size() > usize::MAX - (layout.align() - 1)
-    {
-        false
-    } else {
-        true
-    }
+        || layout.size() > usize::MAX - (layout.align() - 1))
 }
 
 fn check_align_req(size: usize, align_req: &[AlignReq]) -> bool {
-    if align_req.len() == 0 {
+    if align_req.is_empty() {
         return false;
     }
     let len: usize = (size + 7) / 8;
@@ -148,6 +144,7 @@
     rol(v, (0 - c as isize) as usize)
 }
 
+#[allow(clippy::comparison_chain)]
 fn count_lzb(bmp: i64) -> i32 {
     if bmp == 0 {
         -1
@@ -195,7 +192,7 @@
         if req.len > 63 {
             return -1;
         } else {
-            bmp |= rol(((1 as i64) << req.len) - 1, req.offset);
+            bmp |= rol(((1_i64) << req.len) - 1, req.offset);
         }
     }
     bmp
diff --git a/sgx_alloc/Cargo.toml b/sgx_alloc/Cargo.toml
index 02b464b..387eae2 100644
--- a/sgx_alloc/Cargo.toml
+++ b/sgx_alloc/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://dingelish.github.io/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_alloc"
diff --git a/sgx_alloc/src/alignalloc.rs b/sgx_alloc/src/alignalloc.rs
index f9afa9e..b83c130 100644
--- a/sgx_alloc/src/alignalloc.rs
+++ b/sgx_alloc/src/alignalloc.rs
@@ -373,7 +373,7 @@
             if req.len > 63 {
                 return -1;
             } else {
-                bmp |= rol(((1 as i64) << req.len) - 1, req.offset);
+                bmp |= rol(((1_i64) << req.len) - 1, req.offset);
             }
         }
         bmp
diff --git a/sgx_alloc/src/lib.rs b/sgx_alloc/src/lib.rs
index 412e458..f1f8451 100644
--- a/sgx_alloc/src/lib.rs
+++ b/sgx_alloc/src/lib.rs
@@ -32,6 +32,7 @@
 #![feature(core_intrinsics)]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(slice_ptr_get)]
+#![allow(clippy::missing_safety_doc)]
 
 extern crate alloc;
 
diff --git a/sgx_alloc/src/system.rs b/sgx_alloc/src/system.rs
index c6d2167..bc7881f 100644
--- a/sgx_alloc/src/system.rs
+++ b/sgx_alloc/src/system.rs
@@ -225,7 +225,6 @@
     use core::alloc::{GlobalAlloc, Layout};
     use core::ffi::c_void;
     use core::ptr;
-    use libc;
 
     unsafe impl GlobalAlloc for System {
         #[inline]
diff --git a/sgx_backtrace/Cargo.toml b/sgx_backtrace/Cargo.toml
index 0c4799a..2ae3746 100644
--- a/sgx_backtrace/Cargo.toml
+++ b/sgx_backtrace/Cargo.toml
@@ -7,7 +7,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [target.'cfg(not(target_env = "sgx"))'.dependencies]
 sgx_demangle = { path = "../sgx_demangle" }
diff --git a/sgx_backtrace_sys/Cargo.toml b/sgx_backtrace_sys/Cargo.toml
index 81645da..cb874f5 100644
--- a/sgx_backtrace_sys/Cargo.toml
+++ b/sgx_backtrace_sys/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 
 [lib]
diff --git a/sgx_backtrace_sys/libbacktrace/read.c b/sgx_backtrace_sys/libbacktrace/read.c
index 062b109..2a19349 100644
--- a/sgx_backtrace_sys/libbacktrace/read.c
+++ b/sgx_backtrace_sys/libbacktrace/read.c
@@ -94,6 +94,7 @@
     if (got < 0) {
         error_callback(data, "read", error);
         free(view->base);
+        sgx_ocfree();
         return 0;
     }
 
diff --git a/sgx_build_helper/Cargo.toml b/sgx_build_helper/Cargo.toml
index 6705cd8..7b9ebc9 100644
--- a/sgx_build_helper/Cargo.toml
+++ b/sgx_build_helper/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_build_helper"
diff --git a/sgx_cov/Cargo.toml b/sgx_cov/Cargo.toml
index d2b41a9..2e5d173 100644
--- a/sgx_cov/Cargo.toml
+++ b/sgx_cov/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Enabling gcov for SGX crates."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_cov"
diff --git a/sgx_crypto_helper/Cargo.toml b/sgx_crypto_helper/Cargo.toml
index 9d4a145..b2fe636 100644
--- a/sgx_crypto_helper/Cargo.toml
+++ b/sgx_crypto_helper/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_crypto_helper"
diff --git a/sgx_demangle/Cargo.toml b/sgx_demangle/Cargo.toml
index c05799d..5f165b2 100644
--- a/sgx_demangle/Cargo.toml
+++ b/sgx_demangle/Cargo.toml
@@ -7,7 +7,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_demangle"
diff --git a/sgx_edl/Cargo.toml b/sgx_edl/Cargo.toml
index b46a6db..098860b 100644
--- a/sgx_edl/Cargo.toml
+++ b/sgx_edl/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 include = [
     "src/lib.rs",
diff --git a/sgx_edl/edl/sgx_file.edl b/sgx_edl/edl/sgx_file.edl
index 07fb1eb..c70ec59 100644
--- a/sgx_edl/edl/sgx_file.edl
+++ b/sgx_edl/edl/sgx_file.edl
@@ -27,6 +27,7 @@
     untrusted {
         int u_open_ocall([out] int *error, [in, string] const char *pathname, int flags);
         int u_open64_ocall([out] int *error, [in, string] const char *path, int oflag, int mode);
+        int u_openat_ocall([out] int *error, int dirfd, [in, string] const char *pathname, int flags);
 
         int u_fstat_ocall([out] int *error, int fd, [out] struct stat_t *buf);
         int u_fstat64_ocall([out] int *error, int fd, [out] struct stat64_t *buf);
@@ -46,6 +47,7 @@
         int u_fchmod_ocall([out] int *error, int fd, uint32_t mode);
         int u_unlink_ocall([out] int *error, [in, string] const char *pathname);
         int u_link_ocall([out] int *error, [in, string] const char *oldpath, [in, string] const char *newpath);
+        int u_unlinkat_ocall([out] int *error, int dirfd, [in, string] const char *pathname, int flags);
         int u_linkat_ocall([out] int *error, int olddirfd, [in, string] const char *oldpath, int newdirfd, [in, string] const char *newpath, int flags);
         int u_rename_ocall([out] int *error, [in, string] const char *oldpath, [in, string] const char *newpath);
         int u_chmod_ocall([out] int *error, [in, string] const char *path, uint32_t mode);
@@ -54,6 +56,7 @@
         char *u_realpath_ocall([out] int *error, [in, string] const char *pathname);
         int u_mkdir_ocall([out] int *error, [in, string] const char *pathname, uint32_t mode);
         int u_rmdir_ocall([out] int *error, [in, string] const char *pathname);
+        void *u_fdopendir_ocall([out] int *error, int fd);
         void *u_opendir_ocall([out] int *error, [in, string] const char *pathname);
         int u_readdir64_r_ocall([user_check] void *dirp, [in, out] struct dirent64_t *entry, [out] struct dirent64_t **result);
         int u_closedir_ocall([out] int *error, [user_check] void *dirp);
diff --git a/sgx_libc/BUILD b/sgx_libc/BUILD
index 7c5d226..0d66538 100644
--- a/sgx_libc/BUILD
+++ b/sgx_libc/BUILD
@@ -4,7 +4,7 @@
     name = "sgx_libc",
     srcs = glob(["src/*.rs"]),
     crate_features = ["align"],
-    edition = "2018",
+    edition = "2021",
     visibility = ["//visibility:public"],
     deps = ["//sgx_types"],
 )
diff --git a/sgx_libc/Cargo.toml b/sgx_libc/Cargo.toml
index 7441fb5..7f7f364 100644
--- a/sgx_libc/Cargo.toml
+++ b/sgx_libc/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_libc"
diff --git a/sgx_libc/src/lib.rs b/sgx_libc/src/lib.rs
index d60cd39..01d2dd1 100644
--- a/sgx_libc/src/lib.rs
+++ b/sgx_libc/src/lib.rs
@@ -22,7 +22,10 @@
 #![allow(overflowing_literals)]
 #![allow(non_snake_case)]
 #![allow(unused_macros)]
+#![allow(clippy::cmp_null)]
 #![allow(unused_assignments)]
+#![allow(clippy::missing_safety_doc)]
+#![allow(clippy::absurd_extreme_comparisons)]
 
 #[macro_use]
 extern crate alloc;
diff --git a/sgx_libc/src/linux/x86_64/mod.rs b/sgx_libc/src/linux/x86_64/mod.rs
index 314e805..dc55613 100644
--- a/sgx_libc/src/linux/x86_64/mod.rs
+++ b/sgx_libc/src/linux/x86_64/mod.rs
@@ -1418,9 +1418,9 @@
 pub const SA_SIGINFO: c_int = 0x00000004;
 pub const SA_NOCLDWAIT: c_int = 0x00000002;
 
-pub const SIG_DFL: sighandler_t = 0 as sighandler_t;
-pub const SIG_IGN: sighandler_t = 1 as sighandler_t;
-pub const SIG_ERR: sighandler_t = !0 as sighandler_t;
+pub const SIG_DFL: sighandler_t = 0_usize;
+pub const SIG_IGN: sighandler_t = 1_usize;
+pub const SIG_ERR: sighandler_t = !0 as usize;
 
 pub const SIGTRAP: c_int = 5;
 pub const SIGCHLD: c_int = 17;
@@ -1536,7 +1536,7 @@
 
 #[inline]
 unsafe fn __sigmask(sig: c_int) -> u64 {
-    (1 as u64) << (((sig) - 1) % (8 * mem::size_of::<u64>()) as i32)
+    (1_u64) << (((sig) - 1) % (8 * mem::size_of::<u64>()) as i32)
 }
 
 #[inline]
@@ -1612,7 +1612,7 @@
 
 #[inline]
 pub const fn CMSG_ALIGN(len: usize) -> usize {
-    len + mem::size_of::<usize>() - 1 & !(mem::size_of::<usize>() - 1)
+    (len + mem::size_of::<usize>() - 1) & !(mem::size_of::<usize>() - 1)
 }
 
 #[inline]
@@ -1620,7 +1620,7 @@
     if (*mhdr).msg_controllen as usize >= mem::size_of::<cmsghdr>() {
         (*mhdr).msg_control as *mut cmsghdr
     } else {
-        0 as *mut cmsghdr
+        ptr::null_mut::<cmsghdr>()
     }
 }
 
@@ -1642,14 +1642,14 @@
 #[inline]
 pub unsafe fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr {
     if ((*cmsg).cmsg_len as usize) < mem::size_of::<cmsghdr>() {
-        return 0 as *mut cmsghdr;
+        return ptr::null_mut::<cmsghdr>();
     };
     let next = (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr;
     let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize;
     if (next.offset(1)) as usize > max
         || next as usize + CMSG_ALIGN((*next).cmsg_len as usize) > max
     {
-        0 as *mut cmsghdr
+        ptr::null_mut::<cmsghdr>()
     } else {
         next as *mut cmsghdr
     }
@@ -1666,7 +1666,7 @@
 #[inline]
 pub unsafe fn minor(dev: dev_t) -> c_uint {
     let mut minor = 0;
-    minor |= (dev & 0x00000000000000ff) >> 0;
+    minor |= dev & 0x00000000000000ff;
     minor |= (dev & 0x00000ffffff00000) >> 12;
     minor as c_uint
 }
@@ -1678,7 +1678,7 @@
     let mut dev = 0;
     dev |= (major & 0x00000fff) << 8;
     dev |= (major & 0xfffff000) << 32;
-    dev |= (minor & 0x000000ff) << 0;
+    dev |= minor & 0x000000ff;
     dev |= (minor & 0xffffff00) << 12;
     dev
 }
diff --git a/sgx_libc/src/linux/x86_64/ocall.rs b/sgx_libc/src/linux/x86_64/ocall.rs
index 8a17915..c6a0c82 100644
--- a/sgx_libc/src/linux/x86_64/ocall.rs
+++ b/sgx_libc/src/linux/x86_64/ocall.rs
@@ -111,6 +111,13 @@
         oflag: c_int,
         mode: c_int,
     ) -> sgx_status_t;
+    pub fn u_openat_ocall(
+        result: *mut c_int,
+        error: *mut c_int,
+        dirfd: c_int,
+        pathname: *const c_char,
+        flags: c_int,
+    ) -> sgx_status_t;
     pub fn u_fstat_ocall(
         result: *mut c_int,
         error: *mut c_int,
@@ -204,6 +211,13 @@
         oldpath: *const c_char,
         newpath: *const c_char,
     ) -> sgx_status_t;
+    pub fn u_unlinkat_ocall(
+        result: *mut c_int,
+        error: *mut c_int,
+        dirfd: c_int,
+        pathname: *const c_char,
+        flags: c_int,
+    ) -> sgx_status_t;
     pub fn u_linkat_ocall(
         result: *mut c_int,
         error: *mut c_int,
@@ -254,6 +268,7 @@
         error: *mut c_int,
         pathname: *const c_char,
     ) -> sgx_status_t;
+    pub fn u_fdopendir_ocall(result: *mut *mut DIR, error: *mut c_int, fd: c_int) -> sgx_status_t;
     pub fn u_opendir_ocall(
         result: *mut *mut DIR,
         error: *mut c_int,
@@ -684,14 +699,14 @@
         if result as isize != -1 {
             if sgx_is_outside_enclave(result, length) == 0 {
                 set_errno(ESGX);
-                result = -1 as isize as *mut c_void;
+                result = -1_isize as *mut c_void;
             }
         } else {
             set_errno(error);
         }
     } else {
         set_errno(ESGX);
-        result = -1 as isize as *mut c_void;
+        result = -1_isize as *mut c_void;
     }
     result
 }
@@ -1008,6 +1023,29 @@
     result
 }
 
+pub unsafe fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
+    let mut result: c_int = 0;
+    let mut error: c_int = 0;
+
+    let status = u_openat_ocall(
+        &mut result as *mut c_int,
+        &mut error as *mut c_int,
+        dirfd,
+        pathname,
+        flags,
+    );
+
+    if status == sgx_status_t::SGX_SUCCESS {
+        if result == -1 {
+            set_errno(error);
+        }
+    } else {
+        set_errno(ESGX);
+        result = -1;
+    }
+    result
+}
+
 pub unsafe fn fstat(fd: c_int, buf: *mut stat) -> c_int {
     let mut result: c_int = 0;
     let mut error: c_int = 0;
@@ -1346,6 +1384,29 @@
     result
 }
 
+pub unsafe fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
+    let mut result: c_int = 0;
+    let mut error: c_int = 0;
+
+    let status = u_unlinkat_ocall(
+        &mut result as *mut c_int,
+        &mut error as *mut c_int,
+        dirfd,
+        pathname,
+        flags,
+    );
+
+    if status == sgx_status_t::SGX_SUCCESS {
+        if result == -1 {
+            set_errno(error);
+        }
+    } else {
+        set_errno(ESGX);
+        result = -1;
+    }
+    result
+}
+
 pub unsafe fn linkat(
     olddirfd: c_int,
     oldpath: *const c_char,
@@ -1528,6 +1589,23 @@
     result
 }
 
+pub unsafe fn fdopendir(fd: c_int) -> *mut DIR {
+    let mut result: *mut DIR = ptr::null_mut();
+    let mut error: c_int = 0;
+
+    let status = u_fdopendir_ocall(&mut result as *mut *mut DIR, &mut error as *mut c_int, fd);
+
+    if status == sgx_status_t::SGX_SUCCESS {
+        if result.is_null() {
+            set_errno(error);
+        }
+    } else {
+        set_errno(ESGX);
+        result = ptr::null_mut();
+    }
+    result
+}
+
 pub unsafe fn opendir(pathname: *const c_char) -> *mut DIR {
     let mut result: *mut DIR = ptr::null_mut();
     let mut error: c_int = 0;
@@ -2425,7 +2503,7 @@
     let mut result: c_int = 0;
     let mut error: c_int = 0;
     let len_in: socklen_t = if !addrlen.is_null() { *addrlen } else { 0 };
-    let mut len_out: socklen_t = 0 as socklen_t;
+    let mut len_out: socklen_t = 0;
     let status = u_accept_ocall(
         &mut result as *mut c_int,
         &mut error as *mut c_int,
@@ -2459,7 +2537,7 @@
     let mut result: c_int = 0;
     let mut error: c_int = 0;
     let len_in: socklen_t = if !addrlen.is_null() { *addrlen } else { 0 };
-    let mut len_out: socklen_t = 0 as socklen_t;
+    let mut len_out: socklen_t = 0;
     let status = u_accept4_ocall(
         &mut result as *mut c_int,
         &mut error as *mut c_int,
@@ -2781,7 +2859,7 @@
     let mut result: ssize_t = 0;
     let mut error: c_int = 0;
     let len_in: socklen_t = if !addrlen.is_null() { *addrlen } else { 0 };
-    let mut len_out: socklen_t = 0 as socklen_t;
+    let mut len_out: socklen_t = 0;
 
     if buf.is_null() || sgx_is_within_enclave(buf, len) == 0 {
         set_errno(EINVAL);
@@ -3012,7 +3090,7 @@
     let mut result: c_int = 0;
     let mut error: c_int = 0;
     let len_in: socklen_t = if !optlen.is_null() { *optlen } else { 0 };
-    let mut len_out: socklen_t = 0 as socklen_t;
+    let mut len_out: socklen_t = 0;
 
     let status = u_getsockopt_ocall(
         &mut result as *mut c_int,
@@ -3044,7 +3122,7 @@
     let mut result: c_int = 0;
     let mut error: c_int = 0;
     let len_in: socklen_t = if !addrlen.is_null() { *addrlen } else { 0 };
-    let mut len_out: socklen_t = 0 as socklen_t;
+    let mut len_out: socklen_t = 0;
     let status = u_getpeername_ocall(
         &mut result as *mut c_int,
         &mut error as *mut c_int,
@@ -3073,7 +3151,7 @@
     let mut result: c_int = 0;
     let mut error: c_int = 0;
     let len_in: socklen_t = if !addrlen.is_null() { *addrlen } else { 0 };
-    let mut len_out: socklen_t = 0 as socklen_t;
+    let mut len_out: socklen_t = 0;
     let status = u_getsockname_ocall(
         &mut result as *mut c_int,
         &mut error as *mut c_int,
@@ -3219,7 +3297,7 @@
                 cur_ptr = cur.ai_next;
             }
 
-            if addrinfo_vec.len() > 0 {
+            if !addrinfo_vec.is_empty() {
                 if result == 0 {
                     for i in 0..addrinfo_vec.len() - 1 {
                         addrinfo_vec[i].ai_next = addrinfo_vec[i + 1].as_mut() as *mut addrinfo;
diff --git a/sgx_no_tstd/Cargo.toml b/sgx_no_tstd/Cargo.toml
index 213e6a6..914b1f6 100644
--- a/sgx_no_tstd/Cargo.toml
+++ b/sgx_no_tstd/Cargo.toml
@@ -7,7 +7,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_no_tstd"
diff --git a/sgx_no_tstd/build.rs b/sgx_no_tstd/build.rs
index e1d22fa..c529fee 100644
--- a/sgx_no_tstd/build.rs
+++ b/sgx_no_tstd/build.rs
@@ -15,8 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#![feature(available_parallelism)]
-
 extern crate sgx_build_helper as build_helper;
 
 use build_helper::{native_lib_boilerplate, run};
diff --git a/sgx_panic_abort/Cargo.toml b/sgx_panic_abort/Cargo.toml
index d8084b0..0e01779 100644
--- a/sgx_panic_abort/Cargo.toml
+++ b/sgx_panic_abort/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://dingelish.github.io/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
diff --git a/sgx_panic_unwind/Cargo.toml b/sgx_panic_unwind/Cargo.toml
index df1a35c..9f654be 100644
--- a/sgx_panic_unwind/Cargo.toml
+++ b/sgx_panic_unwind/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://dingelish.github.io/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
diff --git a/sgx_panic_unwind/src/dwarf/eh.rs b/sgx_panic_unwind/src/dwarf/eh.rs
index 7394fea..6c59df3 100644
--- a/sgx_panic_unwind/src/dwarf/eh.rs
+++ b/sgx_panic_unwind/src/dwarf/eh.rs
@@ -138,7 +138,11 @@
 
 #[inline]
 fn round_up(unrounded: usize, align: usize) -> Result<usize, ()> {
-    if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) }
+    if align.is_power_of_two() {
+        Ok((unrounded + align - 1) & !(align - 1))
+    } else {
+        Err(())
+    }
 }
 
 unsafe fn read_encoded_pointer(
diff --git a/sgx_panic_unwind/src/gcc.rs b/sgx_panic_unwind/src/gcc.rs
index 4f507f5..56d95ea 100644
--- a/sgx_panic_unwind/src/gcc.rs
+++ b/sgx_panic_unwind/src/gcc.rs
@@ -87,7 +87,7 @@
 // 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
+    0x4d4f_5a00_5255_5354
 }
 
 // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
@@ -122,16 +122,14 @@
     };
     if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
         match eh_action {
-            EHAction::None |
-            EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
+            EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
             EHAction::Catch(_) => uw::_URC_HANDLER_FOUND,
             EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
         }
     } else {
         match eh_action {
             EHAction::None => uw::_URC_CONTINUE_UNWIND,
-            EHAction::Cleanup(lpad) |
-            EHAction::Catch(lpad) => {
+            EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
                 uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
                 uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
                 uw::_Unwind_SetIP(context, lpad);
@@ -167,4 +165,3 @@
     };
     eh::find_eh_action(lsda, &eh_context)
 }
-
diff --git a/sgx_panic_unwind/src/lib.rs b/sgx_panic_unwind/src/lib.rs
index fb98924..3e2e111 100644
--- a/sgx_panic_unwind/src/lib.rs
+++ b/sgx_panic_unwind/src/lib.rs
@@ -44,12 +44,14 @@
 
 mod dwarf;
 
+/// # Safety
 #[rustc_std_internal_symbol]
 #[allow(improper_ctypes_definitions)]
 pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
     Box::into_raw(imp::cleanup(payload))
 }
 
+/// # Safety
 // Entry point for raising an exception, just delegates to the platform-specific
 // implementation.
 #[rustc_std_internal_symbol]
diff --git a/sgx_rand/Cargo.toml b/sgx_rand/Cargo.toml
index 09a7545..1a942d5 100644
--- a/sgx_rand/Cargo.toml
+++ b/sgx_rand/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_rand"
diff --git a/sgx_rand_derive/Cargo.toml b/sgx_rand_derive/Cargo.toml
index be5026c..0b77310 100644
--- a/sgx_rand_derive/Cargo.toml
+++ b/sgx_rand_derive/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_rand_derive"
diff --git a/sgx_serialize/Cargo.toml b/sgx_serialize/Cargo.toml
index f415fa5..665244f 100644
--- a/sgx_serialize/Cargo.toml
+++ b/sgx_serialize/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_serialize"
diff --git a/sgx_serialize_derive/Cargo.toml b/sgx_serialize_derive/Cargo.toml
index 9619005..5ce9db3 100644
--- a/sgx_serialize_derive/Cargo.toml
+++ b/sgx_serialize_derive/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_serialize_derive"
diff --git a/sgx_serialize_derive_internals/Cargo.toml b/sgx_serialize_derive_internals/Cargo.toml
index b499f09..239cd3c 100644
--- a/sgx_serialize_derive_internals/Cargo.toml
+++ b/sgx_serialize_derive_internals/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_serialize_derive_internals"
diff --git a/sgx_signal/Cargo.toml b/sgx_signal/Cargo.toml
index 0db8992..7ba3f47 100644
--- a/sgx_signal/Cargo.toml
+++ b/sgx_signal/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_signal"
diff --git a/sgx_signal/src/exception.rs b/sgx_signal/src/exception.rs
index 0f9f7a8..daa541e 100644
--- a/sgx_signal/src/exception.rs
+++ b/sgx_signal/src/exception.rs
@@ -46,7 +46,7 @@
 }
 
 #[allow(unknown_lints, bare_trait_objects)]
-type ExceptionHandler = Fn(&mut sgx_exception_info_t) -> ContinueType + Send + Sync;
+type ExceptionHandler = dyn Fn(&mut sgx_exception_info_t) -> ContinueType + Send + Sync;
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
 pub struct HandlerId(NonZeroU64);
diff --git a/sgx_tcrypto/Cargo.toml b/sgx_tcrypto/Cargo.toml
index 2d010cb..379b830 100644
--- a/sgx_tcrypto/Cargo.toml
+++ b/sgx_tcrypto/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_tcrypto"
diff --git a/sgx_tcrypto_helper/Cargo.toml b/sgx_tcrypto_helper/Cargo.toml
index e85af17..b24f01c 100644
--- a/sgx_tcrypto_helper/Cargo.toml
+++ b/sgx_tcrypto_helper/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_tcrypto_helper"
diff --git a/sgx_tcrypto_helper/x86_64-unknown-linux-sgx.json b/sgx_tcrypto_helper/x86_64-unknown-linux-sgx.json
deleted file mode 100644
index 69b38be..0000000
--- a/sgx_tcrypto_helper/x86_64-unknown-linux-sgx.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-  "arch": "x86_64",
-  "cpu": "x86-64",
-  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
-  "dynamic-linking": true,
-  "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
-  "executables": true,
-  "has-elf-tls": true,
-  "has-rpath": true,
-  "linker-flavor": "gcc",
-  "linker-is-gnu": true,
-  "llvm-target": "x86_64-unknown-linux-gnu",
-  "max-atomic-width": 64,
-  "os": "linux",
-  "position-independent-executables": true,
-  "pre-link-args": {
-    "gcc": [
-      "-Wl,--as-needed",
-      "-Wl,-z,noexecstack",
-      "-m64"
-    ]
-  },
-  "relro-level": "full",
-  "stack-probes": {
-    "kind": "inline-or-call",
-    "min-llvm-version-for-inline": [
-      11,
-      0,
-      1
-    ]
-  },
-  "target-c-int-width": "32",
-  "target-endian": "little",
-  "target-family": "unix",
-  "target-pointer-width": "64",
-  "vendor": "mesalock"
-}
diff --git a/sgx_tdh/Cargo.toml b/sgx_tdh/Cargo.toml
index cf30524..f65a594 100644
--- a/sgx_tdh/Cargo.toml
+++ b/sgx_tdh/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_tdh"
diff --git a/sgx_tkey_exchange/Cargo.toml b/sgx_tkey_exchange/Cargo.toml
index fae39e2..f55cc8e 100644
--- a/sgx_tkey_exchange/Cargo.toml
+++ b/sgx_tkey_exchange/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_tkey_exchange"
diff --git a/sgx_tprotected_fs/Cargo.toml b/sgx_tprotected_fs/Cargo.toml
index 4808968..3978625 100644
--- a/sgx_tprotected_fs/Cargo.toml
+++ b/sgx_tprotected_fs/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_tprotected_fs"
diff --git a/sgx_trts/BUILD b/sgx_trts/BUILD
index 4027e9e..9dec8b6 100644
--- a/sgx_trts/BUILD
+++ b/sgx_trts/BUILD
@@ -3,7 +3,7 @@
 rust_library(
     name = "sgx_trts",
     srcs = glob(["src/*.rs"]),
-    edition = "2018",
+    edition = "2021",
     visibility = ["//visibility:public"],
     deps = [
         "//sgx_libc",
diff --git a/sgx_trts/Cargo.toml b/sgx_trts/Cargo.toml
index 79a0919..d43b81a 100644
--- a/sgx_trts/Cargo.toml
+++ b/sgx_trts/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_trts"
diff --git a/sgx_trts/src/c_str.rs b/sgx_trts/src/c_str.rs
index 329b96f..da052e1 100644
--- a/sgx_trts/src/c_str.rs
+++ b/sgx_trts/src/c_str.rs
@@ -366,7 +366,6 @@
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     ///
     /// // Some invalid bytes in a vector
@@ -443,38 +442,61 @@
     /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as
     /// the position of the nul byte.
     pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
-        trait SpecIntoVec {
-            fn into_vec(self) -> Vec<u8>;
+        trait SpecNewImpl {
+            fn spec_new_impl(self) -> Result<CString, NulError>;
         }
-        impl<T: Into<Vec<u8>>> SpecIntoVec for T {
-            default fn into_vec(self) -> Vec<u8> {
-                self.into()
-            }
-        }
-        // Specialization for avoiding reallocation.
-        impl SpecIntoVec for &'_ [u8] {
-            fn into_vec(self) -> Vec<u8> {
-                let mut v = Vec::with_capacity(self.len() + 1);
-                v.extend(self);
-                v
-            }
-        }
-        impl SpecIntoVec for &'_ str {
-            fn into_vec(self) -> Vec<u8> {
-                let mut v = Vec::with_capacity(self.len() + 1);
-                v.extend(self.as_bytes());
-                v
+
+        impl<T: Into<Vec<u8>>> SpecNewImpl for T {
+            default fn spec_new_impl(self) -> Result<CString, NulError> {
+                let bytes: Vec<u8> = self.into();
+                match memchr::memchr(0, &bytes) {
+                    Some(i) => Err(NulError(i, bytes)),
+                    None => Ok(unsafe { CString::_from_vec_unchecked(bytes) }),
+                }
             }
         }
 
-        Self::_new(SpecIntoVec::into_vec(t))
-    }
+        // Specialization for avoiding reallocation
+        #[inline(always)] // Without that it is not inlined into specializations
+        fn spec_new_impl_bytes(bytes: &[u8]) -> Result<CString, NulError> {
+            // We cannot have such large slice that we would overflow here
+            // but using `checked_add` allows LLVM to assume that capacity never overflows
+            // and generate twice shorter code.
+            // `saturating_add` doesn't help for some reason.
+            let capacity = bytes.len().checked_add(1).unwrap();
 
-    fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
-        match memchr::memchr(0, &bytes) {
-            Some(i) => Err(NulError(i, bytes)),
-            None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+            // Allocate before validation to avoid duplication of allocation code.
+            // We still need to allocate and copy memory even if we get an error.
+            let mut buffer = Vec::with_capacity(capacity);
+            buffer.extend(bytes);
+
+            // Check memory of self instead of new buffer.
+            // This allows better optimizations if lto enabled.
+            match memchr::memchr(0, bytes) {
+                Some(i) => Err(NulError(i, buffer)),
+                None => Ok(unsafe { CString::_from_vec_unchecked(buffer) }),
+            }
         }
+
+        impl SpecNewImpl for &'_ [u8] {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self)
+            }
+        }
+
+        impl SpecNewImpl for &'_ str {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self.as_bytes())
+            }
+        }
+
+        impl SpecNewImpl for &'_ mut [u8] {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self)
+            }
+        }
+
+        t.spec_new_impl()
     }
 
     /// Creates a C-compatible string by consuming a byte vector,
@@ -497,10 +519,15 @@
     /// }
     /// ```
     #[must_use]
-    pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
+    pub unsafe fn from_vec_unchecked(v: Vec<u8>) -> Self {
+        debug_assert!(memchr::memchr(0, &v).is_none());
+        Self::_from_vec_unchecked(v)
+    }
+
+    unsafe fn _from_vec_unchecked(mut v: Vec<u8>) -> Self {
         v.reserve_exact(1);
         v.push(0);
-        CString {
+        Self {
             inner: v.into_boxed_slice(),
         }
     }
@@ -620,11 +647,10 @@
     /// let err = cstring.into_string().err().expect("into_string().err() failed");
     /// assert_eq!(err.utf8_error().valid_up_to(), 1);
     /// ```
-
     pub fn into_string(self) -> Result<String, IntoStringError> {
         String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError {
             error: e.utf8_error(),
-            inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) },
+            inner: unsafe { Self::_from_vec_unchecked(e.into_bytes()) },
         })
     }
 
@@ -766,7 +792,6 @@
     /// # Example
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     /// assert_eq!(
     ///     unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) },
@@ -775,6 +800,11 @@
     /// ```
     #[must_use]
     pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
+        debug_assert!(memchr::memchr(0, &v).unwrap() + 1 == v.len());
+        Self::_from_vec_with_nul_unchecked(v)
+    }
+
+    unsafe fn _from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
         Self {
             inner: v.into_boxed_slice(),
         }
@@ -796,7 +826,6 @@
     /// when called without the ending nul byte.
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     /// assert_eq!(
     ///     CString::from_vec_with_nul(b"abc\0".to_vec())
@@ -808,7 +837,6 @@
     /// An incorrectly formatted [`Vec`] will produce an error.
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::{CString, FromVecWithNulError};
     /// // Interior nul byte
     /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
@@ -821,7 +849,7 @@
             Some(nul_pos) if nul_pos + 1 == v.len() => {
                 // SAFETY: We know there is only one nul byte, at the end
                 // of the vec.
-                Ok(unsafe { Self::from_vec_with_nul_unchecked(v) })
+                Ok(unsafe { Self::_from_vec_with_nul_unchecked(v) })
             }
             Some(nul_pos) => Err(FromVecWithNulError {
                 error_kind: FromBytesWithNulErrorKind::InteriorNul(nul_pos),
@@ -852,7 +880,7 @@
 
     #[inline]
     fn deref(&self) -> &CStr {
-        unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
+        unsafe { CStr::_from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
     }
 }
 
@@ -909,6 +937,8 @@
 }
 
 impl<'a> From<Cow<'a, CStr>> for CString {
+    /// Converts a `Cow<'a, CStr>` into a `CString`, by copying the contents if they are
+    /// borrowed.
     #[inline]
     fn from(s: Cow<'a, CStr>) -> Self {
         s.into_owned()
@@ -916,6 +946,8 @@
 }
 
 impl From<&CStr> for Box<CStr> {
+    /// Converts a `&CStr` into a `Box<CStr>`,
+    /// by copying the contents into a newly allocated [`Box`].
     fn from(s: &CStr) -> Box<CStr> {
         let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
         unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
@@ -923,6 +955,8 @@
 }
 
 impl From<Cow<'_, CStr>> for Box<CStr> {
+    /// Converts a `Cow<'a, CStr>` into a `Box<CStr>`,
+    /// by copying the contents if they are borrowed.
     #[inline]
     fn from(cow: Cow<'_, CStr>) -> Box<CStr> {
         match cow {
@@ -956,7 +990,7 @@
             };
             // SAFETY: `v` cannot contain null bytes, given the type-level
             // invariant of `NonZeroU8`.
-            CString::from_vec_unchecked(v)
+            Self::_from_vec_unchecked(v)
         }
     }
 }
@@ -1001,7 +1035,8 @@
 }
 
 impl From<CString> for Arc<CStr> {
-    /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> without copying or allocating.
+    /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> by moving the [`CString`]
+    /// data into a new [`Arc`] buffer.
     #[inline]
     fn from(s: CString) -> Arc<CStr> {
         let arc: Arc<[u8]> = Arc::from(s.into_inner());
@@ -1010,6 +1045,8 @@
 }
 
 impl From<&CStr> for Arc<CStr> {
+    /// Converts a `&CStr` into a `Arc<CStr>`,
+    /// by copying the contents into a newly allocated [`Arc`].
     #[inline]
     fn from(s: &CStr) -> Arc<CStr> {
         let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
@@ -1018,7 +1055,8 @@
 }
 
 impl From<CString> for Rc<CStr> {
-    /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> without copying or allocating.
+    /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> by moving the [`CString`]
+    /// data into a new [`Arc`] buffer.
     #[inline]
     fn from(s: CString) -> Rc<CStr> {
         let rc: Rc<[u8]> = Rc::from(s.into_inner());
@@ -1027,6 +1065,8 @@
 }
 
 impl From<&CStr> for Rc<CStr> {
+    /// Converts a `&CStr` into a `Rc<CStr>`,
+    /// by copying the contents into a newly allocated [`Rc`].
     #[inline]
     fn from(s: &CStr) -> Rc<CStr> {
         let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
@@ -1146,7 +1186,7 @@
         // The cast from c_char to u8 is ok because a c_char is always one byte.
         let len = libc::strlen(ptr);
         let ptr = ptr as *const u8;
-        CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+        Self::_from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
     }
 
     /// Creates a C string wrapper from a byte slice.
@@ -1181,15 +1221,16 @@
     /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0");
     /// assert!(cstr.is_err());
     /// ```
-    pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> {
+    pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
         let nul_pos = memchr::memchr(0, bytes);
-        if let Some(nul_pos) = nul_pos {
-            if nul_pos + 1 != bytes.len() {
-                return Err(FromBytesWithNulError::interior_nul(nul_pos));
+        match nul_pos {
+            Some(nul_pos) if nul_pos + 1 == bytes.len() => {
+                // SAFETY: We know there is only one nul byte, at the end
+                // of the byte slice.
+                Ok(unsafe { Self::_from_bytes_with_nul_unchecked(bytes) })
             }
-            Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
-        } else {
-            Err(FromBytesWithNulError::not_nul_terminated())
+            Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
+            None => Err(FromBytesWithNulError::not_nul_terminated()),
         }
     }
 
@@ -1213,12 +1254,19 @@
     #[inline]
     #[must_use]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        // We're in a const fn, so this is the best we can do
+        debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
+        Self::_from_bytes_with_nul_unchecked(bytes)
+    }
+
+    #[inline]
+    const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
         // SAFETY: Casting to CStr is safe because its internal representation
         // is a [u8] too (safe only inside std).
         // Dereferencing the obtained pointer is safe because it comes from a
         // reference. Making a reference is then safe because its lifetime
         // is bound by the lifetime of the given `bytes`.
-        &*(bytes as *const [u8] as *const CStr)
+        &*(bytes as *const [u8] as *const Self)
     }
 
     /// Returns the inner pointer to this C string.
@@ -1450,6 +1498,7 @@
 }
 
 impl From<&CStr> for CString {
+    /// Copies the contents of the `&CStr` into a newly allocated `CString`.
     fn from(s: &CStr) -> CString {
         s.to_owned()
     }
@@ -1473,7 +1522,7 @@
         // byte, since otherwise we could get an empty string that doesn't end
         // in a null.
         if index.start < bytes.len() {
-            unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) }
+            unsafe { CStr::_from_bytes_with_nul_unchecked(&bytes[index.start..]) }
         } else {
             panic!(
                 "index out of bounds: the len is {} but the index is {}",
diff --git a/sgx_trts/src/enclave.rs b/sgx_trts/src/enclave.rs
index 6759491..76f510f 100644
--- a/sgx_trts/src/enclave.rs
+++ b/sgx_trts/src/enclave.rs
@@ -562,6 +562,7 @@
     unsafe { g_global_data.tcs_max_num as u32 }
 }
 
+#[allow(clippy::collapsible_if, clippy::nonminimal_bool)]
 pub fn rsgx_get_tcs_num() -> (u32, u32, u32) {
     let gd = unsafe {
         let p = rsgx_get_global_data();
diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs
index 15be2d4..7659bdc 100644
--- a/sgx_trts/src/lib.rs
+++ b/sgx_trts/src/lib.rs
@@ -64,17 +64,17 @@
 
 #![no_std]
 #![cfg_attr(target_env = "sgx", feature(rustc_private))]
-#![allow(incomplete_features)]
 #![feature(allocator_api)]
-#![feature(asm)]
-#![feature(const_raw_ptr_deref)]
-#![allow(non_camel_case_types)]
-#![allow(non_upper_case_globals)]
-#![allow(non_snake_case)]
 #![feature(specialization)]
 #![feature(vec_into_raw_parts)]
 #![feature(toowned_clone_into)]
 #![feature(rustc_attrs)]
+#![allow(incomplete_features)]
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+#![allow(non_snake_case)]
+#![allow(clippy::missing_safety_doc)]
+#![allow(clippy::derive_hash_xor_eq)]
 
 #[cfg(target_env = "sgx")]
 extern crate sgx_types;
diff --git a/sgx_trts/src/veh.rs b/sgx_trts/src/veh.rs
index 88ae687..19b7342 100644
--- a/sgx_trts/src/veh.rs
+++ b/sgx_trts/src/veh.rs
@@ -107,6 +107,7 @@
 ///
 /// The exception handler was not unregistered (not a valid pointer, handler not found).
 ///
+#[allow(clippy::not_unsafe_ptr_arg_deref)]
 pub fn rsgx_unregister_exception_handler(handle: exception_handle) -> bool {
     let ret = unsafe { sgx_unregister_exception_handler(handle) };
     ret != 0
diff --git a/sgx_tse/Cargo.toml b/sgx_tse/Cargo.toml
index 2ece588..2ba59fd 100644
--- a/sgx_tse/Cargo.toml
+++ b/sgx_tse/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_tse"
diff --git a/sgx_tseal/Cargo.toml b/sgx_tseal/Cargo.toml
index 180edd0..45cb55a 100644
--- a/sgx_tseal/Cargo.toml
+++ b/sgx_tseal/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_tseal"
diff --git a/sgx_tstd/Cargo.toml b/sgx_tstd/Cargo.toml
index 2d27a6e..cac5bd6 100644
--- a/sgx_tstd/Cargo.toml
+++ b/sgx_tstd/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_tstd"
diff --git a/sgx_tstd/hashbrown/CHANGELOG.md b/sgx_tstd/hashbrown/CHANGELOG.md
index c88d3e0..4637bd0 100644
--- a/sgx_tstd/hashbrown/CHANGELOG.md
+++ b/sgx_tstd/hashbrown/CHANGELOG.md
@@ -2,11 +2,41 @@
 
 All notable changes to this project will be documented in this file.
 
-The format is based on [Keep a Changelog](http://keepachangelog.com/)
-and this project adheres to [Semantic Versioning](http://semver.org/).
+The format is based on [Keep a Changelog](https://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](https://semver.org/).
 
 ## [Unreleased]
 
+## [v0.12.0] - 2022-01-17
+
+## Added
+
+- Added `From<[T; N]>` and `From<[(K, V); N]>` for `HashSet` and `HashMap` respectively. (#297)
+- Added an `allocator()` getter to HashMap and HashSet. (#257)
+- Added `insert_unique_unchecked` to `HashMap` and `HashSet`. (#293)
+- Added `into_keys` and `into_values` to HashMap. (#295)
+- Implement `From<array>` on `HashSet` and `HashMap`. (#298)
+- Added `entry_ref` API to `HashMap`. (#201)
+
+## Changed
+
+- Bumped minimum Rust version to 1.56.1 and edition to 2021.
+- Use u64 for the GroupWord on WebAssembly. (#271)
+- Optimized `find`. (#279)
+- Made rehashing and resizing less generic to reduce compilation time. (#282)
+- Inlined small functions. (#283)
+- Use `BuildHasher::hash_one` when `feature = "nightly"` is enabled. (#292)
+- Relaxed the bounds on `Debug` for `HashSet`. (#296)
+- Rename `get_each_mut` to `get_many_mut` and align API with the stdlib. (#291)
+- Don't hash the key when searching in an empty table. (#305)
+
+## Fixed
+
+- Guard against allocations exceeding isize::MAX. (#268)
+- Made `RawTable::insert_no_grow` unsafe. (#254)
+- Inline `static_empty`. (#280)
+- Fixed trait bounds on Send/Sync impls. (#303)
+
 ## [v0.11.2] - 2021-03-25
 
 ## Fixed
@@ -307,7 +337,8 @@
 
 - Initial release
 
-[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...HEAD
+[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.12.0...HEAD
+[v0.12.0]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...v0.12.0
 [v0.11.2]: https://github.com/rust-lang/hashbrown/compare/v0.11.1...v0.11.2
 [v0.11.1]: https://github.com/rust-lang/hashbrown/compare/v0.11.0...v0.11.1
 [v0.11.0]: https://github.com/rust-lang/hashbrown/compare/v0.10.0...v0.11.0
diff --git a/sgx_tstd/hashbrown/Cargo.toml b/sgx_tstd/hashbrown/Cargo.toml
index 7bcb6ba..6927577 100644
--- a/sgx_tstd/hashbrown/Cargo.toml
+++ b/sgx_tstd/hashbrown/Cargo.toml
@@ -1,85 +1,63 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
-#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
-
 [package]
-edition = "2018"
 name = "hashbrown_tstd"
-version = "0.11.2"
+version = "0.12.0"
 authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
-exclude = [".travis.yml", "bors.toml", "/ci/*"]
 description = "A Rust port of Google's SwissTable hash map"
+license = "Apache-2.0/MIT"
+repository = "https://github.com/rust-lang/hashbrown"
 readme = "README.md"
 keywords = ["hash", "no_std", "hashmap", "swisstable"]
 categories = ["data-structures", "no-std"]
-license = "Apache-2.0/MIT"
-repository = "https://github.com/rust-lang/hashbrown"
-[package.metadata.docs.rs]
-features = ["nightly", "rayon", "serde", "raw"]
-[dependencies.ahash]
-version = "0.7.0"
-optional = true
-default-features = false
+exclude = [".github", "bors.toml", "/ci/*"]
+edition = "2021"
 
-# [dependencies.alloc]
-# version = "1.0.0"
-# optional = true
-# package = "rustc-std-workspace-alloc"
+[dependencies]
+# For the default hasher
+ahash = { version = "0.7.0", default-features = false, optional = true }
 
-[dependencies.bumpalo]
-version = "3.5.0"
-optional = true
+# For external trait impls
+rayon = { version = "1.0", optional = true }
+serde = { version = "1.0.25", default-features = false, optional = true }
 
-# [dependencies.compiler_builtins]
-# version = "0.1.2"
-# optional = true
+# When built as part of libstd
+# core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
+# compiler_builtins = { version = "0.1.2", optional = true }
+# alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
 
-# [dependencies.core]
-# version = "1.0.0"
-# optional = true
-# package = "rustc-std-workspace-core"
+# Optional support for bumpalo
+bumpalo = { version = "3.5.0", optional = true }
 
-[dependencies.rayon]
-version = "1.0"
-optional = true
-
-[dependencies.serde]
-version = "1.0.25"
-optional = true
-default-features = false
-[dev-dependencies.doc-comment]
-version = "0.3.1"
-
-[dev-dependencies.fnv]
-version = "1.0.7"
-
-[dev-dependencies.lazy_static]
-version = "1.4"
-
-[dev-dependencies.rand]
-version = "0.7.3"
-features = ["small_rng"]
-
-[dev-dependencies.rayon]
-version = "1.0"
-
-[dev-dependencies.serde_test]
-version = "1.0"
+[dev-dependencies]
+lazy_static = "1.4"
+rand = { version = "0.8.3", features = ["small_rng"] }
+rayon = "1.0"
+fnv = "1.0.7"
+serde_test = "1.0"
+doc-comment = "0.3.1"
 
 [features]
-ahash-compile-time-rng = ["ahash/compile-time-rng"]
 default = ["ahash", "inline-more"]
-inline-more = []
+
+ahash-compile-time-rng = ["ahash/compile-time-rng"]
 nightly = []
-raw = []
-# rustc-dep-of-std = ["nightly", "core", "compiler_builtins", "alloc", "rustc-internal-api"]
-rustc-dep-of-std = ["nightly", "rustc-internal-api"]
 rustc-internal-api = []
+# rustc-dep-of-std = [
+#     "nightly",
+#     "core",
+#     "compiler_builtins",
+#     "alloc",
+#     "rustc-internal-api",
+# ]
+rustc-dep-of-std = [
+    "nightly",
+    "rustc-internal-api",
+]
+raw = []
+
+# Enables usage of `#[inline]` on far more functions than by default in this
+# crate. This may lead to a performance increase but often comes at a compile
+# time cost.
+inline-more = []
+
+[package.metadata.docs.rs]
+features = ["nightly", "rayon", "serde", "raw"]
diff --git a/sgx_tstd/hashbrown/Cargo.toml.orig b/sgx_tstd/hashbrown/Cargo.toml.orig
deleted file mode 100644
index a056c3c..0000000
--- a/sgx_tstd/hashbrown/Cargo.toml.orig
+++ /dev/null
@@ -1,59 +0,0 @@
-[package]
-name = "hashbrown"
-version = "0.11.2"
-authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
-description = "A Rust port of Google's SwissTable hash map"
-license = "Apache-2.0/MIT"
-repository = "https://github.com/rust-lang/hashbrown"
-readme = "README.md"
-keywords = ["hash", "no_std", "hashmap", "swisstable"]
-categories = ["data-structures", "no-std"]
-exclude = [".travis.yml", "bors.toml", "/ci/*"]
-edition = "2018"
-
-[dependencies]
-# For the default hasher
-ahash = { version = "0.7.0", default-features = false, optional = true }
-
-# For external trait impls
-rayon = { version = "1.0", optional = true }
-serde = { version = "1.0.25", default-features = false, optional = true }
-
-# When built as part of libstd
-core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
-compiler_builtins = { version = "0.1.2", optional = true }
-alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
-
-# Optional support for bumpalo
-bumpalo = { version = "3.5.0", optional = true }
-
-[dev-dependencies]
-lazy_static = "1.4"
-rand = { version = "0.7.3", features = ["small_rng"] }
-rayon = "1.0"
-fnv = "1.0.7"
-serde_test = "1.0"
-doc-comment = "0.3.1"
-
-[features]
-default = ["ahash", "inline-more"]
-
-ahash-compile-time-rng = ["ahash/compile-time-rng"]
-nightly = []
-rustc-internal-api = []
-rustc-dep-of-std = [
-    "nightly",
-    "core",
-    "compiler_builtins",
-    "alloc",
-    "rustc-internal-api",
-]
-raw = []
-
-# Enables usage of `#[inline]` on far more functions than by default in this
-# crate. This may lead to a performance increase but often comes at a compile
-# time cost.
-inline-more = []
-
-[package.metadata.docs.rs]
-features = ["nightly", "rayon", "serde", "raw"]
diff --git a/sgx_tstd/hashbrown/README.md b/sgx_tstd/hashbrown/README.md
index 86664c4..0b29cb5 100644
--- a/sgx_tstd/hashbrown/README.md
+++ b/sgx_tstd/hashbrown/README.md
@@ -1,10 +1,10 @@
 hashbrown
 =========
 
-[![Build Status](https://travis-ci.com/rust-lang/hashbrown.svg?branch=master)](https://travis-ci.com/rust-lang/hashbrown)
+[![Build Status](https://github.com/rust-lang/hashbrown/actions/workflows/rust.yml/badge.svg)](https://github.com/rust-lang/hashbrown/actions)
 [![Crates.io](https://img.shields.io/crates/v/hashbrown.svg)](https://crates.io/crates/hashbrown)
 [![Documentation](https://docs.rs/hashbrown/badge.svg)](https://docs.rs/hashbrown)
-[![Rust](https://img.shields.io/badge/rust-1.49.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown)
+[![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown)
 
 This crate is a Rust port of Google's high-performance [SwissTable] hash
 map, adapted to make it a drop-in replacement for Rust's standard `HashMap`
@@ -114,8 +114,8 @@
 
 Licensed under either of:
 
- * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+ * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
 
 at your option.
 
diff --git a/sgx_tstd/hashbrown/benches/bench.rs b/sgx_tstd/hashbrown/benches/bench.rs
index 568c513..c393b9a 100644
--- a/sgx_tstd/hashbrown/benches/bench.rs
+++ b/sgx_tstd/hashbrown/benches/bench.rs
@@ -38,7 +38,7 @@
     type Item = usize;
     fn next(&mut self) -> Option<usize> {
         // Add 1 then multiply by some 32 bit prime.
-        self.state = self.state.wrapping_add(1).wrapping_mul(3787392781);
+        self.state = self.state.wrapping_add(1).wrapping_mul(3_787_392_781);
         Some(self.state)
     }
 }
diff --git a/sgx_tstd/hashbrown/benches/insert_unique_unchecked.rs b/sgx_tstd/hashbrown/benches/insert_unique_unchecked.rs
new file mode 100644
index 0000000..857ad18
--- /dev/null
+++ b/sgx_tstd/hashbrown/benches/insert_unique_unchecked.rs
@@ -0,0 +1,32 @@
+//! Compare `insert` and `insert_unique_unchecked` operations performance.
+
+#![feature(test)]
+
+extern crate test;
+
+use hashbrown::HashMap;
+use test::Bencher;
+
+#[bench]
+fn insert(b: &mut Bencher) {
+    let keys: Vec<String> = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect();
+    b.iter(|| {
+        let mut m = HashMap::with_capacity(1000);
+        for k in &keys {
+            m.insert(k, k);
+        }
+        m
+    });
+}
+
+#[bench]
+fn insert_unique_unchecked(b: &mut Bencher) {
+    let keys: Vec<String> = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect();
+    b.iter(|| {
+        let mut m = HashMap::with_capacity(1000);
+        for k in &keys {
+            m.insert_unique_unchecked(k, k);
+        }
+        m
+    });
+}
diff --git a/sgx_tstd/hashbrown/ci/miri.sh b/sgx_tstd/hashbrown/ci/miri.sh
new file mode 100644
index 0000000..6b95c2d
--- /dev/null
+++ b/sgx_tstd/hashbrown/ci/miri.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env sh
+
+set -ex
+
+export CARGO_NET_RETRY=5
+export CARGO_NET_TIMEOUT=10
+
+MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri)
+echo "Installing latest nightly with Miri: $MIRI_NIGHTLY"
+rustup default "$MIRI_NIGHTLY"
+
+rustup component add miri
+cargo miri setup
+
+cargo miri test
diff --git a/sgx_tstd/hashbrown/ci/run.sh b/sgx_tstd/hashbrown/ci/run.sh
new file mode 100644
index 0000000..a8257e5
--- /dev/null
+++ b/sgx_tstd/hashbrown/ci/run.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env sh
+
+set -ex
+
+: "${TARGET?The TARGET environment variable must be set.}"
+
+if [ "${NO_STD}" = "1" ]; then
+    # Unfortunately serde currently doesn't work without std due to a cargo bug.
+    FEATURES="rustc-internal-api"
+    OP="build"
+else
+    FEATURES="rustc-internal-api,serde,rayon,raw,bumpalo"
+    OP="test"
+fi
+if [ "${CHANNEL}" = "nightly" ]; then
+    FEATURES="${FEATURES},nightly"
+    export RUSTFLAGS="$RUSTFLAGS -D warnings"
+fi
+
+CARGO=cargo
+if [ "${CROSS}" = "1" ]; then
+    export CARGO_NET_RETRY=5
+    export CARGO_NET_TIMEOUT=10
+
+    cargo install --git https://github.com/rust-embedded/cross.git
+    CARGO=cross
+fi
+
+# Make sure we can compile without the default hasher
+"${CARGO}" -vv build --target="${TARGET}" --no-default-features
+"${CARGO}" -vv build --target="${TARGET}" --release --no-default-features
+
+"${CARGO}" -vv ${OP} --target="${TARGET}"
+"${CARGO}" -vv ${OP} --target="${TARGET}" --features "${FEATURES}"
+
+"${CARGO}" -vv ${OP} --target="${TARGET}" --release
+"${CARGO}" -vv ${OP} --target="${TARGET}" --release --features "${FEATURES}"
+
+if [ "${CHANNEL}" = "nightly" ] && [ "${NO_STD}" != 1 ]; then
+    # Run benchmark on native targets, build them on non-native ones:
+    NO_RUN=""
+    if [ "${CROSS}" = "1" ]; then
+        NO_RUN="--no-run"
+    fi
+
+    "${CARGO}" -vv bench "${NO_RUN}" --features "${FEATURES}"
+fi
diff --git a/sgx_tstd/hashbrown/ci/tools.sh b/sgx_tstd/hashbrown/ci/tools.sh
new file mode 100644
index 0000000..5ae8b2e
--- /dev/null
+++ b/sgx_tstd/hashbrown/ci/tools.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env sh
+
+set -ex
+
+retry() {
+    result=0
+    count=1
+    max=5
+    while [ "$count" -le 3 ]; do
+        [ "$result" -ne 0 ] && {
+            printf "\nRetrying, %d of %d\n" $count $max >&2
+        }
+        "$@"
+        result=$?
+        [ $result -eq 0 ] && break
+        count=$((count + 1))
+        sleep 1
+    done
+
+    [ "$count" -gt 3 ] && {
+        printf "\nFailed %d times.\n" $max >&2
+    }
+
+    return $result
+}
+
+
+if retry rustup component add rustfmt ; then
+    cargo fmt --all -- --check
+fi
+
+if retry rustup component add clippy ; then
+    cargo clippy --all --tests --features serde,rayon,bumpalo -- -D clippy::all -D clippy::pedantic
+    cargo clippy --all --tests --features raw -- -D clippy::all -D clippy::pedantic \
+        -A clippy::missing_safety_doc -A clippy::missing_errors_doc
+fi
+
+if command -v shellcheck ; then
+    shellcheck --version
+    shellcheck ci/*.sh
+fi
diff --git a/sgx_tstd/hashbrown/src/external_trait_impls/rayon/helpers.rs b/sgx_tstd/hashbrown/src/external_trait_impls/rayon/helpers.rs
index 9382007..070b08c 100644
--- a/sgx_tstd/hashbrown/src/external_trait_impls/rayon/helpers.rs
+++ b/sgx_tstd/hashbrown/src/external_trait_impls/rayon/helpers.rs
@@ -4,6 +4,7 @@
 use rayon::iter::{IntoParallelIterator, ParallelIterator};
 
 /// Helper for collecting parallel iterators to an intermediary
+#[allow(clippy::linkedlist)] // yes, we need linked list here for efficient appending!
 pub(super) fn collect<I: IntoParallelIterator>(iter: I) -> (LinkedList<Vec<I::Item>>, usize) {
     let list = iter
         .into_par_iter()
diff --git a/sgx_tstd/hashbrown/src/external_trait_impls/rayon/map.rs b/sgx_tstd/hashbrown/src/external_trait_impls/rayon/map.rs
index 61b7380..14d91c2 100644
--- a/sgx_tstd/hashbrown/src/external_trait_impls/rayon/map.rs
+++ b/sgx_tstd/hashbrown/src/external_trait_impls/rayon/map.rs
@@ -512,7 +512,7 @@
         where
             H: Hasher,
         {
-            self.k.hash(state)
+            self.k.hash(state);
         }
     }
 
@@ -679,7 +679,7 @@
     fn test_values_mut() {
         let vec = vec![(1, 1), (2, 2), (3, 3)];
         let mut map: HashMap<_, _> = vec.into_par_iter().collect();
-        map.par_values_mut().for_each(|value| *value = (*value) * 2);
+        map.par_values_mut().for_each(|value| *value *= 2);
         let values: Vec<_> = map.par_values().cloned().collect();
         assert_eq!(values.len(), 3);
         assert!(values.contains(&2));
diff --git a/sgx_tstd/hashbrown/src/external_trait_impls/rayon/raw.rs b/sgx_tstd/hashbrown/src/external_trait_impls/rayon/raw.rs
index 18da1ea..883303e 100644
--- a/sgx_tstd/hashbrown/src/external_trait_impls/rayon/raw.rs
+++ b/sgx_tstd/hashbrown/src/external_trait_impls/rayon/raw.rs
@@ -87,7 +87,7 @@
     }
 }
 
-impl<T: Send, A: Allocator + Clone> ParallelIterator for RawIntoParIter<T, A> {
+impl<T: Send, A: Allocator + Clone + Send> ParallelIterator for RawIntoParIter<T, A> {
     type Item = T;
 
     #[cfg_attr(feature = "inline-more", inline)]
@@ -116,7 +116,7 @@
     marker: PhantomData<&'a RawTable<T, A>>,
 }
 
-unsafe impl<T, A: Allocator + Clone> Send for RawParDrain<'_, T, A> {}
+unsafe impl<T: Send, A: Allocator + Clone> Send for RawParDrain<'_, T, A> {}
 
 impl<T, A: Allocator + Clone> RawParDrain<'_, T, A> {
     #[cfg_attr(feature = "inline-more", inline)]
@@ -134,7 +134,7 @@
         C: UnindexedConsumer<Self::Item>,
     {
         let _guard = guard(self.table, |table| unsafe {
-            table.as_mut().clear_no_drop()
+            table.as_mut().clear_no_drop();
         });
         let iter = unsafe { self.table.as_ref().iter().iter };
         mem::forget(self);
@@ -146,7 +146,9 @@
 impl<T, A: Allocator + Clone> Drop for RawParDrain<'_, T, A> {
     fn drop(&mut self) {
         // If drive_unindexed is not called then simply clear the table.
-        unsafe { self.table.as_mut().clear() }
+        unsafe {
+            self.table.as_mut().clear();
+        }
     }
 }
 
@@ -175,7 +177,7 @@
     {
         // Make sure to modify the iterator in-place so that any remaining
         // elements are processed in our Drop impl.
-        while let Some(item) = self.iter.next() {
+        for item in &mut self.iter {
             folder = folder.consume(unsafe { item.read() });
             if folder.full() {
                 return folder;
@@ -193,7 +195,7 @@
     fn drop(&mut self) {
         // Drop all remaining elements
         if mem::needs_drop::<T>() {
-            while let Some(item) = self.iter.next() {
+            for item in &mut self.iter {
                 unsafe {
                     item.drop();
                 }
diff --git a/sgx_tstd/hashbrown/src/external_trait_impls/serde.rs b/sgx_tstd/hashbrown/src/external_trait_impls/serde.rs
index 7816e78..4d62dee 100644
--- a/sgx_tstd/hashbrown/src/external_trait_impls/serde.rs
+++ b/sgx_tstd/hashbrown/src/external_trait_impls/serde.rs
@@ -161,6 +161,7 @@
             deserializer.deserialize_seq(visitor)
         }
 
+        #[allow(clippy::missing_errors_doc)]
         fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
         where
             D: Deserializer<'de>,
diff --git a/sgx_tstd/hashbrown/src/lib.rs b/sgx_tstd/hashbrown/src/lib.rs
index b2d6584..701b6ea 100644
--- a/sgx_tstd/hashbrown/src/lib.rs
+++ b/sgx_tstd/hashbrown/src/lib.rs
@@ -21,7 +21,8 @@
         allocator_api,
         slice_ptr_get,
         nonnull_slice_from_raw_parts,
-        maybe_uninit_array_assume_init
+        maybe_uninit_array_assume_init,
+        build_hasher_simple_hash_one
     )
 )]
 #![allow(
@@ -128,20 +129,6 @@
     },
 }
 
-/// The error type for [`RawTable::get_each_mut`](crate::raw::RawTable::get_each_mut),
-/// [`HashMap::get_each_mut`], and [`HashMap::get_each_key_value_mut`].
-#[cfg(feature = "nightly")]
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub enum UnavailableMutError {
-    /// The requested entry is not present in the table.
-    Absent,
-    /// The requested entry is present, but a mutable reference to it was already created and
-    /// returned from this call to `get_each_mut` or `get_each_key_value_mut`.
-    ///
-    /// Includes the index of the existing mutable reference in the returned array.
-    Duplicate(usize),
-}
-
 /// Wrapper around `Bump` which allows it to be used as an allocator for
 /// `HashMap`, `HashSet` and `RawTable`.
 ///
diff --git a/sgx_tstd/hashbrown/src/macros.rs b/sgx_tstd/hashbrown/src/macros.rs
index 0279597..4de6b5a 100644
--- a/sgx_tstd/hashbrown/src/macros.rs
+++ b/sgx_tstd/hashbrown/src/macros.rs
@@ -57,8 +57,8 @@
 // default fn syntax for specialization changes in the future.
 #[cfg(feature = "nightly")]
 macro_rules! default_fn {
-	($($tt:tt)*) => {
-        default $($tt)*
+	(#[$($a:tt)*] $($tt:tt)*) => {
+        #[$($a)*] default $($tt)*
     }
 }
 #[cfg(not(feature = "nightly"))]
diff --git a/sgx_tstd/hashbrown/src/map.rs b/sgx_tstd/hashbrown/src/map.rs
index ab11288..d0592cb 100644
--- a/sgx_tstd/hashbrown/src/map.rs
+++ b/sgx_tstd/hashbrown/src/map.rs
@@ -1,15 +1,11 @@
 use crate::raw::{Allocator, Bucket, Global, RawDrain, RawIntoIter, RawIter, RawTable};
 use crate::TryReserveError;
-#[cfg(feature = "nightly")]
-use crate::UnavailableMutError;
 use core::borrow::Borrow;
 use core::fmt::{self, Debug};
 use core::hash::{BuildHasher, Hash};
 use core::iter::{FromIterator, FusedIterator};
 use core::marker::PhantomData;
 use core::mem;
-#[cfg(feature = "nightly")]
-use core::mem::MaybeUninit;
 use core::ops::Index;
 
 /// Default hasher for `HashMap`.
@@ -244,6 +240,7 @@
     move |x| k.eq(x.borrow())
 }
 
+#[cfg(not(feature = "nightly"))]
 #[cfg_attr(feature = "inline-more", inline)]
 pub(crate) fn make_hash<K, Q, S>(hash_builder: &S, val: &Q) -> u64
 where
@@ -257,6 +254,18 @@
     state.finish()
 }
 
+#[cfg(feature = "nightly")]
+#[cfg_attr(feature = "inline-more", inline)]
+pub(crate) fn make_hash<K, Q, S>(hash_builder: &S, val: &Q) -> u64
+where
+    K: Borrow<Q>,
+    Q: Hash + ?Sized,
+    S: BuildHasher,
+{
+    hash_builder.hash_one(val)
+}
+
+#[cfg(not(feature = "nightly"))]
 #[cfg_attr(feature = "inline-more", inline)]
 pub(crate) fn make_insert_hash<K, S>(hash_builder: &S, val: &K) -> u64
 where
@@ -269,6 +278,16 @@
     state.finish()
 }
 
+#[cfg(feature = "nightly")]
+#[cfg_attr(feature = "inline-more", inline)]
+pub(crate) fn make_insert_hash<K, S>(hash_builder: &S, val: &K) -> u64
+where
+    K: Hash,
+    S: BuildHasher,
+{
+    hash_builder.hash_one(val)
+}
+
 #[cfg(feature = "ahash")]
 impl<K, V> HashMap<K, V, DefaultHashBuilder> {
     /// Creates an empty `HashMap`.
@@ -395,6 +414,12 @@
 }
 
 impl<K, V, S, A: Allocator + Clone> HashMap<K, V, S, A> {
+    /// Returns a reference to the underlying allocator.
+    #[inline]
+    pub fn allocator(&self) -> &A {
+        self.table.allocator()
+    }
+
     /// Creates an empty `HashMap` which will use the given hash builder to hash
     /// keys. It will be allocated with the given allocator.
     ///
@@ -773,6 +798,52 @@
     pub fn clear(&mut self) {
         self.table.clear();
     }
+
+    /// Creates a consuming iterator visiting all the keys in arbitrary order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `K`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// let vec: Vec<&str> = map.into_keys().collect();
+    /// ```
+    #[inline]
+    pub fn into_keys(self) -> IntoKeys<K, V, A> {
+        IntoKeys {
+            inner: self.into_iter(),
+        }
+    }
+
+    /// Creates a consuming iterator visiting all the values in arbitrary order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `V`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// let vec: Vec<i32> = map.into_values().collect();
+    /// ```
+    #[inline]
+    pub fn into_values(self) -> IntoValues<K, V, A> {
+        IntoValues {
+            inner: self.into_iter(),
+        }
+    }
 }
 
 impl<K, V, S, A> HashMap<K, V, S, A>
@@ -915,6 +986,46 @@
         }
     }
 
+    /// Gets the given key's corresponding entry by reference in the map for in-place manipulation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut words: HashMap<String, usize> = HashMap::new();
+    /// let source = ["poneyland", "horseyland", "poneyland", "poneyland"];
+    /// for (i, &s) in source.iter().enumerate() {
+    ///     let counter = words.entry_ref(s).or_insert(0);
+    ///     *counter += 1;
+    /// }
+    ///
+    /// assert_eq!(words["poneyland"], 3);
+    /// assert_eq!(words["horseyland"], 1);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn entry_ref<'a, 'b, Q: ?Sized>(&'a mut self, key: &'b Q) -> EntryRef<'a, 'b, K, Q, V, S, A>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        let hash = make_hash::<K, Q, S>(&self.hash_builder, key);
+        if let Some(elem) = self.table.find(hash, equivalent_key(key)) {
+            EntryRef::Occupied(OccupiedEntryRef {
+                hash,
+                key: Some(KeyOrRef::Borrowed(key)),
+                elem,
+                table: self,
+            })
+        } else {
+            EntryRef::Vacant(VacantEntryRef {
+                hash,
+                key: KeyOrRef::Borrowed(key),
+                table: self,
+            })
+        }
+    }
+
     /// Returns a reference to the value corresponding to the key.
     ///
     /// The key may be any borrowed form of the map's key type, but
@@ -985,8 +1096,12 @@
         K: Borrow<Q>,
         Q: Hash + Eq,
     {
-        let hash = make_hash::<K, Q, S>(&self.hash_builder, k);
-        self.table.get(hash, equivalent_key(k))
+        if self.table.is_empty() {
+            None
+        } else {
+            let hash = make_hash::<K, Q, S>(&self.hash_builder, k);
+            self.table.get(hash, equivalent_key(k))
+        }
     }
 
     /// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value.
@@ -1093,24 +1208,24 @@
         K: Borrow<Q>,
         Q: Hash + Eq,
     {
-        let hash = make_hash::<K, Q, S>(&self.hash_builder, k);
-        self.table.get_mut(hash, equivalent_key(k))
+        if self.table.is_empty() {
+            None
+        } else {
+            let hash = make_hash::<K, Q, S>(&self.hash_builder, k);
+            self.table.get_mut(hash, equivalent_key(k))
+        }
     }
 
     /// Attempts to get mutable references to `N` values in the map at once.
     ///
-    /// Returns an array of length `N` with the results of each query. For soundness,
-    /// at most one mutable reference will be returned to any value. An
-    /// `Err(UnavailableMutError::Duplicate(i))` in the returned array indicates that a suitable
-    /// key-value pair exists, but a mutable reference to the value already occurs at index `i` in
-    /// the returned array.
-    ///
-    /// This method is available only if the `nightly` feature is enabled.
+    /// Returns an array of length `N` with the results of each query. For soundness, at most one
+    /// mutable reference will be returned to any value. `None` will be returned if any of the
+    /// keys are duplicates or missing.
     ///
     /// # Examples
     ///
     /// ```
-    /// use hashbrown::{HashMap, UnavailableMutError};
+    /// use hashbrown::HashMap;
     ///
     /// let mut libraries = HashMap::new();
     /// libraries.insert("Bodleian Library".to_string(), 1602);
@@ -1118,58 +1233,59 @@
     /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
     /// libraries.insert("Library of Congress".to_string(), 1800);
     ///
-    /// let got = libraries.get_each_mut([
-    ///     "Athenæum",
-    ///     "New York Public Library",
+    /// let got = libraries.get_many_mut([
     ///     "Athenæum",
     ///     "Library of Congress",
     /// ]);
     /// assert_eq!(
     ///     got,
-    ///     [
-    ///         Ok(&mut 1807),
-    ///         Err(UnavailableMutError::Absent),
-    ///         Err(UnavailableMutError::Duplicate(0)),
-    ///         Ok(&mut 1800),
-    ///     ]
+    ///     Some([
+    ///         &mut 1807,
+    ///         &mut 1800,
+    ///     ]),
     /// );
+    ///
+    /// // Missing keys result in None
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "New York Public Library",
+    /// ]);
+    /// assert_eq!(got, None);
+    ///
+    /// // Duplicate keys result in None
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "Athenæum",
+    /// ]);
+    /// assert_eq!(got, None);
     /// ```
-    #[cfg(feature = "nightly")]
-    pub fn get_each_mut<Q: ?Sized, const N: usize>(
-        &mut self,
-        ks: [&Q; N],
-    ) -> [Result<&'_ mut V, UnavailableMutError>; N]
+    pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]>
     where
         K: Borrow<Q>,
         Q: Hash + Eq,
     {
-        let mut pairs = self.get_each_inner_mut(ks);
-        // TODO use `MaybeUninit::uninit_array` here instead once that's stable.
-        let mut out: [MaybeUninit<Result<&'_ mut V, UnavailableMutError>>; N] =
-            unsafe { MaybeUninit::uninit().assume_init() };
-        for i in 0..N {
-            out[i] = MaybeUninit::new(
-                mem::replace(&mut pairs[i], Err(UnavailableMutError::Absent)).map(|(_, v)| v),
-            );
-        }
-        unsafe { MaybeUninit::array_assume_init(out) }
+        self.get_many_mut_inner(ks).map(|res| res.map(|(_, v)| v))
     }
 
-    /// Attempts to get mutable references to `N` values in the map at once, with immutable
-    /// references to the corresponding keys.
+    /// Attempts to get mutable references to `N` values in the map at once, without validating that
+    /// the values are unique.
     ///
-    /// Returns an array of length `N` with the results of each query. For soundness,
-    /// at most one mutable reference will be returned to any value. An
-    /// `Err(UnavailableMutError::Duplicate(i))` in the returned array indicates that a suitable
-    /// key-value pair exists, but a mutable reference to the value already occurs at index `i` in
-    /// the returned array.
+    /// Returns an array of length `N` with the results of each query. `None` will be returned if
+    /// any of the keys are missing.
     ///
-    /// This method is available only if the `nightly` feature is enabled.
+    /// For a safe alternative see [`get_many_mut`].
+    ///
+    /// # Safety
+    ///
+    /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting
+    /// references are not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
     ///
     /// # Examples
     ///
     /// ```
-    /// use hashbrown::{HashMap, UnavailableMutError};
+    /// use hashbrown::HashMap;
     ///
     /// let mut libraries = HashMap::new();
     /// libraries.insert("Bodleian Library".to_string(), 1602);
@@ -1177,49 +1293,176 @@
     /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
     /// libraries.insert("Library of Congress".to_string(), 1800);
     ///
-    /// let got = libraries.get_each_key_value_mut([
-    ///     "Bodleian Library",
-    ///     "Herzogin-Anna-Amalia-Bibliothek",
-    ///     "Herzogin-Anna-Amalia-Bibliothek",
-    ///     "Gewandhaus",
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "Library of Congress",
     /// ]);
     /// assert_eq!(
     ///     got,
-    ///     [
-    ///         Ok((&"Bodleian Library".to_string(), &mut 1602)),
-    ///         Ok((&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691)),
-    ///         Err(UnavailableMutError::Duplicate(1)),
-    ///         Err(UnavailableMutError::Absent),
-    ///     ]
+    ///     Some([
+    ///         &mut 1807,
+    ///         &mut 1800,
+    ///     ]),
     /// );
+    ///
+    /// // Missing keys result in None
+    /// let got = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "New York Public Library",
+    /// ]);
+    /// assert_eq!(got, None);
     /// ```
-    #[cfg(feature = "nightly")]
-    pub fn get_each_key_value_mut<Q: ?Sized, const N: usize>(
+    pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>(
         &mut self,
         ks: [&Q; N],
-    ) -> [Result<(&'_ K, &'_ mut V), UnavailableMutError>; N]
+    ) -> Option<[&'_ mut V; N]>
     where
         K: Borrow<Q>,
         Q: Hash + Eq,
     {
-        let mut pairs = self.get_each_inner_mut(ks);
-        // TODO use `MaybeUninit::uninit_array` here instead once that's stable.
-        let mut out: [MaybeUninit<Result<(&'_ K, &'_ mut V), UnavailableMutError>>; N] =
-            unsafe { MaybeUninit::uninit().assume_init() };
-        for i in 0..N {
-            out[i] = MaybeUninit::new(
-                mem::replace(&mut pairs[i], Err(UnavailableMutError::Absent))
-                    .map(|(k, v)| (&*k, v)),
-            );
-        }
-        unsafe { MaybeUninit::array_assume_init(out) }
+        self.get_many_unchecked_mut_inner(ks)
+            .map(|res| res.map(|(_, v)| v))
     }
 
-    #[cfg(feature = "nightly")]
-    fn get_each_inner_mut<Q: ?Sized, const N: usize>(
+    /// Attempts to get mutable references to `N` values in the map at once, with immutable
+    /// references to the corresponding keys.
+    ///
+    /// Returns an array of length `N` with the results of each query. For soundness, at most one
+    /// mutable reference will be returned to any value. `None` will be returned if any of the keys
+    /// are duplicates or missing.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut libraries = HashMap::new();
+    /// libraries.insert("Bodleian Library".to_string(), 1602);
+    /// libraries.insert("Athenæum".to_string(), 1807);
+    /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
+    /// libraries.insert("Library of Congress".to_string(), 1800);
+    ///
+    /// let got = libraries.get_many_key_value_mut([
+    ///     "Bodleian Library",
+    ///     "Herzogin-Anna-Amalia-Bibliothek",
+    /// ]);
+    /// assert_eq!(
+    ///     got,
+    ///     Some([
+    ///         (&"Bodleian Library".to_string(), &mut 1602),
+    ///         (&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691),
+    ///     ]),
+    /// );
+    /// // Missing keys result in None
+    /// let got = libraries.get_many_key_value_mut([
+    ///     "Bodleian Library",
+    ///     "Gewandhaus",
+    /// ]);
+    /// assert_eq!(got, None);
+    ///
+    /// // Duplicate keys result in None
+    /// let got = libraries.get_many_key_value_mut([
+    ///     "Bodleian Library",
+    ///     "Herzogin-Anna-Amalia-Bibliothek",
+    ///     "Herzogin-Anna-Amalia-Bibliothek",
+    /// ]);
+    /// assert_eq!(got, None);
+    /// ```
+    pub fn get_many_key_value_mut<Q: ?Sized, const N: usize>(
         &mut self,
         ks: [&Q; N],
-    ) -> [Result<&'_ mut (K, V), UnavailableMutError>; N]
+    ) -> Option<[(&'_ K, &'_ mut V); N]>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.get_many_mut_inner(ks)
+            .map(|res| res.map(|(k, v)| (&*k, v)))
+    }
+
+    /// Attempts to get mutable references to `N` values in the map at once, with immutable
+    /// references to the corresponding keys, without validating that the values are unique.
+    ///
+    /// Returns an array of length `N` with the results of each query. `None` will be returned if
+    /// any of the keys are missing.
+    ///
+    /// For a safe alternative see [`get_many_key_value_mut`].
+    ///
+    /// # Safety
+    ///
+    /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting
+    /// references are not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut libraries = HashMap::new();
+    /// libraries.insert("Bodleian Library".to_string(), 1602);
+    /// libraries.insert("Athenæum".to_string(), 1807);
+    /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
+    /// libraries.insert("Library of Congress".to_string(), 1800);
+    ///
+    /// let got = libraries.get_many_key_value_mut([
+    ///     "Bodleian Library",
+    ///     "Herzogin-Anna-Amalia-Bibliothek",
+    /// ]);
+    /// assert_eq!(
+    ///     got,
+    ///     Some([
+    ///         (&"Bodleian Library".to_string(), &mut 1602),
+    ///         (&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691),
+    ///     ]),
+    /// );
+    /// // Missing keys result in None
+    /// let got = libraries.get_many_key_value_mut([
+    ///     "Bodleian Library",
+    ///     "Gewandhaus",
+    /// ]);
+    /// assert_eq!(got, None);
+    /// ```
+    pub unsafe fn get_many_key_value_unchecked_mut<Q: ?Sized, const N: usize>(
+        &mut self,
+        ks: [&Q; N],
+    ) -> Option<[(&'_ K, &'_ mut V); N]>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.get_many_unchecked_mut_inner(ks)
+            .map(|res| res.map(|(k, v)| (&*k, v)))
+    }
+
+    fn get_many_mut_inner<Q: ?Sized, const N: usize>(
+        &mut self,
+        ks: [&Q; N],
+    ) -> Option<[&'_ mut (K, V); N]>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        let hashes = self.build_hashes_inner(ks);
+        self.table
+            .get_many_mut(hashes, |i, (k, _)| ks[i].eq(k.borrow()))
+    }
+
+    unsafe fn get_many_unchecked_mut_inner<Q: ?Sized, const N: usize>(
+        &mut self,
+        ks: [&Q; N],
+    ) -> Option<[&'_ mut (K, V); N]>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        let hashes = self.build_hashes_inner(ks);
+        self.table
+            .get_many_unchecked_mut(hashes, |i, (k, _)| ks[i].eq(k.borrow()))
+    }
+
+    fn build_hashes_inner<Q: ?Sized, const N: usize>(&self, ks: [&Q; N]) -> [u64; N]
     where
         K: Borrow<Q>,
         Q: Hash + Eq,
@@ -1228,8 +1471,7 @@
         for i in 0..N {
             hashes[i] = make_hash::<K, Q, S>(&self.hash_builder, ks[i]);
         }
-        self.table
-            .get_each_mut(hashes, |i, (k, _)| ks[i].eq(k.borrow()))
+        hashes
     }
 
     /// Inserts a key-value pair into the map.
@@ -1269,6 +1511,36 @@
         }
     }
 
+    /// Insert a key-value pair into the map without checking
+    /// if the key already exists in the map.
+    ///
+    /// Returns a reference to the key and value just inserted.
+    ///
+    /// This operation is safe if a key does not exist in the map.
+    ///
+    /// However, if a key exists in the map already, the behavior is unspecified:
+    /// this operation may panic, loop forever, or any following operation with the map
+    /// may panic, loop forever or return arbitrary result.
+    ///
+    /// That said, this operation (and following operations) are guaranteed to
+    /// not violate memory safety.
+    ///
+    /// This operation is faster than regular insert, because it does not perform
+    /// lookup before insertion.
+    ///
+    /// This operation is useful during initial population of the map.
+    /// For example, when constructing a map from another map, we know
+    /// that keys are unique.
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) {
+        let hash = make_insert_hash::<K, S>(&self.hash_builder, &k);
+        let bucket = self
+            .table
+            .insert(hash, (k, v), make_hasher::<K, _, V, S>(&self.hash_builder));
+        let (k_ref, v_ref) = unsafe { bucket.as_mut() };
+        (k_ref, v_ref)
+    }
+
     /// Tries to insert a key-value pair into the map, and returns
     /// a mutable reference to the value in the entry.
     ///
@@ -1495,6 +1767,27 @@
     }
 }
 
+// The default hasher is used to match the std implementation signature
+#[cfg(feature = "ahash")]
+impl<K, V, A, const N: usize> From<[(K, V); N]> for HashMap<K, V, DefaultHashBuilder, A>
+where
+    K: Eq + Hash,
+    A: Default + Allocator + Clone,
+{
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let map1 = HashMap::from([(1, 2), (3, 4)]);
+    /// let map2: HashMap<_, _> = [(1, 2), (3, 4)].into();
+    /// assert_eq!(map1, map2);
+    /// ```
+    fn from(arr: [(K, V); N]) -> Self {
+        arr.into_iter().collect()
+    }
+}
+
 /// An iterator over the entries of a `HashMap`.
 ///
 /// This `struct` is created by the [`iter`] method on [`HashMap`]. See its
@@ -1575,6 +1868,88 @@
     }
 }
 
+/// An owning iterator over the keys of a `HashMap`.
+///
+/// This `struct` is created by the [`into_keys`] method on [`HashMap`].
+/// See its documentation for more.
+///
+/// [`into_keys`]: struct.HashMap.html#method.into_keys
+/// [`HashMap`]: struct.HashMap.html
+pub struct IntoKeys<K, V, A: Allocator + Clone = Global> {
+    inner: IntoIter<K, V, A>,
+}
+
+impl<K, V, A: Allocator + Clone> Iterator for IntoKeys<K, V, A> {
+    type Item = K;
+
+    #[inline]
+    fn next(&mut self) -> Option<K> {
+        self.inner.next().map(|(k, _)| k)
+    }
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+impl<K, V, A: Allocator + Clone> ExactSizeIterator for IntoKeys<K, V, A> {
+    #[inline]
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+
+impl<K, V, A: Allocator + Clone> FusedIterator for IntoKeys<K, V, A> {}
+
+impl<K: Debug, V: Debug, A: Allocator + Clone> fmt::Debug for IntoKeys<K, V, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list()
+            .entries(self.inner.iter().map(|(k, _)| k))
+            .finish()
+    }
+}
+
+/// An owning iterator over the values of a `HashMap`.
+///
+/// This `struct` is created by the [`into_values`] method on [`HashMap`].
+/// See its documentation for more.
+///
+/// [`into_values`]: struct.HashMap.html#method.into_values
+/// [`HashMap`]: struct.HashMap.html
+pub struct IntoValues<K, V, A: Allocator + Clone = Global> {
+    inner: IntoIter<K, V, A>,
+}
+
+impl<K, V, A: Allocator + Clone> Iterator for IntoValues<K, V, A> {
+    type Item = V;
+
+    #[inline]
+    fn next(&mut self) -> Option<V> {
+        self.inner.next().map(|(_, v)| v)
+    }
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+impl<K, V, A: Allocator + Clone> ExactSizeIterator for IntoValues<K, V, A> {
+    #[inline]
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+
+impl<K, V, A: Allocator + Clone> FusedIterator for IntoValues<K, V, A> {}
+
+impl<K: Debug, V: Debug, A: Allocator + Clone> fmt::Debug for IntoValues<K, V, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list()
+            .entries(self.inner.iter().map(|(k, _)| k))
+            .finish()
+    }
+}
+
 /// An iterator over the keys of a `HashMap`.
 ///
 /// This `struct` is created by the [`keys`] method on [`HashMap`]. See its
@@ -1686,7 +2061,7 @@
 impl<T: Iterator> Drop for ConsumeAllOnDrop<'_, T> {
     #[cfg_attr(feature = "inline-more", inline)]
     fn drop(&mut self) {
-        self.0.for_each(drop)
+        self.0.for_each(drop);
     }
 }
 
@@ -1723,7 +2098,7 @@
         F: FnMut(&K, &mut V) -> bool,
     {
         unsafe {
-            while let Some(item) = self.iter.next() {
+            for item in &mut self.iter {
                 let &mut (ref key, ref mut value) = item.as_mut();
                 if f(key, value) {
                     return Some(self.table.remove(item));
@@ -1786,6 +2161,7 @@
 where
     K: Send,
     V: Send,
+    S: Send,
     A: Send + Allocator + Clone,
 {
 }
@@ -1793,7 +2169,8 @@
 where
     K: Sync,
     V: Sync,
-    A: Send + Allocator + Clone,
+    S: Sync,
+    A: Sync + Allocator + Clone,
 {
 }
 
@@ -2413,6 +2790,119 @@
     }
 }
 
+/// A view into a single entry in a map, which may either be vacant or occupied.
+///
+/// This `enum` is constructed from the [`entry_ref`] method on [`HashMap`].
+///
+/// [`HashMap`]: struct.HashMap.html
+/// [`entry_ref`]: struct.HashMap.html#method.entry_ref
+pub enum EntryRef<'a, 'b, K, Q: ?Sized, V, S, A = Global>
+where
+    A: Allocator + Clone,
+{
+    /// An occupied entry.
+    Occupied(OccupiedEntryRef<'a, 'b, K, Q, V, S, A>),
+
+    /// A vacant entry.
+    Vacant(VacantEntryRef<'a, 'b, K, Q, V, S, A>),
+}
+
+impl<K: Borrow<Q>, Q: ?Sized + Debug, V: Debug, S, A: Allocator + Clone> Debug
+    for EntryRef<'_, '_, K, Q, V, S, A>
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            EntryRef::Vacant(ref v) => f.debug_tuple("EntryRef").field(v).finish(),
+            EntryRef::Occupied(ref o) => f.debug_tuple("EntryRef").field(o).finish(),
+        }
+    }
+}
+
+enum KeyOrRef<'a, K, Q: ?Sized> {
+    Borrowed(&'a Q),
+    Owned(K),
+}
+
+impl<'a, K, Q: ?Sized> KeyOrRef<'a, K, Q> {
+    fn into_owned(self) -> K
+    where
+        K: From<&'a Q>,
+    {
+        match self {
+            Self::Borrowed(borrowed) => borrowed.into(),
+            Self::Owned(owned) => owned,
+        }
+    }
+}
+
+impl<'a, K: Borrow<Q>, Q: ?Sized> AsRef<Q> for KeyOrRef<'a, K, Q> {
+    fn as_ref(&self) -> &Q {
+        match self {
+            Self::Borrowed(borrowed) => borrowed,
+            Self::Owned(owned) => owned.borrow(),
+        }
+    }
+}
+
+/// A view into an occupied entry in a `HashMap`.
+/// It is part of the [`EntryRef`] enum.
+///
+/// [`EntryRef`]: enum.EntryRef.html
+pub struct OccupiedEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone = Global> {
+    hash: u64,
+    key: Option<KeyOrRef<'b, K, Q>>,
+    elem: Bucket<(K, V)>,
+    table: &'a mut HashMap<K, V, S, A>,
+}
+
+unsafe impl<'a, 'b, K, Q, V, S, A> Send for OccupiedEntryRef<'a, 'b, K, Q, V, S, A>
+where
+    K: Send,
+    Q: Sync + ?Sized,
+    V: Send,
+    S: Send,
+    A: Send + Allocator + Clone,
+{
+}
+unsafe impl<'a, 'b, K, Q, V, S, A> Sync for OccupiedEntryRef<'a, 'b, K, Q, V, S, A>
+where
+    K: Sync,
+    Q: Sync + ?Sized,
+    V: Sync,
+    S: Sync,
+    A: Sync + Allocator + Clone,
+{
+}
+
+impl<K: Borrow<Q>, Q: ?Sized + Debug, V: Debug, S, A: Allocator + Clone> Debug
+    for OccupiedEntryRef<'_, '_, K, Q, V, S, A>
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OccupiedEntryRef")
+            .field("key", &self.key())
+            .field("value", &self.get())
+            .finish()
+    }
+}
+
+/// A view into a vacant entry in a `HashMap`.
+/// It is part of the [`EntryRef`] enum.
+///
+/// [`EntryRef`]: enum.EntryRef.html
+pub struct VacantEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone = Global> {
+    hash: u64,
+    key: KeyOrRef<'b, K, Q>,
+    table: &'a mut HashMap<K, V, S, A>,
+}
+
+impl<K: Borrow<Q>, Q: ?Sized + Debug, V, S, A: Allocator + Clone> Debug
+    for VacantEntryRef<'_, '_, K, Q, V, S, A>
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("VacantEntryRef").field(&self.key()).finish()
+    }
+}
+
 /// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists.
 ///
 /// Contains the occupied entry, and the value that was not inserted.
@@ -3362,6 +3852,689 @@
     }
 }
 
+impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> EntryRef<'a, 'b, K, Q, V, S, A> {
+    /// Sets the value of the entry, and returns an OccupiedEntryRef.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// let entry = map.entry_ref("horseyland").insert(37);
+    ///
+    /// assert_eq!(entry.key(), "horseyland");
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn insert(self, value: V) -> OccupiedEntryRef<'a, 'b, K, Q, V, S, A>
+    where
+        K: Hash + From<&'b Q>,
+        S: BuildHasher,
+    {
+        match self {
+            EntryRef::Occupied(mut entry) => {
+                entry.insert(value);
+                entry
+            }
+            EntryRef::Vacant(entry) => entry.insert_entry(value),
+        }
+    }
+
+    /// Ensures a value is in the entry by inserting the default if empty, and returns
+    /// a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    ///
+    /// map.entry_ref("poneyland").or_insert(3);
+    /// assert_eq!(map["poneyland"], 3);
+    ///
+    /// *map.entry_ref("poneyland").or_insert(10) *= 2;
+    /// assert_eq!(map["poneyland"], 6);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn or_insert(self, default: V) -> &'a mut V
+    where
+        K: Hash + From<&'b Q>,
+        S: BuildHasher,
+    {
+        match self {
+            EntryRef::Occupied(entry) => entry.into_mut(),
+            EntryRef::Vacant(entry) => entry.insert(default),
+        }
+    }
+
+    /// Ensures a value is in the entry by inserting the result of the default function if empty,
+    /// and returns a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<String, String> = HashMap::new();
+    /// let s = "hoho".to_string();
+    ///
+    /// map.entry_ref("poneyland").or_insert_with(|| s);
+    ///
+    /// assert_eq!(map["poneyland"], "hoho".to_string());
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V
+    where
+        K: Hash + From<&'b Q>,
+        S: BuildHasher,
+    {
+        match self {
+            EntryRef::Occupied(entry) => entry.into_mut(),
+            EntryRef::Vacant(entry) => entry.insert(default()),
+        }
+    }
+
+    /// Ensures a value is in the entry by inserting, if empty, the result of the default function.
+    /// This method allows for generating key-derived values for insertion by providing the default
+    /// function a reference to the key that was moved during the `.entry_ref(key)` method call.
+    ///
+    /// The reference to the moved key is provided so that cloning or copying the key is
+    /// unnecessary, unlike with `.or_insert_with(|| ... )`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<String, usize> = HashMap::new();
+    ///
+    /// map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count());
+    ///
+    /// assert_eq!(map["poneyland"], 9);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn or_insert_with_key<F: FnOnce(&Q) -> V>(self, default: F) -> &'a mut V
+    where
+        K: Hash + Borrow<Q> + From<&'b Q>,
+        S: BuildHasher,
+    {
+        match self {
+            EntryRef::Occupied(entry) => entry.into_mut(),
+            EntryRef::Vacant(entry) => {
+                let value = default(entry.key.as_ref());
+                entry.insert(value)
+            }
+        }
+    }
+
+    /// Returns a reference to this entry's key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// assert_eq!(map.entry_ref("poneyland").key(), "poneyland");
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn key(&self) -> &Q
+    where
+        K: Borrow<Q>,
+    {
+        match *self {
+            EntryRef::Occupied(ref entry) => entry.key(),
+            EntryRef::Vacant(ref entry) => entry.key(),
+        }
+    }
+
+    /// Provides in-place mutable access to an occupied entry before any
+    /// potential inserts into the map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    ///
+    /// map.entry_ref("poneyland")
+    ///    .and_modify(|e| { *e += 1 })
+    ///    .or_insert(42);
+    /// assert_eq!(map["poneyland"], 42);
+    ///
+    /// map.entry_ref("poneyland")
+    ///    .and_modify(|e| { *e += 1 })
+    ///    .or_insert(42);
+    /// assert_eq!(map["poneyland"], 43);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn and_modify<F>(self, f: F) -> Self
+    where
+        F: FnOnce(&mut V),
+    {
+        match self {
+            EntryRef::Occupied(mut entry) => {
+                f(entry.get_mut());
+                EntryRef::Occupied(entry)
+            }
+            EntryRef::Vacant(entry) => EntryRef::Vacant(entry),
+        }
+    }
+
+    /// Provides shared access to the key and owned access to the value of
+    /// an occupied entry and allows to replace or remove it based on the
+    /// value of the returned option.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    ///
+    /// let entry = map
+    ///     .entry_ref("poneyland")
+    ///     .and_replace_entry_with(|_k, _v| panic!());
+    ///
+    /// match entry {
+    ///     EntryRef::Vacant(e) => {
+    ///         assert_eq!(e.key(), "poneyland");
+    ///     }
+    ///     EntryRef::Occupied(_) => panic!(),
+    /// }
+    ///
+    /// map.insert("poneyland".to_string(), 42);
+    ///
+    /// let entry = map
+    ///     .entry_ref("poneyland")
+    ///     .and_replace_entry_with(|k, v| {
+    ///         assert_eq!(k, "poneyland");
+    ///         assert_eq!(v, 42);
+    ///         Some(v + 1)
+    ///     });
+    ///
+    /// match entry {
+    ///     EntryRef::Occupied(e) => {
+    ///         assert_eq!(e.key(), "poneyland");
+    ///         assert_eq!(e.get(), &43);
+    ///     }
+    ///     EntryRef::Vacant(_) => panic!(),
+    /// }
+    ///
+    /// assert_eq!(map["poneyland"], 43);
+    ///
+    /// let entry = map
+    ///     .entry_ref("poneyland")
+    ///     .and_replace_entry_with(|_k, _v| None);
+    ///
+    /// match entry {
+    ///     EntryRef::Vacant(e) => assert_eq!(e.key(), "poneyland"),
+    ///     EntryRef::Occupied(_) => panic!(),
+    /// }
+    ///
+    /// assert!(!map.contains_key("poneyland"));
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn and_replace_entry_with<F>(self, f: F) -> Self
+    where
+        F: FnOnce(&Q, V) -> Option<V>,
+        K: Borrow<Q>,
+    {
+        match self {
+            EntryRef::Occupied(entry) => entry.replace_entry_with(f),
+            EntryRef::Vacant(_) => self,
+        }
+    }
+}
+
+impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator + Clone> EntryRef<'a, 'b, K, Q, V, S, A> {
+    /// Ensures a value is in the entry by inserting the default value if empty,
+    /// and returns a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<&str, Option<u32>> = HashMap::new();
+    /// map.entry("poneyland").or_default();
+    ///
+    /// assert_eq!(map["poneyland"], None);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn or_default(self) -> &'a mut V
+    where
+        K: Hash + From<&'b Q>,
+        S: BuildHasher,
+    {
+        match self {
+            EntryRef::Occupied(entry) => entry.into_mut(),
+            EntryRef::Vacant(entry) => entry.insert(Default::default()),
+        }
+    }
+}
+
+impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> {
+    /// Gets a reference to the key in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// map.entry_ref("poneyland").or_insert(12);
+    /// assert_eq!(map.entry_ref("poneyland").key(), "poneyland");
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn key(&self) -> &Q
+    where
+        K: Borrow<Q>,
+    {
+        unsafe { &self.elem.as_ref().0 }.borrow()
+    }
+
+    /// Take the ownership of the key and value from the map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// map.entry_ref("poneyland").or_insert(12);
+    ///
+    /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") {
+    ///     // We delete the entry from the map.
+    ///     o.remove_entry();
+    /// }
+    ///
+    /// assert_eq!(map.contains_key("poneyland"), false);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn remove_entry(self) -> (K, V) {
+        unsafe { self.table.table.remove(self.elem) }
+    }
+
+    /// Gets a reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// map.entry_ref("poneyland").or_insert(12);
+    ///
+    /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") {
+    ///     assert_eq!(o.get(), &12);
+    /// }
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn get(&self) -> &V {
+        unsafe { &self.elem.as_ref().1 }
+    }
+
+    /// Gets a mutable reference to the value in the entry.
+    ///
+    /// If you need a reference to the `OccupiedEntryRef` which may outlive the
+    /// destruction of the `EntryRef` value, see [`into_mut`].
+    ///
+    /// [`into_mut`]: #method.into_mut
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// map.entry_ref("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// if let EntryRef::Occupied(mut o) = map.entry_ref("poneyland") {
+    ///     *o.get_mut() += 10;
+    ///     assert_eq!(*o.get(), 22);
+    ///
+    ///     // We can use the same Entry multiple times.
+    ///     *o.get_mut() += 2;
+    /// }
+    ///
+    /// assert_eq!(map["poneyland"], 24);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn get_mut(&mut self) -> &mut V {
+        unsafe { &mut self.elem.as_mut().1 }
+    }
+
+    /// Converts the OccupiedEntryRef into a mutable reference to the value in the entry
+    /// with a lifetime bound to the map itself.
+    ///
+    /// If you need multiple references to the `OccupiedEntryRef`, see [`get_mut`].
+    ///
+    /// [`get_mut`]: #method.get_mut
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// map.entry_ref("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") {
+    ///     *o.into_mut() += 10;
+    /// }
+    ///
+    /// assert_eq!(map["poneyland"], 22);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn into_mut(self) -> &'a mut V {
+        unsafe { &mut self.elem.as_mut().1 }
+    }
+
+    /// Sets the value of the entry, and returns the entry's old value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// map.entry_ref("poneyland").or_insert(12);
+    ///
+    /// if let EntryRef::Occupied(mut o) = map.entry_ref("poneyland") {
+    ///     assert_eq!(o.insert(15), 12);
+    /// }
+    ///
+    /// assert_eq!(map["poneyland"], 15);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn insert(&mut self, mut value: V) -> V {
+        let old_value = self.get_mut();
+        mem::swap(&mut value, old_value);
+        value
+    }
+
+    /// Takes the value out of the entry, and returns it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// map.entry_ref("poneyland").or_insert(12);
+    ///
+    /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") {
+    ///     assert_eq!(o.remove(), 12);
+    /// }
+    ///
+    /// assert_eq!(map.contains_key("poneyland"), false);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn remove(self) -> V {
+        self.remove_entry().1
+    }
+
+    /// Replaces the entry, returning the old key and value. The new key in the hash map will be
+    /// the key used to create this entry.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if this OccupiedEntry was created through [`EntryRef::insert`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::hash_map::{EntryRef, HashMap};
+    /// use std::rc::Rc;
+    ///
+    /// let mut map: HashMap<Rc<str>, u32> = HashMap::new();
+    /// map.insert(Rc::from("Stringthing"), 15);
+    ///
+    /// if let EntryRef::Occupied(entry) = map.entry_ref("Stringthing") {
+    ///     // Also replace the key with a handle to our other key.
+    ///     let (old_key, old_value): (Rc<str>, u32) = entry.replace_entry(16);
+    /// }
+    ///
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn replace_entry(self, value: V) -> (K, V)
+    where
+        K: From<&'b Q>,
+    {
+        let entry = unsafe { self.elem.as_mut() };
+
+        let old_key = mem::replace(&mut entry.0, self.key.unwrap().into_owned());
+        let old_value = mem::replace(&mut entry.1, value);
+
+        (old_key, old_value)
+    }
+
+    /// Replaces the key in the hash map with the key used to create this entry.
+    ///
+    /// # Panics
+    ///
+    /// Will panic if this OccupiedEntry was created through [`Entry::insert`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::hash_map::{EntryRef, HashMap};
+    /// use std::rc::Rc;
+    ///
+    /// let mut map: HashMap<Rc<str>, u32> = HashMap::new();
+    /// let mut known_strings: Vec<Rc<str>> = Vec::new();
+    ///
+    /// // Initialise known strings, run program, etc.
+    ///
+    /// reclaim_memory(&mut map, &known_strings);
+    ///
+    /// fn reclaim_memory(map: &mut HashMap<Rc<str>, u32>, known_strings: &[Rc<str>] ) {
+    ///     for s in known_strings {
+    ///         if let EntryRef::Occupied(entry) = map.entry_ref(s.as_ref()) {
+    ///             // Replaces the entry's key with our version of it in `known_strings`.
+    ///             entry.replace_key();
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn replace_key(self) -> K
+    where
+        K: From<&'b Q>,
+    {
+        let entry = unsafe { self.elem.as_mut() };
+        mem::replace(&mut entry.0, self.key.unwrap().into_owned())
+    }
+
+    /// Provides shared access to the key and owned access to the value of
+    /// the entry and allows to replace or remove it based on the
+    /// value of the returned option.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// map.insert("poneyland".to_string(), 42);
+    ///
+    /// let entry = match map.entry_ref("poneyland") {
+    ///     EntryRef::Occupied(e) => {
+    ///         e.replace_entry_with(|k, v| {
+    ///             assert_eq!(k, "poneyland");
+    ///             assert_eq!(v, 42);
+    ///             Some(v + 1)
+    ///         })
+    ///     }
+    ///     EntryRef::Vacant(_) => panic!(),
+    /// };
+    ///
+    /// match entry {
+    ///     EntryRef::Occupied(e) => {
+    ///         assert_eq!(e.key(), "poneyland");
+    ///         assert_eq!(e.get(), &43);
+    ///     }
+    ///     EntryRef::Vacant(_) => panic!(),
+    /// }
+    ///
+    /// assert_eq!(map["poneyland"], 43);
+    ///
+    /// let entry = match map.entry_ref("poneyland") {
+    ///     EntryRef::Occupied(e) => e.replace_entry_with(|_k, _v| None),
+    ///     EntryRef::Vacant(_) => panic!(),
+    /// };
+    ///
+    /// match entry {
+    ///     EntryRef::Vacant(e) => {
+    ///         assert_eq!(e.key(), "poneyland");
+    ///     }
+    ///     EntryRef::Occupied(_) => panic!(),
+    /// }
+    ///
+    /// assert!(!map.contains_key("poneyland"));
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn replace_entry_with<F>(self, f: F) -> EntryRef<'a, 'b, K, Q, V, S, A>
+    where
+        F: FnOnce(&Q, V) -> Option<V>,
+        K: Borrow<Q>,
+    {
+        unsafe {
+            let mut spare_key = None;
+
+            self.table
+                .table
+                .replace_bucket_with(self.elem.clone(), |(key, value)| {
+                    if let Some(new_value) = f(key.borrow(), value) {
+                        Some((key, new_value))
+                    } else {
+                        spare_key = Some(KeyOrRef::Owned(key));
+                        None
+                    }
+                });
+
+            if let Some(key) = spare_key {
+                EntryRef::Vacant(VacantEntryRef {
+                    hash: self.hash,
+                    key,
+                    table: self.table,
+                })
+            } else {
+                EntryRef::Occupied(self)
+            }
+        }
+    }
+}
+
+impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator + Clone> VacantEntryRef<'a, 'b, K, Q, V, S, A> {
+    /// Gets a reference to the key that would be used when inserting a value
+    /// through the `VacantEntryRef`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// let key: &str = "poneyland";
+    /// assert_eq!(map.entry_ref(key).key(), "poneyland");
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn key(&self) -> &Q
+    where
+        K: Borrow<Q>,
+    {
+        self.key.as_ref()
+    }
+
+    /// Take ownership of the key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// let key: &str = "poneyland";
+    ///
+    /// if let EntryRef::Vacant(v) = map.entry_ref(key) {
+    ///     v.into_key();
+    /// }
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn into_key(self) -> K
+    where
+        K: From<&'b Q>,
+    {
+        self.key.into_owned()
+    }
+
+    /// Sets the value of the entry with the VacantEntryRef's key,
+    /// and returns a mutable reference to it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashMap;
+    /// use hashbrown::hash_map::EntryRef;
+    ///
+    /// let mut map: HashMap<String, u32> = HashMap::new();
+    /// let key: &str = "poneyland";
+    ///
+    /// if let EntryRef::Vacant(o) = map.entry_ref(key) {
+    ///     o.insert(37);
+    /// }
+    /// assert_eq!(map["poneyland"], 37);
+    /// ```
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn insert(self, value: V) -> &'a mut V
+    where
+        K: Hash + From<&'b Q>,
+        S: BuildHasher,
+    {
+        let table = &mut self.table.table;
+        let entry = table.insert_entry(
+            self.hash,
+            (self.key.into_owned(), value),
+            make_hasher::<K, _, V, S>(&self.table.hash_builder),
+        );
+        &mut entry.1
+    }
+
+    #[cfg_attr(feature = "inline-more", inline)]
+    fn insert_entry(self, value: V) -> OccupiedEntryRef<'a, 'b, K, Q, V, S, A>
+    where
+        K: Hash + From<&'b Q>,
+        S: BuildHasher,
+    {
+        let elem = self.table.table.insert(
+            self.hash,
+            (self.key.into_owned(), value),
+            make_hasher::<K, _, V, S>(&self.table.hash_builder),
+        );
+        OccupiedEntryRef {
+            hash: self.hash,
+            key: None,
+            elem,
+            table: self.table,
+        }
+    }
+}
+
 impl<K, V, S, A> FromIterator<(K, V)> for HashMap<K, V, S, A>
 where
     K: Eq + Hash,
@@ -3500,8 +4673,8 @@
 mod test_map {
     use super::DefaultHashBuilder;
     use super::Entry::{Occupied, Vacant};
+    use super::EntryRef;
     use super::{HashMap, RawEntryMut};
-    use crate::TryReserveError::*;
     use rand::{rngs::SmallRng, Rng, SeedableRng};
     use std::borrow::ToOwned;
     use std::cell::RefCell;
@@ -3570,6 +4743,7 @@
         assert_eq!(m.len(), 1);
         assert!(m.insert(2, 4).is_none());
         assert_eq!(m.len(), 2);
+        #[allow(clippy::redundant_clone)]
         let m2 = m.clone();
         assert_eq!(*m2.get(&1).unwrap(), 2);
         assert_eq!(*m2.get(&2).unwrap(), 4);
@@ -3723,6 +4897,7 @@
                 }
             });
 
+            #[allow(clippy::let_underscore_drop)] // kind-of a false positive
             for _ in half.by_ref() {}
 
             DROP_VECTOR.with(|v| {
@@ -3760,6 +4935,17 @@
     }
 
     #[test]
+    fn test_empty_entry_ref() {
+        let mut m: HashMap<std::string::String, bool> = HashMap::new();
+        match m.entry_ref("poneyland") {
+            EntryRef::Occupied(_) => panic!(),
+            EntryRef::Vacant(_) => {}
+        }
+        assert!(*m.entry_ref("poneyland").or_insert(true));
+        assert_eq!(m.len(), 1);
+    }
+
+    #[test]
     fn test_empty_iter() {
         let mut m: HashMap<i32, bool> = HashMap::new();
         assert_eq!(m.drain().next(), None);
@@ -3889,6 +5075,18 @@
     }
 
     #[test]
+    fn test_insert_unique_unchecked() {
+        let mut map = HashMap::new();
+        let (k1, v1) = map.insert_unique_unchecked(10, 11);
+        assert_eq!((&10, &mut 11), (k1, v1));
+        let (k2, v2) = map.insert_unique_unchecked(20, 21);
+        assert_eq!((&20, &mut 21), (k2, v2));
+        assert_eq!(Some(&11), map.get(&10));
+        assert_eq!(Some(&21), map.get(&20));
+        assert_eq!(None, map.get(&30));
+    }
+
+    #[test]
     fn test_is_empty() {
         let mut m = HashMap::with_capacity(4);
         assert!(m.insert(1, 2).is_none());
@@ -3934,7 +5132,7 @@
     fn test_keys() {
         let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
         let map: HashMap<_, _> = vec.into_iter().collect();
-        let keys: Vec<_> = map.keys().cloned().collect();
+        let keys: Vec<_> = map.keys().copied().collect();
         assert_eq!(keys.len(), 3);
         assert!(keys.contains(&1));
         assert!(keys.contains(&2));
@@ -3945,7 +5143,7 @@
     fn test_values() {
         let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
         let map: HashMap<_, _> = vec.into_iter().collect();
-        let values: Vec<_> = map.values().cloned().collect();
+        let values: Vec<_> = map.values().copied().collect();
         assert_eq!(values.len(), 3);
         assert!(values.contains(&'a'));
         assert!(values.contains(&'b'));
@@ -3957,9 +5155,9 @@
         let vec = vec![(1, 1), (2, 2), (3, 3)];
         let mut map: HashMap<_, _> = vec.into_iter().collect();
         for value in map.values_mut() {
-            *value = (*value) * 2
+            *value *= 2;
         }
-        let values: Vec<_> = map.values().cloned().collect();
+        let values: Vec<_> = map.values().copied().collect();
         assert_eq!(values.len(), 3);
         assert!(values.contains(&2));
         assert!(values.contains(&4));
@@ -3967,6 +5165,30 @@
     }
 
     #[test]
+    fn test_into_keys() {
+        let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+        let map: HashMap<_, _> = vec.into_iter().collect();
+        let keys: Vec<_> = map.into_keys().collect();
+
+        assert_eq!(keys.len(), 3);
+        assert!(keys.contains(&1));
+        assert!(keys.contains(&2));
+        assert!(keys.contains(&3));
+    }
+
+    #[test]
+    fn test_into_values() {
+        let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+        let map: HashMap<_, _> = vec.into_iter().collect();
+        let values: Vec<_> = map.into_values().collect();
+
+        assert_eq!(values.len(), 3);
+        assert!(values.contains(&'a'));
+        assert!(values.contains(&'b'));
+        assert!(values.contains(&'c'));
+    }
+
+    #[test]
     fn test_find() {
         let mut m = HashMap::new();
         assert!(m.get(&1).is_none());
@@ -4124,7 +5346,7 @@
     fn test_from_iter() {
         let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
 
-        let map: HashMap<_, _> = xs.iter().cloned().collect();
+        let map: HashMap<_, _> = xs.iter().copied().collect();
 
         for &(k, v) in &xs {
             assert_eq!(map.get(&k), Some(&v));
@@ -4137,7 +5359,7 @@
     fn test_size_hint() {
         let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
 
-        let map: HashMap<_, _> = xs.iter().cloned().collect();
+        let map: HashMap<_, _> = xs.iter().copied().collect();
 
         let mut iter = map.iter();
 
@@ -4150,7 +5372,7 @@
     fn test_iter_len() {
         let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
 
-        let map: HashMap<_, _> = xs.iter().cloned().collect();
+        let map: HashMap<_, _> = xs.iter().copied().collect();
 
         let mut iter = map.iter();
 
@@ -4163,7 +5385,7 @@
     fn test_mut_size_hint() {
         let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
 
-        let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+        let mut map: HashMap<_, _> = xs.iter().copied().collect();
 
         let mut iter = map.iter_mut();
 
@@ -4176,7 +5398,7 @@
     fn test_iter_mut_len() {
         let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
 
-        let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+        let mut map: HashMap<_, _> = xs.iter().copied().collect();
 
         let mut iter = map.iter_mut();
 
@@ -4205,6 +5427,7 @@
         map.insert(2, 1);
         map.insert(3, 4);
 
+        #[allow(clippy::no_effect)] // false positive lint
         map[&4];
     }
 
@@ -4212,7 +5435,7 @@
     fn test_entry() {
         let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
 
-        let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+        let mut map: HashMap<_, _> = xs.iter().copied().collect();
 
         // Existing key (insert)
         match map.entry(1) {
@@ -4259,6 +5482,63 @@
     }
 
     #[test]
+    fn test_entry_ref() {
+        let xs = [
+            ("One".to_owned(), 10),
+            ("Two".to_owned(), 20),
+            ("Three".to_owned(), 30),
+            ("Four".to_owned(), 40),
+            ("Five".to_owned(), 50),
+            ("Six".to_owned(), 60),
+        ];
+
+        let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+
+        // Existing key (insert)
+        match map.entry_ref("One") {
+            EntryRef::Vacant(_) => unreachable!(),
+            EntryRef::Occupied(mut view) => {
+                assert_eq!(view.get(), &10);
+                assert_eq!(view.insert(100), 10);
+            }
+        }
+        assert_eq!(map.get("One").unwrap(), &100);
+        assert_eq!(map.len(), 6);
+
+        // Existing key (update)
+        match map.entry_ref("Two") {
+            EntryRef::Vacant(_) => unreachable!(),
+            EntryRef::Occupied(mut view) => {
+                let v = view.get_mut();
+                let new_v = (*v) * 10;
+                *v = new_v;
+            }
+        }
+        assert_eq!(map.get("Two").unwrap(), &200);
+        assert_eq!(map.len(), 6);
+
+        // Existing key (take)
+        match map.entry_ref("Three") {
+            EntryRef::Vacant(_) => unreachable!(),
+            EntryRef::Occupied(view) => {
+                assert_eq!(view.remove(), 30);
+            }
+        }
+        assert_eq!(map.get("Three"), None);
+        assert_eq!(map.len(), 5);
+
+        // Inexistent key (insert)
+        match map.entry_ref("Ten") {
+            EntryRef::Occupied(_) => unreachable!(),
+            EntryRef::Vacant(view) => {
+                assert_eq!(*view.insert(1000), 1000);
+            }
+        }
+        assert_eq!(map.get("Ten").unwrap(), &1000);
+        assert_eq!(map.len(), 6);
+    }
+
+    #[test]
     fn test_entry_take_doesnt_corrupt() {
         #![allow(deprecated)] //rand
                               // Test for #19292
@@ -4271,18 +5551,18 @@
         let mut m = HashMap::new();
 
         let mut rng = {
-            let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
-            SmallRng::from_seed(seed)
+            let seed = u64::from_le_bytes(*b"testseed");
+            SmallRng::seed_from_u64(seed)
         };
 
         // Populate the map with some items.
         for _ in 0..50 {
-            let x = rng.gen_range(-10, 10);
+            let x = rng.gen_range(-10..10);
             m.insert(x, ());
         }
 
         for _ in 0..1000 {
-            let x = rng.gen_range(-10, 10);
+            let x = rng.gen_range(-10..10);
             match m.entry(x) {
                 Vacant(_) => {}
                 Occupied(e) => {
@@ -4295,6 +5575,44 @@
     }
 
     #[test]
+    fn test_entry_ref_take_doesnt_corrupt() {
+        #![allow(deprecated)] //rand
+                              // Test for #19292
+        fn check(m: &HashMap<std::string::String, ()>) {
+            for k in m.keys() {
+                assert!(m.contains_key(k), "{} is in keys() but not in the map?", k);
+            }
+        }
+
+        let mut m = HashMap::new();
+
+        let mut rng = {
+            let seed = u64::from_le_bytes(*b"testseed");
+            SmallRng::seed_from_u64(seed)
+        };
+
+        // Populate the map with some items.
+        for _ in 0..50 {
+            let mut x = std::string::String::with_capacity(1);
+            x.push(rng.gen_range('a'..='z'));
+            m.insert(x, ());
+        }
+
+        for _ in 0..1000 {
+            let mut x = std::string::String::with_capacity(1);
+            x.push(rng.gen_range('a'..='z'));
+            match m.entry_ref(x.as_str()) {
+                EntryRef::Vacant(_) => {}
+                EntryRef::Occupied(e) => {
+                    e.remove();
+                }
+            }
+
+            check(&m);
+        }
+    }
+
+    #[test]
     fn test_extend_ref() {
         let mut a = HashMap::new();
         a.insert(1, "one");
@@ -4341,11 +5659,11 @@
         let key = "hello there";
         let value = "value goes here";
         assert!(a.is_empty());
-        a.insert(key.clone(), value.clone());
+        a.insert(key, value);
         assert_eq!(a.len(), 1);
         assert_eq!(a[key], value);
 
-        match a.entry(key.clone()) {
+        match a.entry(key) {
             Vacant(_) => panic!(),
             Occupied(e) => assert_eq!(key, *e.key()),
         }
@@ -4354,17 +5672,53 @@
     }
 
     #[test]
+    fn test_occupied_entry_ref_key() {
+        let mut a = HashMap::new();
+        let key = "hello there";
+        let value = "value goes here";
+        assert!(a.is_empty());
+        a.insert(key.to_owned(), value);
+        assert_eq!(a.len(), 1);
+        assert_eq!(a[key], value);
+
+        match a.entry_ref(key) {
+            EntryRef::Vacant(_) => panic!(),
+            EntryRef::Occupied(e) => assert_eq!(key, e.key()),
+        }
+        assert_eq!(a.len(), 1);
+        assert_eq!(a[key], value);
+    }
+
+    #[test]
     fn test_vacant_entry_key() {
         let mut a = HashMap::new();
         let key = "hello there";
         let value = "value goes here";
 
         assert!(a.is_empty());
-        match a.entry(key.clone()) {
+        match a.entry(key) {
             Occupied(_) => panic!(),
             Vacant(e) => {
                 assert_eq!(key, *e.key());
-                e.insert(value.clone());
+                e.insert(value);
+            }
+        }
+        assert_eq!(a.len(), 1);
+        assert_eq!(a[key], value);
+    }
+
+    #[test]
+    fn test_vacant_entry_ref_key() {
+        let mut a: HashMap<std::string::String, &str> = HashMap::new();
+        let key = "hello there";
+        let value = "value goes here";
+
+        assert!(a.is_empty());
+        match a.entry_ref(key) {
+            EntryRef::Occupied(_) => panic!(),
+            EntryRef::Vacant(e) => {
+                assert_eq!(key, e.key());
+                e.insert(value);
             }
         }
         assert_eq!(a.len(), 1);
@@ -4415,6 +5769,49 @@
     }
 
     #[test]
+    fn test_occupied_entry_ref_replace_entry_with() {
+        let mut a: HashMap<std::string::String, &str> = HashMap::new();
+
+        let key = "a key";
+        let value = "an initial value";
+        let new_value = "a new value";
+
+        let entry = a.entry_ref(key).insert(value).replace_entry_with(|k, v| {
+            assert_eq!(k, key);
+            assert_eq!(v, value);
+            Some(new_value)
+        });
+
+        match entry {
+            EntryRef::Occupied(e) => {
+                assert_eq!(e.key(), key);
+                assert_eq!(e.get(), &new_value);
+            }
+            EntryRef::Vacant(_) => panic!(),
+        }
+
+        assert_eq!(a[key], new_value);
+        assert_eq!(a.len(), 1);
+
+        let entry = match a.entry_ref(key) {
+            EntryRef::Occupied(e) => e.replace_entry_with(|k, v| {
+                assert_eq!(k, key);
+                assert_eq!(v, new_value);
+                None
+            }),
+            EntryRef::Vacant(_) => panic!(),
+        };
+
+        match entry {
+            EntryRef::Vacant(e) => assert_eq!(e.key(), key),
+            EntryRef::Occupied(_) => panic!(),
+        }
+
+        assert!(!a.contains_key(key));
+        assert_eq!(a.len(), 0);
+    }
+
+    #[test]
     fn test_entry_and_replace_entry_with() {
         let mut a = HashMap::new();
 
@@ -4464,6 +5861,55 @@
     }
 
     #[test]
+    fn test_entry_ref_and_replace_entry_with() {
+        let mut a = HashMap::new();
+
+        let key = "a key";
+        let value = "an initial value";
+        let new_value = "a new value";
+
+        let entry = a.entry_ref(key).and_replace_entry_with(|_, _| panic!());
+
+        match entry {
+            EntryRef::Vacant(e) => assert_eq!(e.key(), key),
+            EntryRef::Occupied(_) => panic!(),
+        }
+
+        a.insert(key.to_owned(), value);
+
+        let entry = a.entry_ref(key).and_replace_entry_with(|k, v| {
+            assert_eq!(k, key);
+            assert_eq!(v, value);
+            Some(new_value)
+        });
+
+        match entry {
+            EntryRef::Occupied(e) => {
+                assert_eq!(e.key(), key);
+                assert_eq!(e.get(), &new_value);
+            }
+            EntryRef::Vacant(_) => panic!(),
+        }
+
+        assert_eq!(a[key], new_value);
+        assert_eq!(a.len(), 1);
+
+        let entry = a.entry_ref(key).and_replace_entry_with(|k, v| {
+            assert_eq!(k, key);
+            assert_eq!(v, new_value);
+            None
+        });
+
+        match entry {
+            EntryRef::Vacant(e) => assert_eq!(e.key(), key),
+            EntryRef::Occupied(_) => panic!(),
+        }
+
+        assert!(!a.contains_key(key));
+        assert_eq!(a.len(), 0);
+    }
+
+    #[test]
     fn test_raw_occupied_entry_replace_entry_with() {
         let mut a = HashMap::new();
 
@@ -4581,24 +6027,56 @@
         let mut m = HashMap::new();
 
         let mut rng = {
-            let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
-            SmallRng::from_seed(seed)
+            let seed = u64::from_le_bytes(*b"testseed");
+            SmallRng::seed_from_u64(seed)
         };
 
         // Populate the map with some items.
         for _ in 0..50 {
-            let x = rng.gen_range(-10, 10);
+            let x = rng.gen_range(-10..10);
             m.insert(x, ());
         }
 
         for _ in 0..1000 {
-            let x = rng.gen_range(-10, 10);
+            let x = rng.gen_range(-10..10);
             m.entry(x).and_replace_entry_with(|_, _| None);
             check(&m);
         }
     }
 
     #[test]
+    fn test_replace_entry_ref_with_doesnt_corrupt() {
+        #![allow(deprecated)] //rand
+                              // Test for #19292
+        fn check(m: &HashMap<std::string::String, ()>) {
+            for k in m.keys() {
+                assert!(m.contains_key(k), "{} is in keys() but not in the map?", k);
+            }
+        }
+
+        let mut m = HashMap::new();
+
+        let mut rng = {
+            let seed = u64::from_le_bytes(*b"testseed");
+            SmallRng::seed_from_u64(seed)
+        };
+
+        // Populate the map with some items.
+        for _ in 0..50 {
+            let mut x = std::string::String::with_capacity(1);
+            x.push(rng.gen_range('a'..='z'));
+            m.insert(x, ());
+        }
+
+        for _ in 0..1000 {
+            let mut x = std::string::String::with_capacity(1);
+            x.push(rng.gen_range('a'..='z'));
+            m.entry_ref(x.as_str()).and_replace_entry_with(|_, _| None);
+            check(&m);
+        }
+    }
+
+    #[test]
     fn test_retain() {
         let mut map: HashMap<i32, i32> = (0..100).map(|x| (x, x * 10)).collect();
 
@@ -4629,21 +6107,27 @@
     #[test]
     #[cfg_attr(miri, ignore)] // FIXME: no OOM signalling (https://github.com/rust-lang/miri/issues/613)
     fn test_try_reserve() {
-        let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
+        use crate::TryReserveError::{AllocError, CapacityOverflow};
 
         const MAX_USIZE: usize = usize::MAX;
 
+        let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
+
         if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) {
         } else {
             panic!("usize::MAX should trigger an overflow!");
         }
 
-        if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
+        if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 16) {
         } else {
             // This may succeed if there is enough free memory. Attempt to
-            // allocate a second hashmap to ensure the allocation will fail.
+            // allocate a few more hashmaps to ensure the allocation will fail.
             let mut empty_bytes2: HashMap<u8, u8> = HashMap::new();
-            if let Err(AllocError { .. }) = empty_bytes2.try_reserve(MAX_USIZE / 8) {
+            let _ = empty_bytes2.try_reserve(MAX_USIZE / 16);
+            let mut empty_bytes3: HashMap<u8, u8> = HashMap::new();
+            let _ = empty_bytes3.try_reserve(MAX_USIZE / 16);
+            let mut empty_bytes4: HashMap<u8, u8> = HashMap::new();
+            if let Err(AllocError { .. }) = empty_bytes4.try_reserve(MAX_USIZE / 16) {
             } else {
                 panic!("usize::MAX / 8 should trigger an OOM!");
             }
@@ -4654,9 +6138,9 @@
     fn test_raw_entry() {
         use super::RawEntryMut::{Occupied, Vacant};
 
-        let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
+        let xs = [(1_i32, 10_i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
 
-        let mut map: HashMap<_, _> = xs.iter().cloned().collect();
+        let mut map: HashMap<_, _> = xs.iter().copied().collect();
 
         let compute_hash = |map: &HashMap<i32, i32>, k: i32| -> u64 {
             super::make_insert_hash::<i32, _>(map.hasher(), &k)
@@ -4729,7 +6213,7 @@
         // Ensure all lookup methods produce equivalent results.
         for k in 0..12 {
             let hash = compute_hash(&map, k);
-            let v = map.get(&k).cloned();
+            let v = map.get(&k).copied();
             let kv = v.as_ref().map(|v| (&k, v));
 
             assert_eq!(map.raw_entry().from_key(&k), kv);
@@ -4799,8 +6283,6 @@
     #[test]
     #[cfg(feature = "raw")]
     fn test_into_iter_refresh() {
-        use core::hash::{BuildHasher, Hash, Hasher};
-
         #[cfg(miri)]
         const N: usize = 32;
         #[cfg(not(miri))]
@@ -4808,13 +6290,13 @@
 
         let mut rng = rand::thread_rng();
         for n in 0..N {
-            let mut m = HashMap::new();
+            let mut map = HashMap::new();
             for i in 0..n {
-                assert!(m.insert(i, 2 * i).is_none());
+                assert!(map.insert(i, 2 * i).is_none());
             }
-            let hasher = m.hasher().clone();
+            let hash_builder = map.hasher().clone();
 
-            let mut it = unsafe { m.table.iter() };
+            let mut it = unsafe { map.table.iter() };
             assert_eq!(it.len(), n);
 
             let mut i = 0;
@@ -4823,23 +6305,21 @@
             loop {
                 // occasionally remove some elements
                 if i < n && rng.gen_bool(0.1) {
-                    let mut hsh = hasher.build_hasher();
-                    i.hash(&mut hsh);
-                    let hash = hsh.finish();
+                    let hash_value = super::make_insert_hash(&hash_builder, &i);
 
                     unsafe {
-                        let e = m.table.find(hash, |q| q.0.eq(&i));
+                        let e = map.table.find(hash_value, |q| q.0.eq(&i));
                         if let Some(e) = e {
                             it.reflect_remove(&e);
-                            let t = m.table.remove(e);
+                            let t = map.table.remove(e);
                             removed.push(t);
                             left -= 1;
                         } else {
                             assert!(removed.contains(&(i, 2 * i)), "{} not in {:?}", i, removed);
-                            let e = m.table.insert(
-                                hash,
+                            let e = map.table.insert(
+                                hash_value,
                                 (i, 2 * i),
-                                super::make_hasher::<usize, _, usize, _>(&hasher),
+                                super::make_hasher::<usize, _, usize, _>(&hash_builder),
                             );
                             it.reflect_insert(&e);
                             if let Some(p) = removed.iter().position(|e| e == &(i, 2 * i)) {
@@ -4857,14 +6337,14 @@
                 assert!(i < n);
                 let t = unsafe { e.unwrap().as_ref() };
                 assert!(!removed.contains(t));
-                let (k, v) = t;
-                assert_eq!(*v, 2 * k);
+                let (key, value) = t;
+                assert_eq!(*value, 2 * key);
                 i += 1;
             }
             assert!(i <= n);
 
             // just for safety:
-            assert_eq!(m.table.len(), left);
+            assert_eq!(map.table.len(), left);
         }
     }
 
@@ -4886,37 +6366,38 @@
         const EMPTY_MAP: HashMap<u32, std::string::String, MyHasher> =
             HashMap::with_hasher(MyHasher);
 
-        let mut map = EMPTY_MAP.clone();
+        let mut map = EMPTY_MAP;
         map.insert(17, "seventeen".to_owned());
         assert_eq!("seventeen", map[&17]);
     }
 
     #[test]
-    #[cfg(feature = "nightly")]
     fn test_get_each_mut() {
-        use crate::UnavailableMutError::*;
-
         let mut map = HashMap::new();
         map.insert("foo".to_owned(), 0);
         map.insert("bar".to_owned(), 10);
         map.insert("baz".to_owned(), 20);
         map.insert("qux".to_owned(), 30);
 
-        let xs = map.get_each_mut(["foo", "dud", "foo", "qux"]);
-        assert_eq!(
-            xs,
-            [Ok(&mut 0), Err(Absent), Err(Duplicate(0)), Ok(&mut 30)]
-        );
+        let xs = map.get_many_mut(["foo", "qux"]);
+        assert_eq!(xs, Some([&mut 0, &mut 30]));
 
-        let ys = map.get_each_key_value_mut(["bar", "baz", "baz", "dip"]);
+        let xs = map.get_many_mut(["foo", "dud"]);
+        assert_eq!(xs, None);
+
+        let xs = map.get_many_mut(["foo", "foo"]);
+        assert_eq!(xs, None);
+
+        let ys = map.get_many_key_value_mut(["bar", "baz"]);
         assert_eq!(
             ys,
-            [
-                Ok((&"bar".to_owned(), &mut 10)),
-                Ok((&"baz".to_owned(), &mut 20)),
-                Err(Duplicate(1)),
-                Err(Absent),
-            ]
+            Some([(&"bar".to_owned(), &mut 10), (&"baz".to_owned(), &mut 20),]),
         );
+
+        let ys = map.get_many_key_value_mut(["bar", "dip"]);
+        assert_eq!(ys, None);
+
+        let ys = map.get_many_key_value_mut(["baz", "baz"]);
+        assert_eq!(ys, None);
     }
 }
diff --git a/sgx_tstd/hashbrown/src/raw/alloc.rs b/sgx_tstd/hashbrown/src/raw/alloc.rs
index de6c455..76fe1e9 100644
--- a/sgx_tstd/hashbrown/src/raw/alloc.rs
+++ b/sgx_tstd/hashbrown/src/raw/alloc.rs
@@ -33,6 +33,7 @@
     use crate::alloc::alloc::{alloc, dealloc, Layout};
     use core::ptr::NonNull;
 
+    #[allow(clippy::missing_safety_doc)] // not exposed outside of this crate
     pub unsafe trait Allocator {
         fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()>;
         unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
@@ -47,7 +48,7 @@
         }
         #[inline]
         unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
-            dealloc(ptr.as_ptr(), layout)
+            dealloc(ptr.as_ptr(), layout);
         }
     }
     impl Default for Global {
diff --git a/sgx_tstd/hashbrown/src/raw/bitmask.rs b/sgx_tstd/hashbrown/src/raw/bitmask.rs
index 99b2d53..7d4f9fc 100644
--- a/sgx_tstd/hashbrown/src/raw/bitmask.rs
+++ b/sgx_tstd/hashbrown/src/raw/bitmask.rs
@@ -106,7 +106,7 @@
     }
 }
 
-/// Iterator over the contents of a `BitMask`, returning the indicies of set
+/// Iterator over the contents of a `BitMask`, returning the indices of set
 /// bits.
 pub struct BitMaskIter(BitMask);
 
diff --git a/sgx_tstd/hashbrown/src/raw/generic.rs b/sgx_tstd/hashbrown/src/raw/generic.rs
index ef066e8..b4d31e6 100644
--- a/sgx_tstd/hashbrown/src/raw/generic.rs
+++ b/sgx_tstd/hashbrown/src/raw/generic.rs
@@ -9,12 +9,14 @@
     target_pointer_width = "64",
     target_arch = "aarch64",
     target_arch = "x86_64",
+    target_arch = "wasm32",
 ))]
 type GroupWord = u64;
 #[cfg(all(
     target_pointer_width = "32",
     not(target_arch = "aarch64"),
     not(target_arch = "x86_64"),
+    not(target_arch = "wasm32"),
 ))]
 type GroupWord = u32;
 
@@ -37,7 +39,7 @@
 #[derive(Copy, Clone)]
 pub struct Group(GroupWord);
 
-// We perform all operations in the native endianess, and convert to
+// We perform all operations in the native endianness, and convert to
 // little-endian just before creating a BitMask. The can potentially
 // enable the compiler to eliminate unnecessary byte swaps if we are
 // only checking whether a BitMask is empty.
@@ -50,6 +52,7 @@
     /// value for an empty hash table.
     ///
     /// This is guaranteed to be aligned to the group size.
+    #[inline]
     pub const fn static_empty() -> &'static [u8; Group::WIDTH] {
         #[repr(C)]
         struct AlignedBytes {
@@ -103,7 +106,7 @@
     #[inline]
     pub fn match_byte(self, byte: u8) -> BitMask {
         // This algorithm is derived from
-        // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
+        // https://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
         let cmp = self.0 ^ repeat(byte);
         BitMask((cmp.wrapping_sub(repeat(0x01)) & !cmp & repeat(0x80)).to_le())
     }
diff --git a/sgx_tstd/hashbrown/src/raw/mod.rs b/sgx_tstd/hashbrown/src/raw/mod.rs
index 3ae6980..fce54d9 100644
--- a/sgx_tstd/hashbrown/src/raw/mod.rs
+++ b/sgx_tstd/hashbrown/src/raw/mod.rs
@@ -1,16 +1,13 @@
 use crate::alloc::alloc::{handle_alloc_error, Layout};
 use crate::scopeguard::guard;
 use crate::TryReserveError;
-#[cfg(feature = "nightly")]
-use crate::UnavailableMutError;
-use core::hint;
 use core::iter::FusedIterator;
 use core::marker::PhantomData;
 use core::mem;
 use core::mem::ManuallyDrop;
-#[cfg(feature = "nightly")]
 use core::mem::MaybeUninit;
 use core::ptr::NonNull;
+use core::{hint, ptr};
 
 cfg_if! {
     // Use the SSE2 implementation if possible: it allows us to scan 16 buckets
@@ -59,7 +56,7 @@
 #[inline]
 fn likely(b: bool) -> bool {
     if !b {
-        cold()
+        cold();
     }
     b
 }
@@ -67,18 +64,18 @@
 #[inline]
 fn unlikely(b: bool) -> bool {
     if b {
-        cold()
+        cold();
     }
     b
 }
 
 #[cfg(feature = "nightly")]
-#[cfg_attr(feature = "inline-more", inline)]
+#[inline]
 unsafe fn offset_from<T>(to: *const T, from: *const T) -> usize {
     to.offset_from(from) as usize
 }
 #[cfg(not(feature = "nightly"))]
-#[cfg_attr(feature = "inline-more", inline)]
+#[inline]
 unsafe fn offset_from<T>(to: *const T, from: *const T) -> usize {
     (to as usize - from as usize) / mem::size_of::<T>()
 }
@@ -211,7 +208,7 @@
 
     // Any overflows will have been caught by the checked_mul. Also, any
     // rounding errors from the division above will be cleaned up by
-    // next_power_of_two (which can't overflow because of the previous divison).
+    // next_power_of_two (which can't overflow because of the previous division).
     Some(adjusted_cap.next_power_of_two())
 }
 
@@ -292,14 +289,14 @@
 unsafe impl<T> Send for Bucket<T> {}
 
 impl<T> Clone for Bucket<T> {
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     fn clone(&self) -> Self {
         Self { ptr: self.ptr }
     }
 }
 
 impl<T> Bucket<T> {
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     unsafe fn from_base_index(base: NonNull<T>, index: usize) -> Self {
         let ptr = if mem::size_of::<T>() == 0 {
             // won't overflow because index must be less than length
@@ -311,7 +308,7 @@
             ptr: NonNull::new_unchecked(ptr),
         }
     }
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     unsafe fn to_base_index(&self, base: NonNull<T>) -> usize {
         if mem::size_of::<T>() == 0 {
             self.ptr.as_ptr() as usize - 1
@@ -319,7 +316,7 @@
             offset_from(base.as_ptr(), self.ptr.as_ptr())
         }
     }
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub fn as_ptr(&self) -> *mut T {
         if mem::size_of::<T>() == 0 {
             // Just return an arbitrary ZST pointer which is properly aligned
@@ -328,7 +325,7 @@
             unsafe { self.ptr.as_ptr().sub(1) }
         }
     }
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     unsafe fn next_n(&self, offset: usize) -> Self {
         let ptr = if mem::size_of::<T>() == 0 {
             (self.ptr.as_ptr() as usize + offset) as *mut T
@@ -343,23 +340,24 @@
     pub unsafe fn drop(&self) {
         self.as_ptr().drop_in_place();
     }
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub unsafe fn read(&self) -> T {
         self.as_ptr().read()
     }
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub unsafe fn write(&self, val: T) {
         self.as_ptr().write(val);
     }
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub unsafe fn as_ref<'a>(&self) -> &'a T {
         &*self.as_ptr()
     }
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub unsafe fn as_mut<'a>(&self) -> &'a mut T {
         &mut *self.as_ptr()
     }
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[cfg(feature = "raw")]
+    #[inline]
     pub unsafe fn copy_from_nonoverlapping(&self, other: &Self) {
         self.as_ptr().copy_from_nonoverlapping(other.as_ptr(), 1);
     }
@@ -398,7 +396,7 @@
     /// In effect this returns a table with exactly 1 bucket. However we can
     /// leave the data pointer dangling since that bucket is never written to
     /// due to our load factor forcing us to always have at least 1 free bucket.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub const fn new() -> Self {
         Self {
             table: RawTableInner::new_in(Global),
@@ -427,7 +425,7 @@
     /// In effect this returns a table with exactly 1 bucket. However we can
     /// leave the data pointer dangling since that bucket is never written to
     /// due to our load factor forcing us to always have at least 1 free bucket.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub fn new_in(alloc: A) -> Self {
         Self {
             table: RawTableInner::new_in(alloc),
@@ -492,33 +490,39 @@
         }
     }
 
+    /// Returns a reference to the underlying allocator.
+    #[inline]
+    pub fn allocator(&self) -> &A {
+        &self.table.alloc
+    }
+
     /// Deallocates the table without dropping any entries.
     #[cfg_attr(feature = "inline-more", inline)]
     unsafe fn free_buckets(&mut self) {
-        self.table.free_buckets(TableLayout::new::<T>())
+        self.table.free_buckets(TableLayout::new::<T>());
     }
 
     /// Returns pointer to one past last element of data table.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub unsafe fn data_end(&self) -> NonNull<T> {
         NonNull::new_unchecked(self.table.ctrl.as_ptr().cast())
     }
 
     /// Returns pointer to start of data table.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     #[cfg(feature = "nightly")]
     pub unsafe fn data_start(&self) -> *mut T {
         self.data_end().as_ptr().wrapping_sub(self.buckets())
     }
 
     /// Returns the index of a bucket from a `Bucket`.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub unsafe fn bucket_index(&self, bucket: &Bucket<T>) -> usize {
         bucket.to_base_index(self.data_end())
     }
 
     /// Returns a pointer to an element in the table.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub unsafe fn bucket(&self, index: usize) -> Bucket<T> {
         debug_assert_ne!(self.table.bucket_mask, 0);
         debug_assert!(index < self.buckets());
@@ -530,7 +534,7 @@
     #[deprecated(since = "0.8.1", note = "use erase or remove instead")]
     pub unsafe fn erase_no_drop(&mut self, item: &Bucket<T>) {
         let index = self.bucket_index(item);
-        self.table.erase(index)
+        self.table.erase(index);
     }
 
     /// Erases an element from the table, dropping it in place.
@@ -550,7 +554,9 @@
     pub fn erase_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> bool {
         // Avoid `Option::map` because it bloats LLVM IR.
         if let Some(bucket) = self.find(hash, eq) {
-            unsafe { self.erase(bucket) };
+            unsafe {
+                self.erase(bucket);
+            }
             true
         } else {
             false
@@ -579,7 +585,7 @@
     /// Marks all table buckets as empty without dropping their contents.
     #[cfg_attr(feature = "inline-more", inline)]
     pub fn clear_no_drop(&mut self) {
-        self.table.clear_no_drop()
+        self.table.clear_no_drop();
     }
 
     /// Removes all elements from the table without freeing the backing memory.
@@ -593,7 +599,7 @@
     }
 
     unsafe fn drop_elements(&mut self) {
-        if mem::needs_drop::<T>() && self.len() != 0 {
+        if mem::needs_drop::<T>() && !self.is_empty() {
             for item in self.iter() {
                 item.drop();
             }
@@ -624,7 +630,7 @@
         if min_buckets < self.buckets() {
             // Fast path if the table is empty
             if self.table.items == 0 {
-                *self = Self::with_capacity_in(min_size, self.table.alloc.clone())
+                *self = Self::with_capacity_in(min_size, self.table.alloc.clone());
             } else {
                 // Avoid `Result::unwrap_or_else` because it bloats LLVM IR.
                 if self
@@ -676,102 +682,18 @@
         hasher: impl Fn(&T) -> u64,
         fallibility: Fallibility,
     ) -> Result<(), TryReserveError> {
-        // Avoid `Option::ok_or_else` because it bloats LLVM IR.
-        let new_items = match self.table.items.checked_add(additional) {
-            Some(new_items) => new_items,
-            None => return Err(fallibility.capacity_overflow()),
-        };
-        let full_capacity = bucket_mask_to_capacity(self.table.bucket_mask);
-        if new_items <= full_capacity / 2 {
-            // Rehash in-place without re-allocating if we have plenty of spare
-            // capacity that is locked up due to DELETED entries.
-            self.rehash_in_place(hasher);
-            Ok(())
-        } else {
-            // Otherwise, conservatively resize to at least the next size up
-            // to avoid churning deletes into frequent rehashes.
-            self.resize(
-                usize::max(new_items, full_capacity + 1),
-                hasher,
-                fallibility,
-            )
-        }
-    }
-
-    /// Rehashes the contents of the table in place (i.e. without changing the
-    /// allocation).
-    ///
-    /// If `hasher` panics then some the table's contents may be lost.
-    fn rehash_in_place(&mut self, hasher: impl Fn(&T) -> u64) {
         unsafe {
-            // If the hash function panics then properly clean up any elements
-            // that we haven't rehashed yet. We unfortunately can't preserve the
-            // element since we lost their hash and have no way of recovering it
-            // without risking another panic.
-            self.table.prepare_rehash_in_place();
-
-            let mut guard = guard(&mut self.table, move |self_| {
+            self.table.reserve_rehash_inner(
+                additional,
+                &|table, index| hasher(table.bucket::<T>(index).as_ref()),
+                fallibility,
+                TableLayout::new::<T>(),
                 if mem::needs_drop::<T>() {
-                    for i in 0..self_.buckets() {
-                        if *self_.ctrl(i) == DELETED {
-                            self_.set_ctrl(i, EMPTY);
-                            self_.bucket::<T>(i).drop();
-                            self_.items -= 1;
-                        }
-                    }
-                }
-                self_.growth_left = bucket_mask_to_capacity(self_.bucket_mask) - self_.items;
-            });
-
-            // At this point, DELETED elements are elements that we haven't
-            // rehashed yet. Find them and re-insert them at their ideal
-            // position.
-            'outer: for i in 0..guard.buckets() {
-                if *guard.ctrl(i) != DELETED {
-                    continue;
-                }
-
-                'inner: loop {
-                    // Hash the current item
-                    let item = guard.bucket(i);
-                    let hash = hasher(item.as_ref());
-
-                    // Search for a suitable place to put it
-                    let new_i = guard.find_insert_slot(hash);
-
-                    // Probing works by scanning through all of the control
-                    // bytes in groups, which may not be aligned to the group
-                    // size. If both the new and old position fall within the
-                    // same unaligned group, then there is no benefit in moving
-                    // it and we can just continue to the next item.
-                    if likely(guard.is_in_same_group(i, new_i, hash)) {
-                        guard.set_ctrl_h2(i, hash);
-                        continue 'outer;
-                    }
-
-                    // We are moving the current item to a new position. Write
-                    // our H2 to the control byte of the new position.
-                    let prev_ctrl = guard.replace_ctrl_h2(new_i, hash);
-                    if prev_ctrl == EMPTY {
-                        guard.set_ctrl(i, EMPTY);
-                        // If the target slot is empty, simply move the current
-                        // element into the new slot and clear the old control
-                        // byte.
-                        guard.bucket(new_i).copy_from_nonoverlapping(&item);
-                        continue 'outer;
-                    } else {
-                        // If the target slot is occupied, swap the two elements
-                        // and then continue processing the element that we just
-                        // swapped into the old slot.
-                        debug_assert_eq!(prev_ctrl, DELETED);
-                        mem::swap(guard.bucket(new_i).as_mut(), item.as_mut());
-                        continue 'inner;
-                    }
-                }
-            }
-
-            guard.growth_left = bucket_mask_to_capacity(guard.bucket_mask) - guard.items;
-            mem::forget(guard);
+                    Some(mem::transmute(ptr::drop_in_place::<T> as unsafe fn(*mut T)))
+                } else {
+                    None
+                },
+            )
         }
     }
 
@@ -784,30 +706,12 @@
         fallibility: Fallibility,
     ) -> Result<(), TryReserveError> {
         unsafe {
-            let mut new_table =
-                self.table
-                    .prepare_resize(TableLayout::new::<T>(), capacity, fallibility)?;
-
-            // Copy all elements to the new table.
-            for item in self.iter() {
-                // This may panic.
-                let hash = hasher(item.as_ref());
-
-                // We can use a simpler version of insert() here since:
-                // - there are no DELETED entries.
-                // - we know there is enough space in the table.
-                // - all elements are unique.
-                let (index, _) = new_table.prepare_insert_slot(hash);
-                new_table.bucket(index).copy_from_nonoverlapping(&item);
-            }
-
-            // We successfully copied all elements without panicking. Now replace
-            // self with the new table. The old table will have its memory freed but
-            // the items will not be dropped (since they have been moved into the
-            // new table).
-            mem::swap(&mut self.table, &mut new_table);
-
-            Ok(())
+            self.table.resize_inner(
+                capacity,
+                &|table, index| hasher(table.bucket::<T>(index).as_ref()),
+                fallibility,
+                TableLayout::new::<T>(),
+            )
         }
     }
 
@@ -872,19 +776,17 @@
     /// This does not check if the given element already exists in the table.
     #[cfg_attr(feature = "inline-more", inline)]
     #[cfg(any(feature = "raw", feature = "rustc-internal-api"))]
-    pub fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket<T> {
-        unsafe {
-            let (index, old_ctrl) = self.table.prepare_insert_slot(hash);
-            let bucket = self.table.bucket(index);
+    pub unsafe fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket<T> {
+        let (index, old_ctrl) = self.table.prepare_insert_slot(hash);
+        let bucket = self.table.bucket(index);
 
-            // If we are replacing a DELETED entry then we don't need to update
-            // the load counter.
-            self.table.growth_left -= special_is_empty(old_ctrl) as usize;
+        // If we are replacing a DELETED entry then we don't need to update
+        // the load counter.
+        self.table.growth_left -= special_is_empty(old_ctrl) as usize;
 
-            bucket.write(value);
-            self.table.items += 1;
-            bucket
-        }
+        bucket.write(value);
+        self.table.items += 1;
+        bucket
     }
 
     /// Temporary removes a bucket, applying the given function to the removed
@@ -917,14 +819,14 @@
     /// Searches for an element in the table.
     #[inline]
     pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option<Bucket<T>> {
-        unsafe {
-            for bucket in self.iter_hash(hash) {
-                let elm = bucket.as_ref();
-                if likely(eq(elm)) {
-                    return Some(bucket);
-                }
-            }
-            None
+        let result = self.table.find_inner(hash, &mut |index| unsafe {
+            eq(self.bucket(index).as_ref())
+        });
+
+        // Avoid `Option::map` because it bloats LLVM IR.
+        match result {
+            Some(index) => Some(unsafe { self.bucket(index) }),
+            None => None,
         }
     }
 
@@ -950,79 +852,84 @@
 
     /// Attempts to get mutable references to `N` entries in the table at once.
     ///
-    /// Returns an array of length `N` with the results of each query. For soundness,
-    /// at most one mutable reference will be returned to any entry. An
-    /// `Err(UnavailableMutError::Duplicate(i))` in the returned array indicates that a suitable
-    /// entry exists, but a mutable reference to it already occurs at index `i` in the returned
-    /// array.
+    /// Returns an array of length `N` with the results of each query.
+    ///
+    /// At most one mutable reference will be returned to any entry. `None` will be returned if any
+    /// of the hashes are duplicates. `None` will be returned if the hash is not found.
     ///
     /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to
     /// the `i`th key to be looked up.
-    ///
-    /// This method is available only if the `nightly` feature is enabled.
-    #[cfg(feature = "nightly")]
-    pub fn get_each_mut<const N: usize>(
+    pub fn get_many_mut<const N: usize>(
+        &mut self,
+        hashes: [u64; N],
+        eq: impl FnMut(usize, &T) -> bool,
+    ) -> Option<[&'_ mut T; N]> {
+        unsafe {
+            let ptrs = self.get_many_mut_pointers(hashes, eq)?;
+
+            for (i, &cur) in ptrs.iter().enumerate() {
+                if ptrs[..i].iter().any(|&prev| ptr::eq::<T>(prev, cur)) {
+                    return None;
+                }
+            }
+            // All bucket are distinct from all previous buckets so we're clear to return the result
+            // of the lookup.
+
+            // TODO use `MaybeUninit::array_assume_init` here instead once that's stable.
+            Some(mem::transmute_copy(&ptrs))
+        }
+    }
+
+    pub unsafe fn get_many_unchecked_mut<const N: usize>(
+        &mut self,
+        hashes: [u64; N],
+        eq: impl FnMut(usize, &T) -> bool,
+    ) -> Option<[&'_ mut T; N]> {
+        let ptrs = self.get_many_mut_pointers(hashes, eq)?;
+        Some(mem::transmute_copy(&ptrs))
+    }
+
+    unsafe fn get_many_mut_pointers<const N: usize>(
         &mut self,
         hashes: [u64; N],
         mut eq: impl FnMut(usize, &T) -> bool,
-    ) -> [Result<&'_ mut T, UnavailableMutError>; N] {
-        // Collect the requested buckets.
+    ) -> Option<[*mut T; N]> {
         // TODO use `MaybeUninit::uninit_array` here instead once that's stable.
-        let mut buckets: [MaybeUninit<Option<Bucket<T>>>; N] =
-            unsafe { MaybeUninit::uninit().assume_init() };
-        for i in 0..N {
-            buckets[i] = MaybeUninit::new(self.find(hashes[i], |k| eq(i, k)));
-        }
-        let buckets: [Option<Bucket<T>>; N] = unsafe { MaybeUninit::array_assume_init(buckets) };
+        let mut outs: MaybeUninit<[*mut T; N]> = MaybeUninit::uninit();
+        let outs_ptr = outs.as_mut_ptr();
 
-        // Walk through the buckets, checking for duplicates and building up the output array.
-        // TODO use `MaybeUninit::uninit_array` here instead once that's stable.
-        let mut out: [MaybeUninit<Result<&'_ mut T, UnavailableMutError>>; N] =
-            unsafe { MaybeUninit::uninit().assume_init() };
-        for i in 0..N {
-            out[i] = MaybeUninit::new(
-                #[allow(clippy::never_loop)]
-                'outer: loop {
-                    for j in 0..i {
-                        match (&buckets[j], &buckets[i]) {
-                            // These two buckets are the same, and we can't safely return a second
-                            // mutable reference to the same entry.
-                            (Some(prev), Some(cur)) if prev.as_ptr() == cur.as_ptr() => {
-                                break 'outer Err(UnavailableMutError::Duplicate(j));
-                            }
-                            _ => {}
-                        }
-                    }
-                    // This bucket is distinct from all previous buckets (or it doesn't exist), so
-                    // we're clear to return the result of the lookup.
-                    break match &buckets[i] {
-                        None => Err(UnavailableMutError::Absent),
-                        Some(bkt) => unsafe { Ok(bkt.as_mut()) },
-                    };
-                },
-            )
+        for (i, &hash) in hashes.iter().enumerate() {
+            let cur = self.find(hash, |k| eq(i, k))?;
+            *(*outs_ptr).get_unchecked_mut(i) = cur.as_mut();
         }
 
-        unsafe { MaybeUninit::array_assume_init(out) }
+        // TODO use `MaybeUninit::array_assume_init` here instead once that's stable.
+        Some(outs.assume_init())
     }
 
     /// Returns the number of elements the map can hold without reallocating.
     ///
     /// This number is a lower bound; the table might be able to hold
     /// more, but is guaranteed to be able to hold at least this many.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub fn capacity(&self) -> usize {
         self.table.items + self.table.growth_left
     }
 
     /// Returns the number of elements in the table.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub fn len(&self) -> usize {
         self.table.items
     }
 
+    /// Returns `true` if the table contains no elements.
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
     /// Returns the number of buckets in the table.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub fn buckets(&self) -> usize {
         self.table.bucket_mask + 1
     }
@@ -1031,7 +938,7 @@
     /// the caller to ensure that the `RawTable` outlives the `RawIter`.
     /// Because we cannot make the `next` method unsafe on the `RawIter`
     /// struct, we have to make the `iter` method unsafe.
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     pub unsafe fn iter(&self) -> RawIter<T> {
         let data = Bucket::from_base_index(self.data_end(), 0);
         RawIter {
@@ -1042,12 +949,15 @@
 
     /// Returns an iterator over occupied buckets that could match a given hash.
     ///
-    /// In rare cases, the iterator may return a bucket with a different hash.
+    /// `RawTable` only stores 7 bits of the hash value, so this iterator may
+    /// return items that have a hash value different than the one provided. You
+    /// should always validate the returned values before using them.
     ///
     /// It is up to the caller to ensure that the `RawTable` outlives the
     /// `RawIterHash`. Because we cannot make the `next` method unsafe on the
     /// `RawIterHash` struct, we have to make the `iter_hash` method unsafe.
     #[cfg_attr(feature = "inline-more", inline)]
+    #[cfg(feature = "raw")]
     pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash<'_, T, A> {
         RawIterHash::new(self, hash)
     }
@@ -1121,11 +1031,21 @@
     }
 }
 
-unsafe impl<T, A: Allocator + Clone> Send for RawTable<T, A> where T: Send {}
-unsafe impl<T, A: Allocator + Clone> Sync for RawTable<T, A> where T: Sync {}
+unsafe impl<T, A: Allocator + Clone> Send for RawTable<T, A>
+where
+    T: Send,
+    A: Send,
+{
+}
+unsafe impl<T, A: Allocator + Clone> Sync for RawTable<T, A>
+where
+    T: Sync,
+    A: Sync,
+{
+}
 
 impl<A> RawTableInner<A> {
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     const fn new_in(alloc: A) -> Self {
         Self {
             // Be careful to cast the entire slice to a raw pointer.
@@ -1154,6 +1074,15 @@
             None => return Err(fallibility.capacity_overflow()),
         };
 
+        // We need an additional check to ensure that the allocation doesn't
+        // exceed `isize::MAX`. We can skip this check on 64-bit systems since
+        // such allocations will never succeed anyways.
+        //
+        // This mirrors what Vec does in the standard library.
+        if mem::size_of::<usize>() < 8 && layout.size() > isize::MAX as usize {
+            return Err(fallibility.capacity_overflow());
+        }
+
         let ptr: NonNull<u8> = match do_alloc(&alloc, layout) {
             Ok(block) => block.cast(),
             Err(_) => return Err(fallibility.alloc_err(layout)),
@@ -1221,7 +1150,7 @@
                     // EMPTY entries. These will unfortunately trigger a
                     // match, but once masked may point to a full bucket that
                     // is already occupied. We detect this situation here and
-                    // perform a second scan starting at the begining of the
+                    // perform a second scan starting at the beginning of the
                     // table. This second scan is guaranteed to find an empty
                     // slot (due to the load factor) before hitting the trailing
                     // control bytes (containing EMPTY).
@@ -1240,6 +1169,32 @@
         }
     }
 
+    /// Searches for an element in the table. This uses dynamic dispatch to reduce the amount of
+    /// code generated, but it is eliminated by LLVM optimizations.
+    #[inline]
+    fn find_inner(&self, hash: u64, eq: &mut dyn FnMut(usize) -> bool) -> Option<usize> {
+        let h2_hash = h2(hash);
+        let mut probe_seq = self.probe_seq(hash);
+
+        loop {
+            let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) };
+
+            for bit in group.match_byte(h2_hash) {
+                let index = (probe_seq.pos + bit) & self.bucket_mask;
+
+                if likely(eq(index)) {
+                    return Some(index);
+                }
+            }
+
+            if likely(group.match_empty().any_bit_set()) {
+                return None;
+            }
+
+            probe_seq.move_next(self.bucket_mask);
+        }
+    }
+
     #[allow(clippy::mut_mut)]
     #[inline]
     unsafe fn prepare_rehash_in_place(&mut self) {
@@ -1263,14 +1218,22 @@
         }
     }
 
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     unsafe fn bucket<T>(&self, index: usize) -> Bucket<T> {
         debug_assert_ne!(self.bucket_mask, 0);
         debug_assert!(index < self.buckets());
         Bucket::from_base_index(self.data_end(), index)
     }
 
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
+    unsafe fn bucket_ptr(&self, index: usize, size_of: usize) -> *mut u8 {
+        debug_assert_ne!(self.bucket_mask, 0);
+        debug_assert!(index < self.buckets());
+        let base: *mut u8 = self.data_end().as_ptr();
+        base.sub((index + 1) * size_of)
+    }
+
+    #[inline]
     unsafe fn data_end<T>(&self) -> NonNull<T> {
         NonNull::new_unchecked(self.ctrl.as_ptr().cast())
     }
@@ -1322,7 +1285,7 @@
     /// the end of the array.
     #[inline]
     unsafe fn set_ctrl_h2(&self, index: usize, hash: u64) {
-        self.set_ctrl(index, h2(hash))
+        self.set_ctrl(index, h2(hash));
     }
 
     #[inline]
@@ -1415,6 +1378,179 @@
         }))
     }
 
+    /// Reserves or rehashes to make room for `additional` more elements.
+    ///
+    /// This uses dynamic dispatch to reduce the amount of
+    /// code generated, but it is eliminated by LLVM optimizations when inlined.
+    #[allow(clippy::inline_always)]
+    #[inline(always)]
+    unsafe fn reserve_rehash_inner(
+        &mut self,
+        additional: usize,
+        hasher: &dyn Fn(&mut Self, usize) -> u64,
+        fallibility: Fallibility,
+        layout: TableLayout,
+        drop: Option<fn(*mut u8)>,
+    ) -> Result<(), TryReserveError> {
+        // Avoid `Option::ok_or_else` because it bloats LLVM IR.
+        let new_items = match self.items.checked_add(additional) {
+            Some(new_items) => new_items,
+            None => return Err(fallibility.capacity_overflow()),
+        };
+        let full_capacity = bucket_mask_to_capacity(self.bucket_mask);
+        if new_items <= full_capacity / 2 {
+            // Rehash in-place without re-allocating if we have plenty of spare
+            // capacity that is locked up due to DELETED entries.
+            self.rehash_in_place(hasher, layout.size, drop);
+            Ok(())
+        } else {
+            // Otherwise, conservatively resize to at least the next size up
+            // to avoid churning deletes into frequent rehashes.
+            self.resize_inner(
+                usize::max(new_items, full_capacity + 1),
+                hasher,
+                fallibility,
+                layout,
+            )
+        }
+    }
+
+    /// Allocates a new table of a different size and moves the contents of the
+    /// current table into it.
+    ///
+    /// This uses dynamic dispatch to reduce the amount of
+    /// code generated, but it is eliminated by LLVM optimizations when inlined.
+    #[allow(clippy::inline_always)]
+    #[inline(always)]
+    unsafe fn resize_inner(
+        &mut self,
+        capacity: usize,
+        hasher: &dyn Fn(&mut Self, usize) -> u64,
+        fallibility: Fallibility,
+        layout: TableLayout,
+    ) -> Result<(), TryReserveError> {
+        let mut new_table = self.prepare_resize(layout, capacity, fallibility)?;
+
+        // Copy all elements to the new table.
+        for i in 0..self.buckets() {
+            if !is_full(*self.ctrl(i)) {
+                continue;
+            }
+
+            // This may panic.
+            let hash = hasher(self, i);
+
+            // We can use a simpler version of insert() here since:
+            // - there are no DELETED entries.
+            // - we know there is enough space in the table.
+            // - all elements are unique.
+            let (index, _) = new_table.prepare_insert_slot(hash);
+
+            ptr::copy_nonoverlapping(
+                self.bucket_ptr(i, layout.size),
+                new_table.bucket_ptr(index, layout.size),
+                layout.size,
+            );
+        }
+
+        // We successfully copied all elements without panicking. Now replace
+        // self with the new table. The old table will have its memory freed but
+        // the items will not be dropped (since they have been moved into the
+        // new table).
+        mem::swap(self, &mut new_table);
+
+        Ok(())
+    }
+
+    /// Rehashes the contents of the table in place (i.e. without changing the
+    /// allocation).
+    ///
+    /// If `hasher` panics then some the table's contents may be lost.
+    ///
+    /// This uses dynamic dispatch to reduce the amount of
+    /// code generated, but it is eliminated by LLVM optimizations when inlined.
+    #[allow(clippy::inline_always)]
+    #[cfg_attr(feature = "inline-more", inline(always))]
+    #[cfg_attr(not(feature = "inline-more"), inline)]
+    unsafe fn rehash_in_place(
+        &mut self,
+        hasher: &dyn Fn(&mut Self, usize) -> u64,
+        size_of: usize,
+        drop: Option<fn(*mut u8)>,
+    ) {
+        // If the hash function panics then properly clean up any elements
+        // that we haven't rehashed yet. We unfortunately can't preserve the
+        // element since we lost their hash and have no way of recovering it
+        // without risking another panic.
+        self.prepare_rehash_in_place();
+
+        let mut guard = guard(self, move |self_| {
+            if let Some(drop) = drop {
+                for i in 0..self_.buckets() {
+                    if *self_.ctrl(i) == DELETED {
+                        self_.set_ctrl(i, EMPTY);
+                        drop(self_.bucket_ptr(i, size_of));
+                        self_.items -= 1;
+                    }
+                }
+            }
+            self_.growth_left = bucket_mask_to_capacity(self_.bucket_mask) - self_.items;
+        });
+
+        // At this point, DELETED elements are elements that we haven't
+        // rehashed yet. Find them and re-insert them at their ideal
+        // position.
+        'outer: for i in 0..guard.buckets() {
+            if *guard.ctrl(i) != DELETED {
+                continue;
+            }
+
+            let i_p = guard.bucket_ptr(i, size_of);
+
+            'inner: loop {
+                // Hash the current item
+                let hash = hasher(*guard, i);
+
+                // Search for a suitable place to put it
+                let new_i = guard.find_insert_slot(hash);
+                let new_i_p = guard.bucket_ptr(new_i, size_of);
+
+                // Probing works by scanning through all of the control
+                // bytes in groups, which may not be aligned to the group
+                // size. If both the new and old position fall within the
+                // same unaligned group, then there is no benefit in moving
+                // it and we can just continue to the next item.
+                if likely(guard.is_in_same_group(i, new_i, hash)) {
+                    guard.set_ctrl_h2(i, hash);
+                    continue 'outer;
+                }
+
+                // We are moving the current item to a new position. Write
+                // our H2 to the control byte of the new position.
+                let prev_ctrl = guard.replace_ctrl_h2(new_i, hash);
+                if prev_ctrl == EMPTY {
+                    guard.set_ctrl(i, EMPTY);
+                    // If the target slot is empty, simply move the current
+                    // element into the new slot and clear the old control
+                    // byte.
+                    ptr::copy_nonoverlapping(i_p, new_i_p, size_of);
+                    continue 'outer;
+                } else {
+                    // If the target slot is occupied, swap the two elements
+                    // and then continue processing the element that we just
+                    // swapped into the old slot.
+                    debug_assert_eq!(prev_ctrl, DELETED);
+                    ptr::swap_nonoverlapping(i_p, new_i_p, size_of);
+                    continue 'inner;
+                }
+            }
+        }
+
+        guard.growth_left = bucket_mask_to_capacity(guard.bucket_mask) - guard.items;
+
+        mem::forget(guard);
+    }
+
     #[inline]
     unsafe fn free_buckets(&mut self, table_layout: TableLayout) {
         // Avoid `Option::unwrap_or_else` because it bloats LLVM IR.
@@ -1454,7 +1590,7 @@
         //
         // Note that in this context `leading_zeros` refers to the bytes at the
         // end of a group, while `trailing_zeros` refers to the bytes at the
-        // begining of a group.
+        // beginning of a group.
         let ctrl = if empty_before.leading_zeros() + empty_after.trailing_zeros() >= Group::WIDTH {
             DELETED
         } else {
@@ -1524,7 +1660,7 @@
 
                 self.clone_from_spec(source, |self_| {
                     // We need to leave the table in an empty state.
-                    self_.clear_no_drop()
+                    self_.clear_no_drop();
                 });
             }
         }
@@ -1536,8 +1672,8 @@
     unsafe fn clone_from_spec(&mut self, source: &Self, on_panic: impl FnMut(&mut Self));
 }
 impl<T: Clone, A: Allocator + Clone> RawTableClone for RawTable<T, A> {
-    #[cfg_attr(feature = "inline-more", inline)]
     default_fn! {
+        #[cfg_attr(feature = "inline-more", inline)]
         unsafe fn clone_from_spec(&mut self, source: &Self, on_panic: impl FnMut(&mut Self)) {
             self.clone_from_impl(source, on_panic);
         }
@@ -1574,7 +1710,7 @@
         // to make sure we drop only the elements that have been
         // cloned so far.
         let mut guard = guard((0, &mut *self), |(index, self_)| {
-            if mem::needs_drop::<T>() && self_.len() != 0 {
+            if mem::needs_drop::<T>() && !self_.is_empty() {
                 for i in 0..=*index {
                     if is_full(*self_.table.ctrl(i)) {
                         self_.bucket(i).drop();
@@ -1650,7 +1786,7 @@
 }
 
 impl<T, A: Allocator + Clone + Default> Default for RawTable<T, A> {
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     fn default() -> Self {
         Self::new_in(Default::default())
     }
@@ -1824,7 +1960,7 @@
         }
     }
 
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         // We don't have an item count, so just guess based on the range size.
         (
@@ -1871,7 +2007,7 @@
     /// For the iterator to remain valid, this method must be called once
     /// for each insert before `next` is called again.
     ///
-    /// This method does not guarantee that an insertion of a bucket witha greater
+    /// This method does not guarantee that an insertion of a bucket with a greater
     /// index than the last one yielded will be reflected in the iterator.
     ///
     /// This method should be called _after_ the given insert is made.
@@ -1923,7 +2059,7 @@
             //    If it did, we're done.
             //  - Otherwise, update the iterator cached group so that it won't
             //    yield a to-be-removed bucket, or _will_ yield a to-be-added bucket.
-            //    We'll also need ot update the item count accordingly.
+            //    We'll also need to update the item count accordingly.
             if let Some(index) = self.iter.current_group.lowest_set_bit() {
                 let next_bucket = self.iter.data.next_n(index);
                 if b.as_ptr() > next_bucket.as_ptr() {
@@ -2006,7 +2142,7 @@
         }
     }
 
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         (self.items, Some(self.items))
     }
@@ -2030,8 +2166,18 @@
     }
 }
 
-unsafe impl<T, A: Allocator + Clone> Send for RawIntoIter<T, A> where T: Send {}
-unsafe impl<T, A: Allocator + Clone> Sync for RawIntoIter<T, A> where T: Sync {}
+unsafe impl<T, A: Allocator + Clone> Send for RawIntoIter<T, A>
+where
+    T: Send,
+    A: Send,
+{
+}
+unsafe impl<T, A: Allocator + Clone> Sync for RawIntoIter<T, A>
+where
+    T: Sync,
+    A: Sync,
+{
+}
 
 #[cfg(feature = "nightly")]
 unsafe impl<#[may_dangle] T, A: Allocator + Clone> Drop for RawIntoIter<T, A> {
@@ -2072,7 +2218,7 @@
         unsafe { Some(self.iter.next()?.read()) }
     }
 
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
@@ -2103,8 +2249,18 @@
     }
 }
 
-unsafe impl<T, A: Allocator + Copy> Send for RawDrain<'_, T, A> where T: Send {}
-unsafe impl<T, A: Allocator + Copy> Sync for RawDrain<'_, T, A> where T: Sync {}
+unsafe impl<T, A: Allocator + Copy> Send for RawDrain<'_, T, A>
+where
+    T: Send,
+    A: Send,
+{
+}
+unsafe impl<T, A: Allocator + Copy> Sync for RawDrain<'_, T, A>
+where
+    T: Sync,
+    A: Sync,
+{
+}
 
 impl<T, A: Allocator + Clone> Drop for RawDrain<'_, T, A> {
     #[cfg_attr(feature = "inline-more", inline)]
@@ -2136,7 +2292,7 @@
         }
     }
 
-    #[cfg_attr(feature = "inline-more", inline)]
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
@@ -2147,7 +2303,9 @@
 
 /// Iterator over occupied buckets that could match a given hash.
 ///
-/// In rare cases, the iterator may return a bucket with a different hash.
+/// `RawTable` only stores 7 bits of the hash value, so this iterator may return
+/// items that have a hash value different than the one provided. You should
+/// always validate the returned values before using them.
 pub struct RawIterHash<'a, T, A: Allocator + Clone = Global> {
     inner: RawIterHashInner<'a, A>,
     _marker: PhantomData<T>,
@@ -2170,6 +2328,7 @@
 
 impl<'a, T, A: Allocator + Clone> RawIterHash<'a, T, A> {
     #[cfg_attr(feature = "inline-more", inline)]
+    #[cfg(feature = "raw")]
     fn new(table: &'a RawTable<T, A>, hash: u64) -> Self {
         RawIterHash {
             inner: RawIterHashInner::new(&table.table, hash),
@@ -2179,6 +2338,7 @@
 }
 impl<'a, A: Allocator + Clone> RawIterHashInner<'a, A> {
     #[cfg_attr(feature = "inline-more", inline)]
+    #[cfg(feature = "raw")]
     fn new(table: &'a RawTableInner<A>, hash: u64) -> Self {
         unsafe {
             let h2_hash = h2(hash);
@@ -2235,6 +2395,20 @@
 mod test_map {
     use super::*;
 
+    fn rehash_in_place<T>(table: &mut RawTable<T>, hasher: impl Fn(&T) -> u64) {
+        unsafe {
+            table.table.rehash_in_place(
+                &|table, index| hasher(table.bucket::<T>(index).as_ref()),
+                mem::size_of::<T>(),
+                if mem::needs_drop::<T>() {
+                    Some(mem::transmute(ptr::drop_in_place::<T> as unsafe fn(*mut T)))
+                } else {
+                    None
+                },
+            );
+        }
+    }
+
     #[test]
     fn rehash() {
         let mut table = RawTable::new();
@@ -2250,7 +2424,7 @@
             assert!(table.find(i + 100, |x| *x == i + 100).is_none());
         }
 
-        table.rehash_in_place(hasher);
+        rehash_in_place(&mut table, hasher);
 
         for i in 0..100 {
             unsafe {
diff --git a/sgx_tstd/hashbrown/src/raw/sse2.rs b/sgx_tstd/hashbrown/src/raw/sse2.rs
index eed9684..a0bf6da 100644
--- a/sgx_tstd/hashbrown/src/raw/sse2.rs
+++ b/sgx_tstd/hashbrown/src/raw/sse2.rs
@@ -28,6 +28,7 @@
     /// value for an empty hash table.
     ///
     /// This is guaranteed to be aligned to the group size.
+    #[inline]
     #[allow(clippy::items_after_statements)]
     pub const fn static_empty() -> &'static [u8; Group::WIDTH] {
         #[repr(C)]
diff --git a/sgx_tstd/hashbrown/src/rustc_entry.rs b/sgx_tstd/hashbrown/src/rustc_entry.rs
index 1793c4a..465db47 100644
--- a/sgx_tstd/hashbrown/src/rustc_entry.rs
+++ b/sgx_tstd/hashbrown/src/rustc_entry.rs
@@ -574,8 +574,10 @@
     /// ```
     #[cfg_attr(feature = "inline-more", inline)]
     pub fn insert(self, value: V) -> &'a mut V {
-        let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
-        unsafe { &mut bucket.as_mut().1 }
+        unsafe {
+            let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
+            &mut bucket.as_mut().1
+        }
     }
 
     /// Sets the value of the entry with the RustcVacantEntry's key,
@@ -596,7 +598,7 @@
     /// ```
     #[cfg_attr(feature = "inline-more", inline)]
     pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> {
-        let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
+        let bucket = unsafe { self.table.insert_no_grow(self.hash, (self.key, value)) };
         RustcOccupiedEntry {
             key: None,
             elem: bucket,
diff --git a/sgx_tstd/hashbrown/src/scopeguard.rs b/sgx_tstd/hashbrown/src/scopeguard.rs
index 4e9bf04..ccdc0c5 100644
--- a/sgx_tstd/hashbrown/src/scopeguard.rs
+++ b/sgx_tstd/hashbrown/src/scopeguard.rs
@@ -44,6 +44,6 @@
 {
     #[inline]
     fn drop(&mut self) {
-        (self.dropfn)(&mut self.value)
+        (self.dropfn)(&mut self.value);
     }
 }
diff --git a/sgx_tstd/hashbrown/src/set.rs b/sgx_tstd/hashbrown/src/set.rs
index d59183b..bb83054 100644
--- a/sgx_tstd/hashbrown/src/set.rs
+++ b/sgx_tstd/hashbrown/src/set.rs
@@ -378,7 +378,7 @@
     /// ```
     #[cfg_attr(feature = "inline-more", inline)]
     pub fn clear(&mut self) {
-        self.map.clear()
+        self.map.clear();
     }
 }
 
@@ -454,6 +454,12 @@
 where
     A: Allocator + Clone,
 {
+    /// Returns a reference to the underlying allocator.
+    #[inline]
+    pub fn allocator(&self) -> &A {
+        self.map.allocator()
+    }
+
     /// Creates a new empty hash set which will use the given hasher to hash
     /// keys.
     ///
@@ -553,7 +559,7 @@
     /// ```
     #[cfg_attr(feature = "inline-more", inline)]
     pub fn reserve(&mut self, additional: usize) {
-        self.map.reserve(additional)
+        self.map.reserve(additional);
     }
 
     /// Tries to reserve capacity for at least `additional` more elements to be inserted
@@ -595,7 +601,7 @@
     /// ```
     #[cfg_attr(feature = "inline-more", inline)]
     pub fn shrink_to_fit(&mut self) {
-        self.map.shrink_to_fit()
+        self.map.shrink_to_fit();
     }
 
     /// Shrinks the capacity of the set with a lower limit. It will drop
@@ -621,7 +627,7 @@
     /// ```
     #[cfg_attr(feature = "inline-more", inline)]
     pub fn shrink_to(&mut self, min_capacity: usize) {
-        self.map.shrink_to(min_capacity)
+        self.map.shrink_to(min_capacity);
     }
 
     /// Visits the values representing the difference,
@@ -985,6 +991,30 @@
         self.map.insert(value, ()).is_none()
     }
 
+    /// Insert a value the set without checking if the value already exists in the set.
+    ///
+    /// Returns a reference to the value just inserted.
+    ///
+    /// This operation is safe if a value does not exist in the set.
+    ///
+    /// However, if a value exists in the set already, the behavior is unspecified:
+    /// this operation may panic, loop forever, or any following operation with the set
+    /// may panic, loop forever or return arbitrary result.
+    ///
+    /// That said, this operation (and following operations) are guaranteed to
+    /// not violate memory safety.
+    ///
+    /// This operation is faster than regular insert, because it does not perform
+    /// lookup before insertion.
+    ///
+    /// This operation is useful during initial population of the set.
+    /// For example, when constructing a set from another set, we know
+    /// that values are unique.
+    #[cfg_attr(feature = "inline-more", inline)]
+    pub fn insert_unique_unchecked(&mut self, value: T) -> &T {
+        self.map.insert_unique_unchecked(value, ()).0
+    }
+
     /// Adds a value to the set, replacing the existing value, if any, that is equal to the given
     /// one. Returns the replaced value.
     ///
@@ -1098,8 +1128,7 @@
 
 impl<T, S, A> fmt::Debug for HashSet<T, S, A>
 where
-    T: Eq + Hash + fmt::Debug,
-    S: BuildHasher,
+    T: fmt::Debug,
     A: Allocator + Clone,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1130,6 +1159,27 @@
     }
 }
 
+// The default hasher is used to match the std implementation signature
+#[cfg(feature = "ahash")]
+impl<T, A, const N: usize> From<[T; N]> for HashSet<T, DefaultHashBuilder, A>
+where
+    T: Eq + Hash,
+    A: Default + Allocator + Clone,
+{
+    /// # Examples
+    ///
+    /// ```
+    /// use hashbrown::HashSet;
+    ///
+    /// let set1 = HashSet::from([1, 2, 3, 4]);
+    /// let set2: HashSet<_> = [1, 2, 3, 4].into();
+    /// assert_eq!(set1, set2);
+    /// ```
+    fn from(arr: [T; N]) -> Self {
+        arr.into_iter().collect()
+    }
+}
+
 impl<T, S, A> Extend<T> for HashSet<T, S, A>
 where
     T: Eq + Hash,
@@ -1162,7 +1212,7 @@
 {
     #[cfg_attr(feature = "inline-more", inline)]
     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
-        self.extend(iter.into_iter().cloned());
+        self.extend(iter.into_iter().copied());
     }
 
     #[inline]
@@ -1963,7 +2013,7 @@
         let expected = [3, 5, 11, 77];
         for x in a.intersection(&b) {
             assert!(expected.contains(x));
-            i += 1
+            i += 1;
         }
         assert_eq!(i, expected.len());
     }
@@ -1986,7 +2036,7 @@
         let expected = [1, 5, 11];
         for x in a.difference(&b) {
             assert!(expected.contains(x));
-            i += 1
+            i += 1;
         }
         assert_eq!(i, expected.len());
     }
@@ -2012,7 +2062,7 @@
         let expected = [-2, 1, 5, 11, 14, 22];
         for x in a.symmetric_difference(&b) {
             assert!(expected.contains(x));
-            i += 1
+            i += 1;
         }
         assert_eq!(i, expected.len());
     }
@@ -2042,7 +2092,7 @@
         let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
         for x in a.union(&b) {
             assert!(expected.contains(x));
-            i += 1
+            i += 1;
         }
         assert_eq!(i, expected.len());
     }
@@ -2068,7 +2118,7 @@
     fn test_from_iter() {
         let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9];
 
-        let set: HashSet<_> = xs.iter().cloned().collect();
+        let set: HashSet<_> = xs.iter().copied().collect();
 
         for x in &xs {
             assert!(set.contains(x));
@@ -2230,7 +2280,7 @@
     #[test]
     fn test_retain() {
         let xs = [1, 2, 3, 4, 5, 6];
-        let mut set: HashSet<i32> = xs.iter().cloned().collect();
+        let mut set: HashSet<i32> = xs.iter().copied().collect();
         set.retain(|&k| k % 2 == 0);
         assert_eq!(set.len(), 3);
         assert!(set.contains(&2));
@@ -2272,7 +2322,7 @@
 
         const EMPTY_SET: HashSet<u32, MyHasher> = HashSet::with_hasher(MyHasher);
 
-        let mut set = EMPTY_SET.clone();
+        let mut set = EMPTY_SET;
         set.insert(19);
         assert!(set.contains(&19));
     }
diff --git a/sgx_tstd/hashbrown/tests/rayon.rs b/sgx_tstd/hashbrown/tests/rayon.rs
index 39b4770..8c603c5 100644
--- a/sgx_tstd/hashbrown/tests/rayon.rs
+++ b/sgx_tstd/hashbrown/tests/rayon.rs
@@ -269,20 +269,20 @@
     let mut map_seq = MAP_EXISTING_EMPTY.clone();
     let mut map_par = MAP_EXISTING_EMPTY.clone();
 
-    map_seq.extend(MAP_EXTENSION_EMPTY.iter().cloned());
-    map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().cloned());
+    map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied());
+    map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied());
 
     assert_eq3!(map_seq, map_par, expected);
 }
 
 #[test]
 fn map_seq_par_equivalence_existing_empty_extend() {
-    let expected = MAP_EXTENSION.iter().cloned().collect::<HashMap<_, _>>();
+    let expected = MAP_EXTENSION.iter().copied().collect::<HashMap<_, _>>();
     let mut map_seq = MAP_EXISTING_EMPTY.clone();
     let mut map_par = MAP_EXISTING_EMPTY.clone();
 
-    map_seq.extend(MAP_EXTENSION.iter().cloned());
-    map_par.par_extend(MAP_EXTENSION.par_iter().cloned());
+    map_seq.extend(MAP_EXTENSION.iter().copied());
+    map_par.par_extend(MAP_EXTENSION.par_iter().copied());
 
     assert_eq3!(map_seq, map_par, expected);
 }
@@ -293,8 +293,8 @@
     let mut map_seq = MAP_EXISTING.clone();
     let mut map_par = MAP_EXISTING.clone();
 
-    map_seq.extend(MAP_EXTENSION_EMPTY.iter().cloned());
-    map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().cloned());
+    map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied());
+    map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied());
 
     assert_eq3!(map_seq, map_par, expected);
 }
@@ -305,8 +305,8 @@
     let mut map_seq = MAP_EXISTING.clone();
     let mut map_par = MAP_EXISTING.clone();
 
-    map_seq.extend(MAP_EXTENSION.iter().cloned());
-    map_par.par_extend(MAP_EXTENSION.par_iter().cloned());
+    map_seq.extend(MAP_EXTENSION.iter().copied());
+    map_par.par_extend(MAP_EXTENSION.par_iter().copied());
 
     assert_eq3!(map_seq, map_par, expected);
 }
@@ -423,20 +423,20 @@
     let mut set_seq = SET_EXISTING_EMPTY.clone();
     let mut set_par = SET_EXISTING_EMPTY.clone();
 
-    set_seq.extend(SET_EXTENSION_EMPTY.iter().cloned());
-    set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().cloned());
+    set_seq.extend(SET_EXTENSION_EMPTY.iter().copied());
+    set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied());
 
     assert_eq3!(set_seq, set_par, expected);
 }
 
 #[test]
 fn set_seq_par_equivalence_existing_empty_extend() {
-    let expected = SET_EXTENSION.iter().cloned().collect::<HashSet<_>>();
+    let expected = SET_EXTENSION.iter().copied().collect::<HashSet<_>>();
     let mut set_seq = SET_EXISTING_EMPTY.clone();
     let mut set_par = SET_EXISTING_EMPTY.clone();
 
-    set_seq.extend(SET_EXTENSION.iter().cloned());
-    set_par.par_extend(SET_EXTENSION.par_iter().cloned());
+    set_seq.extend(SET_EXTENSION.iter().copied());
+    set_par.par_extend(SET_EXTENSION.par_iter().copied());
 
     assert_eq3!(set_seq, set_par, expected);
 }
@@ -447,8 +447,8 @@
     let mut set_seq = SET_EXISTING.clone();
     let mut set_par = SET_EXISTING.clone();
 
-    set_seq.extend(SET_EXTENSION_EMPTY.iter().cloned());
-    set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().cloned());
+    set_seq.extend(SET_EXTENSION_EMPTY.iter().copied());
+    set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied());
 
     assert_eq3!(set_seq, set_par, expected);
 }
@@ -459,37 +459,37 @@
     let mut set_seq = SET_EXISTING.clone();
     let mut set_par = SET_EXISTING.clone();
 
-    set_seq.extend(SET_EXTENSION.iter().cloned());
-    set_par.par_extend(SET_EXTENSION.par_iter().cloned());
+    set_seq.extend(SET_EXTENSION.iter().copied());
+    set_par.par_extend(SET_EXTENSION.par_iter().copied());
 
     assert_eq3!(set_seq, set_par, expected);
 }
 
 lazy_static! {
-    static ref SET_A: HashSet<char> = ['a', 'b', 'c', 'd'].iter().cloned().collect();
-    static ref SET_B: HashSet<char> = ['a', 'b', 'e', 'f'].iter().cloned().collect();
-    static ref SET_DIFF_AB: HashSet<char> = ['c', 'd'].iter().cloned().collect();
-    static ref SET_DIFF_BA: HashSet<char> = ['e', 'f'].iter().cloned().collect();
-    static ref SET_SYMM_DIFF_AB: HashSet<char> = ['c', 'd', 'e', 'f'].iter().cloned().collect();
-    static ref SET_INTERSECTION_AB: HashSet<char> = ['a', 'b'].iter().cloned().collect();
+    static ref SET_A: HashSet<char> = ['a', 'b', 'c', 'd'].iter().copied().collect();
+    static ref SET_B: HashSet<char> = ['a', 'b', 'e', 'f'].iter().copied().collect();
+    static ref SET_DIFF_AB: HashSet<char> = ['c', 'd'].iter().copied().collect();
+    static ref SET_DIFF_BA: HashSet<char> = ['e', 'f'].iter().copied().collect();
+    static ref SET_SYMM_DIFF_AB: HashSet<char> = ['c', 'd', 'e', 'f'].iter().copied().collect();
+    static ref SET_INTERSECTION_AB: HashSet<char> = ['a', 'b'].iter().copied().collect();
     static ref SET_UNION_AB: HashSet<char> =
-        ['a', 'b', 'c', 'd', 'e', 'f'].iter().cloned().collect();
+        ['a', 'b', 'c', 'd', 'e', 'f'].iter().copied().collect();
 }
 
 #[test]
 fn set_seq_par_equivalence_difference() {
-    let diff_ab_seq = SET_A.difference(&*SET_B).cloned().collect::<HashSet<_>>();
+    let diff_ab_seq = SET_A.difference(&*SET_B).copied().collect::<HashSet<_>>();
     let diff_ab_par = SET_A
         .par_difference(&*SET_B)
-        .cloned()
+        .copied()
         .collect::<HashSet<_>>();
 
     assert_eq3!(diff_ab_seq, diff_ab_par, *SET_DIFF_AB);
 
-    let diff_ba_seq = SET_B.difference(&*SET_A).cloned().collect::<HashSet<_>>();
+    let diff_ba_seq = SET_B.difference(&*SET_A).copied().collect::<HashSet<_>>();
     let diff_ba_par = SET_B
         .par_difference(&*SET_A)
-        .cloned()
+        .copied()
         .collect::<HashSet<_>>();
 
     assert_eq3!(diff_ba_seq, diff_ba_par, *SET_DIFF_BA);
@@ -499,11 +499,11 @@
 fn set_seq_par_equivalence_symmetric_difference() {
     let symm_diff_ab_seq = SET_A
         .symmetric_difference(&*SET_B)
-        .cloned()
+        .copied()
         .collect::<HashSet<_>>();
     let symm_diff_ab_par = SET_A
         .par_symmetric_difference(&*SET_B)
-        .cloned()
+        .copied()
         .collect::<HashSet<_>>();
 
     assert_eq3!(symm_diff_ab_seq, symm_diff_ab_par, *SET_SYMM_DIFF_AB);
@@ -511,10 +511,10 @@
 
 #[test]
 fn set_seq_par_equivalence_intersection() {
-    let intersection_ab_seq = SET_A.intersection(&*SET_B).cloned().collect::<HashSet<_>>();
+    let intersection_ab_seq = SET_A.intersection(&*SET_B).copied().collect::<HashSet<_>>();
     let intersection_ab_par = SET_A
         .par_intersection(&*SET_B)
-        .cloned()
+        .copied()
         .collect::<HashSet<_>>();
 
     assert_eq3!(
@@ -526,8 +526,8 @@
 
 #[test]
 fn set_seq_par_equivalence_union() {
-    let union_ab_seq = SET_A.union(&*SET_B).cloned().collect::<HashSet<_>>();
-    let union_ab_par = SET_A.par_union(&*SET_B).cloned().collect::<HashSet<_>>();
+    let union_ab_seq = SET_A.union(&*SET_B).copied().collect::<HashSet<_>>();
+    let union_ab_par = SET_A.par_union(&*SET_B).copied().collect::<HashSet<_>>();
 
     assert_eq3!(union_ab_seq, union_ab_par, *SET_UNION_AB);
 }
diff --git a/sgx_tstd/hashbrown/tests/set.rs b/sgx_tstd/hashbrown/tests/set.rs
index 3fc0717..5ae1ec9 100644
--- a/sgx_tstd/hashbrown/tests/set.rs
+++ b/sgx_tstd/hashbrown/tests/set.rs
@@ -2,29 +2,33 @@
 
 use hashbrown::HashSet;
 use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng};
+use std::iter;
 
 #[test]
 fn test_hashset_insert_remove() {
     let mut m: HashSet<Vec<char>> = HashSet::new();
-    //let num: u32 = 4096;
-    //let tx: Vec<Vec<u8>> = (0..num).map(|i| (i..(16 + i)).collect()).collect();
-    let seed: [u8; 16] = [
-        130, 220, 246, 217, 111, 124, 221, 189, 190, 234, 121, 93, 67, 95, 100, 43,
-    ];
+    let seed = u64::from_le_bytes(*b"testseed");
 
-    let rng = &mut SmallRng::from_seed(seed);
-    let tx: Vec<Vec<char>> = (0..4096)
-        .map(|_| (rng.sample_iter(&Alphanumeric).take(32).collect()))
-        .collect();
+    let rng = &mut SmallRng::seed_from_u64(seed);
+    let tx: Vec<Vec<char>> = iter::repeat_with(|| {
+        rng.sample_iter(&Alphanumeric)
+            .take(32)
+            .map(char::from)
+            .collect()
+    })
+    .take(4096)
+    .collect();
 
+    // more readable with explicit `true` / `false`
+    #[allow(clippy::bool_assert_comparison)]
     for _ in 0..32 {
-        for i in 0..4096 {
-            assert_eq!(m.contains(&tx[i].clone()), false);
-            assert_eq!(m.insert(tx[i].clone()), true);
+        for x in &tx {
+            assert_eq!(m.contains(x), false);
+            assert_eq!(m.insert(x.clone()), true);
         }
-        for i in 0..4096 {
-            println!("removing {} {:?}", i, tx[i]);
-            assert_eq!(m.remove(&tx[i]), true);
+        for (i, x) in tx.iter().enumerate() {
+            println!("removing {} {:?}", i, x);
+            assert_eq!(m.remove(x), true);
         }
     }
 }
diff --git a/sgx_tstd/src/backtrace.rs b/sgx_tstd/src/backtrace.rs
index e7c96b8..a491f5d 100644
--- a/sgx_tstd/src/backtrace.rs
+++ b/sgx_tstd/src/backtrace.rs
@@ -83,13 +83,14 @@
 // a backtrace or actually symbolizing it.
 
 pub use crate::sys_common::backtrace::__rust_begin_short_backtrace;
-pub use crate::sys_common::backtrace::PrintFormat;
 
 use crate::cell::UnsafeCell;
 use crate::ffi::c_void;
 use crate::fmt;
+use crate::fs;
 use crate::enclave;
 use crate::io;
+use crate::panic::{BacktraceStyle, get_backtrace_style, set_backtrace_style};
 use crate::path::Path;
 use crate::sync::Once;
 use crate::sys::backtrace::{self, BytesOrWideString};
@@ -97,12 +98,8 @@
     lock,
     output_filename,
     resolve_frame_unsynchronized,
-    rust_backtrace_env,
-    RustBacktrace,
-    set_enabled,
     SymbolName,
 };
-use crate::untrusted::fs;
 use crate::vec::Vec;
 
 /// A captured OS thread stack backtrace.
@@ -249,7 +246,16 @@
 impl Backtrace {
     /// Returns whether backtrace captures are enabled
     fn enabled() -> bool {
-        matches!(rust_backtrace_env(), RustBacktrace::Print(_))
+        match get_backtrace_style() {
+            Some(style) => {
+                match style {
+                    BacktraceStyle::Full => true,
+                    BacktraceStyle::Short => true,
+                    BacktraceStyle::Off => false,
+                }
+            }
+            None => false,
+        }
     }
 
     /// Capture a stack backtrace of the current thread.
@@ -424,6 +430,7 @@
 unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}
 
 impl Capture {
+    #[allow(clippy::infallible_destructuring_match)]
     fn resolve(&mut self) {
         // If we're already resolved, nothing to do!
         if self.resolved {
@@ -460,12 +467,19 @@
     fn ip(&self) -> *mut c_void {
         match self {
             RawFrame::Actual(frame) => frame.ip(),
-            #[cfg(test)]
-            RawFrame::Fake => 1 as *mut c_void,
         }
     }
 }
 
+/// Controls how the backtrace should be formatted.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum PrintFormat {
+    /// Show only relevant data from the backtrace.
+    Short,
+    /// Show all the frames with absolute path for files.
+    Full,
+}
+
 /// Enable backtrace for dumping call stack on crash.
 ///
 /// Enabling backtrace here makes the panic information along with call stack
@@ -477,6 +491,10 @@
 pub fn enable_backtrace<P: AsRef<Path>>(path: P, format: PrintFormat) -> io::Result<()> {
     let _ = fs::metadata(&path)?;
     enclave::set_enclave_path(path)?;
-    set_enabled(format);
+    let style = match format {
+        PrintFormat::Short => BacktraceStyle::Short,
+        PrintFormat::Full => BacktraceStyle::Full,
+    };
+    set_backtrace_style(style);
     Ok(())
 }
diff --git a/sgx_tstd/src/collections/hash/map.rs b/sgx_tstd/src/collections/hash/map.rs
index 8b7fd72..2c5012a 100644
--- a/sgx_tstd/src/collections/hash/map.rs
+++ b/sgx_tstd/src/collections/hash/map.rs
@@ -342,10 +342,11 @@
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// for key in map.keys() {
     ///     println!("{}", key);
@@ -355,6 +356,33 @@
         Keys { inner: self.iter() }
     }
 
+    /// Creates a consuming iterator visiting all the keys in arbitrary order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `K`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
+    ///
+    /// let mut vec: Vec<&str> = map.into_keys().collect();
+    /// // The `IntoKeys` iterator produces keys in arbitrary order, so the
+    /// // keys must be sorted to test them against a sorted array.
+    /// vec.sort_unstable();
+    /// assert_eq!(vec, ["a", "b", "c"]);
+    /// ```
+    #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+    pub fn into_keys(self) -> IntoKeys<K, V> {
+        IntoKeys { inner: self.into_iter() }
+    }
+
     /// An iterator visiting all values in arbitrary order.
     /// The iterator element type is `&'a V`.
     ///
@@ -363,10 +391,11 @@
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// for val in map.values() {
     ///     println!("{}", val);
@@ -384,11 +413,11 @@
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    ///
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let mut map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// for val in map.values_mut() {
     ///     *val = *val + 10;
@@ -402,6 +431,33 @@
         ValuesMut { inner: self.iter_mut() }
     }
 
+    /// Creates a consuming iterator visiting all the values in arbitrary order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `V`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
+    ///
+    /// let mut vec: Vec<i32> = map.into_values().collect();
+    /// // The `IntoValues` iterator produces values in arbitrary order, so
+    /// // the values must be sorted to test them against a sorted array.
+    /// vec.sort_unstable();
+    /// assert_eq!(vec, [1, 2, 3]);
+    /// ```
+    #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+    pub fn into_values(self) -> IntoValues<K, V> {
+        IntoValues { inner: self.into_iter() }
+    }
+
     /// An iterator visiting all key-value pairs in arbitrary order.
     /// The iterator element type is `(&'a K, &'a V)`.
     ///
@@ -410,15 +466,17 @@
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// for (key, val) in map.iter() {
     ///     println!("key: {} val: {}", key, val);
     /// }
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn iter(&self) -> Iter<'_, K, V> {
         Iter { base: self.base.iter() }
     }
@@ -432,10 +490,11 @@
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let mut map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// // Update all values
     /// for (_, val) in map.iter_mut() {
@@ -446,6 +505,7 @@
     ///     println!("key: {} val: {}", key, val);
     /// }
     /// ```
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
         IterMut { base: self.base.iter_mut() }
     }
@@ -486,6 +546,10 @@
     /// Clears the map, returning all key-value pairs as an iterator. Keeps the
     /// allocated memory for reuse.
     ///
+    /// If the returned iterator is dropped before being fully consumed, it
+    /// drops the remaining key-value pairs. The returned iterator keeps a
+    /// mutable borrow on the vector to optimize its implementation.
+    ///
     /// # Examples
     ///
     /// ```
@@ -503,6 +567,7 @@
     /// assert!(a.is_empty());
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn drain(&mut self) -> Drain<'_, K, V> {
         Drain { base: self.base.drain() }
     }
@@ -543,6 +608,7 @@
     /// assert_eq!(odds, vec![1, 3, 5, 7]);
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
     where
         F: FnMut(&K, &mut V) -> bool,
@@ -550,6 +616,29 @@
         DrainFilter { base: self.base.drain_filter(pred) }
     }
 
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+    /// The elements are visited in unsorted (and unspecified) order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x*10)).collect();
+    /// map.retain(|&k, _| k % 2 == 0);
+    /// assert_eq!(map.len(), 4);
+    /// ```
+    #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+    pub fn retain<F>(&mut self, f: F)
+    where
+        F: FnMut(&K, &mut V) -> bool,
+    {
+        self.base.retain(f)
+    }
+
     /// Clears the map, removing all key-value pairs. Keeps the allocated memory
     /// for reuse.
     ///
@@ -917,78 +1006,6 @@
     {
         self.base.remove_entry(k)
     }
-
-    /// Retains only the elements specified by the predicate.
-    ///
-    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
-    /// The elements are visited in unsorted (and unspecified) order.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::HashMap;
-    ///
-    /// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x*10)).collect();
-    /// map.retain(|&k, _| k % 2 == 0);
-    /// assert_eq!(map.len(), 4);
-    /// ```
-    #[inline]
-    pub fn retain<F>(&mut self, f: F)
-    where
-        F: FnMut(&K, &mut V) -> bool,
-    {
-        self.base.retain(f)
-    }
-
-    /// Creates a consuming iterator visiting all the keys in arbitrary order.
-    /// The map cannot be used after calling this.
-    /// The iterator element type is `K`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::HashMap;
-    ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
-    ///
-    /// let mut vec: Vec<&str> = map.into_keys().collect();
-    /// // The `IntoKeys` iterator produces keys in arbitrary order, so the
-    /// // keys must be sorted to test them against a sorted array.
-    /// vec.sort_unstable();
-    /// assert_eq!(vec, ["a", "b", "c"]);
-    /// ```
-    #[inline]
-    pub fn into_keys(self) -> IntoKeys<K, V> {
-        IntoKeys { inner: self.into_iter() }
-    }
-
-    /// Creates a consuming iterator visiting all the values in arbitrary order.
-    /// The map cannot be used after calling this.
-    /// The iterator element type is `V`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::HashMap;
-    ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
-    ///
-    /// let mut vec: Vec<i32> = map.into_values().collect();
-    /// // The `IntoValues` iterator produces values in arbitrary order, so
-    /// // the values must be sorted to test them against a sorted array.
-    /// vec.sort_unstable();
-    /// assert_eq!(vec, [1, 2, 3]);
-    /// ```
-    #[inline]
-    pub fn into_values(self) -> IntoValues<K, V> {
-        IntoValues { inner: self.into_iter() }
-    }
 }
 
 impl<K, V, S> HashMap<K, V, S>
@@ -1158,7 +1175,7 @@
     /// assert_eq!(map1, map2);
     /// ```
     fn from(arr: [(K, V); N]) -> Self {
-        crate::array::IntoIter::new(arr).collect()
+        Self::from_iter(arr)
     }
 }
 
@@ -1174,8 +1191,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.iter();
 /// ```
 pub struct Iter<'a, K: 'a, V: 'a> {
@@ -1208,8 +1226,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.iter_mut();
 /// ```
 pub struct IterMut<'a, K: 'a, V: 'a> {
@@ -1237,8 +1256,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.into_iter();
 /// ```
 pub struct IntoIter<K, V> {
@@ -1265,8 +1285,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_keys = map.keys();
 /// ```
 pub struct Keys<'a, K: 'a, V: 'a> {
@@ -1299,8 +1320,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_values = map.values();
 /// ```
 pub struct Values<'a, K: 'a, V: 'a> {
@@ -1333,8 +1355,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.drain();
 /// ```
 pub struct Drain<'a, K: 'a, V: 'a> {
@@ -1362,8 +1385,9 @@
 ///
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.drain_filter(|_k, v| *v % 2 == 0);
 /// ```
 pub struct DrainFilter<'a, K, V, F>
@@ -1385,8 +1409,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_values = map.values_mut();
 /// ```
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
@@ -1405,8 +1430,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_keys = map.into_keys();
 /// ```
 pub struct IntoKeys<K, V> {
@@ -1425,8 +1451,9 @@
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_keys = map.into_values();
 /// ```
 pub struct IntoValues<K, V> {
@@ -1628,6 +1655,7 @@
     ///    .or_insert("poneyland", 0);
     /// assert_eq!(map["poneyland"], 43);
     /// ```
+    #[must_use]
     #[inline]
     pub fn and_modify<F>(self, f: F) -> Self
     where
@@ -1912,15 +1940,17 @@
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// // Not possible with .iter()
     /// let vec: Vec<(&str, i32)> = map.into_iter().collect();
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     fn into_iter(self) -> IntoIter<K, V> {
         IntoIter { base: self.base.into_iter() }
     }
@@ -2310,6 +2340,7 @@
     ///    .or_insert(42);
     /// assert_eq!(map["poneyland"], 43);
     /// ```
+    #[must_use]
     #[inline]
     pub fn and_modify<F>(self, f: F) -> Self
     where
@@ -2333,12 +2364,12 @@
     /// use std::collections::HashMap;
     ///
     /// let mut map: HashMap<&str, String> = HashMap::new();
-    /// let entry = map.entry("poneyland").insert("hoho".to_string());
+    /// let entry = map.entry("poneyland").insert_entry("hoho".to_string());
     ///
     /// assert_eq!(entry.key(), &"poneyland");
     /// ```
     #[inline]
-    pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V> {
+    pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> {
         match self {
             Occupied(mut entry) => {
                 entry.insert(value);
@@ -2664,12 +2695,12 @@
     /// let mut map: HashMap<&str, u32> = HashMap::new();
     ///
     /// if let Entry::Vacant(o) = map.entry("poneyland") {
-    ///     o.insert(37);
+    ///     o.insert_entry(37);
     /// }
     /// assert_eq!(map["poneyland"], 37);
     /// ```
     #[inline]
-    fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> {
+    pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> {
         let base = self.base.insert_entry(value);
         OccupiedEntry { base }
     }
diff --git a/sgx_tstd/src/collections/hash/set.rs b/sgx_tstd/src/collections/hash/set.rs
index 2eb6577..b6b62b6 100644
--- a/sgx_tstd/src/collections/hash/set.rs
+++ b/sgx_tstd/src/collections/hash/set.rs
@@ -195,6 +195,7 @@
     /// }
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn iter(&self) -> Iter<'_, T> {
         Iter { base: self.base.iter() }
     }
@@ -233,14 +234,19 @@
         self.base.is_empty()
     }
 
-    /// Clears the set, returning all elements in an iterator.
+    /// Clears the set, returning all elements as an iterator. Keeps the
+    /// allocated memory for reuse.
+    ///
+    /// If the returned iterator is dropped before being fully consumed, it
+    /// drops the remaining elements. The returned iterator keeps a mutable
+    /// borrow on the vector to optimize its implementation.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set = HashSet::from([1, 2, 3]);
     /// assert!(!set.is_empty());
     ///
     /// // print 1, 2, 3 in an arbitrary order
@@ -251,6 +257,7 @@
     /// assert!(set.is_empty());
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn drain(&mut self) -> Drain<'_, T> {
         Drain { base: self.base.drain() }
     }
@@ -288,6 +295,7 @@
     /// assert_eq!(odds, vec![1, 3, 5, 7]);
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
     where
         F: FnMut(&T) -> bool,
@@ -295,6 +303,28 @@
         DrainFilter { base: self.base.drain_filter(pred) }
     }
 
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// The elements are visited in unsorted (and unspecified) order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
+    /// set.retain(|&k| k % 2 == 0);
+    /// assert_eq!(set.len(), 3);
+    /// ```
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+    pub fn retain<F>(&mut self, f: F)
+    where
+        F: FnMut(&T) -> bool,
+    {
+        self.base.retain(f)
+    }
+
     /// Clears the set, removing all values.
     ///
     /// # Examples
@@ -486,8 +516,8 @@
     ///
     /// ```
     /// use std::collections::HashSet;
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([4, 2, 3, 4]);
     ///
     /// // Can be seen as `a - b`.
     /// for x in a.difference(&b) {
@@ -503,6 +533,7 @@
     /// assert_eq!(diff, [4].iter().collect());
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> {
         Difference { iter: self.iter(), other }
     }
@@ -514,8 +545,8 @@
     ///
     /// ```
     /// use std::collections::HashSet;
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([4, 2, 3, 4]);
     ///
     /// // Print 1, 4 in arbitrary order.
     /// for x in a.symmetric_difference(&b) {
@@ -529,6 +560,7 @@
     /// assert_eq!(diff1, [1, 4].iter().collect());
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn symmetric_difference<'a>(
         &'a self,
         other: &'a HashSet<T, S>,
@@ -543,8 +575,8 @@
     ///
     /// ```
     /// use std::collections::HashSet;
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([4, 2, 3, 4]);
     ///
     /// // Print 2, 3 in arbitrary order.
     /// for x in a.intersection(&b) {
@@ -555,6 +587,7 @@
     /// assert_eq!(intersection, [2, 3].iter().collect());
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
         if self.len() <= other.len() {
             Intersection { iter: self.iter(), other }
@@ -570,8 +603,8 @@
     ///
     /// ```
     /// use std::collections::HashSet;
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([4, 2, 3, 4]);
     ///
     /// // Print 1, 2, 3, 4 in arbitrary order.
     /// for x in a.union(&b) {
@@ -582,6 +615,7 @@
     /// assert_eq!(union, [1, 2, 3, 4].iter().collect());
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
         if self.len() >= other.len() {
             Union { iter: self.iter().chain(other.difference(self)) }
@@ -601,7 +635,7 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let set = HashSet::from([1, 2, 3]);
     /// assert_eq!(set.contains(&1), true);
     /// assert_eq!(set.contains(&4), false);
     /// ```
@@ -625,7 +659,7 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let set = HashSet::from([1, 2, 3]);
     /// assert_eq!(set.get(&2), Some(&2));
     /// assert_eq!(set.get(&4), None);
     /// ```
@@ -648,7 +682,7 @@
     ///
     /// use std::collections::HashSet;
     ///
-    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set = HashSet::from([1, 2, 3]);
     /// assert_eq!(set.len(), 3);
     /// assert_eq!(set.get_or_insert(2), &2);
     /// assert_eq!(set.get_or_insert(100), &100);
@@ -732,7 +766,7 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
     /// let mut b = HashSet::new();
     ///
     /// assert_eq!(a.is_disjoint(&b), true);
@@ -757,7 +791,7 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let sup = HashSet::from([1, 2, 3]);
     /// let mut set = HashSet::new();
     ///
     /// assert_eq!(set.is_subset(&sup), true);
@@ -778,7 +812,7 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let sub: HashSet<_> = [1, 2].iter().cloned().collect();
+    /// let sub = HashSet::from([1, 2]);
     /// let mut set = HashSet::new();
     ///
     /// assert_eq!(set.is_superset(&sub), false);
@@ -875,7 +909,7 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set = HashSet::from([1, 2, 3]);
     /// assert_eq!(set.take(&2), Some(2));
     /// assert_eq!(set.take(&2), None);
     /// ```
@@ -887,28 +921,6 @@
     {
         self.base.take(value)
     }
-
-    /// Retains only the elements specified by the predicate.
-    ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
-    /// The elements are visited in unsorted (and unspecified) order.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::HashSet;
-    ///
-    /// let xs = [1, 2, 3, 4, 5, 6];
-    /// let mut set: HashSet<i32> = xs.iter().cloned().collect();
-    /// set.retain(|&k| k % 2 == 0);
-    /// assert_eq!(set.len(), 3);
-    /// ```
-    pub fn retain<F>(&mut self, f: F)
-    where
-        F: FnMut(&T) -> bool,
-    {
-        self.base.retain(f)
-    }
 }
 
 impl<T, S> Clone for HashSet<T, S>
@@ -996,7 +1008,7 @@
     /// assert_eq!(set1, set2);
     /// ```
     fn from(arr: [T; N]) -> Self {
-        crate::array::IntoIter::new(arr).collect()
+        Self::from_iter(arr)
     }
 }
 
@@ -1067,8 +1079,8 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([3, 4, 5]);
     ///
     /// let set = &a | &b;
     ///
@@ -1099,8 +1111,8 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([2, 3, 4]);
     ///
     /// let set = &a & &b;
     ///
@@ -1131,8 +1143,8 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([3, 4, 5]);
     ///
     /// let set = &a ^ &b;
     ///
@@ -1163,8 +1175,8 @@
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([3, 4, 5]);
     ///
     /// let set = &a - &b;
     ///
@@ -1193,7 +1205,7 @@
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let a = HashSet::from([1, 2, 3]);
 ///
 /// let mut iter = a.iter();
 /// ```
@@ -1214,7 +1226,7 @@
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let a = HashSet::from([1, 2, 3]);
 ///
 /// let mut iter = a.into_iter();
 /// ```
@@ -1234,7 +1246,7 @@
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let mut a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let mut a = HashSet::from([1, 2, 3]);
 ///
 /// let mut drain = a.drain();
 /// ```
@@ -1255,7 +1267,7 @@
 ///
 /// use std::collections::HashSet;
 ///
-/// let mut a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let mut a = HashSet::from([1, 2, 3]);
 ///
 /// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0);
 /// ```
@@ -1278,8 +1290,8 @@
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
 ///
 /// let mut intersection = a.intersection(&b);
 /// ```
@@ -1304,8 +1316,8 @@
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
 ///
 /// let mut difference = a.difference(&b);
 /// ```
@@ -1330,8 +1342,8 @@
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
 ///
 /// let mut intersection = a.symmetric_difference(&b);
 /// ```
@@ -1353,8 +1365,8 @@
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
 ///
 /// let mut union_iter = a.union(&b);
 /// ```
@@ -1369,6 +1381,7 @@
     type IntoIter = Iter<'a, T>;
 
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     fn into_iter(self) -> Iter<'a, T> {
         self.iter()
     }
@@ -1399,6 +1412,7 @@
     /// }
     /// ```
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
     fn into_iter(self) -> IntoIter<T> {
         IntoIter { base: self.base.into_iter() }
     }
diff --git a/sgx_tstd/src/collections/mod.rs b/sgx_tstd/src/collections/mod.rs
index aca02b2..5b2dcbd 100644
--- a/sgx_tstd/src/collections/mod.rs
+++ b/sgx_tstd/src/collections/mod.rs
@@ -249,7 +249,7 @@
 //! ```
 //! use std::collections::VecDeque;
 //!
-//! let vec = vec![1, 2, 3, 4];
+//! let vec = [1, 2, 3, 4];
 //! let buf: VecDeque<_> = vec.into_iter().collect();
 //! ```
 //!
@@ -285,7 +285,7 @@
 //! not. Normally, this would require a `find` followed by an `insert`,
 //! effectively duplicating the search effort on each insertion.
 //!
-//! When a user calls `map.entry(&key)`, the map will search for the key and
+//! When a user calls `map.entry(key)`, the map will search for the key and
 //! then yield a variant of the `Entry` enum.
 //!
 //! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case
diff --git a/sgx_tstd/src/env.rs b/sgx_tstd/src/env.rs
index 1cd21da..cae3405 100644
--- a/sgx_tstd/src/env.rs
+++ b/sgx_tstd/src/env.rs
@@ -35,6 +35,11 @@
 
 /// Returns the current working directory as a [`PathBuf`].
 ///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `getcwd` function on Unix
+/// and the `GetCurrentDirectoryW` function on Windows.
+///
 /// # Errors
 ///
 /// Returns an [`Err`] if the current working directory value is invalid.
@@ -60,6 +65,11 @@
 
 /// Changes the current working directory to the specified path.
 ///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `chdir` function on Unix
+/// and the `SetCurrentDirectoryW` function on Windows.
+///
 /// Returns an [`Err`] if the operation fails.
 ///
 /// # Examples
@@ -562,28 +572,25 @@
 /// may result in "insecure temporary file" security vulnerabilities. Consider
 /// using a crate that securely creates temporary files or directories.
 ///
-/// # Unix
+/// # Platform-specific behavior
 ///
-/// Returns the value of the `TMPDIR` environment variable if it is
+/// On Unix, returns the value of the `TMPDIR` environment variable if it is
 /// set, otherwise for non-Android it returns `/tmp`. If Android, since there
 /// is no global temporary folder (it is usually allocated per-app), it returns
 /// `/data/local/tmp`.
+/// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] /
+/// [`GetTempPath`][GetTempPath], which this function uses internally.
+/// Note that, this [may change in the future][changes].
 ///
-/// # Windows
-///
-/// Returns the value of, in order, the `TMP`, `TEMP`,
-/// `USERPROFILE` environment variable if any are set and not the empty
-/// string. Otherwise, `temp_dir` returns the path of the Windows directory.
-/// This behavior is identical to that of [`GetTempPath`][msdn], which this
-/// function uses internally.
-///
-/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
+/// [changes]: io#platform-specific-behavior
+/// [GetTempPath2]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
+/// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
 ///
 /// ```no_run
 /// use std::env;
 ///
 /// fn main() {
-///     let mut dir = env::temp_dir();
+///     let dir = env::temp_dir();
 ///     println!("Temporary directory: {}", dir.display());
 /// }
 /// ```
diff --git a/sgx_tstd/src/error.rs b/sgx_tstd/src/error.rs
index 91cc72c..d795fc9 100644
--- a/sgx_tstd/src/error.rs
+++ b/sgx_tstd/src/error.rs
@@ -39,11 +39,14 @@
 use crate::cell;
 use crate::char;
 use crate::fmt::{self, Debug, Display};
+#[cfg(feature = "backtrace")]
+use crate::fmt::Write;
 use crate::mem::transmute;
 use crate::num;
 use crate::str;
 use crate::string;
 use crate::sync::Arc;
+use crate::time;
 
 use sgx_types::sgx_status_t;
 
@@ -76,7 +79,7 @@
     ///
     /// #[derive(Debug)]
     /// struct SuperError {
-    ///     side: SuperErrorSideKick,
+    ///     source: SuperErrorSideKick,
     /// }
     ///
     /// impl fmt::Display for SuperError {
@@ -87,7 +90,7 @@
     ///
     /// impl Error for SuperError {
     ///     fn source(&self) -> Option<&(dyn Error + 'static)> {
-    ///         Some(&self.side)
+    ///         Some(&self.source)
     ///     }
     /// }
     ///
@@ -103,7 +106,7 @@
     /// impl Error for SuperErrorSideKick {}
     ///
     /// fn get_super_error() -> Result<(), SuperError> {
-    ///     Err(SuperError { side: SuperErrorSideKick })
+    ///     Err(SuperError { source: SuperErrorSideKick })
     /// }
     ///
     /// fn main() {
@@ -452,6 +455,8 @@
     }
 }
 
+impl Error for char::TryFromCharError {}
+
 impl<'a, K: Debug + Ord, V: Debug> Error
     for crate::collections::btree_map::OccupiedError<'a, K, V>
 {
@@ -570,24 +575,24 @@
 
 impl Error for alloc_crate::collections::TryReserveError {}
 
-impl Error for core::time::FromSecsError {}
+impl Error for time::FromFloatSecsError {}
 
 // Copied from `any.rs`.
 impl dyn Error + 'static {
-    /// Returns `true` if the boxed type is the same as `T`
+    /// Returns `true` if the inner type is the same as `T`.
     #[inline]
     pub fn is<T: Error + 'static>(&self) -> bool {
         // Get `TypeId` of the type this function is instantiated with.
         let t = TypeId::of::<T>();
 
-        // Get `TypeId` of the type in the trait object.
-        let boxed = self.type_id(private::Internal);
+        // Get `TypeId` of the type in the trait object (`self`).
+        let concrete = self.type_id(private::Internal);
 
         // Compare both `TypeId`s on equality.
-        t == boxed
+        t == concrete
     }
 
-    /// Returns some reference to the boxed value if it is of type `T`, or
+    /// Returns some reference to the inner value if it is of type `T`, or
     /// `None` if it isn't.
     #[inline]
     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
@@ -598,7 +603,7 @@
         }
     }
 
-    /// Returns some mutable reference to the boxed value if it is of type `T`, or
+    /// Returns some mutable reference to the inner value if it is of type `T`, or
     /// `None` if it isn't.
     #[inline]
     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
@@ -763,3 +768,637 @@
         })
     }
 }
+
+/// An error reporter that print's an error and its sources.
+///
+/// Report also exposes configuration options for formatting the error chain, either entirely on a
+/// single line, or in multi-line format with each cause in the error chain on a new line.
+///
+/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the
+/// wrapped error be `Send`, `Sync`, or `'static`.
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(error_reporter)]
+/// use std::error::{Error, Report};
+/// use std::fmt;
+///
+/// #[derive(Debug)]
+/// struct SuperError {
+///     source: SuperErrorSideKick,
+/// }
+///
+/// impl fmt::Display for SuperError {
+///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+///         write!(f, "SuperError is here!")
+///     }
+/// }
+///
+/// impl Error for SuperError {
+///     fn source(&self) -> Option<&(dyn Error + 'static)> {
+///         Some(&self.source)
+///     }
+/// }
+///
+/// #[derive(Debug)]
+/// struct SuperErrorSideKick;
+///
+/// impl fmt::Display for SuperErrorSideKick {
+///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+///         write!(f, "SuperErrorSideKick is here!")
+///     }
+/// }
+///
+/// impl Error for SuperErrorSideKick {}
+///
+/// fn get_super_error() -> Result<(), SuperError> {
+///     Err(SuperError { source: SuperErrorSideKick })
+/// }
+///
+/// fn main() {
+///     match get_super_error() {
+///         Err(e) => println!("Error: {}", Report::new(e)),
+///         _ => println!("No error"),
+///     }
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!: SuperErrorSideKick is here!
+/// ```
+///
+/// ## Output consistency
+///
+/// Report prints the same output via `Display` and `Debug`, so it works well with
+/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`:
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// #     source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperError is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperError {
+/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// #         Some(&self.source)
+/// #     }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperErrorSideKick is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// #     Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// get_super_error().map_err(Report::new).unwrap();
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40
+/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+/// ```
+///
+/// ## Return from `main`
+///
+/// `Report` also implements `From` for all types that implement [`Error`], this when combined with
+/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
+/// from `main`.
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// #     source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperError is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperError {
+/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// #         Some(&self.source)
+/// #     }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperErrorSideKick is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// #     Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// fn main() -> Result<(), Report> {
+///     get_super_error()?;
+///     Ok(())
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!: SuperErrorSideKick is here!
+/// ```
+///
+/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line
+/// output format, if you want to make sure your `Report`s are pretty printed and include backtrace
+/// you will need to manually convert and enable those flags.
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// #     source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperError is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperError {
+/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// #         Some(&self.source)
+/// #     }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperErrorSideKick is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// #     Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// fn main() -> Result<(), Report> {
+///     get_super_error()
+///         .map_err(Report::from)
+///         .map_err(|r| r.pretty(true).show_backtrace(true))?;
+///     Ok(())
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!
+///
+/// Caused by:
+///       SuperErrorSideKick is here!
+/// ```
+#[cfg(feature = "backtrace")]
+pub struct Report<E = Box<dyn Error>> {
+    /// The error being reported.
+    error: E,
+    /// Whether a backtrace should be included as part of the report.
+    show_backtrace: bool,
+    /// Whether the report should be pretty-printed.
+    pretty: bool,
+}
+
+#[cfg(feature = "backtrace")]
+impl<E> Report<E>
+where
+    Report<E>: From<E>,
+{
+    /// Create a new `Report` from an input error.
+    pub fn new(error: E) -> Report<E> {
+        Self::from(error)
+    }
+}
+
+#[cfg(feature = "backtrace")]
+impl<E> Report<E> {
+    /// Enable pretty-printing the report across multiple lines.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(error_reporter)]
+    /// use std::error::Report;
+    /// # use std::error::Error;
+    /// # use std::fmt;
+    /// # #[derive(Debug)]
+    /// # struct SuperError {
+    /// #     source: SuperErrorSideKick,
+    /// # }
+    /// # impl fmt::Display for SuperError {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperError is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperError {
+    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+    /// #         Some(&self.source)
+    /// #     }
+    /// # }
+    /// # #[derive(Debug)]
+    /// # struct SuperErrorSideKick;
+    /// # impl fmt::Display for SuperErrorSideKick {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperErrorSideKick is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperErrorSideKick {}
+    ///
+    /// let error = SuperError { source: SuperErrorSideKick };
+    /// let report = Report::new(error).pretty(true);
+    /// eprintln!("Error: {:?}", report);
+    /// ```
+    ///
+    /// This example produces the following output:
+    ///
+    /// ```console
+    /// Error: SuperError is here!
+    ///
+    /// Caused by:
+    ///       SuperErrorSideKick is here!
+    /// ```
+    ///
+    /// When there are multiple source errors the causes will be numbered in order of iteration
+    /// starting from the outermost error.
+    ///
+    /// ```rust
+    /// #![feature(error_reporter)]
+    /// use std::error::Report;
+    /// # use std::error::Error;
+    /// # use std::fmt;
+    /// # #[derive(Debug)]
+    /// # struct SuperError {
+    /// #     source: SuperErrorSideKick,
+    /// # }
+    /// # impl fmt::Display for SuperError {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperError is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperError {
+    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+    /// #         Some(&self.source)
+    /// #     }
+    /// # }
+    /// # #[derive(Debug)]
+    /// # struct SuperErrorSideKick {
+    /// #     source: SuperErrorSideKickSideKick,
+    /// # }
+    /// # impl fmt::Display for SuperErrorSideKick {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperErrorSideKick is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperErrorSideKick {
+    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+    /// #         Some(&self.source)
+    /// #     }
+    /// # }
+    /// # #[derive(Debug)]
+    /// # struct SuperErrorSideKickSideKick;
+    /// # impl fmt::Display for SuperErrorSideKickSideKick {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperErrorSideKickSideKick is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperErrorSideKickSideKick { }
+    ///
+    /// let source = SuperErrorSideKickSideKick;
+    /// let source = SuperErrorSideKick { source };
+    /// let error = SuperError { source };
+    /// let report = Report::new(error).pretty(true);
+    /// eprintln!("Error: {:?}", report);
+    /// ```
+    ///
+    /// This example produces the following output:
+    ///
+    /// ```console
+    /// Error: SuperError is here!
+    ///
+    /// Caused by:
+    ///    0: SuperErrorSideKick is here!
+    ///    1: SuperErrorSideKickSideKick is here!
+    /// ```
+    pub fn pretty(mut self, pretty: bool) -> Self {
+        self.pretty = pretty;
+        self
+    }
+
+    /// Display backtrace if available when using pretty output format.
+    ///
+    /// # Examples
+    ///
+    /// **Note**: Report will search for the first `Backtrace` it can find starting from the
+    /// outermost error. In this example it will display the backtrace from the second error in the
+    /// chain, `SuperErrorSideKick`.
+    ///
+    /// ```rust
+    /// #![feature(error_reporter)]
+    /// #![feature(backtrace)]
+    /// # use std::error::Error;
+    /// # use std::fmt;
+    /// use std::error::Report;
+    /// use std::backtrace::Backtrace;
+    ///
+    /// # #[derive(Debug)]
+    /// # struct SuperError {
+    /// #     source: SuperErrorSideKick,
+    /// # }
+    /// # impl fmt::Display for SuperError {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperError is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperError {
+    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+    /// #         Some(&self.source)
+    /// #     }
+    /// # }
+    /// #[derive(Debug)]
+    /// struct SuperErrorSideKick {
+    ///     backtrace: Backtrace,
+    /// }
+    ///
+    /// impl SuperErrorSideKick {
+    ///     fn new() -> SuperErrorSideKick {
+    ///         SuperErrorSideKick { backtrace: Backtrace::force_capture() }
+    ///     }
+    /// }
+    ///
+    /// impl Error for SuperErrorSideKick {
+    ///     fn backtrace(&self) -> Option<&Backtrace> {
+    ///         Some(&self.backtrace)
+    ///     }
+    /// }
+    ///
+    /// // The rest of the example is unchanged ...
+    /// # impl fmt::Display for SuperErrorSideKick {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperErrorSideKick is here!")
+    /// #     }
+    /// # }
+    ///
+    /// let source = SuperErrorSideKick::new();
+    /// let error = SuperError { source };
+    /// let report = Report::new(error).pretty(true).show_backtrace(true);
+    /// eprintln!("Error: {:?}", report);
+    /// ```
+    ///
+    /// This example produces something similar to the following output:
+    ///
+    /// ```console
+    /// Error: SuperError is here!
+    ///
+    /// Caused by:
+    ///       SuperErrorSideKick is here!
+    ///
+    /// Stack backtrace:
+    ///    0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new
+    ///    1: rust_out::main::_doctest_main_src_error_rs_1158_0
+    ///    2: rust_out::main
+    ///    3: core::ops::function::FnOnce::call_once
+    ///    4: std::sys_common::backtrace::__rust_begin_short_backtrace
+    ///    5: std::rt::lang_start::{{closure}}
+    ///    6: std::panicking::try
+    ///    7: std::rt::lang_start_internal
+    ///    8: std::rt::lang_start
+    ///    9: main
+    ///   10: __libc_start_main
+    ///   11: _start
+    /// ```
+    pub fn show_backtrace(mut self, show_backtrace: bool) -> Self {
+        self.show_backtrace = show_backtrace;
+        self
+    }
+}
+
+#[cfg(feature = "backtrace")]
+impl<E> Report<E>
+where
+    E: Error,
+{
+    fn backtrace(&self) -> Option<&Backtrace> {
+        // have to grab the backtrace on the first error directly since that error may not be
+        // 'static
+        let backtrace = self.error.backtrace();
+        backtrace.or_else(|| {
+            self.error
+                .source()
+                .and_then(|source| source.chain().find_map(|source| source.backtrace()))
+        })
+    }
+
+    /// Format the report as a single line.
+    fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.error)?;
+
+        let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
+
+        for cause in sources {
+            write!(f, ": {}", cause)?;
+        }
+
+        Ok(())
+    }
+
+    /// Format the report as multiple lines, with each error cause on its own line.
+    fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let error = &self.error;
+
+        write!(f, "{}", error)?;
+
+        if let Some(cause) = error.source() {
+            write!(f, "\n\nCaused by:")?;
+
+            let multiple = cause.source().is_some();
+
+            for (ind, error) in cause.chain().enumerate() {
+                writeln!(f)?;
+                let mut indented = Indented { inner: f };
+                if multiple {
+                    write!(indented, "{: >4}: {}", ind, error)?;
+                } else {
+                    write!(indented, "      {}", error)?;
+                }
+            }
+        }
+
+        if self.show_backtrace {
+            let backtrace = self.backtrace();
+
+            if let Some(backtrace) = backtrace {
+                let backtrace = backtrace.to_string();
+
+                f.write_str("\n\nStack backtrace:\n")?;
+                f.write_str(backtrace.trim_end())?;
+            }
+        }
+
+        Ok(())
+    }
+}
+
+#[cfg(feature = "backtrace")]
+impl Report<Box<dyn Error>> {
+    fn backtrace(&self) -> Option<&Backtrace> {
+        // have to grab the backtrace on the first error directly since that error may not be
+        // 'static
+        let backtrace = self.error.backtrace();
+        backtrace.or_else(|| {
+            self.error
+                .source()
+                .and_then(|source| source.chain().find_map(|source| source.backtrace()))
+        })
+    }
+
+    /// Format the report as a single line.
+    fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.error)?;
+
+        let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
+
+        for cause in sources {
+            write!(f, ": {}", cause)?;
+        }
+
+        Ok(())
+    }
+
+    /// Format the report as multiple lines, with each error cause on its own line.
+    fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let error = &self.error;
+
+        write!(f, "{}", error)?;
+
+        if let Some(cause) = error.source() {
+            write!(f, "\n\nCaused by:")?;
+
+            let multiple = cause.source().is_some();
+
+            for (ind, error) in cause.chain().enumerate() {
+                writeln!(f)?;
+                let mut indented = Indented { inner: f };
+                if multiple {
+                    write!(indented, "{: >4}: {}", ind, error)?;
+                } else {
+                    write!(indented, "      {}", error)?;
+                }
+            }
+        }
+
+        if self.show_backtrace {
+            let backtrace = self.backtrace();
+
+            if let Some(backtrace) = backtrace {
+                let backtrace = backtrace.to_string();
+
+                f.write_str("\n\nStack backtrace:\n")?;
+                f.write_str(backtrace.trim_end())?;
+            }
+        }
+
+        Ok(())
+    }
+}
+
+#[cfg(feature = "backtrace")]
+impl<E> From<E> for Report<E>
+where
+    E: Error,
+{
+    fn from(error: E) -> Self {
+        Report { error, show_backtrace: false, pretty: false }
+    }
+}
+
+#[cfg(feature = "backtrace")]
+impl<'a, E> From<E> for Report<Box<dyn Error + 'a>>
+where
+    E: Error + 'a,
+{
+    fn from(error: E) -> Self {
+        let error = box error;
+        Report { error, show_backtrace: false, pretty: false }
+    }
+}
+
+#[cfg(feature = "backtrace")]
+impl<E> fmt::Display for Report<E>
+where
+    E: Error,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
+    }
+}
+
+#[cfg(feature = "backtrace")]
+impl fmt::Display for Report<Box<dyn Error>> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
+    }
+}
+
+// This type intentionally outputs the same format for `Display` and `Debug`for
+// situations where you unwrap a `Report` or return it from main.
+#[cfg(feature = "backtrace")]
+impl<E> fmt::Debug for Report<E>
+where
+    Report<E>: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
+/// Wrapper type for indenting the inner source.
+#[cfg(feature = "backtrace")]
+struct Indented<'a, D> {
+    inner: &'a mut D,
+}
+
+#[cfg(feature = "backtrace")]
+impl<T> Write for Indented<'_, T>
+where
+    T: Write,
+{
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        for (i, line) in s.split('\n').enumerate() {
+            if i > 0 {
+                self.inner.write_char('\n')?;
+                self.inner.write_str("      ")?;
+            }
+
+            self.inner.write_str(line)?;
+        }
+
+        Ok(())
+    }
+}
diff --git a/sgx_tstd/src/ffi/c_str.rs b/sgx_tstd/src/ffi/c_str.rs
index 1e542ce..6ecdabd 100644
--- a/sgx_tstd/src/ffi/c_str.rs
+++ b/sgx_tstd/src/ffi/c_str.rs
@@ -30,7 +30,7 @@
 impl From<NulError> for io::Error {
     /// Converts a [`NulError`] into a [`io::Error`].
     fn from(_: NulError) -> io::Error {
-        io::Error::new_const(io::ErrorKind::InvalidInput, &"data provided contains a nul byte")
+        io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
     }
 }
 
diff --git a/sgx_tstd/src/ffi/mod.rs b/sgx_tstd/src/ffi/mod.rs
index b93c5f4..1c6152a 100644
--- a/sgx_tstd/src/ffi/mod.rs
+++ b/sgx_tstd/src/ffi/mod.rs
@@ -98,9 +98,9 @@
 //! [`OsStr`] and Rust strings work similarly to those for [`CString`]
 //! and [`CStr`].
 //!
-//! * [`OsString`] represents an owned string in whatever
-//! representation the operating system prefers. In the Rust standard
-//! library, various APIs that transfer strings to/from the operating
+//! * [`OsString`] losslessly represents an owned platform string. However, this
+//! representation is not necessarily in a form native to the platform.
+//! In the Rust standard library, various APIs that transfer strings to/from the operating
 //! system use [`OsString`] instead of plain strings. For example,
 //! [`env::var_os()`] is used to query environment variables; it
 //! returns an <code>[Option]<[OsString]></code>. If the environment variable
@@ -109,9 +109,9 @@
 //! your code can detect errors in case the environment variable did
 //! not in fact contain valid Unicode data.
 //!
-//! * [`OsStr`] represents a borrowed reference to a string in a
-//! format that can be passed to the operating system. It can be
-//! converted into a UTF-8 Rust string slice in a similar way to
+//! * [`OsStr`] losslessly represents a borrowed reference to a platform string.
+//! However, this representation is not necessarily in a form native to the platform.
+//! It can be converted into a UTF-8 Rust string slice in a similar way to
 //! [`OsString`].
 //!
 //! # Conversions
@@ -130,16 +130,19 @@
 //!
 //! ## On Windows
 //!
+//! An [`OsStr`] can be losslessly converted to a native Windows string. And
+//! a native Windows string can be losslessly converted to an [`OsString`].
+//!
 //! On Windows, [`OsStr`] implements the
 //! <code>std::os::windows::ffi::[OsStrExt][windows.OsStrExt]</code> trait,
 //! which provides an [`encode_wide`] method. This provides an
-//! iterator that can be [`collect`]ed into a vector of [`u16`].
+//! iterator that can be [`collect`]ed into a vector of [`u16`]. After a nul
+//! characters is appended, this is the same as a native Windows string.
 //!
 //! Additionally, on Windows [`OsString`] implements the
 //! <code>std::os::windows:ffi::[OsStringExt][windows.OsStringExt]</code>
-//! trait, which provides a [`from_wide`] method. The result of this
-//! method is an [`OsString`] which can be round-tripped to a Windows
-//! string losslessly.
+//! trait, which provides a [`from_wide`] method to convert a native Windows
+//! string (without the terminating nul character) to an [`OsString`].
 //!
 //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
 //! [Unicode code point]: https://www.unicode.org/glossary/#code_point
diff --git a/sgx_tstd/src/ffi/os_str.rs b/sgx_tstd/src/ffi/os_str.rs
index e11c6aa..8dc3d03 100644
--- a/sgx_tstd/src/ffi/os_str.rs
+++ b/sgx_tstd/src/ffi/os_str.rs
@@ -19,6 +19,7 @@
 
 use crate::borrow::{Borrow, Cow};
 use crate::cmp;
+use crate::collections::TryReserveError;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::iter::{Extend, FromIterator};
@@ -269,6 +270,42 @@
         self.inner.reserve(additional)
     }
 
+    /// Tries to reserve capacity for at least `additional` more length units
+    /// in the given `OsString`. The string may reserve more space to avoid
+    /// frequent reallocations. After calling `try_reserve`, capacity will be
+    /// greater than or equal to `self.len() + additional`. Does nothing if
+    /// capacity is already sufficient.
+    ///
+    /// # Errors
+    ///
+    /// If the capacity overflows, or the allocator reports a failure, then an error
+    /// is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(try_reserve_2)]
+    /// use std::ffi::{OsStr, OsString};
+    /// use std::collections::TryReserveError;
+    ///
+    /// fn process_data(data: &str) -> Result<OsString, TryReserveError> {
+    ///     let mut s = OsString::new();
+    ///
+    ///     // Pre-reserve the memory, exiting if we can't
+    ///     s.try_reserve(OsStr::new(data).len())?;
+    ///
+    ///     // Now we know this can't OOM in the middle of our complex work
+    ///     s.push(data);
+    ///
+    ///     Ok(s)
+    /// }
+    /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?");
+    /// ```
+    #[inline]
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.inner.try_reserve(additional)
+    }
+
     /// Reserves the minimum capacity for exactly `additional` more capacity to
     /// be inserted in the given `OsString`. Does nothing if the capacity is
     /// already sufficient.
@@ -293,6 +330,48 @@
         self.inner.reserve_exact(additional)
     }
 
+    /// Tries to reserve the minimum capacity for exactly `additional`
+    /// more length units in the given `OsString`. After calling
+    /// `try_reserve_exact`, capacity will be greater than or equal to
+    /// `self.len() + additional` if it returns `Ok(())`.
+    /// Does nothing if the capacity is already sufficient.
+    ///
+    /// Note that the allocator may give the `OsString` more space than it
+    /// requests. Therefore, capacity can not be relied upon to be precisely
+    /// minimal. Prefer [`try_reserve`] if future insertions are expected.
+    ///
+    /// [`try_reserve`]: OsString::try_reserve
+    ///
+    /// # Errors
+    ///
+    /// If the capacity overflows, or the allocator reports a failure, then an error
+    /// is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(try_reserve_2)]
+    /// use std::ffi::{OsStr, OsString};
+    /// use std::collections::TryReserveError;
+    ///
+    /// fn process_data(data: &str) -> Result<OsString, TryReserveError> {
+    ///     let mut s = OsString::new();
+    ///
+    ///     // Pre-reserve the memory, exiting if we can't
+    ///     s.try_reserve_exact(OsStr::new(data).len())?;
+    ///
+    ///     // Now we know this can't OOM in the middle of our complex work
+    ///     s.push(data);
+    ///
+    ///     Ok(s)
+    /// }
+    /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?");
+    /// ```
+    #[inline]
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.inner.try_reserve_exact(additional)
+    }
+
     /// Shrinks the capacity of the `OsString` to match its length.
     ///
     /// # Examples
@@ -369,6 +448,8 @@
 }
 
 impl<T: ?Sized + AsRef<OsStr>> From<&T> for OsString {
+    /// Copies any value implementing <code>[AsRef]&lt;[OsStr]&gt;</code>
+    /// into a newly allocated [`OsString`].
     fn from(s: &T) -> OsString {
         s.as_ref().to_os_string()
     }
@@ -828,6 +909,7 @@
 }
 
 impl From<&OsStr> for Box<OsStr> {
+    /// Copies the string into a newly allocated <code>[Box]&lt;[OsStr]&gt;</code>.
     #[inline]
     fn from(s: &OsStr) -> Box<OsStr> {
         let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
@@ -836,6 +918,8 @@
 }
 
 impl From<Cow<'_, OsStr>> for Box<OsStr> {
+    /// Converts a `Cow<'a, OsStr>` into a <code>[Box]&lt;[OsStr]&gt;</code>,
+    /// by copying the contents if they are borrowed.
     #[inline]
     fn from(cow: Cow<'_, OsStr>) -> Box<OsStr> {
         match cow {
@@ -870,7 +954,8 @@
 }
 
 impl From<OsString> for Arc<OsStr> {
-    /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> without copying or allocating.
+    /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> by moving the [`OsString`]
+    /// data into a new [`Arc`] buffer.
     #[inline]
     fn from(s: OsString) -> Arc<OsStr> {
         let arc = s.inner.into_arc();
@@ -879,6 +964,7 @@
 }
 
 impl From<&OsStr> for Arc<OsStr> {
+    /// Copies the string into a newly allocated <code>[Arc]&lt;[OsStr]&gt;</code>.
     #[inline]
     fn from(s: &OsStr) -> Arc<OsStr> {
         let arc = s.inner.into_arc();
@@ -887,7 +973,8 @@
 }
 
 impl From<OsString> for Rc<OsStr> {
-    /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> without copying or allocating.
+    /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> by moving the [`OsString`]
+    /// data into a new [`Rc`] buffer.
     #[inline]
     fn from(s: OsString) -> Rc<OsStr> {
         let rc = s.inner.into_rc();
@@ -896,6 +983,7 @@
 }
 
 impl From<&OsStr> for Rc<OsStr> {
+    /// Copies the string into a newly allocated <code>[Rc]&lt;[OsStr]&gt;</code>.
     #[inline]
     fn from(s: &OsStr) -> Rc<OsStr> {
         let rc = s.inner.into_rc();
@@ -904,6 +992,7 @@
 }
 
 impl<'a> From<OsString> for Cow<'a, OsStr> {
+    /// Moves the string into a [`Cow::Owned`].
     #[inline]
     fn from(s: OsString) -> Cow<'a, OsStr> {
         Cow::Owned(s)
@@ -911,6 +1000,7 @@
 }
 
 impl<'a> From<&'a OsStr> for Cow<'a, OsStr> {
+    /// Converts the string reference into a [`Cow::Borrowed`].
     #[inline]
     fn from(s: &'a OsStr) -> Cow<'a, OsStr> {
         Cow::Borrowed(s)
@@ -918,6 +1008,7 @@
 }
 
 impl<'a> From<&'a OsString> for Cow<'a, OsStr> {
+    /// Converts the string reference into a [`Cow::Borrowed`].
     #[inline]
     fn from(s: &'a OsString) -> Cow<'a, OsStr> {
         Cow::Borrowed(s.as_os_str())
@@ -925,6 +1016,8 @@
 }
 
 impl<'a> From<Cow<'a, OsStr>> for OsString {
+    /// Converts a `Cow<'a, OsStr>` into an [`OsString`],
+    /// by copying the contents if they are borrowed.
     #[inline]
     fn from(s: Cow<'a, OsStr>) -> Self {
         s.into_owned()
diff --git a/sgx_tstd/src/fs.rs b/sgx_tstd/src/fs.rs
index 1f467fc..cbac797 100644
--- a/sgx_tstd/src/fs.rs
+++ b/sgx_tstd/src/fs.rs
@@ -20,7 +20,7 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 use crate::ffi::OsString;
 use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
+use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write};
 use crate::path::{Path, PathBuf};
 use crate::sys::fs as fs_imp;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@@ -96,6 +96,7 @@
 ///
 /// [`BufReader<R>`]: io::BufReader
 /// [`sync_all`]: File::sync_all
+#[cfg_attr(not(test), rustc_diagnostic_item = "File")]
 pub struct File {
     inner: fs_imp::File,
 }
@@ -351,9 +352,10 @@
     /// open or create a file with specific options if `open()` or `create()`
     /// are not appropriate.
     ///
-    /// It is equivalent to `OpenOptions::new()` but allows you to write more
-    /// readable code. Instead of `OpenOptions::new().read(true).open("foo.txt")`
-    /// you can write `File::with_options().read(true).open("foo.txt")`. This
+    /// It is equivalent to `OpenOptions::new()`, but allows you to write more
+    /// readable code. Instead of
+    /// `OpenOptions::new().append(true).open("example.log")`,
+    /// you can write `File::options().append(true).open("example.log")`. This
     /// also avoids the need to import `OpenOptions`.
     ///
     /// See the [`OpenOptions::new`] function for more details.
@@ -361,16 +363,15 @@
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(with_options)]
     /// use std::fs::File;
     ///
     /// fn main() -> std::io::Result<()> {
-    ///     let mut f = File::with_options().read(true).open("foo.txt")?;
+    ///     let mut f = File::options().append(true).open("example.log")?;
     ///     Ok(())
     /// }
     /// ```
     #[must_use]
-    pub fn with_options() -> OpenOptions {
+    pub fn options() -> OpenOptions {
         OpenOptions::new()
     }
 
@@ -610,15 +611,13 @@
         self.inner.read_vectored(bufs)
     }
 
-    #[inline]
-    fn is_read_vectored(&self) -> bool {
-        self.inner.is_read_vectored()
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        unsafe { Initializer::nop() }
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
     }
 
     // Reserves space in the buffer based on the file size when available.
@@ -663,6 +662,10 @@
         self.inner.read(buf)
     }
 
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.inner.read_vectored(bufs)
     }
@@ -672,12 +675,6 @@
         self.inner.is_read_vectored()
     }
 
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        unsafe { Initializer::nop() }
-    }
-
     // Reserves space in the buffer based on the file size when available.
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         buf.reserve(buffer_capacity_required(self));
@@ -1021,14 +1018,13 @@
     ///
     #[cfg_attr(unix, doc = "```no_run")]
     #[cfg_attr(not(unix), doc = "```ignore")]
-    /// #![feature(is_symlink)]
     /// use std::fs;
     /// use std::path::Path;
     /// use std::os::unix::fs::symlink;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let link_path = Path::new("link");
-    ///     symlink("/origin_does_not_exists/", link_path)?;
+    ///     symlink("/origin_does_not_exist/", link_path)?;
     ///
     ///     let metadata = fs::symlink_metadata(link_path)?;
     ///
@@ -1985,13 +1981,17 @@
 ///
 /// # Platform-specific behavior
 ///
-/// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix
-/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
-/// on Windows.
-/// Note that, this [may change in the future][changes].
+/// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions
+/// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`,
+/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile` functions on
+/// Windows. Note that, this [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
 ///
+/// On macOS before version 10.10 and REDOX this function is not protected against time-of-check to
+/// time-of-use (TOCTOU) race conditions, and should not be used in security-sensitive code on
+/// those platforms. All other platforms are protected.
+///
 /// # Errors
 ///
 /// See [`fs::remove_file`] and [`fs::remove_dir`].
@@ -2009,7 +2009,6 @@
 ///     Ok(())
 /// }
 /// ```
-#[doc(alias = "delete")]
 pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
     fs_imp::remove_dir_all(path.as_ref())
 }
@@ -2197,9 +2196,9 @@
         match path.parent() {
             Some(p) => self.create_dir_all(p)?,
             None => {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::Uncategorized,
-                    &"failed to create whole tree",
+                    "failed to create whole tree",
                 ));
             }
         }
@@ -2222,7 +2221,7 @@
 /// This function will traverse symbolic links to query information about the
 /// destination file. In case of broken symbolic links this will return `Ok(false)`.
 ///
-/// As opposed to the `exists()` method, this one doesn't silently ignore errors
+/// As opposed to the [`Path::exists`] method, this one doesn't silently ignore errors
 /// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
 /// denied on some of the parent directories.)
 ///
@@ -2235,6 +2234,8 @@
 /// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt"));
 /// assert!(fs::try_exists("/root/secret_file.txt").is_err());
 /// ```
+///
+/// [`Path::exists`]: crate::path::Path::exists
 // FIXME: stabilization should modify documentation of `exists()` to recommend this method
 // instead.
 #[inline]
diff --git a/sgx_tstd/src/io/buffered/bufreader.rs b/sgx_tstd/src/io/buffered/bufreader.rs
index 1f0e5fb..cd0795f 100644
--- a/sgx_tstd/src/io/buffered/bufreader.rs
+++ b/sgx_tstd/src/io/buffered/bufreader.rs
@@ -18,8 +18,9 @@
 use crate::cmp;
 use crate::fmt;
 use crate::io::{
-    self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
+    self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
 };
+use crate::mem::MaybeUninit;
 
 /// The `BufReader<R>` struct adds buffering to any reader.
 ///
@@ -63,9 +64,10 @@
 /// ```
 pub struct BufReader<R> {
     inner: R,
-    buf: Box<[u8]>,
+    buf: Box<[MaybeUninit<u8>]>,
     pos: usize,
     cap: usize,
+    init: usize,
 }
 
 impl<R: Read> BufReader<R> {
@@ -105,11 +107,8 @@
     /// }
     /// ```
     pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
-        unsafe {
-            let mut buf = Box::new_uninit_slice(capacity).assume_init();
-            inner.initializer().initialize(&mut buf);
-            BufReader { inner, buf, pos: 0, cap: 0 }
-        }
+        let buf = Box::new_uninit_slice(capacity);
+        BufReader { inner, buf, pos: 0, cap: 0, init: 0 }
     }
 }
 
@@ -182,7 +181,8 @@
     /// }
     /// ```
     pub fn buffer(&self) -> &[u8] {
-        &self.buf[self.pos..self.cap]
+        // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init
+        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) }
     }
 
     /// Returns the number of bytes the internal buffer can hold at once.
@@ -243,6 +243,7 @@
     /// the buffer will not be flushed, allowing for more efficient seeks.
     /// This method does not return the location of the underlying reader, so the caller
     /// must track this information themselves if it is required.
+    #[allow(clippy::collapsible_else_if)]
     pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
         let pos = self.pos as u64;
         if offset < 0 {
@@ -278,6 +279,25 @@
         Ok(nread)
     }
 
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        // If we don't have any buffered data and we're doing a massive read
+        // (larger than our internal buffer), bypass our internal buffer
+        // entirely.
+        if self.pos == self.cap && buf.remaining() >= self.buf.len() {
+            self.discard_buffer();
+            return self.inner.read_buf(buf);
+        }
+
+        let prev = buf.filled_len();
+
+        let mut rem = self.fill_buf()?;
+        rem.read_buf(buf)?;
+
+        self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf
+
+        Ok(())
+    }
+
     // Small read_exacts from a BufReader are extremely common when used with a deserializer.
     // The default implementation calls read in a loop, which results in surprisingly poor code
     // generation for the common path where the buffer has enough bytes to fill the passed-in
@@ -310,16 +330,11 @@
         self.inner.is_read_vectored()
     }
 
-    // we can't skip unconditionally because of the large buffer case in read.
-    unsafe fn initializer(&self) -> Initializer {
-        self.inner.initializer()
-    }
-
     // The inner reader might have an optimized `read_to_end`. Drain our buffer and then
     // delegate to the inner implementation.
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         let nread = self.cap - self.pos;
-        buf.extend_from_slice(&self.buf[self.pos..self.cap]);
+        buf.extend_from_slice(self.buffer());
         self.discard_buffer();
         Ok(nread + self.inner.read_to_end(buf)?)
     }
@@ -350,9 +365,9 @@
             let mut bytes = Vec::new();
             self.read_to_end(&mut bytes)?;
             let string = crate::str::from_utf8(&bytes).map_err(|_| {
-                io::Error::new_const(
+                io::const_io_error!(
                     io::ErrorKind::InvalidData,
-                    &"stream did not contain valid UTF-8",
+                    "stream did not contain valid UTF-8",
                 )
             })?;
             *buf += string;
@@ -369,10 +384,23 @@
         // to tell the compiler that the pos..cap slice is always valid.
         if self.pos >= self.cap {
             debug_assert!(self.pos == self.cap);
-            self.cap = self.inner.read(&mut self.buf)?;
+
+            let mut readbuf = ReadBuf::uninit(&mut self.buf);
+
+            // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()`
+            // from the last time this function was called
+            unsafe {
+                readbuf.assume_init(self.init);
+            }
+
+            self.inner.read_buf(&mut readbuf)?;
+
+            self.cap = readbuf.filled_len();
+            self.init = readbuf.initialized_len();
+
             self.pos = 0;
         }
-        Ok(&self.buf[self.pos..self.cap])
+        Ok(self.buffer())
     }
 
     fn consume(&mut self, amt: usize) {
diff --git a/sgx_tstd/src/io/buffered/bufwriter.rs b/sgx_tstd/src/io/buffered/bufwriter.rs
index c9805f8..3897735 100644
--- a/sgx_tstd/src/io/buffered/bufwriter.rs
+++ b/sgx_tstd/src/io/buffered/bufwriter.rs
@@ -18,7 +18,7 @@
 use crate::error;
 use crate::fmt;
 use crate::io::{
-    self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
+    self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
 };
 use crate::mem;
 use crate::ptr;
@@ -182,9 +182,9 @@
 
             match r {
                 Ok(0) => {
-                    return Err(Error::new_const(
+                    return Err(io::const_io_error!(
                         ErrorKind::WriteZero,
-                        &"failed to write the buffered data",
+                        "failed to write the buffered data",
                     ));
                 }
                 Ok(n) => guard.consume(n),
diff --git a/sgx_tstd/src/io/buffered/mod.rs b/sgx_tstd/src/io/buffered/mod.rs
index c01cb1c..f854b53 100644
--- a/sgx_tstd/src/io/buffered/mod.rs
+++ b/sgx_tstd/src/io/buffered/mod.rs
@@ -26,12 +26,11 @@
 use crate::fmt;
 use crate::io::Error;
 
-pub use bufreader::BufReader;
-pub use bufwriter::BufWriter;
-pub use bufwriter::WriterPanicked;
-pub use linewriter::LineWriter;
+pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter};
 use linewritershim::LineWriterShim;
 
+pub use bufwriter::WriterPanicked;
+
 /// An error returned by [`BufWriter::into_inner`] which combines an error that
 /// happened while writing out the buffer, and the buffered writer object
 /// which may be used to recover from the condition.
diff --git a/sgx_tstd/src/io/copy.rs b/sgx_tstd/src/io/copy.rs
index f3f0a93..b5aa5f4 100644
--- a/sgx_tstd/src/io/copy.rs
+++ b/sgx_tstd/src/io/copy.rs
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License..
 
-use super::{BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE};
 use crate::mem::MaybeUninit;
 
 /// Copies the entire contents of a reader into a writer.
@@ -61,6 +61,16 @@
     R: Read,
     W: Write,
 {
+    generic_copy(reader, writer)
+}
+
+/// The userspace read-write-loop implementation of `io::copy` that is used when
+/// OS-specific specializations for copy offloading are not available or not applicable.
+pub(crate) fn generic_copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>
+where
+    R: Read,
+    W: Write,
+{
     BufferedCopySpec::copy_to(reader, writer)
 }
 
@@ -82,33 +92,30 @@
             return stack_buffer_copy(reader, writer);
         }
 
-        // FIXME: #42788
-        //
-        //   - This creates a (mut) reference to a slice of
-        //     _uninitialized_ integers, which is **undefined behavior**
-        //
-        //   - Only the standard library gets to soundly "ignore" this,
-        //     based on its privileged knowledge of unstable rustc
-        //     internals;
-        unsafe {
-            let spare_cap = writer.buffer_mut().spare_capacity_mut();
-            reader.initializer().initialize(MaybeUninit::slice_assume_init_mut(spare_cap));
-        }
-
         let mut len = 0;
+        let mut init = 0;
 
         loop {
             let buf = writer.buffer_mut();
-            let spare_cap = buf.spare_capacity_mut();
+            let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
 
-            if spare_cap.len() >= DEFAULT_BUF_SIZE {
-                match reader.read(unsafe { MaybeUninit::slice_assume_init_mut(spare_cap) }) {
-                    Ok(0) => return Ok(len), // EOF reached
-                    Ok(bytes_read) => {
-                        assert!(bytes_read <= spare_cap.len());
-                        // SAFETY: The initializer contract guarantees that either it or `read`
-                        // will have initialized these bytes. And we just checked that the number
-                        // of bytes is within the buffer capacity.
+            // SAFETY: init is either 0 or the initialized_len of the previous iteration
+            unsafe {
+                read_buf.assume_init(init);
+            }
+
+            if read_buf.capacity() >= DEFAULT_BUF_SIZE {
+                match reader.read_buf(&mut read_buf) {
+                    Ok(()) => {
+                        let bytes_read = read_buf.filled_len();
+
+                        if bytes_read == 0 {
+                            return Ok(len);
+                        }
+
+                        init = read_buf.initialized_len() - bytes_read;
+
+                        // SAFETY: ReadBuf guarantees all of its filled bytes are init
                         unsafe { buf.set_len(buf.len() + bytes_read) };
                         len += bytes_read as u64;
                         // Read again if the buffer still has enough capacity, as BufWriter itself would do
@@ -129,28 +136,26 @@
     reader: &mut R,
     writer: &mut W,
 ) -> Result<u64> {
-    let mut buf = MaybeUninit::<[u8; DEFAULT_BUF_SIZE]>::uninit();
-    // FIXME: #42788
-    //
-    //   - This creates a (mut) reference to a slice of
-    //     _uninitialized_ integers, which is **undefined behavior**
-    //
-    //   - Only the standard library gets to soundly "ignore" this,
-    //     based on its privileged knowledge of unstable rustc
-    //     internals;
-    unsafe {
-        reader.initializer().initialize(buf.assume_init_mut());
-    }
+    let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
+    let mut buf = ReadBuf::uninit(&mut buf);
 
-    let mut written = 0;
+    let mut len = 0;
+
     loop {
-        let len = match reader.read(unsafe { buf.assume_init_mut() }) {
-            Ok(0) => return Ok(written),
-            Ok(len) => len,
-            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+        match reader.read_buf(&mut buf) {
+            Ok(()) => {}
+            Err(e) if e.kind() == ErrorKind::Interrupted => continue,
             Err(e) => return Err(e),
         };
-        writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?;
-        written += len as u64;
+
+        if buf.filled().is_empty() {
+            break;
+        }
+
+        len += buf.filled().len() as u64;
+        writer.write_all(buf.filled())?;
+        buf.clear();
     }
+
+    Ok(len)
 }
diff --git a/sgx_tstd/src/io/cursor.rs b/sgx_tstd/src/io/cursor.rs
index 01ef7bb..be40a32 100644
--- a/sgx_tstd/src/io/cursor.rs
+++ b/sgx_tstd/src/io/cursor.rs
@@ -18,7 +18,7 @@
 use crate::io::prelude::*;
 
 use crate::cmp;
-use crate::io::{self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 
 use core::convert::TryInto;
 
@@ -297,9 +297,9 @@
                 self.pos = n;
                 Ok(self.pos)
             }
-            None => Err(Error::new_const(
+            None => Err(io::const_io_error!(
                 ErrorKind::InvalidInput,
-                &"invalid seek to a negative or overflowing position",
+                "invalid seek to a negative or overflowing position",
             )),
         }
     }
@@ -323,6 +323,16 @@
         Ok(n)
     }
 
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        let prev_filled = buf.filled_len();
+
+        Read::read_buf(&mut self.fill_buf()?, buf)?;
+
+        self.pos += (buf.filled_len() - prev_filled) as u64;
+
+        Ok(())
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let mut nread = 0;
         for buf in bufs {
@@ -345,11 +355,6 @@
         self.pos += n as u64;
         Ok(())
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl<T> BufRead for Cursor<T>
@@ -393,9 +398,9 @@
 // Resizing write implementation
 fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
     let pos: usize = (*pos_mut).try_into().map_err(|_| {
-        Error::new_const(
+        io::const_io_error!(
             ErrorKind::InvalidInput,
-            &"cursor position exceeds maximum possible vector length",
+            "cursor position exceeds maximum possible vector length",
         )
     })?;
     // Make sure the internal buffer is as least as big as where we
diff --git a/sgx_tstd/src/io/error.rs b/sgx_tstd/src/io/error.rs
index 11b7c0b..6de63fb 100644
--- a/sgx_tstd/src/io/error.rs
+++ b/sgx_tstd/src/io/error.rs
@@ -15,6 +15,9 @@
 // specific language governing permissions and limitations
 // under the License..
 
+mod repr_unpacked;
+use repr_unpacked::Repr;
+
 use crate::convert::From;
 use crate::error;
 use crate::fmt;
@@ -79,16 +82,59 @@
     }
 }
 
-enum Repr {
+// Only derive debug in tests, to make sure it
+// doesn't accidentally get printed.
+#[cfg_attr(feature = "unit_test", derive(Debug))]
+enum ErrorData<C> {
     Os(i32),
     Simple(ErrorKind),
-    // &str is a fat pointer, but &&str is a thin pointer.
-    SimpleMessage(ErrorKind, &'static &'static str),
-    Custom(Box<Custom>),
+    SimpleMessage(&'static SimpleMessage),
+    Custom(C),
     SgxStatus(sgx_status_t),
 }
 
+// `#[repr(align(4))]` is probably redundant, it should have that value or
+// higher already. We include it just because repr_bitpacked.rs's encoding
+// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
+// alignment required by the struct, only increase it).
+//
+// If we add more variants to ErrorData, this can be increased to 8, but it
+// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or
+// whatever cfg we're using to enable the `repr_bitpacked` code, since only the
+// that version needs the alignment, and 8 is higher than the alignment we'll
+// have on 32 bit platforms.
+//
+// (For the sake of being explicit: the alignment requirement here only matters
+// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't
+// matter at all)
+#[repr(align(4))]
 #[derive(Debug)]
+pub(crate) struct SimpleMessage {
+    kind: ErrorKind,
+    message: &'static str,
+}
+
+impl SimpleMessage {
+    pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self {
+        Self { kind, message }
+    }
+}
+
+/// Create and return an `io::Error` for a given `ErrorKind` and constant
+/// message. This doesn't allocate.
+pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) {
+    $crate::io::error::Error::from_static_message({
+        const MESSAGE_DATA: $crate::io::error::SimpleMessage =
+            $crate::io::error::SimpleMessage::new($kind, $message);
+        &MESSAGE_DATA
+    })
+}
+
+// As with `SimpleMessage`: `#[repr(align(4))]` here is just because
+// repr_bitpacked's encoding requires it. In practice it almost certainly be
+// already be this high or higher.
+#[derive(Debug)]
+#[repr(align(4))]
 struct Custom {
     kind: ErrorKind,
     error: Box<dyn error::Error + Send + Sync>,
@@ -223,11 +269,10 @@
     ///
     /// The filesystem does not support making so many hardlinks to the same file.
     TooManyLinks,
-    /// Filename too long.
+    /// A filename was invalid.
     ///
-    /// The limit might be from the underlying filesystem or API, or an administratively imposed
-    /// resource limit.
-    FilenameTooLong,
+    /// This error can also cause if it exceeded the filename length limit.
+    InvalidFilename,
     /// Program argument list too long.
     ///
     /// When trying to run an external program, a system or process limit on the size of the
@@ -304,12 +349,12 @@
             DirectoryNotEmpty => "directory not empty",
             ExecutableFileBusy => "executable file busy",
             FileTooLarge => "file too large",
-            FilenameTooLong => "filename too long",
             FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)",
             FilesystemQuotaExceeded => "filesystem quota exceeded",
             HostUnreachable => "host unreachable",
             Interrupted => "operation interrupted",
             InvalidData => "invalid data",
+            InvalidFilename => "invalid filename",
             InvalidInput => "invalid input parameter",
             IsADirectory => "is a directory",
             NetworkDown => "network down",
@@ -332,17 +377,32 @@
             Unsupported => "unsupported",
             WouldBlock => "operation would block",
             WriteZero => "write zero",
-            ErrorKind::SgxError => "Sgx error status",
+            SgxError => "Sgx error status",
         }
     }
 }
 
+impl fmt::Display for ErrorKind {
+    /// Shows a human-readable description of the `ErrorKind`.
+    ///
+    /// This is similar to `impl Display for Error`, but doesn't require first converting to Error.
+    ///
+    /// # Examples
+    /// ```
+    /// use std::io::ErrorKind;
+    /// assert_eq!("entity not found", ErrorKind::NotFound.to_string());
+    /// ```
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.write_str(self.as_str())
+    }
+}
+
 /// Intended for use for errors not exposed to the user, where allocating onto
 /// the heap (for normal construction via Error::new) is too costly.
 impl From<ErrorKind> for Error {
     /// Converts an [`ErrorKind`] into an [`Error`].
     ///
-    /// This conversion allocates a new error with a simple representation of error kind.
+    /// This conversion creates a new error with a simple representation of error kind.
     ///
     /// # Examples
     ///
@@ -355,14 +415,14 @@
     /// ```
     #[inline]
     fn from(kind: ErrorKind) -> Error {
-        Error { repr: Repr::Simple(kind) }
+        Error { repr: Repr::new_simple(kind) }
     }
 }
 
 impl From<sgx_status_t> for Error {
     #[inline]
     fn from(status: sgx_status_t) -> Error {
-        Error { repr: Repr::SgxStatus(status) }
+        Error { repr: Repr::new_sgx(status) }
     }
 }
 
@@ -374,6 +434,9 @@
     /// originate from the OS itself. The `error` argument is an arbitrary
     /// payload which will be contained in this [`Error`].
     ///
+    /// If no extra payload is required, use the `From` conversion from
+    /// `ErrorKind`.
+    ///
     /// # Examples
     ///
     /// ```
@@ -384,6 +447,9 @@
     ///
     /// // errors can also be created from other errors
     /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
+    ///
+    /// // creating an error without payload
+    /// let eof_error = Error::from(ErrorKind::UnexpectedEof);
     /// ```
     pub fn new<E>(kind: ErrorKind, error: E) -> Error
     where
@@ -392,21 +458,49 @@
         Self::_new(kind, error.into())
     }
 
-    fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
-        Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
+    /// Creates a new I/O error from an arbitrary error payload.
+    ///
+    /// This function is used to generically create I/O errors which do not
+    /// originate from the OS itself. It is a shortcut for [`Error::new`]
+    /// with [`ErrorKind::Other`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(io_error_other)]
+    ///
+    /// use std::io::Error;
+    ///
+    /// // errors can be created from strings
+    /// let custom_error = Error::other("oh no!");
+    ///
+    /// // errors can also be created from other errors
+    /// let custom_error2 = Error::other(custom_error);
+    /// ```
+    pub fn other<E>(error: E) -> Error
+    where
+        E: Into<Box<dyn error::Error + Send + Sync>>,
+    {
+        Self::_new(ErrorKind::Other, error.into())
     }
 
-    /// Creates a new I/O error from a known kind of error as well as a
-    /// constant message.
+    fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
+        Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) }
+    }
+
+    /// Creates a new I/O error from a known kind of error as well as a constant
+    /// message.
     ///
     /// This function does not allocate.
     ///
-    /// This function should maybe change to
-    /// `new_const<const MSG: &'static str>(kind: ErrorKind)`
-    /// in the future, when const generics allow that.
+    /// You should not use this directly, and instead use the `const_io_error!`
+    /// macro: `io::const_io_error!(ErrorKind::Something, "some_message")`.
+    ///
+    /// This function should maybe change to `from_static_message<const MSG: &'static
+    /// str>(kind: ErrorKind)` in the future, when const generics allow that.
     #[inline]
-    pub(crate) const fn new_const(kind: ErrorKind, message: &'static &'static str) -> Error {
-        Self { repr: Repr::SimpleMessage(kind, message) }
+    pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error {
+        Self { repr: Repr::new_simple_message(msg) }
     }
 
     /// Returns an error representing the last OS error which occurred.
@@ -415,12 +509,18 @@
     /// `GetLastError` on Windows) and will return a corresponding instance of
     /// [`Error`] for the error code.
     ///
+    /// This should be called immediately after a call to a platform function,
+    /// otherwise the state of the error value is indeterminate. In particular,
+    /// other standard library functions may call platform functions that may
+    /// (or may not) reset the error value even if they succeed.
+    ///
     /// # Examples
     ///
     /// ```
     /// use std::io::Error;
     ///
-    /// println!("last OS error: {:?}", Error::last_os_error());
+    /// let os_error = Error::last_os_error();
+    /// println!("last OS error: {:?}", os_error);
     /// ```
     #[must_use]
     #[inline]
@@ -456,7 +556,7 @@
     #[must_use]
     #[inline]
     pub fn from_raw_os_error(code: i32) -> Error {
-        Error { repr: Repr::Os(code) }
+        Error { repr: Repr::new_os(code) }
     }
 
     /// Returns the OS error that this error represents (if any).
@@ -491,18 +591,18 @@
     #[must_use]
     #[inline]
     pub fn raw_os_error(&self) -> Option<i32> {
-        match self.repr {
-            Repr::Os(i) => Some(i),
-            Repr::Custom(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::SgxStatus(..) => None,
+        match self.repr.data() {
+            ErrorData::Os(i) => Some(i),
+            ErrorData::Custom(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::SgxStatus(..) => None,
         }
     }
 
     /// Creates a new instance of an `Error` from a particular SGX error status.
     pub fn from_sgx_error(status: sgx_status_t) -> Error {
-        Error { repr: Repr::SgxStatus(status) }
+        Error { repr: Repr::new_sgx(status) }
     }
 
     /// Returns the SGX error that this error represents (if any).
@@ -511,12 +611,12 @@
     /// then this function will return `Some`, otherwise
     /// it will return `None`.
     pub fn raw_sgx_error(&self) -> Option<sgx_status_t> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Custom(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::SgxStatus(status) => Some(status),
+        match self.repr.data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Custom(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::SgxStatus(status) => Some(status),
         }
     }
 
@@ -550,12 +650,12 @@
     #[must_use]
     #[inline]
     pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(ref c) => Some(&*c.error),
-            Repr::SgxStatus(ref s) => Some(s),
+        match self.repr.data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => Some(&*c.error),
+            ErrorData::SgxStatus(..) => None,
         }
     }
 
@@ -624,12 +724,12 @@
     #[must_use]
     #[inline]
     pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(ref mut c) => Some(&mut *c.error),
-            Repr::SgxStatus(ref mut s) => Some(s),
+        match self.repr.data_mut() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => Some(&mut *c.error),
+            ErrorData::SgxStatus(..) => None,
         }
     }
 
@@ -663,12 +763,12 @@
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
     pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(c) => Some(c.error),
-            Repr::SgxStatus(s) => Some(Box::new(s)),
+        match self.repr.into_data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => Some(c.error),
+            ErrorData::SgxStatus(s) => Some(Box::new(s)),
         }
     }
 
@@ -693,31 +793,33 @@
     #[must_use]
     #[inline]
     pub fn kind(&self) -> ErrorKind {
-        match self.repr {
-            Repr::Os(code) => sys::decode_error_kind(code),
-            Repr::Custom(ref c) => c.kind,
-            Repr::Simple(kind) => kind,
-            Repr::SimpleMessage(kind, _) => kind,
-            Repr::SgxStatus(..) => ErrorKind::SgxError,
+        match self.repr.data() {
+            ErrorData::Os(code) => sys::decode_error_kind(code),
+            ErrorData::Custom(c) => c.kind,
+            ErrorData::Simple(kind) => kind,
+            ErrorData::SimpleMessage(m) => m.kind,
+            ErrorData::SgxStatus(..) => ErrorKind::SgxError,
         }
     }
 }
 
 impl fmt::Debug for Repr {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            Repr::Os(code) => fmt
+        match self.data() {
+            ErrorData::Os(code) => fmt
                 .debug_struct("Os")
                 .field("code", &code)
                 .field("kind", &sys::decode_error_kind(code))
                 .field("message", &sys::os::error_string(code))
                 .finish(),
-            Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
-            Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
-            Repr::SimpleMessage(kind, &message) => {
-                fmt.debug_struct("Error").field("kind", &kind).field("message", &message).finish()
-            }
-            Repr::SgxStatus(status) => fmt
+            ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
+            ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
+            ErrorData::SimpleMessage(msg) => fmt
+                .debug_struct("Error")
+                .field("kind", &msg.kind)
+                .field("message", &msg.message)
+                .finish(),
+            ErrorData::SgxStatus(status) => fmt
                 .debug_struct("Sgx")
                 .field("code", &status)
                 .field("message", &status.__description())
@@ -728,15 +830,15 @@
 
 impl fmt::Display for Error {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.repr {
-            Repr::Os(code) => {
+        match self.repr.data() {
+            ErrorData::Os(code) => {
                 let detail = sys::os::error_string(code);
                 write!(fmt, "{} (os error {})", detail, code)
             }
-            Repr::Custom(ref c) => c.error.fmt(fmt),
-            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
-            Repr::SimpleMessage(_, &msg) => msg.fmt(fmt),
-            Repr::SgxStatus(status) => {
+            ErrorData::Custom(c) => c.error.fmt(fmt),
+            ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
+            ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt),
+            ErrorData::SgxStatus(status) => {
                 let detail = status.__description();
                 write!(fmt, "{} (sgx error: {})", detail, status)
             }
@@ -747,32 +849,32 @@
 impl error::Error for Error {
     #[allow(deprecated, deprecated_in_future)]
     fn description(&self) -> &str {
-        match self.repr {
-            Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
-            Repr::SimpleMessage(_, &msg) => msg,
-            Repr::Custom(ref c) => c.error.description(),
-            Repr::SgxStatus(ref s) => s.description(),
+        match self.repr.data() {
+            ErrorData::Os(..) | ErrorData::Simple(..) => self.kind().as_str(),
+            ErrorData::SimpleMessage(msg) => msg.message,
+            ErrorData::Custom(c) => c.error.description(),
+            ErrorData::SgxStatus(ref s) => s.__description(),
         }
     }
 
     #[allow(deprecated)]
     fn cause(&self) -> Option<&dyn error::Error> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(ref c) => c.error.cause(),
-            Repr::SgxStatus(ref s) => Some(s),
+        match self.repr.data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => c.error.cause(),
+            ErrorData::SgxStatus(..) => None,
         }
     }
 
     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(ref c) => c.error.source(),
-            Repr::SgxStatus(ref s) => Some(s),
+        match self.repr.data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => c.error.source(),
+            ErrorData::SgxStatus(..) => None,
         }
     }
 }
diff --git a/sgx_tstd/src/io/error/repr_unpacked.rs b/sgx_tstd/src/io/error/repr_unpacked.rs
new file mode 100644
index 0000000..f171307
--- /dev/null
+++ b/sgx_tstd/src/io/error/repr_unpacked.rs
@@ -0,0 +1,58 @@
+//! This is a fairly simple unpacked error representation that's used on
+//! non-64bit targets, where the packed 64 bit representation wouldn't work, and
+//! would have no benefit.
+
+use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use alloc_crate::boxed::Box;
+
+use sgx_types::sgx_status_t;
+
+type Inner = ErrorData<Box<Custom>>;
+
+pub(super) struct Repr(Inner);
+
+impl Repr {
+    pub(super) fn new_custom(b: Box<Custom>) -> Self {
+        Self(Inner::Custom(b))
+    }
+    #[inline]
+    pub(super) fn new_os(code: i32) -> Self {
+        Self(Inner::Os(code))
+    }
+    #[inline]
+    pub(super) fn new_simple(kind: ErrorKind) -> Self {
+        Self(Inner::Simple(kind))
+    }
+    #[inline]
+    pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
+        Self(Inner::SimpleMessage(m))
+    }
+    #[inline]
+    pub(super) const fn new_sgx(status: sgx_status_t) -> Self {
+        Self(Inner::SgxStatus(status))
+    }
+    #[inline]
+    pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
+        self.0
+    }
+    #[inline]
+    pub(super) fn data(&self) -> ErrorData<&Custom> {
+        match &self.0 {
+            Inner::Os(c) => ErrorData::Os(*c),
+            Inner::Simple(k) => ErrorData::Simple(*k),
+            Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
+            Inner::Custom(m) => ErrorData::Custom(&*m),
+            Inner::SgxStatus(s) => ErrorData::SgxStatus(*s),
+        }
+    }
+    #[inline]
+    pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
+        match &mut self.0 {
+            Inner::Os(c) => ErrorData::Os(*c),
+            Inner::Simple(k) => ErrorData::Simple(*k),
+            Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
+            Inner::Custom(m) => ErrorData::Custom(&mut *m),
+            Inner::SgxStatus(s) => ErrorData::SgxStatus(*s),
+        }
+    }
+}
diff --git a/sgx_tstd/src/io/impls.rs b/sgx_tstd/src/io/impls.rs
index f30b868..2a8ebc6 100644
--- a/sgx_tstd/src/io/impls.rs
+++ b/sgx_tstd/src/io/impls.rs
@@ -19,7 +19,7 @@
 use crate::cmp;
 use crate::fmt;
 use crate::io::{
-    self, BufRead, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
+    self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
 };
 use crate::mem;
 
@@ -33,6 +33,11 @@
     }
 
     #[inline]
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        (**self).read_buf(buf)
+    }
+
+    #[inline]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         (**self).read_vectored(bufs)
     }
@@ -43,11 +48,6 @@
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        (**self).initializer()
-    }
-
-    #[inline]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         (**self).read_to_end(buf)
     }
@@ -136,6 +136,11 @@
     }
 
     #[inline]
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        (**self).read_buf(buf)
+    }
+
+    #[inline]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         (**self).read_vectored(bufs)
     }
@@ -146,11 +151,6 @@
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        (**self).initializer()
-    }
-
-    #[inline]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         (**self).read_to_end(buf)
     }
@@ -259,6 +259,17 @@
     }
 
     #[inline]
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        let amt = cmp::min(buf.remaining(), self.len());
+        let (a, b) = self.split_at(amt);
+
+        buf.append(a);
+
+        *self = b;
+        Ok(())
+    }
+
+    #[inline]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let mut nread = 0;
         for buf in bufs {
@@ -277,14 +288,12 @@
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
-
-    #[inline]
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         if buf.len() > self.len() {
-            return Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"));
+            return Err(io::const_io_error!(
+                ErrorKind::UnexpectedEof,
+                "failed to fill whole buffer"
+            ));
         }
         let (a, b) = self.split_at(buf.len());
 
@@ -332,6 +341,7 @@
 /// return short writes: ultimately, `Ok(0)`; in this situation, `write_all` returns an error of
 /// kind `ErrorKind::WriteZero`.
 impl Write for &mut [u8] {
+    #[allow(clippy::mem_replace_with_default)]
     #[inline]
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let amt = cmp::min(data.len(), self.len());
@@ -364,7 +374,7 @@
         if self.write(data)? == data.len() {
             Ok(())
         } else {
-            Err(Error::new_const(ErrorKind::WriteZero, &"failed to write whole buffer"))
+            Err(io::const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer"))
         }
     }
 
diff --git a/sgx_tstd/src/io/mod.rs b/sgx_tstd/src/io/mod.rs
index 8ca7acf..2497f3d 100644
--- a/sgx_tstd/src/io/mod.rs
+++ b/sgx_tstd/src/io/mod.rs
@@ -268,25 +268,30 @@
 use crate::fmt;
 use crate::mem::replace;
 use crate::ops::{Deref, DerefMut};
-use crate::ptr;
 use crate::slice;
 use crate::str;
 use crate::sys;
 use crate::sys_common::memchr;
 
-pub use self::buffered::IntoInnerError;
+
 pub use self::buffered::WriterPanicked;
-pub use self::buffered::{BufReader, BufWriter, LineWriter};
-pub use self::copy::copy;
-pub use self::cursor::Cursor;
-pub use self::error::{Error, ErrorKind, Result};
-#[cfg(feature = "stdio")]
-pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
-#[cfg(feature = "stdio")]
-pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
+
 #[cfg(feature = "stdio")]
 pub use self::stdio::{_eprint, _print};
-pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
+#[cfg(feature = "stdio")]
+pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
+#[cfg(feature = "stdio")]
+pub use self::stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock};
+pub use self::{
+    buffered::{BufReader, BufWriter, IntoInnerError, LineWriter},
+    copy::copy,
+    cursor::Cursor,
+    error::{Error, ErrorKind, Result},
+    util::{empty, repeat, sink, Empty, Repeat, Sink},
+};
+
+pub use self::readbuf::ReadBuf;
+pub(crate) use error::const_io_error;
 
 mod buffered;
 pub(crate) mod copy;
@@ -294,12 +299,14 @@
 mod error;
 mod impls;
 pub mod prelude;
+mod readbuf;
 #[cfg(feature = "stdio")]
 mod stdio;
 mod util;
 
 const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
 
+#[cfg(feature = "stdio")]
 pub(crate) use stdio::cleanup;
 
 struct Guard<'a> {
@@ -342,7 +349,10 @@
     let ret = f(g.buf);
     if str::from_utf8(&g.buf[g.len..]).is_err() {
         ret.and_then(|_| {
-            Err(Error::new_const(ErrorKind::InvalidData, &"stream did not contain valid UTF-8"))
+            Err(error::const_io_error!(
+                ErrorKind::InvalidData,
+                "stream did not contain valid UTF-8"
+            ))
         })
     } else {
         g.len = g.buf.len();
@@ -356,52 +366,43 @@
 // of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
 // time is 4,500 times (!) slower than a default reservation size of 32 if the
 // reader has a very small amount of data to return.
-//
-// Because we're extending the buffer with uninitialized data for trusted
-// readers, we need to make sure to truncate that if any of this panics.
 pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
     let start_len = buf.len();
     let start_cap = buf.capacity();
-    let mut g = Guard { len: buf.len(), buf };
+
+    let mut initialized = 0; // Extra initialized bytes from previous loop iteration
     loop {
-        // If we've read all the way up to the capacity, reserve more space.
-        if g.len == g.buf.capacity() {
-            g.buf.reserve(32);
+        if buf.len() == buf.capacity() {
+            buf.reserve(32); // buf is full, need more space
         }
 
-        // Initialize any excess capacity and adjust the length so we can write
-        // to it.
-        if g.buf.len() < g.buf.capacity() {
-            unsafe {
-                // FIXME(danielhenrymantilla): #42788
-                //
-                //   - This creates a (mut) reference to a slice of
-                //     _uninitialized_ integers, which is **undefined behavior**
-                //
-                //   - Only the standard library gets to soundly "ignore" this,
-                //     based on its privileged knowledge of unstable rustc
-                //     internals;
-                let capacity = g.buf.capacity();
-                g.buf.set_len(capacity);
-                r.initializer().initialize(&mut g.buf[g.len..]);
-            }
+        let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+
+        // SAFETY: These bytes were initialized but not filled in the previous loop
+        unsafe {
+            read_buf.assume_init(initialized);
         }
 
-        let buf = &mut g.buf[g.len..];
-        match r.read(buf) {
-            Ok(0) => return Ok(g.len - start_len),
-            Ok(n) => {
-                // We can't allow bogus values from read. If it is too large, the returned vec could have its length
-                // set past its capacity, or if it overflows the vec could be shortened which could create an invalid
-                // string if this is called via read_to_string.
-                assert!(n <= buf.len());
-                g.len += n;
-            }
-            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+        match r.read_buf(&mut read_buf) {
+            Ok(()) => {}
+            Err(e) if e.kind() == ErrorKind::Interrupted => continue,
             Err(e) => return Err(e),
         }
 
-        if g.len == g.buf.capacity() && g.buf.capacity() == start_cap {
+        if read_buf.filled_len() == 0 {
+            return Ok(buf.len() - start_len);
+        }
+
+        // store how much was initialized but not filled
+        initialized = read_buf.initialized_len() - read_buf.filled_len();
+        let new_len = read_buf.filled_len() + buf.len();
+
+        // SAFETY: ReadBuf's invariants mean this much memory is init
+        unsafe {
+            buf.set_len(new_len);
+        }
+
+        if buf.len() == buf.capacity() && buf.capacity() == start_cap {
             // The buffer might be an exact fit. Let's read into a probe buffer
             // and see if it returns `Ok(0)`. If so, we've avoided an
             // unnecessary doubling of the capacity. But if not, append the
@@ -410,10 +411,9 @@
 
             loop {
                 match r.read(&mut probe) {
-                    Ok(0) => return Ok(g.len - start_len),
+                    Ok(0) => return Ok(buf.len() - start_len),
                     Ok(n) => {
-                        g.buf.extend_from_slice(&probe[..n]);
-                        g.len += n;
+                        buf.extend_from_slice(&probe[..n]);
                         break;
                     }
                     Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
@@ -469,12 +469,21 @@
         }
     }
     if !buf.is_empty() {
-        Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+        Err(error::const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
     } else {
         Ok(())
     }
 }
 
+pub(crate) fn default_read_buf<F>(read: F, buf: &mut ReadBuf<'_>) -> Result<()>
+where
+    F: FnOnce(&mut [u8]) -> Result<usize>,
+{
+    let n = read(buf.initialize_unfilled())?;
+    buf.add_filled(n);
+    Ok(())
+}
+
 /// The `Read` trait allows for reading bytes from a source.
 ///
 /// Implementors of the `Read` trait are called 'readers'.
@@ -652,30 +661,6 @@
         false
     }
 
-    /// Determines if this `Read`er can work with buffers of uninitialized
-    /// memory.
-    ///
-    /// The default implementation returns an initializer which will zero
-    /// buffers.
-    ///
-    /// If a `Read`er guarantees that it can work properly with uninitialized
-    /// memory, it should call [`Initializer::nop()`]. See the documentation for
-    /// [`Initializer`] for details.
-    ///
-    /// The behavior of this method must be independent of the state of the
-    /// `Read`er - the method only takes `&self` so that it can be used through
-    /// trait objects.
-    ///
-    /// # Safety
-    ///
-    /// This method is unsafe because a `Read`er could otherwise return a
-    /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
-    /// block.
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::zeroing()
-    }
-
     /// Read all bytes until EOF in this source, placing them into `buf`.
     ///
     /// All bytes read from this source will be appended to the specified buffer
@@ -822,7 +807,38 @@
         default_read_exact(self, buf)
     }
 
-    /// Creates a "by reference" adapter for this instance of `Read`.
+    /// Pull some bytes from this source into the specified buffer.
+    ///
+    /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to allow use
+    /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.
+    ///
+    /// The default implementation delegates to `read`.
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+        default_read_buf(|b| self.read(b), buf)
+    }
+
+    /// Read the exact number of bytes required to fill `buf`.
+    ///
+    /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to
+    /// allow use with uninitialized buffers.
+    fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+        while buf.remaining() > 0 {
+            let prev_filled = buf.filled().len();
+            match self.read_buf(buf) {
+                Ok(()) => {}
+                Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+                Err(e) => return Err(e),
+            }
+
+            if buf.filled().len() == prev_filled {
+                return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer"));
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Creates a "by reference" adaptor for this instance of `Read`.
     ///
     /// The returned adapter also implements `Read` and will simply borrow this
     /// current reader.
@@ -1016,13 +1032,13 @@
 ///
 /// # use std::io;
 /// fn main() -> io::Result<()> {
-///     let stdin = io::read_to_string(&mut io::stdin())?;
+///     let stdin = io::read_to_string(io::stdin())?;
 ///     println!("Stdin was:");
 ///     println!("{}", stdin);
 ///     Ok(())
 /// }
 /// ```
-pub fn read_to_string<R: Read>(reader: &mut R) -> Result<String> {
+pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
     let mut buf = String::new();
     reader.read_to_string(&mut buf)?;
     Ok(buf)
@@ -1114,6 +1130,7 @@
     /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
     /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
     /// ```
+    #[allow(clippy::mem_replace_with_default)]
     #[inline]
     pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
         // Number of buffers to remove.
@@ -1239,6 +1256,7 @@
     /// IoSlice::advance_slices(&mut bufs, 10);
     /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
     /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
+    #[allow(clippy::mem_replace_with_default)]
     #[inline]
     pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
         // Number of buffers to remove.
@@ -1270,48 +1288,6 @@
     }
 }
 
-/// A type used to conditionally initialize buffers passed to `Read` methods.
-#[derive(Debug)]
-pub struct Initializer(bool);
-
-impl Initializer {
-    /// Returns a new `Initializer` which will zero out buffers.
-    #[must_use]
-    #[inline]
-    pub fn zeroing() -> Initializer {
-        Initializer(true)
-    }
-
-    /// Returns a new `Initializer` which will not zero out buffers.
-    ///
-    /// # Safety
-    ///
-    /// This may only be called by `Read`ers which guarantee that they will not
-    /// read from buffers passed to `Read` methods, and that the return value of
-    /// the method accurately reflects the number of bytes that have been
-    /// written to the head of the buffer.
-    #[must_use]
-    #[inline]
-    pub unsafe fn nop() -> Initializer {
-        Initializer(false)
-    }
-
-    /// Indicates if a buffer should be initialized.
-    #[must_use]
-    #[inline]
-    pub fn should_initialize(&self) -> bool {
-        self.0
-    }
-
-    /// Initializes a buffer if necessary.
-    #[inline]
-    pub fn initialize(&self, buf: &mut [u8]) {
-        if self.should_initialize() {
-            unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
-        }
-    }
-}
-
 /// A trait for objects which are byte-oriented sinks.
 ///
 /// Implementors of the `Write` trait are sometimes called 'writers'.
@@ -1514,9 +1490,9 @@
         while !buf.is_empty() {
             match self.write(buf) {
                 Ok(0) => {
-                    return Err(Error::new_const(
+                    return Err(error::const_io_error!(
                         ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
+                        "failed to write whole buffer",
                     ));
                 }
                 Ok(n) => buf = &buf[n..],
@@ -1581,9 +1557,9 @@
         while !bufs.is_empty() {
             match self.write_vectored(bufs) {
                 Ok(0) => {
-                    return Err(Error::new_const(
+                    return Err(error::const_io_error!(
                         ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
+                        "failed to write whole buffer",
                     ));
                 }
                 Ok(n) => IoSlice::advance_slices(&mut bufs, n),
@@ -1657,7 +1633,7 @@
                 if output.error.is_err() {
                     output.error
                 } else {
-                    Err(Error::new_const(ErrorKind::Uncategorized, &"formatter error"))
+                    Err(error::const_io_error!(ErrorKind::Uncategorized, "formatter error"))
                 }
             }
         }
@@ -2336,11 +2312,6 @@
         }
         self.second.read_vectored(bufs)
     }
-
-    unsafe fn initializer(&self) -> Initializer {
-        let initializer = self.first.initializer();
-        if initializer.should_initialize() { initializer } else { self.second.initializer() }
-    }
 }
 
 impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
@@ -2535,8 +2506,53 @@
         Ok(n)
     }
 
-    unsafe fn initializer(&self) -> Initializer {
-        self.inner.initializer()
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+        // Don't call into inner reader at all at EOF because it may still block
+        if self.limit == 0 {
+            return Ok(());
+        }
+
+        let prev_filled = buf.filled_len();
+
+        if self.limit <= buf.remaining() as u64 {
+            // if we just use an as cast to convert, limit may wrap around on a 32 bit target
+            let limit = cmp::min(self.limit, usize::MAX as u64) as usize;
+
+            let extra_init = cmp::min(limit as usize, buf.initialized_len() - buf.filled_len());
+
+            // SAFETY: no uninit data is written to ibuf
+            let ibuf = unsafe { &mut buf.unfilled_mut()[..limit] };
+
+            let mut sliced_buf = ReadBuf::uninit(ibuf);
+
+            // SAFETY: extra_init bytes of ibuf are known to be initialized
+            unsafe {
+                sliced_buf.assume_init(extra_init);
+            }
+
+            self.inner.read_buf(&mut sliced_buf)?;
+
+            let new_init = sliced_buf.initialized_len();
+            let filled = sliced_buf.filled_len();
+
+            // sliced_buf / ibuf must drop here
+
+            // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
+            unsafe {
+                buf.assume_init(new_init);
+            }
+
+            buf.add_filled(filled);
+
+            self.limit -= filled as u64;
+        } else {
+            self.inner.read_buf(buf)?;
+
+            //inner may unfill
+            self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64;
+        }
+
+        Ok(())
     }
 }
 
diff --git a/sgx_tstd/src/io/readbuf.rs b/sgx_tstd/src/io/readbuf.rs
new file mode 100644
index 0000000..db776d7
--- /dev/null
+++ b/sgx_tstd/src/io/readbuf.rs
@@ -0,0 +1,257 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License..
+
+use crate::cmp;
+use crate::fmt::{self, Debug, Formatter};
+use crate::mem::MaybeUninit;
+
+/// A wrapper around a byte buffer that is incrementally filled and initialized.
+///
+/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the
+/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet
+/// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a
+/// subset of the initialized region.
+///
+/// In summary, the contents of the buffer can be visualized as:
+/// ```not_rust
+/// [             capacity              ]
+/// [ filled |         unfilled         ]
+/// [    initialized    | uninitialized ]
+/// ```
+pub struct ReadBuf<'a> {
+    buf: &'a mut [MaybeUninit<u8>],
+    filled: usize,
+    initialized: usize,
+}
+
+impl Debug for ReadBuf<'_> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ReadBuf")
+            .field("init", &self.initialized())
+            .field("filled", &self.filled)
+            .field("capacity", &self.capacity())
+            .finish()
+    }
+}
+
+impl<'a> ReadBuf<'a> {
+    /// Creates a new `ReadBuf` from a fully initialized buffer.
+    #[inline]
+    pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
+        let len = buf.len();
+
+        ReadBuf {
+            //SAFETY: initialized data never becoming uninitialized is an invariant of ReadBuf
+            buf: unsafe { (buf as *mut [u8]).as_uninit_slice_mut().unwrap() },
+            filled: 0,
+            initialized: len,
+        }
+    }
+
+    /// Creates a new `ReadBuf` from a fully uninitialized buffer.
+    ///
+    /// Use `assume_init` if part of the buffer is known to be already initialized.
+    #[inline]
+    pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
+        ReadBuf { buf, filled: 0, initialized: 0 }
+    }
+
+    /// Returns the total capacity of the buffer.
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.buf.len()
+    }
+
+    /// Returns a shared reference to the filled portion of the buffer.
+    #[inline]
+    pub fn filled(&self) -> &[u8] {
+        //SAFETY: We only slice the filled part of the buffer, which is always valid
+        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
+    }
+
+    /// Returns a mutable reference to the filled portion of the buffer.
+    #[inline]
+    pub fn filled_mut(&mut self) -> &mut [u8] {
+        //SAFETY: We only slice the filled part of the buffer, which is always valid
+        unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
+    }
+
+    /// Returns a shared reference to the initialized portion of the buffer.
+    ///
+    /// This includes the filled portion.
+    #[inline]
+    pub fn initialized(&self) -> &[u8] {
+        //SAFETY: We only slice the initialized part of the buffer, which is always valid
+        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.initialized]) }
+    }
+
+    /// Returns a mutable reference to the initialized portion of the buffer.
+    ///
+    /// This includes the filled portion.
+    #[inline]
+    pub fn initialized_mut(&mut self) -> &mut [u8] {
+        //SAFETY: We only slice the initialized part of the buffer, which is always valid
+        unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.initialized]) }
+    }
+
+    /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
+    /// initialized.
+    ///
+    /// # Safety
+    ///
+    /// The caller must not de-initialize portions of the buffer that have already been initialized.
+    #[inline]
+    pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+        &mut self.buf[self.filled..]
+    }
+
+    /// Returns a mutable reference to the uninitialized part of the buffer.
+    ///
+    /// It is safe to uninitialize any of these bytes.
+    #[inline]
+    pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+        &mut self.buf[self.initialized..]
+    }
+
+    /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
+    ///
+    /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
+    /// the first use.
+    #[inline]
+    pub fn initialize_unfilled(&mut self) -> &mut [u8] {
+        // should optimize out the assertion
+        self.initialize_unfilled_to(self.remaining())
+    }
+
+    /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
+    /// fully initialized.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `self.remaining()` is less than `n`.
+    #[inline]
+    pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
+        assert!(self.remaining() >= n);
+
+        let extra_init = self.initialized - self.filled;
+        // If we don't have enough initialized, do zeroing
+        if n > extra_init {
+            let uninit = n - extra_init;
+            let unfilled = &mut self.uninitialized_mut()[0..uninit];
+
+            for byte in unfilled.iter_mut() {
+                byte.write(0);
+            }
+
+            // SAFETY: we just initialized uninit bytes, and the previous bytes were already init
+            unsafe {
+                self.assume_init(n);
+            }
+        }
+
+        let filled = self.filled;
+
+        &mut self.initialized_mut()[filled..filled + n]
+    }
+
+    /// Returns the number of bytes at the end of the slice that have not yet been filled.
+    #[inline]
+    pub fn remaining(&self) -> usize {
+        self.capacity() - self.filled
+    }
+
+    /// Clears the buffer, resetting the filled region to empty.
+    ///
+    /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
+    #[inline]
+    pub fn clear(&mut self) {
+        self.set_filled(0); // The assertion in `set_filled` is optimized out
+    }
+
+    /// Increases the size of the filled region of the buffer.
+    ///
+    /// The number of initialized bytes is not changed.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the filled region of the buffer would become larger than the initialized region.
+    #[inline]
+    pub fn add_filled(&mut self, n: usize) {
+        self.set_filled(self.filled + n);
+    }
+
+    /// Sets the size of the filled region of the buffer.
+    ///
+    /// The number of initialized bytes is not changed.
+    ///
+    /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
+    /// example, by a `Read` implementation that compresses data in-place).
+    ///
+    /// # Panics
+    ///
+    /// Panics if the filled region of the buffer would become larger than the initialized region.
+    #[inline]
+    pub fn set_filled(&mut self, n: usize) {
+        assert!(n <= self.initialized);
+
+        self.filled = n;
+    }
+
+    /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
+    ///
+    /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
+    /// bytes than are already known to be initialized.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
+    #[inline]
+    pub unsafe fn assume_init(&mut self, n: usize) {
+        self.initialized = cmp::max(self.initialized, self.filled + n);
+    }
+
+    /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `self.remaining()` is less than `buf.len()`.
+    #[inline]
+    pub fn append(&mut self, buf: &[u8]) {
+        assert!(self.remaining() >= buf.len());
+
+        // SAFETY: we do not de-initialize any of the elements of the slice
+        unsafe {
+            MaybeUninit::write_slice(&mut self.unfilled_mut()[..buf.len()], buf);
+        }
+
+        // SAFETY: We just added the entire contents of buf to the filled section.
+        unsafe { self.assume_init(buf.len()) }
+        self.add_filled(buf.len());
+    }
+
+    /// Returns the amount of bytes that have been filled.
+    #[inline]
+    pub fn filled_len(&self) -> usize {
+        self.filled
+    }
+
+    /// Returns the amount of bytes that have been initialized.
+    #[inline]
+    pub fn initialized_len(&self) -> usize {
+        self.initialized
+    }
+}
diff --git a/sgx_tstd/src/io/stdio.rs b/sgx_tstd/src/io/stdio.rs
index bb72030..8a18478 100644
--- a/sgx_tstd/src/io/stdio.rs
+++ b/sgx_tstd/src/io/stdio.rs
@@ -19,7 +19,7 @@
 
 use crate::cell::RefCell;
 use crate::fmt;
-use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Lines, Split};
+use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
 use crate::lazy::SyncOnceCell;
 use crate::pin::Pin;
 use crate::sync::{SgxMutex as Mutex, SgxMutexGuard as MutexGuard};
@@ -93,11 +93,6 @@
         self.0.is_read_vectored()
     }
 
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
-
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         handle_ebadf(self.0.read_to_end(buf), 0)
     }
@@ -447,28 +442,6 @@
     pub fn lines(self) -> Lines<StdinLock<'static>> {
         self.into_locked().lines()
     }
-
-    /// Consumes this handle and returns an iterator over input bytes,
-    /// split at the specified byte value.
-    ///
-    /// For detailed semantics of this method, see the documentation on
-    /// [`BufRead::split`].
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(stdin_forwarders)]
-    /// use std::io;
-    ///
-    /// let splits = io::stdin().split(b'-');
-    /// for split in splits {
-    ///     println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap()));
-    /// }
-    /// ```
-    #[must_use = "`self` will be dropped if the result is not used"]
-    pub fn split(self, byte: u8) -> Split<StdinLock<'static>> {
-        self.into_locked().split(byte)
-    }
 }
 
 impl fmt::Debug for Stdin {
@@ -488,10 +461,6 @@
     fn is_read_vectored(&self) -> bool {
         self.lock().is_read_vectored()
     }
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         self.lock().read_to_end(buf)
     }
@@ -524,11 +493,6 @@
         self.inner.is_read_vectored()
     }
 
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
-
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         self.inner.read_to_end(buf)
     }
diff --git a/sgx_tstd/src/io/util.rs b/sgx_tstd/src/io/util.rs
index 16f8055..efc956d 100644
--- a/sgx_tstd/src/io/util.rs
+++ b/sgx_tstd/src/io/util.rs
@@ -19,7 +19,7 @@
 
 use crate::fmt;
 use crate::io::{
-    self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
+    self, BufRead, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, Write,
 };
 
 /// A reader which is always at EOF.
@@ -57,8 +57,8 @@
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+    fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        Ok(())
     }
 }
 
@@ -134,6 +134,24 @@
         Ok(buf.len())
     }
 
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        // SAFETY: No uninit bytes are being written
+        for slot in unsafe { buf.unfilled_mut() } {
+            slot.write(self.byte);
+        }
+
+        let remaining = buf.remaining();
+
+        // SAFETY: the entire unfilled portion of buf has been initialized
+        unsafe {
+            buf.assume_init(remaining);
+        }
+
+        buf.add_filled(remaining);
+
+        Ok(())
+    }
+
     #[inline]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let mut nwritten = 0;
@@ -147,11 +165,6 @@
     fn is_read_vectored(&self) -> bool {
         true
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl SizeHint for Repeat {
diff --git a/sgx_tstd/src/lib.rs b/sgx_tstd/src/lib.rs
index 7f3b018..e7fe9ff 100644
--- a/sgx_tstd/src/lib.rs
+++ b/sgx_tstd/src/lib.rs
@@ -46,39 +46,36 @@
 
 #![allow(clippy::declare_interior_mutable_const)]
 #![allow(clippy::len_without_is_empty)]
-#![allow(clippy::mem_replace_with_default)]
 #![allow(clippy::missing_safety_doc)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::transmute_ptr_to_ptr)]
 #![allow(clippy::wrong_self_convention)]
 
 #![feature(rustc_allow_const_fn_unstable)]
-
 #![feature(alloc_error_handler)]
 #![feature(allocator_api)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
 #![feature(allow_internal_unstable)]
 #![feature(array_error_internals)]
-#![feature(asm)]
 #![feature(assert_matches)]
-#![feature(async_stream)]
+#![feature(async_iterator)]
 #![feature(bench_black_box)]
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
-#![feature(c_variadic)]
 #![feature(c_unwind)]
+#![feature(c_variadic)]
 #![feature(cfg_accessible)]
 #![feature(cfg_eval)]
 #![feature(cfg_target_has_atomic)]
 #![feature(char_error_internals)]
 #![feature(char_internals)]
+#![feature(concat_bytes)]
 #![feature(concat_idents)]
-#![feature(const_caller_location)]
 #![feature(const_fn_fn_ptr_basics)]
 #![feature(const_fn_trait_bound)]
 #![feature(const_format_args)]
-#![feature(const_raw_ptr_deref)]
+#![feature(const_mut_refs)]
 #![feature(const_trait_impl)]
 #![feature(core_intrinsics)]
 #![feature(core_panic)]
@@ -88,23 +85,22 @@
 #![feature(duration_checked_float)]
 #![feature(duration_constants)]
 #![feature(edition_panic)]
+#![feature(exact_size_is_empty)]
 #![feature(extend_one)]
 #![feature(fn_traits)]
+#![feature(float_minimum_maximum)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]
 #![feature(get_mut_unchecked)]
-#![feature(global_asm)]
 #![feature(hashmap_internals)]
-#![feature(into_future)]
 #![feature(int_error_internals)]
-#![feature(iter_zip)]
+#![feature(into_future)]
 #![feature(lang_items)]
 #![feature(linked_list_remove)]
-#![feature(llvm_asm)]
 #![feature(log_syntax)]
 #![feature(map_try_insert)]
-#![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_slice)]
+#![feature(maybe_uninit_write_slice)]
 #![feature(mixed_integer_ops)]
 #![feature(must_not_suspend)]
 #![feature(needs_panic_runtime)]
@@ -114,11 +110,13 @@
 #![feature(once_cell)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
+#![feature(panic_can_unwind)]
 #![feature(panic_unwind)]
-#![feature(pin_static_ref)]
 #![feature(prelude_import)]
+#![feature(ptr_as_uninit)]
 #![feature(ptr_internals)]
 #![feature(rustc_attrs)]
+#![feature(slice_internals)]
 #![feature(specialization)]
 #![feature(std_internals)]
 #![feature(str_internals)]
@@ -130,7 +128,6 @@
 #![feature(try_blocks)]
 #![feature(try_reserve_kind)]
 #![feature(unboxed_closures)]
-#![feature(vec_spare_capacity)]
 #![default_lib_allocator]
 
 // Explicitly import the prelude. The compiler uses this same unstable attribute
@@ -189,6 +186,7 @@
 pub use alloc_crate::vec;
 pub use core::any;
 pub use core::array;
+pub use core::async_iter;
 pub use core::cell;
 pub use core::char;
 pub use core::clone;
@@ -213,7 +211,6 @@
 pub use core::pin;
 pub use core::ptr;
 pub use core::result;
-pub use core::stream;
 pub use core::u128;
 pub use core::u16;
 pub use core::u32;
@@ -221,6 +218,11 @@
 pub use core::u8;
 pub use core::usize;
 
+// The runtime entry point and a few unstable public functions used by the
+// compiler
+#[macro_use]
+pub mod rt;
+
 pub mod f32;
 pub mod f64;
 
@@ -257,10 +259,14 @@
     pub use alloc_crate::task::*;
 }
 
-// The runtime entry point and a few unstable public functions used by the
-// compiler
-#[macro_use]
-pub mod rt;
+pub mod arch {
+    // The `no_inline`-attribute is required to make the documentation of all
+    // targets available.
+    // See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for
+    // more information.
+    #[doc(no_inline)] // Note (#82861): required for correct documentation
+    pub use core::arch::*;
+}
 
 // Platform-abstraction modules
 mod sys;
@@ -295,10 +301,12 @@
 #[allow(deprecated)]
 pub use core::{
     assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args,
-    env, file, format_args, format_args_nl, include, include_bytes, include_str, line, llvm_asm,
-    log_syntax, module_path, option_env, stringify, trace_macros,
+    env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
+    module_path, option_env, stringify, trace_macros,
 };
 
+pub use core::concat_bytes;
+
 pub use core::primitive;
 
 mod sealed {
diff --git a/sgx_tstd/src/macros.rs b/sgx_tstd/src/macros.rs
index e992568..5b4e7d0 100644
--- a/sgx_tstd/src/macros.rs
+++ b/sgx_tstd/src/macros.rs
@@ -70,7 +70,9 @@
 ///
 /// io::stdout().flush().unwrap();
 /// ```
+#[cfg(feature = "stdio")]
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")]
 #[allow_internal_unstable(print_internals)]
 macro_rules! print {
     ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*)));
@@ -102,7 +104,9 @@
 /// println!("hello there!");
 /// println!("format {} arguments", "some");
 /// ```
+#[cfg(feature = "stdio")]
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")]
 #[allow_internal_unstable(print_internals, format_args_nl)]
 macro_rules! println {
     () => ($crate::print!("\n"));
@@ -113,10 +117,12 @@
 
 #[cfg(not(feature = "stdio"))]
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")]
 macro_rules! print { ($($arg:tt)*) => ({}) }
 
 #[cfg(not(feature = "stdio"))]
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")]
 macro_rules! println { ($($arg:tt)*) => ({}) }
 
 /// Prints to the standard error.
@@ -140,7 +146,9 @@
 /// ```
 /// eprint!("Error: Could not complete task");
 /// ```
+#[cfg(feature = "stdio")]
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")]
 #[allow_internal_unstable(print_internals)]
 macro_rules! eprint {
     ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*)));
@@ -167,7 +175,9 @@
 /// ```
 /// eprintln!("Error: Could not complete task");
 /// ```
+#[cfg(feature = "stdio")]
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")]
 #[allow_internal_unstable(print_internals, format_args_nl)]
 macro_rules! eprintln {
     () => ($crate::eprint!("\n"));
@@ -178,10 +188,12 @@
 
 #[cfg(not(feature = "stdio"))]
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")]
 macro_rules! eprint { ($($arg:tt)*) => ({}) }
 
 #[cfg(not(feature = "stdio"))]
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")]
 macro_rules! eprintln { ($($arg:tt)*) => ({}) }
 
 /// Prints and returns the value of a given expression for quick and dirty
@@ -309,6 +321,7 @@
 /// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
 /// [`log`]: https://crates.io/crates/log
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")]
 macro_rules! dbg {
     // NOTE: We cannot use `concat!` to make a static string as a format argument
     // of `eprintln!` because `file!` could contain a `{` or
diff --git a/sgx_tstd/src/net/addr.rs b/sgx_tstd/src/net/addr.rs
index 83a4dbc..affcf4d 100644
--- a/sgx_tstd/src/net/addr.rs
+++ b/sgx_tstd/src/net/addr.rs
@@ -919,8 +919,7 @@
 }
 
 #[cfg(feature = "net")]
-#[allow(clippy::unnecessary_wraps)]
-#[allow(clippy::needless_collect)]
+#[allow(clippy::unnecessary_wraps, clippy::needless_collect)]
 fn resolve_socket_addr(lh: LookupHost) -> io::Result<vec::IntoIter<SocketAddr>> {
     let p = lh.port();
     let v: Vec<_> = lh
@@ -948,7 +947,7 @@
         }
 
         #[cfg(not(feature = "net"))]
-        let r = Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"invalid socket address"));
+        let r = Err(io::const_io_error!(io::ErrorKind::InvalidInput, "invalid socket address"));
         #[cfg(feature = "net")]
         let r = resolve_socket_addr((host, port).try_into()?);
         r
@@ -972,7 +971,7 @@
         }
 
         #[cfg(not(feature = "net"))]
-        let r = Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"invalid socket address"));
+        let r = Err(io::const_io_error!(io::ErrorKind::InvalidInput, "invalid socket address"));
         #[cfg(feature = "net")]
         let r = resolve_socket_addr(self.try_into()?);
         r
diff --git a/sgx_tstd/src/net/ip.rs b/sgx_tstd/src/net/ip.rs
index 79503e7..2bcf01e 100644
--- a/sgx_tstd/src/net/ip.rs
+++ b/sgx_tstd/src/net/ip.rs
@@ -841,12 +841,7 @@
     #[inline]
     #[allow(clippy::match_like_matches_macro)]
     pub const fn is_documentation(&self) -> bool {
-        match self.octets() {
-            [192, 0, 2, _] => true,
-            [198, 51, 100, _] => true,
-            [203, 0, 113, _] => true,
-            _ => false,
-        }
+        matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
     }
 
     /// Converts this address to an [IPv4-compatible] [`IPv6` address].
@@ -1087,8 +1082,8 @@
     /// ```
     /// use std::net::Ipv4Addr;
     ///
-    /// let addr = Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe);
-    /// assert_eq!(0xcafebabe, u32::from(addr));
+    /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78);
+    /// assert_eq!(0x12345678, u32::from(addr));
     /// ```
     #[inline]
     fn from(ip: Ipv4Addr) -> u32 {
@@ -1105,8 +1100,8 @@
     /// ```
     /// use std::net::Ipv4Addr;
     ///
-    /// let addr = Ipv4Addr::from(0xcafebabe);
-    /// assert_eq!(Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe), addr);
+    /// let addr = Ipv4Addr::from(0x12345678);
+    /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
     /// ```
     #[inline]
     fn from(ip: u32) -> Ipv4Addr {
@@ -1161,7 +1156,6 @@
     /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
     /// ```
     #[allow(clippy::too_many_arguments)]
-    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))]
     #[must_use]
     #[inline]
     pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
@@ -1736,7 +1730,7 @@
                 }
             }
         } else {
-            // Slow path: write the address to a local buffer, the use f.pad.
+            // Slow path: write the address to a local buffer, then use f.pad.
             // Defined recursively by using the fast path to write to the
             // buffer.
 
diff --git a/sgx_tstd/src/net/mod.rs b/sgx_tstd/src/net/mod.rs
index 1796702..f6c9de4 100644
--- a/sgx_tstd/src/net/mod.rs
+++ b/sgx_tstd/src/net/mod.rs
@@ -32,12 +32,14 @@
 //!   with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`]
 //! * Other types are return or parameter types for various methods in this module
 
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
 
 pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
 pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
 pub use self::parser::AddrParseError;
 #[cfg(feature = "net")]
+pub use self::tcp::IntoIncoming;
+#[cfg(feature = "net")]
 pub use self::tcp::{Incoming, TcpListener, TcpStream};
 #[cfg(feature = "net")]
 pub use self::udp::UdpSocket;
@@ -96,6 +98,6 @@
         }
     }
     Err(last_err.unwrap_or_else(|| {
-        Error::new_const(ErrorKind::InvalidInput, &"could not resolve to any addresses")
+        io::const_io_error!(ErrorKind::InvalidInput, "could not resolve to any addresses")
     }))
 }
\ No newline at end of file
diff --git a/sgx_tstd/src/net/tcp.rs b/sgx_tstd/src/net/tcp.rs
index b939990..bdcadd5 100644
--- a/sgx_tstd/src/net/tcp.rs
+++ b/sgx_tstd/src/net/tcp.rs
@@ -18,7 +18,7 @@
 use crate::io::prelude::*;
 
 use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sys_common::net as net_imp;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -448,7 +448,7 @@
     /// use std::net::TcpStream;
     ///
     /// let stream = TcpStream::connect("127.0.0.1:8000")
-    ///                        .expect("couldn't bind to address");
+    ///                        .expect("Couldn't connect to the server...");
     /// let mut buf = [0; 10];
     /// let len = stream.peek(&mut buf).expect("peek failed");
     /// ```
@@ -659,12 +659,6 @@
     fn is_read_vectored(&self) -> bool {
         self.0.is_read_vectored()
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        Initializer::nop()
-    }
 }
 
 impl Write for TcpStream {
@@ -699,12 +693,6 @@
     fn is_read_vectored(&self) -> bool {
         self.0.is_read_vectored()
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        Initializer::nop()
-    }
 }
 
 impl Write for &TcpStream {
diff --git a/sgx_tstd/src/net/udp.rs b/sgx_tstd/src/net/udp.rs
index 2ba2f0b..52ddab8 100644
--- a/sgx_tstd/src/net/udp.rs
+++ b/sgx_tstd/src/net/udp.rs
@@ -16,7 +16,7 @@
 // under the License..
 
 use crate::fmt;
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
 use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
 use crate::sys_common::net as net_imp;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -203,7 +203,9 @@
     pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
         match addr.to_socket_addrs()?.next() {
             Some(addr) => self.0.send_to(buf, &addr),
-            None => Err(Error::new_const(ErrorKind::InvalidInput, &"no addresses to send data to")),
+            None => {
+                Err(io::const_io_error!(ErrorKind::InvalidInput, "no addresses to send data to"))
+            }
         }
     }
 
diff --git a/sgx_tstd/src/os/fd/owned.rs b/sgx_tstd/src/os/fd/owned.rs
index 4f00737..ca7d353 100644
--- a/sgx_tstd/src/os/fd/owned.rs
+++ b/sgx_tstd/src/os/fd/owned.rs
@@ -21,10 +21,11 @@
 
 use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 use crate::fmt;
+use crate::fs;
 use crate::marker::PhantomData;
 use crate::mem::forget;
+use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
-use crate::untrusted::fs;
 
 /// A borrowed file descriptor.
 ///
@@ -80,6 +81,21 @@
     }
 }
 
+impl OwnedFd {
+    /// Creates a new `OwnedFd` instance that shares the same underlying file handle
+    /// as the existing `OwnedFd` instance.
+    pub fn try_clone(&self) -> crate::io::Result<Self> {
+        // We want to atomically duplicate this file descriptor and set the
+        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
+        // is a POSIX flag that was added to Linux in 2.6.24.
+        let cmd = libc::F_DUPFD_CLOEXEC;
+
+        let fd = cvt(unsafe { libc::fcntl_arg1(self.as_raw_fd(), cmd, 0) })?;
+        Ok(unsafe { Self::from_raw_fd(fd) })
+    }
+
+}
+
 impl AsRawFd for BorrowedFd<'_> {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
@@ -171,6 +187,20 @@
     fn as_fd(&self) -> BorrowedFd<'_>;
 }
 
+impl<T: AsFd> AsFd for &T {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        T::as_fd(self)
+    }
+}
+
+impl<T: AsFd> AsFd for &mut T {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        T::as_fd(self)
+    }
+}
+
 impl AsFd for BorrowedFd<'_> {
     #[inline]
     fn as_fd(&self) -> BorrowedFd<'_> {
@@ -291,5 +321,6 @@
 }
 
 mod libc {
-    pub use sgx_libc::ocall::close;
+    pub use sgx_libc::F_DUPFD_CLOEXEC;
+    pub use sgx_libc::ocall::{close, fcntl_arg1};
 }
diff --git a/sgx_tstd/src/os/fd/raw.rs b/sgx_tstd/src/os/fd/raw.rs
index d73008d..44a63fb 100644
--- a/sgx_tstd/src/os/fd/raw.rs
+++ b/sgx_tstd/src/os/fd/raw.rs
@@ -17,12 +17,14 @@
 
 //! Raw Unix-like file descriptors.
 
+use crate::fs;
+#[cfg(feature = "stdio")]
 use crate::io;
 use crate::os::raw;
 use crate::os::unix::io::OwnedFd;
 use crate::sys_common::{AsInner, IntoInner};
-use crate::untrusted::fs;
 
+#[cfg(feature = "stdio")]
 use sgx_libc as libc;
 
 /// Raw file descriptors.
diff --git a/sgx_tstd/src/os/fs.rs b/sgx_tstd/src/os/linux/fs.rs
similarity index 97%
rename from sgx_tstd/src/os/fs.rs
rename to sgx_tstd/src/os/linux/fs.rs
index 2305e1a..478350c 100644
--- a/sgx_tstd/src/os/fs.rs
+++ b/sgx_tstd/src/os/linux/fs.rs
@@ -15,16 +15,15 @@
 // specific language governing permissions and limitations
 // under the License..
 
-//! Linux-specific extensions to primitives in the `std::fs` module.
+//! Linux-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
 
-#[cfg(feature = "untrusted_fs")]
 use crate::fs::Metadata;
 use crate::sys_common::AsInner;
-#[cfg(not(feature = "untrusted_fs"))]
-use crate::untrusted::fs::Metadata;
 
 #[allow(deprecated)]
-use crate::os::raw;
+use crate::os::linux::raw;
 
 use sgx_libc as libc;
 
diff --git a/sgx_tstd/src/os/linux/mod.rs b/sgx_tstd/src/os/linux/mod.rs
new file mode 100644
index 0000000..473f2ef
--- /dev/null
+++ b/sgx_tstd/src/os/linux/mod.rs
@@ -0,0 +1,21 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License..
+
+//! Linux-specific definitions.
+
+pub mod fs;
+pub mod raw;
diff --git a/sgx_tstd/src/os/raw.rs b/sgx_tstd/src/os/linux/raw.rs
similarity index 73%
rename from sgx_tstd/src/os/raw.rs
rename to sgx_tstd/src/os/linux/raw.rs
index 1defce6..8639757 100644
--- a/sgx_tstd/src/os/raw.rs
+++ b/sgx_tstd/src/os/linux/raw.rs
@@ -17,34 +17,17 @@
 
 //! Linux-specific raw type definitions.
 
-pub type c_char = i8;
-pub type c_schar = i8;
-pub type c_uchar = u8;
-pub type c_short = i16;
-pub type c_ushort = u16;
-pub type c_int = i32;
-pub type c_uint = u32;
-#[cfg(target_pointer_width = "32")]
-pub type c_long = i32;
-#[cfg(target_pointer_width = "32")]
-pub type c_ulong = u32;
-#[cfg(target_pointer_width = "64")]
-pub type c_long = i64;
-#[cfg(target_pointer_width = "64")]
-pub type c_ulong = u64;
-pub type c_longlong = i64;
-pub type c_ulonglong = u64;
-pub type c_float = f32;
-pub type c_double = f64;
+#![allow(deprecated)]
 
-#[doc(no_inline)]
-pub use core::ffi::c_void;
+use crate::os::raw::c_void;
 
 pub type dev_t = u64;
 pub type mode_t = u32;
 pub type pthread_t = *mut c_void;
 
-pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
+#[doc(inline)]
+pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+
 
 mod arch {
     use crate::os::raw::{c_long, c_int};
@@ -78,4 +61,4 @@
         pub st_ctime_nsec: c_long,
         pub __unused: [c_long; 3],
     }
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/os/mod.rs b/sgx_tstd/src/os/mod.rs
index 657af0e..e8c86c1 100644
--- a/sgx_tstd/src/os/mod.rs
+++ b/sgx_tstd/src/os/mod.rs
@@ -17,7 +17,7 @@
 
 //! OS-specific functionality.
 
-pub mod fs;
+pub mod linux;
 pub mod raw;
 pub mod unix;
 
diff --git a/sgx_tstd/src/os/raw/mod.rs b/sgx_tstd/src/os/raw/mod.rs
new file mode 100644
index 0000000..57515b6
--- /dev/null
+++ b/sgx_tstd/src/os/raw/mod.rs
@@ -0,0 +1,89 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License..
+
+//! Platform-specific types, as defined by C.
+//!
+//! Code that interacts via FFI will almost certainly be using the
+//! base types provided by C, which aren't nearly as nicely defined
+//! as Rust's primitive types. This module provides types which will
+//! match those defined by C, so that code that interacts with C will
+//! refer to the correct types.
+
+use core::num::*;
+
+macro_rules! type_alias_no_nz {
+    {
+      $Alias:ident = $Real:ty;
+      $( $Cfg:tt )*
+    } => {
+        $( $Cfg )*
+        pub type $Alias = $Real;
+    }
+}
+
+macro_rules! type_alias {
+    {
+      $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty;
+      $( $Cfg:tt )*
+    } => {
+        type_alias_no_nz! { $Alias = $Real; $( $Cfg )* }
+
+        $( $Cfg )*
+        pub type $NZAlias = $NZReal;
+    }
+}
+
+type_alias! { c_char = i8, NonZero_c_char = NonZeroI8; }
+type_alias! { c_schar = i8, NonZero_c_schar = NonZeroI8; }
+type_alias! { c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
+type_alias! { c_short = i16, NonZero_c_short = NonZeroI16; }
+type_alias! { c_ushort = u16, NonZero_c_ushort = NonZeroU16; }
+type_alias! { c_int = i32, NonZero_c_int = NonZeroI32; }
+type_alias! { c_uint = u32, NonZero_c_uint = NonZeroU32; }
+type_alias! { c_long = i32, NonZero_c_long = NonZeroI32;
+#[cfg(target_pointer_width = "32")] }
+type_alias! { c_ulong = u32, NonZero_c_ulong = NonZeroU32;
+#[cfg(target_pointer_width = "32")] }
+type_alias! { c_long = i64, NonZero_c_long = NonZeroI64;
+#[cfg(target_pointer_width = "64")] }
+type_alias! { c_ulong = u64, NonZero_c_ulong = NonZeroU64;
+#[cfg(target_pointer_width = "64")] }
+type_alias! { c_longlong = i64, NonZero_c_longlong = NonZeroI64; }
+type_alias! { c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; }
+type_alias_no_nz! { c_float = f32; }
+type_alias_no_nz! { c_double = f64; }
+
+#[doc(no_inline)]
+pub use core::ffi::c_void;
+
+/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++).
+///
+/// This type is currently always [`usize`], however in the future there may be
+/// platforms where this is not the case.
+pub type c_size_t = usize;
+
+/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++).
+///
+/// This type is currently always [`isize`], however in the future there may be
+/// platforms where this is not the case.
+pub type c_ptrdiff_t = isize;
+
+/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type.
+///
+/// This type is currently always [`isize`], however in the future there may be
+/// platforms where this is not the case.
+pub type c_ssize_t = isize;
diff --git a/sgx_tstd/src/os/unix/ffi/os_str.rs b/sgx_tstd/src/os/unix/ffi/os_str.rs
index c06e5ea..5ba5083 100644
--- a/sgx_tstd/src/os/unix/ffi/os_str.rs
+++ b/sgx_tstd/src/os/unix/ffi/os_str.rs
@@ -41,9 +41,11 @@
 }
 
 impl OsStringExt for OsString {
+    #[inline]
     fn from_vec(vec: Vec<u8>) -> OsString {
         FromInner::from_inner(Buf { inner: vec })
     }
+    #[inline]
     fn into_vec(self) -> Vec<u8> {
         self.into_inner().inner
     }
diff --git a/sgx_tstd/src/os/unix/fs.rs b/sgx_tstd/src/os/unix/fs.rs
index c5487a2..3e0de5d 100644
--- a/sgx_tstd/src/os/unix/fs.rs
+++ b/sgx_tstd/src/os/unix/fs.rs
@@ -15,14 +15,17 @@
 // specific language governing permissions and limitations
 // under the License..
 
-//! Unix-specific extensions to primitives in the `std::fs` module.
+//! Unix-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
 
+use super::platform::fs::MetadataExt as _;
+use crate::fs::{self, OpenOptions, Permissions};
 use crate::io;
-use crate::os::fs::MetadataExt as _;
+use crate::os::unix::io::{AsFd, AsRawFd};
 use crate::path::Path;
 use crate::sys;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-use crate::untrusted::fs::{self, OpenOptions, Permissions};
 // Used for `File::read` on intra-doc links
 use crate::ffi::OsStr;
 use crate::sealed::Sealed;
@@ -125,7 +128,7 @@
             }
         }
         if !buf.is_empty() {
-            Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+            Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
         } else {
             Ok(())
         }
@@ -205,9 +208,9 @@
         while !buf.is_empty() {
             match self.write_at(buf, offset) {
                 Ok(0) => {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
+                        "failed to write whole buffer",
                     ));
                 }
                 Ok(n) => {
@@ -885,6 +888,72 @@
     }
 }
 
+/// Change the owner and group of the specified path.
+///
+/// Specifying either the uid or gid as `None` will leave it unchanged.
+///
+/// Changing the owner typically requires privileges, such as root or a specific capability.
+/// Changing the group typically requires either being the owner and a member of the group, or
+/// having privileges.
+///
+/// If called on a symbolic link, this will change the owner and group of the link target. To
+/// change the owner and group of the link itself, see [`lchown`].
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::chown("/sandbox", Some(0), Some(0))?;
+///     Ok(())
+/// }
+/// ```
+pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+    sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the owner and group of the file referenced by the specified open file descriptor.
+///
+/// For semantics and required privileges, see [`chown`].
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     let f = std::fs::File::open("/file")?;
+///     fs::fchown(&f, Some(0), Some(0))?;
+///     Ok(())
+/// }
+/// ```
+pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+    sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the owner and group of the specified path, without dereferencing symbolic links.
+///
+/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
+/// and group of the link itself rather than the owner and group of the link target.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::lchown("/symlink", Some(0), Some(0))?;
+///     Ok(())
+/// }
+/// ```
+pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+    sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
 /// Change the root directory of the current process to the specified path.
 ///
 /// This typically requires privileges, such as root or a specific capability.
diff --git a/sgx_tstd/src/os/unix/io/fd.rs b/sgx_tstd/src/os/unix/io/fd.rs
index f855305..88143de 100644
--- a/sgx_tstd/src/os/unix/io/fd.rs
+++ b/sgx_tstd/src/os/unix/io/fd.rs
@@ -15,7 +15,6 @@
 // specific language governing permissions and limitations
 // under the License..
 
-
 //! Owned and borrowed file descriptors.
 
 pub use crate::os::fd::owned::*;
diff --git a/sgx_tstd/src/os/unix/mod.rs b/sgx_tstd/src/os/unix/mod.rs
index 11c2de6..11fc726 100644
--- a/sgx_tstd/src/os/unix/mod.rs
+++ b/sgx_tstd/src/os/unix/mod.rs
@@ -21,8 +21,8 @@
 //! exposes Unix-specific functions that would otherwise be inappropriate as
 //! part of the core `std` library.
 //!
-//! It exposes more ways to deal with platform-specific strings (`OsStr`,
-//! `OsString`), allows to set permissions more granularly, extract low-level
+//! It exposes more ways to deal with platform-specific strings ([`OsStr`],
+//! [`OsString`]), allows to set permissions more granularly, extract low-level
 //! file descriptors from files and sockets, and has platform-specific helpers
 //! for spawning processes.
 //!
@@ -45,6 +45,8 @@
 //! [`OsStr`]: crate::ffi::OsStr
 //! [`OsString`]: crate::ffi::OsString
 
+use crate::os::linux as platform;
+
 pub mod ffi;
 pub mod fs;
 pub mod io;
@@ -71,6 +73,7 @@
     #[doc(no_inline)]
     pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
     #[doc(no_inline)]
+    #[doc(no_inline)]
     #[cfg(feature = "thread")]
     pub use super::thread::JoinHandleExt;
 }
diff --git a/sgx_tstd/src/os/unix/net/addr.rs b/sgx_tstd/src/os/unix/net/addr.rs
index 279caa9..8efe3af 100644
--- a/sgx_tstd/src/os/unix/net/addr.rs
+++ b/sgx_tstd/src/os/unix/net/addr.rs
@@ -19,7 +19,7 @@
 use crate::os::unix::ffi::OsStrExt;
 use crate::path::Path;
 use crate::sys::cvt;
-use crate::{ascii, fmt, io, iter, mem};
+use crate::{ascii, fmt, io, mem, ptr};
 use sgx_libc as libc;
 
 fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
@@ -29,30 +29,33 @@
     path - base
 }
 
-pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
-    let mut addr: libc::sockaddr_un = mem::zeroed();
+pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+    // SAFETY: All zeros is a valid representation for `sockaddr_un`.
+    let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
     addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
 
     let bytes = path.as_os_str().as_bytes();
 
     if bytes.contains(&0) {
-        return Err(io::Error::new_const(
+        return Err(io::const_io_error!(
             io::ErrorKind::InvalidInput,
-            &"paths must not contain interior null bytes",
+            "paths must not contain interior null bytes",
         ));
     }
 
     if bytes.len() >= addr.sun_path.len() {
-        return Err(io::Error::new_const(
+        return Err(io::const_io_error!(
             io::ErrorKind::InvalidInput,
-            &"path must be shorter than SUN_LEN",
+            "path must be shorter than SUN_LEN",
         ));
     }
-    for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
-        *dst = *src as libc::c_char;
-    }
-    // null byte for pathname addresses is already there because we zeroed the
-    // struct
+    // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
+    // both point to valid memory.
+    // NOTE: We zeroed the memory above, so the path is already null
+    // terminated.
+    unsafe {
+        ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
+    };
 
     let mut len = sun_path_offset(&addr) + bytes.len();
     match bytes.get(0) {
@@ -124,15 +127,51 @@
             // linux returns zero bytes of address
             len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
         } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidInput,
-                &"file descriptor did not correspond to a Unix socket",
+                "file descriptor did not correspond to a Unix socket",
             ));
         }
 
         Ok(SocketAddr { addr, len })
     }
 
+    /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if the path is longer than `SUN_LEN` or if it contains
+    /// NULL bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(unix_socket_creation)]
+    /// use std::os::unix::net::SocketAddr;
+    /// use std::path::Path;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let address = SocketAddr::from_path("/path/to/socket")?;
+    /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// Creating a `SocketAddr` with a NULL byte results in an error.
+    ///
+    /// ```
+    /// #![feature(unix_socket_creation)]
+    /// use std::os::unix::net::SocketAddr;
+    ///
+    /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
+    /// ```
+    pub fn from_path<P>(path: P) -> io::Result<SocketAddr>
+    where
+        P: AsRef<Path>,
+    {
+        sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
+    }
+
     /// Returns `true` if the address is unnamed.
     ///
     /// # Examples
@@ -277,9 +316,9 @@
             addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
 
             if namespace.len() + 1 > addr.sun_path.len() {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::InvalidInput,
-                    &"namespace must be shorter than SUN_LEN",
+                    "namespace must be shorter than SUN_LEN",
                 ));
             }
 
diff --git a/sgx_tstd/src/os/unix/net/listener.rs b/sgx_tstd/src/os/unix/net/listener.rs
index 498d368..ca91a3a 100644
--- a/sgx_tstd/src/os/unix/net/listener.rs
+++ b/sgx_tstd/src/os/unix/net/listener.rs
@@ -365,6 +365,7 @@
 /// }
 /// ```
 #[derive(Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct Incoming<'a> {
     listener: &'a UnixListener,
 }
diff --git a/sgx_tstd/src/os/unix/net/stream.rs b/sgx_tstd/src/os/unix/net/stream.rs
index c642623..5e797d4 100644
--- a/sgx_tstd/src/os/unix/net/stream.rs
+++ b/sgx_tstd/src/os/unix/net/stream.rs
@@ -18,7 +18,7 @@
 use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
 use super::{sockaddr_un, SocketAddr};
 use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::Shutdown;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::os::unix::ucred;
@@ -556,11 +556,6 @@
     fn is_read_vectored(&self) -> bool {
         io::Read::is_read_vectored(&&*self)
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl<'a> io::Read for &'a UnixStream {
@@ -576,11 +571,6 @@
     fn is_read_vectored(&self) -> bool {
         self.0.is_read_vectored()
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl io::Write for UnixStream {
diff --git a/sgx_tstd/src/os/unix/raw.rs b/sgx_tstd/src/os/unix/raw.rs
index 8b094ba..93de8f8 100644
--- a/sgx_tstd/src/os/unix/raw.rs
+++ b/sgx_tstd/src/os/unix/raw.rs
@@ -17,6 +17,8 @@
 
 //! Unix-specific primitives available on all unix platforms.
 
+#![allow(deprecated)]
+
 #[allow(non_camel_case_types)]
 pub type uid_t = u32;
 #[allow(non_camel_case_types)]
@@ -25,8 +27,8 @@
 pub type pid_t = i32;
 
 #[doc(inline)]
-pub use crate::os::raw::pthread_t;
+pub use super::platform::raw::pthread_t;
 #[doc(inline)]
-pub use crate::os::raw::{blkcnt_t, time_t};
+pub use super::platform::raw::{blkcnt_t, time_t};
 #[doc(inline)]
-pub use crate::os::raw::{blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t};
+pub use super::platform::raw::{blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t};
diff --git a/sgx_tstd/src/os/unix/thread.rs b/sgx_tstd/src/os/unix/thread.rs
index 08127d4..5ac3ed1 100644
--- a/sgx_tstd/src/os/unix/thread.rs
+++ b/sgx_tstd/src/os/unix/thread.rs
@@ -15,7 +15,9 @@
 // specific language governing permissions and limitations
 // under the License..
 
-//! Unix-specific extensions to primitives in the `std::thread` module.
+//! Unix-specific extensions to primitives in the [`std::thread`] module.
+//!
+//! [`std::thread`]: crate::thread
 
 #[allow(deprecated)]
 use crate::os::unix::raw::pthread_t;
diff --git a/sgx_tstd/src/panic.rs b/sgx_tstd/src/panic.rs
index 5e05262..cca723a 100644
--- a/sgx_tstd/src/panic.rs
+++ b/sgx_tstd/src/panic.rs
@@ -20,6 +20,8 @@
 use crate::any::Any;
 use crate::collections;
 use crate::panicking;
+#[cfg(feature = "backtrace")]
+use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::{SgxMutex, SgxRwLock};
 use crate::thread::Result;
 
@@ -48,6 +50,8 @@
 
 pub use crate::panicking::{set_hook, take_hook};
 
+pub use crate::panicking::update_hook;
+
 pub use core::panic::{Location, PanicInfo};
 
 pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
@@ -199,3 +203,86 @@
 pub fn always_abort() {
     crate::panicking::panic_count::set_always_abort();
 }
+
+/// The configuration for whether and how the default panic hook will capture
+/// and display the backtrace.
+#[cfg(feature = "backtrace")]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum BacktraceStyle {
+    /// Prints a terser backtrace which ideally only contains relevant
+    /// information.
+    Short,
+    /// Prints a backtrace with all possible information.
+    Full,
+    /// Disable collecting and displaying backtraces.
+    Off,
+}
+
+#[cfg(feature = "backtrace")]
+impl BacktraceStyle {
+    pub(crate) fn full() -> Option<Self> {
+        Some(BacktraceStyle::Full)
+    }
+
+    fn as_usize(self) -> usize {
+        match self {
+            BacktraceStyle::Short => 1,
+            BacktraceStyle::Full => 2,
+            BacktraceStyle::Off => 3,
+        }
+    }
+
+    fn from_usize(s: usize) -> Option<Self> {
+        Some(match s {
+            0 => return None,
+            1 => BacktraceStyle::Short,
+            2 => BacktraceStyle::Full,
+            3 => BacktraceStyle::Off,
+            _ => unreachable!(),
+        })
+    }
+}
+
+// Tracks whether we should/can capture a backtrace, and how we should display
+// that backtrace.
+//
+// Internally stores equivalent of an Option<BacktraceStyle>.
+#[cfg(feature = "backtrace")]
+static SHOULD_CAPTURE: AtomicUsize = AtomicUsize::new(0);
+
+/// Configure whether the default panic hook will capture and display a
+/// backtrace.
+///
+/// The default value for this setting may be set by the `RUST_BACKTRACE`
+/// environment variable; see the details in [`get_backtrace_style`].
+#[cfg(feature = "backtrace")]
+pub fn set_backtrace_style(style: BacktraceStyle) {
+    SHOULD_CAPTURE.store(style.as_usize(), Ordering::Release);
+}
+
+/// Checks whether the standard library's panic hook will capture and print a
+/// backtrace.
+///
+/// This function will, if a backtrace style has not been set via
+/// [`set_backtrace_style`], read the environment variable `RUST_BACKTRACE` to
+/// determine a default value for the backtrace formatting:
+///
+/// The first call to `get_backtrace_style` may read the `RUST_BACKTRACE`
+/// environment variable if `set_backtrace_style` has not been called to
+/// override the default value. After a call to `set_backtrace_style` or
+/// `get_backtrace_style`, any changes to `RUST_BACKTRACE` will have no effect.
+///
+/// `RUST_BACKTRACE` is read according to these rules:
+///
+/// * `0` for `BacktraceStyle::Off`
+/// * `full` for `BacktraceStyle::Full`
+/// * `1` for `BacktraceStyle::Short`
+/// * Other values are currently `BacktraceStyle::Short`, but this may change in
+///   the future
+///
+/// Returns `None` if backtraces aren't currently supported.
+#[cfg(feature = "backtrace")]
+pub fn get_backtrace_style() -> Option<BacktraceStyle> {
+    BacktraceStyle::from_usize(SHOULD_CAPTURE.load(Ordering::Acquire))
+}
diff --git a/sgx_tstd/src/panicking.rs b/sgx_tstd/src/panicking.rs
index 561a814..9df0b38 100644
--- a/sgx_tstd/src/panicking.rs
+++ b/sgx_tstd/src/panicking.rs
@@ -24,15 +24,24 @@
 //! * Executing a panic up to doing the actual implementation
 //! * Shims around "try"
 
+#![deny(unsafe_op_in_unsafe_fn)]
+
+#[cfg(feature = "backtrace")]
+use crate::panic::BacktraceStyle;
 use core::panic::{BoxMeUp, Location, PanicInfo};
 
 use crate::any::Any;
 use crate::fmt;
 use crate::intrinsics;
 use crate::mem::{self, ManuallyDrop};
-use crate::ptr;
-use crate::sync::atomic::{AtomicPtr, Ordering};
+#[cfg(feature = "backtrace")]
+use crate::sync::atomic::{AtomicBool, Ordering};
+#[cfg(feature = "stdio")]
 use crate::sys::stdio::panic_output;
+#[cfg(feature = "backtrace")]
+use crate::sys_common::backtrace;
+use crate::sys_common::rwlock::SgxThreadRwLock;
+#[cfg(feature = "stdio")]
 use crate::sys_common::thread_info;
 use crate::thread;
 
@@ -76,7 +85,20 @@
     rtabort!("Rust cannot catch foreign exceptions");
 }
 
-static PANIC_HANDLER: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
+#[derive(Copy, Clone)]
+enum Hook {
+    Default,
+    Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
+}
+
+impl Hook {
+    fn custom(f: impl Fn(&PanicInfo<'_>) + 'static + Sync + Send) -> Self {
+        Self::Custom(Box::into_raw(Box::new(f)))
+    }
+}
+
+static HOOK_LOCK: SgxThreadRwLock = SgxThreadRwLock::new();
+static mut HOOK: Hook = Hook::Default;
 
 /// Registers a custom panic hook, replacing any that was previously registered.
 ///
@@ -98,11 +120,43 @@
 ///
 /// Panics if called from a panicking thread.
 ///
-pub fn set_hook(hook: fn(&PanicInfo<'_>)) {
-    assert!(!thread::panicking(), "cannot modify the panic hook from a panicking thread");
-    PANIC_HANDLER.store(hook as *mut (), Ordering::SeqCst);
-}
+/// # Examples
+///
+/// The following will print "Custom panic hook":
+///
+/// ```should_panic
+/// use std::panic;
+///
+/// panic::set_hook(Box::new(|_| {
+///     println!("Custom panic hook");
+/// }));
+///
+/// panic!("Normal panic");
+/// ```
+pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) {
+    if thread::panicking() {
+        panic!("cannot modify the panic hook from a panicking thread");
+    }
 
+    // SAFETY:
+    //
+    // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+    // - The argument of `Box::from_raw` is always a valid pointer that was created using
+    // `Box::into_raw`.
+    unsafe {
+        let _guard = HOOK_LOCK.write();
+        let old_hook = HOOK;
+        HOOK = Hook::Custom(Box::into_raw(hook));
+        let _ = HOOK_LOCK.write_unlock();
+
+        if let Hook::Custom(ptr) = old_hook {
+            #[allow(unused_must_use)]
+            {
+                Box::from_raw(ptr);
+            }
+        }
+    }
+}
 
 /// Unregisters the current panic hook, returning it.
 ///
@@ -115,29 +169,120 @@
 /// # Panics
 ///
 /// Panics if called from a panicking thread.
-/// 
-pub fn take_hook() -> fn(&PanicInfo<'_>) {
-    let hook = PANIC_HANDLER.swap(ptr::null_mut(), Ordering::SeqCst);
-    if hook.is_null() { default_hook } else { unsafe { mem::transmute(hook) } }
+///
+/// # Examples
+///
+/// The following will print "Normal panic":
+///
+/// ```should_panic
+/// use std::panic;
+///
+/// panic::set_hook(Box::new(|_| {
+///     println!("Custom panic hook");
+/// }));
+///
+/// let _ = panic::take_hook();
+///
+/// panic!("Normal panic");
+/// ```
+#[must_use]
+pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
+    if thread::panicking() {
+        panic!("cannot modify the panic hook from a panicking thread");
+    }
+
+    // SAFETY:
+    //
+    // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+    // - The argument of `Box::from_raw` is always a valid pointer that was created using
+    // `Box::into_raw`.
+    unsafe {
+        let _guard = HOOK_LOCK.write();
+        let hook = HOOK;
+        HOOK = Hook::Default;
+        let _ = HOOK_LOCK.write_unlock();
+
+        match hook {
+            Hook::Default => Box::new(default_hook),
+            Hook::Custom(ptr) => Box::from_raw(ptr),
+        }
+    }
+}
+
+/// Atomic combination of [`take_hook`] and [`set_hook`]. Use this to replace the panic handler with
+/// a new panic handler that does something and then executes the old handler.
+///
+/// [`take_hook`]: ./fn.take_hook.html
+/// [`set_hook`]: ./fn.set_hook.html
+///
+/// # Panics
+///
+/// Panics if called from a panicking thread.
+///
+/// # Examples
+///
+/// The following will print the custom message, and then the normal output of panic.
+///
+/// ```should_panic
+/// #![feature(panic_update_hook)]
+/// use std::panic;
+///
+/// // Equivalent to
+/// // let prev = panic::take_hook();
+/// // panic::set_hook(move |info| {
+/// //     println!("...");
+/// //     prev(info);
+/// // );
+/// panic::update_hook(move |prev, info| {
+///     println!("Print custom message and execute panic handler as usual");
+///     prev(info);
+/// });
+///
+/// panic!("Custom and then normal");
+/// ```
+pub fn update_hook<F>(hook_fn: F)
+where
+    F: Fn(&(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static), &PanicInfo<'_>)
+        + Sync
+        + Send
+        + 'static,
+{
+    if thread::panicking() {
+        panic!("cannot modify the panic hook from a panicking thread");
+    }
+
+    // SAFETY:
+    //
+    // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+    // - The argument of `Box::from_raw` is always a valid pointer that was created using
+    // `Box::into_raw`.
+    unsafe {
+        let _guard = HOOK_LOCK.write();
+        let old_hook = HOOK;
+        HOOK = Hook::Default;
+
+        let prev = match old_hook {
+            Hook::Default => Box::new(default_hook),
+            Hook::Custom(ptr) => Box::from_raw(ptr),
+        };
+
+        HOOK = Hook::custom(move |info| hook_fn(&prev, info));
+        let _ = HOOK_LOCK.write_unlock();
+    }
 }
 
 #[cfg(not(feature = "stdio"))]
-#[allow(unused_variables)]
-fn default_hook(info: &PanicInfo<'_>) {}
+fn default_hook(_info: &PanicInfo<'_>) {}
 
 #[cfg(feature = "stdio")]
 fn default_hook(info: &PanicInfo<'_>) {
-    #[cfg(feature = "backtrace")]
-    use crate::sys_common::backtrace::{self, RustBacktrace};
-
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
     #[cfg(feature = "backtrace")]
-    let backtrace_env = if panic_count::get_count() >= 2 {
-        use crate::sys::backtrace::PrintFmt;
-        RustBacktrace::Print(PrintFmt::Full)
+    let backtrace = if panic_count::get_count() >= 2 {
+        BacktraceStyle::full()
     } else {
-        backtrace::rust_backtrace_env()
+        crate::panic::get_backtrace_style()
     };
 
     // The current implementation always returns `Some`.
@@ -156,14 +301,18 @@
     let write = |err: &mut dyn crate::io::Write| {
         let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location);
 
-        #[cfg(feature = "backtrace")] {
-            use crate::sync::atomic::AtomicBool;
+        #[cfg(feature = "backtrace")]
+        {
             static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
-            match backtrace_env {
-                RustBacktrace::Print(format) => drop(backtrace::print(err, format)),
-                RustBacktrace::Disabled => {}
-                RustBacktrace::RuntimeDisabled => {
+            match backtrace {
+                Some(BacktraceStyle::Short) => {
+                    drop(backtrace::print(err, crate::sys::backtrace::PrintFmt::Short))
+                }
+                Some(BacktraceStyle::Full) => {
+                    drop(backtrace::print(err, crate::sys::backtrace::PrintFmt::Full))
+                }
+                Some(BacktraceStyle::Off) => {
                     if FIRST_PANIC.swap(false, Ordering::SeqCst) {
                         let _ = writeln!(
                             err,
@@ -171,6 +320,8 @@
                         );
                     }
                 }
+                // If backtraces aren't supported, do nothing.
+                None => {}
             }
         }
     };
@@ -180,13 +331,6 @@
     }
 }
 
-fn panic_handler(info: &PanicInfo<'_>) {
-    let hook = PANIC_HANDLER.load(Ordering::SeqCst);
-    let handler: fn(&PanicInfo<'_>) =
-        if hook.is_null() { default_hook } else { unsafe { mem::transmute(hook) } };
-    handler(info);
-}
-
 #[doc(hidden)]
 pub mod panic_count {
     use crate::cell::Cell;
@@ -318,12 +462,14 @@
     // The call to `intrinsics::r#try` is made safe by:
     // - `do_call`, the first argument, can be called with the initial `data_ptr`.
     // - `do_catch`, the second argument, can be called with the `data_ptr` as well.
-    // See their safety preconditions for more informations
-    return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
-        Ok(ManuallyDrop::into_inner(data.r))
-    } else {
-        Err(ManuallyDrop::into_inner(data.p))
-    };
+    // See their safety preconditions for more information
+    unsafe {
+        return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
+            Ok(ManuallyDrop::into_inner(data.r))
+        } else {
+            Err(ManuallyDrop::into_inner(data.p))
+        };
+    }
 
     // We consider unwinding to be rare, so mark this function as cold. However,
     // do not mark it no-inline -- that decision is best to leave to the
@@ -335,7 +481,7 @@
         // the panic handler `__rust_panic_cleanup`. As such we can only
         // assume it returns the correct thing for `Box::from_raw` to work
         // without undefined behavior.
-        let obj = Box::from_raw(__rust_panic_cleanup(payload));
+        let obj = unsafe { Box::from_raw(__rust_panic_cleanup(payload)) };
         panic_count::decrease();
         obj
     }
@@ -349,7 +495,7 @@
     // expects normal function pointers.
     #[inline]
     fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
-        // SAFETY: this is the responsibilty of the caller, see above.
+        // SAFETY: this is the responsibility of the caller, see above.
         unsafe {
             let data = data as *mut Data<F, R>;
             let data = &mut (*data);
@@ -371,7 +517,7 @@
     // expects normal function pointers.
     #[inline]
     fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
-        // SAFETY: this is the responsibilty of the caller, see above.
+        // SAFETY: this is the responsibility of the caller, see above.
         //
         // When `__rustc_panic_cleaner` is correctly implemented we can rely
         // on `obj` being the correct thing to pass to `data.p` (after wrapping
@@ -446,20 +592,32 @@
 
     let loc = info.location().unwrap(); // The current implementation always returns Some
     let msg = info.message().unwrap(); // The current implementation always returns Some
-    #[cfg(feature = "backtrace")] {
+    #[cfg(feature = "backtrace")]
+    {
         crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
             if let Some(msg) = msg.as_str() {
-                rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
+                rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
             } else {
-                rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+                rust_panic_with_hook(
+                    &mut PanicPayload::new(msg),
+                    info.message(),
+                    loc,
+                    info.can_unwind(),
+                );
             }
         })
     }
-    #[cfg(not(feature = "backtrace"))] {
+    #[cfg(not(feature = "backtrace"))]
+    {
         if let Some(msg) = msg.as_str() {
-            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
+            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
         } else {
-            rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+            rust_panic_with_hook(
+                &mut PanicPayload::new(msg),
+                info.message(),
+                loc,
+                info.can_unwind(),
+            );
         }
     }
 }
@@ -474,7 +632,8 @@
 #[inline(never)]
 #[cold]
 #[track_caller]
-pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
     struct PanicPayload<A> {
         inner: Option<A>,
     }
@@ -510,11 +669,11 @@
     let loc = Location::caller();
     #[cfg(feature = "backtrace")] {
         crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
-            rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
+            rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true)
         })
     }
     #[cfg(not(feature = "backtrace"))] {
-        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
+        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true)
     }
 }
 
@@ -527,6 +686,7 @@
     payload: &mut dyn BoxMeUp,
     message: Option<&fmt::Arguments<'_>>,
     location: &Location<'_>,
+    can_unwind: bool,
 ) -> ! {
     let (must_abort, panics) = panic_count::increase();
 
@@ -543,17 +703,37 @@
         } else {
             // Unfortunately, this does not print a backtrace, because creating
             // a `Backtrace` will allocate, which we must to avoid here.
-            let panicinfo = PanicInfo::internal_constructor(message, location);
+            let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
             rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
         }
         rsgx_abort()
     }
 
-    let mut info = PanicInfo::internal_constructor(message, location);
-    info.set_payload(payload.get());
-    panic_handler(&info);
+    unsafe {
+        let mut info = PanicInfo::internal_constructor(message, location, can_unwind);
+        let _guard = HOOK_LOCK.read();
+        match HOOK {
+            // Some platforms (like wasm) know that printing to stderr won't ever actually
+            // print anything, and if that's the case we can skip the default
+            // hook. Since string formatting happens lazily when calling `payload`
+            // methods, this means we avoid formatting the string at all!
+            // (The panic runtime might still call `payload.take_box()` though and trigger
+            // formatting.)
+            #[cfg(feature = "stdio")]
+            Hook::Default if panic_output().is_none() => {}
+            Hook::Default => {
+                info.set_payload(payload.get());
+                default_hook(&info);
+            }
+            Hook::Custom(ptr) => {
+                info.set_payload(payload.get());
+                (*ptr)(&info);
+            }
+        };
+        let _ = HOOK_LOCK.read_unlock();
+    }
 
-    if panics > 1 {
+    if panics > 1 || !can_unwind {
         // If a thread panics while it's already unwinding then we
         // have limited options. Currently our preference is to
         // just abort. In the future we may consider resuming
diff --git a/sgx_tstd/src/path.rs b/sgx_tstd/src/path.rs
index 3b2d6f3..ac7726c 100644
--- a/sgx_tstd/src/path.rs
+++ b/sgx_tstd/src/path.rs
@@ -29,6 +29,13 @@
 //! [`PathBuf`]; note that the paths may differ syntactically by the
 //! normalization described in the documentation for the [`components`] method.
 //!
+//! ## Case sensitivity
+//!
+//! Unless otherwise indicated path methods that do not access the filesystem,
+//! such as [`Path::starts_with`] and [`Path::ends_with`], are case sensitive no
+//! matter the platform or filesystem. An exception to this is made for Windows
+//! drive letters.
+//!
 //! ## Simple usage
 //!
 //! Path manipulation includes both parsing components from slices and building
@@ -78,12 +85,12 @@
 
 use crate::borrow::{Borrow, Cow};
 use crate::cmp;
+use crate::collections::TryReserveError;
 use crate::error::Error;
 use crate::fmt;
 #[cfg(feature = "untrusted_fs")]
 use crate::fs;
 use crate::hash::{Hash, Hasher};
-#[cfg(feature = "untrusted_fs")]
 use crate::io;
 use crate::iter::{self, FusedIterator};
 use crate::ops::{self, Deref};
@@ -92,7 +99,7 @@
 use crate::sync::Arc;
 
 use crate::ffi::{OsStr, OsString};
-
+use crate::sys;
 use crate::sys::path::{is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -132,6 +139,18 @@
 ///     }
 /// }
 ///
+/// # if cfg!(windows) {
+/// assert_eq!(Verbatim(OsStr::new("pictures")),
+///            get_path_prefix(r"\\?\pictures\kittens"));
+/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")),
+///            get_path_prefix(r"\\?\UNC\server\share"));
+/// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\c:\"));
+/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")),
+///            get_path_prefix(r"\\.\BrainInterface"));
+/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")),
+///            get_path_prefix(r"\\server\share"));
+/// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris"));
+/// # }
 /// ```
 #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
 pub enum Prefix<'a> {
@@ -247,6 +266,11 @@
 /// For example, `/` on Unix and `\` on Windows.
 pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP;
 
+/// The primary separator of path components for the current platform.
+///
+/// For example, `/` on Unix and `\` on Windows.
+pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR;
+
 ////////////////////////////////////////////////////////////////////////////////
 // Misc helpers
 ////////////////////////////////////////////////////////////////////////////////
@@ -929,6 +953,25 @@
 impl<'a> cmp::PartialEq for Components<'a> {
     #[inline]
     fn eq(&self, other: &Components<'a>) -> bool {
+        let Components { path: _, front: _, back: _, has_physical_root: _, prefix: _ } = self;
+
+        // Fast path for exact matches, e.g. for hashmap lookups.
+        // Don't explicitly compare the prefix or has_physical_root fields since they'll
+        // either be covered by the `path` buffer or are only relevant for `prefix_verbatim()`.
+        if self.path.len() == other.path.len()
+            && self.front == other.front
+            && self.back == State::Body
+            && other.back == State::Body
+            && self.prefix_verbatim() == other.prefix_verbatim()
+        {
+            // possible future improvement: this could bail out earlier if there were a
+            // reverse memcmp/bcmp comparing back to front
+            if self.path == other.path {
+                return true;
+            }
+        }
+
+        // compare back to front since absolute paths often share long prefixes
         Iterator::eq(self.clone().rev(), other.clone().rev())
     }
 }
@@ -960,13 +1003,12 @@
     // The fast path isn't taken for paths with a PrefixComponent to avoid backtracking into
     // the middle of one
     if left.prefix.is_none() && right.prefix.is_none() && left.front == right.front {
-        // this might benefit from a [u8]::first_mismatch simd implementation, if it existed
-        let first_difference =
-            match left.path.iter().zip(right.path.iter()).position(|(&a, &b)| a != b) {
-                None if left.path.len() == right.path.len() => return cmp::Ordering::Equal,
-                None => left.path.len().min(right.path.len()),
-                Some(diff) => diff,
-            };
+        // possible future improvement: a [u8]::first_mismatch simd implementation
+        let first_difference = match left.path.iter().zip(right.path).position(|(&a, &b)| a != b) {
+            None if left.path.len() == right.path.len() => return cmp::Ordering::Equal,
+            None => left.path.len().min(right.path.len()),
+            Some(diff) => diff,
+        };
 
         if let Some(previous_sep) =
             left.path[..first_difference].iter().rposition(|&b| left.is_sep_byte(b))
@@ -1420,6 +1462,14 @@
         self.inner.reserve(additional)
     }
 
+    /// Invokes [`try_reserve`] on the underlying instance of [`OsString`].
+    ///
+    /// [`try_reserve`]: OsString::try_reserve
+    #[inline]
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.inner.try_reserve(additional)
+    }
+
     /// Invokes [`reserve_exact`] on the underlying instance of [`OsString`].
     ///
     /// [`reserve_exact`]: OsString::reserve_exact
@@ -1428,6 +1478,14 @@
         self.inner.reserve_exact(additional)
     }
 
+    /// Invokes [`try_reserve_exact`] on the underlying instance of [`OsString`].
+    ///
+    /// [`try_reserve_exact`]: OsString::try_reserve_exact
+    #[inline]
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.inner.try_reserve_exact(additional)
+    }
+
     /// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`].
     ///
     /// [`shrink_to_fit`]: OsString::shrink_to_fit
@@ -1482,7 +1540,7 @@
 }
 
 impl From<Box<Path>> for PathBuf {
-    /// Converts a `Box<Path>` into a `PathBuf`
+    /// Converts a <code>[Box]&lt;[Path]&gt;</code> into a [`PathBuf`].
     ///
     /// This conversion does not allocate or copy memory.
     #[inline]
@@ -1492,7 +1550,7 @@
 }
 
 impl From<PathBuf> for Box<Path> {
-    /// Converts a `PathBuf` into a `Box<Path>`
+    /// Converts a [`PathBuf`] into a <code>[Box]&lt;[Path]&gt;</code>.
     ///
     /// This conversion currently should not allocate memory,
     /// but this behavior is not guaranteed on all platforms or in all future versions.
@@ -1510,7 +1568,7 @@
 }
 
 impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
-    /// Converts a borrowed `OsStr` to a `PathBuf`.
+    /// Converts a borrowed [`OsStr`] to a [`PathBuf`].
     ///
     /// Allocates a [`PathBuf`] and copies the data into it.
     #[inline]
@@ -1649,7 +1707,8 @@
 }
 
 impl From<PathBuf> for Arc<Path> {
-    /// Converts a [`PathBuf`] into an [`Arc`] by moving the [`PathBuf`] data into a new [`Arc`] buffer.
+    /// Converts a [`PathBuf`] into an <code>[Arc]<[Path]></code> by moving the [`PathBuf`] data
+    /// into a new [`Arc`] buffer.
     #[inline]
     fn from(s: PathBuf) -> Arc<Path> {
         let arc: Arc<OsStr> = Arc::from(s.into_os_string());
@@ -1667,7 +1726,8 @@
 }
 
 impl From<PathBuf> for Rc<Path> {
-    /// Converts a [`PathBuf`] into an [`Rc`] by moving the [`PathBuf`] data into a new `Rc` buffer.
+    /// Converts a [`PathBuf`] into an <code>[Rc]<[Path]></code> by moving the [`PathBuf`] data into
+    /// a new [`Rc`] buffer.
     #[inline]
     fn from(s: PathBuf) -> Rc<Path> {
         let rc: Rc<OsStr> = Rc::from(s.into_os_string());
@@ -1676,7 +1736,7 @@
 }
 
 impl From<&Path> for Rc<Path> {
-    /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new `Rc` buffer.
+    /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer.
     #[inline]
     fn from(s: &Path) -> Rc<Path> {
         let rc: Rc<OsStr> = Rc::from(s.as_os_str());
@@ -2551,7 +2611,7 @@
     /// This function will traverse symbolic links to query information about the
     /// destination file. In case of broken symbolic links this will return `Ok(false)`.
     ///
-    /// As opposed to the `exists()` method, this one doesn't silently ignore errors
+    /// As opposed to the [`exists()`] method, this one doesn't silently ignore errors
     /// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
     /// denied on some of the parent directories.)
     ///
@@ -2564,6 +2624,8 @@
     /// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt"));
     /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
     /// ```
+    ///
+    /// [`exists()`]: Self::exists
     // FIXME: stabilization should modify documentation of `exists()` to recommend this method
     // instead.
     #[cfg(feature = "untrusted_fs")]
@@ -2644,12 +2706,11 @@
     ///
     #[cfg_attr(unix, doc = "```no_run")]
     #[cfg_attr(not(unix), doc = "```ignore")]
-    /// #![feature(is_symlink)]
     /// use std::path::Path;
     /// use std::os::unix::fs::symlink;
     ///
     /// let link_path = Path::new("link");
-    /// symlink("/origin_does_not_exists/", link_path).unwrap();
+    /// symlink("/origin_does_not_exist/", link_path).unwrap();
     /// assert_eq!(link_path.is_symlink(), true);
     /// assert_eq!(link_path.exists(), false);
     /// ```
@@ -2733,9 +2794,51 @@
 
 impl Hash for Path {
     fn hash<H: Hasher>(&self, h: &mut H) {
-        for component in self.components() {
-            component.hash(h);
+        let bytes = self.as_u8_slice();
+        let (prefix_len, verbatim) = match parse_prefix(&self.inner) {
+            Some(prefix) => {
+                prefix.hash(h);
+                (prefix.len(), prefix.is_verbatim())
+            }
+            None => (0, false),
+        };
+        let bytes = &bytes[prefix_len..];
+
+        let mut component_start = 0;
+        let mut bytes_hashed = 0;
+
+        for i in 0..bytes.len() {
+            let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) };
+            if is_sep {
+                if i > component_start {
+                    let to_hash = &bytes[component_start..i];
+                    h.write(to_hash);
+                    bytes_hashed += to_hash.len();
+                }
+
+                // skip over separator and optionally a following CurDir item
+                // since components() would normalize these away.
+                component_start = i + 1;
+
+                let tail = &bytes[component_start..];
+
+                if !verbatim {
+                    component_start += match tail {
+                        [b'.'] => 1,
+                        [b'.', sep, ..] if is_sep_byte(*sep) => 1,
+                        _ => 0,
+                    };
+                }
+            }
         }
+
+        if component_start < bytes.len() {
+            let to_hash = &bytes[component_start..];
+            h.write(to_hash);
+            bytes_hashed += to_hash.len();
+        }
+
+        h.write_usize(bytes_hashed);
     }
 }
 
@@ -2920,3 +3023,83 @@
         "prefix not found"
     }
 }
+
+/// Makes the path absolute without accessing the filesystem.
+///
+/// If the path is relative, the current directory is used as the base directory.
+/// All intermediate components will be resolved according to platforms-specific
+/// rules but unlike [`canonicalize`][crate::fs::canonicalize] this does not
+/// resolve symlinks and may succeed even if the path does not exist.
+///
+/// If the `path` is empty or getting the
+/// [current directory][crate::env::current_dir] fails then an error will be
+/// returned.
+///
+/// # Examples
+///
+/// ## Posix paths
+///
+/// ```
+/// #![feature(absolute_path)]
+/// # #[cfg(unix)]
+/// fn main() -> std::io::Result<()> {
+///   use std::path::{self, Path};
+///
+///   // Relative to absolute
+///   let absolute = path::absolute("foo/./bar")?;
+///   assert!(absolute.ends_with("foo/bar"));
+///
+///   // Absolute to absolute
+///   let absolute = path::absolute("/foo//test/.././bar.rs")?;
+///   assert_eq!(absolute, Path::new("/foo/test/../bar.rs"));
+///   Ok(())
+/// }
+/// # #[cfg(not(unix))]
+/// # fn main() {}
+/// ```
+///
+/// The path is resolved using [POSIX semantics][posix-semantics] except that
+/// it stops short of resolving symlinks. This means it will keep `..`
+/// components and trailing slashes.
+///
+/// ## Windows paths
+///
+/// ```
+/// #![feature(absolute_path)]
+/// # #[cfg(windows)]
+/// fn main() -> std::io::Result<()> {
+///   use std::path::{self, Path};
+///
+///   // Relative to absolute
+///   let absolute = path::absolute("foo/./bar")?;
+///   assert!(absolute.ends_with(r"foo\bar"));
+///
+///   // Absolute to absolute
+///   let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?;
+///
+///   assert_eq!(absolute, Path::new(r"C:\foo\bar.rs"));
+///   Ok(())
+/// }
+/// # #[cfg(not(windows))]
+/// # fn main() {}
+/// ```
+///
+/// For verbatim paths this will simply return the path as given. For other
+/// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
+/// This may change in the future.
+///
+/// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+/// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
+#[cfg(feature = "untrusted_fs")]
+pub fn absolute<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    _absolute(path)
+}
+
+pub(crate) fn _absolute<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    let path = path.as_ref();
+    if path.as_os_str().is_empty() {
+        Err(io::const_io_error!(io::ErrorKind::InvalidInput, "cannot make an empty path absolute",))
+    } else {
+        sys::path::absolute(path)
+    }
+}
diff --git a/sgx_tstd/src/prelude/v1.rs b/sgx_tstd/src/prelude/v1.rs
index 3ac7da0..756a2c2 100644
--- a/sgx_tstd/src/prelude/v1.rs
+++ b/sgx_tstd/src/prelude/v1.rs
@@ -46,25 +46,23 @@
 #[doc(no_inline)]
 pub use core::prelude::v1::{
     assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
-    format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
-    option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq,
-    PartialOrd,
+    format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
+    stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
 };
 
-// FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates
-// dead links which fail link checker testing.
-#[allow(deprecated, deprecated_in_future)]
-#[doc(hidden)]
-pub use core::prelude::v1::{
-    global_allocator, test, test_case, RustcDecodable, RustcEncodable,
-};
+#[doc(no_inline)]
+pub use core::prelude::v1::concat_bytes;
 
-#[doc(hidden)]
-pub use core::prelude::v1::derive;
-#[doc(hidden)]
+#[allow(deprecated)]
+pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
+
+// Do not `doc(no_inline)` so that they become doc items on their own
+// (no public module for them to be re-exported from).
+pub use core::prelude::v1::{derive, global_allocator, test, test_case};
+
+// Do not `doc(no_inline)` either.
 pub use core::prelude::v1::cfg_accessible;
 
-#[doc(hidden)]
 pub use core::prelude::v1::cfg_eval;
 
 // The file so far is equivalent to src/libcore/prelude/v1.rs,
diff --git a/sgx_tstd/src/rt.rs b/sgx_tstd/src/rt.rs
index cebae78..3104350 100644
--- a/sgx_tstd/src/rt.rs
+++ b/sgx_tstd/src/rt.rs
@@ -37,6 +37,7 @@
 // - the standard error output
 // - some dedicated platform specific output
 // - nothing (so this macro is a no-op)
+#[cfg(feature = "stdio")]
 macro_rules! rtprintpanic {
     ($($t:tt)*) => {
         if let Some(mut out) = crate::sys::stdio::panic_output() {
@@ -45,6 +46,13 @@
     }
 }
 
+#[cfg(not(feature = "stdio"))]
+macro_rules! rtprintpanic {
+    ($($t:tt)*) => {
+        format_args!($($t)*);
+    }
+}
+
 macro_rules! rtabort {
     ($($t:tt)*) => {
         {
@@ -118,7 +126,7 @@
 
 // One-time runtime cleanup.
 // NOTE: this is not guaranteed to run, for example when the program aborts.
-fn cleanup() {
+pub (crate) fn cleanup() {
     static CLEANUP: Once = Once::new();
     CLEANUP.call_once(|| {
         // Flush stdout and disable buffering.
diff --git a/sgx_tstd/src/sgxfs.rs b/sgx_tstd/src/sgxfs.rs
index ffacfad..2a702c0 100644
--- a/sgx_tstd/src/sgxfs.rs
+++ b/sgx_tstd/src/sgxfs.rs
@@ -17,7 +17,7 @@
 
 //! Filesystem manipulation operations.
 
-use crate::io::{self, SeekFrom, Seek, Read, Initializer, Write};
+use crate::io::{self, SeekFrom, Seek, Read, Write};
 use crate::path::Path;
 use crate::sys::sgxfs as fs_imp;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@@ -157,11 +157,6 @@
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl Write for SgxFile {
@@ -181,11 +176,6 @@
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl<'a> Write for &'a SgxFile {
diff --git a/sgx_tstd/src/sync/mpsc/mod.rs b/sgx_tstd/src/sync/mpsc/mod.rs
index 805deb1..55fd9a0 100644
--- a/sgx_tstd/src/sync/mpsc/mod.rs
+++ b/sgx_tstd/src/sync/mpsc/mod.rs
@@ -435,12 +435,13 @@
 }
 
 /// An owning iterator over messages on a [`Receiver`],
-/// created by **Receiver::into_iter**.
+/// created by [`into_iter`].
 ///
 /// This iterator will block whenever [`next`]
 /// is called, waiting for a new message, and [`None`] will be
 /// returned if the corresponding channel has hung up.
 ///
+/// [`into_iter`]: Receiver::into_iter
 /// [`next`]: Iterator::next
 ///
 /// # Examples
diff --git a/sgx_tstd/src/sync/mutex.rs b/sgx_tstd/src/sync/mutex.rs
index 0bba39c..6cbf87a 100644
--- a/sgx_tstd/src/sync/mutex.rs
+++ b/sgx_tstd/src/sync/mutex.rs
@@ -213,6 +213,9 @@
 /// [`lock`]: Mutex::lock
 /// [`try_lock`]: Mutex::try_lock
 #[must_use = "if unused the Mutex will immediately unlock"]
+#[must_not_suspend = "holding a MutexGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
 pub struct SgxMutexGuard<'a, T: ?Sized + 'a> {
     lock: &'a SgxMutex<T>,
     poison: poison::Guard,
diff --git a/sgx_tstd/src/sync/once.rs b/sgx_tstd/src/sync/once.rs
index 262dc81..999b47d 100644
--- a/sgx_tstd/src/sync/once.rs
+++ b/sgx_tstd/src/sync/once.rs
@@ -104,6 +104,7 @@
 use crate::cell::Cell;
 use crate::fmt;
 use crate::marker;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
 use crate::thread::{self, SgxThread as Thread};
 
@@ -134,6 +135,10 @@
 unsafe impl Sync for Once {}
 unsafe impl Send for Once {}
 
+impl UnwindSafe for Once {}
+
+impl RefUnwindSafe for Once {}
+
 /// State yielded to [`Once::call_once_force()`]’s closure parameter. The state
 /// can be used to query the poison status of the [`Once`].
 #[derive(Debug)]
diff --git a/sgx_tstd/src/sync/remutex.bak.rs b/sgx_tstd/src/sync/remutex.bak.rs
deleted file mode 100644
index 6e2aafb..0000000
--- a/sgx_tstd/src/sync/remutex.bak.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License..
-
-
-use alloc_crate::boxed::Box;
-use core::fmt;
-use core::ops::Deref;
-use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
-use crate::sys_common::remutex as sys;
-
-pub use crate::sys_common::remutex::SgxReentrantThreadMutex;
-
-
-/// A re-entrant mutual exclusion
-///
-/// This mutex will block *other* threads waiting for the lock to become
-/// available. The thread which has already locked the mutex can lock it
-/// multiple times without blocking, preventing a common source of deadlocks.
-pub struct SgxReentrantMutex<T> {
-    inner: Box<sys::SgxReentrantThreadMutex>,
-    poison: poison::Flag,
-    data: T,
-}
-
-unsafe impl<T: Send> Send for SgxReentrantMutex<T> {}
-unsafe impl<T: Send> Sync for SgxReentrantMutex<T> {}
-
-impl<T> SgxReentrantMutex<T> {
-    /// Creates a new reentrant mutex in an unlocked state.
-    pub fn new(t: T) -> SgxReentrantMutex<T> {
-        SgxReentrantMutex{
-            inner: Box::new(sys::SgxReentrantThreadMutex::new()),
-            poison: poison::Flag::new(),
-            data: t,
-        }
-    }
-
-    /// Acquires a mutex, blocking the current thread until it is able to do so.
-    ///
-    /// This function will block the caller until it is available to acquire the mutex.
-    /// Upon returning, the thread is the only thread with the mutex held. When the thread
-    /// calling this method already holds the lock, the call shall succeed without
-    /// blocking.
-    ///
-    /// # Errors
-    ///
-    /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return failure if the mutex would otherwise be
-    /// acquired.
-    pub fn lock(&self) -> LockResult<SgxReentrantMutexGuard<'_, T>> {
-        unsafe {
-            self.inner.lock();
-            SgxReentrantMutexGuard::new(self)
-        }
-    }
-
-    /// Attempts to acquire this lock.
-    ///
-    /// If the lock could not be acquired at this time, then `Err` is returned.
-    /// Otherwise, an RAII guard is returned.
-    ///
-    /// This function does not block.
-    ///
-    /// # Errors
-    ///
-    /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return failure if the mutex would otherwise be
-    /// acquired.
-    pub fn try_lock(&self) -> TryLockResult<SgxReentrantMutexGuard<'_, T>> {
-        unsafe {
-            match self.inner.try_lock() {
-                Ok(_) => Ok(SgxReentrantMutexGuard::new(self)?),
-                Err(_) => Err(TryLockError::WouldBlock),
-            }
-        }
-    }
-}
-
-impl<T> Drop for SgxReentrantMutex<T> {
-    fn drop(&mut self) {
-        // This is actually safe b/c we know that there is no further usage of
-        // this mutex (it's up to the user to arrange for a mutex to get
-        // dropped, that's not our job)
-        let result = unsafe { self.inner.destroy() };
-        debug_assert_eq!(result, Ok(()), "Error when destroy an SgxReentrantMutex: {}", result.unwrap_err());
-    }
-}
-
-impl<T: fmt::Debug + 'static> fmt::Debug for SgxReentrantMutex<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.try_lock() {
-            Ok(guard) => f.debug_struct("SgxReentrantMutex").field("data", &*guard).finish(),
-            Err(TryLockError::Poisoned(err)) => {
-                f.debug_struct("SgxReentrantMutex").field("data", &**err.get_ref()).finish()
-            },
-            Err(TryLockError::WouldBlock) => {
-                struct LockedPlaceholder;
-                impl fmt::Debug for LockedPlaceholder {
-                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                        f.write_str("<locked>")
-                    }
-                }
-
-                f.debug_struct("SgxReentrantMutex").field("data", &LockedPlaceholder).finish()
-            }
-        }
-    }
-}
-
-/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
-/// dropped (falls out of scope), the lock will be unlocked.
-///
-/// The data protected by the mutex can be accessed through this guard via its
-/// Deref implementation.
-///
-/// # Mutability
-///
-/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
-/// because implementation of the trait would violate Rust’s reference aliasing
-/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
-/// guarded data.
-#[must_use]
-pub struct SgxReentrantMutexGuard<'a, T: 'a> {
-    // funny underscores due to how Deref currently works (it disregards field
-    // privacy).
-    lock: &'a SgxReentrantMutex<T>,
-    poison: poison::Guard,
-}
-
-impl<T> !Send for SgxReentrantMutexGuard<'_, T> {}
-
-impl<'mutex, T> SgxReentrantMutexGuard<'mutex, T> {
-    fn new(lock: &'mutex SgxReentrantMutex<T>) -> LockResult<SgxReentrantMutexGuard<'mutex, T>> {
-        poison::map_result(lock.poison.borrow(), |guard| {
-            SgxReentrantMutexGuard {
-                lock: lock,
-                poison: guard,
-            }
-        })
-    }
-}
-
-impl<T> Deref for SgxReentrantMutexGuard<'_, T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        &self.lock.data
-    }
-}
-
-impl<T> Drop for SgxReentrantMutexGuard<'_, T> {
-    #[inline]
-    fn drop(&mut self) {
-        let result = unsafe {
-            self.lock.poison.done(&self.poison);
-            self.lock.inner.unlock()
-        };
-        debug_assert_eq!(result, Ok(()), "Error when unlocking an SgxReentrantMutex: {}", result.unwrap_err());
-    }
-}
-
-impl<T: fmt::Debug> fmt::Debug for SgxReentrantMutexGuard<'_, T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(&**self, f)
-    }
-}
-
-impl<T: fmt::Display> fmt::Display for SgxReentrantMutexGuard<'_, T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        (**self).fmt(f)
-    }
-}
diff --git a/sgx_tstd/src/sys/backtrace/mod.rs b/sgx_tstd/src/sys/backtrace/mod.rs
index 9e6dc80..f26ea11 100644
--- a/sgx_tstd/src/sys/backtrace/mod.rs
+++ b/sgx_tstd/src/sys/backtrace/mod.rs
@@ -138,7 +138,7 @@
     pub fn get_enclave_filename() -> io::Result<Vec<u8>> {
         let p = enclave::get_enclave_path();
         let result = match p {
-            None => Err(Error::new(ErrorKind::Other, "Not implemented")),
+            None => Err(Error::new(ErrorKind::Other, "no enclave path found")),
             Some(path) => {
                 let cstr = CString::new(path.as_os_str().as_bytes())?;
                 let v = unsafe { mem::transmute(cstr.into_bytes_with_nul()) };
diff --git a/sgx_tstd/src/sys/fd.rs b/sgx_tstd/src/sys/fd.rs
index cac6135..f38a9e4 100644
--- a/sgx_tstd/src/sys/fd.rs
+++ b/sgx_tstd/src/sys/fd.rs
@@ -16,7 +16,7 @@
 // under the License..
 
 use crate::cmp;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
+use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -66,27 +66,36 @@
     }
 
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        unsafe fn cvt_pread64(
-            fd: c_int,
-            buf: *mut c_void,
-            count: usize,
-            offset: i64,
-        ) -> io::Result<isize> {
-            use libc::pread64;
-            cvt(pread64(fd, buf, count, offset))
-        }
+        use libc::pread64;
 
         unsafe {
-            cvt_pread64(
+            cvt(pread64(
                 self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut c_void,
                 cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
-            )
+            ))
             .map(|n| n as usize)
         }
     }
 
+    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        let ret = cvt(unsafe {
+            libc::read(
+                self.as_raw_fd(),
+                buf.unfilled_mut().as_mut_ptr() as *mut c_void,
+                cmp::min(buf.remaining(), READ_LIMIT),
+            )
+        })?;
+
+        // Safety: `ret` bytes were written to the initialized portion of the buffer
+        unsafe {
+            buf.assume_init(ret as usize);
+        }
+        buf.add_filled(ret as usize);
+        Ok(())
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             libc::write(
@@ -115,23 +124,15 @@
     }
 
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        unsafe fn cvt_pwrite64(
-            fd: c_int,
-            buf: *const c_void,
-            count: usize,
-            offset: i64,
-        ) -> io::Result<isize> {
-            use libc::pwrite64;
-            cvt(pwrite64(fd, buf, count, offset))
-        }
+        use libc::pwrite64;
 
         unsafe {
-            cvt_pwrite64(
+            cvt(pwrite64(
                 self.as_raw_fd(),
                 buf.as_ptr() as *const c_void,
                 cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
-            )
+            ))
             .map(|n| n as usize)
         }
     }
@@ -159,12 +160,9 @@
         }
     }
 
+    #[inline]
     pub fn duplicate(&self) -> io::Result<FileDesc> {
-        // We want to atomically duplicate this file descriptor and set the
-        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
-        // is a POSIX flag that was added to Linux in 2.6.24.
-        let fd = cvt(unsafe { libc::fcntl_arg1(self.as_raw_fd(), libc::F_DUPFD_CLOEXEC, 0) })?;
-        Ok(unsafe { FileDesc::from_raw_fd(fd) })
+        Ok(Self(self.0.try_clone()?))
     }
 }
 
@@ -172,11 +170,6 @@
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         (**self).read(buf)
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl AsInner<OwnedFd> for FileDesc {
diff --git a/sgx_tstd/src/sys/fs.rs b/sgx_tstd/src/sys/fs.rs
index 3e8daf3..bcebf72 100644
--- a/sgx_tstd/src/sys/fs.rs
+++ b/sgx_tstd/src/sys/fs.rs
@@ -19,7 +19,7 @@
 
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
-use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 use crate::mem;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
 use crate::path::{Path, PathBuf};
@@ -29,11 +29,10 @@
 use crate::sys::time::SystemTime;
 use crate::sys::{cvt, cvt_r};
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
-use crate::untrusted::fs;
 
-use sgx_libc::{c_int, dirent64, mode_t, off64_t, stat64};
+use sgx_libc::{c_int, dirent64, mode_t, off64_t, stat64, time_t};
 
-pub use crate::sys_common::fs::{remove_dir_all, try_exists};
+pub use crate::sys_common::fs::try_exists;
 
 pub struct File(FileDesc);
 
@@ -115,22 +114,22 @@
 impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_mtime as libc::time_t,
+            tv_sec: self.stat.st_mtime as time_t,
             tv_nsec: self.stat.st_mtime_nsec as _,
         }))
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_atime as libc::time_t,
+            tv_sec: self.stat.st_atime as time_t,
             tv_nsec: self.stat.st_atime_nsec as _,
         }))
     }
 
     pub fn created(&self) -> io::Result<SystemTime> {
-        Err(io::Error::new_const(
+        Err(io::const_io_error!(
             io::ErrorKind::Unsupported,
-            &"creation time is not available on this platform \
+            "creation time is not available on this platform \
                             currently",
         ))
     }
@@ -235,16 +234,16 @@
 
 impl DirEntry {
     pub fn path(&self) -> PathBuf {
-        self.dir.root.join(OsStr::from_bytes(self.name_bytes()))
+        self.dir.root.join(self.file_name_os_str())
     }
 
     pub fn file_name(&self) -> OsString {
-        OsStr::from_bytes(self.name_bytes()).to_os_string()
+        self.file_name_os_str().to_os_string()
     }
 
     pub fn metadata(&self) -> io::Result<FileAttr> {
         let fd = cvt(unsafe { libc::dirfd(self.dir.dirp.0) })?;
-        let name = self.entry.d_name.as_ptr();
+        let name = self.name_cstr().as_ptr();
         let mut stat: stat64 = unsafe { mem::zeroed() };
         cvt(unsafe { libc::fstatat64(fd, name, &mut stat, libc::AT_SYMLINK_NOFOLLOW) })?;
         Ok(FileAttr::from_stat64(stat))
@@ -259,7 +258,7 @@
             libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }),
             libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }),
             libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }),
-            _ => lstat(&self.path()).map(|m| m.file_type()),
+            _ => self.metadata().map(|m| m.file_type()),
         }
     }
 
@@ -271,6 +270,10 @@
         unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() }
     }
 
+    fn name_cstr(&self) -> &CStr {
+        unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
+    }
+
     pub fn file_name_os_str(&self) -> &OsStr {
         OsStr::from_bytes(self.name_bytes())
     }
@@ -401,7 +404,7 @@
     pub fn truncate(&self, size: u64) -> io::Result<()> {
         use crate::convert::TryInto;
         let size: off64_t =
-                size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
+            size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
         cvt_r(|| unsafe { libc::ftruncate64(self.as_raw_fd(), size) }).map(drop)
     }
 
@@ -422,6 +425,10 @@
         self.0.read_at(buf, offset)
     }
 
+    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
@@ -577,7 +584,10 @@
             Err(Error::last_os_error())
         } else {
             let inner = InnerReadDir { dirp: Dir(ptr), root };
-            Ok(ReadDir { inner: Arc::new(inner), end_of_stream: false })
+            Ok(ReadDir {
+                inner: Arc::new(inner),
+                end_of_stream: false,
+            })
         }
     }
 }
@@ -676,7 +686,7 @@
     Ok(PathBuf::from(OsString::from_vec(buf)))
 }
 
-fn open_from(from: &Path) -> io::Result<(fs::File, fs::Metadata)> {
+fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> {
     use crate::untrusted::fs::File;
     use crate::sys_common::fs::NOT_FILE_ERROR;
 
@@ -690,10 +700,12 @@
 
 fn open_to_and_set_permissions(
     to: &Path,
-    reader_metadata: fs::Metadata,
-) -> io::Result<(fs::File, fs::Metadata)> {
+    reader_metadata: crate::fs::Metadata,
+) -> io::Result<(crate::fs::File, crate::fs::Metadata)> {
+    use crate::fs::OpenOptions;
+
     let perm = reader_metadata.permissions();
-    let writer = fs::OpenOptions::new()
+    let writer = OpenOptions::new()
         // create the file with the correct mode right away
         .mode(perm.mode())
         .write(true)
@@ -717,6 +729,18 @@
     io::copy::copy(&mut reader, &mut writer)
 }
 
+pub fn chown(_path: &Path, _uid: u32, _gid: u32) -> io::Result<()> {
+    super::unsupported::unsupported()
+}
+
+pub fn fchown(_fd: c_int, _uid: u32, _gid: u32) -> io::Result<()> {
+    super::unsupported::unsupported()
+}
+
+pub fn lchown(_path: &Path, _uid: u32, _gid: u32) -> io::Result<()> {
+    super::unsupported::unsupported()
+}
+
 pub fn chroot(_dir: &Path) -> io::Result<()> {
     super::unsupported::unsupported()
 }
@@ -729,3 +753,113 @@
     };
     pub use sgx_libc::*;
 }
+
+pub use remove_dir_impl::remove_dir_all;
+
+mod remove_dir_impl {
+    use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir};
+    use crate::ffi::CStr;
+    use crate::io;
+    use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+    use crate::os::unix::prelude::{OwnedFd, RawFd};
+    use crate::path::{Path, PathBuf};
+    use crate::sync::Arc;
+    use crate::sys::{cvt, cvt_r};
+    use libc::{fdopendir, openat, unlinkat};
+
+    pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
+        let fd = cvt_r(|| unsafe {
+            openat(
+                parent_fd.unwrap_or(libc::AT_FDCWD),
+                p.as_ptr(),
+                libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY,
+            )
+        })?;
+        Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+    }
+
+    fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> {
+        let ptr = unsafe { fdopendir(dir_fd.as_raw_fd()) };
+        if ptr.is_null() {
+            return Err(io::Error::last_os_error());
+        }
+        let dirp = Dir(ptr);
+        // file descriptor is automatically closed by libc::closedir() now, so give up ownership
+        let new_parent_fd = dir_fd.into_raw_fd();
+        // a valid root is not needed because we do not call any functions involving the full path
+        // of the DirEntrys.
+        let dummy_root = PathBuf::new();
+        Ok((
+            ReadDir {
+                inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
+                end_of_stream: false,
+            },
+            new_parent_fd,
+        ))
+    }
+
+    fn is_dir(ent: &DirEntry) -> Option<bool> {
+        match ent.entry.d_type {
+            libc::DT_UNKNOWN => None,
+            libc::DT_DIR => Some(true),
+            _ => Some(false),
+        }
+    }
+
+    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
+        let pcstr = cstr(p)?;
+
+        // entry is expected to be a directory, open as such
+        let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
+
+        // open the directory passing ownership of the fd
+        let (dir, fd) = fdreaddir(fd)?;
+        for child in dir {
+            let child = child?;
+            match is_dir(&child) {
+                Some(true) => {
+                    remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                }
+                Some(false) => {
+                    cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?;
+                }
+                None => match cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) }) {
+                    // type unknown - try to unlink
+                    Err(err)
+                        if err.raw_os_error() == Some(libc::EISDIR)
+                            || err.raw_os_error() == Some(libc::EPERM) =>
+                    {
+                        // if the file is a directory unlink fails with EISDIR on Linux and EPERM everyhwere else
+                        remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                    }
+                    result => {
+                        result?;
+                    }
+                },
+            }
+        }
+
+        // unlink the directory after removing its contents
+        cvt(unsafe {
+            unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR)
+        })?;
+        Ok(())
+    }
+
+    pub fn remove_dir_all(p: &Path) -> io::Result<()> {
+        // We cannot just call remove_dir_all_recursive() here because that would not delete a passed
+        // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse
+        // into symlinks.
+        let attr = lstat(p)?;
+        if attr.file_type().is_symlink() {
+            crate::fs::remove_file(p)
+        } else {
+            remove_dir_all_recursive(None, p)
+        }
+    }
+
+    mod libc {
+        pub use sgx_libc::ocall::{fdopendir, openat, unlinkat};
+        pub use sgx_libc::*;
+    }
+}
diff --git a/sgx_tstd/src/sys/mod.rs b/sgx_tstd/src/sys/mod.rs
index 589e18c..7811256 100644
--- a/sgx_tstd/src/sys/mod.rs
+++ b/sgx_tstd/src/sys/mod.rs
@@ -75,7 +75,7 @@
         libc::ENOSPC => StorageFull,
         libc::ENOSYS => Unsupported,
         libc::EMLINK => TooManyLinks,
-        libc::ENAMETOOLONG => FilenameTooLong,
+        libc::ENAMETOOLONG => InvalidFilename,
         libc::ENETDOWN => NetworkDown,
         libc::ENETUNREACH => NetworkUnreachable,
         libc::ENOTCONN => NotConnected,
@@ -148,9 +148,6 @@
     }
 
     pub fn unsupported_err() -> io::Error {
-        io::Error::new_const(
-            io::ErrorKind::Unsupported,
-            &"operation not supported on this platform",
-        )
+        io::const_io_error!(io::ErrorKind::Unsupported, "operation not supported on this platform",)
     }
 }
diff --git a/sgx_tstd/src/sys/net.rs b/sgx_tstd/src/sys/net.rs
index 0683999..7375f07 100644
--- a/sgx_tstd/src/sys/net.rs
+++ b/sgx_tstd/src/sys/net.rs
@@ -44,9 +44,6 @@
         return Ok(());
     }
 
-    // We may need to trigger a glibc workaround. See on_resolver_failure() for details.
-    // on_resolver_failure();
-
     if err == libc::EAI_SYSTEM {
         return Err(io::Error::last_os_error());
     }
@@ -117,9 +114,9 @@
         let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
 
         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidInput,
-                &"cannot set a 0 duration timeout",
+                "cannot set a 0 duration timeout",
             ));
         }
 
@@ -128,7 +125,7 @@
         loop {
             let elapsed = start.elapsed();
             if elapsed >= timeout {
-                return Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"));
+                return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
             }
 
             let timeout = timeout - elapsed;
@@ -155,9 +152,9 @@
                     // for POLLHUP rather than read readiness
                     if pollfd.revents & libc::POLLHUP != 0 {
                         let e = self.take_error()?.unwrap_or_else(|| {
-                            io::Error::new_const(
+                            io::const_io_error!(
                                 io::ErrorKind::Uncategorized,
-                                &"no error set after POLLHUP",
+                                "no error set after POLLHUP",
                             )
                         });
                         return Err(e);
@@ -169,16 +166,6 @@
         }
     }
 
-    // Attention:
-    // this function is a blocking function, which make an OCALL
-    // and block itself **in the untrusted OS**. This is very much
-    // dangerous and is misleading.
-    // In SGX programming, execution is by default in enclave and
-    // cannot leak information by design. Howeverm, this function
-    // is not. It leaks events.
-    // This function is guarded by feature `net` and should only
-    // be used on demand.
-    // We don't support linux kernel < 2.6.28. So we only use accept4.
     pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
         // Unfortunately the only known way right now to accept a socket and
         // atomically set the CLOEXEC flag is to use the `accept4` syscall on
@@ -274,9 +261,9 @@
         let timeout = match dur {
             Some(dur) => {
                 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::InvalidInput,
-                        &"cannot set a 0 duration timeout",
+                        "cannot set a 0 duration timeout",
                     ));
                 }
 
diff --git a/sgx_tstd/src/sys/os.rs b/sgx_tstd/src/sys/os.rs
index de3821c..afcedf7 100644
--- a/sgx_tstd/src/sys/os.rs
+++ b/sgx_tstd/src/sys/os.rs
@@ -52,7 +52,7 @@
 pub fn error_string(error: i32) -> String {
     let mut buf = [0_i8; TMPBUF_SZ];
     unsafe {
-        assert!(!(trts_error::error_string(error, &mut buf) < 0), "strerror_r failure");
+        assert!(trts_error::error_string(error, &mut buf) >= 0, "strerror_r failure");
 
         let p = buf.as_ptr() as *const _;
         str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
@@ -162,9 +162,9 @@
 
 pub fn current_exe() -> io::Result<PathBuf> {
     match crate::fs::read_link("/proc/self/exe") {
-        Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::Error::new_const(
+        Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!(
             io::ErrorKind::Uncategorized,
-            &"no /proc/self/exe available. Is /proc mounted?",
+            "no /proc/self/exe available. Is /proc mounted?",
         )),
         other => other,
     }
diff --git a/sgx_tstd/src/sys/os_str.rs b/sgx_tstd/src/sys/os_str.rs
index dec62b4..33d0387 100644
--- a/sgx_tstd/src/sys/os_str.rs
+++ b/sgx_tstd/src/sys/os_str.rs
@@ -19,6 +19,7 @@
 //! systems: just a `Vec<u8>`/`[u8]`.
 
 use crate::borrow::Cow;
+use crate::collections::TryReserveError;
 use crate::fmt;
 use crate::fmt::Write;
 use crate::mem;
@@ -126,11 +127,21 @@
     }
 
     #[inline]
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.inner.try_reserve(additional)
+    }
+
+    #[inline]
     pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
     }
 
     #[inline]
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.inner.try_reserve_exact(additional)
+    }
+
+    #[inline]
     pub fn shrink_to_fit(&mut self) {
         self.inner.shrink_to_fit()
     }
diff --git a/sgx_tstd/src/sys/path.rs b/sgx_tstd/src/sys/path.rs
index d7d98cb..61ee743 100644
--- a/sgx_tstd/src/sys/path.rs
+++ b/sgx_tstd/src/sys/path.rs
@@ -15,8 +15,10 @@
 // specific language governing permissions and limitations
 // under the License..
 
+use crate::env;
 use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
 
 #[inline]
 pub fn is_sep_byte(b: u8) -> bool {
@@ -28,9 +30,50 @@
     b == b'/'
 }
 
+#[inline]
 pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
     None
 }
 
 pub const MAIN_SEP_STR: &str = "/";
 pub const MAIN_SEP: char = '/';
+
+/// Make a POSIX path absolute without changing its semantics.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+    // This is mostly a wrapper around collecting `Path::components`, with
+    // exceptions made where this conflicts with the POSIX specification.
+    // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+    // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+    let mut components = path.components();
+    let path_os = path.as_os_str().bytes();
+
+    let mut normalized = if path.is_absolute() {
+        // "If a pathname begins with two successive <slash> characters, the
+        // first component following the leading <slash> characters may be
+        // interpreted in an implementation-defined manner, although more than
+        // two leading <slash> characters shall be treated as a single <slash>
+        // character."
+        if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+            components.next();
+            PathBuf::from("//")
+        } else {
+            PathBuf::new()
+        }
+    } else {
+        env::current_dir()?
+    };
+    normalized.extend(components);
+
+    // "Interfaces using pathname resolution may specify additional constraints
+    // when a pathname that does not name an existing directory contains at
+    // least one non- <slash> character and contains one or more trailing
+    // <slash> characters".
+    // A trailing <slash> is also meaningful if "a symbolic link is
+    // encountered during pathname resolution".
+    if path_os.ends_with(b"/") {
+        normalized.push("");
+    }
+
+    Ok(normalized)
+}
diff --git a/sgx_tstd/src/sys/rwlock.bak.rs b/sgx_tstd/src/sys/rwlock.bak.rs
deleted file mode 100644
index b9339a5..0000000
--- a/sgx_tstd/src/sys/rwlock.bak.rs
+++ /dev/null
@@ -1,308 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License..
-
-use core::cell::UnsafeCell;
-use crate::sync::{SgxThreadCondvar, SgxThreadMutex, SgxThreadSpinlock};
-use crate::thread;
-use sgx_trts::libc;
-use sgx_types::{sgx_thread_t, SysError, SGX_THREAD_T_NULL};
-
-struct SgxThreadRwLockInner {
-    readers_num: u32,
-    writers_num: u32,
-    busy: u32,
-    writer_thread: sgx_thread_t,
-    condvar: SgxThreadCondvar,
-    mutex: SgxThreadMutex,
-    spinlock: SgxThreadSpinlock,
-}
-
-impl SgxThreadRwLockInner {
-    const fn new() -> Self {
-        SgxThreadRwLockInner {
-            readers_num: 0,
-            writers_num: 0,
-            busy: 0,
-            writer_thread: SGX_THREAD_T_NULL,
-            condvar: SgxThreadCondvar::new(),
-            mutex: SgxThreadMutex::new(),
-            spinlock: SgxThreadSpinlock::new(),
-        }
-    }
-
-    unsafe fn ref_busy(&mut self) -> SysError {
-        let ret: SysError;
-        self.spinlock.lock();
-        {
-            if self.busy == u32::MAX {
-                ret = Err(libc::EAGAIN);
-            } else {
-                self.busy += 1;
-                ret = Ok(());
-            }
-        }
-        self.spinlock.unlock();
-        ret
-    }
-
-    unsafe fn deref_busy(&mut self) -> SysError {
-        let ret: SysError;
-        self.spinlock.lock();
-        {
-            if self.busy == 0 {
-                ret = Err(libc::EAGAIN);
-            } else {
-                self.busy -= 1;
-                ret = Ok(());
-            }
-        }
-        self.spinlock.unlock();
-        ret
-    }
-
-    unsafe fn read(&mut self) -> SysError {
-        self.ref_busy()?;
-        self.mutex.lock();
-        {
-            if self.writer_thread == thread::rsgx_thread_self() {
-                self.mutex.unlock();
-                self.deref_busy();
-                return Err(libc::EDEADLK);
-            }
-            if self.readers_num == u32::MAX {
-                self.mutex.unlock();
-                self.deref_busy();
-                return Err(libc::EAGAIN);
-            }
-            while self.writers_num > 0 {
-                self.condvar.wait(&self.mutex);
-            }
-            self.readers_num += 1;
-        }
-        self.mutex.unlock();
-        self.deref_busy();
-        Ok(())
-    }
-
-    unsafe fn try_read(&mut self) -> SysError {
-        self.ref_busy()?;
-        self.mutex.lock();
-        {
-            let mut ret = Ok(());
-            if self.writer_thread == thread::rsgx_thread_self() {
-                ret = Err(libc::EDEADLK);
-            } else if self.readers_num == u32::MAX {
-                ret = Err(libc::EAGAIN);
-            } else if self.writers_num > 0 {
-                ret = Err(libc::EBUSY);
-            }
-            match ret {
-                Ok(_) => {}
-                Err(e) => {
-                    self.mutex.unlock();
-                    self.deref_busy();
-                    return Err(e);
-                }
-            }
-            self.readers_num += 1;
-        }
-        self.mutex.unlock();
-        self.deref_busy();
-        Ok(())
-    }
-
-    unsafe fn write(&mut self) -> SysError {
-        self.ref_busy()?;
-        self.mutex.lock();
-        {
-            if self.writer_thread == thread::rsgx_thread_self() {
-                self.mutex.unlock();
-                self.deref_busy();
-                return Err(libc::EDEADLK);
-            }
-
-            if self.writers_num == u32::MAX {
-                self.mutex.unlock();
-                self.deref_busy();
-                return Err(libc::EAGAIN);
-            }
-
-            self.writers_num += 1;
-            while self.readers_num > 0 {
-                self.condvar.wait(&self.mutex);
-            }
-            while self.writer_thread != SGX_THREAD_T_NULL {
-                self.condvar.wait(&self.mutex);
-            }
-            self.writer_thread = thread::rsgx_thread_self();
-        }
-        self.mutex.unlock();
-        self.deref_busy();
-        Ok(())
-    }
-
-    pub unsafe fn try_write(&mut self) -> SysError {
-        self.ref_busy()?;
-        self.mutex.lock();
-        {
-            let mut ret = Ok(());
-            if self.writer_thread == thread::rsgx_thread_self() {
-                ret = Err(libc::EDEADLK);
-            } else if self.writers_num == u32::MAX {
-                ret = Err(libc::EAGAIN);
-            } else if self.readers_num > 0 || self.writer_thread != SGX_THREAD_T_NULL {
-                ret = Err(libc::EBUSY);
-            }
-
-            match ret {
-                Ok(_) => {}
-                Err(e) => {
-                    self.mutex.unlock();
-                    self.deref_busy();
-                    return Err(e);
-                }
-            }
-            self.writers_num += 1;
-            self.writer_thread = thread::rsgx_thread_self();
-        }
-        self.mutex.unlock();
-        self.deref_busy();
-        Ok(())
-    }
-
-    unsafe fn read_unlock(&mut self) -> SysError {
-        self.raw_unlock()
-    }
-
-    unsafe fn write_unlock(&mut self) -> SysError {
-        self.raw_unlock()
-    }
-
-    unsafe fn raw_unlock(&mut self) -> SysError {
-        self.mutex.lock();
-        {
-            if self.readers_num > 0 {
-                self.readers_num -= 1;
-                if self.readers_num == 0 && self.writers_num > 0 {
-                    self.condvar.broadcast();
-                }
-            } else {
-                if self.writer_thread != thread::rsgx_thread_self() {
-                    self.mutex.unlock();
-                    return Err(libc::EPERM);
-                }
-                self.writers_num -= 1;
-                self.writer_thread = SGX_THREAD_T_NULL;
-                if self.busy > 0 {
-                    self.condvar.broadcast();
-                }
-            }
-        }
-        self.mutex.unlock();
-        Ok(())
-    }
-
-    unsafe fn destroy(&mut self) -> SysError {
-        self.mutex.lock();
-        {
-            if self.readers_num > 0 || self.writers_num > 0 || self.busy > 0 {
-                self.spinlock.unlock();
-                return Err(libc::EBUSY);
-            }
-
-            self.condvar.destroy();
-            self.mutex.destroy();
-        }
-        self.spinlock.unlock();
-        Ok(())
-    }
-}
-
-/// An OS-based reader-writer lock.
-///
-/// This structure is entirely unsafe and serves as the lowest layer of a
-/// cross-platform binding of system rwlocks. It is recommended to use the
-/// safer types at the top level of this crate instead of this type.
-pub struct SgxThreadRwLock {
-    lock: UnsafeCell<SgxThreadRwLockInner>,
-}
-
-impl SgxThreadRwLock {
-    /// Creates a new reader-writer lock for use.
-    pub const fn new() -> Self {
-        SgxThreadRwLock {
-            lock: UnsafeCell::new(SgxThreadRwLockInner::new()),
-        }
-    }
-
-    /// Acquires shared access to the underlying lock, blocking the current
-    /// thread to do so.
-    #[inline]
-    pub unsafe fn read(&self) -> SysError {
-        let rwlock: &mut SgxThreadRwLockInner = &mut *self.lock.get();
-        rwlock.read()
-    }
-
-    /// Attempts to acquire shared access to this lock, returning whether it
-    /// succeeded or not.
-    ///
-    /// This function does not block the current thread.
-    #[inline]
-    pub unsafe fn try_read(&self) -> SysError {
-        let rwlock: &mut SgxThreadRwLockInner = &mut *self.lock.get();
-        rwlock.try_read()
-    }
-
-    /// Acquires write access to the underlying lock, blocking the current thread
-    /// to do so.
-    #[inline]
-    pub unsafe fn write(&self) -> SysError {
-        let rwlock: &mut SgxThreadRwLockInner = &mut *self.lock.get();
-        rwlock.write()
-    }
-
-    /// Attempts to acquire exclusive access to this lock, returning whether it
-    /// succeeded or not.
-    ///
-    /// This function does not block the current thread.
-    #[inline]
-    pub unsafe fn try_write(&self) -> SysError {
-        let rwlock: &mut SgxThreadRwLockInner = &mut *self.lock.get();
-        rwlock.try_write()
-    }
-
-    /// Unlocks previously acquired shared access to this lock.
-    #[inline]
-    pub unsafe fn read_unlock(&self) -> SysError {
-        let rwlock: &mut SgxThreadRwLockInner = &mut *self.lock.get();
-        rwlock.read_unlock()
-    }
-
-    /// Unlocks previously acquired exclusive access to this lock.
-    #[inline]
-    pub unsafe fn write_unlock(&self) -> SysError {
-        let rwlock: &mut SgxThreadRwLockInner = &mut *self.lock.get();
-        rwlock.write_unlock()
-    }
-
-    /// Destroys OS-related resources with this RWLock.
-    #[inline]
-    pub unsafe fn destroy(&self) -> SysError {
-        let rwlock: &mut SgxThreadRwLockInner = &mut *self.lock.get();
-        rwlock.destroy()
-    }
-}
diff --git a/sgx_tstd/src/sys/thread.rs b/sgx_tstd/src/sys/thread.rs
index 8d0cfef..538995b 100644
--- a/sgx_tstd/src/sys/thread.rs
+++ b/sgx_tstd/src/sys/thread.rs
@@ -138,9 +138,9 @@
 
 pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     let cpus = enclave::rsgx_get_cpu_core_num();
-    NonZeroUsize::new(cpus as usize).ok_or_else(|| io::Error::new_const(
+    NonZeroUsize::new(cpus as usize).ok_or_else(|| io::const_io_error!(
         io::ErrorKind::NotFound,
-        &"The number of hardware threads is not known for the target platform",
+        "The number of hardware threads is not known for the target platform",
     ))
 }
 
diff --git a/sgx_tstd/src/sys/time.rs b/sgx_tstd/src/sys/time.rs
index 9f28de2..d9b351a 100644
--- a/sgx_tstd/src/sys/time.rs
+++ b/sgx_tstd/src/sys/time.rs
@@ -157,15 +157,6 @@
             Instant { t: now(libc::CLOCK_MONOTONIC) }
         }
 
-        pub const fn zero() -> Instant {
-            Instant { t: Timespec::zero() }
-        }
-
-        pub fn actually_monotonic() -> bool {
-            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
-                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
-        }
-
         pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
             self.t.sub_timespec(&other.t).ok()
         }
diff --git a/sgx_tstd/src/sys_common/backtrace.rs b/sgx_tstd/src/sys_common/backtrace.rs
index 5f3a88c..dd2d30c 100644
--- a/sgx_tstd/src/sys_common/backtrace.rs
+++ b/sgx_tstd/src/sys_common/backtrace.rs
@@ -24,7 +24,6 @@
 use crate::io;
 use crate::io::prelude::*;
 use crate::path::{Path, PathBuf};
-use crate::sync::atomic::{self, Ordering};
 use crate::sync::SgxThreadMutex as ThreadMutex;
 use crate::sys::backtrace::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
 
@@ -163,58 +162,14 @@
     result
 }
 
-pub enum RustBacktrace {
-    Print(PrintFmt),
-    Disabled,
-    RuntimeDisabled,
-}
-
-/// Controls how the backtrace should be formatted.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum PrintFormat {
-    /// Show only relevant data from the backtrace.
-    Short = 2,
-    /// Show all the frames with absolute path for files.
-    Full = 3,
-}
-
-static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(1);
-
-// For now logging is turned off by default, and this function checks to see
-// whether the magical environment variable is present to see if it's turned on.
-pub fn rust_backtrace_env() -> RustBacktrace {
-    // If the `backtrace` feature of this crate isn't enabled quickly return
-    // `None` so this can be constant propagated all over the place to turn
-    // optimize away callers.
-    if !cfg!(feature = "backtrace") {
-        return RustBacktrace::Disabled;
-    }
-
-    match ENABLED.load(Ordering::SeqCst) {
-        0 => RustBacktrace::Disabled,
-        1 => RustBacktrace::RuntimeDisabled,
-        2 => RustBacktrace::Print(PrintFmt::Short),
-        3 => RustBacktrace::Print(PrintFmt::Full),
-        _ => unreachable!(),
-    }
-}
-
-pub fn set_enabled(print_fmt: PrintFormat) {
-    ENABLED.store(match print_fmt {
-        PrintFormat::Short => 2,
-        PrintFormat::Full => 3,
-    }, Ordering::SeqCst);
-}
-
 /// Prints the filename of the backtrace frame.
 ///
 /// See also `output`.
-#[allow(unused_variables)]
 pub fn output_filename(
     fmt: &mut fmt::Formatter<'_>,
     bows: BytesOrWideString<'_>,
-    print_fmt: PrintFmt,
-    cwd: Option<&PathBuf>,
+    _print_fmt: PrintFmt,
+    _cwd: Option<&PathBuf>,
 ) -> fmt::Result {
     let file: Cow<'_, Path> = match bows {
         BytesOrWideString::Bytes(bytes) => {
@@ -233,4 +188,4 @@
     //     }
     // }
     fmt::Display::fmt(&file.display(), fmt)
-}
\ No newline at end of file
+}
diff --git a/sgx_tstd/src/sys_common/fs.rs b/sgx_tstd/src/sys_common/fs.rs
index 0b6ea93..e006f9a 100644
--- a/sgx_tstd/src/sys_common/fs.rs
+++ b/sgx_tstd/src/sys_common/fs.rs
@@ -14,13 +14,14 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License..
+
+use crate::fs;
 use crate::io::{self, Error, ErrorKind};
 use crate::path::Path;
-use crate::untrusted::fs;
 
-pub(crate) const NOT_FILE_ERROR: Error = Error::new_const(
+pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!(
     ErrorKind::InvalidInput,
-    &"the source path is neither a regular file nor a symlink to a regular file",
+    "the source path is neither a regular file nor a symlink to a regular file",
 );
 
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
diff --git a/sgx_tstd/src/sys_common/net.rs b/sgx_tstd/src/sys_common/net.rs
index f7964ef..dea810c 100644
--- a/sgx_tstd/src/sys_common/net.rs
+++ b/sgx_tstd/src/sys_common/net.rs
@@ -21,7 +21,7 @@
 use crate::convert::{TryFrom, TryInto};
 use crate::ffi::CString;
 use crate::fmt;
-use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::ptr;
@@ -82,7 +82,7 @@
                 *(storage as *const _ as *const c::sockaddr_in6)
             })))
         }
-        _ => Err(Error::new_const(ErrorKind::InvalidInput, &"invalid argument")),
+        _ => Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid argument")),
     }
 }
 
@@ -106,6 +106,7 @@
     }
 }
 
+#[allow(clippy::transmute_ptr_to_ref)]
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -113,7 +114,7 @@
             unsafe {
                 let cur = self.cur.as_ref()?;
                 self.cur = cur.ai_next;
-                match sockaddr_to_addr(&*(cur.ai_addr as *const c::sockaddr_storage), cur.ai_addrlen as usize) {
+                match sockaddr_to_addr(mem::transmute(cur.ai_addr), cur.ai_addrlen as usize) {
                     Ok(addr) => return Some(addr),
                     Err(_) => continue,
                 }
@@ -139,7 +140,7 @@
             ($e:expr, $msg:expr) => {
                 match $e {
                     Some(r) => r,
-                    None => return Err(io::Error::new_const(io::ErrorKind::InvalidInput, &$msg)),
+                    None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, $msg)),
                 }
             };
         }
diff --git a/sgx_tstd/src/sys_common/thread_local_key.rs b/sgx_tstd/src/sys_common/thread_local_key.rs
index e124508..a6d04ea 100644
--- a/sgx_tstd/src/sys_common/thread_local_key.rs
+++ b/sgx_tstd/src/sys_common/thread_local_key.rs
@@ -64,7 +64,7 @@
 #![allow(non_camel_case_types)]
 #![allow(dead_code)] // sys isn't exported yet
 
-use core::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::sync::atomic::{self, AtomicUsize, Ordering};
 use crate::sys::thread_local_key as imp;
 use crate::sync::SgxThreadMutex;
 
diff --git a/sgx_tstd/src/sys_common/thread_parker/generic.rs b/sgx_tstd/src/sys_common/thread_parker/generic.rs
index 68da129..f30e346 100644
--- a/sgx_tstd/src/sys_common/thread_parker/generic.rs
+++ b/sgx_tstd/src/sys_common/thread_parker/generic.rs
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License..
 
-//! Parker implementaiton based on a Mutex and Condvar.
+//! Parker implementation based on a Mutex and Condvar.
 
 use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::SeqCst;
@@ -37,7 +37,7 @@
         Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() }
     }
 
-    // This implementaiton doesn't require `unsafe`, but other implementations
+    // This implementation doesn't require `unsafe`, but other implementations
     // may assume this is only called by the thread that owns the Parker.
     #[allow(clippy::single_match)]
     pub unsafe fn park(&self) {
@@ -73,7 +73,7 @@
         }
     }
 
-    // This implementaiton doesn't require `unsafe`, but other implementations
+    // This implementation doesn't require `unsafe`, but other implementations
     // may assume this is only called by the thread that owns the Parker.
     pub unsafe fn park_timeout(&self, dur: Duration) {
         // Like `park` above we have a fast path for an already-notified thread, and
diff --git a/sgx_tstd/src/sys_common/wtf8.rs b/sgx_tstd/src/sys_common/wtf8.rs
index d37342a..771be71 100644
--- a/sgx_tstd/src/sys_common/wtf8.rs
+++ b/sgx_tstd/src/sys_common/wtf8.rs
@@ -37,6 +37,7 @@
 
 use crate::borrow::Cow;
 use crate::char;
+use crate::collections::TryReserveError;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::iter::FromIterator;
@@ -246,11 +247,47 @@
         self.bytes.reserve(additional)
     }
 
+    /// Tries to reserve capacity for at least `additional` more length units
+    /// in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to avoid
+    /// frequent reallocations. After calling `try_reserve`, capacity will be
+    /// greater than or equal to `self.len() + additional`. Does nothing if
+    /// capacity is already sufficient.
+    ///
+    /// # Errors
+    ///
+    /// If the capacity overflows, or the allocator reports a failure, then an error
+    /// is returned.
+    #[inline]
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.bytes.try_reserve(additional)
+    }
+
     #[inline]
     pub fn reserve_exact(&mut self, additional: usize) {
         self.bytes.reserve_exact(additional)
     }
 
+    /// Tries to reserve the minimum capacity for exactly `additional`
+    /// length units in the given `Wtf8Buf`. After calling
+    /// `try_reserve_exact`, capacity will be greater than or equal to
+    /// `self.len() + additional` if it returns `Ok(())`.
+    /// Does nothing if the capacity is already sufficient.
+    ///
+    /// Note that the allocator may give the `Wtf8Buf` more space than it
+    /// requests. Therefore, capacity can not be relied upon to be precisely
+    /// minimal. Prefer [`try_reserve`] if future insertions are expected.
+    ///
+    /// [`try_reserve`]: Wtf8Buf::try_reserve
+    ///
+    /// # Errors
+    ///
+    /// If the capacity overflows, or the allocator reports a failure, then an error
+    /// is returned.
+    #[inline]
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.bytes.try_reserve_exact(additional)
+    }
+
     #[inline]
     pub fn shrink_to_fit(&mut self) {
         self.bytes.shrink_to_fit()
@@ -825,7 +862,8 @@
 
     #[inline]
     fn next(&mut self) -> Option<CodePoint> {
-        next_code_point(&mut self.bytes).map(|c| CodePoint { value: c })
+        // SAFETY: `self.bytes` has been created from a WTF-8 string
+        unsafe { next_code_point(&mut self.bytes).map(|c| CodePoint { value: c }) }
     }
 
     #[inline]
diff --git a/sgx_tstd/src/thread/local.rs b/sgx_tstd/src/thread/local.rs
index e98c26d..6319514 100644
--- a/sgx_tstd/src/thread/local.rs
+++ b/sgx_tstd/src/thread/local.rs
@@ -116,6 +116,7 @@
 ///
 /// [`std::thread::LocalKey`]: crate::thread::LocalKey
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
 #[allow_internal_unstable(thread_local_internals)]
 macro_rules! thread_local {
     // empty (base case for the recursion)
@@ -151,11 +152,11 @@
         #[cfg(not(feature = "thread"))]
         #[inline] // see comments below
         unsafe fn __getit() -> $crate::result::Result<&'static $t, $crate::thread::AccessError> {
-            const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local();
+            const INIT_EXPR: $t = $init;
 
             if !$crate::mem::needs_drop::<$t>() || $crate::thread::thread_policy() == $crate::thread::SgxThreadPolicy::Bound {
                 #[thread_local]
-                static mut VAL: $t = $init;
+                static mut VAL: $t = INIT_EXPR;
                 Ok(&VAL)
             } else {
                 Err($crate::thread::AccessError::new(
@@ -166,7 +167,10 @@
 
         #[cfg(feature = "thread")]
         unsafe fn __getit() -> $crate::result::Result<&'static $t, $crate::thread::AccessError> {
-            const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local();
+            const INIT_EXPR: $t = $init;
+
+            #[thread_local]
+            static mut VAL: $t = INIT_EXPR;
 
             // If a dtor isn't needed we can do something "very raw" and
             // just get going.
@@ -182,8 +186,6 @@
                 ));
             }
 
-            #[thread_local]
-            static mut VAL: $t = $init;
             // 0 == dtor not registered
             // 1 == dtor registered, dtor not run
             // 2 == dtor registered and is running or has run
@@ -242,7 +244,11 @@
                 static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
                     $crate::thread::__FastLocalKeyInner::new();
 
-                __KEY.get(__init)
+                // FIXME: remove the #[allow(...)] marker when macros don't
+                // raise warning for missing/extraneous unsafe blocks anymore.
+                // See https://github.com/rust-lang/rust/issues/74838.
+                #[allow(unused_unsafe)]
+                unsafe { __KEY.get(__init) }
             }
 
             unsafe {
@@ -421,7 +427,7 @@
 
         pub unsafe fn get(&self, init: fn() -> T) -> Result<&'static T, AccessError> {
             if !mem::needs_drop::<T>() || thread::thread_policy() == SgxThreadPolicy::Bound {
-	        // SAFETY: The caller must ensure no reference is ever handed out to
+                // SAFETY: The caller must ensure no reference is ever handed out to
                 // the inner cell nor mutable reference to the Option<T> inside said
                 // cell. This make it safe to hand a reference, though the lifetime
                 // of 'static is itself unsafe, making the get method unsafe.
@@ -509,7 +515,7 @@
             Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) }
         }
 
-        // note that this is just a publically-callable function only for the
+        // note that this is just a publicly-callable function only for the
         // const-initialized form of thread locals, basically a way to call the
         // free `register_dtor` function defined elsewhere in libstd.
         pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
@@ -518,7 +524,7 @@
 
         pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Result<&'static T, AccessError> {
             // SAFETY: See the definitions of `LazyKeyInner::get` and
-            // `try_initialize` for more informations.
+            // `try_initialize` for more information.
             //
             // The caller must ensure no mutable references are ever active to
             // the inner cell or the inner T when this is called.
@@ -547,13 +553,13 @@
 
             if !super::pthread_info_tls.m_pthread.is_null() {
                 // Note:
-                // If the current thread was created by pthread_create, we should call
+                // If the current thread was created by `pthread_create`, we should call
                 // the try_register_dtor function. You can know whether the current thread has
                 // been created by pthread_create() through the m_thread member of pthread_info
                 // (thread local storage) of pthread library in intel sgx sdk.
                 //
-                // Destructor will only be called when a thread created by pthread_create exits,
-                // because sys_common::thread_local::StaticKey does not call pthread_key_delete
+                // Destructor will only be called when a thread created by `pthread_create` exits,
+                // because `sys_common::thread_local::StaticKey` does not call `pthread_key_delete`
                 // to trigger the destructor.
                 if !mem::needs_drop::<T>() || self.try_register_dtor() {
                     // SAFETY: See comment above (his function doc).
diff --git a/sgx_tstd/src/thread/mod.rs b/sgx_tstd/src/thread/mod.rs
index 33fe854..9fcaf3f 100644
--- a/sgx_tstd/src/thread/mod.rs
+++ b/sgx_tstd/src/thread/mod.rs
@@ -55,6 +55,12 @@
 #[macro_use]
 mod local;
 
+#[cfg(feature = "thread")]
+mod scoped;
+
+#[cfg(feature = "thread")]
+pub use scoped::{scope, Scope, ScopedJoinHandle};
+
 pub use self::local::{AccessError, LocalKey};
 
 pub use self::local::statik::Key as __StaticLocalKeyInner;
@@ -63,11 +69,6 @@
 #[cfg(feature = "thread")]
 pub use self::local::os::Key as __OsLocalKeyInner;
 
-// This is only used to make thread locals with `const { .. }` initialization
-// expressions unstable. If and/or when that syntax is stabilized with thread
-// locals this will simply be removed.
-pub const fn require_unstable_const_init_thread_local() {}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Builder
 ////////////////////////////////////////////////////////////////////////////////
@@ -113,6 +114,7 @@
 /// [`unwrap`]: crate::result::Result::unwrap
 /// [naming-threads]: ./index.html#naming-threads
 #[cfg(feature = "thread")]
+#[must_use = "must eventually spawn the thread"]
 #[derive(Debug)]
 pub struct Builder {
     // A name for the thread-to-be, for identification in panic messages
@@ -281,6 +283,20 @@
         F: Send + 'a,
         T: Send + 'a,
     {
+        Ok(JoinHandle(self.spawn_unchecked_(f, None)?))
+    }
+
+    unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
+        self,
+        f: F,
+        scope_data: Option<&'scope scoped::ScopeData>,
+    ) -> io::Result<JoinInner<'scope, T>>
+    where
+        F: FnOnce() -> T,
+        F: Send + 'a,
+        T: Send + 'a,
+        'scope: 'a,
+    {
         let Builder { name } = self;
 
         let my_thread = SgxThread::new(name.map(|name| {
@@ -288,7 +304,8 @@
         }));
         let their_thread = my_thread.clone();
 
-        let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None));
+        let my_packet: Arc<Packet<'scope, T>> =
+            Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) });
         let their_packet = my_packet.clone();
 
         let main = move || {
@@ -306,10 +323,14 @@
             // closure (it is an Arc<...>) and `my_packet` will be stored in the
             // same `JoinInner` as this closure meaning the mutation will be
             // safe (not modify it and affect a value far away).
-            *their_packet.get() = Some(try_result);
+            *their_packet.result.get() = Some(try_result);
         };
 
-        Ok(JoinHandle(JoinInner {
+        if let Some(scope_data) = scope_data {
+            scope_data.increment_num_running_threads();
+        }
+
+        Ok(JoinInner {
             // SAFETY:
             //
             // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed
@@ -323,14 +344,14 @@
             // Similarly, the `sys` implementation must guarantee that no references to the closure
             // exist after the thread has terminated, which is signaled by `Thread::join`
             // returning.
-            native: Some(imp::Thread::new(
+            native: imp::Thread::new(
                 mem::transmute::<Box<dyn FnOnce() + 'a>, Box<dyn FnOnce() + 'static>>(
                     Box::new(main),
-                ),          
-            )?),
+                ),
+            )?,
             thread: my_thread,
-            packet: Packet(my_packet),
-        }))
+            packet: my_packet,
+        })
     }
 }
 
@@ -787,10 +808,13 @@
 
 /// A unique identifier for a running thread.
 ///
-/// A `ThreadId` is an opaque object that has a unique value for each thread
-/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's
-/// system-designated identifier. A `ThreadId` can be retrieved from the [`id`]
-/// method on a [`Thread`].
+/// A `ThreadId` is an opaque object that uniquely identifies each thread
+/// created during the lifetime of a process. `ThreadId`s are guaranteed not to
+/// be reused, even when a thread terminates. `ThreadId`s are under the control
+/// of Rust's standard library and there may not be any relationship between
+/// `ThreadId` and the underlying platform's notion of a thread identifier --
+/// the two concepts cannot, therefore, be used interchangeably. A `ThreadId`
+/// can be retrieved from the [`id`] method on a [`Thread`].
 ///
 /// # Examples
 ///
@@ -821,7 +845,10 @@
 
             // If we somehow use up all our bits, panic so that we're not
             // covering up subtle bugs of IDs being reused.
-            assert!(!(COUNTER == u64::MAX), "failed to generate unique thread ID: bitspace exhausted");
+            if COUNTER == u64::MAX {
+                let _ = GUARD.unlock(); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
+                panic!("failed to generate unique thread ID: bitspace exhausted");
+            }
 
             let id = COUNTER;
             COUNTER += 1;
@@ -1044,46 +1071,60 @@
 /// [`std::panic::resume_unwind`]: crate::panic::resume_unwind
 pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
 
-// This packet is used to communicate the return value between the spawned thread
-// and the rest of the program. Memory is shared through the `Arc` within and there's
-// no need for a mutex here because synchronization happens with `join()` (the
-// caller will never read this packet until the thread has exited).
+// This packet is used to communicate the return value between the spawned
+// thread and the rest of the program. It is shared through an `Arc` and
+// there's no need for a mutex here because synchronization happens with `join()`
+// (the caller will never read this packet until the thread has exited).
 //
-// This packet itself is then stored into a `JoinInner` which in turns is placed
-// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to
-// manually worry about impls like Send and Sync. The type `T` should
-// already always be Send (otherwise the thread could not have been created) and
-// this type is inherently Sync because no methods take &self. Regardless,
-// however, we add inheriting impls for Send/Sync to this type to ensure it's
-// Send/Sync and that future modifications will still appropriately classify it.
+// An Arc to the packet is stored into a `JoinInner` which in turns is placed
+// in `JoinHandle`.
 #[cfg(feature = "thread")]
-struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
+struct Packet<'scope, T> {
+    scope: Option<&'scope scoped::ScopeData>,
+    result: UnsafeCell<Option<Result<T>>>,
+}
+
+// Due to the usage of `UnsafeCell` we need to manually implement Sync.
+// The type `T` should already always be Send (otherwise the thread could not
+// have been created) and the Packet is Sync because all access to the
+// `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync.
+#[cfg(feature = "thread")]
+unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {}
 
 #[cfg(feature = "thread")]
-unsafe impl<T: Send> Send for Packet<T> {}
-#[cfg(feature = "thread")]
-unsafe impl<T: Sync> Sync for Packet<T> {}
+impl<'scope, T> Drop for Packet<'scope, T> {
+    fn drop(&mut self) {
+        // Book-keeping so the scope knows when it's done.
+        if let Some(scope) = self.scope {
+            // If this packet was for a thread that ran in a scope, the thread
+            // panicked, and nobody consumed the panic payload, we make sure
+            // the scope function will panic.
+            let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+            scope.decrement_num_running_threads(unhandled_panic);
+        }
+    }
+}
 
 /// Inner representation for JoinHandle
 #[cfg(feature = "thread")]
-struct JoinInner<T> {
-    native: Option<imp::Thread>,
+struct JoinInner<'scope, T> {
+    native: imp::Thread,
     thread: SgxThread,
-    packet: Packet<T>,
+    packet: Arc<Packet<'scope, T>>,
 }
 
 #[cfg(feature = "thread")]
-impl<T> JoinInner<T> {
-    fn join(&mut self) -> Result<T> {
-        self.native.take().unwrap().join();
-        unsafe { (*self.packet.0.get()).take().unwrap() }
+impl<'scope, T> JoinInner<'scope, T> {
+    fn join(mut self) -> Result<T> {
+        self.native.join();
+        Arc::get_mut(&mut self.packet).unwrap().result.get_mut().take().unwrap()
     }
 }
 
 /// An owned permission to join on a thread (block on its termination).
 ///
 /// A `JoinHandle` *detaches* the associated thread when it is dropped, which
-/// means that there is no longer any handle to thread and no way to `join`
+/// means that there is no longer any handle to the thread and no way to `join`
 /// on it.
 ///
 /// Due to platform restrictions, it is not possible to [`Clone`] this
@@ -1143,7 +1184,7 @@
 /// [`thread::Builder::spawn`]: Builder::spawn
 /// [`thread::spawn`]: spawn
 #[cfg(feature = "thread")]
-pub struct JoinHandle<T>(JoinInner<T>);
+pub struct JoinHandle<T>(JoinInner<'static, T>);
 
 #[cfg(feature = "thread")]
 unsafe impl<T> Send for JoinHandle<T> {}
@@ -1206,22 +1247,30 @@
     /// }).unwrap();
     /// join_handle.join().expect("Couldn't join on the associated thread");
     /// ```
-    pub fn join(mut self) -> Result<T> {
+    pub fn join(self) -> Result<T> {
         self.0.join()
     }
+
+    /// Checks if the associated thread is still running its main function.
+    ///
+    /// This might return `false` for a brief moment after the thread's main
+    /// function has returned, but before the thread itself has stopped running.
+    pub fn is_running(&self) -> bool {
+        Arc::strong_count(&self.0.packet) > 1
+    }
 }
 
 #[cfg(feature = "thread")]
 impl<T> AsInner<imp::Thread> for JoinHandle<T> {
     fn as_inner(&self) -> &imp::Thread {
-        self.0.native.as_ref().unwrap()
+        &self.0.native
     }
 }
 
 #[cfg(feature = "thread")]
 impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
     fn into_inner(self) -> imp::Thread {
-        self.0.native.unwrap()
+        self.0.native
     }
 }
 
@@ -1256,9 +1305,12 @@
 /// The purpose of this API is to provide an easy and portable way to query
 /// the default amount of parallelism the program should use. Among other things it
 /// does not expose information on NUMA regions, does not account for
-/// differences in (co)processor capabilities, and will not modify the program's
-/// global state in order to more accurately query the amount of available
-/// parallelism.
+/// differences in (co)processor capabilities or current system load,
+/// and will not modify the program's global state in order to more accurately
+/// query the amount of available parallelism.
+///
+/// Where both fixed steady-state and burst limits are available the steady-state
+/// capacity will be used to ensure more predictable latencies.
 ///
 /// Resource limits can be changed during the runtime of a program, therefore the value is
 /// not cached and instead recomputed every time this function is called. It should not be
@@ -1271,6 +1323,15 @@
 /// platform-specific APIs as well. The following platform limitations currently
 /// apply to `available_parallelism`:
 ///
+/// On Windows:
+/// - It may undercount the amount of parallelism available on systems with more
+///   than 64 logical CPUs. However, programs typically need specific support to
+///   take advantage of more than 64 logical CPUs, and in the absence of such
+///   support, the number returned by this function accurately reflects the
+///   number of logical CPUs the program can use by default.
+/// - It may overcount the amount of parallelism available on systems limited by
+///   process-wide affinity masks, or job object limitations.
+///
 /// On Linux:
 /// - It may overcount the amount of parallelism available when limited by a
 ///   process-wide affinity mask, or when affected by cgroup limits.
@@ -1292,10 +1353,10 @@
 ///
 /// ```
 /// # #![allow(dead_code)]
-/// #![feature(available_parallelism)]
-/// use std::thread;
+/// use std::{io, thread};
 ///
-/// let count = thread::available_parallelism().map(|n| n.get()).unwrap_or(1);
+///     let count = thread::available_parallelism()?.get();
+///     assert!(count >= 1_usize);
 /// ```
 #[cfg(feature = "thread")]
 pub fn available_parallelism() -> io::Result<NonZeroUsize> {
diff --git a/sgx_tstd/src/thread/scoped.rs b/sgx_tstd/src/thread/scoped.rs
new file mode 100644
index 0000000..5a4b9c9
--- /dev/null
+++ b/sgx_tstd/src/thread/scoped.rs
@@ -0,0 +1,332 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License..
+
+use super::{current, park, Builder, JoinInner, Result, SgxThread};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use crate::sync::Arc;
+
+/// A scope to spawn scoped threads in.
+///
+/// See [`scope`] for details.
+pub struct Scope<'env> {
+    data: ScopeData,
+    /// Invariance over 'env, to make sure 'env cannot shrink,
+    /// which is necessary for soundness.
+    ///
+    /// Without invariance, this would compile fine but be unsound:
+    ///
+    /// ```compile_fail
+    /// #![feature(scoped_threads)]
+    ///
+    /// std::thread::scope(|s| {
+    ///     s.spawn(|s| {
+    ///         let a = String::from("abcd");
+    ///         s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped
+    ///     });
+    /// });
+    /// ```
+    env: PhantomData<&'env mut &'env ()>,
+}
+
+/// An owned permission to join on a scoped thread (block on its termination).
+///
+/// See [`Scope::spawn`] for details.
+pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>);
+
+pub(super) struct ScopeData {
+    num_running_threads: AtomicUsize,
+    a_thread_panicked: AtomicBool,
+    main_thread: SgxThread,
+}
+
+impl ScopeData {
+    pub(super) fn increment_num_running_threads(&self) {
+        // We check for 'overflow' with usize::MAX / 2, to make sure there's no
+        // chance it overflows to 0, which would result in unsoundness.
+        if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 {
+            // This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles.
+            self.decrement_num_running_threads(false);
+            panic!("too many running threads in thread scope");
+        }
+    }
+    pub(super) fn decrement_num_running_threads(&self, panic: bool) {
+        if panic {
+            self.a_thread_panicked.store(true, Ordering::Relaxed);
+        }
+        if self.num_running_threads.fetch_sub(1, Ordering::Release) == 1 {
+            self.main_thread.unpark();
+        }
+    }
+}
+
+/// Create a scope for spawning scoped threads.
+///
+/// The function passed to `scope` will be provided a [`Scope`] object,
+/// through which scoped threads can be [spawned][`Scope::spawn`].
+///
+/// Unlike non-scoped threads, scoped threads can borrow non-`'static` data,
+/// as the scope guarantees all threads will be joined at the end of the scope.
+///
+/// All threads spawned within the scope that haven't been manually joined
+/// will be automatically joined before this function returns.
+///
+/// # Panics
+///
+/// If any of the automatically joined threads panicked, this function will panic.
+///
+/// If you want to handle panics from spawned threads,
+/// [`join`][ScopedJoinHandle::join] them before the end of the scope.
+///
+/// # Example
+///
+/// ```
+/// #![feature(scoped_threads)]
+/// use std::thread;
+///
+/// let mut a = vec![1, 2, 3];
+/// let mut x = 0;
+///
+/// thread::scope(|s| {
+///     s.spawn(|_| {
+///         println!("hello from the first scoped thread");
+///         // We can borrow `a` here.
+///         dbg!(&a);
+///     });
+///     s.spawn(|_| {
+///         println!("hello from the second scoped thread");
+///         // We can even mutably borrow `x` here,
+///         // because no other threads are using it.
+///         x += a[0] + a[2];
+///     });
+///     println!("hello from the main thread");
+/// });
+///
+/// // After the scope, we can modify and access our variables again:
+/// a.push(4);
+/// assert_eq!(x, a.len());
+/// ```
+#[track_caller]
+pub fn scope<'env, F, T>(f: F) -> T
+where
+    F: FnOnce(&Scope<'env>) -> T,
+{
+    let scope = Scope {
+        data: ScopeData {
+            num_running_threads: AtomicUsize::new(0),
+            main_thread: current(),
+            a_thread_panicked: AtomicBool::new(false),
+        },
+        env: PhantomData,
+    };
+
+    // Run `f`, but catch panics so we can make sure to wait for all the threads to join.
+    let result = catch_unwind(AssertUnwindSafe(|| f(&scope)));
+
+    // Wait until all the threads are finished.
+    while scope.data.num_running_threads.load(Ordering::Acquire) != 0 {
+        park();
+    }
+
+    // Throw any panic from `f`, or the return value of `f` if no thread panicked.
+    match result {
+        Err(e) => resume_unwind(e),
+        Ok(_) if scope.data.a_thread_panicked.load(Ordering::Relaxed) => {
+            panic!("a scoped thread panicked")
+        }
+        Ok(result) => result,
+    }
+}
+
+impl<'env> Scope<'env> {
+    /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
+    ///
+    /// Unlike non-scoped threads, threads spawned with this function may
+    /// borrow non-`'static` data from the outside the scope. See [`scope`] for
+    /// details.
+    ///
+    /// The join handle provides a [`join`] method that can be used to join the spawned
+    /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing
+    /// the panic payload.
+    ///
+    /// If the join handle is dropped, the spawned thread will implicitly joined at the
+    /// end of the scope. In that case, if the spawned thread panics, [`scope`] will
+    /// panic after all threads are joined.
+    ///
+    /// This call will create a thread using default parameters of [`Builder`].
+    /// If you want to specify the stack size or the name of the thread, use
+    /// [`Builder::spawn_scoped`] instead.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the OS fails to create a thread; use [`Builder::spawn_scoped`]
+    /// to recover from such errors.
+    ///
+    /// [`join`]: ScopedJoinHandle::join
+    pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+    where
+        F: FnOnce(&Scope<'env>) -> T + Send + 'env,
+        T: Send + 'env,
+    {
+        Builder::new().spawn_scoped(self, f).expect("failed to spawn thread")
+    }
+}
+
+impl Builder {
+    /// Spawns a new scoped thread using the settings set through this `Builder`.
+    ///
+    /// Unlike [`Scope::spawn`], this method yields an [`io::Result`] to
+    /// capture any failure to create the thread at the OS level.
+    ///
+    /// [`io::Result`]: crate::io::Result
+    ///
+    /// # Panics
+    ///
+    /// Panics if a thread name was set and it contained null bytes.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(scoped_threads)]
+    /// use std::thread;
+    ///
+    /// let mut a = vec![1, 2, 3];
+    /// let mut x = 0;
+    ///
+    /// thread::scope(|s| {
+    ///     thread::Builder::new()
+    ///         .name("first".to_string())
+    ///         .spawn_scoped(s, |_|
+    ///     {
+    ///         println!("hello from the {:?} scoped thread", thread::current().name());
+    ///         // We can borrow `a` here.
+    ///         dbg!(&a);
+    ///     })
+    ///     .unwrap();
+    ///     thread::Builder::new()
+    ///         .name("second".to_string())
+    ///         .spawn_scoped(s, |_|
+    ///     {
+    ///         println!("hello from the {:?} scoped thread", thread::current().name());
+    ///         // We can even mutably borrow `x` here,
+    ///         // because no other threads are using it.
+    ///         x += a[0] + a[2];
+    ///     })
+    ///     .unwrap();
+    ///     println!("hello from the main thread");
+    /// });
+    ///
+    /// // After the scope, we can modify and access our variables again:
+    /// a.push(4);
+    /// assert_eq!(x, a.len());
+    /// ```
+    pub fn spawn_scoped<'scope, 'env, F, T>(
+        self,
+        scope: &'scope Scope<'env>,
+        f: F,
+    ) -> io::Result<ScopedJoinHandle<'scope, T>>
+    where
+        F: FnOnce(&Scope<'env>) -> T + Send + 'env,
+        T: Send + 'env,
+    {
+        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?))
+    }
+}
+
+impl<'scope, T> ScopedJoinHandle<'scope, T> {
+    /// Extracts a handle to the underlying thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(scoped_threads)]
+    /// #![feature(thread_is_running)]
+    ///
+    /// use std::thread;
+    ///
+    /// thread::scope(|s| {
+    ///     let t = s.spawn(|_| {
+    ///         println!("hello");
+    ///     });
+    ///     println!("thread id: {:?}", t.thread().id());
+    /// });
+    /// ```
+    #[must_use]
+    pub fn thread(&self) -> &SgxThread {
+        &self.0.thread
+    }
+
+    /// Waits for the associated thread to finish.
+    ///
+    /// This function will return immediately if the associated thread has already finished.
+    ///
+    /// In terms of [atomic memory orderings], the completion of the associated
+    /// thread synchronizes with this function returning.
+    /// In other words, all operations performed by that thread
+    /// [happen before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses)
+    /// all operations that happen after `join` returns.
+    ///
+    /// If the associated thread panics, [`Err`] is returned with the panic payload.
+    ///
+    /// [atomic memory orderings]: crate::sync::atomic
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(scoped_threads)]
+    /// #![feature(thread_is_running)]
+    ///
+    /// use std::thread;
+    ///
+    /// thread::scope(|s| {
+    ///     let t = s.spawn(|_| {
+    ///         panic!("oh no");
+    ///     });
+    ///     assert!(t.join().is_err());
+    /// });
+    /// ```
+    pub fn join(self) -> Result<T> {
+        self.0.join()
+    }
+
+    /// Checks if the associated thread is still running its main function.
+    ///
+    /// This might return `false` for a brief moment after the thread's main
+    /// function has returned, but before the thread itself has stopped running.
+    pub fn is_running(&self) -> bool {
+        Arc::strong_count(&self.0.packet) > 1
+    }
+}
+
+impl<'env> fmt::Debug for Scope<'env> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Scope")
+            .field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed))
+            .field("a_thread_panicked", &self.data.a_thread_panicked.load(Ordering::Relaxed))
+            .field("main_thread", &self.data.main_thread)
+            .finish_non_exhaustive()
+    }
+}
+
+impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ScopedJoinHandle").finish_non_exhaustive()
+    }
+}
diff --git a/sgx_tstd/src/time.rs b/sgx_tstd/src/time.rs
index fe761bc..6de4707 100644
--- a/sgx_tstd/src/time.rs
+++ b/sgx_tstd/src/time.rs
@@ -48,8 +48,6 @@
 
 #![allow(clippy::needless_doctest_main)]
 
-mod monotonic;
-
 use crate::error::Error;
 use crate::fmt;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
@@ -58,16 +56,16 @@
 
 pub use core::time::Duration;
 
-pub use core::time::FromSecsError;
+pub use core::time::FromFloatSecsError;
 
 /// A measurement of a monotonically nondecreasing clock.
 /// Opaque and useful only with [`Duration`].
 ///
-/// Instants are always guaranteed to be no less than any previously measured
-/// instant when created, and are often useful for tasks such as measuring
+/// Instants are always guaranteed, barring [platform bugs], to be no less than any previously
+/// measured instant when created, and are often useful for tasks such as measuring
 /// benchmarks or timing how long an operation takes.
 ///
-/// Note, however, that instants are not guaranteed to be **steady**. In other
+/// Note, however, that instants are **not** guaranteed to be **steady**. In other
 /// words, each tick of the underlying clock might not be the same length (e.g.
 /// some seconds may be longer than others). An instant may jump forwards or
 /// experience time dilation (slow down or speed up), but it will never go
@@ -97,6 +95,8 @@
 /// }
 /// ```
 ///
+/// [platform bugs]: Instant#monotonicity
+///
 /// # OS-specific behaviors
 ///
 /// An `Instant` is a wrapper around system-specific types and it may behave
@@ -138,6 +138,26 @@
 /// > structure cannot represent the new point in time.
 ///
 /// [`add`]: Instant::add
+///
+/// ## Monotonicity
+///
+/// On all platforms `Instant` will try to use an OS API that guarantees monotonic behavior
+/// if available, which is the case for all [tier 1] platforms.
+/// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization
+/// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks
+/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older Rust versions this
+/// lead to a panic instead. [`checked_duration_since`] can be used to detect and handle situations
+/// where monotonicity is violated, or `Instant`s are subtracted in the wrong order.
+///
+/// This workaround obscures programming errors where earlier and later instants are accidentally
+/// swapped. For this reason future rust versions may reintroduce panics.
+///
+/// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html
+/// [`duration_since`]: Instant::duration_since
+/// [`elapsed`]: Instant::elapsed
+/// [`sub`]: Instant::sub
+/// [`checked_duration_since`]: Instant::checked_duration_since
+///
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Instant(time::Instant);
 
@@ -189,7 +209,12 @@
 /// }
 /// ```
 ///
-/// # Underlying System calls
+/// # Platform-specific behavior
+///
+/// The precision of `SystemTime` can depend on the underlying OS-specific time format.
+/// For example, on Windows the time is represented in 100 nanosecond intervals whereas Linux
+/// can represent nanosecond intervals.
+///
 /// Currently, the following system calls are being used to get the current time using `now()`:
 ///
 /// |  Platform |               System call                                            |
@@ -258,81 +283,47 @@
         Instant::_now()
     }
 
+    #[inline]
     pub(crate) fn _now() -> Instant {
-        let os_now = time::Instant::now();
-
-        // And here we come upon a sad state of affairs. The whole point of
-        // `Instant` is that it's monotonically increasing. We've found in the
-        // wild, however, that it's not actually monotonically increasing for
-        // one reason or another. These appear to be OS and hardware level bugs,
-        // and there's not really a whole lot we can do about them. Here's a
-        // taste of what we've found:
-        //
-        // * #48514 - OpenBSD, x86_64
-        // * #49281 - linux arm64 and s390x
-        // * #51648 - windows, x86
-        // * #56560 - windows, x86_64, AWS
-        // * #56612 - windows, x86, vm (?)
-        // * #56940 - linux, arm64
-        // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar
-        //   Firefox bug
-        //
-        // It seems that this just happens a lot in the wild.
-        // We're seeing panics across various platforms where consecutive calls
-        // to `Instant::now`, such as via the `elapsed` function, are panicking
-        // as they're going backwards. Placed here is a last-ditch effort to try
-        // to fix things up. We keep a global "latest now" instance which is
-        // returned instead of what the OS says if the OS goes backwards.
-        //
-        // To hopefully mitigate the impact of this, a few platforms are
-        // excluded as "these at least haven't gone backwards yet".
-        //
-        // While issues have been seen on arm64 platforms the Arm architecture
-        // requires that the counter monotonically increases and that it must
-        // provide a uniform view of system time (e.g. it must not be possible
-        // for a core to recieve a message from another core with a time stamp
-        // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
-        // there have been a few 64bit SoCs that have bugs which cause time to
-        // not monoticially increase, these have been fixed in the Linux kernel
-        // and we shouldn't penalize all Arm SoCs for those who refuse to
-        // update their kernels:
-        // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1
-        // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10
-        // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11
-        // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12
-        if time::Instant::actually_monotonic() {
-            return Instant(os_now);
-        }
-
-        Instant(monotonic::monotonize(os_now))
+        Instant(time::Instant::now())
     }
 
-    /// Returns the amount of time elapsed from another instant to this one.
+    /// Returns the amount of time elapsed from another instant to this one,
+    /// or zero duration if that instant is later than this one.
     ///
     /// # Panics
     ///
-    /// This function will panic if `earlier` is later than `self`.
+    /// Previous rust versions panicked when `earlier` was later than `self`. Currently this
+    /// method saturates. Future versions may reintroduce the panic in some circumstances.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     ///
     /// # Examples
     ///
     /// ```no_run
     /// use std::time::{Duration, Instant};
     /// use std::thread::sleep;
-    /// use std::untrusted::time::InstantEx;
     ///
     /// let now = Instant::now();
     /// sleep(Duration::new(1, 0));
     /// let new_now = Instant::now();
     /// println!("{:?}", new_now.duration_since(now));
+    /// println!("{:?}", now.duration_since(new_now)); // 0ns
     /// ```
     #[must_use]
     pub fn duration_since(&self, earlier: Instant) -> Duration {
-        self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
+        self.checked_duration_since(earlier).unwrap_or_default()
     }
 
     /// Returns the amount of time elapsed from another instant to this one,
     /// or None if that instant is later than this one.
     ///
+    /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s,
+    /// this method can return `None`.
+    ///
+    /// [monotonicity bugs]: Instant#monotonicity
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -376,9 +367,11 @@
     ///
     /// # Panics
     ///
-    /// This function may panic if the current time is earlier than this
-    /// instant, which is something that can happen if an `Instant` is
-    /// produced synthetically.
+    /// Previous rust versions panicked when self was earlier than the current time. Currently this
+    /// method returns a Duration of zero in that case. Future versions may reintroduce the panic.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     ///
     /// # Examples
     ///
@@ -454,6 +447,16 @@
 impl Sub<Instant> for Instant {
     type Output = Duration;
 
+    /// Returns the amount of time elapsed from another instant to this one,
+    /// or zero duration if that instant is later than this one.
+    ///
+    /// # Panics
+    ///
+    /// Previous rust versions panicked when `other` was later than `self`. Currently this
+    /// method saturates. Future versions may reintroduce the panic in some circumstances.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     fn sub(self, other: Instant) -> Duration {
         self.duration_since(other)
     }
@@ -503,6 +506,7 @@
         SystemTime::_now()
     }
 
+    #[inline]
     pub(crate) fn _now() -> SystemTime {
         SystemTime(time::SystemTime::now())
     }
diff --git a/sgx_tstd/src/time/monotonic.rs b/sgx_tstd/src/time/monotonic.rs
deleted file mode 100644
index f577a6c..0000000
--- a/sgx_tstd/src/time/monotonic.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License..
-
-use crate::sys::time;
-
-#[inline]
-pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-    inner::monotonize(raw)
-}
-
-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
-pub mod inner {
-    use crate::sync::atomic::AtomicU64;
-    use crate::sync::atomic::Ordering::*;
-    use crate::sys::time;
-    use crate::time::Duration;
-
-    pub(in crate::time) const ZERO: time::Instant = time::Instant::zero();
-
-    // bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9
-    const UNINITIALIZED: u64 = 0b11 << 30;
-    static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED);
-
-    #[inline]
-    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-        monotonize_impl(&MONO, raw)
-    }
-
-    #[inline]
-    pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant {
-        let delta = raw.checked_sub_instant(&ZERO).unwrap();
-        let secs = delta.as_secs();
-        // occupies no more than 30 bits (10^9 seconds)
-        let nanos = delta.subsec_nanos() as u64;
-
-        // This wraps around every 136 years (2^32 seconds).
-        // To detect backsliding we use wrapping arithmetic and declare forward steps smaller
-        // than 2^31 seconds as expected and everything else as a backslide which will be
-        // monotonized.
-        // This could be a problem for programs that call instants at intervals greater
-        // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
-        let packed = (secs << 32) | nanos;
-        let updated = mono.fetch_update(Relaxed, Relaxed, |old| {
-            (old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2).then_some(packed)
-        });
-        match updated {
-            Ok(_) => raw,
-            Err(newer) => {
-                // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
-                // passed in value and the 64bits loaded from the atomic
-                let seconds_lower = newer >> 32;
-                let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
-                if secs & 0xffff_ffff > seconds_lower {
-                    // Backslide caused the lower 32bit of the seconds part to wrap.
-                    // This must be the case because the seconds part is larger even though
-                    // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
-                    //
-                    // We assume that backslides are smaller than 2^32 seconds
-                    // which means we need to add 1 to the upper half to restore it.
-                    //
-                    // Example:
-                    // most recent observed time: 0xA1_0000_0000_0000_0000u128
-                    // bits stored in AtomicU64:     0x0000_0000_0000_0000u64
-                    // backslide by 1s
-                    // caller time is             0xA0_ffff_ffff_0000_0000u128
-                    // -> we can fix up the upper half time by adding 1 << 32
-                    seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
-                }
-                let secs = seconds_upper | seconds_lower;
-                let nanos = newer as u32;
-                ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
-            }
-        }
-    }
-}
-
-#[cfg(target_has_atomic = "128")]
-pub mod inner {
-    use crate::sync::atomic::AtomicU128;
-    use crate::sync::atomic::Ordering::*;
-    use crate::sys::time;
-    use crate::time::Duration;
-
-    const ZERO: time::Instant = time::Instant::zero();
-    static MONO: AtomicU128 = AtomicU128::new(0);
-
-    #[inline]
-    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-        let delta = raw.checked_sub_instant(&ZERO).unwrap();
-        // Split into seconds and nanos since Duration doesn't have a
-        // constructor that takes a u128
-        let secs = delta.as_secs() as u128;
-        let nanos = delta.subsec_nanos() as u128;
-        let timestamp: u128 = secs << 64 | nanos;
-        let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp);
-        let secs = (timestamp >> 64) as u64;
-        let nanos = timestamp as u32;
-        ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
-    }
-}
-
-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
-pub mod inner {
-    use crate::cmp;
-    use crate::sys::time;
-    use crate::sys_common::mutex::StaticMutex;
-
-    #[inline]
-    pub(super) fn monotonize(os_now: time::Instant) -> time::Instant {
-        static LOCK: SgxThreadMutex = SgxThreadMutex::new();
-        static mut LAST_NOW: time::Instant = time::Instant::zero();
-        unsafe {
-            let _lock = LOCK.lock();
-            let now = cmp::max(LAST_NOW, os_now);
-            LAST_NOW = now;
-            let _ = LOCK.unlock();
-            now
-        }
-    }
-}
diff --git a/sgx_tstd/src/untrusted/path.rs b/sgx_tstd/src/untrusted/path.rs
index eae9843..fb6144f 100644
--- a/sgx_tstd/src/untrusted/path.rs
+++ b/sgx_tstd/src/untrusted/path.rs
@@ -15,10 +15,9 @@
 // specific language governing permissions and limitations
 // under the License..
 
-use crate::untrusted::fs;
+use crate::fs;
 use crate::io;
-use crate::path::Path;
-use crate::path::PathBuf;
+use crate::path::{self, Path, PathBuf};
 
 pub trait PathEx {
     fn metadata(&self) -> io::Result<fs::Metadata>;
@@ -275,3 +274,73 @@
         fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
     }
 }
+
+/// Makes the path absolute without accessing the filesystem.
+///
+/// If the path is relative, the current directory is used as the base directory.
+/// All intermediate components will be resolved according to platforms-specific
+/// rules but unlike [`canonicalize`][crate::fs::canonicalize] this does not
+/// resolve symlinks and may succeed even if the path does not exist.
+///
+/// If the `path` is empty or getting the
+/// [current directory][crate::env::current_dir] fails then an error will be
+/// returned.
+///
+/// # Examples
+///
+/// ## Posix paths
+///
+/// ```
+/// #![feature(absolute_path)]
+/// # #[cfg(unix)]
+/// fn main() -> std::io::Result<()> {
+///   use std::path::{self, Path};
+///
+///   // Relative to absolute
+///   let absolute = path::absolute("foo/./bar")?;
+///   assert!(absolute.ends_with("foo/bar"));
+///
+///   // Absolute to absolute
+///   let absolute = path::absolute("/foo//test/.././bar.rs")?;
+///   assert_eq!(absolute, Path::new("/foo/test/../bar.rs"));
+///   Ok(())
+/// }
+/// # #[cfg(not(unix))]
+/// # fn main() {}
+/// ```
+///
+/// The path is resolved using [POSIX semantics][posix-semantics] except that
+/// it stops short of resolving symlinks. This means it will keep `..`
+/// components and trailing slashes.
+///
+/// ## Windows paths
+///
+/// ```
+/// #![feature(absolute_path)]
+/// # #[cfg(windows)]
+/// fn main() -> std::io::Result<()> {
+///   use std::path::{self, Path};
+///
+///   // Relative to absolute
+///   let absolute = path::absolute("foo/./bar")?;
+///   assert!(absolute.ends_with(r"foo\bar"));
+///
+///   // Absolute to absolute
+///   let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?;
+///
+///   assert_eq!(absolute, Path::new(r"C:\foo\bar.rs"));
+///   Ok(())
+/// }
+/// # #[cfg(not(windows))]
+/// # fn main() {}
+/// ```
+///
+/// For verbatim paths this will simply return the path as given. For other
+/// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
+/// This may change in the future.
+///
+/// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+/// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
+pub fn absolute<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    path::_absolute(path)
+}
diff --git a/sgx_tunittest/Cargo.toml b/sgx_tunittest/Cargo.toml
index b218bd0..75bc127 100644
--- a/sgx_tunittest/Cargo.toml
+++ b/sgx_tunittest/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 include = [
     "LICENSE",
diff --git a/sgx_types/BUILD b/sgx_types/BUILD
index 99de063..c83124b 100644
--- a/sgx_types/BUILD
+++ b/sgx_types/BUILD
@@ -3,7 +3,7 @@
 rust_library(
     name = "sgx_types",
     visibility = ["//visibility:public"],
-    edition = "2018",
+    edition = "2021",
     srcs = glob(["src/*.rs"]),
     deps = [],
 )
\ No newline at end of file
diff --git a/sgx_types/Cargo.toml b/sgx_types/Cargo.toml
index 04dd878..f46b176 100644
--- a/sgx_types/Cargo.toml
+++ b/sgx_types/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_types"
diff --git a/sgx_ucrypto/Cargo.toml b/sgx_ucrypto/Cargo.toml
index 99d1547..5fe574a 100644
--- a/sgx_ucrypto/Cargo.toml
+++ b/sgx_ucrypto/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_ucrypto"
diff --git a/sgx_unwind/Cargo.toml b/sgx_unwind/Cargo.toml
index feae347..c90d477 100644
--- a/sgx_unwind/Cargo.toml
+++ b/sgx_unwind/Cargo.toml
@@ -7,7 +7,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 exclude = [
     "libunwind/autom4te.cache/*",
     "libunwind/aclocal.m4",
diff --git a/sgx_unwind/build.rs b/sgx_unwind/build.rs
index dada8f6..89c5603 100644
--- a/sgx_unwind/build.rs
+++ b/sgx_unwind/build.rs
@@ -15,8 +15,6 @@
 // specific language governing permissions and limitations
 // under the License..
 
-#![feature(available_parallelism)]
-
 extern crate sgx_build_helper as build_helper;
 
 use build_helper::{native_lib_boilerplate, run};
diff --git a/sgx_unwind/libunwind/src/se-iterate-phdr.c b/sgx_unwind/libunwind/src/se-iterate-phdr.c
index 85f08f2..74390a6 100644
--- a/sgx_unwind/libunwind/src/se-iterate-phdr.c
+++ b/sgx_unwind/libunwind/src/se-iterate-phdr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2020 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011-2021 Intel Corporation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
diff --git a/sgx_unwind/libunwind/src/se-libc-stubs.c b/sgx_unwind/libunwind/src/se-libc-stubs.c
index bb94ece..cb1592c 100644
--- a/sgx_unwind/libunwind/src/se-libc-stubs.c
+++ b/sgx_unwind/libunwind/src/se-libc-stubs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2020 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011-2021 Intel Corporation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
diff --git a/sgx_unwind/src/macros.rs b/sgx_unwind/src/macros.rs
index a1d26d6..ae6fa6e 100644
--- a/sgx_unwind/src/macros.rs
+++ b/sgx_unwind/src/macros.rs
@@ -1,12 +1,19 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
 //
-// 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.
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License..
 
 /// A macro for defining `#[cfg]` if-else statements.
 ///
diff --git a/sgx_urts/Cargo.toml b/sgx_urts/Cargo.toml
index 00c5b2b..b5a2320 100644
--- a/sgx_urts/Cargo.toml
+++ b/sgx_urts/Cargo.toml
@@ -6,7 +6,7 @@
 license-file = "LICENSE"
 documentation = "https://teaclave.apache.org/sgx-sdk-docs/"
 description = "Rust SGX SDK provides the ability to write Intel SGX applications in Rust Programming Language."
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "sgx_urts"
diff --git a/sgx_urts/src/file.rs b/sgx_urts/src/file.rs
index 1666232..0b6d8b7 100644
--- a/sgx_urts/src/file.rs
+++ b/sgx_urts/src/file.rs
@@ -57,6 +57,26 @@
 }
 
 #[no_mangle]
+pub extern "C" fn u_openat_ocall(
+    error: *mut c_int,
+    dirfd: c_int,
+    pathname: *const c_char,
+    flags: c_int,
+) -> c_int {
+    let mut errno = 0;
+    let ret = unsafe { libc::openat(dirfd, pathname, flags) };
+    if ret < 0 {
+        errno = Error::last_os_error().raw_os_error().unwrap_or(0);
+    }
+    if !error.is_null() {
+        unsafe {
+            *error = errno;
+        }
+    }
+    ret
+}
+
+#[no_mangle]
 pub extern "C" fn u_fstat_ocall(error: *mut c_int, fd: c_int, buf: *mut stat) -> c_int {
     let mut errno = 0;
     let ret = unsafe { libc::fstat(fd, buf) };
@@ -338,6 +358,26 @@
 }
 
 #[no_mangle]
+pub extern "C" fn u_unlinkat_ocall(
+    error: *mut c_int,
+    dirfd: c_int,
+    pathname: *const c_char,
+    flags: c_int,
+) -> c_int {
+    let mut errno = 0;
+    let ret = unsafe { libc::unlinkat(dirfd, pathname, flags) };
+    if ret < 0 {
+        errno = Error::last_os_error().raw_os_error().unwrap_or(0);
+    }
+    if !error.is_null() {
+        unsafe {
+            *error = errno;
+        }
+    }
+    ret
+}
+
+#[no_mangle]
 pub extern "C" fn u_linkat_ocall(
     error: *mut c_int,
     olddirfd: c_int,
@@ -478,6 +518,21 @@
 }
 
 #[no_mangle]
+pub extern "C" fn u_fdopendir_ocall(error: *mut c_int, fd: c_int) -> *mut DIR {
+    let mut errno = 0;
+    let ret = unsafe { libc::fdopendir(fd) };
+    if ret.is_null() {
+        errno = Error::last_os_error().raw_os_error().unwrap_or(0);
+    }
+    if !error.is_null() {
+        unsafe {
+            *error = errno;
+        }
+    }
+    ret
+}
+
+#[no_mangle]
 pub extern "C" fn u_opendir_ocall(error: *mut c_int, pathname: *const c_char) -> *mut DIR {
     let mut errno = 0;
     let ret = unsafe { libc::opendir(pathname) };
diff --git a/sgx_ustdc/file.c b/sgx_ustdc/file.c
index 3303015..2a3fa7c 100644
--- a/sgx_ustdc/file.c
+++ b/sgx_ustdc/file.c
@@ -47,6 +47,15 @@
     return ret;
 }
 
+int u_openat_ocall(int *error, int dirfd, const char *pathname, int flags)
+{
+    int ret = openat(dirfd, pathname, flags);
+    if (error) {
+        *error = ret == -1 ? errno : 0;
+    }
+    return ret;
+}
+
 int u_fstat_ocall(int *error, int fd, struct stat *buf)
 {
     int ret = fstat(fd, buf);
@@ -200,6 +209,15 @@
     return ret;
 }
 
+int u_unlinkat_ocall(int *error, int dirfd, const char *pathname, int flags)
+{
+    int ret = unlinkat(dirfd, pathname, flags);
+    if (error) {
+        *error = ret == -1 ? errno : 0;
+    }
+    return ret;
+}
+
 int u_linkat_ocall(int *error, int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags)
 {
     int ret = linkat(olddirfd, oldpath, newdirfd, newpath, flags);
@@ -272,7 +290,16 @@
     return ret;
 }
 
-void *u_opendir_ocall(int *error, const char *pathname)
+DIR *u_fdopendir_ocall(int *error, int fd)
+{
+    DIR *ret = fdopendir(fd);
+    if (error) {
+        *error = ret == NULL ? errno : 0;
+    }
+    return ret;
+}
+
+DIR *u_opendir_ocall(int *error, const char *pathname)
 {
     DIR *ret = opendir(pathname);
     if (error) {
diff --git a/xargo/sgx_tstd/Cargo.toml b/xargo/sgx_tstd/Cargo.toml
index 391c5b1..7a1c23c 100644
--- a/xargo/sgx_tstd/Cargo.toml
+++ b/xargo/sgx_tstd/Cargo.toml
@@ -3,7 +3,7 @@
 version = "0.0.0"
 authors = ["The Teaclave Authors"]
 build = "build.rs"
-edition = "2018"
+edition = "2021"
 
 [lib]
 name = "std"
diff --git a/xargo/x86_64-unknown-linux-sgx.json b/xargo/x86_64-unknown-linux-sgx.json
index 69b38be..53f104e 100644
--- a/xargo/x86_64-unknown-linux-sgx.json
+++ b/xargo/x86_64-unknown-linux-sgx.json
@@ -1,13 +1,13 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
+  "crt-static-respected": true,
   "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
-  "exe-allocation-crate": "alloc_system",
   "executables": true,
-  "has-elf-tls": true,
   "has-rpath": true,
+  "has-thread-local": true,
   "linker-flavor": "gcc",
   "linker-is-gnu": true,
   "llvm-target": "x86_64-unknown-linux-gnu",
@@ -30,6 +30,13 @@
       1
     ]
   },
+  "supported-sanitizers": [
+    "address",
+    "cfi",
+    "leak",
+    "memory",
+    "thread"
+  ],
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",