NASM, or The Netwide Assembler, is an x86 compiler that allows us to turn Assembly code in to machine code object files. Once we have an object file, we can link it and create the final executable. This example is meant for Unix systems or Windows with MinGW toolchain installed. On Debian systems, it can be installed with the nasm package. Put the code below in to hello.asm
Variables are defined the data section and code goes in the text section. We define the hello world string and the length of it. Then, the number that represents the system call for printing is moved into the eax register. That is where the computer will look for the system call number when the system interrupt int 80h is called. To see what other cool things we can do with Linux system calls, check out the chart at the bottom of the page.
Source Code
; Define variables in the data section
SECTION .DATA
hello: db 'Hello world!',10
helloLen: equ $-hello
; Code goes in the text section
SECTION .TEXT
GLOBAL _start
_start:
mov eax,4 ; 'write' system call = 4
mov ebx,1 ; file descriptor 1 = STDOUT
mov ecx,hello ; string to write
mov edx,helloLen ; length of string to write
int 80h ; call the kernel
; Terminate program
mov eax,1 ; 'exit' system call
mov ebx,0 ; exit with error code 0
int 80h ; call the kernel
Compiling and Running
# Compile
nasm -f elf64 hello.asm -o hello.o
# Link
ld hello.o -o hello
# Run
./hello
Linux System Calls
In the example above, we move the number 4 in to eax and then call the system interrupt int 80h. We always call the same interrupt, but depending on what values we put in the registers, different things happen. Linux provides a number of system calls besides the one we use, 4, which corresponds to the write call. We write to STDOUT, also knows as file descriptor 1, but we could also write to 2(STDERR) or the file descriptor of a text file on the hard disk or a network socket. STDIN is file descriptor 0, which we would to read from and not write to. Can you figure out what value we would need to put in to eax in order to perform a read? Hint: it is the value for the sys_read system call which you can find in the link below. What else would you need to change in order to read from STDIN? The table below shows what system calls are available as well as what parameters are expected in each register. Registers that have empty values are unused. Check out the Linux System Call Chart.
References
- http://www.tldp.org/HOWTO/Assembly-HOWTO/ - Source code adapted from here as allowed under the GNU Free Documentation License..