[SPCA] Finish unorthodox control flow

This commit is contained in:
2026-01-16 08:19:39 +01:00
parent 8ca91096af
commit ad5098bb07
9 changed files with 135 additions and 1 deletions

View File

@@ -0,0 +1,22 @@
#include <setjmp.h>
#include <stdio.h>
static jmp_buf buf;
void second( void ) {
printf( "second\n" );
longjmp( buf, 1 );
}
void first( void ) {
second();
printf( "first\n" ); // Never executed
}
int main() {
if ( !setjmp( buf ) ) // returns 0 initially
first();
else
printf( "main\n" ); // 1 is returned when longjmp is executed
return 0;
}

View File

@@ -0,0 +1,27 @@
# Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license
setjmp:
mov %rbx, (%rdi)
mov %rbp, 8(%rdi)
mov %r12, 16(%rdi)
mov %r13, 24(%rdi)
mov %r14, 32(%rdi)
mov %r15, 40(%rdi)
lea 8(%rsp), %rdx
mov %rdx, 48(%rdi)
mov (%rsp), %rdx
mov %rdx, 56(%rdi)
xor %eax, %eax
ret
longjmp:
xor %eax, %eax
cmp $1, %esi # CF = val ? 0 : 1
adc %esi, %eax # eax = val + !val
mov (%rdi), %rbx # rdi is the jmp_buf, restore regs from it
mov 8(%rdi), %rbp
mov 16(%rdi), %r12
mov 24(%rdi), %r13
mov 32(%rdi), %r14
mov 40(%rdi), %r15
mov 48(%rdi), %rsp
jmp *56(%rdi) # goto saved address without altering rsp

View File

@@ -0,0 +1,40 @@
#include "10_coroutine.h"
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#define CORO_STACK_SIZE 128
static struct coroutine *cur_co;
static struct coroutine *main_co;
void co_init() {
main_co = (struct coroutine *) calloc( 1, sizeof( struct coroutine ) );
cur_co = main_co;
co_switchto( main_co );
}
void *co_switchto( struct coroutine *next, void *arg ) {
if ( setjmp( cur_co->env ) == 0 ) {
cur_co = next;
cur_co->arg = arg;
longjmp( cur_co->env, 1 );
}
return cur_co->arg;
}
static void start_cl( void ) {
( cur_co->start )( cur_co->arg );
co_switchto( main_co );
printf( "Error: returned from coroutine start closure.\n" );
exit( -1 );
}
struct coroutine *co_new( co_start_fn *start, void *ctxt ) {
struct coroutine *co = (struct coroutine *) calloc( 1, sizeof( struct coroutine ) );
co->stack = calloc( 1, CORO_STACK_SIZE + 16 );
co->start = start;
co->arg = ctxt;
setjmp( co->env );
co->env[ 0 ].__jmpbuf[ 6 ] = ( (uint64_t) ( co->stack ) + CORO_STACK_SIZE ); // Machine specific
co->env[ 0 ].__jmpbuf[ 7 ] = ( (uint64_t) ( start_cl ) ); // Machine specific
}

View File

@@ -0,0 +1,13 @@
#include <setjmp.h>
typedef void( co_start_fn )( void * );
struct coroutine {
void *stack; // The call stack
jmp_buf env; // The saved context
co_start_fn *start; // Function to call
void *arg; // Argument to the function
};
struct coroutine *co_new( co_start_fn *start, void *ctxt );
void co_free( struct coroutine *self );
void *co_switchto( struct coroutine *next );
void co_init( void );