ShiftLeft 15 Junior Poster in Training

Source code NASM on Ubuntu 12.04

This demonstrates Input/Output algos using syscall and how they can be implemented in a fairly condensed loop. These routine do not conform to any specific call convention and without modification won't interface with higher level languages.

My code is stand alone assembly and doesn't use standard libraries either. Only dependance is on Linux kernel.

Main.S
        STDIN   equ 0
     SYS_READ   equ 0

        global  GetS

        section .text

;   ENTER:  RCX = Maximum characters
;           RDX = Pointer to input buffer

;   LEAVE:  RAX = Number of characters entered
;           < 0 Entry was longer than RCX, excess truncated
;           RCX = Amount of space left in buffer
;           RDI = Points to next avaliable position

     GetS   push    rsi
            push    rdx     

    ; Setup registers for syscall. You may ask, why not do this in the caller, but Show
    ; and this procedure are designed to be companion routines and this facilitates less
    ; overhead for an algo where inside a loop theres a prompt and then an entry
    ; immediately afterward.

            push    rcx
            pop     rdx                     ; ARG3 = Maximum number of characters
            push    rdi
            pop     rsi                     ; ARG2 = Pointer to buffer
            push    0
            pop     rdi                     ; ARG1 = STDIN
            push    rdi
            pop     rax                     ; ARG0 = SYS_READ

            push    rcx
            syscall
            pop     rcx

    ; Now registers are setup as specified in LEAVE:

            sub     ecx, eax                ; Determine amount of space left
            dec     eax
            mov     rdi, rsi                ; Move base pointer back to RDI
            add     di, rax                 ; Next avaliable position
            push    rax                     ; RAX exit value
            jz      .Exit                   ; If nothing entered, all remains the same.

    ; Ok, operator has entered something, now we need determine if there was overflow

            mov      al, 0                  ; Terminating byte
            or      ecx, ecx                ; Is there space left
            jnz     .Exit                   ; If so, we know last character is CR

    ; At this point we might have overflow, only if last character is not CR

            cmp     byte [rdi], 10
            jz      .Exit                   ; ZF = 1, we used the exact amount of space

    ; Now we know there was overflow and a negated value will indicate this to caller

    .Full   inc     rdi                     ; RDI is always after input CR or not
            neg     qword [rsp]
            jmp .   Exit + 1                ; No need to post NULL as last char, no room

    .Exit   stosb                           ; Replace CR with NULL
            pop     rax
            pop     rdx
            pop     rsi
            or      rax, rax                ; Set appropriate flags
            ret
Show.S
    SYS_WRITE       equ      1
       STDOUT   equ  1

        global  Show

        section .text

; Display a null terminated string on monitor or to whever stream is directed.

;   ENTER:  RSI = Pointer to null terminated ASCII string.

;   LEAVE:  RAX = Character count including NULL (terminator)
;       RSI = Next string (if it exists). 

  Show:
        push    rdi
        push    rdx                     ; Preserve those not to be changed      
        push    rcx

    ; Determine strings length.

        or      rcx, -1                 ; Hope its not this large
        xor     eax, eax
        push    rsi
        pop     rdi                     ; ARG2 = Pointer to string
        repnz   scasb                   ; Scan until terminator is found (hopefully)
        neg     rcx
        sub     ecx, 2

        push    rdi                     ; This is the address we want to return in RSI

    ; Now we can setup for system call.
        ; RDI = STDOUT
        ; RSI = Pointer to string
        ; RDX = Number of characters to display

        push    rcx                     ; Push/Pop combinations, less code & faster
        pop     rdx                     ; ARG3 = Character count
        mov      al, SYS_WRITE          ; ARG0 = Function #
        push    rax
        pop     rdi                     ; ARG1 = File # (SYS_WRITE & STDOUT are equal)
        syscall                         ; Output ASCII string

    ; I dont think its really necessary to check for errors here as operator will 
    ; probably be aware without prompting.

        pop     rsi                     ; Address of next avaliable position

        pop     rcx
        pop     rdx                     ; Retrive registers
        pop     rdi

        inc     rax                     ; Bump count to include terminator
        ret
GetS.S
        STDIN   equ 0
     SYS_READ   equ 0

        global  GetS

        section .text

;   ENTER:  RCX = Maximum characters
;           RDX = Pointer to input buffer

;   LEAVE:  RAX = Number of characters entered
;           < 0 Entry was longer than RCX, excess truncated
;           RCX = Amount of space left in buffer
;           RDI = Points to next avaliable position

     GetS   push    rsi
            push    rdx     

    ; Setup registers for syscall. You may ask, why not do this in the caller, but Show
    ; and this procedure are designed to be companion routines and this facilitates less
    ; overhead for an algo where inside a loop theres a prompt and then an entry
    ; immediately afterward.

            push    rcx
            pop     rdx                     ; ARG3 = Maximum number of characters
            push    rdi
            pop     rsi                     ; ARG2 = Pointer to buffer
            push    0
            pop     rdi                     ; ARG1 = STDIN
            push    rdi
            pop     rax                     ; ARG0 = SYS_READ

            push    rcx
            syscall
            pop     rcx

    ; Now registers are setup as specified in LEAVE:

            sub     ecx, eax                ; Determine amount of space left
            dec     eax
            mov     rdi, rsi                ; Move base pointer back to RDI
            add     di, rax                 ; Next avaliable position
            push    rax                     ; RAX exit value
            jz      .Exit                   ; If nothing entered, all remains the same.

    ; Ok, operator has entered something, now we need determine if there was overflow

            mov      al, 0                  ; Terminating byte
            or      ecx, ecx                ; Is there space left
            jnz     .Exit                   ; If so, we know last character is CR

    ; At this point we might have overflow, only if last character is not CR

            cmp     byte [rdi], 10
            jz      .Exit                   ; ZF = 1, we used the exact amount of space

    ; Now we know there was overflow and a negated value will indicate this to caller

    .Full   inc     rdi                     ; RDI is always after input CR or not
            neg     qword [rsp]
            jmp .   Exit + 1                ; No need to post NULL as last char, no room

    .Exit   stosb                           ; Replace CR with NULL
            pop     rax
            pop     rdx
            pop     rsi
            or      rax, rax                ; Set appropriate flags
            ret
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.