mu/subx/054string-equal.subx

236 lines
11 KiB
Plaintext
Raw Normal View History

2018-10-03 05:16:59 +00:00
# Comparing 'regular' length-prefixed strings.
== code
# instruction effective address register 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
2018-10-03 05:16:59 +00:00
Entry: # run all tests
2019-02-15 06:46:07 +00:00
#? e8/call test-compare-equal-strings/disp32
e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
# syscall(exit, Num-test-failures)
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
2018-12-28 16:56:21 +00:00
b8/copy-to-EAX 1/imm32/exit
cd/syscall 0x80/imm8
2018-10-03 05:16:59 +00:00
2019-02-15 00:24:20 +00:00
string-equal?: # s : (address string), benchmark : (address string) -> EAX : boolean
# pseudocode:
2019-02-15 00:24:20 +00:00
# lens = s->length
# if (lens != benchmark->length) return false
# i = 0
# currs = s->data
# currb = benchmark->data
2019-03-20 05:41:34 +00:00
# while i < s->length
2019-02-15 00:24:20 +00:00
# c1 = *currs
# c2 = *currb
# if (c1 != c2) return false
# ++i, ++currs, ++currb
# return true
2019-02-15 00:24:20 +00:00
#
# registers:
# i: ECX
2019-02-15 00:24:20 +00:00
# lens: EDX
2019-02-15 06:46:07 +00:00
# currs: ESI
# currb: EDI
# c1: EAX
# c2: EBX
#
2019-01-06 20:51:49 +00:00
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# . save registers
51/push-ECX
52/push-EDX
53/push-EBX
56/push-ESI
2019-02-15 06:46:07 +00:00
57/push-EDI
# ESI = s
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
# EDI = benchmark
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI
2019-02-15 00:24:20 +00:00
# lens/EDX = s->length
2019-02-15 06:46:07 +00:00
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
2019-02-15 00:24:20 +00:00
$string-equal?:lengths:
# if (lens != benchmark->length) return false
39/compare 0/mod/indirect 7/rm32/EDI . . . 2/r32/EDX . . # compare *EDI and EDX
2019-01-16 19:13:39 +00:00
75/jump-if-not-equal $string-equal?:false/disp8
2019-02-15 06:46:07 +00:00
# currs/ESI = s->data
81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 4/imm32 # add to ESI
# currb/EDI = benchmark->data
81 0/subop/add 3/mod/direct 7/rm32/EDI . . . . . 4/imm32 # add to EDI
# i/ECX = c1/EAX = c2/EBX = 0
31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX
2019-01-16 19:13:39 +00:00
$string-equal?:loop:
2019-02-15 00:24:20 +00:00
# if (i >= lens) return true
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
2019-01-16 19:13:39 +00:00
7d/jump-if-greater-or-equal $string-equal?:true/disp8
2019-02-15 06:46:07 +00:00
# c1 = *currs
8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL
# c2 = *currb
8a/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at *EDI to BL
# if (c1 != c2) return false
39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX
2019-01-16 19:13:39 +00:00
75/jump-if-not-equal $string-equal?:false/disp8
# ++i
2019-04-12 01:58:16 +00:00
41/increment-ECX
2019-02-15 06:46:07 +00:00
# ++currs
2019-04-17 05:43:17 +00:00
46/increment-ESI
2019-02-15 06:46:07 +00:00
# ++currb
2019-04-17 05:43:17 +00:00
47/increment-EDI
2019-01-16 19:13:39 +00:00
eb/jump $string-equal?:loop/disp8
$string-equal?:true:
b8/copy-to-EAX 1/imm32
2019-01-16 19:13:39 +00:00
eb/jump $string-equal?:end/disp8
$string-equal?:false:
b8/copy-to-EAX 0/imm32
2019-01-16 19:13:39 +00:00
$string-equal?:end:
# . restore registers
2019-02-15 06:46:07 +00:00
5f/pop-to-EDI
5e/pop-to-ESI
5b/pop-to-EBX
5a/pop-to-EDX
59/pop-to-ECX
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
2018-10-03 05:16:59 +00:00
# - tests
2018-10-03 05:16:59 +00:00
test-compare-empty-with-empty-string:
2019-01-16 19:13:39 +00:00
# EAX = string-equal?("", "")
# . . push args
68/push ""/imm32
68/push ""/imm32
# . . call
2019-01-16 19:13:39 +00:00
e8/call string-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check-ints-equal(EAX, 1, msg)
# . . push args
68/push "F - test-compare-empty-with-empty-string"/imm32
68/push 1/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return
2018-10-03 05:16:59 +00:00
test-compare-empty-with-non-empty-string: # also checks length-mismatch code path
2019-01-16 19:13:39 +00:00
# EAX = string-equal?("", "Abc")
# . . push args
68/push "Abc"/imm32
68/push ""/imm32
# . . call
2019-01-16 19:13:39 +00:00
e8/call string-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-compare-empty-with-non-empty-string"/imm32
68/push 0/imm32/false
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return
2018-10-03 05:16:59 +00:00
test-compare-equal-strings:
2019-01-16 19:13:39 +00:00
# EAX = string-equal?("Abc", "Abc")
# . . push args
68/push "Abc"/imm32
68/push "Abc"/imm32
# . . call
2019-01-16 19:13:39 +00:00
e8/call string-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check-ints-equal(EAX, 1, msg)
# . . push args
68/push "F - test-compare-equal-strings"/imm32
68/push 1/imm32/true
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return
2018-10-03 05:16:59 +00:00
test-compare-inequal-strings-equal-lengths:
2019-01-16 19:13:39 +00:00
# EAX = string-equal?("Abc", "Adc")
# . . push args
68/push "Adc"/imm32
68/push "Abc"/imm32
# . . call
2019-01-16 19:13:39 +00:00
e8/call string-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check-ints-equal(EAX, 0, msg)
# . . push args
68/push "F - test-compare-inequal-strings-equal-lengths"/imm32
68/push 0/imm32/false
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return
2018-10-05 17:42:16 +00:00
# helper for later tests
check-string-equal: # s : (address string), expected : (address string), msg : (address string)
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# . save registers
50/push-EAX
# EAX = string-equal?(s, expected)
# . . push args
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call string-equal?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check-ints-equal(EAX, 1, msg)
# . . push args
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
68/push 1/imm32
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
$check-string-equal:end:
# . restore registers
58/pop-to-EAX
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
# test the helper
test-check-string-equal:
# check-string-equal?("Abc", "Abc")
# . . push args
68/push "Abc"/imm32
68/push "Abc"/imm32
# . . call
e8/call check-string-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check-ints-equal(EAX, 1, msg)
# . . push args
68/push "F - test-check-string-equal"/imm32
68/push 0/imm32/false
50/push-EAX
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
c3/return
# . . vim:nowrap:textwidth=0