I have program on MASM32 which solve a simple piecewise-defined function. In pseudo-code it's:
if (a > b) x = 2 + b/a
else if (a == b) x = 25
else x = (a - 5)/b
I input a, b, h and n. In loop program makes n steps (a = a + h, x = ...) and writes result of piecewise to array. Now I must write function for print array. This is the code:
include \masm32\include\masm32rt.inc
.const
two dq 2.
five dq 5.
twfive dq 25.
enterA db "a: ", 0
enterB db "b: ", 0
enterH db "h: ", 0
enterN db "n: ", 0
InputFormat db "%lf", 0
InputNFormat db "%d", 0
OutputFormat db "%f", 10, 0
OutputFormatD db "%d", 10, 0
.data
.data?
a dq ?
b dq ?
h dq ?
n dd ?
tmp dq ?
l dd 0
arr dq 50 dup(0)
.code
main proc
FINIT ; init of coprocessor
invoke crt_printf, addr enterA
invoke crt_scanf, addr InputFormat, addr a
invoke crt_printf, addr enterB
invoke crt_scanf, addr InputFormat, addr b
invoke crt_printf, addr enterH
invoke crt_scanf, addr InputFormat, addr h
invoke crt_printf, addr enterN
invoke crt_scanf, addr InputNFormat, addr n
MOV ECX, n ; ECX = n = number of loop repetition
MOV EDI, 0 ; EDI = 0
FLD a ; ST(0) = a
cycle:
FCOM b ; compare a and b, result in SWR
; C2 = 1 => incomparable
; C0 = 1 => a < b
; C3 = 1 => a = b
; else => a > b
FSTSW AX ; SWR to AX
SAHF ; ZF = C3, PF = C2, CF = C0
JP incomparable
JC less
JZ equal
;else a > b:
FLD b ; ST(0) = b, ST(1) = a
FDIVR ; ST(0) = b / a
FADD two ; ST(0) = 2 + b / a
JMP endc
incomparable:
;
less:
FSUB five ; ST(0) = a - 5
FDIV b ; ST(0) = (a - 5) / b
JMP endc
equal:
FSTP tmp ; ST is empty
FLD twfive ; ST(0) = 25
JMP endc
endc:
FSTP arr[EDI]
ADD EDI, 8
ADD l, 1
FLD a ; ST(0) = a
FADD h ; ST(0) = a + h
FST a ; a = ST(0)
LOOP cycle
; all code above works perfect
; sodom and gomorrah will be here
inkey
invoke ExitProcess, NULL
main endp
end main
So, first I was trying write a function but I had problems with passing parameters to it. I've decided to try put offset to register, push to stack, then pop it and print (at least) a first element of array. But I get many mistakes.
MOV EDI, offset arr ; move offset of array to EDI
XOR ECX, ECX ; clear ECX (but not increment yet)
PUSH QWORD [EDI + ECX * 8] ; found this solution (but with dword, not qword)
POP QWORD [tmp] ; on stackoverflow, but it is not working :c
invoke crt_printf, addr OutputFormat, tmp
Then I tried to replace push/pop operations to mov :
MOV [tmp], [EDI + ECX * 4]
Nothing. And I can't use only registers because I use DQ (afaik registers are 32-bit, DQ — 64-bit).
I tried a lot of ways (for example FLD/FSTP), but I have only build-errors or incorrect output. Could you tell me the correct solution?
PUSH/POP r/m64
isn't valid in 32-bit mode (even if it had been, the correct MASM syntax would've been QWORD PTR [...
rather than just QWORD [...
).
But there are other ways to move your data:
You could use two PUSH DWORD PTR
instructions that each push half of the data, and then two POP DWORD PTR
instructions to pop the data into place.
You could use the MOVQ
instruction to transfer the data through an MMX register (you'll need to add the .mmx
directive to the beginning of your assembly file for this to assemble):
movq mm0,[EDI + ECX * 8]
movq [tmp],mm0
emms
You could move the data using the FPU:
fld QWORD PTR [EDI + ECX * 8]
fstp QWORD PTR [tmp]