News:

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

having a crash issue

Started by magus841, May 10, 2010, 04:12:49 AM

Previous topic - Next topic

magus841

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.

jj2007

#1
try
pushad
    call WriteDec
    call Crlf
popad

EDIT: Sorry, I had not read your code thoroughly. Michael's version will work.

MichaelW

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
eschew obfuscation

Tedd

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.
No snowflake in an avalanche feels responsible.

dedndave

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

clive

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.
It could be a random act of randomness. Those happen a lot as well.

magus841

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 :)

dedndave

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