# 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-starts-with-fails/disp32 #? e8/call test-slice-starts-with-single-character/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: # 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 # EBX = p 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX # 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 # 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 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 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 # ESI = s 8b/copy 1/mod/*+disp8 5/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 = f 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI # EDX = f->length 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 0xc/disp8 . # copy *(EDI+12) to EDX # EBX = f->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 (f->write >= f->length) flush and clear f'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 f->write 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 3/r32/EBX 4/disp8 . # copy EBX to *(EDI+4) # . flush(f) # . . 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 = f+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 # . f->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: # f->data[f->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 # . f->data[f->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) # ++f->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 # write an entire stream's contents to a buffered-file # ways to do this: # - construct a 'maximal slice' and pass it to write-slice # - flush the buffered-file and pass the stream directly to its fd (disabling buffering) # we'll go with the first way for now write-stream-buffered: # f : (address buffered-file), s : (address stream) -> # . 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 56/push-ESI # ESI = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI # var slice/ECX = {s->data, s->data + s->write} # . push s->data + s->write 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX 50/push-EAX # . push s->data 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy ESI+12 to EAX 50/push-EAX # . ECX = ESP 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX # write-slice(f, slice) # . . push args 51/push-ECX ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) # . . call e8/call write-slice/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP $write-stream-buffered:end: # . restore locals 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # . restore registers 5e/pop-to-ESI 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-stream-buffered: # . 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 # . clear-stream(_test-tmp-stream) # . . push args 68/push _test-tmp-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 # initialize input # . write(_test-tmp-stream, "abcd") # . . push args 68/push "abcd"/imm32 68/push _test-tmp-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # perform the write-stream-buffered # . write-stream-buffered(_test-buffered-file, _test-tmp-stream) # . . push args 68/push _test-tmp-stream/imm32 68/push _test-buffered-file/imm32 # . . call e8/call write-stream-buffered/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # check that the write happened as expected # . 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, "abcd", msg) # . . push args 68/push "F - test-write-stream-buffered"/imm32 68/push "abcd"/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 == 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