asm1

Registri x86

Arhitectura x86 are:

  • 8 registri de uz general (GPR - General-Purpose Registers )
  • 1 registru cu flag-uri/indicatori de conditii (EFLAGS)
  • 1 registru pointer la instructiunea urmatoare ce va fi executata (IP - Instruction Pointer)
  • alti registri


Registri General Purpose

  • AX - accumulator - folosit in operatii aritmetice
  • CX - counter - folosit in bucle si in instructiuni de shiftare si rotatie
  • DX - data - folosit in operatii aritmetice si I/O
  • BX - base - folosit ca un pointer la date
  • SP - stack pointer - pointer la varful stivei
  • BP - stack base pointer - pointer la baza stivei
  • SI - source index - pointer la sursa in operatii stream
  • DI - destination index - pointer la destinatie in operatii stream

(E)FLAGS

Este un registru de 32 de biti care indica "starea" procesorului la un moment dat. Doar o parte din cei 32 de biti sunt folositi pentru a furniza informatii despre rezultatul ultimei operatii executate de procesor. Bitii din EFLAGS se mai numesc si indicatori:

  • CF - carry flag (transport) - are valoarea 1 (este setat) daca dupa ultima operatie a aparut transport, 0 (nu este setat) altfel
  • PF - parity flag (paritate) - are valoarea 1 daca numarul de biti de 1 din rezultatul ultimei operatii este par
  • ZF - zero flag - are valoarea 1 daca rezultatul ultimei operatii a fost 0
  • SF - sign flag (semn) - are valoarea 1 daca rezultatul ultimei operatii a fost negativ (bitul cel mai semnificativ este 1)
  • OF - overflow flag (depasire) - are valoarea 1 daca ultima operatie a produs depasire aritmetica

Mai multe informatii: https://en.wikipedia.org/wiki/FLAGS_register

Adrese

Orice adresa este formata din doua componente: segment si offset (deplasament), notatia uzuala fiind segment:offset.

Pentru partea de offset exista mai multe variante:

  • Constanta numerica
    • [100]
  • Valoarea unui registru general pe 32 biti
    • [EAX] (se poate scrie si cu litere mici)
  • Suma dintre valoarea unui registru general pe 32 biti si o constanta
    • [EBX+5]
  • Suma a doi registri generali pe 32 biti
    • [ECX+ESI]
  • Combinatia celor 2 variante anterioare: suma a 2 registri si a unei constante
    • [EDX+EBP+14]
  • Suma a 2 registri, dintre care unul inmultit cu 2, 4, sau 8, la care se poate aduna o constanta
    • [EAX+EDI*2]
    • [ECX+EDX*4+5]


Sintaxa

Exista 2 sintaxe diferite pentru limbajul de asamblare.

  • Intel - folosit in Visual Studio
  • AT&T - folosit in DevC++ / Linux

Pentru a vedea diferentele, consultati pagina: http://asm.sourceforge.net/articles/linasm.html#Syntax

In cadrul laboratorului vom folosi sintaxa Intel, deci vom lucra in Visual Studio. Cei care nu vor sa foloseasca Visual Studio, se vor documenta pentru sintaxa AT&T.

Instructiuni

Instructiunile ASM au urmatorul format:

[eticheta]   mnemonic/operatie   [operanzi]

MOV - atribuire

Sintaxa: mov destinatie, sursa

Efect: pune in destinatie valoarea din sursa.

Destinatia, respectiv sursa, pot fi:

  • registru, registru.
    • mov eax, ebx
    • mov al, bh
  • registru, adresa de memorie
    • mov bl, [eax]
  • adresa de memorie, registru
    • mov [esi], esx
  • registru, constanta numerica
    • mov ah, 0
  • memorie, constanta numerica
    • mov [eax], 3

Ex. 1:

#include <stdio.h>

void main() {
  _asm {
    mov eax, 0;
    mov ah, 1;
  }
}

Ex. 2 - eroare compilare

#include <stdio.h>

void main() {
  int i = 0;
  _asm {
    mov ax, i;
  }
}


Dimensiunea operanzilor / directiva de size:

mov byte ptr [eax], 5;   //afecteaza 1 octet
mov word ptr [eax], 5;   //afecteaza 2 octeti
mov dword ptr [eax], 5;  //afecteaza 4 octeti (double word)

ADD - adunare

Sintaxa: add op1, op2

Efect: op1 = op1 + op2

Ex. 1:

#include <stdio.h>

void main(){
  int a=10;
  _asm {
    add a, 5
  }
  printf("%d\n",a);
}

Ex. 2:

#include <stdio.h>

void main() {
  _asm {
    mov eax, 0xFFFFFFFF
    add eax, 2 // rezultatul este 0x100000001; necesita 33 biti.
               // setare carry
    mov eax, 0
    mov ax, 0xFFFF
    add ax, 2 // doar ax se modifica!
              // desi rezultatul este 0x10001, al 17-lea bit din eax nu se modifica.
              // se seteaza carry
  }
}

SUB - scadere

Sintaxa: sub op1, op2

Efect: op1 = op1 - op2

Ex. 1:

#include <stdio.h>

void main() {
  int a=10, b=14;
  _asm {
    mov eax, b
    sub a, eax
  }
  printf("%d\n", a);
}


AND, OR, XOR, NOT - instructiuni boolene

Sintaxa:

  • and destinatie, sursa
  • or destinatie, sursa
  • xor destinatie, sursa
  • not destinatie

Instrucţiunile and, or, xor modifică indicatorul ZERO

Utilitatea principală a acestor instrucţiuni este in lucrul cu măşti. De exemplu, dacă ne interesează valoarea bitului al 5-lea din registrul ax, este suficient să se execute and intre ax şi valoarea (scrisa binar) 0000000000010000 (aceasta se numeşte mască). Rezultatul operaţiei va fi 0 (iar indicatorul ZERO va deveni 1) dacă bitul al 5-lea din ax are valoarea 0, respectiv va fi diferit de 0 (iar indicatorul ZERO va deveni 0) dacă bitul al 5-lea din ax are valoarea 1.

Dezavantajul abordării de mai sus este acela că instrucţiunea and modifică valoarea primului operand, plasind acolo rezultatul operaţiei.

Instrucţiunea test are acelaşi efect ca şi and (execută AND intre biţii celor doi operanzi, modifică la fel indicatorul ZERO), dar nu alterează valoarea primului operand. De exemplu:

test ax, 0x0010 // binar: 0000000000010000

modifică indicatorul ZERO ca şi

and ax, 0x0010 

fără a altera valoarea din ax.