mirror of
https://github.com/janishutz/eth-summaries.git
synced 2026-03-14 17:00:05 +01:00
[SPCA] Finish unorthodox control flow
This commit is contained in:
@@ -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;
|
||||
}
|
||||
27
semester3/spca/code-examples/01_asm/09_setjmp-longjmp.s
Normal file
27
semester3/spca/code-examples/01_asm/09_setjmp-longjmp.s
Normal 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
|
||||
40
semester3/spca/code-examples/01_asm/10_coroutine.c
Normal file
40
semester3/spca/code-examples/01_asm/10_coroutine.c
Normal 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
|
||||
}
|
||||
13
semester3/spca/code-examples/01_asm/10_coroutine.h
Normal file
13
semester3/spca/code-examples/01_asm/10_coroutine.h
Normal 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 );
|
||||
Reference in New Issue
Block a user