6123 - runtime helper for initializing arrays
I built this in 3 phases: a) create a helper in the bootstrap VM to render the state of the stack. b) interactively arrive at the right function (tools/stack_array.subx) c) pull the final solution into the standard library (093stack_allocate.subx) As the final layer says, this may not be the fastest approach for most (or indeed any) Mu programs. Perhaps it's better on balance for the compiler to just emit n/4 `push` instructions. (I'm sure this solution can be optimized further.)
This commit is contained in:
parent
bfb7c60135
commit
28746b3666
26
039debug.cc
26
039debug.cc
|
@ -93,6 +93,32 @@ if (!Watch_this_effective_address.empty()) {
|
|||
put(Watch_points, Watch_this_effective_address, addr);
|
||||
}
|
||||
|
||||
//: If a label starts with '$dump-stack', dump out to the trace n bytes on
|
||||
//: either side of ESP.
|
||||
|
||||
:(after "Run One Instruction")
|
||||
if (contains_key(Symbol_name, EIP) && starts_with(get(Symbol_name, EIP), "$dump-stack")) {
|
||||
dump_stack(64);
|
||||
}
|
||||
:(code)
|
||||
void dump_stack(int n) {
|
||||
uint32_t stack_pointer = Reg[ESP].u;
|
||||
uint32_t start = ((stack_pointer-n)&0xfffffff0);
|
||||
dbg << "stack:" << end();
|
||||
for (uint32_t addr = start; addr < start+n*2; addr+=16) {
|
||||
if (addr >= AFTER_STACK) break;
|
||||
ostringstream out;
|
||||
out << HEXWORD << addr << ":";
|
||||
for (int i = 0; i < 16; i+=4) {
|
||||
out << ' ';
|
||||
out << ((addr+i == stack_pointer) ? '[' : ' ');
|
||||
out << HEXWORD << read_mem_u32(addr+i);
|
||||
out << ((addr+i == stack_pointer) ? ']' : ' ');
|
||||
}
|
||||
dbg << out.str() << end();
|
||||
}
|
||||
}
|
||||
|
||||
//: Special label that dumps regions of memory.
|
||||
//: Not a general mechanism; by the time you get here you're willing to hack
|
||||
//: on the emulator.
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# A function which pushes n zeros on the stack.
|
||||
# Not really useful to call manually.
|
||||
# The Mu compiler uses it when defining arrays on the stack.
|
||||
|
||||
== code
|
||||
|
||||
#? Entry:
|
||||
#? # . prologue
|
||||
#? 89/<- %ebp 4/r32/esp
|
||||
#? #
|
||||
#? 68/push 0xfcfdfeff/imm32
|
||||
#? b8/copy-to-eax 0x34353637/imm32
|
||||
#? $dump-stack0:
|
||||
#? (push-n-zero-bytes 4)
|
||||
#? 68/push 0x20/imm32
|
||||
#? $dump-stack9:
|
||||
#? b8/copy-to-eax 1/imm32/exit
|
||||
#? cd/syscall 0x80/imm8
|
||||
|
||||
# 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.
|
||||
|
||||
# Overhead:
|
||||
# 62 + n*6 instructions to push n bytes.
|
||||
# If we just emitted code to push n zeroes, it would be:
|
||||
# 5 bytes for 4 zero bytes, so 1.25 bytes per zero. And that's not even
|
||||
# instructions.
|
||||
# But on the other hand it would destroy the instruction cache, where this
|
||||
# approach requires 15 instructions, fixed.
|
||||
|
||||
# n must be positive
|
||||
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:
|
||||
# -- esp = ebp
|
||||
50/push-eax
|
||||
# -- 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:bulk-cleaning:
|
||||
89/<- *Push-n-zero-bytes-esp 4/r32/esp
|
||||
81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
|
||||
81 0/subop/add *(ebp+4) 4/imm32
|
||||
(zero-out *Push-n-zero-bytes-esp *(ebp+4)) # n+4
|
||||
$push-n-zero-bytes:epilogue:
|
||||
8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp # restore spill
|
||||
c3/return
|
||||
|
||||
== data
|
||||
Push-n-zero-bytes-ebp: # (addr int)
|
||||
0/imm32
|
||||
Push-n-zero-bytes-esp: # (addr int)
|
||||
0/imm32
|
|
@ -0,0 +1,636 @@
|
|||
== 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 init.linux tools/stack_array.subx && 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
|
Loading…
Reference in New Issue