asm.console.io || [ MATHS ] || [Notation] || [Copyright] || [Contents] || [Source Text] || [Dictionary]
Last updated: Tue Nov 18 15:34:22 PST 2014

Contents (index)


    Assembly Language Console I/O

    Motivation

    To look at using C library functions such as printf and scanf for basic console input/output in Assembly Language.

    Introduction

    The quickest and easiest approach to using console I/O in Assembly Language that will be somewhat operating system agnostic, is to use the printf and scanf functions from the standard C library. When writing programs in NASM to use these C library functions, you should include extern directives for the four following functions: printf, scanf, getchar, get_stdout, and fflush. Note: the registers used in 64-Bit Windows ( Win64_regs ) and 64-Bit Linux ( Linux64_regs ) are different! Also note, that for 32-Bit programming, the parameters have to be pushed on to the stack.

  1. Win64_regs::= order of registers used as parameters with C library functions on Win64 systems:

     1st = rcx
     2nd = rdx
     3rd = r8
     4th = r9
     5th = [rsp+20h]
     6th = [rsp+28h]

    An excellent bit from Calling conventions for different C++ compilers and operating systems, by Agner Fog, Technical University of Denmark, in regards to the shadow space:

    The caller must reserve 32 bytes of stack space as "shadow space" for register parameters, even if there are no parameters. The 32 bytes of shadow space come immediately after the return address. Any parameters on the stack come after the 32 empty bytes. The intended purpose of the shadow space is as a "home address" for the register parameters which the called function can use for storing the register parameters in case the registers are used for something else. The caller does not need to put anything into the shadow space. Since the shadow space is owned by the called function, it is safe to use these 32 bytes of shadow space for any purpose by the called function. Even a function without parameters can rely on having 32 bytes of storage space after the return address.

    The entire pdf file can be found at: [ calling_conventions.pdf ]

  2. Linux64_regs::= order of registers used as parameters with C library functions on Linux64 systems:

     1st = rdi
     2nd = rsi
     3rd = rdx
     4th = rcx
     5th = r8
     6th = r9

  3. get_stdout::= gets the file handle of standard output, takes no parameters, but returns the standard output file handle in the rax register.

  4. fflush::= flushes the buffer for the specified file handler, passed as a parameter in rdi for Linux64, or rcx for Win64. Unfortunately, standard input file handle is not included.

  5. getchar::= gets a character from the current standard input stream, returned in the al register; if using to prompt the user to press a key, you will need to ensure the keyboard input buffer is empty by using the following loop:

     lp: call getchar
         cmp al, 0Ah    ; is al linefeed (ascii 0Ah)?
         jne lp
         ...            ; code to execute after buffer is cleared out

  6. printf::= print formatted string, in C/C++ printf is used as follows: printf(some_format_string, variables_corresponding_to_format_string);

     Specifier   Output
     %c          Character
     %d or %i    Signed decimal integer
     %e          Scientific notation (mantissa/exponent) using e character
     %E          Scientific notation (mantissa/exponent) using E character
     %f          Decimal floating point
     %g          Use the shorter of %e or %f.
     %G          Use the shorter of %E or %f
     %o          Signed octal
     %s          String of characters
     %u          Unsigned decimal integer
     %x          Unsigned hexadecimal integer
     %X          Unsigned hexadecimal integer (capital letters)

    Example in C/C++:

     x = 9; y = 6; sum = x + y;
     printf("The sum of %d and %d is %d\n", x, y, sum); // Outputs: The sum of 9 and 6 is 15

    In Assembly Language:

     extern printf
     extern get_stdout
     extern fflush
     section .data
         x          dq     9
         y          dq     6
         sum        dq     0
         message    db     "The sum of %ld and %ld is %ld", 13, 10, 0
     section .text
     global main
     main:
         mov rax, [x]         ; load value of x into rax
         add rax, [y]         ; add value of y to rax
         mov [sum], rax       ; store rax in sum
         mov rax, 0           ; clear out rax, if rax is nonzero, then printf will hang looking for floating values in format string
         lea rdi, [message]   ; rdi points to memory address of format string
         mov rsi, [x]         ; rsi contains second parameter value
         mov rdx, [y]         ; rdx contains third parameter value
         mov rcx, [sum]       ; rcx contains fourth parameter value
         call printf          ; call printf
         call get_stdout      ; get_stdout gets the file handle of output stream
         mov rdi, rax         ; returned in rax, copied to rdi since fflush take one parameter, the handle
         call fflush          ; flush the output stream (this makes the output window in SASM output right away)
         xor eax, eax         ; clear out rax for return value
         ret

    . . . . . . . . . ( end of section Assembly Language Console I/O) <<Contents | Index>>


Formulae and Definitions in Alphabetical Order