.Open 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. Win64_regs::= order of registers used as parameters with C library functions on Win64 systems: .As_is 1st = rcx .As_is 2nd = rdx .As_is 3rd = r8 .As_is 4th = r9 .As_is 5th = [rsp+20h] .As_is 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: .See http://www.agner.org/optimize/calling_conventions.pdf Linux64_regs::= order of registers used as parameters with C library functions on Linux64 systems: .As_is 1st = rdi .As_is 2nd = rsi .As_is 3rd = rdx .As_is 4th = rcx .As_is 5th = r8 .As_is 6th = r9 get_stdout::= gets the file handle of standard output, takes no parameters, but returns the standard output file handle in the rax register. 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. 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: .As_is lp: call getchar .As_is cmp al, 0Ah ; is al linefeed (ascii 0Ah)? .As_is jne lp .As_is ... ; code to execute after buffer is cleared out printf::= print formatted string, in C/C++ printf is used as follows: printf(some_format_string, variables_corresponding_to_format_string); .As_is Specifier Output .As_is %c Character .As_is %d or %i Signed decimal integer .As_is %e Scientific notation (mantissa/exponent) using e character .As_is %E Scientific notation (mantissa/exponent) using E character .As_is %f Decimal floating point .As_is %g Use the shorter of %e or %f. .As_is %G Use the shorter of %E or %f .As_is %o Signed octal .As_is %s String of characters .As_is %u Unsigned decimal integer .As_is %x Unsigned hexadecimal integer .As_is %X Unsigned hexadecimal integer (capital letters) Example in C/C++: .As_is x = 9; y = 6; sum = x + y; .As_is 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: .As_is extern printf .As_is extern get_stdout .As_is extern fflush .As_is section .data .As_is x dq 9 .As_is y dq 6 .As_is sum dq 0 .As_is message db "The sum of %ld and %ld is %ld", 13, 10, 0 .As_is section .text .As_is global main .As_is main: .As_is mov rax, [x] ; load value of x into rax .As_is add rax, [y] ; add value of y to rax .As_is mov [sum], rax ; store rax in sum .As_is mov rax, 0 ; clear out rax, if rax is nonzero, then printf will hang looking for floating values in format string .As_is lea rdi, [message] ; rdi points to memory address of format string .As_is mov rsi, [x] ; rsi contains second parameter value .As_is mov rdx, [y] ; rdx contains third parameter value .As_is mov rcx, [sum] ; rcx contains fourth parameter value .As_is call printf ; call printf .As_is call get_stdout ; get_stdout gets the file handle of output stream .As_is mov rdi, rax ; returned in rax, copied to rdi since fflush take one parameter, the handle .As_is call fflush ; flush the output stream (this makes the output window in SASM output right away) .As_is xor eax, eax ; clear out rax for return value .As_is ret .Close Assembly Language Console I/O