-
Installation:
sudo apt-get install nasm
- Syntax can differ between assemblers (even for same arch)
-
ex1.asm
global _start ; entry point for program (processor executes from here), global - keyword used to make an id accessible to linker _start: ; label (names locations in code) mov eax, 1 mov ebx, 42 int 0x80 ; processor transfers control to interrupt handler specified by value 0x80 - 80 is for system call, 1 : exit call, ebx -> exit status
-
assembling:
nasm -f elf32 ex1.asm -o ex1.o
elf32
32 bit elf object file is loaded- executable and linking format
- Executable format used by linux
- executable and linking format
-
building executable:
ld -m elf_i386 ex1.o -o ex1
elf_i386
- x86 elf program
-
Running:
./ex1 echo $?
-
Subtracting
... sub ebx, 29 int 0x80
- comments:
; comment
- comments:
-
Example:
mov ebx, 123 ; ebx = 123 mov eax, ebx ; eax = ebx add ebx, ecx ; ebx += ecx sub ebx, edx ; ebx -= edx mul ebx ; eax *= ebx div edx ; eax /= edx
-
Inline data
global _start section .data msg db "Hello, world!", 0x0a ; 0x0a - for newline character len equ $ - msg ; $ location after string, msg start of string section .text _start: mov eax, 4 ; sys_write system call mov ebx, 1 ; stdout file descriptor mov ecx, msg ; bytes to write - string pointer mov edx, len ; number of bytes to write int 0x80 ; perform system call - interrupt mov eax, 1 ; sys_exit system call mov ebx, 0 ; exit status is 0 int 0x80
-
Control flow needs to be built using jump instructions
-
EIP
- instruction pointer- Holds location of machine code the processor is executing
- Instruction pointer cannot be changed explicitly (using add ...)
EIP
can be changed using jump operations
-
Example:
global _start section .text _start: mov ebx, 42 ; exit status is 42 mov eax, 1 ; sys_exit system call jmp skip ; jump to "skip" label mov ebx, 13 ; exit status is 13 skip: ; label int 0x80
-
Example:
global _start section .text _start: mov ecx, 99 ; set ecx to 99 mov ebx, 42 ; exit status is 42 mov eax, 1 ; sys_exit system call cmp ecx, 100 ; compare ecx to 100 jl skip ; jump to "skip" label mov ebx, 13 ; exit status is 13 skip: int 0x80
cmp
sets flags in background
-
Conditional jumps:
je A, B ; Jump if Equal jne A, B ; Jump if Not Equal jg A, B ; Jump if Greater jge A, B ; Jump if Greater or Equal jl A, B ; Jump if Less jle A, B ; Jump if Less or Equal
-
Building loop: 2 ^ x (don't use exit to return result but return 0)
global _start section .text _start: mov ebx, 1 ; start ebx at 1 mov ecx, 4 ; number of iterations label: add ebx, ebx ; ebx += ebx dec ecx ; ecx -= 1 - more efficient cmp ecx, 0 ; compare ecx with 0 jg label ; jump to label if greater mov eax, 1 ; sys_exit system call int 0x80
-
Example:
global _start section .data add db "yellow" ; memory contains the word "yellow" section .text _start: mov eax, 4 ; sys_write system call mov ebx, 1 ; stdout file descriptor mov ecx, addr ; bytes to write mov edx, 6 ; number of bytes to write mov eax, 1 ; sys_exit system call mov ebx, 0 ; exit status is 0 int 0x80 ; interrupt
-
How to change content?
mov [addr], byte 'H' ; moving data into the address, byte 'H' (byte representation of 'H' - because mov can be used for larger size data as well) mov [addr+5], byte '!' ; offset of 5 bytes
-
Other data types
section .data ; db is 1 byte name1 db "string" name2 db 0xff ; literals can also be stored name3 db 100 ; dw is 2 bytes name4 dw 0x1234 name5 dw 1000 ; dd is 4 bytes name6 dd 0x12345678 name7 dd 100000
-
Stack:
-
LIFO data structure
- It is an array
- Stack pointer (register)
- Random access also exists (we can read and write to arbitrary location)
-
Example:
ESP
- stack pointer that holds the current location of the top of the stack- Top starts at highest address and gets decreased
- pushing:
-
ESP is decreased by 4 (it pushes 4 byte integers)
-
Value is stored in the memory
push 1234 push 8765 push 246 sub exp, 4 mov [esp], dword 357 ; moving 4 bytes pop eax ; only increases ESP and does not remove value mov eax, dword [esp] add esp, 4 ; same as pop
-
-
Stack example:
global _start _start: sub esp, 4 ; allocate 4 bytes mov [esp], byte 'H' mov [esp+1], byte 'e' mov [esp+2], byte 'y' mov [esp+3], byte '!' mov eax, 4 ; sys_write mov ebx, 1 ; stdout mov ecx, esp ; pointer to bytes to write mov edx, 4 ; number of bytes to write int 0x80
-
-
A chunk of code that we can jump to and perform a few operations and get back
- Re-usable
- We can call c functions from assembly
-
call
- Pushes EIP to stack (location of next instruction)
- Performs a jump (to location of function)
- Return location doesn't have to be explicitly stored (automatically comes back on return)
-
Example:
global _start _start: call func mov eax, 1 int 0x80 func: mov ebx, 42 pop eax ; returns address of mov eax, 1 ; this and next can be replaced by `ret` jmp eax ret
-
Preserving stack status - using base pointer
global _start _start: call func mov eax, 1 mov ebx, 0 int 0x80 func: mov ebp, esp ; stores top pointer first sub esp, 2 mov [esp], byte 'H' mov [esp+1], byte 'i' mov eax, 4 ; sys_write system call mov ebx, 1 ; stdout file descriptor mov ecx, esp ; bytes to write mov edx, 2 ; number of bytes to write int 0x80 ; interrupt mov esp, ebp ; restores top pointer ret
-
Nested function calls: push
ebp
and popebp
push ebp mov ebp, esp sub esp, 2 ... mov esp, ebp pop ebp
-
Passing an argument
_start: push 21 ; argument call times2 mov ebx, eax ; return value is stored in eax but moving to ebx mov eax, 1 int 0x80 times2: push ebp mov ebp, esp ; preserves current top of stack mov eax, [ebp+8] ; argument, next argument is 4 bytes after add eax, eax mov esp, ebp ; restore stack pointer pop ebp ret
-
Calling a c function inside assembly
global main ; must be provided and c will add _start for us extern printf section .data msg db "Testing %i...", 0x0a, 0x00 ; 0x0a - 10 - \n, 0x00 - tells end of string (null terminator) main: push ebp ; prolog mov ebp, esp push 123 ; push in reverse order push msg call printf mov eax, 0 ; exit status mov esp, ebp ; epilog pop ebp ret 1. Assembling and linking nasm -f elf32 ex10.asm ex10.o sudo apt-get install gcc-multilib -y # one-time activity - pre-requisite for integrating asm with c gcc -m32 ex10.o -o ex10 # 32 bit assembly ./ex10
-
We need to pop items from the stack when we return from a function
-
Assembly program
global add42 ; linker gets access to this label add42: push ebp mov ebp, esp mov eax, [ebp+8] ; 4 bytes for ebp, 4 bytes for return address add eax, 42 mov esp, ebp pop ebp ret
-
Assembling
nams -f elf32 add42.asm -o add42.o
-
Compiling C function - needs to know args and types - done using header file
-
add42.h
int add42(int x);
-
-
C - code
#include <stdio.h> #include "add42.h" int main() { int result; result = add42(30); printf("Result: %i\n", result); return 0; }
-
compiling
gcc -m32 add32.o main.c -o ex11 # add32.o is 32 bit object file ./ex11
-
-
-
Inline assembly - discouraged
- not clean
- Each platform can use a different object file without modifying the c code
- Separate object files make the code more modular
- Easy to test, maintain and re-use
- Object files can be used in other assembly programs
- not clean