about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2018-09-24 18:48:41 -0700
committerKartik Agaram <vc@akkartik.com>2018-09-24 22:55:37 -0700
commitc5d9a32fe6add8c986942261dd22377f911d1ca0 (patch)
treeb963fff418cc486cd3a7c1bf1b5d1c036a938045
parent9353569934e08c4ba531da5b64aeb4ae08ac2aae (diff)
downloadmu-c5d9a32fe6add8c986942261dd22377f911d1ca0.tar.gz
4516
More calling convention tweaks.

Use EBP to get consistently at parameters and locals.
Always put the first function argument closest to EBP.
-rw-r--r--subx/apps/crenshaw2-1bin1205 -> 1217 bytes
-rw-r--r--subx/apps/crenshaw2-1.subx18
-rwxr-xr-xsubx/apps/factorialbin1208 -> 1215 bytes
-rw-r--r--subx/apps/factorial.subx88
-rwxr-xr-xsubx/examples/ex10bin165 -> 165 bytes
-rw-r--r--subx/examples/ex10.subx19
-rw-r--r--subx/examples/ex11bin1028 -> 1034 bytes
-rw-r--r--subx/examples/ex11.subx76
-rwxr-xr-xsubx/examples/ex8bin143 -> 144 bytes
-rw-r--r--subx/examples/ex8.subx8
-rwxr-xr-xsubx/examples/ex9bin129 -> 129 bytes
-rw-r--r--subx/examples/ex9.subx19
12 files changed, 130 insertions, 98 deletions
diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1
index c89ebf5d..f5d28502 100644
--- a/subx/apps/crenshaw2-1
+++ b/subx/apps/crenshaw2-1
Binary files differdiff --git a/subx/apps/crenshaw2-1.subx b/subx/apps/crenshaw2-1.subx
index 6d2e3297..8ffded90 100644
--- a/subx/apps/crenshaw2-1.subx
+++ b/subx/apps/crenshaw2-1.subx
@@ -318,6 +318,9 @@ test_compare_argv_with_longer_array:
 # }}}
 
 write_stderr:  # s : (address array byte) -> <void>
+  # prolog
+  55/push-EBP
+  89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
   # save registers
   50/push-EAX
   51/push-ECX
@@ -327,10 +330,10 @@ write_stderr:  # s : (address array byte) -> <void>
     # fd = 2 (stderr)
   bb/copy                         .               .             .           .             .           .           .               2/imm32           # copy 2 to EBX
     # x = s+4
-  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   0x14/disp8      .                 # copy *(ESP+20) to ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/SIB    5/base/EBP  4/index/none  .           1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
   81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
     # size = *s
-  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   0x14/disp8      .                 # copy *(ESP+20) to EDX
+  8b/copy                         1/mod/*+disp8   4/rm32/SIB    5/base/EBP  4/index/none  .           2/r32/EDX   8/disp8         .                 # copy *(EBP+8) to EDX
   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
     # call write()
   b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
@@ -341,9 +344,14 @@ write_stderr:  # s : (address array byte) -> <void>
   59/pop-ECX
   58/pop-EAX
   # end
+  89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+  5d/pop-to-EBP
   c3/return
 
 write_stdout:  # s : (address array byte) -> <void>
+  # prolog
+  55/push-EBP
+  89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
   # save registers
   50/push-EAX
   51/push-ECX
@@ -353,10 +361,10 @@ write_stdout:  # s : (address array byte) -> <void>
     # fd = 1 (stdout)
   bb/copy                         .               .             .           .             .           .           .               1/imm32           # copy 1 to EBX
     # x = s+4
-  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   0x14/disp8      .                 # copy *(ESP+20) to ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   8/disp8         .                 # copy *(ESP+8) to ECX
   81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
     # size = *s
-  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   0x14/disp8      .                 # copy *(ESP+20) to EDX
+  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   8/disp8         .                 # copy *(ESP+8) to EDX
   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
     # call write()
   b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
@@ -367,6 +375,8 @@ write_stdout:  # s : (address array byte) -> <void>
   59/pop-ECX
   58/pop-EAX
   # end
+  89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+  5d/pop-to-EBP
   c3/return
 
 == data
diff --git a/subx/apps/factorial b/subx/apps/factorial
index 4f93fe32..f0505cba 100755
--- a/subx/apps/factorial
+++ b/subx/apps/factorial
Binary files differdiff --git a/subx/apps/factorial.subx b/subx/apps/factorial.subx
index b74fba89..5cc51b64 100644
--- a/subx/apps/factorial.subx
+++ b/subx/apps/factorial.subx
@@ -20,15 +20,15 @@
 # 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
 
 # main:
+  # prolog
+  89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
   # if (argc > 1)
-  8b/copy                         0/mod/indirect  4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   .               .                 # copy *ESP to EAX
-  3d/compare                      .               .             .           .             .           .           .               1/imm32           # compare EAX with 1
+  81          7/subop/compare     1/mod/*+disp8   4/rm32/SIB    5/base/EBP  4/index/none  .           .           0/disp8         1/imm32           # compare *EBP with 1
   7e/jump-if-lesser-or-equal  $run_main/disp8
   # and if (argv[1] == "test")
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   8/disp8         .                 # copy *(ESP+8) to EAX
     # push args
-  50/push-EAX
   68/push  "test"/imm32
+  ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x8/disp8       .                 # push *(EBP+8)
     # call
   e8/call  argv_equal/disp32
     # discard args
@@ -92,9 +92,9 @@ test_factorial:
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
   # check_ints_equal(EAX, 120, failure message)
     # push args
-  50/push-EAX
-  68/push  0x78/imm32/expected-120
   68/push  "F - test_factorial"/imm32
+  68/push  0x78/imm32/expected-120
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -107,7 +107,7 @@ test_factorial:
 # print msg to stderr if a != b, otherwise print "."
 check_ints_equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
   # load args into EAX, EBX and ECX
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   0xc/disp8       .                 # copy *(ESP+12) to EAX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   0x4/disp8       .                 # copy *(ESP+4) to EAX
   8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           3/r32/EBX   0x8/disp8       .                 # copy *(ESP+8) to EBX
   # if EAX == b/EBX
   39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
@@ -124,7 +124,7 @@ check_ints_equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
   # else:
 $check_ints_equal:else:
   # copy msg into ECX
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   0xc/disp8       .                 # copy *(ESP+12) to ECX
     # print(ECX)
       # push args
   51/push-ECX
@@ -160,12 +160,12 @@ argv_equal:  # s : null-terminated ascii string, benchmark : length-prefixed asc
   #   return *s1 == 0
 # {{{
   # initialize s into EDI
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           7/r32/EDI   8/disp8         .                 # copy *(ESP+8) to EDI
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           7/r32/EDI   4/disp8         .                 # copy *(ESP+4) to EDI
   # initialize benchmark length n into EDX
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   8/disp8         .                 # copy *(ESP+8) to EDX
   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
   # initialize benchmark data into ESI
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           6/r32/ESI   4/disp8         .                 # copy *(ESP+4) to ESI
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           6/r32/ESI   8/disp8         .                 # copy *(ESP+8) to ESI
   81          0/subop/add         3/mod/direct    6/rm32/ESI    .           .             .           .           .               4/imm32           # add 4 to ESI
   # initialize loop counter i into ECX
   b9/copy                         .               .             .           .             .           .           .               0/imm32/exit      # copy 1 to ECX
@@ -207,16 +207,17 @@ $argv_fail:
 test_compare_null_argv_with_empty_array:
   # EAX = argv_equal(Null_argv, "")
     # push args
-  68/push  Null_argv/imm32
   68/push  ""/imm32
+  68/push  Null_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
-  # call check_ints_equal(EAX, 1)
-  50/push-EAX
-  68/push  1/imm32/true
+  # call check_ints_equal(EAX, 1, msg)
+    # push args
   68/push  "F - test_compare_null_argv_with_empty_array"/imm32
+  68/push  1/imm32/true
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -226,16 +227,17 @@ test_compare_null_argv_with_empty_array:
 test_compare_null_argv_with_non_empty_array:
   # EAX = argv_equal(Null_argv, "Abc")
     # push args
-  68/push  Null_argv/imm32
   68/push  "Abc"/imm32
+  68/push  Null_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
-  # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+  # call check_ints_equal(EAX, 0, msg)
+    # push args
   68/push  "F - test_compare_null_argv_with_non_empty_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -245,16 +247,17 @@ test_compare_null_argv_with_non_empty_array:
 test_compare_argv_with_equal_array:
   # EAX = argv_equal(Abc_argv, "Abc")
     # push args
-  68/push  Abc_argv/imm32
   68/push  "Abc"/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
-  # call check_ints_equal(EAX, 1)
-  50/push-EAX
-  68/push  1/imm32/true
+  # call check_ints_equal(EAX, 1, msg)
+    # push args
   68/push  "F - test_compare_argv_with_equal_array"/imm32
+  68/push  1/imm32/true
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -264,16 +267,17 @@ test_compare_argv_with_equal_array:
 test_compare_argv_with_inequal_array:
   # EAX = argv_equal(Abc_argv, "Adc")
     # push args
-  68/push  Abc_argv/imm32
   68/push  "Adc"/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
-  # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+  # call check_ints_equal(EAX, 0, msg)
+    # push args
   68/push  "F - test_compare_argv_with_equal_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -283,16 +287,17 @@ test_compare_argv_with_inequal_array:
 test_compare_argv_with_empty_array:
   # EAX = argv_equal(Abc_argv, "")
     # push args
-  68/push  Abc_argv/imm32
   68/push  ""/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
   # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+    # push args
   68/push  "F - test_compare_argv_with_equal_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -302,16 +307,17 @@ test_compare_argv_with_empty_array:
 test_compare_argv_with_shorter_array:
   # EAX = argv_equal(Abc_argv, "Ab")
     # push args
-  68/push  Abc_argv/imm32
   68/push  "Ab"/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
   # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+    # push args
   68/push  "F - test_compare_argv_with_shorter_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -321,16 +327,17 @@ test_compare_argv_with_shorter_array:
 test_compare_argv_with_longer_array:
   # EAX = argv_equal(Abc_argv, "Abcd")
     # push args
-  68/push  Abc_argv/imm32
   68/push  "Abcd"/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
   # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+    # push args
   68/push  "F - test_compare_argv_with_longer_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -339,6 +346,9 @@ test_compare_argv_with_longer_array:
 # }}}
 
 write_stderr:  # s : (address array byte) -> <void>
+  # prolog
+  55/push-EBP
+  89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
   # save registers
   50/push-EAX
   51/push-ECX
@@ -348,10 +358,10 @@ write_stderr:  # s : (address array byte) -> <void>
     # fd = 2 (stderr)
   bb/copy                         .               .             .           .             .           .           .               2/imm32           # copy 2 to EBX
     # x = s+4
-  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   0x14/disp8      .                 # copy *(ESP+20) to ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/SIB    5/base/EBP  4/index/none  .           1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
   81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
     # size = *s
-  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   0x14/disp8      .                 # copy *(ESP+20) to EDX
+  8b/copy                         1/mod/*+disp8   4/rm32/SIB    5/base/EBP  4/index/none  .           2/r32/EDX   8/disp8         .                 # copy *(EBP+8) to EDX
   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
     # call write()
   b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
@@ -362,6 +372,8 @@ write_stderr:  # s : (address array byte) -> <void>
   59/pop-ECX
   58/pop-EAX
   # end
+  89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+  5d/pop-to-EBP
   c3/return
 
 == data
diff --git a/subx/examples/ex10 b/subx/examples/ex10
index 7035843c..59cbc497 100755
--- a/subx/examples/ex10
+++ b/subx/examples/ex10
Binary files differdiff --git a/subx/examples/ex10.subx b/subx/examples/ex10.subx
index 81f4f2ae..92e9f1f4 100644
--- a/subx/examples/ex10.subx
+++ b/subx/examples/ex10.subx
@@ -18,14 +18,13 @@
 #         argv[0]: *(ESP+4)
 #         argv[1]: *(ESP+8)
 #         ...
-  # s1 = argv[1] (EAX)
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   8/disp8         .                 # copy *(ESP+8) to EAX
-  # s2 = argv[2] (EBX)
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           3/r32/EBX   0xc/disp8       .                 # copy *(ESP+12) to EBX
-  # call argv_equal(s1, s2)
-    # push args
-  50/push-EAX
-  53/push-EBX
+  # prolog
+  89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+  # call argv_equal(argv[1], argv[2])
+    # push argv[2]
+  ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+    # push argv[1]
+  ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x8/disp8       .                 # push *(EBP+8)
     # call
   e8/call argv_equal/disp32
   # exit(EAX)
@@ -38,8 +37,8 @@ $exit:
 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
 argv_equal:  # (s1, s2) : null-terminated ascii strings -> EAX : boolean
   # initialize s1 (ECX) and s2 (EDX)
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   8/disp8         .                 # copy *(ESP+8) to ECX
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   8/disp8         .                 # copy *(ESP+8) to EDX
   # while (true)
 $argv_loop:
     # c1/EAX, c2/EBX = *s1, *s2
diff --git a/subx/examples/ex11 b/subx/examples/ex11
index fb11d1b6..646c2eb7 100644
--- a/subx/examples/ex11
+++ b/subx/examples/ex11
Binary files differdiff --git a/subx/examples/ex11.subx b/subx/examples/ex11.subx
index 460c3430..b651bf22 100644
--- a/subx/examples/ex11.subx
+++ b/subx/examples/ex11.subx
@@ -44,12 +44,12 @@ argv_equal:  # s : null-terminated ascii string, benchmark : length-prefixed asc
   #   return *s1 == 0
 
   # initialize s into EDI
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           7/r32/EDI   8/disp8         .                 # copy *(ESP+8) to EDI
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           7/r32/EDI   4/disp8         .                 # copy *(ESP+4) to EDI
   # initialize benchmark length n into EDX
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   8/disp8         .                 # copy *(ESP+8) to EDX
   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
   # initialize benchmark data into ESI
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           6/r32/ESI   4/disp8         .                 # copy *(ESP+4) to ESI
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           6/r32/ESI   8/disp8         .                 # copy *(ESP+8) to ESI
   81          0/subop/add         3/mod/direct    6/rm32/ESI    .           .             .           .           .               4/imm32           # add 4 to ESI
   # initialize loop counter i into ECX
   b9/copy                         .               .             .           .             .           .           .               0/imm32/exit      # copy 1 to ECX
@@ -92,16 +92,17 @@ $argv_fail:
 test_compare_null_argv_with_empty_array:
   # EAX = argv_equal(Null_argv, "")
     # push args
-  68/push  Null_argv/imm32
   68/push  ""/imm32
+  68/push  Null_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
-  # call check_ints_equal(EAX, 1)
-  50/push-EAX
-  68/push  1/imm32/true
+  # call check_ints_equal(EAX, 1, msg)
+    # push args
   68/push  "F - test_compare_null_argv_with_empty_array"/imm32
+  68/push  1/imm32/true
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -111,16 +112,17 @@ test_compare_null_argv_with_empty_array:
 test_compare_null_argv_with_non_empty_array:
   # EAX = argv_equal(Null_argv, "Abc")
     # push args
-  68/push  Null_argv/imm32
   68/push  "Abc"/imm32
+  68/push  Null_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
-  # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+  # call check_ints_equal(EAX, 0, msg)
+    # push args
   68/push  "F - test_compare_null_argv_with_non_empty_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -130,16 +132,17 @@ test_compare_null_argv_with_non_empty_array:
 test_compare_argv_with_equal_array:
   # EAX = argv_equal(Abc_argv, "Abc")
     # push args
-  68/push  Abc_argv/imm32
   68/push  "Abc"/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
-  # call check_ints_equal(EAX, 1)
-  50/push-EAX
-  68/push  1/imm32/true
+  # call check_ints_equal(EAX, 1, msg)
+    # push args
   68/push  "F - test_compare_argv_with_equal_array"/imm32
+  68/push  1/imm32/true
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -149,16 +152,17 @@ test_compare_argv_with_equal_array:
 test_compare_argv_with_inequal_array:
   # EAX = argv_equal(Abc_argv, "Adc")
     # push args
-  68/push  Abc_argv/imm32
   68/push  "Adc"/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
-  # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+  # call check_ints_equal(EAX, 0, msg)
+    # push args
   68/push  "F - test_compare_argv_with_equal_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -168,16 +172,17 @@ test_compare_argv_with_inequal_array:
 test_compare_argv_with_empty_array:
   # EAX = argv_equal(Abc_argv, "")
     # push args
-  68/push  Abc_argv/imm32
   68/push  ""/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
   # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+    # push args
   68/push  "F - test_compare_argv_with_equal_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -187,16 +192,17 @@ test_compare_argv_with_empty_array:
 test_compare_argv_with_shorter_array:
   # EAX = argv_equal(Abc_argv, "Ab")
     # push args
-  68/push  Abc_argv/imm32
   68/push  "Ab"/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
   # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+    # push args
   68/push  "F - test_compare_argv_with_shorter_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -206,16 +212,17 @@ test_compare_argv_with_shorter_array:
 test_compare_argv_with_longer_array:
   # EAX = argv_equal(Abc_argv, "Abcd")
     # push args
-  68/push  Abc_argv/imm32
   68/push  "Abcd"/imm32
+  68/push  Abc_argv/imm32
     # call
   e8/call  argv_equal/disp32
     # discard args
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
   # call check_ints_equal(EAX, 0)
-  50/push-EAX
-  68/push  0/imm32/false
+    # push args
   68/push  "F - test_compare_argv_with_longer_array"/imm32
+  68/push  0/imm32/false
+  50/push-EAX
     # call
   e8/call  check_ints_equal/disp32
     # discard args
@@ -227,7 +234,7 @@ test_compare_argv_with_longer_array:
 # print msg to stderr if a != b, otherwise print "."
 check_ints_equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
   # load args into EAX, EBX and ECX
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   0xc/disp8       .                 # copy *(ESP+12) to EAX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   0x4/disp8       .                 # copy *(ESP+4) to EAX
   8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           3/r32/EBX   0x8/disp8       .                 # copy *(ESP+8) to EBX
   # if EAX == b/EBX
   39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
@@ -244,7 +251,7 @@ check_ints_equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
   # else:
 $check_ints_equal:else:
   # copy msg into ECX
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   0xc/disp8       .                 # copy *(ESP+12) to ECX
     # print(ECX)
       # push args
   51/push-ECX
@@ -263,6 +270,9 @@ $check_ints_equal:else:
   c3/return
 
 write_stderr:  # s : (address array byte) -> <void>
+  # prolog
+  55/push-EBP
+  89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
   # save registers
   50/push-EAX
   51/push-ECX
@@ -272,10 +282,10 @@ write_stderr:  # s : (address array byte) -> <void>
     # fd = 2 (stderr)
   bb/copy                         .               .             .           .             .           .           .               2/imm32           # copy 2 to EBX
     # x = s+4
-  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   0x14/disp8      .                 # copy *(ESP+20) to ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/SIB    5/base/EBP  4/index/none  .           1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
   81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
     # size = *s
-  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   0x14/disp8      .                 # copy *(ESP+20) to EDX
+  8b/copy                         1/mod/*+disp8   4/rm32/SIB    5/base/EBP  4/index/none  .           2/r32/EDX   8/disp8         .                 # copy *(EBP+8) to EDX
   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
     # call write()
   b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
@@ -286,6 +296,8 @@ write_stderr:  # s : (address array byte) -> <void>
   59/pop-ECX
   58/pop-EAX
   # end
+  89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+  5d/pop-to-EBP
   c3/return
 
 == data
diff --git a/subx/examples/ex8 b/subx/examples/ex8
index 463f83b8..8f95f543 100755
--- a/subx/examples/ex8
+++ b/subx/examples/ex8
Binary files differdiff --git a/subx/examples/ex8.subx b/subx/examples/ex8.subx
index fb35dc7e..1a094b89 100644
--- a/subx/examples/ex8.subx
+++ b/subx/examples/ex8.subx
@@ -18,11 +18,11 @@
 # instruction                     effective address                                                   operand     displacement    immediate
 # op          subop               mod             rm32          base        index         scale       r32
 # 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
-  # var s = argv[1] (EBX)
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none              3/r32/EBX   8/disp8         .                       # copy *(ESP+8) to EBX
-  # call ascii_length(EBX)
+  # prolog
+  89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+  # call ascii_length(argv[1])
     # push args
-  53/push-EBX
+  ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x8/disp8       .                 # push *(EBP+8)
     # call
   e8/call  ascii_length/disp32
     # discard args
diff --git a/subx/examples/ex9 b/subx/examples/ex9
index 874efe52..144cec89 100755
--- a/subx/examples/ex9
+++ b/subx/examples/ex9
Binary files differdiff --git a/subx/examples/ex9.subx b/subx/examples/ex9.subx
index dde9fa37..8c0fba29 100644
--- a/subx/examples/ex9.subx
+++ b/subx/examples/ex9.subx
@@ -20,14 +20,13 @@
 # instruction                     effective address                                                   operand     displacement    immediate
 # op          subop               mod             rm32          base        index         scale       r32
 # 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
-  # s1 = argv[1] (EAX)
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none              0/r32/EAX   8/disp8         .                 # copy *(ESP+8) to EAX
-  # s2 = argv[2] (EBX)
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none              3/r32/EBX   0xc/disp8       .                 # copy *(ESP+12) to EBX
-  # call string_equal(s1, s2)
-    # push args
-  50/push-EAX
-  53/push-EBX
+  # prolog
+  89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+  # call ascii_difference(argv[1], argv[2])
+    # push argv[2]
+  ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+    # push argv[1]
+  ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x8/disp8       .                 # push *(EBP+8)
     # call
   e8/call  ascii_difference/disp32
     # discard args
@@ -39,10 +38,10 @@
 
 ascii_difference:  # (s1, s2) : null-terminated ascii strings
   # a = first letter of s1 (ECX)
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none              0/r32/EAX   8/disp8         .                 # copy *(ESP+8) to EAX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none              0/r32/EAX   4/disp8         .                 # copy *(ESP+4) to EAX
   8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # copy *EAX to EAX
   # b = first letter of s2 (EDX)
-  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none              1/r32/ECX   4/disp8                           # copy *(ESP+4) to ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none              1/r32/ECX   8/disp8                           # copy *(ESP+8) to ECX
   8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # copy *ECX to ECX
   # a-b
   29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX