I am trying a write a procedure that will read the input of the user and assign input values to the corresponding addresses (trying to create an array dynamically). However, after running the cycle, the program crashes at the ret part. The debugger indicates unauthorized access to DB[0000000]. What am I doing wrong?
array_ini:
lp:
push temp
push readnum
call [scanf]
mov eax, [temp]
mov [array + ebx*2], eax
add ebx,2
cmp ebx,10
jl lp
push done
call [printf]
ret
Related
I'm quite new to x86 assembly, and I'm trying to build off a hello world program. I'm trying to make a subroutine, that writes a single byte to stdout, but i've hit a problem.
The line mov ebx, [esp+1] (to load the byte passed, when I call the subroutine) causes a segfault.
I've tried xoring the ebx register with itself, to make sure that it is empty, to make sure, that it doesn't mess with the syscall
_start:
push 32h
call _writeByte
; This just jumps to an exit routine
jmp _exit
_writeByte:
; This line causes the problem. If I remove it the program works fine
mov ebx, [esp+1]
xor ebx, ebx
mov eax, 1
mov edi, 1
mov esi, tmp
mov edx, 1
syscall
ret
Why is the program segfaulting?
I'm in x64 mode, and like a bunch of people suggested in the comments using mov ebx, [rsp+8] worked, because esp are just the 4 lower bytes of the register. The stack is outside the low 4 GiB of virtual address space, so ESP != RSP and [esp] will be an unmapped page.
Note that x86-64 calling conventions pass the first few args in register, not on the stack, so you normally don't want to do this at all (unless your function has lots of args).
Edit: Thank you so much for all your help! I really appreciate it because for some reason I am having some trouble conceptualizing assembly but I'm piecing it together.
1) I am using the debugger to step through line by line. The problem, Unhandled exception at 0x0033366B in Project2.exe: 0xC0000005: Access violation writing location 0x00335FF8 occurs at this line:
mov [arrayfib + ebp*4], edx
Is think maybe this because the return statement from the other loop is not able to be accessed by the main procedure, but not sure - having a hard time understanding what is happening here.
2) I have added additional comments, hopefully making this somewhat clearer. For context: I've linked the model I've used to access the Fibonacci numbers, and my goal is to fill this array with the values, looping from last to first.
.386
.model flat, stdcall
.stack 4096
INCLUDE Irvine32.inc
ExitProcess PROTO, dwExitCode: DWORD
.data
arrayfib DWORD 35 DUP (99h)
COMMENT !
eax = used to calculate fibonacci numbers
edi = also used to calculate fibonacci numbers
ebp = number of fibonacci sequence being calculated
edx = return value of fibonacci number requested
!
.code
main PROC
;stores n'th value to calculate fibonacci sequence to
mov ebp, 30
mov edx, 0
;recursive call to fibonacci sequence procedure
call FibSequence
mov [arrayfib + ebp*4], edx
dec ebp
jnz FibSequence
mov esi, OFFSET arrayfib
mov ecx, LENGTHOF arrayfib
mov ebx, TYPE arrayfib
call DumpMem
INVOKE ExitProcess, 0
main ENDP
;initializes 0 and 1 as first two fibonacci numbers
FibSequence PROC
mov eax, 0
mov edi, 1
;subrracts 2 from fibonacci number to be calculated. if less than 0, jumps to finish,
;else adds two previous fibonacci numbers together
L1:
sub ebp, 2
cmp ebp, 0
js FINISH
add eax, edi
add edi, eax
LOOP L1
;stores odd fibonacci numbers
FINISH:
test eax, 1
jz FINISHEVEN
mov edx, eax
ret
;stores even fibonacci numbers
FINISHEVEN:
mov edx, edi
ret
FibSequence ENDP
END main
Your Fibonacci function destroys EBP, returning with it less than zero.
If your array is at the start of a page, then arrafib + ebp*4] will try to access the previous page and fault. Note the fault address of 0x00335FF8 - the last 3 hex digits are the offset within a 4k virtual page, an 0x...3FF8 = 0x...4000 + 4*-2.
So this is exactly what happened: EBP = -2 when your mov store executed.
(It's normal for function calls to destroy their register args in typical calling conventions, although using EBP for arg-passing is unusual. Normally on Windows you'd pass args in ECX and/or EDX, and return in EAX. Or on the stack, but that sucks for performance.)
(There's a lot of other stuff that doesn't make sense about your Fibonacci function too, e.g. I think you want jmp L1 not loop L1 which is like dec ecx / jnz L1 without setting flags).
In assembly language, every instruction has a specific effect on the architectural state (register values and memory contents). You can look up this effect in an instruction-set reference manual like https://www.felixcloutier.com/x86/index.html.
There is no "magic" that preserves registers for you. (Well, MASM will push/pop for you if you write stuff like proc foo uses EBP, but until you understand what that's doing for you it's better not to have the assembler adding instructions to you code.)
If you want a function to preserve its caller's EBP value, you need to write the function that way. (e.g. mov to copy the value to another register.) See What are callee and caller saved registers? for more about this idea.
maybe this because the return statement from the other loop is not able to be accessed by the main procedure
That doesn't make any sense.
ret is just how we write pop eip. There are no non-local effects, you just have to make sure that ESP is pointing to the address (pushed by call) that you want to jump to. Aka the return address.
I have an array of two-byte integers, which I am populating with random 3 digit numbers, using ESI to walk through the array. I am getting an access violation when I attempt to access the 9th element of the array and store it in ESI.
ARRAYSIZE = 200
.data
list WORD ARRAYSIZE DUP(?)
fillArray PROC
push OFFSET list
mov esi, [esp] ;GET ADDRESS OF FIRST ELEMENT INTO ESI
mov ecx, request ;NUMBER OF ELEMENTS TO BE ADDED
ArrFill:
;calculate random 3-digit number, store in eax
dec ecx
mov [esi], eax ;THIS IS THE LINE THAT THROWS THE EXCEPTION
sub esi, 2
cmp ecx, 0
jnz ArrFill
Exception thrown: Access violation writing location 0x00405FFE (The value of ESI when thrown).
When I change the array to four-byte integers, I also get an access violation for trying to access the 5th element of the array at the same address.
push OFFSET list
mov esi, [esp] ;GET ADDRESS OF FIRST ELEMENT INTO ESI
Why not simply assign the offset to ESI with mov esi, OFFSET list
mov [esi], eax ;THIS IS THE LINE THAT THROWS THE EXCEPTION
Since the array contains words you can only write the contents of AX, not EAX! Use mov [esi], ax
sub esi, 2
To progress through the array you need to add to the pointer not subtract from it. Use add esi, 2
Hudspero
You are getting an access violation because you are trying to write past the array boundary.
Few things:
You don't seem to be initializing ecx. You should initialize this to the size of the array.
As you are cmp ecx,0 you should be decrementing ecx before the comparison
You should move the esiaddress adjustment after you ensure you won't write past the boundary. I would restructure the code to test ecx for zero and jump out if true, otherwise decrement esiand jump back to ArrFill
I am trying to make a for loop in assembly where the EAX register is set to 5, and increased until it is greater than 10. Each time it increases, it outputs it's current value. When I execute my program, it goes in an infinite loop which only outputs 4. Why is EAX's value 4? Why is register EAX not increasing as it should?
include 'include/macro/import32.inc'
format PE console
entry start
section '.text' code readable executable
start:
mov eax,5
loop1:
inc eax
push eax
push msg2
call [printf]
cmp eax,10
jb loop1
call [getchar]
push 0
call [exit]
section '.data' data readable writable
msg2 db "%i",0dh,0ah,0
section 'idata' import data readable
library msvcrt,"msvcrt.dll"
import msvcrt,printf,"printf",getchar,"getchar",exit,"exit"
The output from printf is returned in eax which contains the number of characters printed: 3 in your case (the digit, CR, and LF). Since that is less than 10, you loop up, add 1 (which makes it 4), print that, and repeat.
What you need to do is store eax (push eax) before setting up the printf call, then restore it (pop eax) after printf returns like:
loop1:
inc eax
push eax ; store eax
push eax
push msg2
call [printf]
add esp,8 ; clean the stack from the printf call
pop eax ; restore eax
cmp eax,10
jb loop1
Or use a different register such as ebx for your loop variable.
Always preserve EAX before using printf. printf destroys your EAX
inc eax
push eax
...call to printf
pop eax
cmp eax,10
I am trying to implement atoi in assembly (the netwide assembler). I have verified that my approach is valid by inspecting the register values with a debugger. The problem is that the application will crash when it is about to exit. I am afraid my program is corrupting the stack somehow. I am linking against the GCC stdlib to allow the use of the printf function. I noticed it mutated the registers which caused unexpected behaviour (extensive iterations over values I did not recognize), however I solved this by storing the value of EAX inside EBX (not modified by printf) and then restoring the value after the function call. This is why I have been able to confirm that the program now behaves as it is supposed to by singlestepping through the algorithm AND confirm that the program crashes as it is about to terminate.
Here is the code:
global _main
extern _printf
section .data
_str: db "%d", 0
section .text
_main:
mov eax, 1234
mov ebx, 10
call _itoa
_terminate:
ret
_itoa:
test eax, eax
jz _terminate
xor edx, edx
div ebx
add edx, 30h
push eax
push edx
push _str
call _printf
add esp, 8
pop eax
jmp _itoa
And here is the stackdump:
Exception: STATUS_ACCESS_VIOLATION at eip=00402005
eax=00000000 ebx=00000000 ecx=20000038 edx=61185C40 esi=612A3A7C edi=0022CD84
ebp=0022ACF8 esp=0022AC20 program=C:\Cygwin\home\Benjamin\nasm\itoa.exe, pid 3556, thread main
cs=001B ds=0023 es=0023 fs=003B gs=0000 ss=0023
Stack trace:
Frame Function Args
0022ACF8 00402005 (00000000, 0022CD84, 61007120, 00000000)
End of stack trace
EDIT: Please note that the stackdump really is not that relevant anymore as the program no longer crashes, it just displays an incorrect value.
I'm not familiar with your platform, but I would expect you need to restore the stack by popping off the pushed values after calling printf().
Since printf() doesn't know how many arguments will be passed, it can't restore the stack. Your code pushes arguments that are never popped off. So when your procedure returns, it gets the return address from the data that was pushed on the stack, which are not going to point to valid code. And that would be your access violation.