Let me start this by saying that I do know I am not supposed to be brute forcing the program, but I am at a bit of an impasse, the purpose is to use the elements of one array to basically "sort" the elements of another array.
Given:
start = 1
chars: H,A,C,E,B,D,F,G
links: 0,4,5,6,2,3,7,0
So you'd start at the first element, A, which is also the number 4 in the links array, which points to the letter B in the chars array, and so on and so forth. The characters are stored in a new array in alphabetical order, where I am having trouble in is getting the index number of the chars array after every step, maybe the code will show a bit more where I am having trouble
INCLUDE Irvine32.inc
start = 1
.data
chars BYTE 'H','A','C','E','B','D','F','G'
links DWORD 0,4,5,6,2,3,7,0
array BYTE 0,0,0,0,0,0,0,0
.code
main PROC
mov al, chars +1
mov array, al
mov esi, start ; moves the start location into the esi register
mov eax, [links + 4] ; moves the second element of the array into eax
mov dl, chars[eax] ; moves the character element of the array chars into dl
mov array[esi], dl ; moves the character into the array
inc esi
mov eax, [links + 16]
mov dl, chars[eax]
mov array[esi], dl
inc esi
mov eax, [links + 8]
mov dl, chars[eax]
mov array[esi], dl
inc esi
mov eax, [links + 20]
mov dl, chars[eax]
mov array[esi], dl
inc esi
mov eax, [links + 12]
mov dl, chars[eax]
mov array[esi], dl
inc esi
mov eax, [links + 24]
mov dl, chars[eax]
mov array[esi], dl
inc esi
mov eax, [links + 28]
mov dl, chars[eax]
mov array[esi], dl
inc esi
main ENDP
END main
So I think if I just knew how to get the index of the array element after the "links" array points to it I think I could put it into a loop, I just need to know how to do that.
mov al, chars +1
mov array, al
mov esi, start ; moves the start location into the esi register
mov ebx, offset links
Again:
mov eax, [ebx + esi*4] ; moves the next element of the array into eax
mov dl, chars[eax] ; moves the character element of the array chars into dl
mov array[esi], dl ; moves the character into the array
inc esi
Repeat this code the required number of times by testing the ESI register.
You could improve this code by starting at 0 in stead of 1. It would eliminate the 2 lines at the top. It would need modifying the definition of links.
links DWORD 1,4,5,6,2,3,7,0
Related
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:
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
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
So we're currently studying Intel 8086 Insertion Sort Code that our professor showed us. He wanted us to figure out why the code skips the 0th element within the array and the 3rd element in the array from a code that he had taken from the web.
; void isort(int *a, int n)
; sorts the first n elements of a
;
; Parameters
; a - pointer to the array
; n - number of elements to sorts
%define a [ebp + 8]
%define n [ebp + 12]
isort:
enter 0, 0
pusha
mov ecx, 1
for:
mov ebx, ecx
imul ebx, 4
add ebx, a
mov ebx, [ebx]
mov edx, ecx
dec edx
while:
cmp edx, 0
jl while_quit
mov eax, edx
imul eax, 4
add eax, a
cmp ebx, [eax]
jge while_quit
mov esi, [eax]
mov dword [eax + 4], esi
dec edx
jmp while
while_quit:
mov [eax], ebx
inc ecx
cmp ecx, n
jl for
popa
leave
ret
And the sample array was {5, 8, 12, 2, 1, 7}. This is more for understanding the 8086 language since we just started a couple days ago, and I was wondering if anyone could explain how and what might be going wrong.
Consider what the code will do when ECX is 1:
The while loop will be entered with EBX=8 and EDX=0.
The jl while_quit will not be taken, since EDX is 0.
EBX is compared to [EAX]. That is; 8 is compared to a[0], which is 5, so the jge while_quit is taken.
mov [eax], ebx stores 8 at a[0], so your array now contains {8,8,12,2,1,7}. Clearly not what you want, since you've lost one of the original elements.
Apart from the code's logical flaw, those imul instructions are completely unnecessary since you can use scaled indices on the x86. So the sorting code can be simplified to this (I've verified that it sorts the array correctly):
mov ecx, 1
for_:
; esi = &a[holePos]
lea esi,[a + ecx*4]
; valueToInsert = a[holePos]
mov ebx, [esi]
while_:
; Did we reach the beginning of the array?
cmp esi, OFFSET a
jle while_quit
; valueToInsert < a[holePos-1] ?
cmp ebx, [esi-4]
jge while_quit
; a[holePos] = a[holePos-1]
mov eax, [esi-4]
mov [esi], eax
; esi = &a[holePos-1]
sub esi,4
jmp while_
while_quit:
; a[holePos] = valueToInsert
mov [esi], ebx
inc ecx
cmp ecx, 6
jl for_
I'm using MASM syntax, but you get the idea.
My assignment is to find the smallest letter in the array using assembly embedded into C. I am not sure how to access each element of the array. I tried googling and I found out that some people are doing the following:
mov ecx, arrayOfLetters
and then increment ecx to access each element. Is that right or what I wrote so is correct?
please help, I am confused.
char findMinLetter( char arrayOfLetters[], int arraySize )
{
char min;
__asm{
push eax
push ebx
push ecx
push edx
mov dl, 0x7f // initialize DL
xor ebx, ebx //EBX started off as 0
//moves letters from array to registers
mov ecx, arrayOfLetters[ebx]
mov edx, arrayOfLetters[ebx+1]
The first thing to understand is that 'arrayOfLetters' as passed to your subroutine is a pointer.
To access data (one byte at a time) from pointer (in ecx) in assembler, use:
mov al, [ecx]
mov al, [ecx+1]
... or ...
mov al, [ecx]
inc ecx
mov al, [ecx]
The next issue is how local variables are accessed: there are two main styles used and both of them use stack.
mov ecx, _localvariable_ ; this translates to either
mov ecx, [ebp + offset] ; style (1) or
mov ecx, [esp + offset] ; style (2)
If there was a assembler supporting instruction mov ecx, _localvariable [+1], that would most likely convert to:
mov ecx, [ebp + offset + 1]
And this would not access the char array[], but just some arbitrary byte in the stack.