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
Related
I have elements loaded in stack and I need to move them to array. My code looks like this:
%include "asm_io.inc"
segment .data
array db 100 dup(0)
length db 0
segment .text
global _asm_main
extern getchar
_asm_main:
enter 0, 0
pusha
call getchar
char_loop:
mov ebx,10
sub eax, '0'
mul ebx
mov ebx, eax
call getchar
sub eax, '0'
add eax, ebx
push eax
inc BYTE[length]
call getchar
cmp eax, 10
je fill_array
cmp eax, 13
je fill_array
cmp eax, 32
je skip_spaces
jmp char_loop
skip_spaces:
call getchar
cmp eax, 32
je skip_spaces
jmp char_loop
fill_array:
mov ecx, [length]
mov ebx, array
l1:
pop eax
mov [ebx], eax ; should be al instead of eax
inc ebx
call print_int
call print_nl
loop l1
print_array:
mov ecx, [length]
mov ebx, array
l2:
mov eax, [ebx] ; should be al instead of eax
call print_int
call print_nl
inc ebx
loop l2
_asm_end:
call print_nl
popa
mov eax, 0
leave
ret
print_int in asm_io.asm is
print_int:
enter 0,0
pusha
pushf
push eax
push dword int_format
call _printf
pop ecx
pop ecx
popf
popa
leave
ret
Where int_format is int_format db "%i",0
Length and values in stack are correct, I had them printed but when I try to print array only last value is correct. Other values are random numbers. I tried combinations of registers of different sizes but it did not work. I think that error has to do something with size of registers or size of array.
Answer here:
As #xiver77 said in comments I was writing into array 4 bytes instead 1 byte. One element in array has 1 byte and I tried to write 4 bytes. That creates overflow of bites and change other elements in array. Instead mov [ebx], eax should be mov [ebx], al and mov eax, [ebx] for printing should be mov al [ebx].
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 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
I have the following assembly code:
; File: strrev.asm
; A subroutine called from C programs.
; Parameters: string A
; Result: String is reversed and returned.
SECTION .text
global strrev
_strrev: nop
strrev:
push ebp
mov ebp, esp
; registers ebx,esi, and edi must be saved if used
push ebx
push edi
xor esi, esi
xor eax, eax
mov ecx, [ebp+8] ; load the start of the array into ecx
jecxz end ; jump if [ecx] is zero
mov edi, ecx
reverseLoop:
cmp byte[edi], 0
je reverseLoop_1
inc edi
inc eax
jmp reverseLoop
reverseLoop_1:
mov esi, edi ;move end of array into esi
mov edi, ecx ;reset start of array to edi
reverseLoop_2:
mov al, [esi]
mov bl, [edi]
mov [esi], bl
mov [edi], al
inc edi
dec esi
dec eax
jnz reverseLoop_2
end:
pop edi ; restore registers
pop ebx
mov esp, ebp ; take down stack frame
pop ebp
ret
Which works fine until you start looping through reverseLoop_2. Using gdb, eax is listed as being 11, which it should be (this is the length of the string I passed in through a separate c program). This is show in the debugger as:
Breakpoint 2, reverseLoop_2 () at strrev.asm:40
40 mov al, [esi]
(gdb) display $eax
1: $eax = 11
However, if I step through the program to the next line, it resets to 0.
(gdb) next
41 mov bl, [edi]
1: $eax = 0
I need eax to be preserved since its the one keeping track of how many times reverseLoop_2 needs to loop. Why is it resetting to 0 after the call to mov?
If you're using eax as a loop counter, you shouldn't write to it inside the loop :
reverseLoop_2:
mov al, [esi]
Remember that al is the least significant byte of eax :
I think this should work.
mov eax, address of your string
push esi
push edi
mov edi, eax
mov esi, eax
; find end of string
sub ecx, ecx
not ecx
sub al, al
cld
repne scasb
; points to the byte after '0x00'
dec edi
dec edi
; main loop will swap the first with the last byte
; and increase/decrease the pointer until the cross each other
_loop:
cmp esi, edi ; if both pointers meet, we are done
jg _done
mov al, [edi]
mov bl, [esi]
mov [esi], al
mov [edi], bl
inc esi
dec edi
jmp _loop
_done:
pop edi
pop esi
I am writing a number manipulation program, and one step is to reverse the array. So far I have
reverseArray proc
mov eax, arraySize
mov temp, eax
Imul eax, 4
mov esi, eax
mov eax, 0
mov number, 0
jne L1
L1:
cmp temp, 0
je L3
mov eax, numbers[esi]
mov tempnumbers[ecx], eax
mov eax, tempnumbers[ecx]
call writeDec
call crlf
sub esi,4
add ecx, 4
sub temp, 1
loop L1
L2:
ret
L3:
.If(number >= 0)
mov esi, 0
.ENDIF
mov eax, number
cmp eax, arraySize
je L2
mov eax, tempnumbers[esi]
mov numbers[esi], eax
add esi, 4
add number, 1
loop L3
However this only reverses about half of my array. Did I do something wrong with the esi or ecx counters? Any help would be appreciated.
Use edi instead of ecx, and set it to 0 at the start.