Lesson 1 - Hello, world!
First, some background...

Assembly language is bare-bones. The only interface a programmer has above the
actual hardware is the kernel itself. In order to build useful programs in
assembly we need to use the linux system calls provided by the kernel. These
system calls are a library built into the operating system to provide functions
such as reading input from a keyboard and writing output to the screen.

When you invoke a system call the kernel will immediately suspend execution of
your program. It will then contact the necessary drivers needed to perform the
task you requested on the hardware and then return control back to your 
program.

Note: Drivers are called drivers because the kernel literally uses them to 
drive the hardware.

We can accomplish this all in assembly by loading EAX with the function number
(operation code OPCODE) we want to execute and filling the remaining registers
with the arguments we want to pass to the system call. A software interrupt is
requested with the INT instruction and the kernel takes over and calls the
function from the library with our arguments. Simple.

For example requesting an interrupt when EAX=1 will call sys_exit and
requesting an interrupt when EAX=4 will call sys_write instead. EBX, ECX & EDX
will be passed as arguments if the function requires them. Click here to view
an example of a Linux System Call Table and its corresponding OPCODES.

Writing our program...

Firstly we create a variable 'msg' in our .data section and assign it the
string we want to output in this case 'Hello, world!'. In our .text section we
tell the kernel where to begin execution by providing it with a global
label _start: to denote the programs entry point.

We will be using the system call sys_write to output our message to the console
window. This function is assigned OPCODE 4 in the Linux System Call Table. The
function also takes 3 arguments which are sequentially loaded into EDX, ECX and
EBX before requesting a software interrupt which will perform the task.

The arguments passed are as follows:

    EDX will be loaded with the length (in bytes) of the our string.
    ECX will be loaded with the address of our variable created in the .data 
        section.
    EBX will be loaded with the file we want to write to – in this case STDOUT.

The datatype and meaning of the arguments passed can be found in the function's
definition.

We compile, link and run the program using the commands below.

helloworld.asm

; Hello World Program - asmtutor.com
; Compile with: nasm -f elf helloworld.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 
; helloworld.o -o helloworld
; Run with: ./helloworld
 
SECTION .data
msg     db      'Hello World!', 0Ah     ; assign msg variable with your message
                                        ; string
 
SECTION .text
global  _start
 
_start:
 
    mov     edx, 13     ; number of bytes to write - one for each letter plus 
                        ; 0Ah (line feed character)
    mov     ecx, msg    ; move the memory address of our message string into
                        ; ecx
    mov     ebx, 1      ; write to the STDOUT file
    mov     eax, 4      ; invoke SYS_WRITE (kernel opcode 4)
    int     80h
    
Compile it with NASM as follows:

~$ nasm -f elf helloworld.asm 
~$ ld -m elf_i386 helloworld.o -o helloworld 
~$ ./helloworld
Hello World! 
Segmentation fault

The segmentation fault, right now is normal... more in lesson 2
