Inserting values into array in assembly MASM32 - arrays

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

Related

Segmentation fault Core Dumped X86 Assembly Array

I asked for help earlier and thought I was home free but I'm not. My logic was wrong and I've greatly altered it. This program is supposed to return the Max int in the array (which also happens to be the last element). After tracing it with GDB a few times, I see that I get to the 5th (2nd to last) element in the array, "20", when I hit a segmentation fault and the program halts. I set ECX to the array length and subtracted 1 from ECX to avoid this, but my logic is obviously wrong. Am I wrong in depending on the ECX counter to terminate the loop. Any ideas please?
***EDIT MAJOR EDITS TO CODE
SECTION .data ;data section
msg1: db "Here are the array elements:", 10, 0
msg1Len: equ $-msg1
msg2: db "Here is the sorted array:", 10, 0
msg2Len: equ $-msg2
arr: dd 12, 16, 6, 18, 10, 40, 30
arrLen: equ ($-arr)/4 ;number of elements = array length / 4
SECTION .bss
max resd 1 ;declare and reserve space for max
SECTION .text
global bsort
bsort:
push ebp ; save old ebp register
mov ebp, esp ; build a new stack
restart:
mov ebx, arr ; the base address argument is saved in ebx register
mov ecx, arrLen ; the size argument is saved in exc register
sub ecx, 1 ; Last member has no following element to compare with.
; So we need to reduce the counter by 1
top:
mov eax, [ebx] ;; access first array element. Move its value to eax
cmp eax, [ebx+4] ; compare the value of eax ([ebx]) with [ebx+4]
jle noswap ; if value at eax is less or equal to value of [ebx+4]
; no need to exchang values. Jump to noswap
xchg eax, [ebx+4] ; if value at eax > value [ebx+4], exchange
mov [ebx], eax ; store the new exchanged value at [ebx]
jmp restart ; reset the base address and counter. Start over
noswap:
add ebx, 4 ; move to the next array element
loop top ; loop back to the top if the register ecx > 0
leave
ret
global main
main:
push ebp
mov ebp, esp
mov ecx, msg1 ;print msg1
mov edx, msg1Len
call PString
;save array base address in ebx and save sizein in ecx
mov ebx, arr
mov ecx, arrLen; store num elements in ecx
;loop to print array
PrintArray:
mov eax, [ebx] ;move value [ebx] to eax
call PrintDec
call Println
add ebx, 4
loop PrintArray
;call bubblesort
call bsort
mov ecx, msg2
mov edx, msg2Len
call PString
;save arr base add in sbx and size in ecx
mov ebx, arr
mov ecx, arrLen
PrintSortedArray:
mov eax, [ebx]
call PrintDec
call Println
add ebx, 4
loop PrintSortedArray
;exit program and clean stack
mov esp, ebp
pop ebp
ret
PString:; save register values of the called function
pusha
mov eax,4 ; use 'write' system call = 4
mov ebx,1 ; file descriptor 1 = STDOUT
int 80h ; call the kernel
; restore the old register values of the called function
popa
ret
Println:
;will call PString func
;will change content of ecx and edx
;need to save registers used by the main program
section .data
nl db 10
section .text
pusha
mov ecx, nl
mov edx, 1
call PString
;return original register values
popa
ret
PrintDec:
;saves all registers so they return unmodified
;build the function to handle dword size
section .bss
decstr resb 10 ; 10 32-bit digits
ct1 resd 1 ;keep track of dec-string size
section .text
pusha; save registers
mov dword[ct1],0 ;initially assume 0
mov edi, decstr ; edi points to dec-string
add edi, 9 ; moved to the last element of string
xor edx, edx ; clear edx for 64-bit div
whileNotZero:
mov ebx, 10 ; get ready to divide by 10
div ebx ; divide by 10
add edx, '0' ; convert to ascii
mov byte[edi], dl ; put it in string
dec edi ; move to next char in str
inc dword[ct1] ; inc char counter
xor edx, edx ; clear edx
cmp eax, 0 ;is remainder 0?
jne whileNotZero ;if no, keep on looping
inc edi ; conversion finished, bring edi
mov ecx, edi ; back to start of string. make ecx
mov edx, [ct1] ; point to counterm edx gets # chars
mov eax, 4 ; print to stdout
mov ebx, 1
int 0x80 ; call kernel
popa ; restore registers
ret

Sorting array in x86 assembly language

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

Get index of array element in Assembly

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

getting character from string and using it as array index... ASM

Having trouble using a string array and getting each character from it and adding a 1 to a frequency table of the corresponding ascii index (frequency table is indexed by ascii value): Example, get character 'a' then add 1 to the frequency table of index of the array ['a']. I was getting segmentation errors and now getting error: invalid combination of opcode and operands, talking about mov ax, al
Any questions about the parameters of the problem please ask. I have working on this for hours and could really use another pair of eyes to check what I am doing wrong (syntax/concept if you see one) Please help.
Update: I have got it print stuff out, so I think it is "working"; however I am now trying to print the characters that each array index corresponds. It won't print the character of the array that I am pointing to (it prints literally nothing for the character).
Latest update: I got it to work. changed some of the code under the label .loopa and now it works fine! :)
Code below:
SECTION .data ; Data section, initialized variables
array5: db "Hello, world...", 0
array5Len: equ $-array5-1
asoutput: db "%s", 0 ; string output
newline: db "", 10, 0 ; format for a new line
acoutput: db "%c: ", 0 ; output format for character output
SECTION .bss ; BSS, uninitialized variables
arrayq: resd 128 ; frequency array of the first 127 ascii values initialized to 0 (none have been counted yet)
SECTION .text
global main ; the standard gcc entry point
main: ; the program label for the entry point
push ebp ; set up stack frame
mov ebp,esp
mov esi, array5
mov edi, 0
mov ebx, arrayq
mov ecx, array5Len
; get each character of array5 and add 1 to the frequency table of the corresponding ascii value (which the arrayq is indexed by ascii value).
.loopf:
xor eax, eax
mov al, [esi]
;mov ax, [esi]
;mov ax, al
;mov cx, ax
add edi, eax
mov ebx, 1
add [arrayq+4*edi], ebx
mov edi, 0
add esi, 1
loop .loopf
push dword array2
push dword asoutput
call printf
add esp, 8
push dword newline
call printf
add esp, 4
;pop ebx
mov ebx, arrayq
mov ecx, 128 ; size of arrayq
mov esi, 0 ;start at beginning
.loopa:
mov eax, 0
cmp [ebx+esi], eax
je .skip
mov eax, esi
push ebx
push ecx
mov ebx, 4
cdq
div ebx
push eax
push dword acoutput
call printf
add esp, 8
pop ecx
pop ebx
push ebx
push ecx ; make sure to put ecx (counter) on stack so we don't lose it when calling printf)
push dword [ebx + esi] ; put the value of the array at this (esi) index on the stack to be used by printf
push dword aoutput ; put the array output format on the stack for printf to use
call printf ; call the printf command
add esp, 8 ; add 4 bytes * 2
pop ecx ; get ecx back
pop ebx
push ebx
push ecx
push dword newline
call printf
add esp, 4
pop ecx
pop ebx
.skip:
add esi, 4
loop .loopa
.end:
mov esp, ebp ; takedown stack frame
pop ebp ; same as "leave" op
Changed code under .loopa label to make it print the character the index is corresponding to:
.loopa:
mov eax, 0
cmp [ebx+esi], eax
je .skip
mov eax, esi
push ebx
push ecx
mov ebx, 4
cdq
div ebx
push eax
push dword acoutput
call printf
add esp, 8
pop ecx
pop ebx

Intel 8086 Insertion Sort: Skipping numbers within the Array

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.

Resources