How to read input from STDIN in x86_64 assembly?
First of all : there are no variables in assembly. There are just labels for some kind of data. The data is, by design, untyped - at least in real assemblers, not HLA (e.g. MASM).
Reading from the standard input is achieved by using the system call read
. I assume you've already read the post you mentioned and you know how to call system calls in x64 Linux. Assuming that you're using NASM (or something that resembles its syntax), and that you want to store the input from stdin at the address buffer
, where you have reserved BUFSIZE
bytes of memory, executing the system call would look like this :
xor eax, eax ; rax <- 0 (syscall number for 'read')
xor edi, edi ; edi <- 0 (stdin file descriptor)
mov rsi, buffer ; rsi <- address of the buffer. lea rsi, [rel buffer]
mov edx, BUFSIZE ; rdx <- size of the buffer
syscall ; execute read(0, buffer, BUFSIZE)
Upon returning, rax
will contain the result of the syscall. If you want to know more about how it works, please consult man 2 read
. Note that the syscall for read
on mac is 0x2000003
instead of 0
, so that first line would instead be mov rax, 0x2000003
.
Parsing an integer in assembly language is not that simple, though. Since read
only gives you plain binary data that appears on the standard input, you need to convert the integer value yourself. Keep in mind that what you type on the keyboard is sent to the application as ASCII codes (or any other encoding you might be using - I'm assuming ASCII here). Therefore, you need to convert the data from an ASCII-encoded decimal to binary.
A function in C for converting such a structure to a normal unsigned int could look something like this:
unsigned int parse_ascii_decimal(char *str,unsigned int strlen)
{
unsigned int ret = 0, mul = 1;
int i = strlen-1;
while(i >= 0)
{
ret += (str[i] & 0xf) * mul;
mul *= 10;
--i;
}
return ret;
}
Converting this to assembly (and extending to support signed numbers) is left as an exercise for the reader. :) (Or see NASM Assembly convert input to integer? - a simpler algorithm only has 1 multiply per iteration, with total = total*10 + digit
. And you can check for the first non-digit character as you iterate instead of doing strlen separately, if the length isn't already known.)
Last but not least - the write
syscall requires you to always pass a pointer to a buffer with the data that's supposed to be written to a given file descriptor. Therefore, if you want to output a newline, there is no other way but to create a buffer containing the newline sequence.