# new data structure: a slice is an open interval of addresses [start, end) # that includes 'start' but not 'end' == 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 a single test, while debugging #? e8/call test-slice-to-string/disp32 #? # 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 #? b8/copy-to-EAX 1/imm32/exit #? cd/syscall 0x80/imm8 slice-empty?: # s : (address slice) -> EAX : boolean # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # . save registers 51/push-ECX # ECX = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX # if (s->start == s->end) return true # . EAX = s->start 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX # . compare EAX and s->end 39/compare 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # compare EAX and *(ECX+4) b8/copy-to-EAX 1/imm32/true 74/jump-if-equal $slice-empty?:end/disp8 b8/copy-to-EAX 0/imm32/false $slice-empty?:end: # . restore registers 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 test-slice-empty-true: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX = {34, 34} 68/push 34/imm32/end 68/push 34/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # slice-empty?(slice) # . . push args 51/push-ECX # . . call e8/call slice-empty?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # check-ints-equal(EAX, 1, msg) # . . push args 68/push "F - test-slice-empty-true"/imm32 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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-empty-false: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX = {34, 23} 68/push 23/imm32/end 68/push 34/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # slice-empty?(slice) # . . push args 51/push-ECX # . . call e8/call slice-empty?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # check-ints-equal(EAX, 0, msg) # . . push args 68/push "F - test-slice-empty-false"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return slice-equal?: # s : (address slice), p : (address string) -> EAX : boolean # pseudocode: # if (p == 0) return (s == 0) # currs = s->start # maxs = s->end # if (maxs - currs != p->length) return false # currp = p->data # while currs < maxs # if (*currs != *currp) return false # ++currs # ++currp # return true # # registers: # currs: EDX # maxs: ESI # currp: EBX # *currs: EAX # *currp: ECX # # . 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 # ESI = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI # currs/EDX = s->start 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX # maxs/ESI = s->end 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 6/r32/ESI 4/disp8 . # copy *(ESI+4) to ESI # EAX = maxs - currs 89/copy 3/mod/direct 0/rm32/EAX . . . 6/r32/ESI . . # copy ESI to EAX 29/subtract 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # subtract EDX from EAX # EBX = p 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX # if (p != 0) goto next check 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0/imm32 # compare EBX 75/jump-if-not-equal $slice-equal?:nonnull-string/disp8 $slice-equal?:null-string: # return s->start == s->end 3d/compare-EAX-and 0/imm32 74/jump-if-equal $slice-equal?:true/disp8 eb/jump $slice-equal?:false/disp8 $slice-equal?:nonnull-string: # if (EAX != p->length) return false 39/compare 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # compare *EBX and EAX 75/jump-if-not-equal $slice-equal?:false/disp8 # currp/EBX = p->data 81 0/subop/add 3/mod/direct 3/rm32/EBX . . . . . 4/imm32 # add to EBX # EAX = ECX = 0 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX $slice-equal?:loop: # if (currs >= maxs) return true 39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI 7d/jump-if-greater-or-equal $slice-equal?:true/disp8 # AL = *currp 8a/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at *EBX to AL # CL = *currs 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL # if (EAX != ECX) return false 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX and ECX 75/jump-if-not-equal $slice-equal?:false/disp8 # ++currp 43/increment-EBX # ++currs 42/increment-EDX eb/jump $slice-equal?:loop/disp8 $slice-equal?:false: b8/copy-to-EAX 0/imm32 eb/jump $slice-equal?:end/disp8 $slice-equal?:true: b8/copy-to-EAX 1/imm32 $slice-equal?:end: # . restore registers 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 test-slice-equal: # - slice-equal?(slice("Abc"), "Abc") == 1 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-equal?(ECX, "Abc") # . . push args 68/push "Abc"/imm32 51/push-ECX # . . call e8/call slice-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-slice-equal"/imm32 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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-equal-false: # - slice-equal?(slice("bcd"), "Abc") == 0 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-4/imm32/end 68/push _test-slice-data-1/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-equal?(ECX, "Abc") # . . push args 68/push "Abc"/imm32 51/push-ECX # . . call e8/call slice-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-slice-equal-false"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-equal-too-long: # - slice-equal?(slice("Abcd"), "Abc") == 0 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-4/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-equal?(ECX, "Abc") # . . push args 68/push "Abc"/imm32 51/push-ECX # . . call e8/call slice-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-slice-equal-too-long"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-equal-too-short: # - slice-equal?(slice("A"), "Abc") == 0 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-1/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-equal?(ECX, "Abc") # . . push args 68/push "Abc"/imm32 51/push-ECX # . . call e8/call slice-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-slice-equal-too-short"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-equal-empty: # - slice-equal?(slice(""), "Abc") == 0 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-0/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-equal?(ECX, "Abc") # . . push args 68/push "Abc"/imm32 51/push-ECX # . . call e8/call slice-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-slice-equal-empty"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-equal-with-empty: # - slice-equal?(slice("Ab"), "") == 0 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-2/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-equal?(ECX, "") # . . push args 68/push ""/imm32 51/push-ECX # . . call e8/call slice-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-slice-equal-with-empty"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-equal-empty-with-empty: # - slice-equal?(slice(""), "") == 1 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-0/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-equal?(ECX, "") # . . push args 68/push ""/imm32 51/push-ECX # . . call e8/call slice-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-slice-equal-empty-with-empty"/imm32 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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-equal-with-null: # - slice-equal?(slice("Ab"), null) == 0 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-2/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-equal?(ECX, 0) # . . push args 68/push 0/imm32 51/push-ECX # . . call e8/call slice-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-slice-equal-with-null"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return slice-starts-with?: # s : (address slice), head : (address string) -> EAX : boolean # pseudocode # lenh = head->length # if (lenh > s->end - s->start) return false # i = 0 # currs = s->start # currp = head->data # while i < lenh # if (*currs != *currh) return false # ++i # ++currs # ++currh # return true # # registers: # currs: ESI # currh: EDI # *currs: EAX # *currh: EBX # i: ECX # lenh: EDX # # . prolog 55/push-EBP 89/copy rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI # ECX = s->end - s->start 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX 2b/subtract 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # subtract *ESI from ECX # EDI = head 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI # lenh/EDX = head->length 8b/copy 0/mod/indirect 7/rm32/EDI . . . 2/r32/EDX . . # copy *EDI to EDX # if (lenh > s->end - s->start) return false 39/compare 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # compare EDX with ECX 7f/jump-if-greater $slice-starts-with?:false/disp8 # currs/ESI = s->start 8b/subtract 0/mod/indirect 6/rm32/ESI . . . 6/r32/ESI . . # copy *ESI to ESI # currh/EDI = head->data 81 0/subop/add 3/mod/direct 7/rm32/EDI . . . . . 4/imm32 # add to EDI # i/ECX = 0 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX # EAX = EBX = 0 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 $slice-starts-with?:loop: # if (i >= lenh) return true 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX 7d/jump-if-greater-or-equal $slice-starts-with?:true/disp8 # AL = *currs 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL # BL = *currh 8a/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at *EDI to BL # if (*currs != *currh) return false 39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX 75/jump-if-not-equal $slice-starts-with?:false/disp8 # ++i 41/increment-ECX # ++currs 46/increment-ESI # ++currh 47/increment-EDI eb/jump $slice-starts-with?:loop/disp8 $slice-starts-with?:true: b8/copy-to-EAX 1/imm32 eb/jump $slice-starts-with?:end/disp8 $slice-starts-with?:false: b8/copy-to-EAX 0/imm32 $slice-starts-with?:end: # . restore registers 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 test-slice-starts-with-single-character: # - slice-starts-with?(slice("Abc"), "A") == 1 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-starts-with?(ECX, "A") # . . push args 68/push "A"/imm32 51/push-ECX # . . call e8/call slice-starts-with?/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-slice-starts-with-single-character"/imm32 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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-starts-with-empty-string: # - slice-starts-with?(slice("Abc"), "") == 1 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-starts-with?(ECX, "") # . . push args 68/push ""/imm32 51/push-ECX # . . call e8/call slice-starts-with?/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-slice-starts-with-empty-string"/imm32 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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-starts-with-multiple-characters: # - slice-starts-with?(slice("Abc"), "Ab") == 1 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-starts-with?(ECX, "Ab") # . . push args 68/push "Ab"/imm32 51/push-ECX # . . call e8/call slice-starts-with?/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-slice-starts-with-multiple-characters"/imm32 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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-starts-with-entire-string: # - slice-starts-with?(slice("Abc"), "Abc") == 1 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-starts-with?(ECX, "Abc") # . . push args 68/push "Abc"/imm32 51/push-ECX # . . call e8/call slice-starts-with?/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-slice-starts-with-entire-string"/imm32 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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-starts-with-fails: # - slice-starts-with?(slice("Abc"), "Abd") == 1 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-starts-with?(ECX, "Abd") # . . push args 68/push "Abd"/imm32 51/push-ECX # . . call e8/call slice-starts-with?/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-slice-starts-with-fails"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return test-slice-starts-with-fails-2: # - slice-starts-with?(slice("Abc"), "Ac") == 1 # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var slice/ECX 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-starts-with?(ECX, "Ac") # . . push args 68/push "Ac"/imm32 51/push-ECX # . . call e8/call slice-starts-with?/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-slice-starts-with-fails-2"/imm32 68/push 0/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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return write-slice: # out : (address buffered-file), s : (address slice) # . 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 52/push-EDX 53/push-EBX 56/push-ESI 57/push-EDI # ESI = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI # curr/ECX = s->start 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX # max/ESI = s->end 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 6/r32/ESI 4/disp8 . # copy *(ESI+4) to ESI # EDI = out 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI # EDX = out->length 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 0xc/disp8 . # copy *(EDI+12) to EDX # EBX = out->write 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 3/r32/EBX 4/disp8 . # copy *(EDI+4) to EBX $write-slice:loop: # if (curr >= max) break 39/compare 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # compare ECX with ESI 7d/jump-if-greater-or-equal $write-slice:loop-end/disp8 # if (out->write >= out->length) flush and clear out's stream 39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX with EDX 7c/jump-if-lesser $write-slice:to-stream/disp8 # . persist out->write 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 3/r32/EBX 4/disp8 . # copy EBX to *(EDI+4) # . flush(out) # . . push args 57/push-EDI # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # . clear-stream(stream = out+4) # . . push args 8d/copy-address 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EDI+4 to EAX 50/push-EAX # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # . out->write must now be 0; update its cache at EBX 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX $write-slice:to-stream: # out->data[out->write] = *in # . AL = *in 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL # . out->data[out->write] = AL 88/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/EDI 3/index/EBX . 0/r32/AL 0x10/disp8 . # copy AL to *(EDI+EBX+16) # ++out->write 43/increment-EBX # ++in 41/increment-ECX eb/jump $write-slice:loop/disp8 $write-slice:loop-end: # persist necessary variables from registers 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 3/r32/EBX 4/disp8 . # copy EBX to *(EDI+4) $write-slice:end: # . restore registers 5f/pop-to-EDI 5e/pop-to-ESI 5b/pop-to-EBX 5a/pop-to-EDX 59/pop-to-ECX 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-write-slice: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # setup # . clear-stream(_test-stream) # . . push args 68/push _test-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 50/push-EAX # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # var slice/ECX = "Abc" 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # write-slice(_test-buffered-file, slice) # . . push args 51/push-ECX 68/push _test-buffered-file/imm32 # . . call e8/call write-slice/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # flush(_test-buffered-file) # . . push args 68/push _test-buffered-file/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # check-stream-equal(_test-stream, "Abc", msg) # . . push args 68/push "F - test-write-slice"/imm32 68/push "Abc"/imm32 68/push _test-stream/imm32 # . . call e8/call check-stream-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return # copy a slice into a new (dynamically allocated) string slice-to-string: # ad : (address allocation-descriptor), in : (address slice) -> out/EAX : (address array) # . 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 # ESI = in 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI # curr/EDX = in->start 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX # max/EBX = in->end 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 3/r32/EBX 4/disp8 . # copy *(ESI+4) to EBX # size/ECX = max - curr + 4 # total size of output string (including the initial length) 89/copy 3/mod/direct 1/rm32/ECX . . . 3/r32/EBX . . # copy EBX to ECX 29/subtract 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # subtract EDX from ECX 81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX # out/EAX = allocate(ad, size) # . . push args 51/push-ECX ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) # . . call e8/call allocate/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # if (EAX == 0) abort 3d/compare-EAX-and 0/imm32 74/jump-if-equal $slice-to-string:abort/disp8 # *out = size-4 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX 81 5/subop/subtract 0/mod/indirect 0/rm32/EAX . . . . . 4/imm32 # subtract 4 from *EAX # save out 50/push-EAX # EAX = _append-4(EAX+4, EAX+size, curr, max) # clobbering ECX # . . push args 53/push-EBX 52/push-EDX # . . push EAX+size (clobbering ECX) 01/add 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to ECX 51/push-ECX # . . push EAX+4 (clobbering EAX) 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX 50/push-EAX # . . call e8/call _append-4/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP # restore out (assumes _append-4 can't error) 58/pop-to-EAX $slice-to-string:end: # . restore registers 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 $slice-to-string:abort: # . _write(2/stderr, error) # . . push args 68/push "slice-to-string: out of space"/imm32 68/push 2/imm32/stderr # . . call e8/call _write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # . syscall(exit, 1) bb/copy-to-EBX 1/imm32 b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 # never gets here test-slice-to-string: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # var heap/EDX : (address allocation-descriptor) = {0, 0} 68/push 0/imm32/limit 68/push 0/imm32/curr 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX # heap = new-segment(512) # . . push args 52/push-EDX 68/push 0x200/imm32 # . . call e8/call new-segment/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # var slice/ECX = "Abc" 68/push _test-slice-data-3/imm32/end 68/push _test-slice-data-0/imm32/start 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # EAX = slice-to-string(heap, slice) # . . push args 51/push-ECX 52/push-EDX # . . call e8/call slice-to-string/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # dump word-slice {{{ #? # . write(2/stderr, "AA: ") #? # . . push args #? 68/push "AA: "/imm32 #? 68/push 2/imm32/stderr #? # . . call #? e8/call write/disp32 #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # . write(2/stderr, EAX) #? # . . push args #? 50/push-EAX #? 68/push 2/imm32/stderr #? # . . call #? e8/call write/disp32 #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # . write(2/stderr, "$\n") #? # . . push args #? 68/push "$\n"/imm32 #? 68/push 2/imm32/stderr #? # . . call #? e8/call write/disp32 #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # }}} # EAX = string-equal?(EAX, "Abc") # . . push args 68/push "Abc"/imm32 50/push-EAX # . . 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 68/push "F - test-slice-to-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 # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return == data _test-slice-data-0: 41/A _test-slice-data-1: 62/b _test-slice-data-2: 63/c _test-slice-data-3: 64/d _test-slice-data-4: # . _. vim:nowrap:textwidth=0