1

I am new to NASM and am trying to convert a 16-bit binary to decimal.

the code goes like this:

        extern printf
        SECTION .data


fmt:    db  "The resultant BCD is: ", 0
fmtshort:   db  "%lu    ", 0

binary: dq  1010                    ; 16 bit binary number (8 byte int) = 1001101010011010
msb:    dq  0                       ; most significant bit size int msv = 0 (initially)
divider:    dq  1                   ; used to isolate the msb of the decimal;

        SECTION .text               ; code section
        global main

main:
    push rbp                    ; base pointer
    mov rcx,[binary]                    ; loading it into binary value
    mov r14,0                   ; decimal(initially) = 0;
    mov r13,0                   ; counter(i) = 0;
    mov r15,0                   ; r15 = 0;
    mov rdi,fmt                 ; storing format in the 1st register
    call printf                 ; calling printf
    jmp getFromBinary               ; Jump to condition first

cgetFromBinary:
    mov rdx,0
    mov rax,rcx
    mov rbx,10
    div rbx
    mov rcx,rax                 ; remainder: rdx, quotient: r11 <- rax
    mov rax,r13                 ; rax = i
    mov r12,1                   ; result of 2^i
    jmp loop1                   ; calculate 2^i
cloop1:
    imul r12,2                  ; multiply r12 *= 2
    dec rax                     ; rax--
loop1:
    cmp r15,rax                 ; 0 < rax?
    jl cloop1                   ; jump if met

    imul rdx,r12                    ; multiply remainder *= 2^i
    add r14,rdx                 ; add decimal += remainder
    inc r13                     ; i++

getFromBinary:
    cmp rcx,0                   ; is binary == 0? 
    jnz cgetFromBinary              ; jump if condition is met

    mov rdi,fmtshort                ; store the format
    mov rsi,r14                 ; store the 1st printf var
    call printf                 ; call printf


ending:           
        pop rbp         ; pop the stack
        mov rax,0       ; exit code
        ret             ; return to OS from main

So far, I've only done it to the part of converting it to decimal and I noticed rcx has its value refreshed or reset to 0 on entering a new label "getFromBinary" as seen in gdb:

Breakpoint 1, main () at bcd.asm:16
16              push rbp                                        ; base pointer
(gdb) n
17              mov rcx,[binary]                                        ; loading it into binary value
(gdb) n
18              mov r14,0                                       ; decimal(initially) = 0;
(gdb) p (int)$rcx
$1 = 1010
(gdb) n
19              mov r13,0                                       ; counter(i) = 0;
(gdb) n
20              mov r15,0                                       ; r15 = 0;
(gdb) n
21              mov rdi,fmt                                     ; storing format in the 1st register
(gdb) n
22              call printf                                     ; calling printf
(gdb) n
23              jmp getFromBinary                               ; Jump to condition first
(gdb) n
getFromBinary () at bcd.asm:46
46              cmp rcx,0                                       ; is binary == 0?
(gdb) n
47              jnz cgetFromBinary                              ; jump if condition is met
(gdb) n
49              mov rdi,fmtshort                                ; store the format
(gdb) p (int)$rcx
$2 = 0

How can i use rcx in different labels?

EDIT: Tinkering with the code, I was able to solve it by using the variable itself:

        extern printf
        SECTION .data


fmt:    db  "The resultant BCD is: ", 0
fmtshort:   db  "%lu    ", 0

binary: dq  1001101010011010                    ; 16 bit binary number (8 byte int) = 1001101010011010
msb:    dq  0                       ; most significant bit size int msv = 0 (initially)
divider:    dq  1                   ; used to isolate the msb of the decimal;

        SECTION .text               ; code section
        global main

main:
    push rbp                    ; base pointer
    mov rcx,[binary]                    ; loading it into binary value
    mov r14,0                   ; decimal(initially) = 0;
    mov r13,0                   ; counter(i) = 0;
    mov r15,0                   ; r15 = 0;
    mov rdi,fmt                 ; storing format in the 1st register
    call printf                 ; calling printf
    jmp getFromBinary               ; Jump to condition first

cgetFromBinary:
    mov rdx,0
    mov rax,[binary]
    mov rbx,10
    div rbx
    mov [binary],rax                    ; remainder: rdx, quotient: r11 <- rax
    mov rax,r13                 ; rax = i
    mov r12,1                   ; result of 2^i
    jmp loop1                   ; calculate 2^i
cloop1:
    imul r12,2                  ; multiply r12 *= 2
    dec rax                     ; rax--
loop1:
    cmp r15,rax                 ; 0 < rax?
    jl cloop1                   ; jump if met

    imul rdx,r12                    ; multiply remainder *= 2^i
    add r14,rdx                 ; add decimal += remainder
    inc r13                     ; i++

getFromBinary:
    mov rcx,[binary]
    cmp rcx,0                   ; is binary == 0? 
    jnz cgetFromBinary              ; jump if condition is met

    mov rdi,fmtshort                ; store the format
    mov rsi,r14                 ; store the 1st printf var
    call printf                 ; call printf


ending:           
        pop rbp         ; pop the stack
        mov rax,0       ; exit code
        ret             ; return to OS from main

But the question still remains as to how can i use the register itself in different labels?

mayank
  • 176
  • 1
  • 12
  • 2
    `rcx` is a caller-saved register per the calling convention. `printf` is allowed to modify it. – Jester Dec 11 '20 at 14:06
  • So had I used some other register that would've worked? EDIT: Just saw the links. Thanks a million @Jester – mayank Dec 11 '20 at 14:09
  • 3
    `imul r12,2` really? Use `shl r12, 1` like a normal person. Also note that `1001101010011010` is decimal. You forgot a `0y` or `0b` prefix or `y` / `b` suffix to tell the assembler the place-values are base 2 instead of base 10. https://nasm.us/doc/nasmdoc3.html#section-3.4 – Peter Cordes Dec 11 '20 at 14:41
  • Thanks a lot, @PeterCordes. I didn't know one could directly input binary using `0b` as the prefix in NASM (There wouldn't be a need to convert it into decimal in the first place) will remember your recommendations. Again thanks :D – mayank Dec 11 '20 at 18:13
  • 1
    There's never a need to do that, and it's something you should never do. `dq 39578` is exactly identical to `dq 0b1001101010011010`, just 2 different source-level ways of writing the same number value. Writing it as a gigantic decimal number will fail for larger numbers when the decimal number can't be represented by 64 binary bits. – Peter Cordes Dec 11 '20 at 18:51

0 Answers0