Sorting array in x86 assembly language - arrays

I have to sort an array in descending order using parameters on the stack to an array and an array size. I passed the size by value at ebp+12 and the array by reference at ebp+8.
I know the code is kind of all over the place, but I'm just trying to get to something that works and I can try to clean it up from there.
I've been debugging and it seems to iterate through as I want it to, but my array isn't being sorted. I've been banging my head against this for hours, so any guidance would be greatly appreciated.
The pseudo-code algorithm I'm trying to follow is:
for(k=0, k<arrlength-1,k++)
I=K
for(J=k+1,J<arrlength,J++)
if(arr[j]>arr[i])
I=J
xchg(arr[k], arr[i])
And this is my attempt to implement it in x86 assembly:
;------------------------------------------------
sortlist PROC
;Sorts an array of specified size into descending order
;Receives: DWORD request value, address of an array
;Returns: array of size request, sorted in descending order
;------------------------------------------------
.data
first DWORD ?
next DWORD ?
.code
push ebp
mov ebp, esp
mov ecx, [ebp+12]
mov edi, [ebp+8]
mov eax, 0
mov ebx, 0
mov edx, 0
mov esi, 0
dec ecx ;loop for array length - 1
L1:
add edi, ebx ;ebx = 0 first loop, 4 all remaining loops
mov eax, [edi] ;get the value of the first element
mov first, edi ;store address of first element in first
mov next, edi
push ecx
push edi
L2:
add edi, 4 ;move to next element in array
mov edx, [edi] ;set value of next element to edx
cmp [next], edx ;compare element to next element
jg nxt
mov next, edi ;If less than, move address of greater to next
nxt:
loop L2
mov eax,[next] ;move values pointed to by 1st & next to regs
mov ebx,[first]
mov [first],eax ;move values(swapped) to addresses
mov [next],ebx
mov ebx,4
pop edi
pop ecx
loop L1
pop ebp
ret 8
sortlist ENDP

Related

Array Bubble Sort in Assembly Language

Problem is that why is only sorting the last element and then putting 5 on every index?
I am posting for the first time so I apologize if my question is unclear.
arr BYTE 5,4,3,2,1
arr1 BYTE 5 DUP(?)
temp BYTE ?
.code
main PROC
mov ecx,LENGTHOF arr
mov esi,Offset arr
mov edi,offset arr+1
L1:
mov al,[esi]
mov edx,ecx
mov ecx,4
L2:
mov bl,[edi]
cmp al,bl
JG L3
jmp L5
L3:
mov temp,al
mov [esi],bl
;mov dl,temp
mov [edi],al
inc edi
L5:
loop L2
mov ecx,edx
inc esi
loop L1
;Printing my array
mov ecx,LENGTHOF arr
mov al,arr[0]
CALL dumpRegs
mov al,arr[1]
CALL dumpRegs
mov al,arr[2]
CALL dumpRegs
mov al,arr[3]
CALL dumpRegs
CALL dumpRegs
exit
main ENDP
END main
Problem is that why is only sorting the last element and then putting 5 on every index?
Your L2 InnerLoop works exclusively with the 1st array element since, once it is loaded in AL, you don't advance the pointer in ESI. And because this particular value happens to be the greatest value in the array, it gets stored everywhere.
Your L2 InnerLoop also works with a fixed count of 4 where it should be working with a count of CurrentOuterLoopCount - 1.
The correct solution does not need the 2 different pointer registers. The array elements that are to be compared are always adjacent to each other and so a simple offset of +1 will do the trick.
This is a working BubbleSort. Find out how it works, don't just copy it!
arr BYTE 5,4,3,2,1
.code
main PROC
mov ecx, LENGTHOF arr
sub ecx, 1
jbe Done ; Array is empty or has but 1 element
OuterLoop:
mov edx, ecx ; 5 elements means 4 comparisons
mov esi, Offset arr
InnerLoop:
mov al, [esi]
mov bl, [esi+1]
cmp al, bl
jng NoSwap
mov [esi], bl
mov [esi+1], al
NoSwap:
inc esi
dec edx
jnz InnerLoop
dec ecx ; Next time 3 comparisons, then 2, and then 1
jnz OuterLoop
Done:

Sorting through an array after filling in x86 MASM assembly language

can anyone help me with this problem, I'm new to assembly language and somewhat stuck on what to do next. Here's the code:
.data
evenStart dword 11h
oddStart dword 20h
darray dword 15 dup (?)
.code
main PROC
mov esi, OFFSET darray
xor ecx, ecx
L1:
mov ebx, OFFSET evenStart
test cl,1
jz iseven
mov ebx, OFFSET oddStart
iseven:
mov eax, [ebx]
inc dword ptr [ebx]
mov dword ptr [esi + 4*ecx],eax
inc ecx
cmp ecx,15
jb L1
exit
main ENDP
END main
So the project requires me to fill the uninitilized array, which I did. But then it also ask me to sort through this array in descending order and then put the middle elements of the array into the eax register and call DumpRegs. This is the part where I got stuck in. Any help on how to proceed would be great. Thank you!
Next Bubble Sort uses nested loops. Because your array has 15 elements, the outer loop can do 14 comparisons during its 1st iteration. With each iteration of the outer loop it has to do 1 comparison less because the smallest element has bubbled towards the end of the array.
mov ebx, 15-1 ; Outer loop iteration count
OuterLoop:
mov esi, offset darray
mov ecx, ebx ; Inner loop iteration count
InnerLoop:
lodsd
mov edx, [esi]
cmp eax, edx
jge Skip
mov [esi-4], edx ; Swap these 2 elements
mov [esi], eax
Skip:
dec ecx
jnz InnerLoop
dec ebx
jnz OuterLoop
The unsorted array:
11h, 20h, 12h, 21h, 13h, 22h, 14h, 23h, 15h, 24h, 16h, 25h, 17h, 26h, 18h
The sorted array:
26h, 25h, 24h, 23h, 22h, 21h, 20h, 18h, 17h, 16h, 15h, 14h, 13h, 12h, 11h
In this array with an odd number of elements (15), the element indexes range from 0 to 14. There is a true middle element at index 7.

Wrong values from int array in nasm passed from C

I'm trying to pass an array of 4-byte integers from C to 32-bit nasm in linux. The function call passes a pointer to the first integer and the length in an integer value in that order. The C-program reads a list of numbers from a file. I've verified that the array is populating correctly.
When I run the following code I get consistent, large values. Each value is the same as the last and none were in the original array.
The relevant nasm code is as follows:
_sumAndPrintList:
push ebp
mov ebp, esp
sub esp, 16
push ebx
push ecx
push edx
push edi
push esi
mov ebx, [ebp + 8] ;Pointer to start of list
mov ecx, [ebp + 12] ;Size of list
push ebx
push ecx
push header ;This is a string and prints correctly
call printf
add esp, 4
pop ecx
pop ebx
xor edi, edi ;counter
xor esi, esi ;running total
printLoop:
cmp edi, ecx ;check if at end of list
je endPrintLoop
add esi, [ebx] ;add value in ebx to esi
mov [value], ebx ;move value in array to value
mov [total], esi ;put esi in total
push ebx
push ecx
push edi
push esi
push total
push value
push printNums ;string that prints the value and then the total
call printf
add esp, 12
pop esi
pop edi
pop ecx
pop ebx
add ebx, dword 1
inc edi
jmp printLoop
Everything prints correctly, just the values are wrong and the total is wrong. I'm fairly new to assembly, so if I've included too much or too little or you have questions, feel free to ask/let me know.

Inserting values into array in assembly MASM32

I'm having trouble figuring out how to put a value I currently have in register EAX into an array.
The basic function of this program is to take the dates array, convert them to unique numbers, BubbleSort them, and convert them back.
I put the values I find with "datetonum" into EAX, and I want to store those values I find into my array named ra.
I can't seem to figure out how to do something that.
Seems like it should be fairly simple?
Thanks in advance!
include \masm32\include\masm32rt.inc
.data
dates BYTE "23-JUL-2010", 0, "23-JAN-2010", 0, "23-JUL-2009", 0, "31-JUL-2012", 0, "05-MAR-2010", 0
months BYTE "JAN",0,"FEB",0,"MAR",0,"APR",0,"MAY",0,"JUN",0,"JUL",0,"AUG",0,"SEP",0,"OCT",0,"NOV",0,"DEC",0
nDates DWORD 4
ra DWORD 1,0,0,0,0
.code
start:
lea EAX, dates ; create pointer to beginning of dates array
push EAX
call datetonum
;-------------------
;put value currently in EAX into array to be sorted
;-------------------
print "Array to be sorted contents: "
print chr$(13,10)
lea ECX, ra
mov [ECX + nDates], EAX
print ra
print chr$(13,10)
Here's the datetonum function
;param1 (date string) = address of 12 byte date
datetonum:
enter 4, 0 ; [EBP - 4] holds 4 byte temp variable
mov EBX, [EBP + 8] ; pointer to entire date string
lea ESI, [EBX] ; pointing to day part of date
lea EDI, [EBP - 4] ; pointing to address of local variable to store day string
mov ECX, 2
cld
rep movsb
mov EDX, 0
mov [EDI], EDX ; add null terminator
lea EDX, [EBP - 4]
mov EAX, sval(EDX) ; convert day string to int
push EAX ; push EAX to stack
; extract month from date
lea ESI, [EBX + 3] ; pointing to month part of date
lea EDI, [EBP - 4] ; pointing to address of local variable to store month string
mov ECX, 3
cld
rep movsb
mov EDX, 0
mov [EDI], EDX ; add null terminator
; debug print of month string
pushad
lea EDX, [EBP - 4]
print EDX
print chr$(9) ; print a tab character
print chr$(13,10)
popad
; find month number
sub ESI, ESI
lea EDX, [EBP - 4]
mov EAX, [EDX]
mov ECX, 12
search_top:
lea EDX, [months + ESI * 4]
mov EBX, [EDX]
inc ESI
cmp EAX, EBX
loopne search_top
mov EDX, ESI ; result is in ESI
pop EAX ; pop EAX off the stack
mov AH, DL ; copy the month int into AH
push EAX ; push EAX to stack
; convert year chars to 2 byte int
mov EBX, [EBP + 8]
lea ESI, [EBX + 7] ; pointing to year part of date
lea EDI, [EBP - 4] ; pointing to address of local variable to store year string
mov ECX, 4
cld
rep movsb
mov EDX, 0
mov [EDI], EDX ; add null terminator
lea EDX, [EBP - 4]
mov EDX, sval(EDX) ; convert year string to int
pop EAX ; pop EAX off the stack
mov EBX, EAX ; copy EAX (contains month in AH and day in AL) to EBX
mov EAX, EDX ; copy year to EAX
shl EAX, 16 ; shift the year over to high 16 bits in EAX
mov AX, BX ; copy the month and day into low 16 bits in EAX
;print EAX ; this crashes the proc
print str$(EAX)
print chr$(13,10)
leave
ret 4
exit
If your dates are stored in an array, and you want to use another array to store the dates converted to numbers, you will need at least one loop. You can use index registers (ESI, EDI) to point to both arrays, then use one register to read the value from one array, and the other register to move the value into the other array.
Let's imagine you already have next 3 procedures :
num2date : converts a num in EAX back into a date (the opposite of datetonum). This date is stored in a variable date that is declared like this : date BYTE "DD-MMM-AAAA".
bubble_sort : sorts the numbers in array ra.
transfer_date : takes the 11 bytes of variable date and move them into the position pointed by ESI (ESI is pointing somewhere inside array dates).
This could be the logic of your code :
start:
;▼ NEXT LOOP CONVERTS ALL DATES TO NUMBERS ▼
lea ESI, dates ;POINTER TO ARRAY "DATES".
lea EDI, ra ;POINTER TO ARRAY "RA".
mov ECX, 5 ;LENGTH OF ARRAY "DATES".
dates2numbers:
push ECX ESI EDI ;PRESERVE REGISTERS.
mov EAX, [ESI] ;CURRENT DATE.
push EAX
call datetonum ;CONVERT CURRENT DATE TO A NUMBER.
pop EAX ;GET THE NUMBER.
pop EDI ESI ECX ;RESTORE REGISTERS.
mov [EDI], EAX ;STORE NUMBER IN "RA".
add ESI, 12 ;NEXT ITEM IN ARRAY "DATES" (12 BYTES EACH).
add EDI, 4 ;NEXT ITEM IN ARRAY "RA" (4 BYTES EACH).
loop dates2numbers
call bubble_sort ;◄■■■ SORT ARRAY "RA".
;▼ NEXT LOOP CONVERTS ALL NUMBERS TO DATES ▼
lea ESI, dates ;POINTER TO ARRAY "DATES".
lea EDI, ra ;POINTER TO ARRAY "RA".
mov ECX, 5 ;LENGTH OF ARRAY "RA".
numbers2dates:
push ECX ESI EDI ;PRESERVE REGISTERS.
mov EAX, [EDI] ;CURRENT NUMBER.
call num2date ;CONVERTS EAX TO A DATE IN VARIABLE "DATE".
;VARIABLE "DATE" LOOKS LIKE THIS : DATE BYTE "DD-MMM-AAAA"
;"NUM2DATE" SHOULD PRESERVE ESI AND RESTORE IT
;BECAUSE "TRANSFER_DATE" WILL NEED IT.
call transfer_date ;TRANSFER CONTENT OF VARIABLE "DATE" INTO THE
;ARRAY "DATES" AT THE POSITION ESI IS POINTING TO.
pop EDI ESI ECX ;RESTORE REGISTERS.
add ESI, 12 ;NEXT ITEM IN ARRAY "DATES" (12 BYTES EACH).
add EDI, 4 ;NEXT ITEM IN ARRAY "RA" (4 BYTES EACH).
loop numbers2dates

Array access in MASM

I'm having some difficulty with my array accessing in MASM. I've got a very large array and a temp variable like so:
.data
array DWORD 65000 DUP (0)
temp DWORD 0
In my main, I've got this to fill it:
mov esi, offset array
mov edi, 0
mov ecx, 0
fill:
mov [esi], ecx
add esi, 4
inc ecx
cmp ecx, 65000
jl fill
mov esi, offset array ;reset the array location to the start
After, I want to access the array with this loop:
mark:
mov temp, 4 ;get another 4 to temp to move along the array
add esi, temp ;add temp to esi to keep moving
mov edx, [esi] ;access the current value
cmp esi, 20 ;just trying to get first few elements
jmp mark
exit
main ENDP
END main
I always have an access violation error, with the break at the line where I try to access the current value. This occurs on the very first loop as well. Any idea why this is happening? Thanks!
Your code will work to an extent, however:
mark:
mov temp, 4
add esi, temp ;Incrementing before first loop means you miss the first stored value
mov edx, [esi]
cmp esi, 20 ;ESI is the address your are accessing, not a count
jmp mark ;This loop will be infinite

Resources