Skip to content

Instantly share code, notes, and snippets.

@LevitatingBusinessMan
Last active February 28, 2024 08:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LevitatingBusinessMan/0ac98c5e4d7c4c8d07defd0b296168e1 to your computer and use it in GitHub Desktop.
Save LevitatingBusinessMan/0ac98c5e4d7c4c8d07defd0b296168e1 to your computer and use it in GitHub Desktop.
A totally sane implementation of a coroutine in C
#include <stdio.h>
#define COROUTINE static long ip = 0; if (ip) asm ("jmp *%0" : : "r" (ip + 7));
#define YIELD_32(i) asm volatile("movl %1, %%eax \n pop %%rbp \n call 1f\n 1: pop %0 \n ret" : "=m" (ip) : "r" (i));
int fibonacci() {
COROUTINE
YIELD_32(0);
YIELD_32(1);
YIELD_32(1);
YIELD_32(2);
YIELD_32(3);
YIELD_32(5);
YIELD_32(8);
YIELD_32(13);
YIELD_32(21);
YIELD_32(34);
}
int main(int argc, char** argv) {
for (int i = 0; i < 10; i ++) {
printf("%d\n", fibonacci());
}
}
use std::arch::asm;
use std::ptr::addr_of;
macro_rules! coroutine {
() => {
static mut IP: usize = 0;
unsafe {
if IP != 0 {
asm!(
"jmp *%rax",
in("rax") IP + 7,
options(att_syntax)
)
}
}
}
}
macro_rules! yielt {
($e:expr) => { unsafe { asm!(
"pop %rbp",
"call 1f",
"1: popq {}(%rip)",
"ret",
sym IP,
in("rax") $e,
options(att_syntax)
) } }
}
unsafe extern fn fibonacci() -> u32 {
coroutine!();
yielt!(0);
yielt!(1);
yielt!(1);
yielt!(2);
yielt!(3);
yielt!(5);
yielt!(8);
yielt!(13);
yielt!(21);
yielt!(34);
panic!();
}
fn main() {
for i in 0..10 {
unsafe {
println!("{}", fibonacci());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment