I am (as you would have already guessed) new to nasm coding and I am trying to code this simple combinatorial program (calculates combinations (nCr)) in nasm assembly analogous to this C code I made:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n = 9;
int r = 2;
int i = 0;
int npr = 1;
int rfac = 1;
int k = n;
//nPr
while (i<r)
{
npr = npr*(k);
k--;
i++;
}
//r!
while(r>0)
{
rfac = rfac*r;
r--;
}
//nPr/r! = nCr
printf("%d\n", npr/rfac);
return 0;
}
My imitation assembly code in nasm:
extern printf
SECTION .data
fmt: db "%d", 10, 0 ;format for printf (used once)
n: dq 10 ; 64 bit double var n = 10.000
r: dq 2 ; 64 bit int var r = 3
i: dq 0 ; 64 bit int var i = 0
npr: dq 1 ; 64 bit double var npr = 1.000
rfac: dq 1 ; 64 bit int var npr = 1
SECTION .text ; code section
global main
main:
push rbp ; base pointer
mov rax,[npr] ; load npr
mov rbx,[i] ; load i
mov rcx,[n] ; load n
mov rdx,[r] ; load r for condition checking
;sub rdx,[r] ; subtract n - r
;sub rdx,1 ; subtract (n = n-r) - 1. now we can compare it to rdx
jmp loop1 ; Jump to condition first
cloop1 imul rax,rcx ; multiply the word npr with n
dec rcx ; decrement n
inc rbx ; increment i
loop1 cmp rbx,rdx ; Check the condition
jl cloop1 ; Jump to content of the loop if met
mov rdx,[r] ; load r
mov rcx,[rfac] ; load rfac
mov rbx,0 ; set rbx to 0
jmp loop2 ; Jump to condition first
cloop2 imul rcx,rdx ; multiply the word rfac with r
dec rdx ; decrement r
loop2 cmp rbx,rdx ; Check the condition(0<=r)
jl cloop2 ; Jump to content of the loop if met
diva:
mov rdx,0
mov rax,rax
idiv rcx ; divide rax(npr) by rcx(rfac)
mov rsi,rax ; 1st printf var
xor rax,rax ; make it 0?
call printf ; call the function
pop rbp ; pop the stack
mov rax,0 ; exit code
ret ; return to OS from main
It kept giving me seg fault so i debugged it:
diva () at ncr.asm:43
43 mov rdx,0
(gdb) info registers
rax 0x5a 90
rbx 0x0 0
rcx 0x2 2
rdx 0x0 0
rsi 0x7ffffffedec8 140737488281288
rdi 0x1 1
rbp 0x400570 0x400570 <__libc_csu_init>
rsp 0x7ffffffedde0 0x7ffffffedde0
r8 0x7fffff3ecd80 140737475693952
r9 0x7fffff3ecd80 140737475693952
r10 0x2 2
r11 0x7 7
r12 0x400400 4195328
r13 0x7ffffffedec0 140737488281280
r14 0x0 0
r15 0x0 0
rip 0x400545 0x400545 <diva>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) next
44 mov rax,rax
(gdb) next
45 idiv rcx ; divide rax(npr) by rcx(rfac)
(gdb) next
46 mov rsi,rax ; 1st printf var
(gdb) next
47 xor rax,rax ; make it 0?
(gdb) next
48 call printf ; call the function
(gdb) next
Program received signal SIGSEGV, Segmentation fault.
__strchrnul_avx2 () at ../sysdeps/x86_64/multiarch/strchr-avx2.S:57
57 ../sysdeps/x86_64/multiarch/strchr-avx2.S: No such file or directory.
(gdb)
from what I see, the loops were fine and when i called the printf function it gave me the seg fault.
I've seen in some places that they push the format and then the function and then call it. I tried it but I think I did it wrong. Any advice/ criticism and downright profanity if needed on my code is welcome if you feel its constructive in my improvement.
EDIT: Changed "%f" to "%d" and these are the values in the registers just before the printf call:
(gdb) next
48 call printf ; call the function
(gdb) info registers
rax 0x0 0
rbx 0x0 0
rcx 0x2 2
rdx 0x0 0
rsi 0x2d 45
rdi 0x1 1
rbp 0x400570 0x400570 <__libc_csu_init>
rsp 0x7ffffffedde0 0x7ffffffedde0
r8 0x7fffff3ecd80 140737475693952
r9 0x7fffff3ecd80 140737475693952
r10 0x2 2
r11 0x7 7
r12 0x400400 4195328
r13 0x7ffffffedec0 140737488281280
r14 0x0 0
r15 0x0 0
rip 0x400556 0x400556 <diva+17>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0