Hello yet again! I'm having a bit of trouble and I'm not sure what's going on. I wrote my program in C++ to call an assembler routine to calculate and output all the prime numbers between two input values. But my problem occurs when I try to return to the main program in C++. The program just crashes. I think the problem is that I'm not preserving my registers but I'm unsure how to do that without breaking my program entirely. It finds all the prime numbers. It just crashes at ret. Here's the C++ code:
#include <iostream>
#include <ctime>
#include <cmath>
using namespace std;
extern "C"{
void IsPrime(long int begvalue, long int endvalue);
}
int main(void) {
long int start, end;
float dif;
long int begvalue = 3, endvalue = 10000;
start = clock(); //begin the clock
IsPrime(begvalue, endvalue); //reduce the time this call consumes
end = clock(); //end the clock
dif = (end - start)/(float) CLOCKS_PER_SEC;
cout << "Amount of time to evaluate the potential prime was = " << dif << " seconds" << endl;
}
And now here's the assembler code:
TITLE Prime Numbers (main.asm)
;finds prime numbers between two numbers
;outputs those primes
INCLUDE Irvine32.inc
IsPrime PROTO C
.data
end_Val DWORD ?
beg_Val DWORD ?
div_Val DWORD ?
.code
IsPrime PROC C
push ebp
mov ebp, esp
mov eax, [ebp + 12]
mov end_Val, eax
mov eax, [ebp + 8]
mov beg_Val, eax
A1:
;putting the next value in eax
mov eax, beg_Val
cmp eax, end_Val
je done
;starting counter and subtracting 2 from it.
mov ecx, eax
sub ecx, 2
;set up ebx to use div with
mov div_Val, 2
Calculate:
;Zero out the edx, remainder register
mov edx, 0;
;preserve my testing value
push eax
div div_Val
pop eax
inc div_Val
;Comparing the remainder to zero. number is prime
;if the remainder is zero. otherwise continue onto
;the next number.
cmp edx, 0
je non_prime
loop Calculate
call WriteDec
call Crlf
non_prime:
inc beg_Val
jmp A1
done:
ret
IsPrime ENDP
END
WriteDec just outputs to the console window whatever integer is in the eax register and Crlf just jumps to a new line. And I'm sure there's better ways to calculate prime numbers, but for the purposes of my class, this is fine.
Apologies if this is obvious :( I'm still new to this.
try
pushad
call WriteDec
call Crlf
popad
EDIT: Sorry, I had not read your code thoroughly. Michael's version will work.
Here is your asm source with minimal corrections:
TITLE Prime Numbers (main.asm)
;finds prime numbers between two numbers
;outputs those primes
INCLUDE Irvine32.inc
;--------------------------------------------------------------------
; No need for a PROTO here because the procedure is not invoked from
; this module. And if there were a need, the PROTO should match the
; procedure definition.
;--------------------------------------------------------------------
; IsPrime PROTO C
.data
;------------------------------------------------------------
; Instead of these we can just use the procedure parameters.
;------------------------------------------------------------
;end_Val DWORD ?
;beg_Val DWORD ?
div_Val DWORD ?
.code
;----------------------------------------------------------
; The procedure definition should match the cpp prototype.
;----------------------------------------------------------
IsPrime PROC C beg_Val:DWORD, end_Val:DWORD
;---------------------------------------------------------
; MASM provides the necessary prologue and epilogue code.
;---------------------------------------------------------
; push ebp
; mov ebp, esp
; mov eax, [ebp + 12]
; mov end_Val, eax
; mov eax, [ebp + 8]
; mov beg_Val, eax
A1:
;putting the next value in eax
mov eax, beg_Val
cmp eax, end_Val
je done
;starting counter and subtracting 2 from it.
mov ecx, eax
sub ecx, 2
;set up ebx to use div with
mov div_Val, 2
Calculate:
;Zero out the edx, remainder register
mov edx, 0;
;preserve my testing value
push eax
div div_Val
pop eax
inc div_Val
;Comparing the remainder to zero. number is prime
;if the remainder is zero. otherwise continue onto
;the next number.
cmp edx, 0
je non_prime
loop Calculate
call WriteDec
call Crlf
non_prime:
inc beg_Val
jmp A1
done:
ret
IsPrime ENDP
END
If you must do it this way, a small improvement (but a big time difference):
You only need to check for division against 2, and then all odd numbers up to the square-root of the number to be checked, i.e. you can add 2 each time, since all primes (except 2) are odd.
Advanced: you only need to check division against each prime up to the square-root.
probably the reason it is crashing is:
the EBX, ESI, EDI, and EBP registers should be preserved
he is only preserving EBP
i am not sure about the C-compiler, but it may also require ECX and/or EDX be preserved
You only need to preserve EBX, ESI, EDI (EBP, ESP) across the call, if you don't use them they are implicitly preserved. There are early versions of Watcom C that did not preserve EBX (which is more of a Microsoft rule), Watcom also had register and stack parameter passing modes.
EAX, ECX, and EDX have no preservation requirements.
The subroutine fails to identify loop conditions where the value prior to "sub ecx,2" is ONE or TWO.
MichaelW's changes actually work perfectly. And I cut a second off the original C++ function. Thank you for the replies. I am very happy now :)
yes - notice how he was careful not to use EBX, ESI, or EDI
by not using them, you don't have to preserve them :bg
sometimes, you can write faster code by using one or more of these registers, though