Asembler x86 – język programowania z rodziny asemblerów do komputerów klasy PC, które posiadają architekturę głównego procesora zgodną z x86.[1]
W rzeczywistości jest to kilka różnych języków używanych do zapisu tych samych instrukcji i dyrektyw, różniących się składnią.
Trzy najpopularniejsze składnie to:
Ponieważ kod w języku asemblera jest niskopoziomowy, istnieją automatyczne translatory między obydwoma składniami.
W składni i metodach programowania za pomocą danej składni asemblera x86 wykorzystuje się kilka ogólnie przyjętych (bądź sprzętowo narzuconych) konwencji. Przykładowo dla składni Intel/Microsoft i NASM są to m.in.:
mov ax, bx
Oprócz prostszego zapisu dyrektyw i atrybutów, NASM eliminuje niejednoznaczności zapisu składni Intel/Microsoft.
W składni MASM interpretacja argumentu operacji przez asembler zależy od sposobu jego wcześniejszego zdefiniowania - w przykładzie poniżej argumenty x i y mają różną interpretację, a zapis [x] jest interpretowany podobnie do zapisu y.
x equ 1000 ; definicja symbolu x o wartości 1000
y dd 123 ; definicja zmiennej y o wartości początkowej 123, zajmującej 32 bity
mov eax, x ; ładuje stałą 1000
mov ebx, [x] ; ładuje wartość danej spod adresu 1000
mov edx, y ; ładuje WARTOŚĆ zmiennej y
mov edx, [y] ; ładuje wartość zmiennej y, tak samo, jak linia powyżej
mov ecx, offset y ; ładuje adres zmiennej y
movzx eax, byte ptr y ; ładuje bajt spod adresu y z rozszerzeniem zerami do 32 bitów
mov eax, 8[ebp] ; ładuje daną spod adresu ebp+8
Każde odwołanie do danej w pamięci jest w składni NASM oznaczone nawiasami kwadratowymi. Brak nawiasów oznacza stałą lub adres.
x equ 1000 ; definicja symbolu x o wartości 1000
y dd 123 ; definicja zmiennej y o wartości początkowej 123, zajmującej 32 bity
mov eax, x ; ładuje stałą 1000
mov ebx, [x] ; ładuje wartość danej spod adresu 1000
mov edx, y ; ładuje ADRES zmiennej y
mov edx, [y] ; ładuje wartość zmiennej y
movzx eax, byte [y] ; ładuje bajt spod adresu y zrozszerzeniem zerami do 32 bitów
mov eax, [ebp+8] ; ładuje daną spod adresu ebp+8
Poniżej dwa przykłady, możliwe do skompilowania w systemie Linux: pierwszy można skompilować przy użyciu nasm, drugi – asemblerem z binutils (lub samym gcc, jeśli ma on rozszerzenie .s
). Linkowanie w obu przypadkach gcc lub ręcznie.
Kompilacja pierwszego:
nasm -f elf32 beer.asm && gcc -s -o beer beer.o
Kompilacja drugiego:
gcc -s -o beer beer.s
global main
extern printf
section .data
beer db "%d bottles of beer on the wall, %d bottles of beer."
db 0x0a
db "Take one down and pass it around, %d bottles of beer."
db 0x0a
db 0
main:
mov ecx, 99
_loop:
dec ecx
push ecx
push ecx
inc ecx
push ecx
push ecx
push beer
call printf
add esp,16
pop ecx
or ecx, ecx
jne _loop
xor eax,eax
ret
.section .rodata
.beer:
.ascii "%d bottles of Beer on the wall, %d bottles of Beer.\n"
.asciz "Take one down and pass it around, %d bottles of Beer.\n"
.text
.global main
main:
mov $99, %ecx
loop:
dec %ecx
push %ecx
push %ecx
inc %ecx
push %ecx
push %ecx
pushl $.beer
call printf
add $16,%esp
pop %ecx
or %ecx, %ecx
jne loop
xorl %eax,%eax
ret