Actually that is possible too, if you do it like this:
function DoSomething(a as integer, b as float) : ref b
inc b, a
endfunction
The "ref" command would modify the return address of the function to call your DLL, which would copy the value of "b" to the argument used by the caller.
"ref" would also be a perfect use for a variadic command
Also, I've been doing some research into when array elements are used as parameters. In short, it's not nice. You can detect these cases very easily though, since the pattern will always end with "0F 85 ?? ?? ?? ?? 50"
Also, array indices are always stored in temporary variables ($D0, $D1, ...)
I was slightly surprised that DBPro doesn't let you pass a UDT array element as a parameter, but at least its a case that doesn't need to be taken into account...
edit:
Just realised a flaw in my logic: after the function returns, any strings will have been freed already. There are two ways I can think of solving this:
- Override the "?FreeSS@@YAKK@Z" function to check if you are about to return from a function and if so do any necessary copying.
- Override the "?EquateSS@@YAKKK@Z" function to do the copying and not bother with processing strings at the end of the function.
The first would be more consistent but the second seems less hacky.
edit2:
Also here's a new version of my disassembler which supports pretty much all the instructions DBPro uses:
set display mode desktop width(), desktop height(), 32
` Insert ASM code into getReturnAddress:
` 0x8B 0x45 0x04 mov eax, [ebp+4]
` 0xC3 ret
` (Bytes reversed to get correct endian-ness:)
poke dword get ptr to function("getReturnAddress"), 0xC304458B
` Insert ASM code into getReturnEBP:
` 0x8B 0x45 0x00 mov eax, [ebp+0]
` 0xC3 ret
` (Bytes reversed to get correct endian-ness:)
poke dword get ptr to function("getReturnEBP"), 0xC300458B
global blockSize
global blockPtr
global blockRel
blockSize = 283
type mytype
tmp
param1 as byte
param2 as byte
endtype
type mytype2
tmp
m as mytype
endtype
dim testvals(5) as mytype
for i = 0 to 5
testvals(i).param1 = i+1
next i
`m.m.param1 = 1
`m.m.param2 = 2
`m.param3 = 3
`m.param4 = 4
`m.param5 = 5
`m.param6 = 6
`runtest()
test(testvals(0), testvals(1))
test(testvals(2), testvals(3))
test(testvals(4), testvals(5))
disasm()
sync : sync
wait key
end
function runtest()
m as mytype2
m1 as mytype2
m2 as mytype2
m.m.param1 = 1
m.m.param2 = 2
test(m2.m.param1, m2.m.param1)
test(m1.m.param1, m1.m.param1)
test(m.m.param1, m.m.param1)
endfunction
function disasm()
r16 = 0
datasize = 0
x = 0
for i = 0 to blockSize-1
if datasize
ink 0xFF8080FF, 0
print peekHex(i, 1) + " ";
ink 0xFFFFFFFF, 0
dec datasize
if datasize = 0
print ""
y = get cursor y()
if y > screen height()-50
inc x, 500
set cursor x, 0
else
set cursor x, y
endif
endif
else
if peek byte(blockPtr+blockSize+i)
print peekHex(i, 1)
y = get cursor y()
if y > screen height()-50
inc x, 500
set cursor x, 0
else
set cursor x, y
endif
else
v = peek byte(blockPtr+i)
if v = 0x66
r16 = 1
ink 0xFFC06020, 0
print peekHex(i, 1);
ink 0xFFFFFFFF, 0
else
print peekHex(i, 1);
if r16
rsize = 2
else
rsize = 4
endif
if v = 0x0F
`Two byte instructions
inc i
print " " + peekHex(i, 1);
if peek byte(blockPtr+blockSize+i) = 0
v = peek byte(blockPtr+i)
if v >= 0x80 and v < 0x90
select v
case 0x80 : printOp(6, "jo") : endcase
case 0x81 : printOp(6, "jno") : endcase
case 0x82 : printOp(6, "jc") : endcase
case 0x83 : printOp(6, "jnc") : endcase
case 0x84 : printOp(6, "jz") : endcase
case 0x85 : printOp(6, "jnz") : endcase
case 0x86 : printOp(6, "jna") : endcase
case 0x87 : printOp(6, "ja") : endcase
case 0x88 : printOp(6, "js") : endcase
case 0x89 : printOp(6, "jns") : endcase
case 0x8A : printOp(6, "jp") : endcase
case 0x8B : printOp(6, "jnp") : endcase
case 0x8C : printOp(6, "jl") : endcase
case 0x8D : printOp(6, "jnl") : endcase
case 0x8E : printOp(6, "jng") : endcase
case 0x8F : printOp(6, "jg") : endcase
endselect
printHex(i+1, rsize) : datasize = rsize
printAddressName(i+1, rsize, 1)
else
endif
endif
else
if v >= 0xB8 and v < 0xC0
printOp(3, "mov")
r = v-0xB8
printReg2(r, r16)
printComma()
printHex(i+1, rsize) : datasize = rsize
else
if v >= 0x50 and v < 0x60
if v < 0x58
printOp(3, "push")
r = v-0x50
else
printOp(3, "pop")
r = v-0x58
endif
printReg2(r, r16)
else
if v = 0xE8
printOp(3, "call")
printHex(i+1, 4) : datasize = 4
printAddressName(i+1, 4, 1)
else
if v = 0x3D
printOp(3, "cmp")
printReg2(0, r16)
printComma()
printHex(i+1, rsize) : datasize = rsize
else
if v = 0x05 or v = 0x2D
if v = 0x05
printOp(3, "add")
else
printOp(3, "sub")
endif
printReg2(0, r16)
printComma()
printHex(i+1, rsize) : datasize = rsize
else
if v >= 0xA0 and v < 0xA4
printOp(3, "mov")
if v = 0xA0 then printRegL(0) : printComma()
if v = 0xA1 then printReg2(0, r16) : printComma()
print "[";
printHex(i+1, 4) : datasize = 4
print "]";
if v = 0xA2 then printComma() : printRegL(0)
if v = 0xA3 then printComma() : printReg2(0, r16)
if v = 0xA0 or v = 0xA2
printExample(i+1, 1, 0)
else
printExample(i+1, rsize, 0)
endif
else
if v >= 0x88 and v < 0x8C
printOp(3, "mov")
if v = 0x8A then printRegL(getModRmReg(i+1)) : printComma()
if v = 0x8B then printReg2(getModRmReg(i+1), r16) : printComma()
if v = 0x88 or v = 0x8A
datasize = printModRmL(i+1, 1)
else
datasize = printModRm2(i+1, 1, r16)
endif
if v = 0x88 then printComma() : printRegL(getModRmReg(i+1))
if v = 0x89 then printComma() : printReg2(getModRmReg(i+1), r16)
else
if v = 0xFF
v = getModRmReg(i+1)
select v
case 0
printOp(3, "inc") : datasize = printModRm2(i+1, 1, r16)
endcase
case 1
printOp(3, "dec") : datasize = printModRm2(i+1, 1, r16)
endcase
case 2
printOp(3, "call") : datasize = printModRm2(i+1, 0, r16)
endcase
case 3
printOp(3, "callf") : datasize = printModRm2(i+1, 0, r16)
endcase
case 4
printOp(3, "jmp") : datasize = printModRm2(i+1, 0, r16)
endcase
case 5
printOp(3, "jmpf") : datasize = printModRm2(i+1, 0, r16)
endcase
case 6
printOp(3, "push") : datasize = printModRm2(i+1, 1, r16)
endcase
endselect
else
if v = 0xDD
if peek byte(blockPtr+i+1) < 0xC0
v = getModRmReg(i+1)
select v
case 0
printOp(3, "fld") : datasize = printModRm(i+1, 1)
endcase
case 1
printOp(3, "fisttp") : datasize = printModRm(i+1, 1)
endcase
case 2
printOp(3, "fst") : datasize = printModRm(i+1, 1)
endcase
case 3
printOp(3, "fstp") : datasize = printModRm(i+1, 1)
endcase
case 4
printOp(3, "frstor") : datasize = printModRm(i+1, 1)
endcase
case 5
printOp(3, "fucomp") : datasize = printModRm(i+1, 1)
endcase
case 6
printOp(3, "fnsave") : datasize = printModRm(i+1, 1)
endcase
case 7
printOp(3, "fnsave") : datasize = printModRm(i+1, 1)
endcase
case 8
printOp(3, "fnstsw") : datasize = printModRm(i+1, 1)
endcase
endselect
else
endif
else
if v = 0xC6 or v = 0xC7
r = getModRmReg(i+1)
if r = 0
printOp(3, "mov")
if v = 0xC6
datasize = printModRmL(i+1, 1)
printComma()
printHex(i+datasize+1, 1) : inc datasize, 1
else
datasize = printModRm2(i+1, 1, r16)
printComma()
printHex(i+datasize+1, rsize) : inc datasize, rsize
endif
endif
else
if v = 0xE8 or v = 0xE9 or v = 0xEB
if v = 0xE8
printOp(3, "call")
else
printOp(3, "jmp")
endif
if v = 0xEB
printHex(i+1, 1) : datasize = 1
printAddressName(i+1, 1, 1)
else
printHex(i+1, rsize) : datasize = rsize
printAddressName(i+1, rsize, 1)
endif
else
if v >= 0x80 and v < 0x84
r = getModRmReg(i+1)
select r
case 0 : printOp(3, "add") : endcase
case 1 : printOp(3, "or") : endcase
case 2 : printOp(3, "adc") : endcase
case 3 : printOp(3, "sbb") : endcase
case 4 : printOp(3, "and") : endcase
case 5 : printOp(3, "sub") : endcase
case 6 : printOp(3, "xor") : endcase
case 7 : printOp(3, "cmp") : endcase
endselect
if v = 0x80 or v = 0x82
datasize = printModRmL(i+1, 1)
printComma()
printHex(i+datasize+1, 1) : inc datasize, 1
else
datasize = printModRm2(i+1, 1, r16)
printComma()
printHex(i+datasize+1, rsize) : inc datasize, rsize
endif
else
if v >= 0x38 and v < 0x3C
printOp(3, "cmp")
if v = 0x3A then printRegL(getModRmReg(i+1)) : printComma()
if v = 0x3B then printReg2(getModRmReg(i+1), r16) : printComma()
if v = 0x38 or v = 0x3A
datasize = printModRmL(i+1, 1)
else
datasize = printModRm2(i+1, 1, r16)
endif
if v = 0x38 then printComma() : printRegL(getModRmReg(i+1))
if v = 0x39 then printComma() : printReg2(getModRmReg(i+1), r16)
else
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
r16 = 0
endif
print ""
y = get cursor y()
if y > screen height()-50
inc x, 500
set cursor x, 0
else
set cursor x, y
endif
endif
endif
next i
endfunction
function printAddressName(offset, size, isrel)
select size
case 1
ptr = peek byte(blockPtr+offset)
if ptr >= 0x80 then ptr = ptr - 0x100
endcase
case 2
ptr = peek word(blockPtr+offset)
if ptr >= 0x8000 then ptr = ptr - 0x10000
endcase
case 4
ptr = peek integer(blockPtr+offset)
endcase
endselect
if isrel
ptr = ptr + size + blockPtr+blockRel+offset
endif
ink 0xFF0000FF, 0
n = get function count()
for i = 1 to n
fptr = get ptr to function(i)
if fptr > ptr
if i > 1
name$ = get function name$(i-1)
offset = ptr - get ptr to function(i-1)
print " (" + name$ + " + 0x" + hex$(offset) + ")";
else
print " (Main Program)";
endif
exit
endif
next i
ink 0xFFFFFFFF, 0
endfunction
function printExample(offset, size, rel)
ptr = peek integer(blockPtr+offset) + rel
ink 0xFF0000FF, 0
if is memory readable(ptr, size)
print " (0x";
for i = size-1 to 0 step -1
print toHex(peek byte(ptr+i), 2);
next i
print ")";
else
print " *invalid*";
endif
ink 0xFFFFFFFF, 0
endfunction
function printHex(offset, size)
print "0x" + peekHex(offset, size);
endfunction
function printComma()
ink 0xFF808080, 0
print ", ";
ink 0xFFFFFFFF, 0
endfunction
function printOp(indent, op$)
op$ = space$(max(16-indent, 1)) + op$ + space$(max(7-fast len(op$), 1))
ink 0xFFFF0000, 0
print op$;
ink 0xFFFFFFFF, 0
endfunction
function printReg(index)
ink 0xFFFFFF00, 0
print getReg(index);
ink 0xFFFFFFFF, 0
endfunction
function printReg2(index, r16)
ink 0xFFFFFF00, 0
print getReg2(index, r16);
ink 0xFFFFFFFF, 0
endfunction
function printRegX(index)
ink 0xFFFFFF00, 0
print getRegX(index);
ink 0xFFFFFFFF, 0
endfunction
function printRegL(index)
ink 0xFFFFFF00, 0
print getRegL(index);
ink 0xFFFFFFFF, 0
endfunction
function peekHex(offset, size)
result$ = ""
for i = 0 to size-1
if peek byte(blockPtr+blockSize+offset+i)
result$ = "??" + result$
else
result$ = toHex(peek byte(blockPtr+offset+i), 2) + result$
endif
next i
endfunction result$
function toHex(v, size)
v$ = hex$(v)
while fast len(v$) < size
v$ = "0" + v$
endwhile
endfunction v$
function printModRm(offset, deref)
result = printModRmS(offset, deref, 0, 0)
endfunction result
function printModRmL(offset, deref)
result = printModRmS(offset, deref, 1, 0)
endfunction result
function printModRm2(offset, deref, r16)
result = printModRmS(offset, deref, 0, r16)
endfunction result
function printModRmS(offset, deref, r8, r16)
datasize = 1
modrm = peek byte(blockPtr+offset)
mode = modrm >> 6
reg = modrm && 0x7
if mode = 3 and deref
deref = 0
else
r8 = 0
r16 = 0
endif
if deref then print "[";
if reg = 5 and mode = 0
printHex(offset+datasize, 4) : inc datasize,4
else
if reg = 4 and mode <> 3
sib = peek byte(blockPtr+offset+datasize) : inc datasize, 1
basereg = sib && 0x7
indexreg = (sib >> 3) && 0x7
scale = 1 << (sib >> 6)
if indexreg <> 4
if r8
printRegL(indexreg)
else
printReg2(indexreg, r16)
endif
if scale > 1 then print "*", scale;
print "+";
endif
if r8
printRegL(basereg)
else
printReg2(basereg, r16)
endif
else
if r8
printRegL(reg)
else
printReg2(reg, r16)
endif
endif
if mode = 1
print "+";
printHex(offset+datasize, 1) : inc datasize,1
else
if mode = 2
print "+";
printHex(offset+datasize, 4) : inc datasize,4
else
endif
endif
endif
if deref then print "]";
endfunction datasize
function getModRmReg(offset)
modrm = peek byte(blockPtr+offset)
reg = (modrm >> 3) && 0x7
endfunction reg
function getReg2(index, r16)
if r16
result$ = getRegX(index)
else
result$ = getReg(index)
endif
endfunction result$
function getReg(index)
result$ = ""
select index
case 0
result$ = "eax"
endcase
case 1
result$ = "ecx"
endcase
case 2
result$ = "edx"
endcase
case 3
result$ = "ebx"
endcase
case 4
result$ = "esp"
endcase
case 5
result$ = "ebp"
endcase
case 6
result$ = "esi"
endcase
case 7
result$ = "edi"
endcase
endselect
endfunction result$
function getRegX(index)
result$ = ""
select index
case 0
result$ = "ax"
endcase
case 1
result$ = "cx"
endcase
case 2
result$ = "dx"
endcase
case 3
result$ = "bx"
endcase
case 4
result$ = "sp"
endcase
case 5
result$ = "bp"
endcase
case 6
result$ = "si"
endcase
case 7
result$ = "di"
endcase
endselect
endfunction result$
function getRegL(index)
result$ = ""
select index
case 0
result$ = "al"
endcase
case 1
result$ = "cl"
endcase
case 2
result$ = "dl"
endcase
case 3
result$ = "bl"
endcase
case 4
result$ = "ah"
endcase
case 5
result$ = "ch"
endcase
case 6
result$ = "dh"
endcase
case 7
result$ = "bh"
endcase
endselect
endfunction result$
function test(a as mytype, b as mytype)
addr = getReturnAddress()
if blockPtr = 0
blockPtr = alloc zeroed(blockSize*2)
copy memory blockPtr, addr-blockSize, blockSize
blockRel = addr-blockSize-blockPtr
else
for i = 0 to blockSize-1
v1 = peek byte(addr+i-blockSize)
v2 = peek byte(blockPtr+i)
if v1 <> v2
poke byte blockPtr+blockSize+i, 1
endif
next i
endif
endfunction
` Will be replaced by ASM code at init time
function getReturnAddress()
endfunction result
` Will be replaced by ASM code at init time
function getReturnEBP()
endfunction result
[b]