News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Multiply Double by Integer

Started by wwisznie, June 09, 2009, 12:55:00 PM

Previous topic - Next topic

wwisznie

Greetings Everybody!

I am working on a code that receives a double and an int from a c program.  It then is supposed to multiply the two and return a 64 bit floating point result.  I am successfully to receive high part of double to EAX and low part to EBX.  I put the int into ECX.  Now, I am stuck as to how to proceed :'(  Any help would be greatly appreciated.  Below is my code so far:

section       .text
global      _multiply

_multiply:
   push      ebp      ; save program status
   mov      ebp,esp    ;
   push      ebx      ;
   push      esi      ;
   push      edi      ;
   mov      ebx,[ebp+8]   ; low part of double
   mov      eax,[ebp+12]   ; high part of double
   mov      ecx,[ebp+16]   ; integer



   ;mov      edi,eax    ; get sign of double
   ;test      ecx,ecx    ;
   ;jns      intpositive   ; integer is positive
   ;xor      edi,ecx    ; multiply signs

dedndave


        movzx eax,(word or byte)

will zero-extend the word or byte into the eax register (for unsigned values)

        movsx eax,(word or byte)

will sign-extend the word or byte into the eax register (for signed values)

the high dword of the result after mul or imul winds up in edx, the low dword winds up in eax

i like to use xchg, as it is a one byte opcode when used with eax

        xchg eax,ebx
        xchg eax,edx

thing is - what was in ebx is now in edx

if that's a problem, use this

        mov ebx,eax
        mov eax,edx

qWord

hi,


fild DWORD ptr [ebp+16] ; load integer
fmul REAL8 ptr [ebp+8] ;mul by double
fstp REAL8 ptr [r32] ;pointer to dest.

; or in registers:
;fstp REAL8 ptr [esp-8]
;mov eax,DWORD ptr [esp-8] ;low-dword
;mov edx,DWORD ptr [esp-4] ;high-dword


regards, qWord
FPU in a trice: SmplMath
It's that simple!

dedndave

ah yes - i missed the word "float" - lol

wwisznie

Thank you dedndave and qWord both for your input.  You guys are lightning quick  :U  I ended up using qWord's advise.  Now the program is working correctly.  Since I compiled it under NASM, I had to change two details from qWord's advise.  Here is the code in case anyone needs it in the future:

section       .text
global      _multiply

_multiply:
   push      ebp      ; save program status
   mov      ebp,esp    ;
   push      ebx      ;
   push      esi      ;
   push      edi      ;
   mov      ebx,[ebp+8]   ; low part of double
   mov      eax,[ebp+12]   ; high part of double
   mov      ecx,[ebp+16]   ; integer

   fldz                    ; initialize
   fild DWORD [ebp+16] ; load integer
   fmul qword [ebp+8] ;mul by double
   fstp qword [ebp+20] ;pointer to dest

   
   fld      qword[ebp+20]   ; store in fp register
   add      esp,8      ; free place on stack
   pop      esi      ; restore program status
   pop      ebx      ;
   mov      esp,ebp    ;
   pop      ebp      ;
   ret            ;


;============================================================
;============================================================
; and here is the corresponding c source

#include <stdio.h>

double multiply ( double a , int b ) ;

int main ( int argc , char * argv [] )
  {
  double a ;
  int b ;

  printf ( "Enter a number (double):  " ) ;
  scanf ( "%lf" , &a ) ;
  printf ( "Enter a number (int):  " ) ;
  scanf ( "%d" , &b ) ;
  printf ( "%lf * %d = %lf\n" , a , b , multiply ( a , b ) ) ;
  scanf( "%d", &b);  // suprefluous read to make cmd window stay open
  return 0 ;
  }




raymond

A few comments.

i) The "fldz" instruction is totally useless in this context.

ii) Storing the result of the multiplication on the stack and reloading it in the same FPU register is also totally useless in this context.

iii) You preserve ebx, esi and edi (even though you are not even using esi nor edi within that procedure). However, you only restore esi and ebx before exiting the procedure. That would cause a stack imbalance and the proper return address from the procedure would not be loaded in the EIP register most probably causing the program to crash.

iv) Storing some value from the FPU onto the stack does NOT modify the ESP register. I'm surprised your program didn't crash on exit from the procedure by modifying the ESP register like you did (i.e. add esp,8) which would overcompensate for the 4 bytes you forgot to pop off.

Those are some of the details of assembly! :dazzled: :eek
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Mirno

As Raymond points out you do some strange things...

Setting up a stack frame is not necessary, given you push and pop nothing, don't use locals, or make any function calls.

You push ebx, esi, and edi, but pop them back out to different registers (new esi = old edi, new ebx = old esi, old ebx left on the stack).

You store things to registers, which you never use.

fldz does nothing for you here.

You store your result to some memory, then re-load it.

You add 8 to esp, then overwrite esp with ebp - hence the add does nothing.

You should be wary that the function declaration is using the C calling convention, if it was not then you would need to use "ret 12" rather than plain ret. I would comment it as such.

Your code should work using the following:

_multiply:
    fild DWORD [esp + 16]  ; Load the integer "b"
    fmul REAL8 [esp +  8]  ; Load the double "a"
    ret                    ; Use ret 12 if using stdcall


Thanks,

Mirno