0

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
mayank
  • 176
  • 1
  • 12

1 Answers1

0

I GOT IT!!!!

I DID IT I FINALLY SOLVED IT!!!

anyway here is the thing i used:

Instead of pushing the format as push fmt,

I instead read the nasm docs, saw some examples and found out that we have to store the format fmt in rdi and the variables in their respective order in rsi, rdx,rcx,r8 and so on.

so I did exactly that and BOOM! pops the answer on execution. MY JOY HAS NO LITERAL BOUNDS

repaired code:

        extern printf

        SECTION .data


fmt:    db "nCr = %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 rdi,fmt     ; storing format
        mov rsi,rax     ; 1st printf var
        mov rax,0       ; make it 0?        
        call printf     ; call the function
        
        pop rbp         ; pop the stack
        mov rax,0       ; exit code
        ret             ; return to OS from main
mayank
  • 176
  • 1
  • 12
  • 1
    Indeed, you have to know the proper calling conventions in order to be able to call C functions. The authoritative documentation, for Linux and other Unix-like OSes, is the [System V ABI](https://stackoverflow.com/questions/18133812/where-is-the-x86-64-system-v-abi-documented) which you ought to get familiar with. It also explains, for instance, why your `mov rax, 0` is needed before the call to `printf`. – Nate Eldredge Nov 20 '20 at 15:15