Handy Code Snippets in Assembly

CS 301 Lecture, Dr. Lawlor

For your class projects, there's a lot of stuff you should be able to just do.  Here's how to do it.

Writing Text to the Screen

The easiest way to write a short string to the screen is with the standard C library function puts.  This function takes one parameter, a pointer to the string to print, followed by a newline.  In C++:
puts("Sup?");

(Try this in NetRun now!)

In assembly:

mov rdi,someString
extern puts
call puts
ret

section .data
someString:
db "Sup?",0 ; <- the zero indicates the end of the string

(Try this in NetRun now!)

Printing integers

There's a weirdly flexible C function printf that can print text and integers.  It's just like puts in that it takes a string, but printf's string contains weird escape codes like "%d" that indicate "print the corresponding integer argument here".  For example:
printf("The integer is %d\n",17);

(Try this in NetRun now!)

Printf is "varargs", meaning it takes a variable number of arguments, so you can print several integers in one call with something like printf("The integers: %d, %d, and %d...\n",2,7,9);

In assembly, there is one weird annoyance with printf, that it requires a "16-byte aligned stack". 

sub rsp,8 ; stack MUST be 16-byte aligned after call pushes return address...
mov rdi,formatString ; "format string": contains %d for each printed integer
mov rsi,17 ; integer to print
extern printf
call printf
add rsp,8 ; put stack back
ret

section .data
formatString:
db "The integer is %d",0xa,0 ; <- 0xa == newline; 0 == end of string

(Try this in NetRun now!)

Reading Characters

You can read one character at a time with getchar, which returns the character read.
return getchar();

(Try this in NetRun now!)

In assembly:
extern getchar
call getchar
; returned character is in rax
ret

(Try this in NetRun now!)

Reading Strings

You can read a string from the keyboard into a fixed-size buffer using gets.  Note that this is inherently insecure and dangerous, but it does work for short strings.
; Read the string
mov rdi,myString
extern gets
call gets
; Print the string
mov rdi,myString
extern puts
call puts
ret

section .data
myString:
times 1024 db 0 ; big character buffer, 1024 bytes all zeros

(Try this in NetRun now!)

There's another slightly more complex function called fgets that takes a byte count, so it's actually safe even for long or malicious input values:
; Read the string with "fgets(string,length,stdin)"
mov rdi,myString
mov rsi,1024
extern stdin
mov rdx,QWORD[stdin] ; subtle: push stdin's value, not the pointer!
extern fgets
call fgets

; Print the string
mov rdi,myString
extern puts
call puts
ret

section .data
myString:
times 1024 db 0 ; big character buffer, 1024 bytes all zeros

(Try this in NetRun now!)

Random Numbers

The standard C library function rand will return you a pseudorandom integer.   It's "pseudorandom", not actually random, because two consecutive calls to rand in a given program run will return different values, but the sequence coming from rand is deterministic, so you can run your program again and again, and always get exactly the same values.  This determinism is handy for debugging!
extern rand
call rand
ret

(Try this in NetRun now!)

If you want a random number from 0 to 10, you need to wrap the big random number around so it's in the range you want.  A standard way to do this is to take the random number mod 10, like "rand()%10", or using the horrible idiv assembly interface:
extern rand
call rand
mov edx,0 ; high bits of numerator
mov ecx,10 ; denominator: random number ranges from zero to this
idiv ecx ; divide eax:edx by ecx. rax gets ratio, rdx gets remainder.
mov rax,rdx ; rdx gets remainder after idiv
ret

(Try this in NetRun now!)

To generate a random number from zero up to a power of two, you can just use bitwise AND, like:
extern rand
call rand
and rax,15 ; random number from 0 to 15
ret

(Try this in NetRun now!)

To get a different random number stream, call "srand" with an integer.  Oddly, it looks like "srand(0)" and "srand(1)" give the same default random number stream.
mov rdi,2 ; stream to get (different numbers give different rand results)
extern srand
call srand

extern rand
call rand
and rax,15 ; random number from 0 to 15
ret

(Try this in NetRun now!)

To get a different random number stream each time you run the program, you can get the time as a number of seconds from "time(0)", and then pass that value to srand:
mov rdi,0 ; time(0)
extern time
call time

mov rdi,rax ; number of seconds since 1970
extern srand
call srand

extern rand
call rand
and rax,15 ; random number from 0 to 15
ret

(Try this in NetRun now!)