HLA Assembly Recursive Fibonacci Program - recursion

I have written some code to solve this prompt:
Create an HLA Assembly language program that prompts for a number from the user. Create and call a function that calculates a value in the Fibonacci sequence. In mathematics, the Fibonacci sequence is named after the Italian mathematician Leonardo of Pisa who was known during his lifetime as Fibonacci. The Fibonacci sequence starts with 1 and 1. Each later term in the sequence is the sum of the two previous values. So the series will be: 1,1,2,3,5,8,13 and so on. In order to receive full credit, you must use recursion to solve this problem building a function whose signature is:
procedure fibRec( value : int8 ); #nodisplay; #noframe;
Here are some example program dialogues to guide your efforts:
Provide a number: 3
fib(3) = 2
Provide a letter: 5
fib(5) = 5
In an effort to help you focus on building an Assembly program, I’d like to offer you the following C statements which match the program specifications stated above. If you like, use them as the basis for building your Assembly program.
SAMPLE C CODE:
------------------------
int main( )
{
int value;
printf( "Provide a value: " );
scanf( "%d", &value );
int f = fibRec( value );
printf( "fib( %d ) = %d\n", value, f );
return( 0 );
}
int fibRec( int value )
{
int result = 1;
if (value == 1 || value == 2) // base case
result = 1;
else
result = fibRec( value-1 ) + fibRec( value-2 );
return( result );
}
and my approach is to try to use the C implementation and convert it to HLA.
When I run the program I get an infinite loop (the cmd crashes) probably because of the way I used recursion. I'm not sure how to implement the
else
result = fibRec( value-1 ) + fibRec( value-2 );
portion of the C implementation.
Here is what I have:
program fib;
#include("stdlib.hhf");
static
value : int8;
//returnAddress : dword;
//temp: int16;
procedure fibRec( value : int8 ); #nodisplay; #noframe;
begin fibRec;
mov(CL, value);
mov(1, DL);
cmp(CL, 1);
je Res1;
cmp(CL, 2);
je Res1;
jmp Else1;
//else result = fibRec( value-1 ) + fibRec( value-2 );
Else1:
//mov(1, DL);
dec(CL);
call fibRec;
sub(2, CL);
call fibRec;
add(CL, DL);
jmp ProgExit;
Res1:
mov(1, DL);
jmp ProgExit;
ProgExit:
end fibRec;
/////////////////////////////////////////////////////////////////////////////////////////////////////
begin fib;
stdout.put( "Provide a value: " );
stdin.get(value); //CHANGED TO IVALUE
mov(CL, value); //SAVES THE INPUT TO A REGISTER
call fibRec; // MUST CALL THE PROCEDURE
stdout.put("fib(");
stdout.puti8(value);
stdout.put(") = ");
stdout.put(DL);
end fib;

Learn how to debug your code, there are obvious problems if you would try to step over it, like at the beginning you overwrite user input with value in CL.
Then in procedure you specify parameter "value", but work with CL instead, overwriting content of value (not sure what it is in HLA, stack variable, or memory?).
You use CL/DL 8 bit registers for values, but C example uses int (32b signed).
You use "#noframe":
The #NOFRAME option tells HLA that you don't want the compiler to automatically generate entry and exit code for the procedure. This tells HLA not to automatically generate the RET instruction (along with several other instructions).
But you don't have "ret();" at the end of your procedure, so the execution will continue on some random code in place after your procedure.
And finally about your recursion problem.
ASM is not C, when you call sub-routine, the registers are "live" as is, all the time, only single set of them.
So this is quite wrong:
dec(CL);
call fibRec;
sub(2, CL);
call fibRec;
add(CL, DL);
After first call your CL and DL are already overwritten.
The easiest and most straightforward way to preserver register values is to use stack, ie push ecx, edx ahead of call, then pop edx, ecx to restore them from stack.
For example, the fib. subroutine written in x86 32b assembler (NASM Intel syntax! So it's mov destination, source, the other way than your HLA!):
fibRecursion:
; expects unsigned "n" (1+) in eax, returns fibonacci(n) in eax
; will crash on large "n" due to stack overflow
cmp eax,2
ja moreThanTwo
mov eax,1 ; n: 0, 1 and 2 returns "1"
ret
moreThanTwo:
push edx ; preserve edx
dec eax
push eax ; store n-1 in stack
call fibRecursion ; eax = fib(n-1)
xchg eax,[esp] ; store fib(n-1) in stack, get n-1 into eax
dec eax
call fibRecursion ; eax = fib(n-2)
pop edx ; edx = fib(n-1)
add eax,edx ; eax = fib(n) = eax+edx
pop edx ; restore edx
ret
Yep, so now you have just to fix the syntax for HLA... (more like rewrite it, so you make sure you understand how it works).
And learn how to debug your code, I think I forgot to mention this.
Also did I mention you should debug your code?
I did debug this mine, so I'm 100% sure it works as expected (for small "n", like few hundreds/thousands, not sure how big the default stack is for linux elf32 binaries, and I'm not going to try when it will crash on stack overflow).

Related

Return a pointer at a specific position - Assembly

I am a beginner in Assembly and i have a simple question.
This is my code :
BITS 64 ; 64−bit mode
global strchr ; Export 'strchr'
SECTION .text ; Code section
strchr:
mov rcx, -1
.loop:
inc rcx
cmp byte [rdi+rcx], 0
je exit_null
cmp byte [rdi+rcx], sil
jne .loop
mov rax, [rdi+rcx]
ret
exit_null:
mov rax, 0
ret
This compile but doesn't work. I want to reproduce the function strchr as you can see. When I test my function with a printf it crashed ( the problem isn't the test ).
I know I can INC rdi directly to move into the rdi argument and return it at the position I want.
But I just want to know if there is a way to return rdi at the position rcx to fix my code and probably improve it.
Your function strchr seems to expect two parameters:
pointer to a string in RDI, and
pointer to a character in RSI.
Register rcx is used as index inside the string? In this case you should use al instead of cl. Be aware that you don't limit the search size. When the character refered by RSI is not found in the string, it will probably trigger an exception. Perhaps you should test al loaded from [rdi+rcx] and quit further searching when al=0.
If you want it to return pointer to the first occurence of character
inside the string, just
replace mov rax,[rdi+rcx] with lea rax,[rdi+rcx].
Your code (from edit Version 2) does the following:
char* strchr ( char *p, char x ) {
int i = -1;
do {
if ( p[i] == '\0' ) return null;
i++;
} while ( p[i] != x );
return * (long long*) &(p[i]);
}
As #vitsoft says, your intention is to return a pointer, but in the first return (in assembly) is returning a single quad word loaded from the address of the found character, 8 characters instead of an address.
It is unusual to increment in the middle of the loop.  It is also odd to start the index at -1.  On the first iteration, the loop continue condition looks at p[-1], which is not a good idea, since that's not part of the string you're being asked to search.  If that byte happens to be the nul character, it'll stop the search right there.
If you waited to increment until both tests are performed, then you would not be referencing p[-1], and you could also start the index at 0, which would be more usual.
You might consider capturing the character into a register instead of using a complex addressing mode three times.
Further, you could advance the pointer in rdi and forgo the index variable altogether.
Here's that in C:
char* strchr ( char *p, char x ) {
for(;;) {
char c = *p;
if ( c == '\0' )
break;
if ( c == x )
return p;
p++;
}
return null;
}
Thanks to your help, I finally did it !
Thanks to the answer of Erik, i fixed a stupid mistake. I was comparing str[-1] to NULL so it was making an error.
And with the answer of vitsoft i switched mov to lea and it worked !
There is my code :
strchr:
mov rcx, -1
.loop:
inc rcx
cmp byte [rdi+rcx], 0
je exit_null
cmp byte [rdi+rcx], sil
jne .loop
lea rax, [rdi+rcx]
ret
exit_null:
mov rax, 0
ret
The only bug remaining in the current version is loading 8 bytes of char data as the return value instead of just doing pointer math, using mov instead of lea. (After various edits removed and added different bugs, as reflected in different answers talking about different code).
But this is over-complicated as well as inefficient (two loads, and indexed addressing modes, and of course extra instructions to set up RCX).
Just increment the pointer since that's what you want to return anyway.
If you're going to loop 1 byte at a time instead of using SSE2 to check 16 bytes at once, strchr can be as simple as:
;; BITS 64 is useless unless you're writing a kernel with a mix of 32 and 64-bit code
;; otherwise it only lets you shoot yourself in the foot by putting 64-bit machine code in a 32-bit object file by accident.
global mystrchr
mystrchr:
.loop: ; do {
movzx ecx, byte [rdi] ; c = *p;
cmp cl, sil ; if (c == needle) return p;
je .found
inc rdi ; p++
test cl, cl
jnz .loop ; }while(c != 0)
;; fell out of the loop on hitting the 0 terminator without finding a match
xor edi, edi ; p = NULL
; optionally an extra ret here, or just fall through
.found:
mov rax, rdi ; return p
ret
I checked for a match before end-of-string so I'd still have the un-incremented pointer, and not have to decrement it in the "found" return path. If I started the loop with inc, I could use an [rdi - 1] addressing mode, still avoiding a separate counter. That's why I switched up the order of which branch was at the bottom of the loop vs. your code in the question.
Since we want to compare the character twice, against SIL and against zero, I loaded it into a register. This might not run any faster on modern x86-64 which can run 2 loads per clock as well as 2 branches (as long as at most one of them is taken).
Some Intel CPUs can micro-fuse and macro-fuse cmp reg,mem / jcc into a single load+compare-and-branch uop for the front-end, at least when the memory addressing mode is simple, not indexed. But not cmp [mem], imm/jcc, so we're not costing any extra uops for the front-end on Intel CPUs by separately loading into a register. (With movzx to avoid a false dependency from writing a partial register like mov cl, [rdi])
Note that if your caller is also written in assembly, it's easy to return multiple values, e.g. a status and a pointer (in the not-found case, perhaps to the terminating 0 would be useful). Many C standard library string functions are badly designed, notably strcpy, to not help the caller avoid redoing length-finding work.
Especially on modern CPUs with SIMD, explicit lengths are quite useful to have: a real-world strchr implementation would check alignment, or check that the given pointer isn't within 16 bytes of the end of a page. But memchr doesn't have to, if the size is >= 16: it could just do a movdqu load and pcmpeqb.
See Is it safe to read past the end of a buffer within the same page on x86 and x64? for details and a link to glibc strlen's hand-written asm. Also Find the first instance of a character using simd for real-world implementations like glibc's using pcmpeqb / pmovmskb. (And maybe pminub for the 0-terminator check to unroll over multiple vectors.)
SSE2 can go about 16x faster than the code in this answer for non-tiny strings. For very large strings, you might hit a memory bottleneck and "only" be about 8x faster.

TASM struct initilization and pointer math issues

I am attempting to write a simple DOS test program in assembly using TASM v4.1 that walks through a structure that contains four strings of equal length, but I've hit two issues.
ideal
model small
stack 1024
struc Strings_s
s1 db 32 dup (?)
s2 db 32 dup (?)
s3 db 32 dup (?)
s4 db 32 dup (?)
ends Strings_s
codeseg
start:
mov ax, #data
mov ds, ax ; Set %DS to point to the data segment
mov cx, 4 ; Load loop count
mov si, offset mystrings.s1 ; Load seg offset of first string
start_1:
push si
call putstr ; Print asciiz string
pop si
;add si, offset (Strings_s ptr ds:0).s1 ; ***BROKEN***
add si, offset (Strings_s ptr ds:0).s2 ; FIXED
loop start_1 ; Loop
fin:
mov ax, 4C00h ; [DOS] terminate program
int 21h ; ...
putstr_0:
mov bx, 07h
mov ah, 0Eh ; [BIOS] Display character
int 10h ; ...
putstr:
lodsb ; Get next char from %SI
test al, al ; End of string?
jne putstr_0 ; no, loop
return:
ret ; Return to caller
LF equ 10
CR equ 13
dataseg
mystrings Strings_s <"One string","Two strings","Three strings","Four strings">
end start
The first issue is that I need to terminate the strings I'm declaring in the struct, but adding ,CR,LF,0 is misinterpreted as additional struct members and TASM doesn't see \r\n\0 as escape sequences.
The second issue is that I'm trying to add the length Strings_s.s1 without hard coding 32 into my code. I first tried using the sizestr directive on the struct member, but even with version t300 defined before the ideal directive, TASM considers it an undefined symbol. So then I tried the example I included using the offset and struct cast, but it ends up being encoded as add si,0.
Ideas?
EDIT: The second issue turned out to be a simple error. You need to offset to the second member of the struct. (code fixed)
EDIT2: The sizestr directive only works against text macros and is really just a simple strlen of the text after the equ directive, so it isn't what I thought it was. I also tried slipping in a Strings_len EQU $-Strings_s between the s1 and s2 members, but it incorrectly equated to 23, not 32.

Issues with a recursive factorial: Segmentation fault

.global main
.type main%function
main:
ldr r1,[r1,#4] // take the argv[1]
ldrb r1,[r1] // take the value
sub r1,r1,#48 // convert from char to dec
mov r2,r1
push {ip,lr}
bl fact
pop {ip,lr}
ldr r0,=message
b printf
fact:
sub r2,r2,#1 // decrease the num
push {r2,lr} // save the num and lr
cmp r2,#1 // compare the num with 1
blne fact // if the num is NOT 1, then BL the fact subroutine recursively
pop {r2,lr} // if the num is 1, then start to restore the nums in the stack
mul r1,r1,r2 // and multiply them
bx lr // then returns
message:
.asciz "Factorial: %d"
If I execute it, I get this Segmentation Fault:
$ ./a.out
Segmentation fault
What could be the reason? I tried to remove the printf call to see if there were problems with printf, but still get the error, so there must be a problem inside fact subroutine.
Lol. I fixed the issue.
I just didn't pass any argument by commandline, so basically argv[1] is null, thus Segmentation fault.
I just need to execute with:
./a.out 7
for example 7 to do the factorial of 7.

I have trouble in understanding the output of the following code

I have the following program :
int main()
{
char arr[] = "geeksforgeeks";
char *ptr = arr;
while(*ptr != '\0')
++*ptr++;
printf("%s %s", arr, ptr);
getchar();
return 0;
}
Output: hffltgpshfflt
Explanation given is :
If one knows the precedence and associativity of the operators then there is nothing much left. Below is the precedence of operators.
Postfixx ++ left-to-right
Prefix ++ right-to-left
Dereference * right-to-left
Therefore the expression ++*ptr++ has following effect :
Value of *ptr is incremented
Value of ptr is incremented
My question is how this pointer expression ++*ptr++ is getting implemented and why does this statement "printf("%s %s", arr, ptr);" not printing the string "geeksforgeeks" as well ?
Please help.
Answer to --> why does this statement "printf("%s %s", arr, ptr);" not printing the string "geeksforgeeks" as well ?
Here,array elements of arr are incremented by 1 i.e.,g+1=h,e+1=f.... so on this is getting incremented by 1 due to ++*ptr which increments the ptr value .
ptr++ will incremented by one it means the ptr address is incremented by '1'. until the null character.
So, you are printing arr it shows the value as hffltgpshfflt and printing the ptr which is now pointing to NULL which prints nothing. you can check the ptr value by %x format it prints 0.

MPI send recv confusion

I have attached a sample of the MPI program I am trying to write. When I run this program using "mpirun -np 4 a.out", my output is:
Sender: 1
Data received from 1
Sender: 2
Data received from 1
Sender: 2
And the run hangs there. I dont understand why does the sender variable change its value after MPI_recv? Any ideas?
Thank you,
Pradeep
` program mpi_test
include 'mpif.h'
!----------------( Initialize variables )--------------------
integer, dimension(3) :: recv, send
integer :: sender, np, rank, ierror
call mpi_init( ierror )
call mpi_comm_rank( mpi_comm_world, rank, ierror )
call mpi_comm_size( mpi_comm_world, np, ierror )
!----------------( Main program )--------------------
! receive the data from the other processors
if (rank.eq.0) then
do sender = 1, np-1
print *, "Sender: ", sender
call mpi_recv(recv, 3, mpi_int, sender, 1,
& mpi_comm_world, status, ierror)
print *, "Data received from ",sender
end do
end if
! send the data to the main processor
if (rank.ne.0) then
send(1) = 3
send(2) = 4
send(3) = 4
call mpi_send(send, 3, mpi_int, 0, 1, mpi_comm_world, ierr)
end if
!----------------( clean up )--------------------
call mpi_finalize(ierror)
return
end program mpi_test`
This is a typical stack smashing scenario. You have not declared the status variable and hence the compiler automatically makes one REAL variable for you. But status should rather be an INTEGER array of MPI_STATUS_SIZE elements:
integer, dimension(MPI_STATUS_SIZE) :: status
What happens in your case is that status is too small to hold the real MPI status object and hence some of the other stack variables get overwritten. Simply declare status as it should be declared in order to solve the problem.
Another thing - modern Fortran supports the IMPLICIT NONE statement, which disables automatic declaration of undeclared variables. If you put implicit none immediately after the include statement, the compiler would generate an error message instead.

Resources