Vysvetlivky k vzorovému príkladu

Aby sme sa nemuseli príliš detailne zaoberať štruktúrou programu v assembleri, t.j. čo všetko okrem nášho algoritmu musí obsahovať, aby sa vôbec dal spustiť v danom operačnom systéme, budeme používať tzv. vložený (embedded) assembler. To znamená, že to bude len akýsi fragment kódu vložený do štandartného C-programu.

Microsoft Visual C++

Vo Visual C sa vkladá assembler medzi krútené zátvorky uvedené kľúčovým slovom __asm { } . Nasledujú jednotlivé inštrukcie, prípadne s komentárom. Premenné z C-programu, môžete používať priamo. Je však potrebné mať na pamäti, že do registrov môžete presúvať len premenné zodpovedajúcej veľkosti. Nemôžete teda napr. do registra EAX presunúť premennú typu double. Výsledok práce programu odovzdáte C-programu tiež jednoducho cez premenné.

// zaciatok bloku asm
 __asm            
{
     MOV EAX, iCislo // do EAX vloz hodnotu premennej iCislo (z pamate)
     INC EAX // pripocitaj 1
     MOV iVysledok,EAX // do premennej iVysledok vloz vysledok z registra EAX
} // koniec bloku asm

DEV-C++ (gcc)

Kompilátor gcc má trocha odlišnú syntax pre vložený assembler. Je to vlastne funkcia asm ("retazec") , kde samotné inštrukcie musíme písať ako textový reťazec. Pretože takýto blok sa priamo podsunie prekladaču assembleru, musí vložený kúsok vyzerať presne rovnako ako zdrojový kód pre assembler. To znamená, že každá inštrukcia musí končiť \n. Nepríjemná komplikácia je, že gcc používa inú syntax (tzv. AT&T), dosť odlišnú od Intel syntaxe. Napríklad operandy zdroj, cieľ sa uvádzajú v opačnom poradí. Našťastie sa to dá prenaučiť príkazom .intel_syntax noprefix.

Premenné z C-programu, môžete používať priamo, len musíte pridať znak podtržítko pred názov premennej. Premenné z C-programu, ktoré chcete používať v assembleri však musia byť zadefinované ako globálne.

Podobne ako vo Visual C však musíte mať na pamäti, že do registrov môžete presúvať len premenné zodpovedajúcej veľkosti. Nemôžete teda napr. do registra EAX presunúť premennú typu double. Výsledok práce programu odovzdáte C-programu tiež jednoducho cez premenné.

Príklad:

asm(“.intel_syntax noprefix \n” // Prepneme z AT&T syntaxe na na Intel

     “mov eax,_iCislo \n” // iCislo -> EAX
     “inc eax \n” // EAX ++
     “mov _iVysledok,eax \n” // EAX -> iVysledok

“.att_syntax \n”); // Dame vsetko do povodneho stavu

CLion

Študenti pracujúci v prostredí CLion mávali problém s oboma predošlými syntaxami. Existuje ešte tretia možnosť.

Príklad:

__asm__ (
            “movl %[iCislo], %%eax;” //movl kopiruje udaje z premennej do registra
            “inc %%eax;” //pripocitame 1
            “movl %%eax, %[iVysledok];” //do premennej iVysledok vloz vysledok z registra EAX
            : [iVysledok] “=r” (iVysledok) //:toto je apersand //rozdiel medzi “r” a “=r” je v tom, že prvý sa používa pre vstupné operandy a druhý pre výstupné operandy. “r” umožňuje kompilátoru vybrať akýkoľvek dostupný
    // register na uloženie hodnoty operandu, zatiaľ čo “=r” zabezpečuje, že hodnota výstupného operandu sa zapíše späť do pamäte.
    : [iCislo] “r” (iCislo)
    );

Microsoft Visual C++ Ladenie

Pri práci s assemblerom možno oceníte možnosť spustenia programu krok za krokom, pričom môžete sledovať zmeny v jednotlivých registroch. Debugovanie sa spustí po preložení programu z menu postupnosťou Debug >> Start Debug >> Step Into. V programe sa pohybujete vpred klávesou F10 (Step Over). Vaše okno môže vyzerať napr. takto:

Vzorový príklad:

#include <stdio.h>

static int iCislo, iVysledok;         // Niektore verzie potrebuju globalne premenne

int main(int argc, char* argv[])
{
    iCislo = 27;
    iVysledok = 0;
    printf("\nCislo: %d  Vysledok: %d",iCislo,iVysledok);

#ifdef __GNUC__                      // Tato cast sa preklada len v Dev-C++ (gcc)

   asm(".intel_syntax noprefix \n"   // Prepneme z AT&T syntaxe na na Intel 
   
       "mov eax,_iCislo        \n"   // iCislo -> EAX
       "inc eax                \n"   // EAX ++ 
       "mov _iVysledok,eax     \n"   // EAX  -> iVysledok  

       ".att_syntax            \n"); // Dame vsetko do povodneho stavu      

#elif _MSC_VER                       // Tato cast sa preklada iba v MS Visual C++

    __asm {                          // zaciatok bloku asm
    MOV EAX, iCislo                  // do EAX vloz hodnotu premennej iCislo (z pamate)
    INC EAX                           // pripocitaj 1
    MOV iVysledok,EAX                // do premennej iVysledok vloz vysledok z registra EAX
    }                                // koniec bloku asm

#endif
  
    printf("\nCislo: %d  Vysledok: %d",iCislo,iVysledok);
    
    printf("\n\nStlac ENTER a skoncime...");
    scanf("?");    
    return(0);
}
Close Menu