Implementing our own fibers 123 "mov rsp, [rsi + 0x00]", "mov r15, [rsi + 0x08]", "mov r14, [rsi + 0x10]", "mov r13, [rsi + 0x18]", "mov r12, [rsi + 0x20]", "mov rbx, [rsi + 0x28]", "mov rbp, [rsi + 0x30]", "ret", options(noreturn) ); } So, this is our full stack switch function. Y ou probably remember from our first example that this is just a bit more elaborate. We first read out the values of all the registers we need and then set all the register values to the register values we saved when we suspended execution on the new thread. This is essentially all we need to do to save and resume the execution. Here we see the #[naked] attribute used again. Usually, every function has a prologue and an epilogue and we don't want that here since this is all assembly and we want to handle everything ourselves. If we don't include this, we will fail to switch back to our stack the second time. Y ou can also see us using the offset we introduced earlier in practice: 0x00[rdi] # 0 0x08[rdi] # 8 0x10[rdi] # 16 0x18[rdi] # 24 These are hex numbers indicating the offset from the memory pointer to which we want to read/write. I wrote down the base 10 numbers as comments, so as you can see, we only offset the pointer in 8-byte steps, which is the same size as the u64 fields on our Thread Context struct. This is also why it's important to annotate Thread Context with #[repr(C)] ; it tells us that the data will be represented in memory in this exact way so we write to the right field. The Rust ABI makes no guarantee that they are represented in the same order in memory; however, the C-ABI does. Finally, there is one new option added to the asm! block. option(noreturn) is a requirement when writing naked functions and we will receive a compile error if we don't add it. Usually, the compiler will assume that a function call will return, but naked functions are not anything like the functions we're used to. They're more like labeled containers of assembly that we can call, so we don't want the compiler to emit ret instructions at the end of the function or make any assumptions that we return to the previous stack frame. By using this option, we tell the compiler to treat the assembly block as if it never returns, and we make sure that we never fall through the assembly block by adding a ret instruction ourselves. Next up is our main function, which is pretty straightforward, so I'll simply present the code here: