== code

# Problem: create a function which pushes n zeros on the stack.
# This is not a regular function, so it won't be idiomatic.
# Registers must be properly restored.
# Registers can be spilled, but that modifies the stack and needs to be
# cleaned up.

# This file is kinda like a research notebook, to interactively arrive at the
# solution. Nobody should have to do this without a computer. To run it:
#   $ ./translate_subx_debug 000init.linux stack_array.subx  &&  bootstrap/bootstrap --debug --trace --dump run a.elf
# There are multiple versions. You'll need to uncomment exactly one.

# The final version has its own Entry, but the others share this one.
#? Entry:
#?     # . prologue
#?     89/<- %ebp 4/r32/esp
#?     #
#?     68/push 0xfcfdfeff/imm32
#?     b8/copy-to-eax 0x34353637/imm32
#? $dump-stack:
#?     (push-n-zero-bytes 0x20)
#? $dump-stack2:
#?     68/push 0x20202020/imm32
#? $dump-stack3:
#?     b8/copy-to-eax 1/imm32/exit
#?     cd/syscall 0x80/imm8

## 0

#? push-n-zero-bytes:  # n: int
#?     # . prologue
#?     55/push-ebp
#?     89/<- %ebp 4/r32/esp
#? $push-n-zero-bytes:end:
#?     # . epilogue
#?     89/<- %esp 5/r32/ebp
#?     5d/pop-to-ebp
#?     c3/return

# stack at dump-stack:
# 0 a: bdffffd0: 00000000     00000000     00000000      00000000
# 0 a: bdffffe0: 00000000     00000000     00000000      00000000
# 0 a: bdfffff0: 00000000     fcfdfeff     00000001      bf000000
#
# =>
#
# stack at dump-stack3:
# 0 a: stack:
# 0 a: bdffffd0: 00000000     00000000     00000000      00000000
# 0 a: bdffffe0: 00000000     00000000     bdfffff8/ebp  090000cc/ra
# 0 a: bdfffff0: 00000004/arg fcfdfeff     00000001      bf000000

## 1

#? push-n-zero-bytes:  # n: int
#?     # . prologue
#?     55/push-ebp
#?     89/<- %ebp 4/r32/esp
#?     # . save registers
#?     50/push-eax
#? $push-n-zero-bytes:end:
#?     # . restore registers
#?     58/pop-to-eax
#?     # . epilogue
#?     5d/pop-to-ebp
#?     c3/return

# stack at dump-stack3:
# 0 a: bdffffd0: 00000000 00000000 00000000 00000000
# 0 a: bdffffe0: 00000000 34353637 bdfffff8 090000d1
# 0 a: bdfffff0: 00000004 fcfdfeff 00000001 bf000000

## 2

#? push-n-zero-bytes:  # n: int
#?     # . prologue
#?     55/push-ebp
#?     89/<- %ebp 4/r32/esp
#?     # . save registers
#?     50/push-eax
#?     #
#?     8b/-> *(esp+8) 0/r32/eax
#?     2b/subtract *(ebp+8) 4/r32/esp
#?     89/<- *(esp+8) 0/r32/eax
#? $push-n-zero-bytes:end:
#?     # . restore registers
#?     58/pop-to-eax
#?     # . epilogue
#?     5d/pop-to-ebp
#?     c3/return

# stack at dump-stack3:
# 0 a: bdffff90: 00000000 00000000 00000000 00000000
# 0 a: bdffffa0: 00000000 00000000 00000000 00000000
# 0 a: bdffffb0: 00000000 00000000 00000000 00000000
# 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
# 0 a: bdffffd0: 00000000 00000000 00000000 00000000
# 0 a: bdffffe0: 00000000 34353637 bdfffff8 090000d1
# 0 a: bdfffff0: 00000020 fcfdfeff 00000001 bf000000

## 3

#? push-n-zero-bytes:  # n: int
#?     # . prologue
#?     55/push-ebp
#?     89/<- %ebp 4/r32/esp
#?     # . save registers
#?     # -- esp = ebp
#?     50/push-eax
#?     # -- esp+8 = ebp+4
#?     8b/-> *(esp+8) 0/r32/eax
#?     2b/subtract *(ebp+8) 4/r32/esp
#?     89/<- *(esp+8) 0/r32/eax
#?     c7 0/subop/copy *(ebp+4) 0/imm32
#? $push-n-zero-bytes:end:
#?     # . restore registers
#?     58/pop-to-eax
#?     # . epilogue
#?     5d/pop-to-ebp
#?     c3/return

# stack at dump-stack3:
# 0 a: bdffff90: 00000000 00000000 00000000 00000000
# 0 a: bdffffa0: 00000000 00000000 00000000 00000000
# 0 a: bdffffb0: 00000000 00000000 00000000 00000000
# 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
# 0 a: bdffffd0: 20202020 00000000 00000000 00000000
# 0 a: bdffffe0: 00000000 34353637 bdfffff8 00000000
# 0 a: bdfffff0: 00000020 fcfdfeff 00000001 bf000000

## 4

#? push-n-zero-bytes:  # n: int
#?     # . prologue
#?     55/push-ebp
#?     89/<- %ebp 4/r32/esp
#?     # . save registers
#?     # -- esp = ebp
#?     50/push-eax
#?     # copy return address over
#?     # -- esp+8 = ebp+4
#?     8b/-> *(esp+8) 0/r32/eax
#?     2b/subtract *(ebp+8) 4/r32/esp
#?     89/<- *(esp+8) 0/r32/eax
#?     58/pop-to-eax
#?     c7 0/subop/copy *(ebp+8) 0/imm32
#?     c7 0/subop/copy *(ebp+4) 0/imm32
#?     c7 0/subop/copy *(ebp+0) 0/imm32
#?     c7 0/subop/copy *(ebp-4) 0/imm32
#?     # . epilogue
#?     5d/pop-to-ebp
#?     c3/return

# stack at dump-stack3:
# 0 a: bdffff90: 00000000 00000000 00000000 00000000
# 0 a: bdffffa0: 00000000 00000000 00000000 00000000
# 0 a: bdffffb0: 00000000 00000000 00000000 00000000
# 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
# 0 a: bdffffd0: 20202020 00000000 00000000 00000000
# 0 a: bdffffe0: 00000000 00000000 00000000 00000000
# 0 a: bdfffff0: 00000000 fcfdfeff 00000001 bf000000

# Stack looks good now (the 20202020 marks where the array length 0x20 will
# go, and the next 0x20 bytes show the space for the array has been zeroed
# out).
# Final issue: ebp has been clobbered on return.

## 5

# I'd like to translate ebp to esp so we can stop pushing ebp. But we need to
# hold 'n' somewhere, which would require a register, which we then need to
# push.

#? push-n-zero-bytes:  # n: int
#?     55/push-ebp
#?     89/<- %ebp 4/r32/esp
#?     # -- esp = ebp
#?     50/push-eax
#? $push-n-zero-bytes:bulk-cleaning:
#? $push-n-zero-bytes:copy-ra:
#?     # -- esp+8 = ebp+4
#?     8b/-> *(esp+8) 0/r32/eax
#?     2b/subtract *(esp+0xc) 4/r32/esp
#?     # -- esp+8+n = ebp+4
#?     89/<- *(esp+8) 0/r32/eax
#?     58/pop-to-eax
#?     # -- esp+n = ebp
#? $push-n-zero-bytes:spot-cleaning:
#?     c7 0/subop/copy *(ebp+8) 0/imm32
#?     c7 0/subop/copy *(ebp+4) 0/imm32
#?     c7 0/subop/copy *(ebp+0) 0/imm32
#?     c7 0/subop/copy *(ebp-4) 0/imm32
#?     5d/pop-to-ebp
#?     c3/return

# stack at dump-stack3:
# 0 a: bdffff90: 00000000 00000000 00000000 00000000
# 0 a: bdffffa0: 00000000 00000000 00000000 00000000
# 0 a: bdffffb0: 00000000 00000000 00000000 00000000
# 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
# 0 a: bdffffd0: 20202020 00000000 00000000 00000000
# 0 a: bdffffe0: 00000000 00000000 00000000 00000000
# 0 a: bdfffff0: 00000000 fcfdfeff 00000001 bf000000

# Bah. May be simpler to just create a new segment of global space for this
# function.

## 6

#? push-n-zero-bytes:  # n: int
#?     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
#?     89/<- %ebp 4/r32/esp
#?     # -- esp = ebp
#?     50/push-eax
#? $push-n-zero-bytes:bulk-cleaning:
#? $push-n-zero-bytes:copy-ra:
#?     # -- esp+8 = ebp+4
#?     # -- esp+4 = ebp
#?     8b/-> *(esp+4) 0/r32/eax
#?     2b/subtract *(ebp+4) 4/r32/esp
#?     # -- esp+4+n = ebp
#?     89/<- *(esp+4) 0/r32/eax
#?     58/pop-to-eax
#?     # -- esp+n = ebp
#? $push-n-zero-bytes:spot-cleaning:
#?     c7 0/subop/copy *(ebp+4) 0/imm32
#?     c7 0/subop/copy *(ebp+0) 0/imm32
#?     c7 0/subop/copy *(ebp-4) 0/imm32
#?     c7 0/subop/copy *(ebp-8) 0/imm32
#?     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
#?     c3/return
#? 
#? == data
#? Push-n-zero-bytes-ebp:  # (addr int)
#?   0/imm32
#? == code

# stack at dump-stack3:
# 0 a: bdffff90: 00000000 00000000 00000000 00000000
# 0 a: bdffffa0: 00000000 00000000 00000000 00000000
# 0 a: bdffffb0: 00000000 00000000 00000000 00000000
# 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
# 0 a: bdffffd0: 20202020 00000000 00000000 00000000
# 0 a: bdffffe0: 00000000 00000000 00000000 00000000
# 0 a: bdfffff0: 00000000 fcfdfeff 00000001 bf000000

# Ok, we're there. Now start using zero-out rather than spot-cleaning.

## 7: we need to zero out the return address, but we can't do it inside the function.
## So we'll change the signature slightly.
## Before: clear N bytes and then push N as the array length.
## After: clear N bytes, set *esp to N.
## The helper adds and clears N bytes *before* esp. esp can't be cleared since
## it contains the return address.

#? Entry:
#?     # . prologue
#?     89/<- %ebp 4/r32/esp
#?     #
#?     68/push 0xfcfdfeff/imm32
#?     b8/copy-to-eax 0x34353637/imm32
#? $dump-stack0:
#?     (push-n-zero-bytes 0x20)
#? $dump-stack9:
#?     c7 0/subop/copy *esp 0x20/imm32
#? $dump-stacka:
#?     b8/copy-to-eax 1/imm32/exit
#?     cd/syscall 0x80/imm8
#? 
#? push-n-zero-bytes:  # n: int
#? $push-n-zero-bytes:prologue:
#?     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
#?     89/<- %ebp 4/r32/esp
#? $push-n-zero-bytes:copy-ra:
#? $dump-stack1:
#?     # -- esp = ebp
#?     50/push-eax
#? $dump-stack2:
#?     # -- esp+8 = ebp+4
#?     # -- esp+4 = ebp
#?     8b/-> *(esp+4) 0/r32/eax
#? $dump-stack3:
#?     2b/subtract *(ebp+4) 4/r32/esp
#? $dump-stack4:
#?     # -- esp+4+n = ebp
#?     89/<- *(esp+4) 0/r32/eax
#? $dump-stack5:
#?     58/pop-to-eax
#?     # -- esp+n = ebp
#? $push-n-zero-bytes:bulk-cleaning:
#? $dump-stack6:
#?     89/<- *Push-n-zero-bytes-esp 4/r32/esp
#?     81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
#? $dump-stack7:
#?     (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n
#? $push-n-zero-bytes:epilogue:
#? $dump-stack8:
#?     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
#?     c3/return
#? 
#? zero-out:  # start: (addr byte), len: int
#?     # pseudocode:
#?     #   curr/esi = start
#?     #   i/ecx = 0
#?     #   while true
#?     #     if (i >= len) break
#?     #     *curr = 0
#?     #     ++curr
#?     #     ++i
#?     #
#?     # . prologue
#?     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
#?     56/push-esi
#?     # curr/esi = start
#?     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
#?     # var i/ecx: int = 0
#?     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
#?     # edx = len
#?     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
#? $zero-out:loop:
#?     # if (i >= len) break
#?     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
#?     7d/jump-if->=  $zero-out:end/disp8
#?     # *curr = 0
#?     c6          0/subop/copy        0/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm8            # copy byte to *esi
#?     # ++curr
#?     46/increment-esi
#?     # ++i
#?     41/increment-ecx
#?     eb/jump  $zero-out:loop/disp8
#? $zero-out:end:
#?     # . restore registers
#?     5e/pop-to-esi
#?     5a/pop-to-edx
#?     59/pop-to-ecx
#?     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
#? 
#? == data
#? Push-n-zero-bytes-ebp:  # (addr int)
#?   0/imm32
#? Push-n-zero-bytes-esp:  # (addr int)
#?   0/imm32
#? == code

# stack at dump-stack0:
# 0 a: bdffffb0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffc0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffd0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
# 0 a: bdfffff0:  00000000  [fcfdfeff]  00000001   bf000000 

# desired state after push-n-zero-bytes:
# 0 a: bdffff90:  00000000   00000000   00000000   00000000 
# 0 a: bdffffa0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec 
# 0 a: bdffffc0:  0900012a   bdffffd0   00000020   090000d1 
# 0 a: bdffffd0: [rrrrrrrr]  00000000   00000000   00000000 
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
# 0 a: bdfffff0:  00000000   fcfdfeff   00000001   bf000000 

# Stack pointer contains ra is caller's responsibility to over-write with array length.

# actual state:
# 0 a: bdffff90:  00000000   00000000   00000000   00000000
# 0 a: bdffffa0:  00000000   00000000   00000000   00000000
# 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec
# 0 a: bdffffc0:  0900012a   bdffffd0   00000020   090000d1
# 0 a: bdffffd0:  00000000  [00000000]  00000000   00000000
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000
# 0 a: bdfffff0:  00000020   fcfdfeff   00000001   bf000000

# Couple of issues. But where does the return address disappear to?

## 8:

#? Entry:
#?     # . prologue
#?     89/<- %ebp 4/r32/esp
#?     #
#?     68/push 0xfcfdfeff/imm32
#?     b8/copy-to-eax 0x34353637/imm32
#? $dump-stack0:
#?     (push-n-zero-bytes 0x20)
#? $dump-stack9:
#?     68/push 0x20/imm32
#? #?     c7 0/subop/copy *esp 0x20/imm32
#? $dump-stacka:
#?     b8/copy-to-eax 1/imm32/exit
#?     cd/syscall 0x80/imm8
#? 
#? push-n-zero-bytes:  # n: int
#? $push-n-zero-bytes:prologue:
#?     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
#?     89/<- %ebp 4/r32/esp
#? $push-n-zero-bytes:copy-ra:
#? $dump-stack1:
#?     # -- esp = ebp
#?     50/push-eax
#? $dump-stack2:
#?     # -- esp+8 = ebp+4
#?     # -- esp+4 = ebp
#?     8b/-> *(esp+4) 0/r32/eax
#? $dump-stack3:
#?     2b/subtract *(ebp+4) 4/r32/esp
#? $dump-stack4:
#?     # -- esp+4+n = ebp
#?     89/<- *(esp+4) 0/r32/eax
#? $dump-stack5:
#?     58/pop-to-eax
#?     # -- esp+n = ebp
#? $push-n-zero-bytes:bulk-cleaning:
#? $dump-stack6:
#?     89/<- *Push-n-zero-bytes-esp 4/r32/esp
#?     81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
#? $dump-stack7:
#?     (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n
#? $push-n-zero-bytes:epilogue:
#? $dump-stack8:
#?     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
#?     c3/return
#? 
#? zero-out:  # start: (addr byte), len: int
#?     # pseudocode:
#?     #   curr/esi = start
#?     #   i/ecx = 0
#?     #   while true
#?     #     if (i >= len) break
#?     #     *curr = 0
#?     #     ++curr
#?     #     ++i
#?     #
#?     # . prologue
#?     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
#?     56/push-esi
#?     # curr/esi = start
#?     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
#?     # var i/ecx: int = 0
#?     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
#?     # edx = len
#?     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
#? $zero-out:loop:
#?     # if (i >= len) break
#?     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
#?     7d/jump-if->=  $zero-out:end/disp8
#?     # *curr = 0
#?     c6          0/subop/copy        0/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm8            # copy byte to *esi
#?     # ++curr
#?     46/increment-esi
#?     # ++i
#?     41/increment-ecx
#?     eb/jump  $zero-out:loop/disp8
#? $zero-out:end:
#?     # . restore registers
#?     5e/pop-to-esi
#?     5a/pop-to-edx
#?     59/pop-to-ecx
#?     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
#? 
#? == data
#? Push-n-zero-bytes-ebp:  # (addr int)
#?   0/imm32
#? Push-n-zero-bytes-esp:  # (addr int)
#?   0/imm32
#? == code

# stack at dump-stack0:
# 0 a: bdffffb0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffc0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffd0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
# 0 a: bdfffff0:  00000000  [fcfdfeff]  00000001   bf000000 

# desired state after push-n-zero-bytes:
# 0 a: bdffff90:  00000000   00000000   00000000   00000000 
# 0 a: bdffffa0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec 
# 0 a: bdffffc0:  0900012a   bdffffd0   00000020   090000d1 
# 0 a: bdffffd0: [rrrrrrrr]  00000000   00000000   00000000 
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
# 0 a: bdfffff0:  00000000   fcfdfeff   00000001   bf000000 

# actual state:
# 0 a: bdffff90:  00000000   00000000   00000000   00000000
# 0 a: bdffffa0:  00000000   00000000   00000000   00000000
# 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec
# 0 a: bdffffc0:  09000124   bdffffd0   00000020   090000d1
# 0 a: bdffffd0: [00000000]  00000000   00000000   00000000
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000
# 0 a: bdfffff0:  00000020   fcfdfeff   00000001   bf000000

# Ok, just one diff, at bdfffff0

## 9:

Entry:
    # . prologue
    89/<- %ebp 4/r32/esp
    #
    68/push 0xfcfdfeff/imm32
    b8/copy-to-eax 0x34353637/imm32
$dump-stack0:
    (push-n-zero-bytes 0x20)
$dump-stack9:
    68/push 0x20/imm32
$dump-stacka:
    b8/copy-to-eax 1/imm32/exit
    cd/syscall 0x80/imm8

push-n-zero-bytes:  # n: int
$push-n-zero-bytes:prologue:
    89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
    89/<- %ebp 4/r32/esp
$push-n-zero-bytes:copy-ra:
$dump-stack1:
    # -- esp = ebp
    50/push-eax
$dump-stack2:
    # -- esp+8 = ebp+4
    # -- esp+4 = ebp
    8b/-> *(esp+4) 0/r32/eax
$dump-stack3:
    2b/subtract *(ebp+4) 4/r32/esp
$dump-stack4:
    # -- esp+4+n = ebp
    89/<- *(esp+4) 0/r32/eax
$dump-stack5:
    58/pop-to-eax
    # -- esp+n = ebp
$push-n-zero-bytes:bulk-cleaning:
$dump-stack6:
    89/<- *Push-n-zero-bytes-esp 4/r32/esp
    81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
$dump-stack7:
    81 0/subop/add *(ebp+4) 4/imm32
    (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n
$push-n-zero-bytes:epilogue:
$dump-stack8:
    8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
    c3/return

zero-out:  # start: (addr byte), len: int
    # pseudocode:
    #   curr/esi = start
    #   i/ecx = 0
    #   while true
    #     if (i >= len) break
    #     *curr = 0
    #     ++curr
    #     ++i
    #
    # . prologue
    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
    56/push-esi
    # curr/esi = start
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # var i/ecx: int = 0
    31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
    # edx = len
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
$zero-out:loop:
    # if (i >= len) break
    39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
    7d/jump-if->=  $zero-out:end/disp8
    # *curr = 0
    c6          0/subop/copy        0/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm8            # copy byte to *esi
    # ++curr
    46/increment-esi
    # ++i
    41/increment-ecx
    eb/jump  $zero-out:loop/disp8
$zero-out:end:
    # . restore registers
    5e/pop-to-esi
    5a/pop-to-edx
    59/pop-to-ecx
    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

== data
Push-n-zero-bytes-ebp:  # (addr int)
  0/imm32
Push-n-zero-bytes-esp:  # (addr int)
  0/imm32
== code

# stack at dump-stack0:
# 0 a: bdffffb0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffc0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffd0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
# 0 a: bdfffff0:  00000000  [fcfdfeff]  00000001   bf000000 

# desired state after push-n-zero-bytes:
# 0 a: bdffff90:  00000000   00000000   00000000   00000000 
# 0 a: bdffffa0:  00000000   00000000   00000000   00000000 
# 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec 
# 0 a: bdffffc0:  0900012a   bdffffd0   00000020   090000d1 
# 0 a: bdffffd0: [xxxxxxxx]  00000000   00000000   00000000 
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
# 0 a: bdfffff0:  00000000   fcfdfeff   00000001   bf000000 

# actual state:
# 0 a: bdffff90:  00000000   00000000   00000000   00000000
# 0 a: bdffffa0:  00000000   00000000   00000000   00000000
# 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec
# 0 a: bdffffc0:  0900012f   bdffffd0   00000024   090000d1
# 0 a: bdffffd0: [00000000]  00000000   00000000   00000000
# 0 a: bdffffe0:  00000000   00000000   00000000   00000000
# 0 a: bdfffff0:  00000000   fcfdfeff   00000001   bf000000