Value of unused variable changing after subroutine call - Assembly - gcc

I am pretty new to assembly that I'm learning from the last 7 hours (It's an early peek into the courses I had in the next semester starting next month). I read some online tutorials, and the nasm manual and started to port a C program to nasm, just for learning.
int fact(int n)
{
return (n < 0) ? 1 : n * fact(n - 1);
}
I then started to port it to assembly, and had this as my solution:
fact:
; int fact(int n)
cmp dword ebx, 0 ; n == 0
je .yes
.no:
push ebx ; save ebx in stack
sub ebx, dword 1 ; sub 1 from ebx. (n - 1)
call fact ; call fact recursively
pop ebx ; get back the ebx from stack
imul eax, ebx ; eax *= ebx; eax == fact(n - 1)
ret
.yes:
mov eax, dword 1 ; store 1 in eax to return it
ret
I take in a DWORD (int I suppose) in the ebx register and return the value in the eax register. As you can see I am not at all using the variable i that I have declared in the .bss section. My variables are like this:
section .bss
; int i, f
i resb 2
f resb 2
It's 2 bytes for an int right? Okay then I'm prompting the user in the _main, getting the input with _scanf and then calling the function. Other than this and calling the function, I have no other code that changes the value of i variable.
mov ebx, dword [i] ; check for validity of the factorial value
cmp dword ebx, 0
jnl .no
.yes:
push em ; print error message and exit
call _printf
add esp, 4
ret
.no:
push dword 0 ; print the result and exit
push dword [i]
push rm
call _printf
add esp, 12
call fact ; call the fact function
mov dword [f], eax
push dword [f] ; print the result and exit
push dword [i]
push rm
call _printf
add esp, 12
ret
I don't see where I'm modifying the value of i variable, on first print before the call to fact it is indeed the same value entered by the user, but after calling the function, in the later print, it is printing some garbage value, as the following output:
E:\ASM> factorial
Enter a number: 5
The factorial of 5 is 0The factorial of 7864325 is 120
E:\ASM>
Any clues? My complete source code is in this gist: https://gist.github.com/sriharshachilakapati/70049a778e12d8edd9c7acf6c2d44c33

Related

I'm unsure what the problem with my assembly code it works until eax is popped and replaced by a register

; Input x and y, output min of the two numbers
.586
.MODEL FLAT
INCLUDE io.h
.STACK 4096
.DATA
number DWORD ?
array DWORD 20, 15, 62, 40, 18
nbrElts DWORD 5
prompt BYTE "Enter value:", 0
string BYTE 80 DUP (?)
resultLbl BYTE "Position", 0
result BYTE 11 DUP (?), 0
.CODE
_MainProc PROC
input prompt, string, 20 ; read ASCII characters
atod string ; convert to integer
mov number, eax ; store in memory
push nbrElts ; 3rd parameter (# of elements in array)
lea eax, array ; 2nd parameter (address of array)
push eax
push number ; 1st parameter (value from user)
call searchArray ; searchArray(number, array, 5)
add esp, 12
dtoa result, eax ; convert to ASCII characters
output resultLbl, result ; output label and result
mov eax, 0 ; exit with return code 0
ret
_MainProc ENDP
; searchArray(int x, array, int y)
;
searchArray PROC
push ebp ; save base pointer
mov ebp, esp ; establish stack frame
push eax ; save registers
push ebx
push esi
push ecx
push edx
mov ebx, [ebp+8] ; x, value from user
mov esi, [ebp+12] ; address of array
mov ecx, [ebp+16] ; y, number of elements
mov edx, 1
mov ecx, 5
forLoop:
mov eax, [esi] ; a[i]
cmp eax, ebx ; eax = ebx ?
je isEqual
;cmp eax, ebx
add esi, 4
inc edx
loop forLoop
;mov eax, 0
cmp edx, 6
je notEqual
isEqual:
mov eax, edx
jmp exitCode
notEqual:
mov eax, 0
jmp exitCode
exitCode:
mov eax, edx
pop edx ; restore EBP
pop ecx ; restore EAX
pop esi
pop ebx
pop ebp
ret ; return
searchArray ENDP
END ; end of source code
The pops at the end of the function need to match the pushes at the beginning of the function. If they don't match, the stack pointer ends up in the wrong place and the ret returns to the wrong place.
In your case, you have an extra push without a corresponding pop.
The reason to push registers at the beginning and pop them at the end is to preserve their values. But you don't want to preserve the value of eax. You want to return a different value, the result of the function. So there is absolutely no reason to push eax.

80x86 assembly code not returning from function and displaying output

The goal of the program is to calculate a GCD of two numbers using a recursive function defined by this pseudo code
unsigned int gcd ( unsigned int a, unsigned int b ) {
if ( a > b )
return gcd ( a - b, b ) ;
if ( a < b )
return gcd ( a, b - a ) ;
return a ;
}
Here is the (undoubtedly poor) assembly code I'm having issues with.
.586
.MODEL FLAT
INCLUDE io.h
.STACK 4096
.DATA
a DWORD ?
b DWORD ?
prompt1 BYTE "a: ", 0
prompt2 BYTE "b:", 0
string BYTE 20 DUP (?)
resultLbl BYTE "gcd:", 0
result BYTE 11 DUP (?), 0
.CODE
_MainProc PROC
input prompt1, string, 20
atod string
mov a, eax
input prompt2, string, 20
atod string
mov b, eax
push b
push a
call _gcd
add esp, 8
dtoa result, eax
output resultLbl, result
mov eax, 0
ret
_MainProc ENDP
_gcd PROC
push ebp
mov ebp, esp
push ebx
push eax
mov eax, [ebp+8]
mov ebx, [ebp+12]
cmp eax, ebx
jg loop1
cmp eax, ebx
jl loop2
pop ebx
pop ebp
ret
loop1:
push ebx
sub eax, ebx
push eax
call _gcd
loop2:
sub ebx, eax
push ebx
push eax
output did2, result
call _gcd
_gcd ENDP
END
By creating some outputs in the loops to display a message when they occur I can tell that the program is calculating the GCD correctly however as soon as both values are equal and "ret" is hit inside of _gcd the program terminates. What do I need to change so the GCD value is returned and displayed correctly?

How to echo memory location use NASM [duplicate]

I am looking for a way to print an integer in assembler (the compiler I am using is NASM on Linux), however, after doing some research, I have not been able to find a truly viable solution. I was able to find a description for a basic algorithm to serve this purpose, and based on that I developed this code:
global _start
section .bss
digit: resb 16
count: resb 16
i: resb 16
section .data
section .text
_start:
mov dword[i], 108eh ; i = 4238
mov dword[count], 1
L01:
mov eax, dword[i]
cdq
mov ecx, 0Ah
div ecx
mov dword[digit], edx
add dword[digit], 30h ; add 48 to digit to make it an ASCII char
call write_digit
inc dword[count]
mov eax, dword[i]
cdq
mov ecx, 0Ah
div ecx
mov dword[i], eax
cmp dword[i], 0Ah
jg L01
add dword[i], 48 ; add 48 to i to make it an ASCII char
mov eax, 4 ; system call #4 = sys_write
mov ebx, 1 ; file descriptor 1 = stdout
mov ecx, i ; store *address* of i into ecx
mov edx, 16 ; byte size of 16
int 80h
jmp exit
exit:
mov eax, 01h ; exit()
xor ebx, ebx ; errno
int 80h
write_digit:
mov eax, 4 ; system call #4 = sys_write
mov ebx, 1 ; file descriptor 1 = stdout
mov ecx, digit ; store *address* of digit into ecx
mov edx, 16 ; byte size of 16
int 80h
ret
C# version of what I want to achieve (for clarity):
static string int2string(int i)
{
Stack<char> stack = new Stack<char>();
string s = "";
do
{
stack.Push((char)((i % 10) + 48));
i = i / 10;
} while (i > 10);
stack.Push((char)(i + 48));
foreach (char c in stack)
{
s += c;
}
return s;
}
The issue is that it outputs the characters in reverse, so for 4238, the output is 8324. At first, I thought that I could use the x86 stack to solve this problem, push the digits in, and pop them out and print them at the end, however when I tried implementing that feature, it flopped and I could no longer get an output.
As a result, I am a little bit perplexed about how I can implement a stack in to this algorithm in order to accomplish my goal, aka printing an integer. I would also be interested in a simpler/better solution if one is available (as it's one of my first assembler programs).
One approach is to use recursion. In this case you divide the number by 10 (getting a quotient and a remainder) and then call yourself with the quotient as the number to display; and then display the digit corresponding to the remainder.
An example of this would be:
;Input
; eax = number to display
section .data
const10: dd 10
section .text
printNumber:
push eax
push edx
xor edx,edx ;edx:eax = number
div dword [const10] ;eax = quotient, edx = remainder
test eax,eax ;Is quotient zero?
je .l1 ; yes, don't display it
call printNumber ;Display the quotient
.l1:
lea eax,[edx+'0']
call printCharacter ;Display the remainder
pop edx
pop eax
ret
Another approach is to avoid recursion by changing the divisor. An example of this would be:
;Input
; eax = number to display
section .data
divisorTable:
dd 1000000000
dd 100000000
dd 10000000
dd 1000000
dd 100000
dd 10000
dd 1000
dd 100
dd 10
dd 1
dd 0
section .text
printNumber:
push eax
push ebx
push edx
mov ebx,divisorTable
.nextDigit:
xor edx,edx ;edx:eax = number
div dword [ebx] ;eax = quotient, edx = remainder
add eax,'0'
call printCharacter ;Display the quotient
mov eax,edx ;eax = remainder
add ebx,4 ;ebx = address of next divisor
cmp dword [ebx],0 ;Have all divisors been done?
jne .nextDigit
pop edx
pop ebx
pop eax
ret
This example doesn't suppress leading zeros, but that would be easy to add.
I think that maybe implementing a stack is not the best way to do this (and I really think you could figure out how to do that, saying as how pop is just a mov and a decrement of sp, so you can really set up a stack anywhere you like by just allocating memory for it and setting one of your registers as your new 'stack pointer').
I think this code could be made clearer and more modular if you actually allocated memory for a c-style null delimited string, then create a function to convert the int to string, by the same algorithm you use, then pass the result to another function capable of printing those strings. It will avoid some of the spaghetti code syndrome you are suffering from, and fix your problem to boot. If you want me to demonstrate, just ask, but if you wrote the thing above, I think you can figure out how with the more split up process.
; Input
; EAX = pointer to the int to convert
; EDI = address of the result
; Output:
; None
int_to_string:
xor ebx, ebx ; clear the ebx, I will use as counter for stack pushes
.push_chars:
xor edx, edx ; clear edx
mov ecx, 10 ; ecx is divisor, devide by 10
div ecx ; devide edx by ecx, result in eax remainder in edx
add edx, 0x30 ; add 0x30 to edx convert int => ascii
push edx ; push result to stack
inc ebx ; increment my stack push counter
test eax, eax ; is eax 0?
jnz .push_chars ; if eax not 0 repeat
.pop_chars:
pop eax ; pop result from stack into eax
stosb ; store contents of eax in at the address of num which is in EDI
dec ebx ; decrement my stack push counter
cmp ebx, 0 ; check if stack push counter is 0
jg .pop_chars ; not 0 repeat
mov eax, 0x0a
stosb ; add line feed
ret ; return to main
; eax = number to stringify/output
; edi = location of buffer
intToString:
push edx
push ecx
push edi
push ebp
mov ebp, esp
mov ecx, 10
.pushDigits:
xor edx, edx ; zero-extend eax
div ecx ; divide by 10; now edx = next digit
add edx, 30h ; decimal value + 30h => ascii digit
push edx ; push the whole dword, cause that's how x86 rolls
test eax, eax ; leading zeros suck
jnz .pushDigits
.popDigits:
pop eax
stosb ; don't write the whole dword, just the low byte
cmp esp, ebp ; if esp==ebp, we've popped all the digits
jne .popDigits
xor eax, eax ; add trailing nul
stosb
mov eax, edi
pop ebp
pop edi
pop ecx
pop edx
sub eax, edi ; return number of bytes written
ret

Recursion in Assembly

I need help with Assembly code which I just started learning.
.intel_syntax noprefix;
.text;
.globl main;
main:
mov eax, 3;
mov ebx, 0;
push eax;
push ebx;
call f;
add esp, 8;
push eax;
mov eax, offset message;
push eax;
call printf
add esp,8;
mov eax,0;
ret;
f:
mov eax, [esp+8];
mov ebx, [esp+4];
cmp eax,3;
jge ety2;
cmp eax,2;
je ety1;
cmp eax,0;
je ety1;
cmp eax,1;
je ety3;
ety3:
mov eax,0;
ret;
ety1:
mov eax,1;
ret;
ety2:
xor ebx,ebx;
dec eax;
push eax;
push ebx;
call f;
add esp,8;
add ebx,[esp+4];
add ebx,eax;
mov eax,[esp+8];
dec eax;
dec eax;
push eax;
push ebx;
call f;
add esp,8;
add ebx,[esp+4];
add ebx,eax;
add ebx,eax;
mov eax,[esp+8];
dec eax;
dec eax;
dec eax;
push eax;
push ebx;
call f;
add esp,8;
add ebx,[esp+4];
sub ebx,eax;
mov eax,[esp+8];
mov eax,ebx;
ret;
.data;
message:
.asciz "Result=%i\n";
.att_syntax prefix;
In main function 'eax' register is used as a 'n' parameter for function that:
for n=0 or n=2 returns 1;
for n=1 returns 0;
for n>=3 returns f(n-1)+(2*f(n-2))-f(n-3);
So for n=3 function returns 0, n=4 returns 2, n=5 returns 1, n=6 returns 5 e.t.c.
The recursion is pretty problematic, for values < 5 fuction works fine, but for 6, 7 e.t.c. function returns tremendously high or low (negative) values.
I've been working on it for +10 hours, and I can't manage to make it work
property. What am I doing wrong?
It is required to use "PUSH" and "[esp+4]", "add esp,4;" and other simple instructions that are already in the code.
Program is compiled under -m32 command parameter(gcc -Wall funcas.s -m32 -o test).
I wrote down the same code in C to show what i'm trying to achieve
#include <stdio.h>
#include <stdlib.h>
int funkcja(int n)
{
if(n>=3)
{
return (funkcja(n-1)+(2*funkcja(n-2))-funkcja(n-3));
}
else
{
if(n==2)return 1;
if(n==1)return 0;
if(n==0)return 1;
}
return -1;
}
int main()
{
int a=6;
printf("%d\n", funkcja(a));
return 0;
}
The problem is that the code keeps accumulating all of the results. Change f to only use one parameter. Example Microsoft type assembler code. In both f() and main(), n is stored on the stack.
.model flat,c
; ...
.data
fmt db '%d',00ah,000h
.code
extern printf:proc
public main
f proc ;int f(int n)
mov eax, [esp+4]
cmp eax,3
jge f2
cmp eax,2
je f1
cmp eax,1
je f0
cmp eax,0
je f1
mov eax,-1
ret
f0: mov eax,0
ret
f1: mov eax,1
ret
f2: push ebx ;save ebx
dec eax ;eax = n-1
push eax ;[esp] = n-1
call f ;eax = f(n-1)
mov ebx,eax ;ebx = f(n-1)
dec dword ptr [esp] ;[esp] = n-2
call f ;eax = f(n-2)
add eax,eax ;eax = 2*f(n-2)
add ebx,eax ;ebx = f(n-1) + 2*f(n-2)
dec dword ptr [esp] ;[esp] = n-3
call f ;eax = f(n-3)
add esp,4 ;restore esp
sub ebx,eax ;ebx = f(n-1) + 2*f(n-2) - f(n-3)
mov eax,ebx ;eax = f(n-1) + 2*f(n-2) - f(n-3)
pop ebx ;restore ebx
ret
f endp
main proc near
push dword ptr 0 ;[esp] = n
main0: call f
push eax
push offset fmt
call printf
add esp,8
inc dword ptr [esp]
cmp dword ptr [esp],20
jl main0
add esp,4
xor eax,eax
ret
main endp
I don't understand your action with EBX and the second argument on the stack.
Let's start from scratch. A recursive function is a function as well. When you call it you have to preserve registers which can be altered by the function and you need unaltered after the function return. The function calls itself three times with different n and operates with the different results. While you've got n on the stack for arbitrary recovery, you have to preserve the results. It becomes more clear when you split return (funkcja(n-1)+(2*funkcja(n-2))-funkcja(n-3)); into
int result = 0;
result += funkcja(n-1);
result += ( 2 * funkcja(n-2) );
result -= funkcja(n-3);
return result;
result is a so called local variable. It's only needed for this run of the function and will lost with the function return. A local variable is usually stored on the stack. You don't need to build a stackframe with prolog and epilog, a simple push/pop combination will do it as well.
# f(n) = f(n-1) + (2*f(n-2)) - f(n-3)
# 0 1
# 1 0
# 2 1
# 3 0 1 + 0 - 1
# 4 2 0 + 2 - 0
# 5 1 2 + 0 - 1
# 6 5 1 + 4 - 0
# 7 5 5 + 2 - 2
# 8 14 5 + 10 - 1
# 9 19 14 + 10 - 5
.intel_syntax noprefix
.text
.globl main
main:
mov eax, 9
push eax
call funkcja
add esp, 4
push eax
mov eax, offset message
push eax
call printf
add esp,8
mov eax,0
ret
funkcja:
mov eax, [esp+4]
cmp eax,3
jge 3f
2:
cmp eax,2
jne 0f
mov eax, 1
ret
0:
cmp eax,0
jne 1f
mov eax, 1
ret
1:
xor eax, eax
ret
3:
push 0 # Result = 0
# 1. Call
mov eax, [esp+8] # +8: retrieve n behind push and return address
sub eax, 1
push eax
call funkcja
add esp, 4
add [esp], eax # Result += EAX
# 2. Call
mov eax, [esp+8] # +8: retrieve n behind push and return address
sub eax, 2
push eax
call funkcja
add esp, 4
add eax, eax
add [esp], eax # Result += EAX
# 3. Call
mov eax, [esp+8] # +8: retrieve n behind push and return address
sub eax, 3
push eax
call funkcja
add esp, 4
sub [esp], eax # Result -= EAX
pop eax # Return EAX = Result
ret
.data;
message: .asciz "Result=%i\n"
.att_syntax prefix

NASM mov from register to memory

I know there are lots of references out there talking about NASM and mov but either I'm missing something fundamental or people need to write better help guides!
SECTION .data
fmtStart: db "Enter two numbers in format '# #'", 10, 0
fmtTest: db "sum: %d", 10, 0
input: db "%d %d", 0
SECTION .bss ; BSS, uninitialized variables
int1: resd 1
int2: resd 1
sum: resd 1
SECTION .text ; Code section.
global main ; the standard gcc entry point
main: ; the program label for the entry point
push ebp ; set up stack frame
mov ebp,esp
;; Get the data
push dword fmtStart
call printf
add esp, 4
push dword int2
push dword int1
push dword input
call scanf
add esp, 12
;; Do calculations
;; Add
xor eax, eax
mov eax, [int1]
add eax, [int2]
mov [sum], eax
push dword sum
push dword fmtTest
call printf
add esp, 24
mov esp, ebp ; take down stack frame
pop ebp ; same as "leave" op
mov eax,0 ; normal, no error, return value
ret ; return
I get:
Enter two numbers in format '# #'
2 3
sum: 4247592
which isn't what I get when I add 2 and 3 with my calculator, maybe that's just me though.
my understanding of the code is as follows: the data section declares variables that are initialized to stuff, in this case my formatted strings; the bss section is for uninitialized variables, in this case my input vars and the sum var; the text section is where the code goes; I declare main as the entry point for gcc; I prompt the user for two numbers; I zero out eax with the xor; move the value of int1 to eax; add the value of int2 to eax; move what's in eax to be the value of sum; push it onto the stack with the formatted string; call printf to display stuff; end the program.
--EDIT--
To be clear, either add isn't working or mov isn't working. It seems like add should be working so I'm assuming it's mov. I don't understand what about mov [var], register would be wrong but obviously something isn't right!
Here's the problem:
push dword sum
push dword fmtTest
call printf
printf, unlike scanf, takes its arguments (after the format) by value, while in your code sum is the address of the memory location. Just do:
push [sum]
push fmtTest
call printf
(incidentally, the xor eax,eax before the mov eax,[int1] is useless, since you are immediately rewriting the content of the register)

Resources