0

Here are my questions,

  1. How do I store the remainder from edx back at the memory address of the third parameter?
  2. Do I need to use a subroutine in order to do so?
  3. What is the most efficient way to do so?

If you could show the correct code for this or a detailed explanation of how to that would be great. If you could show a combination of the two that would be excellent.

Here is my .asm file:

.386

.model flat

public _Divide

.code

_Divide proc

        push ebp
        mov ebp, esp
        mov eax, [ebp + 8]
        mov ebx, [ebp + 12]
        cwd
        idiv ebx
        mov ecx, [ebp + 16]
        cmp ecx, 0
        jne remainder
        jmp done
remainder:
        mov [ebp + 16], edx   ;this is showing as the minimum value for a 
                              ;long in the cpp(-860,000,000)
done:
        pop ebp
        ret
_Divide endp

        end

Here is the .cpp file from which I am calling the _Division function:

#include <iostream>

using namespace std;

extern "C" long Divide (long, long, long *);

void main ()
{
long    Result;
long    Remainder;
long    Dividend;
long    Divisor;

do
    {
    cout << "Enter Dividend" << endl; 
    cin >> Dividend;
    cout << "Enter Divisor" << endl;
    cin >> Divisor;

    Result = Divide (Dividend, Divisor, &Remainder);
    cout << "Result is " << Result << " and Remainder is " << Remainder << endl;
    } while ((Result >= 0) || (Remainder != 0));

Result = Divide (Dividend, Divisor, 0);
cout << "Result is " << Result << " and Remainder is not used" << endl;
}
Sparky10
  • 44
  • 1
  • 7
  • You're storing the remainder at `[ebp + 16]`, not at the address contained in `[ebp + 16]`. You've got the address in `ecx`, just store it there - `mov [ecx], edx`. – Frank Kotler Mar 18 '14 at 04:42

1 Answers1

4

Your assembler code has some bugs:

  • It clobbers EBX which is a saved register (i.e. should retain content across function calls) in the x86 ABI.
  • You should be using cdq (double to quad word) to sign extend EAX into EDX:EAX instead of cwd (word to double word) to sign extend AX into DX:AX.
  • For the Remainder out parameter, you were not storing to the location it pointed to.

This code should work:

div.asm

.386
.model flat

.code
public _Divide
_Divide proc
    push ebp
    mov ebp, esp
    push ebx
    mov eax, [ebp + 8]
    mov ebx, [ebp + 12]
    cdq
    idiv ebx
    mov ecx, [ebp + 16]
    cmp ecx, 0
    je return
    mov [ecx], edx
return:
    pop ebx
    pop ebp
    ret
_Divide endp
    end

and if we take Jester's suggestion to use a memory operand with idiv to reduce our register use, the code becomes:

_Divide:
    push ebp
    mov ebp, esp
    mov eax, [ebp + 8]
    cdq
    idiv DWORD [ebp + 12]
    mov ecx, [ebp + 16]
    cmp ecx, 0
    je return
    mov [ecx], edx
return:
    pop ebp
    ret
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
scottt
  • 7,008
  • 27
  • 37
  • @Sparky10: Also, `idiv` can take a memory operand, so no need to load the divisor into a register; but if you do, you can use `ecx` so `ebx` doesn't need to be saved. – Jester Mar 18 '14 at 11:43
  • excellent advice @scottt, jester and frank. Thank you all for the clarification I truly appreciate it. – Sparky10 Mar 19 '14 at 04:56
  • [`test ecx,ecx` is slightly more efficient than `cmp ecx,0`, and sets flags exactly the same.](https://stackoverflow.com/questions/33721204/test-whether-a-register-is-zero-with-cmp-reg-0-vs-or-reg-reg/33724806#33724806). And BTW, instead of saving/restoring `ebx`, you could have just loaded the divisor into `ecx` before reusing `ecx` for the pointer. – Peter Cordes Nov 19 '17 at 22:38