Prev: DynatOS 64-bit is here!!!
Next: Slow nasm
From: kuroikaze on 22 Oct 2007 20:22 So yeah I've written this program and I haven't been able to figure out what I did wrong (aside from the completely insane code written by a total amateur). I really wish this was Java, as I would have been done in 10 minutes. Anyway so the assignment is to enter a 4-digit integer and determine whether or not it is prime. Then I am to find the prime numbers on either side of it. So if one put in 23 I should be able to find 19 and 29 (I think those are the closest primes). I keep getting "integer overflows" according to windbg even when I tried converting everything to EAX and DWORDS. This is due Tuesday afternoon (it's Monday night of course!) so hopefully someone has an idea what I did wrong. Thanks! ..386 ..MODEL FLAT ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD INCLUDE io.h ;header file for input/output cr EQU 0dh ;carriage return character Lf EQU 0ah ;line feed ..STACK 4096 ;reserve 4096-byte stack ..DATA ;reserve storage for data prompt1 BYTE "Please enter a four digit integer: ", 0 prompt2 BYTE cr, Lf, " is not a prime number.", 0 prompt3 BYTE cr, Lf, " is a prime number.", 0 prompt4 BYTE cr, Lf, "Largest prime number smaller than ", 0 prompt5 BYTE cr, Lf, "Smallest prime number larger than ", 0 string BYTE 11 DUP (?) orig WORD ? lower WORD ? higher WORD ? ..CODE _start: mov bx, 2 output prompt1 input string, 6 atoi string ; put input in ax mov orig, ax ; copy ax to orig origtest: cmp bx, ax ; subtract input from bx je origprime ; if input and bx are = then jump cwd ; convert to word div bx ; divide ax by bx cmp dx, 0 ; sub ax minus 0 je orignotprime ; if 0 and dx are = then jump inc bx ; increment bx register jmp origtest ; restart loop lowerloop: sub ax, 1 jmp lowerprimetest lowerprimetest: cmp bx, ax je lowerprime cwd div bx cmp dx, 0 je lowerloop inc bx jmp lowerprimetest lowerprime: mov lower, ax jmp highestloop highestloop: add ax, 1 jmp higherprimetest higherprimetest: cmp bx, ax je higherprime cwd div bx cmp dx, 0 je highestloop inc bx jmp higherprimetest higherprime: mov higher, ax jmp finalout origprime: mov bx, 2 mov ax, orig itoa string, ax ; Convert ax to Ascii output string ; Output: ax output prompt2 ; is a prime number jmp lowerloop orignotprime: mov bx, 2 mov ax, orig itoa string, ax output string output prompt3 ; is not a prime number jmp lowerloop finalout: output prompt4 ; Largest number smaller than mov ax, lower itoa string, ax output string output prompt5 ; Smallest number greather than mov ax, higher itoa string, ax output string INVOKE ExitProcess, 0 PUBLIC _start END
From: Frank Kotler on 22 Oct 2007 22:54 kuroikaze(a)gmail.com wrote: .... > Anyway so the assignment is to enter a 4-digit integer .... which would eliminate certain overflows. But in your code, you seem to allow six... > I keep getting "integer overflows" according to windbg even when I > tried converting everything to EAX and DWORDS. Probably a "divide overflow" - quotient won't fit in ax. I reacll some machine I had which reported this error as "divide by zero" (no I didn't!). Linux (my current version) calls it a "floating point error" (what floating point???). Converting to 32-bit registers and "dd" probably won't help. (I'd do it anyway - doing 16-bit ops in 32-bit code bloats your code with 66h "operation size override prefixes") > This is due Tuesday afternoon (it's Monday night of course!) so > hopefully someone has an idea what I did wrong. Didn't start sooner? :) > Thanks! > > > .386 > .MODEL FLAT > > ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD > INCLUDE io.h ;header file for input/output Without this, we can't try your code. Since you're in a hurry, I'll take a wild guess or two anyway... > cr EQU 0dh ;carriage return character > Lf EQU 0ah ;line feed > > .STACK 4096 ;reserve 4096-byte stack > .DATA ;reserve storage for data > > prompt1 BYTE "Please enter a four digit integer: ", 0 > prompt2 BYTE cr, Lf, " is not a prime number.", 0 > prompt3 BYTE cr, Lf, " is a prime number.", 0 > prompt4 BYTE cr, Lf, "Largest prime number smaller than ", 0 > prompt5 BYTE cr, Lf, "Smallest prime number larger than ", 0 > string BYTE 11 DUP (?) > orig WORD ? > lower WORD ? > higher WORD ? > > > .CODE > _start: > > mov bx, 2 > output prompt1 > input string, 6 > atoi string ; put input in ax What's this return in case of error? -1? (hope not!) > mov orig, ax ; copy ax to orig > > origtest: Since ax gets altered by the "div" in this loop, you probably want to reload it each time through. mov ax, orig > cmp bx, ax ; subtract input from bx > je origprime ; if input and bx are = then jump > cwd ; convert to word > div bx ; divide ax by bx The "cwd" will zero dx... *provided* ax is non-negative. Four digits would eliminate this possibility, but with six... ax could get "so big it's negative". If you intend to handle negative inputs, use "idiv", else use "xor dx, dx" instead. (the CPU doesn't know if an integer is "signed" or "unsigned" - depends on what instructions you use - and "cwd" works on signed values) > cmp dx, 0 ; sub ax minus 0 > je orignotprime ; if 0 and dx are = then jump > inc bx ; increment bx register > jmp origtest ; restart loop > > lowerloop: > > sub ax, 1 ax is no longer "orig"! > jmp lowerprimetest > > lowerprimetest: > > cmp bx, ax What's in bx at this point? I assume you intend to restart with 2. > je lowerprime > cwd > div bx Again, the "cwd" is "risky", and ax is altered. In this case, we don't want to reload ax from "orig" - push/pop ax around the "div"? > cmp dx, 0 > je lowerloop > inc bx > jmp lowerprimetest > > lowerprime: > > mov lower, ax > jmp highestloop > > highestloop: > > add ax, 1 What's ax now? Still "lower"? > jmp higherprimetest > > higherprimetest: > > cmp bx, ax > je higherprime > cwd > div bx Again... > cmp dx, 0 > je highestloop > inc bx > jmp higherprimetest > > higherprime: > > mov higher, ax > jmp finalout > > origprime: > > mov bx, 2 ??? > mov ax, orig > itoa string, ax ; Convert ax to Ascii > output string ; Output: ax > output prompt2 ; is a prime number > jmp lowerloop > > orignotprime: > > mov bx, 2 ??? > mov ax, orig > itoa string, ax > output string > output prompt3 ; is not a prime number > jmp lowerloop > > finalout: > > output prompt4 ; Largest number smaller than > mov ax, lower > itoa string, ax > output string > output prompt5 ; Smallest number greather than > mov ax, higher > itoa string, ax > output string > > > INVOKE ExitProcess, 0 > > PUBLIC _start > > END Run it again in windbg, paying attention to *where* the "divide overflow" occurs, and watch (e)dx. If it's => (e)bx, there's the problem (result won't fit in (e)ax). On thinking about it, my "push ax/pop ax around the div" isn't going to work well. You've got three nearly identical "isprime" routines. You know how to do a subroutine? You'll never learn any younger, and it may simplify this problem. Lemme play with this and get back to you... Best, Frank
From: kuroikaze on 22 Oct 2007 23:37 > ... which would eliminate certain overflows. But in your code, you seem > to allow six... Suggestions to correct? > Didn't start sooner? :) I was out of town and worked on this all night Sunday and afterwork Monday. I'm trying! > > What's this return in case of error? -1? (hope not!) > > > mov orig, ax ; copy ax to orig > > > origtest: > > Since ax gets altered by the "div" in this loop, you probably want to > reload it each time through. ....doh! I forgot EAX gets changed by the div command. I would need to reload from orig before incrementing it! It's possible my overflow errors stem from here. > mov ax, orig > > > cmp bx, ax ; subtract input from bx > > je origprime ; if input and bx are = then jump > > cwd ; convert to word > > div bx ; divide ax by bx > > The "cwd" will zero dx... *provided* ax is non-negative. Four digits > would eliminate this possibility, but with six... ax could get "so big > it's negative". If you intend to handle negative inputs, use "idiv", > else use "xor dx, dx" instead. (the CPU doesn't know if an integer is > "signed" or "unsigned" - depends on what instructions you use - and > "cwd" works on signed values) Basically I did a find/replace converting everything to eax/ebx/edx. Words became DWords etc. Also I put a xor dx,dx before my cwd's cause I didn't know what xor did, but I'll got in there and delete all the cwd's. > What's in bx at this point? I assume you intend to restart with 2. Yeah..actually I should make sure to include that. > Lemme play with this and get back to you... > > Best, > Frank i don't know what push/pop means and since this is assignment 3 in Assembly 1 I basically know nothing of subroutines or anything else. i feel this assignment is much too hard compared to the first two and everyone is struggling with it. anyway i completely forgot about the io include but all that does is convert things to ascii with the Ascii to Double (atod) Double to Ascii (dtoa) kinda stuff. it's provided by my textbook so there's no problem inside of it. just in case i'll open it in notepad and post it below: ; IO.H -- header file for I/O macros ; 32-bit version for flat memory model ; R. Detmer last revised 8/2000 ..NOLIST ; turn off listing ..386 EXTRN itoaproc:near32, atoiproc:near32 EXTRN dtoaproc:near32, atodproc:near32 EXTRN inproc:near32, outproc:near32 itoa MACRO dest,source,xtra ;; convert integer to ASCII string IFB <source> .ERR <missing operand(s) in ITOA> EXITM ENDIF IFNB <xtra> .ERR <extra operand(s) in ITOA> EXITM ENDIF push ebx ;; save EBX mov bx, source push bx ;; source parameter lea ebx,dest ;; destination address push ebx ;; destination parameter call itoaproc ;; call itoaproc(source,dest) pop ebx ;; restore EBX ENDM atoi MACRO source,xtra ;; convert ASCII string to integer in AX ;; offset of terminating character in ESI IFB <source> .ERR <missing operand in ATOI> EXITM ENDIF IFNB <xtra> .ERR <extra operand(s) in ATOI> EXITM ENDIF push ebx ;; save EBX lea ebx,source ;; source address to EBX push ebx ;; source parameter on stack call atoiproc ;; call atoiproc(source) pop ebx ;; parameter removed by ret ENDM dtoa MACRO dest,source,xtra ;; convert double to ASCII string IFB <source> .ERR <missing operand(s) in DTOA> EXITM ENDIF IFNB <xtra> .ERR <extra operand(s) in DTOA> EXITM ENDIF push ebx ;; save EBX mov ebx, source push ebx ;; source parameter lea ebx,dest ;; destination address push ebx ;; destination parameter call dtoaproc ;; call dtoaproc(source,dest) pop ebx ;; restore EBX ENDM atod MACRO source,xtra ;; convert ASCII string to integer in EAX ;; offset of terminating character in ESI IFB <source> .ERR <missing operand in ATOD> EXITM ENDIF IFNB <xtra> .ERR <extra operand(s) in ATOD> EXITM ENDIF lea eax,source ;; source address to EAX push eax ;; source parameter on stack call atodproc ;; call atodproc(source) ;; parameter removed by ret ENDM output MACRO string,xtra ;; display string IFB <string> .ERR <missing operand in OUTPUT> EXITM ENDIF IFNB <xtra> .ERR <extra operand(s) in OUTPUT> EXITM ENDIF push eax ;; save EAX lea eax,string ;; string address push eax ;; string parameter on stack call outproc ;; call outproc(string) pop eax ;; restore EAX ENDM input MACRO dest,length,xtra ;; read string from keyboard IFB <length> .ERR <missing operand(s) in INPUT> EXITM ENDIF IFNB <xtra> .ERR <extra operand(s) in INPUT> EXITM ENDIF push ebx ;; save EBX lea ebx,dest ;; destination address push ebx ;; dest parameter on stack mov ebx,length ;; length of buffer push ebx ;; length parameter on stack call inproc ;; call inproc(dest,length) pop ebx ;; restore EBX ENDM ..NOLISTMACRO ; suppress macro expansion listings ..LIST ; begin listing
From: Frank Kotler on 23 Oct 2007 12:51 kuroikaze(a)gmail.com wrote: [snip] > Wow that's a lot to digest. I'll be looking it over and working on > the assignment all day. Here's a second shot at it - completely untested, I've probably missed a few (?) things. I've tried to use instructions you already know (?). You might want to leave my "first shot" for later. > I appreciate your help and will probably turn here in the future > should I get another tough assignment. Okay... keep in touch and let us know how it's going. We never hear back about what kind of grade we got, and what (if any) comments were made about the assignment... what the expected "right answer" was... > The first two I completed in about 3-4 hours each. If you wanna get into an extensive discussion... what were they? What help *is* your course giving you, and what are they leaving out? Get the damn assignment assembling and running without crashing first - correct results would be nice. Plenty of time to discuss and improve it - and plenty of room for improvement! Best, Frank ..386 ..MODEL FLAT ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD INCLUDE io.h ;header file for input/output cr EQU 0dh ;carriage return character Lf EQU 0ah ;line feed ; .STACK 4096 ;reserve 4096-byte stack I don't think you need/want this for a PE file... ..DATA ;reserve storage for data prompt1 BYTE "Please enter a four digit integer: ", 0 prompt2 BYTE cr, Lf, " is not a prime number.", 0 prompt3 BYTE cr, Lf, " is a prime number.", 0 prompt4 BYTE cr, Lf, "Largest prime number smaller than ", 0 prompt5 BYTE cr, Lf, "Smallest prime number larger than ", 0 string BYTE 11 DUP (?) orig DWORD ? lower DWORD ? higher DWORD ? save_eax DWORD ? ..CODE _start: mov ebx, 2 output prompt1 input string, 6 atod string ; put input in eax mov orig, eax ; copy eax to orig origtest: cmp ebx, eax ; subtract input from bx je origprime ; if input and bx are = then jump ; cwd ; convert to word mov edx, 0 mov save_eax, eax div ebx ; divide ax by bx mov eax, save_eax cmp edx, 0 ; sub ax minus 0 je orignotprime ; if 0 and dx are = then jump inc ebx ; increment bx register jmp origtest ; restart loop lowerloopinit: mov ebx, 2 lowerloop: sub eax, 1 ; jmp lowerprimetest lowerprimetest: cmp ebx, eax je lowerprime ;cwd mov edx, 0 mov save_eax, eax div ebx mov eax, save_eax cmp edx, 0 je lowerloop inc ebx jmp lowerprimetest lowerprime: mov lower, eax ; jmp highestloop mov eax, orig mov ebx, 2 highestloop: add eax, 1 ; jmp higherprimetest higherprimetest: cmp ebx, eax je higherprime ; cwd mov edx, 0 mov save_eax, eax div ebx mov eax, save_eax cmp edx, 0 je highestloop inc ebx jmp higherprimetest higherprime: mov higher, eax jmp finalout origprime: ; mov bx, 2 mov eax, orig dtoa string, eax ; Convert ax to Ascii output string ; Output: ax output prompt2 ; is a prime number jmp lowerloopinit orignotprime: ; mov bx, 2 mov eax, orig dtoa string, eax output string output prompt3 ; is not a prime number jmp lowerloopinit finalout: output prompt4 ; Largest number smaller than mov eax, lower dtoa string, eax output string output prompt5 ; Smallest number greather than mov eax, higher dtoa string, eax output string INVOKE ExitProcess, 0 PUBLIC _start END
From: kuroikaze on 23 Oct 2007 13:25
Okay here's the re-written overflow-free error code. Unfortunately it doesn't work right. 1059 is my "control" test and the answers that should come out are not what come out of my program. When I put in 1059 I should get 1051 and 1061 are the two primes. Instead I get 1053 and 1060?!? ; JJ Sauram - Assignment 3 ; Date: 10/18/2007 ; Find Prime Numbers ..386 ..MODEL FLAT ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD INCLUDE io.h ;header file for input/output cr EQU 0dh ;carriage return character Lf EQU 0ah ;line feed ..STACK 4096 ;reserve 4096-byte stack ..DATA ;reserve storage for data prompt1 BYTE "Please enter a four digit integer: ", 0 prompt2 BYTE cr, Lf, " is not a prime number.", 0 prompt3 BYTE cr, Lf, " is a prime number.", 0 prompt4 BYTE cr, Lf, "Largest prime number smaller than ", 0 prompt5 BYTE cr, Lf, "Smallest prime number larger than ", 0 string BYTE 11 DUP (?) orig DWORD ? lower DWORD ? higher DWORD ? ..CODE _start: mov ebx, 2 output prompt1 input string, 6 atod string ; put input in eax mov orig, eax ; copy eax to orig mov ecx, eax origtest: cmp ebx, eax ; subtract input from ebx je origprime ; if input and ebx are = then jump XOR edx,edx ; zero out edx div ebx ; divide eax by ebx cmp edx, 0 ; sub eax minus 0 je orignotprime ; if 0 and edx are = then jump inc ebx ; increment ebx register mov eax, ecx ; put the original test back in eax jmp origtest ; restart loop lowerloop: sub ecx, 1 jmp lowerprimetest lowerprimetest: mov eax, ecx cmp ebx, eax je lowerprime XOR edx,edx div ebx cmp edx, 0 je lowerloop inc ebx jmp lowerprimetest lowerprime: mov lower, ecx mov ecx, orig jmp highestloop highestloop: add ecx, 1 jmp higherprimetest higherprimetest: mov eax, ecx cmp ebx, eax je higherprime XOR edx,edx div ebx cmp edx, 0 je highestloop inc ebx jmp higherprimetest higherprime: mov higher, ecx jmp finalout origprime: mov ebx, 2 dtoa string, ecx ; Convert ecx to Ascii output string ; Output: ecx output prompt2 ; is a prime number jmp lowerloop orignotprime: mov ebx, 2 dtoa string, ecx output string output prompt3 ; is not a prime number jmp lowerloop finalout: output prompt4 ; Largest number smaller than mov eax, lower dtoa string, eax output string output prompt5 ; Smallest number greather than mov eax, higher dtoa string, eax output string INVOKE ExitProcess, 0 PUBLIC _start END |