U8 and i8 memory values

I've been investigating how i8 and u8 work. Along with how casting and stuff is done. I've found something weird and I think I'm missing some knowledge on either how the compiler is doing something or how the hardware is doing something.

fn main() {
let n: u8 = 255; //x &n 0x7fffffffe12f: 0x00_00_00_ff
let m: i8 = n as i8; //x &m 0x7fffffffe12e: 0x00_00_ff_ff
let p: i8 = -1; //x &p 0x7fffffffe12d: 0x00_ff_ff_ff
let o: i8 = m - p ; //x &o 0x7fffffffe12c: 0xff_ff_ff_00

println!("hello {} {}", n, m);


So when I look at the memory it looks like the previous values are pushed to the left. I don't know much assembly but I don't see that bit shifting happening anywhere. So my question is what is causing those bits to appear to be shifting? What is actually happening? Who does the sizing? Does the compiler keep track of the sizing and use the assembly suffixs to perform operations on the byte or does the hardware somehow know the sizes it needs to deal with?

Thanks for the help

Should've mentioned I also tried the same thing in C and got the basically the same results. So this isn't really a rust specific question. Rust just drove me to ask the question.

0x7fffffffe12f looks like a non-randomized stack address, how did you obtain it?

The variables are located right next to each other in memory as bytes. The shifting effect results from whatever you did to read the memory: the four-byte window indicated in the comment is moved one by one to lower addresses, revealing different parts of the memory.

It's probably clearer if you look at a larger memory dump at a fixed address.

Yeah I think I was reading the GDB output wrong.
with this,
0x7fffffffe52c: 22 4e 38 f5

signed char n = -11;
unsigned char p = 56;
signed char m = 78;
signed char o = 34;