mu/linux/103kernel-string-equal.subx
Kartik K. Agaram 827dd4a7fe start throwing error on duplicate label
One less error that's only in the bootstrap phase.

On the other hand, for simplicity I got rid of the ability to override
the Entry label. One less special case, but we're also going further
from the ability to run subsets of layers. We haven't really been
exercising it for a long time, though (commit 7842, March 2021 when we
made baremetal the default).
2021-08-22 21:09:28 -07:00

270 lines
12 KiB
Plaintext

# Checking null-terminated strings.
#
# By default we create strings as arrays of bytes, and all arrays have a 4-byte
# size prefix.
#
# However, we sometimes need to deal with null-terminated strings when
# interacting with the Linux kernel. This layer implements a function for
# comparing a null-terminated 'kernel string' with a size-prefixed 'SubX
# string'.
#
# To run (from the subx directory):
# $ bootstrap/bootstrap translate 10[0-3]*.subx -o a.elf
# $ bootstrap/bootstrap run a.elf # runs a series of tests
# ...... # all tests pass
#
# (We can't yet run the tests when given a "test" commandline argument,
# because checking for it would require the function being tested! Breakage
# would cause tests to not run, rather than to fail as we'd like.)
== 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
#? Entry: # run all tests
#? 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
#? e8/call syscall_exit/disp32
kernel-string-equal?: # s: (addr kernel-string), benchmark: (addr array byte) -> result/eax: boolean
# pseudocode:
# n = benchmark->size
# s1 = s
# s2 = benchmark->data
# i = 0
# while (i < n)
# c1 = *s1
# c2 = *s2
# if (c1 == 0) return false
# if (c1 != c2) return false
# ++s1, ++s2, ++i
# return *s1 == 0
#
# registers:
# i: ecx
# n: edx
# s1: edi
# s2: esi
# c1: eax
# c2: ebx
#
# . prologue
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
57/push-edi
# var s1/edi: (addr byte) = s
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi
# var n/edx: int = benchmark->size
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
8b/copy 0/mod/indirect 2/rm32/edx . . . 2/r32/edx . . # copy *edx to edx
# var s2/esi: (addr byte) = benchmark->data
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 4/imm32 # add to esi
# var i/ecx: int = 0
b9/copy-to-ecx 0/imm32/exit
# var c1/eax: byte = 0
b8/copy-to-eax 0/imm32
# var c2/ebx: byte = 0
bb/copy-to-ebx 0/imm32
$kernel-string-equal?:loop:
# if (i >= n) break
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
7d/jump-if->= $kernel-string-equal?:break/disp8
# c1 = *s1
8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 0/r32/AL . . # copy byte at *edi to AL
# c2 = *s2
8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 3/r32/BL . . # copy byte at *esi to BL
# if (c1 == 0) return false
3d/compare-eax-and 0/imm32/null
74/jump-if-= $kernel-string-equal?:false/disp8
# if (c1 != c2) return false
39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx
75/jump-if-!= $kernel-string-equal?:false/disp8
# ++i
41/increment-ecx
# ++s1
47/increment-edi
# ++s2
46/increment-esi
eb/jump $kernel-string-equal?:loop/disp8
$kernel-string-equal?:break:
# return *s1 == 0
8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 0/r32/AL . . # copy byte at *edi to AL
3d/compare-eax-and 0/imm32/null
75/jump-if-!= $kernel-string-equal?:false/disp8
$kernel-string-equal?:true:
b8/copy-to-eax 1/imm32
eb/jump $kernel-string-equal?:end/disp8
$kernel-string-equal?:false:
b8/copy-to-eax 0/imm32
$kernel-string-equal?:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
# - tests
test-compare-null-kernel-string-with-empty-array:
# eax = kernel-string-equal?(Null-kernel-string, "")
# . . push args
68/push ""/imm32
68/push Null-kernel-string/imm32
# . . call
e8/call kernel-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-null-kernel-string-with-empty-array"/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
test-compare-null-kernel-string-with-non-empty-array:
# eax = kernel-string-equal?(Null-kernel-string, "Abc")
# . . push args
68/push "Abc"/imm32
68/push Null-kernel-string/imm32
# . . call
e8/call kernel-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-null-kernel-string-with-non-empty-array"/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
test-compare-kernel-string-with-equal-array:
# eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
# . . push args
68/push "Abc"/imm32
68/push _test-Abc-kernel-string/imm32
# . . call
e8/call kernel-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-kernel-string-with-equal-array"/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
test-compare-kernel-string-with-inequal-array:
# eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
# . . push args
68/push "Adc"/imm32
68/push _test-Abc-kernel-string/imm32
# . . call
e8/call kernel-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-kernel-string-with-equal-array"/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
test-compare-kernel-string-with-empty-array:
# eax = kernel-string-equal?(_test-Abc-kernel-string, "")
# . . push args
68/push ""/imm32
68/push _test-Abc-kernel-string/imm32
# . . call
e8/call kernel-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-kernel-string-with-equal-array"/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
test-compare-kernel-string-with-shorter-array:
# eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
# . . push args
68/push "Ab"/imm32
68/push _test-Abc-kernel-string/imm32
# . . call
e8/call kernel-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-kernel-string-with-shorter-array"/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
test-compare-kernel-string-with-longer-array:
# eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
# . . push args
68/push "Abcd"/imm32
68/push _test-Abc-kernel-string/imm32
# . . call
e8/call kernel-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-kernel-string-with-longer-array"/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
== data
Null-kernel-string: # (addr kernel-string)
00/null
_test-Abc-kernel-string: # (addr kernel-string)
41/A 62/b 63/c 00/null
# . . vim:nowrap:textwidth=0