Well... I've only just assembled this and tried it with a couple of input sequences - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 and 9, 8, 7, 6, 5, 4, 3, 2, 1, 0. The good news is that the sort worked perfectly both times. The bad news is that it segfaulted both times. (apparently on "call Crlf", which seems strange!)
So... "the research continues", but let me point out a couple of things that "don't look right to me" before I get back (I hope) to trying to find the actual problem...
%include "Along32.inc"
section .data
max dd 0
maxIndex dd 0
prompt1 : db "Overflow error, must use less than 100 numbers.",0ah, 0
prompt2 : db "You must submit at least 1 number.",0ah, 0
size dd 0
section .bss
array resd 100;
section .code
global _start
_start: ; main program
push esp ;
This is apparently an attempt to assure that esp is going to be the same at the end of the program as at the beginning - but it isn't going to work. If the stack gets messed up, the value you pop into esp at the end isn't going to be the same value you pushed here! (that's probably why "call Crlf" appears to fail for me - but perhaps not for you)
mov ecx,0;
call readInts ;
This call never returns. Already the stack is messed up! It may not be obvious to a beginner that "call" (and "ret") use the stack at all, but they sure do!
"call" does something like this:
; call somefunc
; next_instruction:
push next_instruction
jmp somefunc
and when the CPU gets to "ret" in "somefunc" (we hope it does) it does:
; ret
pop return_address
jmp return_address
If all goes well, "return_address" is "next_instruction" and we continue right after the "call" ("somefunc" can be called from different places, and should return to where it was called from). But the CPU doesn't know if the stack is "balanced" and will "pop" and "jmp" whatever it finds next on the stack. If it's total garbage, the crash is immediate. If it is some valid address, but not the right one, execution may continue for quite a while before the problem becomes obvious - if it does. This can make for a very hard to find bug!
Anyway, back to your code:
;explenation-reads in an array of ints, sorts them by finding largest and puting it in last place over and over, and then printing out the array.
overFlow:
mov edx, prompt1 ;
call WriteString ;
jmp exit ;
zeroError:
mov edx, prompt2 ;
call WriteString ;
jmp exit ;
readInts:
cmp ecx, 100 ;
je overFlow ;
call ReadInt ;
push ecx ;
mov ecx, eax ;
jecxz sortSetUp ;
pop ecx ;
mov [array+ecx*4],eax ;
inc ecx ;
call readInts ;
Another "call" with no "ret". Return-addresses pile up on the stack. One for every input (which may explain the different behavior on different runs). Just "jmp readInts" should work here, and would be "better", I think.
While we're here...
call ReadInt ;
push ecx ;
mov ecx, eax ;
jecxz sortSetUp ;
This is a legitimate "call" - Curtis Wong's code has a "ret" in it and the stack should have the proper return address on it, so we return here with the users input clutched firmly in eax. Gammac's right that 0 is a valid input, but we need to use it to pretend they said "quit". I don't understand why you did it the way you did ("because it came to me to do it that way" is a good reason). Why not:
call ReadInt
cmp eax, 0
jz sortSetUp
...
This would save pushing and popping ecx - it could remain the "item count". I think the way you do it should work, but I get nervous when I see anything like:
push something
set some condition code ("flags")
any conditional jump
pop something
As long as the pushes and pops match on both branches of the conditional jump, it's no problem, but it's a place where bugs can sneak in. Since "pop" doesn't alter the flags, we can often do:
push something
set some condition codes
pop something
some conditional jump
but when we're popping ecx and the condition is "jecxz", this isn't going to work!
sortSetUp:
pop ecx ;
cmp ecx, 0 ;
je zeroError ;
dec ecx ;
mov esi, array ;
mov [size], ecx ;
mov edx, ecx ;
sortNext:
cmp edx,0 ;
je printAllSetUp;
mov ebx,[esi+edx*4] ;
mov [max],ebx ;
mov [maxIndex],edx ;
mov ecx,edx ;
sort:
cmp ebx,[esi+ecx*4] ;
Jge skip ;
mov ebx,[array+ecx*4];
mov [max], ebx ;
mov [maxIndex], ecx ;
mov eax,[max] ;
skip:
cmp ecx, 0;
je zeroLoopEnd ;
dec ecx ;
jmp sort ;
zeroLoopEnd:
mov eax, [max] ;
xchg [esi+edx*4], eax ;
mov ebx,[maxIndex] ;
mov [esi+ebx*4],eax ;
dec edx ;
call sortNext;
Yet another "call" with no "ret". Well, your sort routine seems to be working. Could probably do "jmp sortNext" with no ill effects. The way I learned to do a bubble sort, as I remember it, went something like:
top:
set some "swap flag" to zero (some register)
iterate through the array doing comparisons
jge noswap ; or some condition
do the swap
set the "swap flag" to non-zero
noswap:
continue through the array, until done
check the "swap flag"
if it's still zero, we're done
if not, go back to top and make another pass
If you call a "print_array" after each pass, you can watch the larger numbers "bubble" up to the top of the array. Since your method seems to work, better leave it alone - maybe get rid of that excess "call".
printAllSetUp:
mov edx,0 ;
mov ecx, [size] ;
inc ecx ;
call printAll ;
printAll:
mov eax,[esi+edx*4] ;
inc edx ;
call WriteInt ;
jecxz exit ;
loop printAll ;
This looks good and seems to work right.
exit: ;exit function
pop esp ;
call Crlf ;
This is where it crashes for me. I said it was unusual for a "call" to crash (usually it's the "ret"s that get ya). If the value we popped into esp were any legitimate memory, it would have worked. It might not have been the "right" place on the stack, but "call" would have had someplace to put its return address, and the "ret" in Crlf would have found it. But if we'd popped something else - an array index or a value for number of items or anything - when "call" tried to save its return address, it would have been trying to write to invalid memory, and would segfault. I haven't tracked down why, but I think that must be what's happening. If you'd put the "pop esp" after the "call", we might never have noticed that the stack was messed up - but it still would have been.
mov eax,1 ;mov 1 eax
Useless comment. One ring to rule them all? Oh, I see, it's sys_exit!
sys_exit doesn't care what shape the stack is in. All of the memory for our process - including the stack - just vanishes and we return to the shell (bash, which is buggy as it turns out) not to here.
int 0x80 ; ask kernal to exit
Old-fashioned way to spell "kernel". Not wrong, just "old school". Okay, I'm just being picky now. I hear a bell ringing. I think it's recess! TTYL
Best,
Frank