4 ms·
Can anyone explain to me why these two issues aren't considered deal breakers for introducing Rust into the kernel? 1. It doesn't map almost 1:1 to assembly th
by ristos 2y ago
Can anyone explain to me why these two issues aren't considered deal breakers for introducing Rust into the kernel?
1. It doesn't map almost 1:1 to assembly the way C does, so it's not inherently clear if the code will necessarily do what it says it does. That seems questionable for something as important as a kernel and driver.
2. Only one real Rust compiler, that's a recursive compiler, which reminds me of the Trusting Trust problem:
https://dl.acm.org/doi/abs/10.1145/358198.358210 https://dl.acm.org/doi/abs/10.1145/358198.358210
- jcranmer 2y ago> 1. It doesn't map almost 1:1 to assembly the way C does, so it's not inherently clear if the code will necessarily do what it says it does. As someone who works on a C compiler, I will tell you that Rust maps marginally better 1:1 to assembly than C does. No major C compiler goes 1:1 to assembly; it all gets flushed into a compiler IR that happily mangles the code in fun and interesting ways before getting compiled into the assembly you get at the end. Rust code does that too, but at least Rust doesn't pull anything silly on you like the automatic type promotion that C does. If C maps 1:1 to assembly in your view, then (unsafe) Rust does; if Rust doesn't map 1:1 to assembly, nor does C. It's as simple as that.
- ristos 2y agoI get that GCC and Clang does all sorts of optimizations, but doesn't unoptimized C map closely to 1:1? I've heard it being called a high level assembly that maps closely to assembly many times at this point, it makes sense to me why people would say that. > If C maps 1:1 to assembly in your view, then (unsafe) Rust does; if Rust doesn't map 1:1 to assembly, nor does C. It's as simple as that. I thought the mapping issue was unrelated to the borrow checker, and that it's possible to write a borrow checker for a restricted subset of C. I thought the thing that was making it not map 1:1 was actually all of the extra features in Rust, like the ADTs and async and all of that. Is that not actually the case?
- josefx 2y ago> but doesn't unoptimized C map closely to 1:1 What is a variable in C? A register? A memory location? The language doesn't have basic concepts needed to map anything 1:1 to assembly and the ones it has usually come with half a dozen standards worth of required error handling, because having single instruction features like sqrt return -1 on error wasn't enough.
- ristos 2y ago> What is a variable in C? A register? A memory location? Wouldn't it depend on the type? Something like: int p; p = &x; MOV @R1, R2 ; R1 contains the address of x, move it to pointer p in R2 int p; int value = *p; MOV @R2, R0 ; Dereference pointer p (in R2), load the value into R0 (int value) int x = 5; MOV #5, -(SP) ; Push the value 5 onto the stack (stack-allocated int) int x = 10; int y = x + 5; MOV #10, R0 ; Load the immediate value 10 into register R0 (for x) ADD #5, R0 ; Add 5 to the value in R0 (x + 5), store result in R0 or MOV #10, -(SP) ; Push 10 onto the stack for x MOV (SP), R0 ; Load x from stack into R0 ADD #5, R0 ; Add 5 to x Whether a variable gets stack-allocated or register-allocated, it's still a pretty close mapping afaict. From my understanding the original C mapped closely to PDP-7 and then PDP-11 assembly. The original implementation and how it maps to PDP-11 could be used as a reference implementation.
- steveklabnik 2y agoThe C standard does not reference the stack anywhere. Depending on optimization level, things can change. Without any optimizations, variables of “automatic storage duration” such as local variables, may get placed on the stack. But with optimizations turned on, they may end up in a register, or even not be stored anywhere, for example if they’re an integer literal that never gets modified after assignment.
- rcxdude 2y agoUnoptimized C is not something anyone actually uses. And it maps less obviously to assembler than C with some optimizations, because C compilers in no-optimization mode generally do brain-dead things like allocating all variables on the stack. ADTs and such don't actually make the mapping less obvious. Async kinda does, but again it's not hard to have at least some mental model of how an async function will turn into a state machine implementation. C, C++, and Rust are all about equal in terms of how well I can predict how a given function maps to assembly, which is that if I care, I need to check, but I'm rarely completely bamboozled by what I see.
- steveklabnik 2y ago1. C doesn’t actually do that. Rust is the same as C in this regard. 2. The Linux kernel doesn’t use standard C, it uses many gcc specific extensions. By this point, clang also supports those extensions and can compile the kernel, but that took work, and upstream has never tried to be only standard C.
- ozgrakkurt 2y agoThis complexity issue is very similar to memory issues of older languages. Most rust people say it is ok or you can avoid it etc. but they don’t understand people just tend to go to the path of least resistance and most times this means a lot of traits and generics. Would be super cool to have something like zig but with borrow checker