Składnia assemblera NASM
Pierwsze programy

Pierwszy program Linux 32-bit (Pokaż/ukryj kod)

 
; NASM 32 bit: program zapisany w pliku hello.asm
; kompilacja: nasm -felf hello.asm -o hello.o
; linkowanie: ld hello.o -o hello
; linkowanie w systemach 64-bit:  ld -m elf_i386 hello.o -o hello
 
 
section .text
 
global _start           ; linux rozpoczyna wykonywanie programu od etykiety _start
_start:                 ; musi ona być widoczna na zewnątrz (global)
 
mov eax, 4              ; numer funkcji systemowej:  
                        ;  sys_write - zapisz do pliku
mov ebx, 1              ; numer pliku, do którego piszemy.
                        ; 1 = standardowe wyjście = ekran
mov ecx, tekst          ; ECX = adres (offset) tekstu
mov edx, dlugosc        ; EDX = długość tekstu
int 80h                 ; wywołujemy funkcję systemową
 
mov eax, 1              ; numer funkcji systemowej
                        ; (sys_exit - wyjdź z programu)
int 80h                 ; wywołujemy funkcję systemową
 
section .data           ; początek sekcji danych.
 
tekst db "Czesc", 0ah   ; nasz napis, który wyświetlimy
dlugosc equ $ - tekst   ; długość napisu
 

Pierwszy program Linux 64-bit (Pokaż/ukryj kod)

; wersja NASM na system 64-bitowy (x86-64)
; kompilacja: nasm -felf64 hello64.asm -o hello64.o
; linkowanie: ld hello64.o -o hello64
 
bits 64
section	.text			; początek sekcji kodu.
global _start		        ; linux rozpoczyna wykonywanie programu od etykiety _start
                                 ; musi ona być widoczna na zewnątrz (global)
 
_start:				; punkt startu programu
	mov	rax, 1		; numer funkcji systemowej:
				; sys_write - zapisz do pliku
	mov	rdi, 1		; numer pliku, do którego piszemy.
				; 1 = standardowe wyjście = ekran
	mov	rsi, tekst	; RSI = adres (offset) tekstu
	mov	rdx, dlugosc	; RDX = długość tekstu
	syscall			; wywołujemy funkcję systemową
	mov	rax, 60		; numer funkcji systemowej
				; (sys_exit - wyjdź z programu)
	syscall			; wywołujemy funkcję systemową
 
section .data			; początek sekcji danych.
	tekst	db	"Czesc", 0ah	; nasz napis, który wyświetlimy
	dlugosc	equ	$ - tekst	; długość napisu
 

Pierwszy program Windows (Pokaż/ukryj kod)

; wersja NASM: program zapisany w pliku tekstowym a.asm 
; kompilacja: nasm -fbin -o a.com a.asm
 
org 0x100
 
section .data                            ; sekcja danych zainicjalizowanych
    info: db "Hello world!",13, 10, '$'  ; ciąg znaków zakończony znakiem dolara - wymagane przez funkcję                                             
                                         ; o numerze 9, wyświetlającą ciąg, znaki 10 i 13 dają nową linię
 
section .bss                     ; sekcja danych niezainicjalizowanych
    bufor:      resb 5           ; bufor 5 bajtów 
 
 
section .text           ; sekcja kodu
 
    mov ah, 9
    mov dx, info
    int 0x21            ; wywołaj przerwanie 0x21 - po załadowaniu 9 do AH wyświetlona będzie 
                        ; zawartość rejestru DX
 
    mov ah,0    
    int 0x16            ; wywołaj przerwanie 0x16 - po załadowaniu 0 do AH program czeka 
                        ; na naciśnięcie klawisza
 
    mov ax, 0x4C00      ; wyjście z programu z kodem błędu 0: w AH wpisane 4C, w AL wpisane 00, 
                        ; czyli kod wyjścia
    int 0x21
 

Sekcje w linuxie

Wybrane sekcje zdefiniowane dla formatu elf

section .text    progbits  alloc   exec    nowrite  align=16 
section .data    progbits  alloc   noexec  write    align=4 
section .bss     nobits    alloc   noexec  write    align=4 
section .comment progbits  noalloc noexec  nowrite  align=1 
section other    progbits  alloc   noexec  nowrite  align=1

Deklarowanie danych

Do definiowania zainicjowanych danych używamy pseudoinstrukcji
db, dw, dd, dq, dt, do
w zależności od wielkości danych

db    0x55                ; just the byte 0x55 
db    0x55,0x56,0x57      ; three bytes in succession 
db    'a',0x55            ; character constants are OK 
db    'hello',13,10,'$'   ; so are string constants 
dw    0x1234              ; 0x34 0x12 
dw    'a'                 ; 0x61 0x00 (it's just a number) 
dw    'ab'                ; 0x61 0x62 (character constant) 
dw    'abc'               ; 0x61 0x62 0x63 0x00 (string) 
dd    0x12345678          ; 0x78 0x56 0x34 0x12 
dd    1.234567e20         ; floating-point constant 
dq    0x123456789abcdef0  ; eight byte constant 
dq    1.234567e20         ; double-precision float 
dt    1.234567e20         ; extended-precision float

Deklarowanie niezainicjowanych danych

Do definiowania niezainicjowanych danych używamy

resb, resw, resd, resq, rest, reso
w zależności od wielkości danych.
buffer:         resb    64              ; reserve 64 bytes 
wordvar:        resw    1               ; reserve a word 
realarray:      resq    10              ; array of ten reals 
ymmval:         resy    1               ; one YMM register

Deklarowanie stałych

Do definiowania stałych służy equ.

message         db      'hello, world' 
msglen          equ     $-message

Specjalny symbol $ ewaluuje do adresu początku obecnej lini.

Powtarzanie instrukcji

Dowolną instrukcję czy pseudoinstrukcje możemy wykonać wielokrotnie dzięki times.

 ; inicjuje 64 bajty wartościa 0
 
zerobuf:        times 64 db 0  
 
; uzupełnia buffor aby zajmował dokladnie 64 bajty 
 
bufor: db      'hello, world'  
       times 64-$+bufor db ' ' 

Specjalny symbol $ ewaluuje do adresu początku obecnej lini.


Tomasz Kapela, Kraków 2011-2020