# Helper to allocate a stream on the heap. == 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 new-stream: # ad: (addr allocation-descriptor), length: int, elemsize: int, out: (addr handle stream _) # . prologue 55/push-ebp 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp # . save registers 50/push-eax 52/push-edx # var size/edx: int = elemsize*length (clobbering eax) # . eax = elemsize 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax # . eax *= length 31/xor 3/mod/direct 2/rm32/edx . . . 2/r32/edx . . # clear edx f7 4/subop/multiply 1/mod/*+disp8 5/rm32/ebp . . 0xc/disp8 . # multiply *(ebp+12) into edx:eax # . if overflow abort 81 7/subop/compare 3/mod/direct 2/rm32/edx . . . . . 0/imm32 # compare edx 75/jump-if-!= $new-stream:abort/disp8 # . edx = elemsize*length 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx # var n/eax: int = size + 12 (for read, write and size) 05/add-to-eax 0xc/imm32 # allocate(ad, n, out) # . . push args ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) 50/push-eax 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 . . . . . 0xc/imm32 # add to esp # eax = out->payload 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x14/disp8 . # copy *(ebp+20) to eax 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax # skip payload->allocid 05/add-to-eax 4/imm32 # eax->size = size 89/copy 1/mod/*+disp8 0/rm32/eax . . . 2/r32/edx 8/disp8 . # copy edx to *(eax+8) # clear-stream(eax) # . . push args 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 $new-stream:end: # . restore registers 5a/pop-to-edx 58/pop-to-eax # . epilogue 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 5d/pop-to-ebp c3/return $new-stream:abort: (abort "new-stream: size too large") # never gets here test-new-stream: # . prologue 55/push-ebp 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp # var ad/ecx: allocation-descriptor containing 16 bytes # . var end/ecx: (addr byte) 89/<- %ecx 4/r32/esp # . var start/edx: (addr byte) = end - 32 81 5/subop/subtract %esp 0x20/imm32 89/<- %edx 4/r32/esp # . ad = {start, end} 51/push-ecx 52/push-edx 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx # var start/edx = ad->curr 8b/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy *ecx to edx # var h/ebx: (handle stream byte) 68/push 0/imm32 68/push 0/imm32 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx # new-stream(ad, 3, 2, h) # . . push args 53/push-ebx 68/push 2/imm32 68/push 3/imm32 51/push-ecx # . . call e8/call new-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp # eax = out->payload 8b/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy *(ebx+4) to eax # check-ints-equal(eax, edx, msg) # . . push args 68/push "F - test-new-stream: returns current pointer of allocation descriptor"/imm32 52/push-edx 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 # skip payload->allocid 05/add-to-eax 4/imm32 # check-ints-equal(eax->size, 6, msg) # . . push args 68/push "F - test-new-stream: sets size correctly"/imm32 68/push 6/imm32 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . . 8/disp8 # push *(eax+8) # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp # the rest is delegated to clear-stream() so we won't bother checking it # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x30/imm32 # add to esp # . epilogue 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 5d/pop-to-ebp c3/return # . . vim:nowrap:textwidth=0