diff --git a/apply.s b/apply.s
index 21a1efc..2d7109d 100644
--- a/apply.s
+++ b/apply.s
@@ -8,40 +8,22 @@
 
 main:
 	# make an integer
-	pushq $1
-	pushq $INT_code
-	mov %rsp, %r11
+	thunkto %r11, $INT_code, $1
 
-	# make a closure for adding stuff
-	pushq $0
-	pushq $plus
-	pushq $FUN2_code
-	mov %rsp, %r12
+	# make an empty closure for adding stuff
+	thunkto %r12, $FUN2_code, $plus, $0
 
 	# apply first argument
-	push %r11
-	push %r12
-	pushq $2
-	pushq $apply1
-	mov %rsp, %r12
-	
+	thunkto %r12, $apply1, $2, %r12, %r11
+
 	# apply second argument (the p.a. function part is still in r12)
-	push %r11
-	push %r12
-	pushq $2
-	pushq $apply1
-	mov %rsp, %r12
+	thunkto %r12, $apply1, $2, %r12, %r11
 
 	# print the result
-	push %r12
-	pushq $1
-	pushq $print
-	mov %rsp, %r12
+	thunkto %r12, $print, $1, %r12
 
-	# make the continuation for main (exit)
-	push %rsi
-	pushq $1
-	pushq $main_exit
+	# make a continuation for main (exit) and set it for print call
+	thunkto %rsi, $main_exit, $1, %rsi
 
-	mov %rsp, %rsi
+	# start evaluating the print
 	enter %r12
diff --git a/exit_123.s b/exit_123.s
index ed96ad1..1e7ba23 100644
--- a/exit_123.s
+++ b/exit_123.s
@@ -5,30 +5,10 @@
 
 # || -> cont
 .thunkcode main
-	# push a new integer
-	pushq $100
-	pushq $INT_code
-	mov %rsp, %r11 # backup first arg
-
-	# push another new integer
-	pushq $23
-	pushq $INT_code
-	mov %rsp, %r12 # backup second arg
-
-	# push the plus
-	push %r12
-	push %r11
-	pushq $2
-	pushq $plus
-	mov %rsp, %r13 # backup plus
-
-	# push a cont thunk for main_exit
-	push %rsi
-	pushq $1
-	pushq $main_exit
-
-	# evaluate into main_exit
-	mov %rsp, %rsi
+	thunkto %r11, $INT_code, $100
+	thunkto %r12, $INT_code, $23
+	thunkto %r13, $plus, $2, %r11, %r12
+	thunkto %rsi, $main_exit, $1
 	enter %r13
 
 .include "include/main_exit.s"
diff --git a/fibs.s b/fibs.s
index c32f424..3d35544 100644
--- a/fibs.s
+++ b/fibs.s
@@ -9,26 +9,15 @@
 # | lag1 | lag2 | -> cont
 .thunkcode fibs
 	# next value
-	pushq 030(%rbp)
-	pushq 020(%rbp)
-	pushq $2
-	pushq $plus
-	mov %rsp, %r11
+	thunkto %r11, $plus, $2, 020(%rbp), 030(%rbp)
 
 	# fib call with the next value
-	push %r11
-	pushq 030(%rbp)
-	pushq $2
-	pushq $fibs
-	mov %rsp, %r12
+	thunkto %r12, $fibs, $2, 030(%rbp), %r11
 
-	# cons list with lag1
-	push %r12
-	push 020(%rbp)
-	pushq $1
-	pushq $LIST_code
-	mov %rsp, %r13
+	# cons list with the lagged arg
+	thunkto %r13, $LIST_code, $1, 020(%rbp), %r12
 
+	# TODO simplify
 	# replace self with IND
 	mov %r13, 010(%rbp)
 	movq $IND_code, 0(%rbp)
@@ -39,43 +28,15 @@
 
 # || -> cont
 .thunkcode fibs0
-	pushq $1
-	pushq $INT_code
-	mov %rsp, %r12
-	pushq $0
-	pushq $INT_code
-	mov %rsp, %r11
-	
-	push %r12
-	push %r11
-	pushq $2
-	pushq $fibs
-
-	enter %rsp
+	thunkto %r12, $INT_code, $1
+	thunkto %r11, $INT_code, $0
+	thunkto %rbp, $fibs, $2, %r11, %r12
+	enter_rbp
 
 .thunkcode main
-	pushq $0
-	pushq $fibs0
-	mov %rsp, %r12
-
-	pushq $20
-	pushq $INT_code
-	mov %rsp, %r11
-
-	push %r12
-	push %r11
-	pushq $2
-	pushq $list_int_index
-	mov %rsp, %r11
-
-	push %r11
-	pushq $1
-	pushq $print
-	mov %rsp, %r11
-
-	push %rsi
-	pushq $1
-	pushq $main_exit
-
-	mov %rsp, %rsi
+	thunkto %r12, $fibs0, $0
+	thunkto %r11, $INT_code, $20
+	thunkto %r11, $list_int_index, $2, %r11, %r12
+	thunkto %r11, $print, $1, %r11
+	thunkto %rsi, $main_exit, $1, %rsi
 	enter %r11
diff --git a/include/apply.s b/include/apply.s
index 124e434..2b88dd0 100644
--- a/include/apply.s
+++ b/include/apply.s
@@ -3,14 +3,7 @@
 
 # | fun | arg | -> cont
 .thunkcode apply1
-	# push a thunk for eval
-	push %rsi # cont
-	push %rbp # ret (self)
-	pushq 030(%rbp) # arg
-	pushq $3
-	pushq $apply1_fini
-
-	mov %rsp, %rsi # return to above thunk
+	thunkto %rsi, $apply1_fini, $3, 030(%rbp), %rbp, %rsi
 	enter 020(%rbp) # evaluate fun
 
 # fun -> | arg | ret | cont |
@@ -23,7 +16,7 @@
 	pushq 020(%rbp) #push the new arg
 	lea 030(%rsi), %rdx # the end (first arg)
 	lea (%rdx, %r11, 8), %rbx # address behind the last arg
-	
+
 	cmp %rdx, %rbx
 	jle apply1_fini_cont
 apply1_fini_copy:
@@ -43,7 +36,7 @@ apply1_fini_cont:
 	mov -010(%rdi), %r12 # amount of args required to make the thunk
 	cmp %r11, %r12
 	jg apply1_fini_feed # not enough args, just make a bigger FUN
-	
+
 	# if there was enough args, we simply have a thunk that we want to
 	# continue evaluating, so let's jump to it.
 	mov 030(%rbp), %rdi # load the original thunk
diff --git a/include/io.s b/include/io.s
index c348e7f..7e78c1b 100644
--- a/include/io.s
+++ b/include/io.s
@@ -4,12 +4,7 @@ _io_s_file:
 
 # | int | -> cont
 .thunkcode print
-	push %rsi
-	push %rbp
-	pushq $2
-	pushq $print_fini
-
-	mov %rsp, %rsi
+	thunkto %rsi, $print_fini, $2, %rbp, %rsi
 	enter 020(%rbp)
 
 # arg -> | ret | cont |
diff --git a/include/listops.s b/include/listops.s
index eb8f6cf..447c125 100644
--- a/include/listops.s
+++ b/include/listops.s
@@ -13,28 +13,20 @@ _listops_s_file:
 	mov 020(%rbp), %rcx
 	mov 010(%rcx), %rcx
 	test %rcx, %rcx
-	jz list_int_index_found #we are taking 0, all happy, return it
+	jz list_int_index_found # we are taking the head, all happy, return it
 
-	#more probably we need to continue, make replacement thunks
+	# more likely, we need to continue -- make new args thunks
 	sub $1, %rcx
-	pushq %rcx
-	pushq $INT_code
-	mov %rsp, %r11
-
-	pushq 030(%rsi) # tail
-	push %r11
-	pushq $2
-	pushq $list_int_index
-	mov %rsp, %r11
+	thunkto %r11, $INT_code, %rcx # decreased index
+	thunkto %r11, $list_int_index, $2, %r11, 030(%rsi) # new call on tail
 
 	primop2_cont_indirect %r11
 
-list_int_index_not_found:
-	movq 0, %rax #fault
-
 list_int_index_found:
 	mov 020(%rsi), %rax #head
 	primop2_cont_indirect %rax
-	
+
+list_int_index_not_found:
+	movq 0, %rax #fault (TODO: we should have a better fault)
 
 .endif # _listops_s_file
diff --git a/include/macros.s b/include/macros.s
index c857995..c52f6b0 100644
--- a/include/macros.s
+++ b/include/macros.s
@@ -39,4 +39,22 @@ _macros_s_file:
 	\name:
 .endm
 
+.macro thunkargs arg,args:vararg
+	.ifnb \arg
+	thunkargs \args
+	pushq \arg
+	.endif
+.endm
+
+.macro thunk code:req,n:req,args:vararg
+	thunkargs \args
+	pushq \n
+	pushq \code
+.endm
+
+.macro thunkto reg:req,code:req,n:req,args:vararg
+	thunk \code,\n,\args
+	mov %rsp, \reg
+.endm
+
 .endif # _macros_s_file
diff --git a/include/primops.s b/include/primops.s
index f019bca..3fb03b8 100644
--- a/include/primops.s
+++ b/include/primops.s
@@ -7,25 +7,19 @@ _primops_s_file:
 .macro .primop2 name
 # | arg1 | arg2 | -> cont
 .thunkcode \name
-	# push a thunk for finishing the plus
-	push %rsi # cont
-	push %rbp # ret (self)
-	pushq 030(%rbp) # arg2
-	pushq $3
-	pushq $\name\()_step1
-
-	mov %rsp, %rsi # continue to the new thunk
+	# push a thunk for collecting the first arg and set it as continuation
+	thunkto %rsi, $\name\()_step1, $3, 030(%rbp), %rbp, %rsi
 	enter 0x10(%rbp) # evaluate arg1
 
 # arg1 -> | arg2 | ret | cont |
 .thunkcode \name\()_step1
-	# this is guaranteed to be entered only once (it's a cont), so we can rewrite the thunk in place
-	mov 020(%rbp), %rax
-	movq $\name\()_fini, 0(%rbp)
-	mov %rsi, 020(%rbp)
+	# this is guaranteed to be entered only once (it's a case cont), so we
+	# can rewrite the thunk in place
+	xchg %rsi, 020(%rbp) # store arg1, get arg 2
+	movq $\name\()_fini, 0(%rbp) # continue with finishing
 
-	mov %rbp, %rsi # continue on the rewritten thunk
-	enter %rax # evaluate arg1
+	xchg %rbp, %rsi # continue here, evaluate arg 2
+	enter_rbp
 
 # arg2 -> | arg1 | ret | cont |
 .thunkcode \name\()_fini
@@ -35,8 +29,9 @@ _primops_s_file:
 .endm
 
 .macro primop2_ret_int val
+	# TODO: try to generalize
 	# the result should now be in %rax
-	mov 030(%rbp), %rsi # save result to the original plus thunk
+	mov 030(%rbp), %rsi # save result to the original primop2 thunk
 	movq \val, 010(%rsi)
 	movq $INT_code, 0(%rsi)
 
@@ -44,6 +39,7 @@ _primops_s_file:
 .endm
 
 .macro primop2_cont_indirect new
+	# TODO: try to generalize
 	mov 030(%rbp), %rdi # load the original thunk
 	mov 040(%rbp), %rsi # set the continuation
 	movq \new, 010(%rdi) # set the indirect to the new thunk
diff --git a/print_123.s b/print_123.s
index 612b4c8..b87309b 100644
--- a/print_123.s
+++ b/print_123.s
@@ -8,35 +8,21 @@
 # || -> cont
 .thunkcode main
 	# push a new integer
-	pushq $100
-	pushq $INT_code
-	mov %rsp, %r11 # backup first arg
+	thunkto %r11, $INT_code, $100
 
 	# push another new integer
-	pushq $23
-	pushq $INT_code
-	mov %rsp, %r12 # backup second arg
+	thunkto %r12, $INT_code, $23
 
 	# push the plus
-	push %r12
-	push %r11
-	pushq $2
-	pushq $plus
-	mov %rsp, %r11 # backup plus
+	thunkto %r11, $plus, $2, %r11, %r12
 
 	# push the print
-	push %r11
-	pushq $1
-	pushq $print
-	mov %rsp, %r11 # backup print
+	thunkto %r11, $print, $1, %r11
 
-	# push a cont thunk for main_exit
-	push %rsi
-	pushq $1
-	pushq $main_exit
+	# push a cont thunk for main_exit and set continuation for main_exit
+	thunkto %rsi, $main_exit, $1, %rsi
 
 	# evaluate into main_exit
-	mov %rsp, %rsi
 	enter %r11
 
 .include "include/main_exit.s"