Yes, it is stored in the binary and copied onto the stack.
You cannot mutate data that is in the final binary, but you may copy it and then modify it.
The array is not copied into the stack; you tried to name the complete type there by saying b: &[i32; 5] but you are missing a lifetime there, which can be named. Since the array is actually in the binary itself, it will live for the entirety of the program and will not change. There is a lifetime that's used for this; it's called the 'static lifetime. So, the entirety of the type is:
let b: &'static [i32; 5] = &[1, 2, 3, 4, 5];
When you take a reference to anything, the underlying object is not copied. That is the entire point of references after all.
What you can do though, is allow mutation of that array in your code, but then where it is stored is the stack. Where the data is actually stored is an implementation detail and should not be relied upon.
Take for example:
let b: &mut [i32; 5] = &mut [1, 2, 3, 4, 5];
Playground.
Now this lifetime is not 'static: Playground, since there is a temporary made on the stack for the mutable array. (Note that I've declared it as &'static mut _, _ means "inferred type", which evaluates to [i32; 5]).
I have already partially answered this, but in this case, it is stored on the stack.
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:2:34
|
2 | let b: &'static mut _ = &mut [1, 2, 3, 4, 5];
| -------------- ^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'static`
3 | }
| - temporary value is freed at the end of this statement