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
Related
In the first loop I fill the array, then I want to print this array, but I'll have an error. It's Segmentation fault. I just change ecx register, since is my counter for _loop2.
extern printf
SECTION .bss
array resb 10
SECTION .data
fmt: db "array[%d] = %d", 10, 0 ; The printf format, "\n",'0'
SECTION .text
global main
main:
mov ecx, 0
_loop:
inc ecx
mov [array + ecx * 4], ecx
cmp ecx, 10
jnz _loop
mov ecx, 0
_loop2:
jmp print
add ecx, 1
cmp ecx, 10
jnz _loop2
ret
print:
;push ebp ; set up stack frame
;mov ebp, esp
push ecx
push dword [array + ecx * 4] ; value of variable a SECOND
push dword fmt ; address of ctrl string
call printf ; Call C function
add esp, 8 ; stack (4 * 2)
;mov esp, ebp ; takedown stack frame
;pop ebp ; same as "leave" op
mov eax,0 ; normal, no error, return value
;ret ; return
Several issues as mentioned in comments:
array resb 10 will reserve space for 10 bytes, but you want to store 10 dwords there (40 bytes). Change to array resd 10.
(Pointed out by Sep Roland) In _loop you have an off-by-one bug; since the inc is done before the mov you will access the dwords at [array+4], [array+8], ... [array+40], where the last one is out of range. This is like doing int array[10]; for (i=1; i <= 10; i++) array[i]=i; in C, and is incorrect for exactly the same reason. One fix would be to do mov [array + ecx * 4 - 4], ecx instead.
After _loop2 you have jmp print, which will transfer control to print and never come back. Since you apparently want to call print as a subroutine and continue executing with add ecx, 1 ; cmp ecx, 10, etc, you need to call print instead of jmp. And also uncomment the ret at the end of print so that it will actually return. Subroutines in assembly language don't automatically return unless you actually execute ret; otherwise the CPU will just continue executing whatever garbage happens to be next in memory.
You have a push ecx to save the value of ecx before the call to printf, which is good since printf will overwrite that register, but you need to pop ecx afterwards to get that value back and put the stack back to where it was.
Specifically, the pop ecx should follow the add esp, 8; a stack is a last-in-first-out structure, and the push ecx was before the pushing of the printf arguments, so you need to pop ecx after removing those arguments from the stack.
The mov eax, 0 as a return value at the end of print is unnecessary since you never use it anywhere else.
With these changes the code works as it should.
I'm learning x86 assembly and I'm trying to write a program that reads a number n (2 digits) from user input and iterate n times.
I've tried many ways but I get an infinite loop or segment fault.
input:
push msgInputQty
call printf
add esp, 4
push quantity
call gets
add esp, 4
mov ecx, 2
mov eax, 0
mov ebx, 0
mov edi, 0
mov dl, 10
transform:
mul dl
mov ebx, 0
mov bl, byte[quantity+edi]
sub bl, 30h
add eax, ebx
inc edi
loop transform
mov ecx, eax
printNTimes:
push msgDig
call printf
add esp, 4
loop printNTimes
I'd like to save in ecx and iterate n times this number
Your ecx register is being blown away by the call to printf.
ecx is a volatile register in some calling conventions and its likely that your loop is being corrupted by what printf is leaving in there.
To begin with, I would follow Raymond's advice in the comment attached to your original question and attach a debugger to witness this behaviour for yourself.
As for a solution, you can try preserving ecx and restoring it after the call to see the difference:
; for example
mov edi,ecx
call printf
mov ecx,edi
There may be more issues here (hard to know for sure since your code is incomplete ... but things like your stack allocations that don't appear to be for any reason are interesting) - but that is a good place to start.
Peter has left a comment under my answer to point out that you could remove the issue and optimize my solution by just not using ecx for your loop at all and instead do it manually, making your code change:
mov edi, eax
printNTimes:
push msgDig
call printf
add esp, 4
dec edi
jnz printNTimes
I'm was working on some homework to print out an array as it's sorting some integers from an array. I have the code working fine, but decided to try using EAX instead of AL in my code and ran into errors. I can't figure out why that is. Is it possible to use EAX here at all?
; This program sorts an array of signed integers, using
; the Bubble sort algorithm. It invokes a procedure to
; print the elements of the array before, the bubble sort,
; once during each iteration of the loop, and once at the end.
INCLUDE Irvine32.inc
.data
myArray BYTE 5, 1, 4, 2, 8
;myArray DWORD 5, 1, 4, 2, 8
currentArray BYTE 'This is the value of array: ' ,0
startArray BYTE 'Starting array. ' ,0
finalArray BYTE 'Final array. ' ,0
space BYTE ' ',0 ; BYTE
.code
main PROC
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
MOV EBX,0 ; clearing registers, moving 0 into each, and initialize
MOV ECX,0 ; clearing registers, moving 0 into each, and initialize
MOV EDX,0 ; clearing registers, moving 0 into each, and initialize
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
MOV ECX, lengthOf myArray ; load ECX with # of elements of array
DEC ECX ; decrement count by 1
L1:
PUSH ECX ; save outer loop count
MOV ESI, OFFSET myArray ; point to first value
L2:
MOV AL,[ESI] ; get array value
CMP [ESI+1], AL ; compare a pair of values
JGE L3 ; if [esi] <= [edi], don't exch
XCHG AL, [ESI+1] ; exchange the pair
MOV [ESI], AL
CALL printArray ; call printArray function
CALL crlf
L3:
INC ESI ; increment esi to the next value
LOOP L2 ; inner loop
POP ECX ; retrieve outer loop count
LOOP L1 ; else repeat outer loop
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET finalArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
CALL printArray
L4 : ret
exit
main ENDP
printArray PROC uses ESI ECX
;myArray loop
MOV ESI, OFFSET myArray ; address of myArray
MOV ECX, LENGTHOF myArray ; loop counter (5 values within array)
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET currentArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
L5 :
MOV AL, [ESI] ; add an integer into eax from array
CALL writeInt
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET space
CALL writeString
POP EDX ; restores the original edx register value
ADD ESI, TYPE myArray ; point to next integer
LOOP L5 ; repeat until ECX = 0
CALL crlf
RET
printArray ENDP
END main
END printArray
; output:
;Starting array. This is the value of array: +1 +5 +4 +2 +8
;This is the value of array: +1 +4 +5 +2 +8
;This is the value of array: +1 +4 +2 +5 +8
;This is the value of array: +1 +2 +4 +5 +8
;Final array. This is the value of array: +1 +2 +4 +5 +8
As you can see the output sorts the array just fine from least to greatest. I was trying to see if I could move AL into EAX, but that gave me a bunch of errors. Is there a work around for this so I can use a 32 bit register and get the same output?
Using EAX is definitely possible, in fact you already are. You asked "I was trying to see if I could move AL into EAX, but that gave me a bunch of errors." Think about what that means. EAX is the extended AX register, and AL is the lower partition of AX. Take a look at this diagram:image of EAX register
. As you can see, moving AL into EAX using perhaps the MOVZX instruction would simply put the value in AL into EAX and fill zeroes in from right to left. You'd be moving AL into AL, and setting the rest of EAX to 0. You could actually move everything into EAX and run the program just the same and there'd be no difference because it's using the same part of memory.
Also, why are you pushing and popping EAX so much? The only reason to push/pop things from the runtime stack is to recover them later, but you never do that, so you can just let whatever is in EAX at the time just die.
If you still want to do an 8-bit store, you need to use an 8-bit register. (AL is an 8-bit register. IDK why you mention 16 in the title).
x86 has widening loads (movzx and movsx), but integer stores from a register operand always take a register the same width as the memory operand. i.e. the way to store the low byte of EAX is with mov [esi], al.
In printArray, you should use movzx eax, byte ptr [esi] to zero-extend into EAX. (Or movsx to sign-extend, if you want to treat your numbers as int8_t instead of uint8_t.) This avoids needing the upper 24 bits of EAX to be zeroed.
BTW, your code has a lot of unnecessary instructions. e.g.
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
totally pointless. You don't need to "init" or "declare" a register before using it for the first time, if your first usage is write-only. What you do with EDX is amusing:
MOV EDX,0 ; clearing registers, moving 0 into each, and initialize
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
"Caller-saved" registers only have to be saved if you actually want the old value. I prefer the terms "call-preserved" and "call-clobbered". If writeString destroys its input register, then EDX holds an unknown value after the function returns, but that's fine. You didn't need the value anyway. (Actually I think Irvine32 functions at most destroy EAX.)
In this case, the previous instruction only zeroed the register (inefficiently). That whole block could be:
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
xor edx,edx ; edx = 0
Actually you should omit the xor-zeroing too, because you don't need it to be zeroed. You're not using it as counter in a loop or anything, all the other uses are write-only.
Also note that XCHG with memory has an implicit lock prefix, so it does the read-modify-write atomically (making it much slower than separate mov instructions to load and store).
You could load a pair of bytes using movzx eax, word ptr [esi] and use a branch to decide whether to rol ax, 8 to swap them or not. But store-forwarding stalls from byte stores forwarding to word loads isn't great either.
Anyway, this is getting way off topic from the title question, and this isn't codereview.SE.
I'm new to assembly. I'm having different output for following simple code from what I expected. each time before printf is called, content of eax is shifted to the right by some number. What am I doing wrong? Thanks.
Code:
;file name : testing.asm
;assemble and link with:
;nasm -f elf testing.asm && gcc -m32 -o testing testing.o
extern printf ; the C function, to be called
SECTION .data ; Data section, initialized variables
a: dd 15 ; int a=15
str: db "content in eax=%d", 10, 0
SECTION .text ; Code section.
global main ; the standard gcc entry point
main: ; the program label for the entry point
mov ebp, esp
mov eax, [a] ; put a from store into register
shr eax, 1 ; eax content should be 15>>1 = 7
push eax
push dword str ; string to be printed
call printf ; printf(str,content_of_eax)
shr eax, 2
push eax ; eax content should be 7>>2 = 1
push dword str
call printf ; printf(str,content_of_eax)
shr eax, 1
push eax ; eax content should be 1>>1 = 0
push dword str
call printf ; printf(str,content_of_eax)
mov esp, ebp ; takedown stack frame
mov eax, 0 ; normal, no error, return value
ret ; return
Output:
content in eax=7
content in eax=4
content in eax=8
Expected Output:
content in eax=7
content in eax=1
content in eax=0
printf returns its result in eax, the original value is lost.
You should reload it from [a] or use a register that is saved across function calls such as esi, but you should save it as well and restore it before returning to the caller. You should pop the arguments passed to printf with a add esp,8 after each call to keep your stack frame consistent.
In your data section you could just use an equate for a since you only use that variable once and do not change it (i'll call it value).
fmt db "content in eax=%d",0xa,0
value equ 15
In the main function i'm pretty sure (correct me if i'm wrong) that you're supposed to save the base pointer before you update it with the stack pointer.
main:
push ebp
mov ebp, esp
Now you could create a local variable to store the current value you are working on.
sub esp, 4
From there you would just keep fetching, shifting and storing the value on the stack before each call to printf.
mov eax, value ; move 15 into eax
shr eax, 1 ; make first shift
mov dword[ebp-4], eax ; store result in local variable
push eax ; eax = 7
push fmt
call printf
add esp, 8 ; clean eax & fmt off the stack
mov eax, [ebp-4] ; fetch last shift result from variable
shr eax, 2 ; make second shift
mov dword[ebp-4], eax ; store result back in variable
push eax ; eax = 1
push fmt
call printf
add esp, 8
mov eax, [ebp-4] ; fetch last shift result from variable
shr eax, 1 ; make last shift
push eax ; eax = 0
push fmt
call printf
add esp, 8
add esp, 4 ; clean local variable
And then remember, before you return, when you release the stack frame that you also restore (pop) the base pointer.
mov esp, ebp
pop ebp
This should output:
content in eax=7
content in eax=1
content in eax=0
Remember that printf will return the number of characters transmitted to the output. So when you do this:
call printf ; printf(str,content_of_eax)
shr eax, 2
You are actually shifting the result from printf:
"content in eax=7\n" is 17 characters, so shitfting by 2 gives: 17 / 4 = 4
You need to save the value (either in a preserved register, on the stack or in memory) before shifting.
This answer seems not to be a good solution, I'm currently keeping it because of the discussion below
Like others said, printf will return it's result to eax. The result of printf is the number of bytes written.
Since you pushed the result of the shr operation to the stack, you can retrieve them again using pop, like this:
shr eax, 1 ; eax content should be 15>>1 = 7
push eax
push dword str ; string to be printed
call printf ; printf(str,content_of_eax)
pop eax
pop eax
shr eax, 2
push eax ; eax content should be 7>>2 = 1
push dword str
call printf ; printf(str,content_of_eax)
# and so on ...
I am trying to make an assembly program for finding GCD, takes in two integers, and prints out the GCD. The code assembles fine, however the program gets stuck in an infinite loop after both integers have been submitted:
;Title - GCD
INCLUDE Irvine32.inc
.data
strA BYTE "Enter an integer A: ",0
strB BYTE "Enter an integer B: ",0
temp DWORD ?
finalStr BYTE "GCD of the two integers is: ",0
.code
main PROC
call Clrscr
mainLoop:
mov edx,OFFSET strA
call WriteString
call ReadInt
mov temp, eax
call Crlf
mov edx, OFFSET strB
call WriteString
call ReadInt
mov ebx, eax
mov eax, temp
call Crlf
call GCD
mov edx, OFFSET finalStr
call WriteString
call WriteInt
call WaitMsg
jmp mainLoop
main ENDP
;-----------------------------------------------
abs PROC
; Computes the absolute value of a number.
; Receives: eax = the number
; Returns: eax = absolute value of the number
;-----------------------------------------------
cmp eax, 0 ; see if we have a negative number
jge done
neg eax
done:
ret
abs ENDP
;-----------------------------------------------
gcd PROC
; Finds Greatest Common Divisor of two integers
; Recieves: eax= int A , ebx = int B
; Returns eax = GCD
;-----------------------------------------------
call abs ;takes absolute value of both registers
mov temp, eax
mov eax, ebx
call abs
mov eax, temp
cmp eax, ebx ; making sure we divide the bigger number by the smaller
jz DONE ; if numbers are equal, GCD is eax either way
jc SWITCH ;swaps if ebx is larger then eax
mov edx, 0
SWITCH: ;swaps values so eax is larger then ebx
mov temp, eax
mov eax, ebx
mov ebx, temp
mov edx, 0
jmp L1
L1: ;divides until remainder is 0, then eax is GCD
div ebx
cmp edx, 0
jz DONE
mov eax, edx
jmp L1
DONE:
gcd ENDP
END main
How can I get out of this loop?
I see one problem straight up:
call abs ;takes absolute value of both registers
mov temp, eax
mov eax, ebx
call abs
mov eax, temp
There's nothing there moving the abs-ed ebx value back into ebx, it should be:
call abs ;takes absolute value of both registers
mov temp, eax
mov eax, ebx
call abs
mov ebx, eax
mov eax, temp
Another issue, though not directly related to your problem, is that the x86 architecture has long had an xchg instruction that would greatly clean up your code, specifically the use of temp.
And think about this sequence:
cmp eax, ebx ; making sure we divide the bigger number by the smaller
jz DONE ; if numbers are equal, GCD is eax either way
jc SWITCH ;swaps if ebx is larger then eax
mov edx, 0
SWITCH: ;swaps values so eax is larger then ebx
You'll find that the code at SWITCH: is going to be run regardless of which value is larger.
You can fix that by changing:
jc SWITCH ; swaps if ebx is larger then eax
mov edx, 0
into:
jc SWITCH ; swaps if ebx is larger then eax
mov edx, 0
jmp L1
Beyond that, I'm going to suggest actually running that code in your head to get an understanding of how it works but, more importantly, how to think like a machine in such a way that you become a better developer.
Start with the following table:
[temp] eax ebx edx <stack>
-------- -------- -------- -------- --------
? ? ? ? ?,
Then execute each line in turn, filling in the columns as data changes.
You'll eventually figure out where the problem is coming from and you'll also understand why sometimes the older guys that only ever had this means to debug are much better at it :-)
I'll give you a clue. Keep a particular eye on edx and see how that's changing, and how it's likely to affect certain other instructions, like div, that may depend on it being zero.