rust-lang / rfcs

RFCs for changes to Rust
https://rust-lang.github.io/rfcs/
Apache License 2.0
5.88k stars 1.56k forks source link

Consider adding Linux targets that don't depend on libc #2610

Open japaric opened 5 years ago

japaric commented 5 years ago

e.g. x86_64-linux (or x86_64-unknown-linux-rust).

These would be the spiritual successor of steed: a standard library, free of C dependencies, for Linux systems. Steed implemented (or planned to) the Rust standard library using raw Linux system calls instead of libc's API. These libc-less targets would also implement std using raw system calls.

Even though steed has been inactive for over a year people continue to star it on GitHub and currently has over 500 stars so it seems there's still interest for something like it.

What we learned during development is that maintaining a standard library out of tree is a lot of work because things get quickly out sync so if there's still interest for something like steed I would recommend writing an RFC to add support for libc-less targets (e.g. x86_64-linux) to rust-lang/rust; this would be equivalent to importing and developing steed as part of rust-lang/rust.

An RFC is also a good way to (re-)evaluate the ROI of making a libc-less standard library. One of the goals of steed was hassle-free cross compilation but today that's solved by the Linux/MUSL targets + rust-lld (works on stable). The other goal was better optimizations (plain LTO doesn't optimize across FFI) but cross-language LTO is a now thing (-Z cross-lang-lto). There may be less costly ways to achieve the same results.

The rest of this post describes the status of steed as of 2017-10-20 (date of last commit).

What we had working:

  1. standard I/O (std::io::{stdin,stderr,stdout})
  2. filesystem operations (std::fs)
  3. collections (std::collections) (but see (a) below)
  4. std::sync::Mutex (courtesy of parking_lot)
  5. std::env
  6. UDP and TCP sockets (std::net) (but see (d) below)
  7. minimal support for threads and TLS
  8. #[test] support (but see (c) below)

You can check the examples directory to get an idea of what you could write with it.

What was missing:

a. a proper allocator. steed used a bump pointer allocator that never freed memory b. all the math stuff (e.g. f32::sin). These days one can use libm. c. unwinding, all the steed targets used -C panic=abort d. hostname lookup e. errno. It was unclear whether we should implement it or not. It seems to only be required by std::io::Error::last_os_error. Linux system calls have a Result-like API so errno is not required to propagate errors from syscalls to the std API.

and much more stuff; you can check the issue tracker for the full list.


cc @tbu- @briansmith

mark-i-m commented 5 years ago

This sounds really cool! However, I think you may be underestimating how much work this is. There would also need to be collaboration with kernel developers about system calls and stuff.

lorenz commented 5 years ago

@mark-i-m I agree that it is quite a bit of work, but there is no need for collaborating with kernel devs. The syscall interface is considered stable and they treat any change that'll break userspace as a bug. Go has successfully implemented this strategy on all OSs they support. So I'd argue it is pretty doable and in my opinion desirable.

tbu- commented 5 years ago

This sounds really cool! However, I think you may be underestimating how much work this is. There would also need to be collaboration with kernel developers about system calls and stuff.

Most of the stuff was already in place, as you can see in @japaric's comment. :)

mark-i-m commented 5 years ago

@lorenz Yes, you are right, but what I mean is that if we want to influence the syscall interfaces to make them more Rust-friendly we would need to interact more with the kernel devs...

lorenz commented 5 years ago

@mark-i-m What do you have in mind that you want changed? The syscall interface is totally usable from Rust and is in various ways a better fit than libc itself.

mark-i-m commented 5 years ago

Admittedly, I haven't yet gotten to thinking extensively about this, but mainly my thinking is that syscalls often don't even attempt to by safe, so adding good Rust wrappers around them is either painful or inefficient.

For example, it is hard to write a good safe wrapper for mmap because it can do so many things; encoding all of them into efficient zero-cost abstractions is hard. There are also a bunch of syscalls that depend on C-defined structs/types (and their layouts), e.g. clock_get*, sched_setaffinity. (EDIT: actually, I'm not sure if these structs/types are just parts of libc... so I might be wrong there...)

lorenz commented 5 years ago

But this is not about implementing all possible safe uses of (for example) mmap, but just about reimplementing the standard library on top of syscalls which limits the scope to these specific operations. Also structs with C layout are no problem in Rust (we have #[repr(C)]) and are a sensible choice for a kernel since they are interoperable with everything. The kernel people will never maintain a separate syscall interface just for a specific programming language.

mark-i-m commented 5 years ago

The kernel people will never maintain a separate syscall interface just for a specific programming language.

No, but they do talk with e.g. libc maintainers to discuss interfaces, libc support, etc.

But this is not about implementing all possible safe uses of (for example) mmap, but just about reimplementing the standard library on top of syscalls which limits the scope to these specific operations.

That's true, but this is also an opportunity to expose the kernel ABI in a safer way, although that doesn't seem to be the intent of this issue...

SimonSapin commented 5 years ago

Any newly-proposed syscall will at best be present in the next kernel version, but it’ll be a number of years before you can usefully ship a program that just assumes it is present.

briansmith commented 5 years ago

Any newly-proposed syscall will at best be present in the next kernel version, but it’ll be a number of years before you can usefully ship a program that just assumes it is present.

Yes, but Rust can take advantage of them right away by falling back to something else when it receives ENOSYS (or whatever), without having to rely on convincing glibc/musl maintainers to do so.

SimonSapin commented 5 years ago

Sure but if a fallback is needed anyway there is no point in doing all this only "to make them more Rust-friendly", is there? (As opposed to, say, a performance optimization.)

joshtriplett commented 5 years ago

@mark-i-m It sounds like you're interested in something different than this is proposing. @japaric is proposing a standard library that's equivalent to the current std but without linking to the platform libc, by calling existing syscalls directly. That's a useful goal that many people want, and it doesn't involve changes to syscalls in any way.

If someone wanted to add new syscalls to Linux, for whatever reason, that would be outside the scope of this proposal.

joshtriplett commented 5 years ago

As a separate thought, for a target like this, we could theoretically have a libc-compatible C library implemented in Rust, and then link C programs to that library. We don't need that, but it would make for an interesting future addition to this target.

Darkspirit commented 5 years ago

libc-compatible C library implemented in Rust

https://gitlab.redox-os.org/redox-os/relibc#relibc https://github.com/redox-os/relibc

"relibc is a portable POSIX C standard library written in Rust."

It is under heavy development, and currently supports Redox and Linux.

The motivation for this project is twofold: Reduce issues the redox crew was having with newlib, and create a safer alternative to a C standard library written in C. It is mainly designed to be used under redox, as an alternative to newlib, but it also supports linux syscalls via the sc crate.

Supported OSes Redox OS Linux

Supported architectures x86_64 Aarch64

Edit: Just found this: This tries to add an x86_64-unknown-linux-relibc target: https://github.com/mati865/rust/issues/1#issuecomment-487393630 https://github.com/mati865/rust/compare/master...relibc https://github.com/rust-lang/libc/compare/master...mati865:relibc

newpavlov commented 5 years ago

Looking forward to playing with this libc-free target! I wonder if it will be possible to later remove x86_64-unknown-linux reliance on libc after experimenting on a separate target?

newpavlov commented 5 years ago

a proper allocator. steed used a bump pointer allocator that never freed memory

IIUC elfmalloc can be used here.

zmlzm commented 5 years ago

There is a news : A libc in LLVM

dvc94ch commented 5 years ago

Does adding new targets require a rfc? Or were large changes required to the codebase?

elichai commented 4 years ago

Hi, I've started working on exactly this but with a bit of a different mindset.

My goal is to push rust safety's guarantees as much as possible. currently it stops at the entrance to libc. so I'm writing a rust libc implementation.

I already seen parts of libc that have UB potential if you misuse them. something that rust can easily solve.

But. I want this to be a usable target, so I propose to make a new target that will still link to libc, but will slowly move away from using libc, currently I see 3 areas where libc is actually needed:

  1. There are users who call libc and then use std::io::Error::last_os_error() for the errno. so we need to keep this working(potentially until a new edition / rust 2.X where we could deprecate this?)
  2. libunwind.
  3. pthreads.

For the first one, I personally think it's fine, because then LTO should remove libc for users who don't use that part of libstd.

For the second one I think the right path forward is a rewrite in rust. but I understand that this can take a while.

For the third one, this should be a public discussion. do we want to just copy the pthreads implementation? or do we want to invent our own threads that makes more sense for rust? if so how will that affect FFI to C?

Until these questions are answered I still think it's a big win to have a target that for the short run tries to minimize the calls to libc but for the long run plans to remove it completely.

Would love people's feedback on this. Already made a list of all the calls to libc in rust's libstd, and a start of how I think the API can/should look like https://github.com/elichai/syscalls-rs

To emphasize. I don't want just a musl rewrite in rust with big blobs of unsafe. My whole point is to extend the safety because: A. libstd dev's can also make mistakes, so let's get them a safer API like what they're doing for the users in all other aspects. B. A lot of users in the wild are calling libc, we can make this safer. C. I hope that one day we'll get memory safety through the whole stack, and I think this is the next stage for rust.

SimonSapin commented 4 years ago

I'm writing a rust libc implementation.

To me “libc implementation” means something specific. It provides C APIs as defined in the C standard and POSIX, and tries to be compatible with other implementations in the same way that musl and glibc are compatible with each other. relibc is a libc implementation written in Rust.

It seems that you don’t mean that, but rather something that “spiritually” fills a role similar to that of libc in communicating with the kernel through syscalls and providing higher-level abstractions?

A lot of users in the wild are calling libc, we can make this safer.

Or do you mean something used not instead of libc, but an abstraction on top of it?

how will that affect FFI to C?

As far as I can tell, steed and this issue are about programs that do not use C at all. As soon as you have C code that code needs a libc implementation (as defined above), so there isn’t much point in avoiding it in libstd, in my opinion.

elichai commented 4 years ago

I'm talking about a rust replacement for libc. I'm not planing of exposing FFI functions to C. The point is to have something like "libr" meaning all the libc functionality but for rust. because we're not C. So currently I'm trying to give the same functions but have rust safer function signatures to them.

I hope that in the long run it will prove itself safer and overall better. then we'd want to use it in libstd by default even if you still link to C code that'll use libc.

SimonSapin commented 4 years ago

If you’re changing signatures anyway, it doesn’t have to stay close to “the same functions” at all. Do you need any well-defined abstraction between libstd’s public API and syscalls? Why shouldn’t std::fs::File be the safer signature for open(2)?

elichai commented 4 years ago

It could, although open is used directly also in flock::Lock. but this is just 1 syscall. there are some syscalls scattered all over libstd. this could be a simple drop in replacement for most of them. (maybe a bit more gymnastics for flags etc.)

and the point is levels of abstractions, you can have a function that calls directly 4 syscalls and handles all their errors etc. and then say that that function is the safer api. but for good better abstractions it's better to split each syscall and the handling of the data/errors to it's own file. that way it's also way easier to review carefully.

dvc94ch commented 4 years ago

If you’re changing signatures anyway, it doesn’t have to stay close to “the same functions” at all. Do you need any well-defined abstraction between libstd’s public API and syscalls? Why shouldn’t std::fs::File be the safer signature for open(2)?

There is also a lot of stuff you can't do with rusts stdlib at the moment, some which I've needed recently are:

While there are libraries doing these things, they use the libc crate and are usually plastered with unsafe code.

castarco commented 3 years ago

The point is to have something like "libr" meaning all the libc functionality but for rust. because we're not C. So currently I'm trying to give the same functions but have rust safer function signatures to them.

I think it makes a lot of sense... although it would be nicer if that hypothetical libr was linkable from non-rust binaries too. The problem here is that a lot of time will pass until we a stable ABI, and this constrains a lot the kind of interfaces that we could expose in that libr until then.

As a side note, the name libr was taken 5 years ago, for a binding to the language R. Even more sadly, that library seems abandoned. There's another (very small) library librs that seems to go in that direction, but probably abandoning the possibility of being linkable from non-rust code.

pmmccorm commented 3 years ago

In summary the options are:

1) Create an entirely new layer for libstd to use. This layer can be written as if its sole consumer is libstd, so it needs to provide "just enough" / exactly what libstd needs The layer can reside outside of libstd (no_std) or built into libstd. libstd can be ported to this.

2) Create a drop-in libc replacement implemented entirely no_std. libstd will then use this and other applications can use this as well. In addition this can provide a C-linkable ABI, so it could also serve as a drop-in replacement for libc. Stretch goal.

3) I'm adding a sort of hybrid of the above two here: implement the subset of libc that libstd uses in pure no_std rust. The API does not have to match C's exactly (but still drop-in), it can just meet what libstd is expecting and using. The list posted by @elichai would serve as a starting point: https://github.com/elichai/syscalls-rs

"Step 0" for any of the above paths is: The machinery for syscalls (discovering what is available, which numbers they are, how to make them) for all supported platforms (CPU + OS). glibc does all sorts of things at build time to generate these. This should really be in a whole separate no_std library. Does something like this exist already?

Once this no_std_syscall library exists option 1/3 can be brought up pretty quickly and evolved into 2 as time passes.

newpavlov commented 3 years ago

I don't think we should copy libc API since it would allow us to remove some of its peculiarities, e.g. errno. Plus it would reduce scope of the work significantly. So the first option is the best one in my opinion.

The machinery for syscalls (discovering what is available, which numbers they are, how to make them) for all supported platforms (CPU + OS). glibc does all sorts of things at build time to generate these.

Aren't syscall numbers fixed per target arch? And since Rust have recently updated supported kernel version, we don't need too much of fallback code (if any). As for OS, IIRC only Linux has stable syscall API.

briansmith commented 3 years ago
  1. Create an entirely new layer for libstd to use. This layer can be written as if its sole consumer is libstd, so it needs to provide "just enough" / exactly what libstd needs The layer can reside outside of libstd (no_std) or built into libstd. libstd can be ported to this.

My interest in this is to greatly reduce use of unsafe in the libstd codebase, so the "entirely new layer for libstd to use" approach is the one I prefer.

The machinery for syscalls (discovering what is available, which numbers they are, how to make them) for all supported platforms (CPU + OS). glibc does all sorts of things at build time to generate these. This should really be in a whole separate no_std library. Does something like this exist already?

It depends on the operating system. Not all operating systems provide a stable ABI at the syscall layer. I'm thinking about Windows in particular.

Note also this issue is scoped to Linux currently: "Consider adding Linux targets that don't depend on libc." I don't think we should expand the scope to other operating systems.

elichai commented 3 years ago

My interest in this is to greatly reduce use of unsafe in the libstd codebase, so the "entirely new layer for libstd to use" approach is the one I prefer.

Yep, that's also my interest, reducing unsafe code + getting rid of safety minefields that libc has (especially around vargs handling). this is why I've started: https://github.com/elichai/syscalls-rs, which gives a rust-like API directly to syscalls , but sadly I don't have a lot of time lately, hope to come back to this (also, reimplementing pthreads will not be an easy task)

sunfishcode commented 3 years ago

I'm working on a project which opens up another option: rsix.

It's similar to syscalls-rs mentioned above in that it can use native-linux syscalls, but it's structured to have configurable backends, with raw linux syscalls and libc being the two current options. And, while it has inline asm that it uses on nightly Rust, it also has out-of-line asm for stable Rust as well. So for the functions it supports, crates can use it today as a drop-in replacement for libc, because it supports all the same platforms libc does, using native syscalls when it can, and libc itself when it can't.

And, it's built around some novel features, notably OwnedFd/BorrowedFd in place of RawFd (see the I/O safety RFC for background).

These properties enable it to be useful in some real-world use cases today, which will ideally will help it grow in a sustainable way.

sunfishcode commented 3 years ago

mustang is built on rsix, and which adds program startup, selected libc replacements, and adds a #[global_allocator], and defines custom targets (eg. x86-64_unknoxn-linux-mustang, aarch64-unknown-linux-mustang). With all these together, it can build programs built entirely in Rust, with no dependency on libc or crt1.o, including a fully std-using Hello World.

jxsl13 commented 2 years ago

making rust libc independent would be a great step forward.

sunfishcode commented 2 years ago

Mustang now has a pthread implementation, including TLS, TLS destructors, and detaching. It's complete enough to pass all of these, and can run tests via the standard #[test] harness. And, mustang now uses the dlmalloc allocator.

In all, mustang now supports everything from Steed's "What we had working" list at the top of this issue, plus several things from Steed's "What was missing" list:

sunfishcode commented 2 years ago

Mustang now has:

Mustang is still experimental, though it's now able to run non-trivial programs. I encourage people to try it out, and report their experiences!

In terms of the options described above here, Mustang does both 1 and 3 right now.

In theory, std could be ported to use rsix directly, factoring out many instances of unsafe, as discussed above. Eventually, this could become possible with origin and other crates too. In any case, I encourage anyone interest to discuss it in the issue.

sunfishcode commented 2 years ago

Mustang now supports threads with TLS, TLS destructors, and detaching. This blog post walks through what Mustang's new thread support is and how it works.

sunfishcode commented 2 years ago

Is Mustang a good idea? If so, how would you use it? Is Mustang the wrong approach? Is it confusing? Is this issue not worth solving anymore now that Rust has musl targets and cross-language LTO? I'm interested in any feedback people would like to share, including negative feedback.

parasyte commented 2 years ago

I have followed this thread for a long time because I would like to bring more std capabilities to a custom target that I maintain only infrequently. Mustang interests me for that reason, but I haven't given it any evaluation with my use case. I'm not entirely sure where to begin, but it appears I would need more than just Mustang since it builds on rsix. My target is "bare metal" and doesn't have a kernel to provide syscalls.

That said, if I were to implement the minimal number of syscalls (whatever that list looks like) for my target, and it allowed me to use Mustang as a sorta drop-in replacement for std, that would be sooooo satisfying.

jeff-hykin commented 2 years ago

Is Mustang a good idea? If so, how would you use it? Is Mustang the wrong approach? Is it confusing? Is this issue not worth solving anymore now that Rust has musl targets and cross-language LTO? I'm interested in any feedback people would like to share, including negative feedback.

@sunfishcode

Every programming problem I have, when I track it down to it's source, seems to originate with C/C++. It wasn't till a few years ago that I realized how seriously everything I do somehow, some way, has C/C++ as a foundation. Basically every zero-day exploit in my cyber security class is because of something stupid in C/C++. And it goes well beyond security, the more I dive into C++ the more terrible stuff I find. When I found out even Rust needed the clib, it was like seeing an iron-clad fortress only to look closer and see it was being held up by sticks, ducktape, and prayers.

A perfect example is two days ago I was trying to convert an RGB array to a PNG ... in Python. All the python libraries for png's; they have messy C/C++ dependencies. I wanted to see how the image conversion was implemented so I go to libpng's website. And whatdyahknow, there's a warning about a major security flaw right there at the top of the page.

IMG_20211022_075506_535.jpg

But I don't even care about security; I just care about correctness and clarity. Libpng was your typical big messy confusing C codebase. So what do I do? I search for a Rust PNG lib. (Again, I'm coding Python, yet my workflow is pulling me into lower levels of code). Not only was there a pure Rust implementation, not only does it avoid ever using unsafe, but most importantly to me: I can fricken understand the code at a high level. I have about 5 years of frequent C++ experience, and about 3 months of Rust experience, yet when I want to understand an implementation I go to the Rust codebase.

TLDR: Musl is great and all, but I actually want to be able to read, understand, and trust the implementation, not just wrap up my code into a static binary. And if there was one thing that SHOULDN'T be C in my opinion it would be the very foundation of Rust itself.

newpavlov commented 2 years ago

@sunfishcode I am a big fan of pure-Rust targets (e.g. I think we also should have a pure Rust WASI target). I think that Mustang is a great initiative for prototyping libc-free Rust std and its achievements are laudable, but I believe it should be eventually merged into Rust proper, otherwise it risks the same fate as steed. Not only the current approach is less ergonomic compared to using MUSL, but also has discoverability issues.

sunfishcode commented 2 years ago

Thanks for the feedback! I appreciate hearing people's thoughts :-).

A few updates: @nivkner implemented fork+exec support, and @nivkner and @Urgau added support for sched_affinity, so Mustang can now run std::process::Command, and it can even now run ripgrep in some cases! Some features are still missing though.

I've also started a branch to explore another side of the space, porting Rust's std to rustix. See here for the current status.

cgwalters commented 2 years ago

From my PoV, most of the important projects for which I use Rust will have C/C++ linked in process for the forseeable future. I know I'm not alone in that.

I can certainly understand the desire for something like mustang, but I think the concern boils down to: is the benefit of adding this new target worth the maintenance overhead?

A somewhat related concern I have is proliferation and duplication of low-level crates. Most in the community seem OK with the way crates.io works versus having a larger standard library. But there are tradeoffs with this. For example, my company's software needs to be multi-arch across beyond just aarch64 and x86_64, also to ppc64le and s390x. Historically, they mostly needed to adapt to changes in the Linux kernel and glibc. Now of course in the Linux ecosystem there's also musl and bionic, but rustix is adding another one. That's not without cost.

rustix heavily overlaps with nix - which is a dependency of tokio for example.

Related to this, the distributed crates.io ecosystem also means that there's much less uniformity in things like continuous integration systems. For example, while it's great that rustix' CI flow tests many platforms, it does not cover all of the tier 2 targets (including the two I need to support mentioned above, ppc64le and s390x). If rustix is a dependency of std, this type of thing would need to change.

Yet another related issue here - and this is my personal opinion - is lack of uniformity in peer review. Changes to rust-lang/rust require peer review, as do changes to glibc. Now, you are clearly an amazingly prolific code writer. But as far as I can tell, most code changes to rustix merge without any peer review. I would hope that as part of having Rust std depend on rustix, this could be improved; that seems like a natural evolution from "PoC" to production.

All these concerns aside, from my PoV all the code and design in the whole dependency chain you've created from cap-std down to rustix, the safe IO bits etc. looks quite good! I still have on my TODO list trying out switching from the openat crate and converting some of my nix usage to rustix.

algesten commented 2 years ago

Surely if Rustix became a dependency of std, it would cease being an external crate and merge onto the main rust tree?

cgwalters commented 2 years ago

Another related thing here is basically that the libc developers are saying "you either use libc or you don't": best encapsulated by this thread: https://github.com/rust-lang/rust/issues/89522#issuecomment-946023944

Right now, rustix seems to have a clean design where it can be configured in either way, which is good. But I am sure the temptation will be high in some cases to start making direct syscalls in the libc backend when e.g. libc is lagging on binding a particular syscall. And that brings the issues in the above thread.

Again though I'll say rustix is cool (as is the mustang experiment), and from my PoV there is a clear need for it to exist given the fact that we need a high level interface in std that also supports Windows, but we also need to have external crates which do Unix and very Linux specific things. So it does probably make sense to take the next step and have std depend on rustix.

But, perhaps instead it makes sense to try to push for using rustix instead of nix in the ecosystem ahead of using it in std? I previously looked at this a bit in this discussion, and I can try some more (edit: OK did some over here).

sunfishcode commented 2 years ago

@cgwalters

I very much agree. These projects are at a "let's talk about what we might want this to look like" phase, rather than any kind of official proposal, or even a pre-RFC. They definitely have growing and maturing to do, both as codebases and as projects.

There are certainly costs in duplication and churn. But there are also costs in stagnation and not exploring. A theme I've seen come up in several places recently is that if one looks at the projects as being about just one goal, like "a libc-free Rust (on the one popular OS where that even makes sense)", or "micro-optimizing syscall wrappers (which aren't the part of syscalls which take most of the time)", it looks less interesting. The key is to look at the combined goals, which also include factoring out unsafe and error handling and raw pointers, exploring and promoting I/O safety down the stack, and building foundations for practical capability-based security, which is itself part of even larger goals.

As for starting with the ecosystem ahead of std, I've started a few things in this space too, and am interested in doing more. And I agree, it makes sense to do more of this before making any official proposals. At the same time, it seems useful to start the conversations about std too, because if we need to make major changes to support std, it's easier if we can get those changes started sooner rather than later.

sunfishcode commented 2 years ago

Mustang is now using the new futex-based Mutex/RwLock/Condvar implementations that @m-ou-se recently developed for std instead of parking_lot, which avoids the need to do global allocation from within the locking primitives. This makes Mustang's global allocator setup much simpler. The 32-bit x86 port is now back online. And origin no longer needs a git dependency on a parking_lot fork so it's now updated on crates.io so we can read the docs on docs.rs.

sunfishcode commented 2 years ago

I'm now placing the project to work toward Mustang becoming an official Rust target on hold. I'll continue to maintain it for the foreseeable future. If anyone has ideas about what they would like to see Mustang become, please reach out.

rrnewton commented 1 year ago

this is why I've started: https://github.com/elichai/syscalls-rs, which gives a rust-like API directly to syscalls ,

@elichai, one thing we've released as part of https://github.com/facebookexperimental/reverie is the "reverie-syscalls" crate, that provides one type-safe view of how to construct Syscall calls themselves (e.g. with proper argument types). Not sure how this compares with your effort or the nc crate, which seems to be receiving recent development.

It's designed for use with ptracers, so it would require some adaptation to be used to directly invoke syscalls, and maybe @jasonwhite can comment on whether that would make sense. It probably wouldn't be zero cost (without significant compiler optimization) because you do construct structs to represent the syscalls. But the macros used to derive these structs could probably also derive a direct function interface for invoking the syscalls, while retaining one source-of-truth for what are the syscalls, their numbers, and their argument types.

rrnewton commented 1 year ago

I'm wondering if someone here can redirect me to the best place for building Rust no_std programs without libc (musl or gnu). That's a much less lofty goal than reimpleminting libc, as described throughout this issue.

It seems like Rust OS kernel projects have their own setup, but I'm not seeing any ergonomic way to just build a static binary that doesn't link libc (the way you can with gcc or clang -nostdlib). There isn't a x86_64-unknown-linux-nolibc target for example. So the nc library seems ideal for invoking some syscalls from a no_std/libc-free static binary, but that build mode doesn't seem to exist in an accessible form. Or am I missing something?

Lokathor commented 1 year ago

If you don't want libc then you don't want to use linux either, so you probably want a binary target that ends with "none".

azazar commented 1 year ago

libc != linux. Why should everyone want libc?