{{tag>Assembly}}
====== Assembly Programming ======
Assembly is about as close as you can get to machine code.
There are many Assembly compilers out there. ''nasm'' is one compiler that is available across platforms and can be used to program x86 processors.
===== x86 on Linux =====
Use interrupt ''0x80'' to make Linux system calls like reading and writing to file descriptors and sockets.
For a list of system calls in Linux, run ''man syscalls'' or refer to an online man page like [[https://man7.org/linux/man-pages/man2/syscalls.2.html]]. To get the actual number, try to find the ''unistd.h'' file. For example, in Debian, ''/usr/include/asm-generic/unistd.h'' has all of the statements that define the syscall numbers (''NR''). Or, refer to the source code of Linux (pick the right branch) [[https://github.com/torvalds/linux/blob/v4.17/arch/x86/entry/syscalls/syscall_64.tbl]] and [[https://github.com/torvalds/linux/blob/v4.17/arch/x86/entry/syscalls/syscall_32.tbl]].
Here is an example of compiling with ''nasm'':
nasm -f elf64 file.asm
# or for 32-bit
nasm -f elf file.asm
If you need to link against something you can use:
ln -d -o outfile file.o
Here is a Hello World example:
SECTION .DATA
hello: db 'Hello world!',10
helloLen: equ $-hello
SECTION .TEXT
GLOBAL _start
_start:
mov eax,4 ; 'write' system call = 4
mov ebx,2 ; 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
Compile and run with:
# Compile
nasm -f elf64 hello.asm -o hello.o
# Link
ld hello.o -o hello
# Run
./hello
===== x86 on DOS =====
Use interrupt ''0x21'' to make DOS system calls like reading and writing files.
For a list of DOS system calls, refer to [[https://en.wikipedia.org/wiki/DOS_API]]
===== x86 on BIOS =====
When interacting with the BIOS, you use a different system call for each function. BIOS will have less system calls available than an kernel like DOS or Linux, but it gives you the tools you need to build an operating system. For example, BIOS will let you change the video mode, get input from keyboard, write text to screen, and draw pixels on the screen.
For a list of BIOS system calls, refer to [[https://en.wikipedia.org/wiki/BIOS_interrupt_call]].
===== Create a library =====
You can write and compile libraries that can be linked against by other programs.
This example shows how to create a function called ''print_hello()'' that can be used from other Assembly or C programs.
; Compile this program using
; nasm -f elf64 static_lib.asm
; gcc myprogram.c static_lib.o
; ./a.out
SECTION .DATA
hello: db 'Hello world!',10
helloLen: equ $-hello
SECTION .TEXT
GLOBAL print_hello
print_hello:
mov eax,4 ; 'write' system call = 4
mov ebx,2 ; 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
===== Create an executable =====
By creating a ''main()'' function, we can make an executable instead of a library.
; Because we have a reference to 'main'
; we can compile with nasm to create the
; .o object file, and then compile that with
; gcc. Example
; nasm -f elf64 c_main.asm
; gcc c_main.o
; ./a.out
SECTION .DATA
hello: db 'Hello world!',10
helloLen: equ $-hello
SECTION .TEXT
GLOBAL main
main:
mov eax,4 ; 'write' system call = 4
mov ebx,2 ; 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
And compile and run with:
nasm -f elf64 c_main.asm
gcc c_main.o
./a.out
===== Call Assembly functions from C =====
/* example.c */
/* Compile and run with `gcc example.c say_hi.o -o hello` */
#include
int main(int argc, char *argv[]) {
extern say_hi();
say_hi();
}
Next, compile and link the C program with gcc. Do that with:
gcc example.c say_hi.o -o hello
You can then run the ''hello'' program that was just created.
./hello
===== Call C function from Assembly =====
You can call C functions from Assembly as well. This example calls printf(). In the main function, we push and pop the stack and put our operations in between. We move all the parameters in to the appropriate registers, and then we call the function.
; printf.asm
; Define printf as an external function
extern printf
SECTION .DATA
msg: db "Hello world", 0 ; Zero is Null terminator
fmt: db "%s", 10, 0 ; printf format string follow by a newline(10) and a null terminator(0), "\n",'0'
SECTION .TEXT
global main
main:
push rbp ; Push stack
; Set up parameters and call the C function
mov rdi,fmt
mov rsi,msg
mov rax,0
call printf
pop rbp ; Pop stack
mov rax,0 ; Exit code 0
ret ; Return
Compile and run that with:
nasm printf.asm -f elf64 -o printf.o
gcc printf.o
./a.out