From 37d53a70958bfe5b1d7946229af9c12f0b865abc Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 23 Sep 2018 22:38:16 -0700 Subject: 4512 --- html/subx/examples/ex11.subx.html | 364 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 html/subx/examples/ex11.subx.html (limited to 'html/subx/examples/ex11.subx.html') diff --git a/html/subx/examples/ex11.subx.html b/html/subx/examples/ex11.subx.html new file mode 100644 index 00000000..f0fd07c2 --- /dev/null +++ b/html/subx/examples/ex11.subx.html @@ -0,0 +1,364 @@ + + + + +Mu - subx/examples/ex11.subx + + + + + + + + + + +
+  1 ## Null-terminated vs length-prefixed ascii strings.
+  2 #
+  3 # By default we create strings with a 4-byte length prefix rather than a null suffix.
+  4 # However, commandline arguments come null-prefixed from the Linux kernel.
+  5 # This example shows a helper that can compare a commandline argument with the
+  6 # (length-prefixed) literal string "target".
+  7 #
+  8 # To run:
+  9 #   $ subx translate ex11.subx ex11
+ 10 #   $ subx run ex11  # runs a series of tests
+ 11 #   ......  # all tests pass
+ 12 #
+ 13 # (We can't yet run the tests when given a "test" commandline argument,
+ 14 # because checking for it would require the function being tested! Breakage
+ 15 # would cause tests to not run, rather than to fail as we'd like.)
+ 16 
+ 17 == code
+ 18 # instruction                     effective address                                                   operand     displacement    immediate
+ 19 # op          subop               mod             rm32          base        index         scale       r32
+ 20 # 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
+ 21 
+ 22 # main:
+ 23   e8/call  run_tests/disp32  # 'run_tests' is a function created automatically by SubX. It calls all functions that start with 'test_'.
+ 24   # exit(EAX)
+ 25   89/copy                         3/mod/direct    3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # copy EAX to EBX
+ 26   b8/copy                         .               .             .           .             .           .           .               1/imm32           # copy 1 to EAX
+ 27   cd/syscall  0x80/imm8
+ 28 
+ 29 # compare a null-terminated ascii string with a more idiomatic length-prefixed byte array
+ 30 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
+ 31 argv_equal:  # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean
+ 32   # pseudocode:
+ 33   #   initialize n = b.length
+ 34   #   initialize s1 = s
+ 35   #   initialize s2 = b.data
+ 36   #   i = 0
+ 37   #   for (i = 0; i < n; ++n)
+ 38   #     c1 = *s1
+ 39   #     c2 = *s2
+ 40   #     if c1 == 0
+ 41   #       return false
+ 42   #     if c1 != c2
+ 43   #       return false
+ 44   #   return *s1 == 0
+ 45 
+ 46   # initialize s into EDI
+ 47   8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           7/r32/EDI   8/disp8         .                 # copy *(ESP+8) to EDI
+ 48   # initialize benchmark length n into EDX
+ 49   8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
+ 50   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
+ 51   # initialize benchmark data into ESI
+ 52   8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           6/r32/ESI   4/disp8         .                 # copy *(ESP+4) to ESI
+ 53   81          0/subop/add         3/mod/direct    6/rm32/ESI    .           .             .           .           .               4/imm32           # add 4 to ESI
+ 54   # initialize loop counter i into ECX
+ 55   b9/copy                         .               .             .           .             .           .           .               0/imm32/exit      # copy 1 to ECX
+ 56   # while (i/ECX < n/EDX)
+ 57 $argv_loop:
+ 58   39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+ 59   74/jump-if-equal  $argv_break/disp8
+ 60     # c1/EAX, c2/EBX = *s, *benchmark
+ 61   b8/copy  0/imm32  # clear EAX
+ 62   8a/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy byte at *EDI to lower byte of EAX
+ 63   bb/copy  0/imm32  # clear EBX
+ 64   8a/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy byte at *ESI to lower byte of EBX
+ 65     # if (c1 == 0) return false
+ 66   3d/compare                      .               .             .           .             .           .           .               0/imm32           # compare EAX with 0
+ 67   74/jump-if-equal  $argv_fail/disp8
+ 68     # if (c1 != c2) return false
+ 69   39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX with EBX
+ 70   75/jump-if-not-equal  $argv_fail/disp8
+ 71     # ++s1, ++s2, ++i
+ 72   41/inc-ECX
+ 73   46/inc-ESI
+ 74   47/inc-EDI
+ 75   # end while
+ 76   eb/jump  $argv_loop/disp8
+ 77 $argv_break:
+ 78   # if (*s/EDI == 0) return true
+ 79   b8/copy  0/imm32  # clear EAX
+ 80   8a/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy byte at *EDI to lower byte of EAX
+ 81   81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EAX with 0
+ 82   75/jump-if-not-equal  $argv_fail/disp8
+ 83   b8/copy                         .               .             .           .             .           .           .               1/imm32           # copy 1 to EAX
+ 84   c3/return
+ 85   # return false
+ 86 $argv_fail:
+ 87   b8/copy                         .               .             .           .             .           .           .               0/imm32           # copy 0 to EAX
+ 88   c3/return
+ 89 
+ 90 ## tests
+ 91 
+ 92 test_compare_null_argv_with_empty_array:
+ 93   # EAX = argv_equal(Null_argv, "")
+ 94     # push args
+ 95   68/push  Null_argv/imm32
+ 96   68/push  ""/imm32
+ 97     # call
+ 98   e8/call  argv_equal/disp32
+ 99     # discard args
+100   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
+101   # call check_ints_equal(EAX, 1)
+102   50/push-EAX
+103   68/push  1/imm32/true
+104   68/push  "F - test_compare_null_argv_with_empty_array"/imm32
+105     # call
+106   e8/call  check_ints_equal/disp32
+107     # discard args
+108   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add 12 to ESP
+109   c3/return
+110 
+111 test_compare_null_argv_with_non_empty_array:
+112   # EAX = argv_equal(Null_argv, "Abc")
+113     # push args
+114   68/push  Null_argv/imm32
+115   68/push  "Abc"/imm32
+116     # call
+117   e8/call  argv_equal/disp32
+118     # discard args
+119   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
+120   # call check_ints_equal(EAX, 0)
+121   50/push-EAX
+122   68/push  0/imm32/false
+123   68/push  "F - test_compare_null_argv_with_non_empty_array"/imm32
+124     # call
+125   e8/call  check_ints_equal/disp32
+126     # discard args
+127   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add 12 to ESP
+128   c3/return
+129 
+130 test_compare_argv_with_equal_array:
+131   # EAX = argv_equal(Abc_argv, "Abc")
+132     # push args
+133   68/push  Abc_argv/imm32
+134   68/push  "Abc"/imm32
+135     # call
+136   e8/call  argv_equal/disp32
+137     # discard args
+138   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
+139   # call check_ints_equal(EAX, 1)
+140   50/push-EAX
+141   68/push  1/imm32/true
+142   68/push  "F - test_compare_argv_with_equal_array"/imm32
+143     # call
+144   e8/call  check_ints_equal/disp32
+145     # discard args
+146   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add 12 to ESP
+147   c3/return
+148 
+149 test_compare_argv_with_inequal_array:
+150   # EAX = argv_equal(Abc_argv, "Adc")
+151     # push args
+152   68/push  Abc_argv/imm32
+153   68/push  "Adc"/imm32
+154     # call
+155   e8/call  argv_equal/disp32
+156     # discard args
+157   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
+158   # call check_ints_equal(EAX, 0)
+159   50/push-EAX
+160   68/push  0/imm32/false
+161   68/push  "F - test_compare_argv_with_equal_array"/imm32
+162     # call
+163   e8/call  check_ints_equal/disp32
+164     # discard args
+165   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add 12 to ESP
+166   c3/return
+167 
+168 test_compare_argv_with_empty_array:
+169   # EAX = argv_equal(Abc_argv, "")
+170     # push args
+171   68/push  Abc_argv/imm32
+172   68/push  ""/imm32
+173     # call
+174   e8/call  argv_equal/disp32
+175     # discard args
+176   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
+177   # call check_ints_equal(EAX, 0)
+178   50/push-EAX
+179   68/push  0/imm32/false
+180   68/push  "F - test_compare_argv_with_equal_array"/imm32
+181     # call
+182   e8/call  check_ints_equal/disp32
+183     # discard args
+184   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add 12 to ESP
+185   c3/return
+186 
+187 test_compare_argv_with_shorter_array:
+188   # EAX = argv_equal(Abc_argv, "Ab")
+189     # push args
+190   68/push  Abc_argv/imm32
+191   68/push  "Ab"/imm32
+192     # call
+193   e8/call  argv_equal/disp32
+194     # discard args
+195   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
+196   # call check_ints_equal(EAX, 0)
+197   50/push-EAX
+198   68/push  0/imm32/false
+199   68/push  "F - test_compare_argv_with_shorter_array"/imm32
+200     # call
+201   e8/call  check_ints_equal/disp32
+202     # discard args
+203   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add 12 to ESP
+204   c3/return
+205 
+206 test_compare_argv_with_longer_array:
+207   # EAX = argv_equal(Abc_argv, "Abcd")
+208     # push args
+209   68/push  Abc_argv/imm32
+210   68/push  "Abcd"/imm32
+211     # call
+212   e8/call  argv_equal/disp32
+213     # discard args
+214   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add 8 to ESP
+215   # call check_ints_equal(EAX, 0)
+216   50/push-EAX
+217   68/push  0/imm32/false
+218   68/push  "F - test_compare_argv_with_longer_array"/imm32
+219     # call
+220   e8/call  check_ints_equal/disp32
+221     # discard args
+222   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add 12 to ESP
+223   c3/return
+224 
+225 ## helpers
+226 
+227 # print msg to stderr if a != b, otherwise print "."
+228 check_ints_equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
+229   # load args into EAX, EBX and ECX
+230   8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   0xc/disp8       .                 # copy *(ESP+12) to EAX
+231   8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           3/r32/EBX   0x8/disp8       .                 # copy *(ESP+8) to EBX
+232   # if EAX == b/EBX
+233   39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
+234   75/jump-if-unequal  $check_ints_equal:else/disp8
+235     # print('.')
+236       # push args
+237   68/push  "."/imm32
+238       # call
+239   e8/call  write_stderr/disp32
+240       # discard arg
+241   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
+242     # return
+243   c3/return
+244   # else:
+245 $check_ints_equal:else:
+246   # copy msg into ECX
+247   8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
+248     # print(ECX)
+249       # push args
+250   51/push-ECX
+251       # call
+252   e8/call  write_stderr/disp32
+253       # discard arg
+254   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
+255     # print newline
+256       # push args
+257   68/push  Newline/imm32
+258       # call
+259   e8/call  write_stderr/disp32
+260       # discard arg
+261   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
+262   # end
+263   c3/return
+264 
+265 write_stderr:  # s : (address array byte) -> <void>
+266   # save registers
+267   50/push-EAX
+268   51/push-ECX
+269   52/push-EDX
+270   53/push-EBX
+271   # write(2/stderr, (data) s+4, (size) *s)
+272     # fd = 2 (stderr)
+273   bb/copy                         .               .             .           .             .           .           .               2/imm32           # copy 2 to EBX
+274     # x = s+4
+275   8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   0x14/disp8      .                 # copy *(ESP+20) to ECX
+276   81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
+277     # size = *s
+278   8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   0x14/disp8      .                 # copy *(ESP+20) to EDX
+279   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
+280     # call write()
+281   b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
+282   cd/syscall  0x80/imm8
+283   # restore registers
+284   5b/pop-EBX
+285   5a/pop-EDX
+286   59/pop-ECX
+287   58/pop-EAX
+288   # end
+289   c3/return
+290 
+291 == data
+292 Newline:
+293   # size
+294   01 00 00 00
+295   # data
+296   0a/newline
+297 
+298 # for argv_equal tests
+299 Null_argv:
+300   00/null
+301 Abc_argv:
+302   41/A 62/b 63/c 00/null
+303 
+304 # vim:ft=subx:nowrap:so=0
+
+ + + -- cgit 1.4.1-2-gfad0