SGX target and "no operating system" x86/x86_64 targets in general


#1

In one of my crates it would be very helpful to know whether SGX is being targeted and/or whether there is no underlying operating system, e.g. because the user of the crate is itself an operating system. Up to this point we’ve done this by using #![no_std], however this approach has worked out fairly poorly because avoiding use of the default allocator is painful. I would instead like to target "x86_64 with no operating system facilities assumed except for a heap for dynamic allocation.”

I remember the old discussion on “scenerios” which lead to the portability lint RFC. However there doesn’t seem to be a concrete plan for the subsetting idea; in particular, there doesn’t seem to be a way to indicate that some code (optionally) depends on only the heap allocation part of libstd.

Thus, my questions are:

  1. What should the target for SGX be? Should there be a x86_64-intel-sgx target? Should we use some x86_64-pc-none target?

  2. What should the target for an (x86-64) operating system kernel be?

  3. What is the preferred route to creating a way to target an (x86_64) subset of libstd that where libstd provides a heap but none of the (I/O) services that delegate to an OS?

/cc @jethrogb


#2

I’m in a very similar boat, targeting two no_std environments in the “no operating system facilities except for a heap” category (one of which is SGX) and would concur things could be a lot better here.


#3

1 What should the target for SGX be? Should there be a x86_64-intel-sgx target? Should we use some x86_64-pc-none target?

We are internally using x86_64-unknown-none-gnu, see https://github.com/rust-lang/rust/pull/37133 and latest port at https://github.com/jseyfried/rust/tree/no_os. This is quite the misnomer of course, since there is no GNU.

There is of course no standard (yet). I’m sure we can come up with something reasonable here. For example:

  • arch: x86_64 (or i686)
  • os: none (or unknown?)
  • env: sgx (possibly a hint to the compiler meaning SGX in-enclave user leaf instructions should work)
  • vendor: unknown (for raw SGX usage), or intel (when compiling with the Intel SDK), or some other vendor

2 What should the target for an (x86-64) operating system kernel be?

I’d say something like x86_64-none-unknown

3 What is the preferred route to creating a way to target an (x86_64) subset of libstd that where libstd provides a heap but none of the (I/O) services that delegate to an OS?

That would probably be Refactoring std for ultimate portability. I think there is consensus around the design, someone just needs to do the work. Note that Rust’s std currently requires a source of randomness to operate (because of std::collections::hash_map::RandomState). This is fine on x86_64 if you have RDRAND, but on other platforms operating std without an OS might just not be possible.


#4

Right. Basically I want to detect when SGX is the target and perhaps default to seeding the RNG using RDRAND only in that case, and require the use of the OS facilities otherwise. And in both the SGX and “I’m implementing the OS myself” cases, I want to provide facilities for implementing the OS PRNG, e.g. using a FIPS-140-ish PRNG/DRBG, including in particular adding API hooks for seeding. This also requires knowing whether we have to worry about fork()/clone()/etc.


#5

Something I think would be immensely helpful for “no operating system facilities except for a heap” use cases is if Box, String, and Vec were magically added to the prelude somehow if you have an #[allocator] defined.

Right now using them in no_std environments involves using them through the liballoc API, which requires #[feature(alloc)] which requires nightly, then littering your code with a bunch of use alloc::boxed::Box etc directives, potentially gated on cargo features for pulling them in through liballoc rather than std.

If they were just in the prelude, the use directives and #[feature(alloc)] would be unnecessary and there would be no nightly dependency.