Search code examples
64-bitsystem-callsfasm

Using syscall with FASM to read numbers with suffix


I am trying to simulate a scanf in assembly that takes different suffixes (h-hex,b-bin etc). This worked fine for unsigned values, but after adding those 5 lines (commented below, to enable signed values), I ran into problem of missing front digit if I entered unsigned value, but works as expected for signed values.

;Linux Mint 17 (64-bit)
;./fasm scanf.asm
;./scanf
format elf64 executable
include 'PROC64.INC'
include 'IF.INC'

    push    tstValue    
    call    SCANF

    push    1           ;sign
    push    [tstValue]  ;No problem here
    call    DISP_INT

    call    EXIT
    tstValue dq 0

proc SCANF,value
    locals
        flag db 0
        key rb 1
    endl
    push    rsi rdi rax rcx rdx
    push    rbx r8 r9 r10

    xor     r10,r10
    xor     r8,r8           ;loop index
    lea     rsi,[key]   
    mov     edx,1       
    xor     edi,edi     
    xor     eax,eax         ;Problem starts after I     
    syscall                 ;added these
    cmp     byte[key],'-'   ;5 new lines to allow signess   
    jne     .begin          ;
    mov     byte[flag],1    ;
.begin: 
    xor     rax,rax
    syscall
    mov     r10b,byte[rsi]
    cmp     r10b,0ah
    jz      .select
    push    r10
    inc     r8
    jmp     .begin
.select:
    pop     rax
    cmp     al,'h'
    je      .hexadecimal
    cmp     al,'H'
    je      .hexadecimal
    cmp     al,'b'
    je      .binary
    cmp     al,'B'
    je      .binary
    cmp     al,'o'
    je      .octal
    cmp     al,'O'
    je      .octal
    cmp     al,'d'
    je      .decimal
    cmp     al,'D'
    je      .decimal
    push    rax     ;if no suffix, defaults to decimal
    inc     r8      ;re-adjust index
.decimal:   
    xor     r9,r9
    pop     rax
    sub     rax,30h
    add     r9,rax
    mov     rcx,10
    mov     rbx,10
    dec     r8
    jmp     .translate
.hexadecimal:
    xor     r9,r9
    pop     rax
    .if al >= 'a' & al <= 'f'
        sub rax,27h
    .elseif al >= 'A' & al <= 'F'
        sub rax,7h
    .endif
    sub     rax,30h
    add     r9,rax
    mov     rcx,16
    mov     rbx,16
    dec     r8
    jmp     .translate
.octal:
    xor     r9,r9
    pop     rax
    sub     rax,30h
    add     r9,rax
    mov     rcx,8
    mov     rbx,8
    dec     r8
    jmp     .translate
.binary:    
    xor     r9,r9
    pop     rax
    sub     rax,30h
    add     r9,rax
    mov     rcx,2
    mov     rbx,2
    dec     r8
    jmp     .translate
.translate:
    dec     r8
    jz      .exit
    pop     rax
   .if al >= 'a' & al <= 'f'
        sub rax,27h
   .elseif al >= 'A' & al <= 'F'
        sub rax,7h
   .endif
    sub     rax,30h 
    mul     rcx
    add     r9,rax
    mov     rax,rbx
    mul     rcx
    mov     rcx,rax
    jmp     .translate
.exit:      
    mov     rax,[value]
    .if [flag] = 1
        neg r9
    .endif
    mov     [rax],r9
    pop     r10 r9 r8 rbx
    pop     rdx rcx rax rdi rsi
    ret
endp

I checked all the registers before that .begin label and they all working as expected (so that syscall should have the correct arguments for reading a single character, eax=0,edx=1,edi=0, rsi points to the character). If I deleted all those 5 lines in question, the program works normally but that leaves me with unsigned program only.

Can anybody help me pointing out what could be the problem? I seem to be running out of idea. I didn't make any push or increase my index (r8) prior to calling .begin. That should cancel out stack or indexing problem.

This is the output for unsigned

3455    ;keyboard input
455

This one works (for signed)

-3455
-3455

Thank you in advance


Solution

  • The fourth line that you've commented must jump 2 lines further. That's why you're losing the first digit of an unsigned value!

    xor     eax,eax         ;Problem starts after I     
    syscall                 ;added these
    cmp     byte[key],'-'   ;5 new lines to allow signess   
    jne     .beginEx        ;
    mov     byte[flag],1    ;
    .begin: 
    xor     rax,rax
    syscall
    .beginEx:
    mov     r10b,byte[rsi]