I've written a function that determines if a value is prime or not prime. But when I return from the function, it comes up with an error.
The error message is
Unhandled exception at 0x00000001 in Project.exe: 0xC0000005: Access violation executing location 0x00000001.
This function should return eax.
push ebp
mov ebp, esp
mov eax, [ebp+8] ; store input value
mov ecx, [ebp+8] ; store input value in counter
sub esp, 4 ; local variable
sub ecx, 1 ; avoid compare with itself
cmp eax, 3 ; compare with 1, 2, 3
jbe Prime
L1:
cmp ecx, 3 ; when count=3 to stop
je NotP
mov edx, 0 ; clear edx to save remainder
mov [esp-4], eax ; save input value
div ecx ; divide number
cmp edx, 0 ; check remainder
je NotP ; if remainder=0 then not prime
jmp Prime
loop L1
NotP:
mov eax, 0
push eax ; if delete this ilne still come up error
pop ebp
ret
Prime:
mov eax, 1
push eax ; if delete this ilne still come up error
pop ebp
ret
isPrime endp
mov [esp-4], eax ; save input value
If you plan on using the local variable that you reserved room for, then you have to write:
mov [esp], eax ; save input value
or alternatively write:
mov [ebp-4], eax ; save input value
A correct prolog/epilog would be:
push ebp
mov ebp, esp
sub esp, 4 ; local variable
mov eax, [ebp+8] ; store input value
...
NotP:
mov eax, 0
pop ebp ; remove local variable
pop ebp
ret
Prime:
mov eax, 1
pop ebp ; remove local variable
pop ebp
ret
isPrime endp
cmp edx, 0 ; check remainder
je NotP ; if remainder=0 then not prime
jmp Prime
loop L1
Finding the remainder not zero is not enough to conclude that the number is prime! More tests are needed. For now, that loop L1 instruction is never executed.
e.g. To test 15, your first division does 15 / 14 which yields a non-zero remainder but 15 isn't a prime number.
L1:
cmp ecx, 3 ; when count=3 to stop
je NotP
The top of the loop can't be correct either! Consider testing the number 7.
First division is 7 / 6 and has a remainder so the loop has to continue
Second division is 7 / 5 and has a remainder so the loop has to continue
Third division is 7 / 4 and has a remainder so the loop has to continue
You don't try any more divisions and conclude "not prime", yet 7 is definitively a prime number.
Related
I am getting the Exception thrown at 0x0044369D in Project2.exe: 0xC0000005: Access violation writing location 0x00000099. From my research so far, I am under the impression this has to do with a null pointer or out of range memory being accessed from the line mov [eax], ecx
I used the offset operator in mov eax, OFFSET arrayfib and I thought that should remedy this. I can't seem to figure out what is causing the issue here.
.model flat, stdcall
.stack 4096
INCLUDE Irvine32.inc
ExitProcess PROTO, dwExitCode: DWORD
.data
arrayfib DWORD 35 DUP (99h)
.code
main PROC
mov eax, OFFSET arrayfib ;address of fibonacci number array
mov bx, 30 ;number of Fibonacci numbers to generate
call fibSequence ;call to Fibonacci sequence procedure
mov edx, OFFSET arrayfib ;passes information to call DumpMem
mov ecx, LENGTHOF arrayfib
mov ebx, TYPE arrayfib
call DumpMem
INVOKE ExitProcess, 0
main ENDP
;----------------------------------------------------------------------------------
;fibSequence
;Calculates the fibonacci numbers to the n'th fibonacci number
;Receives: eax = address of the Fibonacci number array
;bx = number of Fibonacci numbers to generate
;ecx = used for Fibonacci calculation (i-2)
;edx = used for Fibonacci calculation (i-1)
;returns: [eax+4i] = each value of fibonacci sequence in array, scaled for doubleword
;---------------------------------------------------------------------------------
fibSequence PROC
mov ecx, 0 ;initialize the registers with Fib(0) and Fib(1)
mov edx, 1
mov [eax], edx ;store first Fibonacci number in the array
;since a Fibonacci number has been generated, decrement the counter
;test for completion, proceed
mov eax, [eax+4]
fibLoop:
sub bx, 1
jz quit ;if bx = 0, jump to exit
add ecx, edx
push ecx ;save fib# for next iteration before it is destroyed
mov [eax], ecx ;stores new fibonacci number in the next address of array
push edx ;save other fib# before it is destroyed
mov ecx, edx
mov edx, [eax]
mov eax, [eax+4] ;increments accounting for doubleword
pop edx
pop ecx
quit:
exit
fibSequence ENDP
END main
Also if there are any other suggestions I would be happy to hear them. I am new to all this and looking to learn as much as possible.
I'd like to know, how to do the following.
I have an array, where i have to summ numbers (easy)
but the twist is, that i have to have a function call for it,
that get's is params through specific registers. How do i implement that?
In this case, the function needs to get the array (offset) through ESI, and the length of it through ECX.
please educate me
EDIT:
in the meantime i've conjured up this. No idea if this works to as my MASM compliling just broken itself for no reason
.data
intarray DWORD 10000h,20000h,30000h,40000h
.code
szummer proc uses esi ecx,
ptrArray:PTR DWORD, ;points to the array
szArray: Dword ;array size
mov esi, ptrArray ;address of the array
mov ecx, szArray ;szize
mov eax, 0 ;set to 0
AS1:
add eax, [esi] ;add each int to sum
add esi, 4 ;point to next int
loop AS1 ;reapet for array size
ret;
szummer endp
main proc
mov ecx, OFFSET intarray
mov esi, LENGHTOF intarray
INVOKE ArraySum,ecx,esi
invoke ExitProcess,0
main endp
end main
The MASM directive INVOKE works only with the calling conventions C (cdecl), STDCALL, BASIC, FORTRAN and PASCAL. All of these conventions pass the arguments on the stack. Thus, you can't use INVOKE for passing the arguments in registers. You can use the Assembly instruction CALL instead. Your program - slightly modified ;-) - with MASM32 library included (because of "ExitProcess"):
INCLUDE \masm32\include\masm32rt.inc
.DATA
intarray DWORD 10000h,20000h,30000h,40000h
.CODE
szummer proc uses esi ecx
mov eax, 0 ;set to 0
AS1:
add eax, [esi] ;add each int to sum
add esi, 4 ;point to next int
loop AS1 ;reapet for array size
ret;
szummer endp
main proc
mov esi, OFFSET intarray
mov ecx, LENGTHOF intarray
call szummer
invoke ExitProcess,0
main ENDP
END main
I'm getting this error when running program:
Access violation writing location 0x0105100b
Does anyone know what's wrong with this code? It's breaking at mov [ecx],dl
.686
.model flat
extern _ExitProcess#4: PROC
public _main
.data
.code
data1 db 61H,62H,63H,64H,65H,66H,67H,68H,69H,70H,0H
data2 db 25 dup (?)
_main:
mov eax, OFFSET data1
mov ecx, OFFSET data2
mov edx, 0
mov ebp, ecx
sub ebp, eax ; licznik
mov dl, BYTE PTR [eax]
mov [ecx],dl
koniec:
push 0
call _ExitProcess#4
END
I am trying to write a simple sum function in x86 assembly - to which i am passing 3 and 8 as arguments. However, the code doesn't print the sum. Appreciate any help in spotting the errors. I'm using NASM
section .text
global _start
_sum:
push ebp
mov ebp, esp
push edi
push esi ;prologue ends
mov eax, [ebp+8]
add eax, [ebp+12]
pop esi ;epilogue begins
pop edi
mov esp, ebp
pop ebp
ret 8
_start:
push 8
push 3
call _sum
mov edx, 1
mov ecx, eax
mov ebx, 1 ;stdout
mov eax, 4 ;write
int 0x80
mov ebx, 0
mov eax, 1 ;exit
int 0x80
To me, this looks like Linux assembler. From this page, in the Examples section, subsection int 0x80, it looks like ecx expects the address of the string:
_start:
movl $4, %eax ; use the write syscall
movl $1, %ebx ; write to stdout
movl $msg, %ecx ; use string "Hello World"
movl $12, %edx ; write 12 characters
int $0x80 ; make syscall
So, you'll have to get a spare chunk of memory, convert your result to a string, probably null-terminate that string, and then call the write with the address of the string in ecx.
For an example of how to convert an integer to a string see Printing an Int (or Int to String) You'll have to store each digit in a string instead of printing it, and null-terminate it. Then you can print the string.
Sorry, I have not programmed in assembly in years, so I cannot give you a more detailed answer, but hope that this will be enough to point you in the right direction.
I call the function the following way from main:
main:
;memory alocation ect
call encode
The encode function looks like this:
It does a simple RLE algorithm.
encode:
;IN eax - pointer a memoria elejere
;IN ecx - sor hossza
;OUT eax -pointer az eredmeny elejere
;OUt ecx -a kiirt sor hossza
;elso char
Here it reads the first characer
;push eax
push ebp
xor ebp,ebp
push esi
push edi
push eax
xor edi,edi
Here it allocates memory:
;lefoglal memoria eredmenynek
mov ebx,eax
mov eax,ecx
call mem_alloc
;esi legyen eredmeny memoria kezdete
mov esi,eax
mov eax,ebx
;eax ismet a memoria poiter
xor edx,edx
mov dl,[eax]
; push eax
; xor eax,eax
; mov al,dl
; call io_writeint
; call mio_writeln
; pop eax
;lastChar az elso char
mov [lastChar],dl
The main loop the loops to the "vector"
inc ebp
;dec ecx
.goloop:
mov dl,[eax+ebp]
xor ebx,ebx
mov bl,[lastChar]
cmp dl,bl
jne .newChar
xor ebx,ebx
mov bl,[count]
inc bl
mov [count],bl
.backloop:
loop .goloop
.newChar:
mov [esi+edi],bl
inc edi
mov byte[esi+edi],-1
inc edi
mov bl,[count]
mov [esi+edi],bl
inc edi
mov byte[count],0
cmp ecx,0
ja .backloop
.veg:
mov ebx,esi
mov edx,edi
pop edi
pop esi
pop eax
pop ebp
pop eax
mov eax,ebx
mov ecx,edx
ret
It appears that you push four registers onto the stack but pop five off.
When you CALL an address, the instruction pointer is pushed onto the stack, then the processor JMPs to the label/address you specify. When RET is executed, it POPs off the stack and jumps to the address that it popped off. RET expects that the address that CALL pushed onto the stack will be the next word in the stack, but you have already popped this byte off when you popped more registers than you pushed.
You could try taking the very last
push eax
out of your code.