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