So I have the following code that worked for finding the LARGEST number in any given n by m matrix.
segment .bss
num: resw 1 ;For storing a number, to be read of printed....
nod: resb 1 ;For storing the number of digits....
temp: resb 2
matrix1: resw 200
m: resw 1
n: resw 1
i: resw 1
j: resw 1
buff resb 4
segment .data
msg1: db "Enter the number of rows in the matrix : "
msg_size1: equ $-msg1
msg2: db "Enter the elements one by one(row by row) : "
msg_size2: equ $-msg2
msg3: db "Enter the number of columns in the matrix : "
msg_size3: equ $-msg3
msg4: db "The smallest Number is... : "
msg_size4: equ $-msg4
tab: db 9 ;ASCII for vertical tab
new_line: db 10 ;ASCII for new line
segment .text
global _start
_start:
mov eax, 4
mov ebx, 1
mov ecx, msg1
mov edx, msg_size1
int 80h
mov ecx, 0
call read_num
mov cx, word[num]
mov word[m], cx
mov eax, 4
mov ebx, 1
mov ecx, msg3
mov edx, msg_size3
int 80h
mov ecx, 0
call read_num
mov cx, word[num]
mov word[n], cx
mov eax, 4
mov ebx, 1
mov ecx, msg2
mov edx, msg_size2
int 80h
;Reading each element of the matrix........
mov eax, 0
mov ebx, matrix1
mov word[i], 0
mov word[j], 0
i_loop:
mov word[j], 0
j_loop:
call read_num
mov dx , word[num]
;eax will contain the array index and each element is 2 bytes(1 word) long
mov word[ebx + 2 * eax], dx
inc eax ;Incrementing array index by one....
inc word[j]
mov cx, word[j]
cmp cx, word[n]
jb j_loop
inc word[i]
mov cx, word[i]
cmp cx, word[m]
jb i_loop
; read out matrix code
xor esp, [matrix1]
; esp initialized to first element in array, & is first smallest value
;Loop through the matrix, check each number if its
;larger than the first number in the array. AT the end print said number.
;Reading each element of the matrix.(Storing the elements in row major order).......
mov ebp, 0
mov edi, matrix1
mov esp, 0
mov word[i], 0
mov word[j], 0
i_loop2:
mov word[j], 0
j_loop2:
;eax will contain the array index and each element is 2 bytes(1 word) long
mov dx, word[edi+2*ebp] ;
mov word[num] , dx
cmp esp, [num] ; compares current smallest number with current element iterated.
jle skip
mov esp, [num] ; stores new smallest number
mov esi, ebp ; Stores pointer to the smallest element (never used..?)
skip:
inc ebp
inc word[j]
mov cx, word[j]
cmp cx, word[n]
jb j_loop2
inc word[i]
mov cx, word[i]
cmp cx, word[m]
jb i_loop2
;outut
mov eax, 4
mov ebx, 1
mov ecx, msg4
mov edx, msg_size4
int 80h
mov ecx, 0
mov eax, 4 ; system_write
mov ebx, 1 ; stdout
mov ecx, esp ; move smallest element to accumulator
add ecx, 48 ; convert to ascii representation
mov [buff], ecx ; move to memory
mov ecx, buff
mov edx, 4 ; size, 4 bytes
int 80h
exit:
mov eax, 1
mov ebx, 0
int 80h
;Function to read a number from console and to store that in num
read_num:
pusha
mov word[num], 0
loop_read:
mov eax, 3
mov ebx, 0
mov ecx, temp
mov edx, 1
int 80h
cmp byte[temp], 10
je end_read
mov ax, word[num]
mov bx, 10
mul bx
mov bl, byte[temp]
sub bl, 30h
mov bh, 0
add ax, bx
mov word[num], ax
jmp loop_read
end_read:
popa
ret
I've identified the problem is likely mov esp, 0 but without that line the results are even worse, with it the answer is always '0'. Without it it result in either nothing or gibberish.
Again, it original works for finding the LARGEST number but now I want to find the smallest, logically this should've meant just changing jge to jle but either it keeps zero (likely because of mov esp, 0 ) or gibberish if I try to make it something else?
How can I fix this so I do find the smallest number with the least amount of changes? The code did originally work albeit only after significant trial and error almost at random with my fiddling.
Additionally the gibberish outputted is this: â½µÿ
If I remove mov esp, 0 but keep it as jge, it still works for the LARGEST number, but if I switch it to jle, it outputs â½µÿ. This makes zero sense.
Related
Today I'm working on arrays and addressing modes so I made this snippet to train myself. Everything is working fine (apparently) but I chose the easiest way using fixed size arrays. My question is about dynamic memory allocation. In my code, my arrays arrayand array2 have a fixed size (8 * 4(int)). If I wanted to extend them, or to speak with C concepts, make a realloc or something like depending on real time values for the size, may I have to implement system calls like sys_brk and mmapby myself in assembly
or is there an other option ? The other question deals with the part of my code used to reverse an array (label .reversing) I know they are faster solutions than mine so if you could give me some advices, it would be nice.
%define ARRAY_LEN 8
%macro print 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 0x80
%endmacro
%macro exit 0
xor ebx, ebx
mov eax, 1
int 0x80
%endmacro
section .bss
sumarrays resd 1
dynarray resd 256
section .rodata
highest equ 0x78
evensum equ 0x102
sumarray1 equ 0x1e6
sumarray2 equ 0x256
section .data
revarray times ARRAY_LEN dd 0
strok db "Good result !", 0xa, 0
lenstrok equ $ - strok
strerror db "Bad result !", 0xa, 0
lenerror equ $ - strerror
array dd 0x33, 0x21, 0x32, 0x78, 0x48, 0x77, 0x19, 0x10
array2 dd 0x12, 0x98, 0x65, 0x62, 0x4e, 0x3e, 0x1f, 0x3a
section .text
global sort
global sum
global _start
_start:
; sort array from highest value to lowest value
sub esp, 8
push ARRAY_LEN
push array
call sort
add esp, 8
and esp, 0xfffffff0
; copying array into some another ones : array -> revarray
mov esi, eax
mov edi, revarray
mov ecx, ARRAY_LEN
rep movsd
; now let's reverse the array
mov esi, revarray ;esi = address of array
mov ecx, ARRAY_LEN ;ecx = number of elements
lea edi, [esi + ecx * 4 - 4]
.reversing:
mov eax, [esi] ;eax = value at start
mov ebx, [edi] ;ebx = value at end
mov [edi], eax
mov [esi], ebx
add esi, 4 ;incrementing address of next item at start
sub edi, 4 ;incrementing address of next item at end
cmp esi, edi ;middle reached ?
jb .reversing ;no we continue
.reversed:
;after, we compute the sum of the elements in the array
mov esi, revarray ; address of array
mov edx, ARRAY_LEN ; num elem of array
sub esp, 8
call arraysum ; sum computation
add esp, 8
cmp eax, sumarray1 ; we check the result to be sure
jne .failure
; merging array2 with array
; esi = source address of first array
; edi = address of second array, the destination one
mov esi, array2
mov edi, array
sub esp, 8
call mergearrays
add esp, 8
; we compute the sum of the merged arrays into the new (old one in fact)
mov esi, array
mov ecx, ARRAY_LEN
add esp, 8
call arraysum
add esp, 8
cmp eax, 0x43c ; we check the result to be sure
jne .failure ; if not egal, exit
; compute the sum of even numbers only in the array
; set up edx to 0 at beginning of loop
; cmova edx, $value_even_number
mov esi, revarray
xor ebx, ebx
xor ecx, ecx
.iterate:
xor edx, edx ; setting up edx to 0
mov eax, [esi + ecx * 4]
test al, 1 ; CF == 0 ? so it's an even number
cmovz edx, eax ; we store the value of current element in edx
add ebx, edx ; so in case of odd number => add 0
inc ecx
cmp ecx, ARRAY_LEN ; end of array reached ?
jne .iterate ; no, we continue
cmp ebx, 0x102 ; check if result is good
je .success
jmp .failure
exit
.success:
print strok, lenstrok
exit
.failure:
print strerror, lenerror
exit
; ********************************************
; computes the sum of all elements of an array
; esi = address of the array
; edx = number of elements in array
; output : eax
; ********************************************
arraysum:
push ebx
xor ebx, ebx
xor ecx, ecx
.arraysum:
mov eax, [esi + ecx *4]
add ebx, eax
inc ecx
cmp ecx, edx
je .sumdone
jmp .arraysum
.sumdone:
mov eax, ebx
pop ebx
ret
; *********************************************
; procedure that sort array from highest to lowest value
; first arg = address of the array
; second arg = number of elements in a array
; return : eax, sorted array
; ********************************************
sort:
push ebp
mov ebp, esp
mov edx, [ebp + 12]
.loop1:
mov esi, [ebp + 8]
mov ecx, [ebp + 12]
.loop2:
mov eax, [esi]
mov ebx, [esi + 4]
cmp eax, ebx
jg .skip
mov [esi], ebx
mov [esi + 4], eax
.skip:
add esi, 4 ;perform loop checks
dec ecx
cmp ecx, 1
ja .loop2
dec edx
ja .loop1
mov eax,[ebp + 8] ; save result in eax
mov esp,ebp
pop ebp
ret
; ****************************************************
; function adding two arrays merging them
; esi = address of first array
; edi = address of second array (destination array)
; ****************************************************
mergearrays:
xor ecx, ecx
.merging:
mov eax, [esi + ecx * 4]
xadd [edi + ecx * 4], eax
inc ecx
cmp ecx, ARRAY_LEN
je .mergedone
jmp .merging
.mergedone:
ret
My program works, but there is something wrong with my printMax function. The program terminates with a
Segmentation fault (core dumped).
I have tried building a stack for the function and just doing a pusha popa and both ways, I get the seg fault core dumped.
I've tried calling the function, but it just runs twice.
Any idea what I am doing wrong?
SECTION .data ;data section
msg1 : db "Here are the array elements:", 10, 0
msg1Len: equ $-msg1
msg2 : db "Here is the max value in the array:", 10, 0
msg2Len: equ $-msg2
arr : dd 2,4,6,8,10,20,40
arrLen : equ ($-arr)/4 ;number of elements = array length / 4
SECTION .bss
max resd 1 ;declare and reserve space for max
SECTION .text
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
printMax:
section .text
pusha
;reset array to find max
mov ebx, arr
mov ecx, arrLen
loopForMax:
mov eax, [ebx]
cmp eax, [ebx +4]
jle sameMax
mov [max], eax
sameMax:
add ebx, 4 ;move to next element
loop loopForMax
mov ecx, msg2
mov edx, msg2Len
call PString
mov eax, [max]
call PrintDec
call Println
popa
ret
;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
I am trying to read chars from input file, and place them in an array (except new line chars).
here is my code:
mov dword [counter], 0
mov edi, [size]
loop:
mov esi, state
cmp [counter], edi ; read all chars of the file
je end_loop
pushad
mov eax, 3
mov ebx, dword [file_desc]
mov ecx, read_char
mov edx, 1
int 0x80
popad
cmp byte [read_char], '1'
je put_char
cmp byte [read_char], ' '
je put_char
jmp loop
put_char:
mov edx, [read_char]
mov [esi + counter], edx
;; print number of char read from 0 to size-1
pushad
mov ecx, dword [counter]
push ecx
push printInt
call printf
add esp, 8
popad
;; print char read
pushad
push edx
push printChar
call printf
add esp, 8
popad
;; print value stored in state[counter]
pushad
push dword [esi + counter]
push printChar
call printf
add esp, 8
popad
mov eax, [counter]
inc eax
mov [counter], eax
jmp loop
end_loop:
the printing inside the loop works fine, as i get the char number, the char i have just read and the char in [esi + counter] (supposed to be state[counter]).
however, trying to print it after the reading loop, with this code:
mov dword [counter], 0
mov edi, [size]
printarray:
mov esi, state
cmp [counter], edi
je end
pushad
push dword [esi + counter]
push printChar
call printf
add esp, 8
popad
pushad
mov ecx, [counter]
inc ecx
mov [counter], ecx
popad
jmp printarray
end:
all I get is blanks (new char lines every line, from my printChar).
I don't understand my the values I read are not stored in the array.
There is no code between end loop and mov dword [counter], 0 just before the printarray loop.
mere are my data and bss:
section .data
newLine: DB "", 10, 0
printInt: DB "%d", 10, 0
printString: DB "%s", 10, 0
printChar: DB "%c", 10, 0
hello: DB "hello", 10, 0
section .bss
file_name resb 80
file_desc resd 1
WorldLength resd 1
WorldWidth resd 1
generations resd 1
print_freq resd 1
state resb 60*60
read_char resb 1
counter resd 1
size resd 1
Thank you for your help.
Well...
First of all, don't use 32-bit registers when operating on bytes. I'm sure that even if your code worked, some data would be overwritten.
I believe that your problem resides somewhere in statements similar to these
mov [esi + counter], edx
...
push dword [esi + counter]
They actually mean: "take the address of counter and add it to esi", which I think isn't what you want.
Onto this,
- reading the file character by character is terribly inefficient
- using counter variables instead of ecx is inefficient
- incrementing register rather than a memory location iself is inefficient too
I've tried to rewrite your code as much as I could, and I hope it was worth something.
mov eax, 3
mov ebx, dword [file_desc]
mov ecx, state
mov edx, [size]
int 0x80
; eax now contains the number of bytes read, so why not to use it?
mov ebx, eax
add ebx, state
mov byte [ebx], 0x0 ; this will be end-of-string, although it may not really be necessary
xor ecx, ecx ; this will be our counter now
_loop: ; loop is actually an instruction
cmp ecx, eax
je _end
inc ecx ; ecx++
mov dl, '\n'
cmp byte [state + ecx], dl ; is newline?
jne _loop ; nope? ok, try again
mov dl, ' ' ; yes?
mov byte [state + ecx], dl ; replace newline with space character
jmp _loop
_end:
; print the result
mov edx, eax ; the size - number of bytes read
mov eax, 4
mov ebx, dword [file_desc]
mov ecx, state
int 0x80
Problem solved.
I should have used this to put the char in the array:
put_char:
mov dl, [read_char]
mov [esi], dl
mov eax, [counter]
inc eax
mov [counter], eax
inc esi
jmp loop
I removed the printing, those were for debugging only.
Thanks :)
I am trying to get my frequency table to fully display but while trying to run the loop
through the next label it gives me an exception handler error. I am wondering how I can get my loop to run fully
My code:
INCLUDE Irvine32.inc
.data
target BYTE "AAEBDCFBBC", 0
freqTable DWORD 256 DUP(0)
introPrompt BYTE "Here are the indexes in hex and their counts in the array: ", 0ah,
0dh, 0
prompt BYTE "Location ", 0
prompt2 BYTE " : ", 0
numcount DWORD 0
sLength DWORD ?
location DWORD ?
count DWORD 0
temp BYTE ?
.code
main PROC
mov edx, OFFSET target
call StrLength
mov sLength, eax
Get_frequencies PROTO,
pval1: DWORD,
tableVal: DWORD
INVOKE Get_frequencies, ADDR target, ADDR freqTable
mov eax, numCount
call WriteDec
call crlf
mov edx, OFFSET introPrompt
call WriteString
;Writes the frequency table
mov esi, OFFSET freqTable
mov ecx, 256
top:
mov edx, OFFSET prompt
call WriteString
mov eax, count
call WriteHex
mov edx, OFFSET prompt2
call WriteString
mov eax, [esi]
call WriteDec
call crlf
add esi, 4
inc count
loop top
call WaitMsg
exit
main ENDP
Get_frequencies PROC USES edi esi,
pval1: DWORD,
tableVal: DWORD
mov edi, pval1 ;edi points to target array
mov esi, pval1 ;esi points to freqTable
mov edx, 0
mov eax, 0
mov numCount, 0
L1:
mov al, [edi]
mov dl, [esi]
mov temp, dl
cmp al, 0
jne L2
jmp next
L2:
inc edi
cmp al, dl
jne L1
inc numCount
jmp L1
next:
mov ecx, esi
mov ecx, tableVal
imul edx, 4
add ecx, edx
mov ebx, numCount
mov [ecx], ebx
cmp temp, 0
je finish
inc esi
inc edi
jmp L1
finish:
ret
Get_frequencies ENDP
END main
So the numCount global variable contains how many times a character is repeated and I add the number to the frequency table depending on the hex value. I try to increase the esi and edi to go again starting at the following value on the start but it gives me an exception handle error.
Thank you very much
I am using Masm with Irvine32 library. I am new to Assembly and I'm having trouble with converting the contents of a file into an array once I read it in. Once I read in the file and convert it, I should be able to sum up the array or whatever else I need to do with it but right now I'm having trouble with converting my array back to ascii after converting it to int, in order to print it out. I believe what I need to do is read in an input file that contains a list of numbers separated by spaces, convert ascii to int, store in an array, and finally, convert back to ascii and output the results. Is this correct?
My input looks something like this, with spaces to separate the numbers:
24 31 4 63 9 11 17 3 56 37
Here is my program so far:
INCLUDE Irvine32.inc
.data
TEN dword 10
BUFFER_SIZE = 5000
buffer dword BUFFER_SIZE dup (?)
bytesRead dword 0
inFilename byte "input.txt", 0
infileH dword 0
cnt dword 0
ary dword 20 dup (?) ; Array for storing converted ascii to int
bry dword 20 dup (?)
size dword 10
.code
main PROC
call zeroOut
; Open input file
mov edx, OFFSET inFilename
call OpenInputFile
mov infileH, eax
; Read file into buffer
mov edx, OFFSET buffer
mov ecx, BUFFER_SIZE
call ReadFromFile
mov bytesRead, eax
; Close input file
mov eax, infileH
call CloseFile
; Convert ascii to int and store in ary
call zeroOut
lea esi, OFFSET buffer
lea edi, OFFSET ary
mov edx, size
L1:
call convertasciitoint
mov [edi], eax
inc edi
inc esi
dec edx
call DumpRegs
cmp edx, 0
jne L1
call zeroOut
; Convert int to ascii for printing
lea esi, OFFSET ary
lea edi, OFFSET bry
mov ebx, size
L2:
call convertinttoascii
mov [edi], eax
inc esi
inc edi
dec ebx
cmp ebx, 0
jne L2
; Print output
lea esi, OFFSET bry
call myLine
exit
main ENDP
convertasciitoint PROC
mov ecx, 0
mov eax, 0
nextDigit:
mov bl, [esi]
cmp bl, '0'
jl outOfHere
cmp bl, '9'
jg outOfHere
add bl, -30h
imul eax, 10
add eax, ebx
;mov [esi], eax
;mov [edi], eax
inc ecx
inc esi
;inc edi
jmp nextDigit
outOfHere:
mov cnt, ecx
ret
convertasciitoint ENDP
convertinttoascii PROC
mov ecx, cnt
nextDigit:
mov al, [esi]
div TEN
mov eax, 0
mov al, dl
add al, 30h
;mov [edi], dl
;mov dl, [esi]
;inc esi
;inc edi
call DumpRegs
dec ecx
cmp ecx, 0
jne nextDigit
ret
convertinttoascii ENDP
myLine PROC
nextChar:
mov al, [esi]
inc esi
call WriteChar
cmp al, NULL
jne nextChar
ret
myLine ENDP
zeroOut PROC
mov eax, 0
mov ebx, 0
mov ecx, 0
mov edx, 0
ret
zeroOut ENDP
END main
Right now my program reads in the entire file correctly, if I print the buffer array everything is output correctly. I can convert my array to int but I can't convert it back to ascii correctly. Am I not looping or incrementing correctly? Using the input above, my output (after converting back to ascii) is 8589793965, which isn't correct. I can't figure out what I'm doing wrong. I'm trying to read in a number, divide by ten and add 30h to the remainder, is this correct? I can't seem to get to the second digit of the number correctly.
Any help would be much appreciated. Thanks