https://github.com/akkartik/mu/blob/main/linux/stack_array.subx
  1 == code
  2 
  3 # Problem: create a function which pushes n zeros on the stack.
  4 # This is not a regular function, so it won't be idiomatic.
  5 # Registers must be properly restored.
  6 # Registers can be spilled, but that modifies the stack and needs to be
  7 # cleaned up.
  8 
  9 # This file is kinda like a research notebook, to interactively arrive at the
 10 # solution. Nobody should have to do this without a computer. To run it:
 11 #   $ ./translate_subx_debug 000init.linux stack_array.subx  &&  bootstrap/bootstrap --debug --trace --dump run a.elf
 12 # There are multiple versions. You'll need to uncomment exactly one.
 13 
 14 # The final version has its own Entry, but the others share this one.
 15 #? Entry:
 16 #?     # . prologue
 17 #?     89/<- %ebp 4/r32/esp
 18 #?     #
 19 #?     68/push 0xfcfdfeff/imm32
 20 #?     b8/copy-to-eax 0x34353637/imm32
 21 #? $dump-stack:
 22 #?     (push-n-zero-bytes 0x20)
 23 #? $dump-stack2:
 24 #?     68/push 0x20202020/imm32
 25 #? $dump-stack3:
 26 #?     b8/copy-to-eax 1/imm32/exit
 27 #?     cd/syscall 0x80/imm8
 28 
 29 ## 0
 30 
 31 #? push-n-zero-bytes:  # n: int
 32 #?     # . prologue
 33 #?     55/push-ebp
 34 #?     89/<- %ebp 4/r32/esp
 35 #? $push-n-zero-bytes:end:
 36 #?     # . epilogue
 37 #?     89/<- %esp 5/r32/ebp
 38 #?     5d/pop-to-ebp
 39 #?     c3/return
 40 
 41 # stack at dump-stack:
 42 # 0 a: bdffffd0: 00000000     00000000     00000000      00000000
 43 # 0 a: bdffffe0: 00000000     00000000     00000000      00000000
 44 # 0 a: bdfffff0: 00000000     fcfdfeff     00000001      bf000000
 45 #
 46 # =>
 47 #
 48 # stack at dump-stack3:
 49 # 0 a: stack:
 50 # 0 a: bdffffd0: 00000000     00000000     00000000      00000000
 51 # 0 a: bdffffe0: 00000000     00000000     bdfffff8/ebp  090000cc/ra
 52 # 0 a: bdfffff0: 00000004/arg fcfdfeff     00000001      bf000000
 53 
 54 ## 1
 55 
 56 #? push-n-zero-bytes:  # n: int
 57 #?     # . prologue
 58 #?     55/push-ebp
 59 #?     89/<- %ebp 4/r32/esp
 60 #?     # . save registers
 61 #?     50/push-eax
 62 #? $push-n-zero-bytes:end:
 63 #?     # . restore registers
 64 #?     58/pop-to-eax
 65 #?     # . epilogue
 66 #?     5d/pop-to-ebp
 67 #?     c3/return
 68 
 69 # stack at dump-stack3:
 70 # 0 a: bdffffd0: 00000000 00000000 00000000 00000000
 71 # 0 a: bdffffe0: 00000000 34353637 bdfffff8 090000d1
 72 # 0 a: bdfffff0: 00000004 fcfdfeff 00000001 bf000000
 73 
 74 ## 2
 75 
 76 #? push-n-zero-bytes:  # n: int
 77 #?     # . prologue
 78 #?     55/push-ebp
 79 #?     89/<- %ebp 4/r32/esp
 80 #?     # . save registers
 81 #?     50/push-eax
 82 #?     #
 83 #?     8b/-> *(esp+8) 0/r32/eax
 84 #?     2b/subtract *(ebp+8) 4/r32/esp
 85 #?     89/<- *(esp+8) 0/r32/eax
 86 #? $push-n-zero-bytes:end:
 87 #?     # . restore registers
 88 #?     58/pop-to-eax
 89 #?     # . epilogue
 90 #?     5d/pop-to-ebp
 91 #?     c3/return
 92 
 93 # stack at dump-stack3:
 94 # 0 a: bdffff90: 00000000 00000000 00000000 00000000
 95 # 0 a: bdffffa0: 00000000 00000000 00000000 00000000
 96 # 0 a: bdffffb0: 00000000 00000000 00000000 00000000
 97 # 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
 98 # 0 a: bdffffd0: 00000000 00000000 00000000 00000000
 99 # 0 a: bdffffe0: 00000000 34353637 bdfffff8 090000d1
100 # 0 a: bdfffff0: 00000020 fcfdfeff 00000001 bf000000
101 
102 ## 3
103 
104 #? push-n-zero-bytes:  # n: int
105 #?     # . prologue
106 #?     55/push-ebp
107 #?     89/<- %ebp 4/r32/esp
108 #?     # . save registers
109 #?     # -- esp = ebp
110 #?     50/push-eax
111 #?     # -- esp+8 = ebp+4
112 #?     8b/-> *(esp+8) 0/r32/eax
113 #?     2b/subtract *(ebp+8) 4/r32/esp
114 #?     89/<- *(esp+8) 0/r32/eax
115 #?     c7 0/subop/copy *(ebp+4) 0/imm32
116 #? $push-n-zero-bytes:end:
117 #?     # . restore registers
118 #?     58/pop-to-eax
119 #?     # . epilogue
120 #?     5d/pop-to-ebp
121 #?     c3/return
122 
123 # stack at dump-stack3:
124 # 0 a: bdffff90: 00000000 00000000 00000000 00000000
125 # 0 a: bdffffa0: 00000000 00000000 00000000 00000000
126 # 0 a: bdffffb0: 00000000 00000000 00000000 00000000
127 # 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
128 # 0 a: bdffffd0: 20202020 00000000 00000000 00000000
129 # 0 a: bdffffe0: 00000000 34353637 bdfffff8 00000000
130 # 0 a: bdfffff0: 00000020 fcfdfeff 00000001 bf000000
131 
132 ## 4
133 
134 #? push-n-zero-bytes:  # n: int
135 #?     # . prologue
136 #?     55/push-ebp
137 #?     89/<- %ebp 4/r32/esp
138 #?     # . save registers
139 #?     # -- esp = ebp
140 #?     50/push-eax
141 #?     # copy return address over
142 #?     # -- esp+8 = ebp+4
143 #?     8b/-> *(esp+8) 0/r32/eax
144 #?     2b/subtract *(ebp+8) 4/r32/esp
145 #?     89/<- *(esp+8) 0/r32/eax
146 #?     58/pop-to-eax
147 #?     c7 0/subop/copy *(ebp+8) 0/imm32
148 #?     c7 0/subop/copy *(ebp+4) 0/imm32
149 #?     c7 0/subop/copy *(ebp+0) 0/imm32
150 #?     c7 0/subop/copy *(ebp-4) 0/imm32
151 #?     # . epilogue
152 #?     5d/pop-to-ebp
153 #?     c3/return
154 
155 # stack at dump-stack3:
156 # 0 a: bdffff90: 00000000 00000000 00000000 00000000
157 # 0 a: bdffffa0: 00000000 00000000 00000000 00000000
158 # 0 a: bdffffb0: 00000000 00000000 00000000 00000000
159 # 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
160 # 0 a: bdffffd0: 20202020 00000000 00000000 00000000
161 # 0 a: bdffffe0: 00000000 00000000 00000000 00000000
162 # 0 a: bdfffff0: 00000000 fcfdfeff 00000001 bf000000
163 
164 # Stack looks good now (the 20202020 marks where the array length 0x20 will
165 # go, and the next 0x20 bytes show the space for the array has been zeroed
166 # out).
167 # Final issue: ebp has been clobbered on return.
168 
169 ## 5
170 
171 # I'd like to translate ebp to esp so we can stop pushing ebp. But we need to
172 # hold 'n' somewhere, which would require a register, which we then need to
173 # push.
174 
175 #? push-n-zero-bytes:  # n: int
176 #?     55/push-ebp
177 #?     89/<- %ebp 4/r32/esp
178 #?     # -- esp = ebp
179 #?     50/push-eax
180 #? $push-n-zero-bytes:bulk-cleaning:
181 #? $push-n-zero-bytes:copy-ra:
182 #?     # -- esp+8 = ebp+4
183 #?     8b/-> *(esp+8) 0/r32/eax
184 #?     2b/subtract *(esp+0xc) 4/r32/esp
185 #?     # -- esp+8+n = ebp+4
186 #?     89/<- *(esp+8) 0/r32/eax
187 #?     58/pop-to-eax
188 #?     # -- esp+n = ebp
189 #? $push-n-zero-bytes:spot-cleaning:
190 #?     c7 0/subop/copy *(ebp+8) 0/imm32
191 #?     c7 0/subop/copy *(ebp+4) 0/imm32
192 #?     c7 0/subop/copy *(ebp+0) 0/imm32
193 #?     c7 0/subop/copy *(ebp-4) 0/imm32
194 #?     5d/pop-to-ebp
195 #?     c3/return
196 
197 # stack at dump-stack3:
198 # 0 a: bdffff90: 00000000 00000000 00000000 00000000
199 # 0 a: bdffffa0: 00000000 00000000 00000000 00000000
200 # 0 a: bdffffb0: 00000000 00000000 00000000 00000000
201 # 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
202 # 0 a: bdffffd0: 20202020 00000000 00000000 00000000
203 # 0 a: bdffffe0: 00000000 00000000 00000000 00000000
204 # 0 a: bdfffff0: 00000000 fcfdfeff 00000001 bf000000
205 
206 # Bah. May be simpler to just create a new segment of global space for this
207 # function.
208 
209 ## 6
210 
211 #? push-n-zero-bytes:  # n: int
212 #?     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
213 #?     89/<- %ebp 4/r32/esp
214 #?     # -- esp = ebp
215 #?     50/push-eax
216 #? $push-n-zero-bytes:bulk-cleaning:
217 #? $push-n-zero-bytes:copy-ra:
218 #?     # -- esp+8 = ebp+4
219 #?     # -- esp+4 = ebp
220 #?     8b/-> *(esp+4) 0/r32/eax
221 #?     2b/subtract *(ebp+4) 4/r32/esp
222 #?     # -- esp+4+n = ebp
223 #?     89/<- *(esp+4) 0/r32/eax
224 #?     58/pop-to-eax
225 #?     # -- esp+n = ebp
226 #? $push-n-zero-bytes:spot-cleaning:
227 #?     c7 0/subop/copy *(ebp+4) 0/imm32
228 #?     c7 0/subop/copy *(ebp+0) 0/imm32
229 #?     c7 0/subop/copy *(ebp-4) 0/imm32
230 #?     c7 0/subop/copy *(ebp-8) 0/imm32
231 #?     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
232 #?     c3/return
233 #? 
234 #? == data
235 #? Push-n-zero-bytes-ebp:  # (addr int)
236 #?   0/imm32
237 #? == code
238 
239 # stack at dump-stack3:
240 # 0 a: bdffff90: 00000000 00000000 00000000 00000000
241 # 0 a: bdffffa0: 00000000 00000000 00000000 00000000
242 # 0 a: bdffffb0: 00000000 00000000 00000000 00000000
243 # 0 a: bdffffc0: 00000000 00000000 00000000 090000d1
244 # 0 a: bdffffd0: 20202020 00000000 00000000 00000000
245 # 0 a: bdffffe0: 00000000 00000000 00000000 00000000
246 # 0 a: bdfffff0: 00000000 fcfdfeff 00000001 bf000000
247 
248 # Ok, we're there. Now start using zero-out rather than spot-cleaning.
249 
250 ## 7: we need to zero out the return address, but we can't do it inside the function.
251 ## So we'll change the signature slightly.
252 ## Before: clear N bytes and then push N as the array length.
253 ## After: clear N bytes, set *esp to N.
254 ## The helper adds and clears N bytes *before* esp. esp can't be cleared since
255 ## it contains the return address.
256 
257 #? Entry:
258 #?     # . prologue
259 #?     89/<- %ebp 4/r32/esp
260 #?     #
261 #?     68/push 0xfcfdfeff/imm32
262 #?     b8/copy-to-eax 0x34353637/imm32
263 #? $dump-stack0:
264 #?     (push-n-zero-bytes 0x20)
265 #? $dump-stack9:
266 #?     c7 0/subop/copy *esp 0x20/imm32
267 #? $dump-stacka:
268 #?     b8/copy-to-eax 1/imm32/exit
269 #?     cd/syscall 0x80/imm8
270 #? 
271 #? push-n-zero-bytes:  # n: int
272 #? $push-n-zero-bytes:prologue:
273 #?     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
274 #?     89/<- %ebp 4/r32/esp
275 #? $push-n-zero-bytes:copy-ra:
276 #? $dump-stack1:
277 #?     # -- esp = ebp
278 #?     50/push-eax
279 #? $dump-stack2:
280 #?     # -- esp+8 = ebp+4
281 #?     # -- esp+4 = ebp
282 #?     8b/-> *(esp+4) 0/r32/eax
283 #? $dump-stack3:
284 #?     2b/subtract *(ebp+4) 4/r32/esp
285 #? $dump-stack4:
286 #?     # -- esp+4+n = ebp
287 #?     89/<- *(esp+4) 0/r32/eax
288 #? $dump-stack5:
289 #?     58/pop-to-eax
290 #?     # -- esp+n = ebp
291 #? $push-n-zero-bytes:bulk-cleaning:
292 #? $dump-stack6:
293 #?     89/<- *Push-n-zero-bytes-esp 4/r32/esp
294 #?     81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
295 #? $dump-stack7:
296 #?     (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n
297 #? $push-n-zero-bytes:epilogue:
298 #? $dump-stack8:
299 #?     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
300 #?     c3/return
301 #? 
302 #? zero-out:  # start: (addr byte), len: int
303 #?     # pseudocode:
304 #?     #   curr/esi = start
305 #?     #   i/ecx = 0
306 #?     #   while true
307 #?     #     if (i >= len) break
308 #?     #     *curr = 0
309 #?     #     ++curr
310 #?     #     ++i
311 #?     #
312 #?     # . prologue
313 #?     55/push-ebp
314 #?     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
315 #?     # . save registers
316 #?     50/push-eax
317 #?     51/push-ecx
318 #?     52/push-edx
319 #?     56/push-esi
320 #?     # curr/esi = start
321 #?     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
322 #?     # var i/ecx: int = 0
323 #?     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
324 #?     # edx = len
325 #?     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
326 #? $zero-out:loop:
327 #?     # if (i >= len) break
328 #?     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
329 #?     7d/jump-if->=  $zero-out:end/disp8
330 #?     # *curr = 0
331 #?     c6          0/subop/copy        0/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm8            # copy byte to *esi
332 #?     # ++curr
333 #?     46/increment-esi
334 #?     # ++i
335 #?     41/increment-ecx
336 #?     eb/jump  $zero-out:loop/disp8
337 #? $zero-out:end:
338 #?     # . restore registers
339 #?     5e/pop-to-esi
340 #?     5a/pop-to-edx
341 #?     59/pop-to-ecx
342 #?     58/pop-to-eax
343 #?     # . epilogue
344 #?     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
345 #?     5d/pop-to-ebp
346 #?     c3/return
347 #? 
348 #? == data
349 #? Push-n-zero-bytes-ebp:  # (addr int)
350 #?   0/imm32
351 #? Push-n-zero-bytes-esp:  # (addr int)
352 #?   0/imm32
353 #? == code
354 
355 # stack at dump-stack0:
356 # 0 a: bdffffb0:  00000000   00000000   00000000   00000000 
357 # 0 a: bdffffc0:  00000000   00000000   00000000   00000000 
358 # 0 a: bdffffd0:  00000000   00000000   00000000   00000000 
359 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
360 # 0 a: bdfffff0:  00000000  [fcfdfeff]  00000001   bf000000 
361 
362 # desired state after push-n-zero-bytes:
363 # 0 a: bdffff90:  00000000   00000000   00000000   00000000 
364 # 0 a: bdffffa0:  00000000   00000000   00000000   00000000 
365 # 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec 
366 # 0 a: bdffffc0:  0900012a   bdffffd0   00000020   090000d1 
367 # 0 a: bdffffd0: [rrrrrrrr]  00000000   00000000   00000000 
368 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
369 # 0 a: bdfffff0:  00000000   fcfdfeff   00000001   bf000000 
370 
371 # Stack pointer contains ra is caller's responsibility to over-write with array length.
372 
373 # actual state:
374 # 0 a: bdffff90:  00000000   00000000   00000000   00000000
375 # 0 a: bdffffa0:  00000000   00000000   00000000   00000000
376 # 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec
377 # 0 a: bdffffc0:  0900012a   bdffffd0   00000020   090000d1
378 # 0 a: bdffffd0:  00000000  [00000000]  00000000   00000000
379 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000
380 # 0 a: bdfffff0:  00000020   fcfdfeff   00000001   bf000000
381 
382 # Couple of issues. But where does the return address disappear to?
383 
384 ## 8:
385 
386 #? Entry:
387 #?     # . prologue
388 #?     89/<- %ebp 4/r32/esp
389 #?     #
390 #?     68/push 0xfcfdfeff/imm32
391 #?     b8/copy-to-eax 0x34353637/imm32
392 #? $dump-stack0:
393 #?     (push-n-zero-bytes 0x20)
394 #? $dump-stack9:
395 #?     68/push 0x20/imm32
396 #? #?     c7 0/subop/copy *esp 0x20/imm32
397 #? $dump-stacka:
398 #?     b8/copy-to-eax 1/imm32/exit
399 #?     cd/syscall 0x80/imm8
400 #? 
401 #? push-n-zero-bytes:  # n: int
402 #? $push-n-zero-bytes:prologue:
403 #?     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
404 #?     89/<- %ebp 4/r32/esp
405 #? $push-n-zero-bytes:copy-ra:
406 #? $dump-stack1:
407 #?     # -- esp = ebp
408 #?     50/push-eax
409 #? $dump-stack2:
410 #?     # -- esp+8 = ebp+4
411 #?     # -- esp+4 = ebp
412 #?     8b/-> *(esp+4) 0/r32/eax
413 #? $dump-stack3:
414 #?     2b/subtract *(ebp+4) 4/r32/esp
415 #? $dump-stack4:
416 #?     # -- esp+4+n = ebp
417 #?     89/<- *(esp+4) 0/r32/eax
418 #? $dump-stack5:
419 #?     58/pop-to-eax
420 #?     # -- esp+n = ebp
421 #? $push-n-zero-bytes:bulk-cleaning:
422 #? $dump-stack6:
423 #?     89/<- *Push-n-zero-bytes-esp 4/r32/esp
424 #?     81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
425 #? $dump-stack7:
426 #?     (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n
427 #? $push-n-zero-bytes:epilogue:
428 #? $dump-stack8:
429 #?     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
430 #?     c3/return
431 #? 
432 #? zero-out:  # start: (addr byte), len: int
433 #?     # pseudocode:
434 #?     #   curr/esi = start
435 #?     #   i/ecx = 0
436 #?     #   while true
437 #?     #     if (i >= len) break
438 #?     #     *curr = 0
439 #?     #     ++curr
440 #?     #     ++i
441 #?     #
442 #?     # . prologue
443 #?     55/push-ebp
444 #?     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
445 #?     # . save registers
446 #?     50/push-eax
447 #?     51/push-ecx
448 #?     52/push-edx
449 #?     56/push-esi
450 #?     # curr/esi = start
451 #?     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
452 #?     # var i/ecx: int = 0
453 #?     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
454 #?     # edx = len
455 #?     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
456 #? $zero-out:loop:
457 #?     # if (i >= len) break
458 #?     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
459 #?     7d/jump-if->=  $zero-out:end/disp8
460 #?     # *curr = 0
461 #?     c6          0/subop/copy        0/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm8            # copy byte to *esi
462 #?     # ++curr
463 #?     46/increment-esi
464 #?     # ++i
465 #?     41/increment-ecx
466 #?     eb/jump  $zero-out:loop/disp8
467 #? $zero-out:end:
468 #?     # . restore registers
469 #?     5e/pop-to-esi
470 #?     5a/pop-to-edx
471 #?     59/pop-to-ecx
472 #?     58/pop-to-eax
473 #?     # . epilogue
474 #?     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
475 #?     5d/pop-to-ebp
476 #?     c3/return
477 #? 
478 #? == data
479 #? Push-n-zero-bytes-ebp:  # (addr int)
480 #?   0/imm32
481 #? Push-n-zero-bytes-esp:  # (addr int)
482 #?   0/imm32
483 #? == code
484 
485 # stack at dump-stack0:
486 # 0 a: bdffffb0:  00000000   00000000   00000000   00000000 
487 # 0 a: bdffffc0:  00000000   00000000   00000000   00000000 
488 # 0 a: bdffffd0:  00000000   00000000   00000000   00000000 
489 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
490 # 0 a: bdfffff0:  00000000  [fcfdfeff]  00000001   bf000000 
491 
492 # desired state after push-n-zero-bytes:
493 # 0 a: bdffff90:  00000000   00000000   00000000   00000000 
494 # 0 a: bdffffa0:  00000000   00000000   00000000   00000000 
495 # 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec 
496 # 0 a: bdffffc0:  0900012a   bdffffd0   00000020   090000d1 
497 # 0 a: bdffffd0: [rrrrrrrr]  00000000   00000000   00000000 
498 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
499 # 0 a: bdfffff0:  00000000   fcfdfeff   00000001   bf000000 
500 
501 # actual state:
502 # 0 a: bdffff90:  00000000   00000000   00000000   00000000
503 # 0 a: bdffffa0:  00000000   00000000   00000000   00000000
504 # 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec
505 # 0 a: bdffffc0:  09000124   bdffffd0   00000020   090000d1
506 # 0 a: bdffffd0: [00000000]  00000000   00000000   00000000
507 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000
508 # 0 a: bdfffff0:  00000020   fcfdfeff   00000001   bf000000
509 
510 # Ok, just one diff, at bdfffff0
511 
512 ## 9:
513 
514 Entry:
515     # . prologue
516     89/<- %ebp 4/r32/esp
517     #
518     68/push 0xfcfdfeff/imm32
519     b8/copy-to-eax 0x34353637/imm32
520 $dump-stack0:
521     (push-n-zero-bytes 0x20)
522 $dump-stack9:
523     68/push 0x20/imm32
524 $dump-stacka:
525     b8/copy-to-eax 1/imm32/exit
526     cd/syscall 0x80/imm8
527 
528 push-n-zero-bytes:  # n: int
529 $push-n-zero-bytes:prologue:
530     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
531     89/<- %ebp 4/r32/esp
532 $push-n-zero-bytes:copy-ra:
533 $dump-stack1:
534     # -- esp = ebp
535     50/push-eax
536 $dump-stack2:
537     # -- esp+8 = ebp+4
538     # -- esp+4 = ebp
539     8b/-> *(esp+4) 0/r32/eax
540 $dump-stack3:
541     2b/subtract *(ebp+4) 4/r32/esp
542 $dump-stack4:
543     # -- esp+4+n = ebp
544     89/<- *(esp+4) 0/r32/eax
545 $dump-stack5:
546     58/pop-to-eax
547     # -- esp+n = ebp
548 $push-n-zero-bytes:bulk-cleaning:
549 $dump-stack6:
550     89/<- *Push-n-zero-bytes-esp 4/r32/esp
551     81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
552 $dump-stack7:
553     81 0/subop/add *(ebp+4) 4/imm32
554     (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n
555 $push-n-zero-bytes:epilogue:
556 $dump-stack8:
557     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
558     c3/return
559 
560 zero-out:  # start: (addr byte), len: int
561     # pseudocode:
562     #   curr/esi = start
563     #   i/ecx = 0
564     #   while true
565     #     if (i >= len) break
566     #     *curr = 0
567     #     ++curr
568     #     ++i
569     #
570     # . prologue
571     55/push-ebp
572     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
573     # . save registers
574     50/push-eax
575     51/push-ecx
576     52/push-edx
577     56/push-esi
578     # curr/esi = start
579     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
580     # var i/ecx: int = 0
581     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
582     # edx = len
583     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
584 $zero-out:loop:
585     # if (i >= len) break
586     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
587     7d/jump-if->=  $zero-out:end/disp8
588     # *curr = 0
589     c6          0/subop/copy        0/mod/direct    6/rm32/esi    .           .             .           .           .               0/imm8            # copy byte to *esi
590     # ++curr
591     46/increment-esi
592     # ++i
593     41/increment-ecx
594     eb/jump  $zero-out:loop/disp8
595 $zero-out:end:
596     # . restore registers
597     5e/pop-to-esi
598     5a/pop-to-edx
599     59/pop-to-ecx
600     58/pop-to-eax
601     # . epilogue
602     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
603     5d/pop-to-ebp
604     c3/return
605 
606 == data
607 Push-n-zero-bytes-ebp:  # (addr int)
608   0/imm32
609 Push-n-zero-bytes-esp:  # (addr int)
610   0/imm32
611 == code
612 
613 # stack at dump-stack0:
614 # 0 a: bdffffb0:  00000000   00000000   00000000   00000000 
615 # 0 a: bdffffc0:  00000000   00000000   00000000   00000000 
616 # 0 a: bdffffd0:  00000000   00000000   00000000   00000000 
617 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
618 # 0 a: bdfffff0:  00000000  [fcfdfeff]  00000001   bf000000 
619 
620 # desired state after push-n-zero-bytes:
621 # 0 a: bdffff90:  00000000   00000000   00000000   00000000 
622 # 0 a: bdffffa0:  00000000   00000000   00000000   00000000 
623 # 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec 
624 # 0 a: bdffffc0:  0900012a   bdffffd0   00000020   090000d1 
625 # 0 a: bdffffd0: [xxxxxxxx]  00000000   00000000   00000000 
626 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000 
627 # 0 a: bdfffff0:  00000000   fcfdfeff   00000001   bf000000 
628 
629 # actual state:
630 # 0 a: bdffff90:  00000000   00000000   00000000   00000000
631 # 0 a: bdffffa0:  00000000   00000000   00000000   00000000
632 # 0 a: bdffffb0:  00000000   00000000   00000000   bdffffec
633 # 0 a: bdffffc0:  0900012f   bdffffd0   00000024   090000d1
634 # 0 a: bdffffd0: [00000000]  00000000   00000000   00000000
635 # 0 a: bdffffe0:  00000000   00000000   00000000   00000000
636 # 0 a: bdfffff0:  00000000   fcfdfeff   00000001   bf000000