Introduction
I will not focus on history. I will be assuming you are a beginner on the Assembly programming language. And assuming that, I will explain it for anybody who's interested to understand an assembly code to really understand it. The (Netwide Assembler) and we will be coding in
Taking RAX as an example for knowing more about the registers:
RAX: Re-extended ax. As previously said, it is used in arithmetic operations and function calls.
EAX: Extended ax. The 32-bit version of RAX.
AX: 16-bit version of RAX.
AL: 8-bit subdivision of AX (least significant bit of AX).
AH: 8-bit subdivision of AX (most significant bit of AX).
Learn more about least and most significant bit . They allow programs to request services from the kernel, such as reading from or writing to files, allocating memory, or terminating a process. In x86_64 Assembly, the syscall instruction is used to invoke these services.
How System Calls Work
When a program makes a syscall:
- The program sets specific values in registers to indicate the syscall number and its parameters.
- The
syscallinstruction is executed. - The operating system processes the request and returns a result, typically in a register.
You can consult the Linux Syscalls Table here.
Registers Used in Syscalls
RAX: Contains the syscall number (identifies the service to invoke).
RDI: The first argument for the syscall.
RSI: The second argument for the syscall.
RDX: The third argument for the syscall.
R10: The fourth argument for the syscall.
R8: The fifth argument for the syscall.
R9: The sixth argument for the syscall.- The return value of the syscall is stored in
RAX.
Example: Writing to Standard Output
Below is a simple example where the program writes "Hello, World!" to the terminal using the write syscall:
section .data
hello db "Hello, World!", 0xA, 0 ; The message to write, followed by a newline and a null terminator
section .text
global _start
_start:
; Syscall: write
mov rax, 1 ; Syscall number for write (1)
mov rdi, 1 ; File descriptor for standard output (1)
mov rsi, message ; Address of the message
mov rdx, 15 ; Length of the message
syscall ; Make the syscall
; Syscall: exit
mov rax, 60 ; Syscall number for exit (60)
mov rdi, 0 ; Exit status (0)
syscall ; Make the syscall
The mov instruction moves values between registers and memory addresses.
Labels
Labels in Assembly are identifiers followed by a : (colon). They act as markers in the code, serving as references for jumps, loops, or points to access data. Think of them as "raw functions" or "bookmarks" within your program.
Types of Labels
There are two main types of labels in Assembly:
Local Labels: Used within a specific section of the program and cannot be accessed globally. These are typically written with a leading.(dot) to signify they are local.
Global Labels: Accessible throughout the program and often marked with theglobalkeyword for external visibility.
Declaring Labels
A label is simply an identifier followed by a colon (:). For example:
start: ; This is a global label
.loop: ; This is a local label
Using labels for control flow
Labels are often used with control flow instructions like jmp (unconditional jump) or je (jump if equal). Here's an example of how labels are used in a loop:
section .text
global _start
_start:
mov ecx, 5 ; Set the counter (ecx) to 5
.loop: ; Start of the loop
dec ecx ; Decrement the counter
jnz .loop ; Jump back to .loop if ecx != 0
; Exit the program
mov rax, 60 ; Syscall for exit
mov rdi, 0 ; Exit code 0
syscall
In this example:
.loopis a local label.- The program jumps back to
.loopwhile the counter (ecx) is greater than zero.
Using Global Labels
Global labels can be accessed across files when linking multiple Assembly files. To declare a global label, use the global directive:
File 1: function.asm
section .text
global my_function
my_function:
; Code for the function
ret ; returns to the caller
File 2: call_function.asm
extern my_function ; Declare the external function
section .text
global _start
_start:
call my_function ; Call the external function
; Exit the program
mov rax, 60
mov rdi, 0
syscall
The global _start on each main file tells the linker where is the main entry for it to link.
Offset calculation
say db "Say something!", 0xA, 0:
0xA: Adds a newline character (\n).
0: Null terminator (\0) to mark the string's end.
This creates the string "Say something!\n\0" in memory.
say_len equ $ - say:
equ: Defines a constant value.
$: Represents the current memory address (after the string ends).
$ - say: Calculates the length of the string in bytes by subtracting the starting address (say) from the current address ($).
This computes the total string length, including the characters, newline (0xA), and null terminator (0).
And we're done.
Now read again the code we wrote at the beginning:
prompter.asm:
section .data
; Define initialized data
say db "Say something!", 0xA, 0 ; The string "Say something!" followed by a newline (0xA) and null terminator (0)
say_len equ $ - say ; Calculate the length of the string (current address minus 'say' label)
input_char db "> ", 0 ; The prompt string "> " followed by a null terminator
input_char_len equ $ - input_char ; Calculate the length of the prompt string
said db "You said: ", 0 ; The string "You said: " followed by a null terminator
said_len equ $ - said ; Calculate the length of the "You said: " string
section .bss
; Define uninitialized data
input resb 128 ; Reserve 128 bytes of space for storing user input
section .text
global _start ; Define the program's entry point
_start:
; Display the message "Say something!"
mov rax, 1 ; Syscall number for 'write'
mov rdi, 1 ; File descriptor: 1 (stdout)
mov rsi, say ; Address of the string "Say something!"
mov rdx, say_len ; Length of the string
syscall ; Make the system call
; Display the prompt "> "
mov rax, 1 ; Syscall number for 'write'
mov rdi, 1 ; File descriptor: 1 (stdout)
mov rsi, input_char ; Address of the prompt string "> "
mov rdx, input_char_len ; Length of the prompt string
syscall ; Make the system call
; Read user input (up to 128 bytes)
mov rax, 0 ; Syscall number for 'read'
mov rdi, 0 ; File descriptor: 0 (stdin)
mov rsi, input ; Address to store user input
mov rdx, 128 ; Max number of bytes to read
syscall ; Make the system call
; Display the string "You said: "
mov rax, 1 ; Syscall number for 'write'
mov rdi, 1 ; File descriptor: 1 (stdout)
mov rsi, said ; Address of the string "You said: "
mov rdx, said_len ; Length of the "You said: " string
syscall ; Make the system call
; Display the user input
mov rax, 1 ; Syscall number for 'write'
mov rdi, 1 ; File descriptor: 1 (stdout)
mov rsi, input ; Address of the user input
mov rdx, 128 ; Max number of bytes to display
syscall ; Make the system call
; Exit the program
mov rax, 60 ; Syscall number for 'exit'
mov rsi, 0 ; Exit code: 0
syscall ; Make the system call
Run the code
First we need to assemble it with nasm:
nasm -f elf64 prompter.asm -o prompter.o
Then link the object file with ld:
ld prompter.o -o prompter
And run the code:
./prompter
Final considerations
You learned what Assembly is like and how to use it. But, that's only the peek of the iceberg. Thanks for reading and see you in the next article!
SOCIAL SHARE CARD GENERATOR