Výuka assembleru
1. Začínáme s assemblerem
V tomto díle assembleru pro začátečníky se seznámíme se základními pojmy, se kterými se budeme setkávat. Napíšeme také jednoduchý prográmek, který nám bude sloužit jako kostra pro experimentování s assemblerem.
Assembler je nízkoúrovňový programovací jazyk, který umožňuje psát programy přímo ve strojovém kódu procesoru. Program napsaný v assembleru se skládá z instrukcí. Jedna instrukce je jakýmsi povelem pro procesor, aby vykonal určitou činnost. Programy psané v assembleru není možné přenést na jiný procesor, než pro který byl napsán, pokud oba jsou procesory vyrobeny jinou architekturou. Program napsaný pro procesor Intel Pentium je například možné spustit na procesorech AMD odpovídající řady, ale nikoliv už na procesorech Motorola nebo Power PC. Blízkost assembleru s procesorem umožňuje velice dobrou optimalizaci programu, a to jak ve velikosti, tak v rychlosti. Nevýhodou assembleru je zdlouhavost psaní rozsáhlejších programů a také již uváděná nepřenositelnost mezi procesory (Programy napsané v C/C++ po překompilování přenositelné jsou).
Instrukce procesoru se dají zhruba rozdělit na
32bitové procesory X86 obsahují 10 32bitových registrů, které se běžně používají za běhu programu. Jsou to procesory
Jména registrů pocházejí z dob 16bitových procesorů, vyjadřovaly jejich časté použití. Registry EAX, EBX, ECX a EDX mají ještě spodní 16bitovou část, označenou AX, BX, CX, DX. Tato spodní část se dále dělí na horní byte (registr AH, BH, CH, DH) a spodní byte (registry AL, BL, CL, DL). Celkový přehled ukazuje na příkladu registru EAX obrázek vpravo.
Programy budeme psát a kompilovat v prostředí Microsoft Visual Studio, verze 6.0. Kostru programu převezmeme z článku Použití prostředí Visual Studio pro vývoj programů v assembleru, kde si můžete stáhnout kompletní příklad včetně projektu pro Visual Studio. Na tomto jednoduchého programu si postupně probereme všechny typy instrukcí. Nejsnadněji spustíte Visual Studio stlačením klávesy Enter nebo dvojitým kliknutím myší na souboru s příponou .dsw
Vstupním bodem programu bude pro nás funkce WinMain, podobně jako v C/C++. Není to sice nezbytně nutné (vstupní bod se může jmenovat jakkoliv), ale když jsme na to zvyklí z C/C++, tak není důvod zavádět odlišnosti. Kód funkce WinMain smažeme, ponecháme pouze kostru funkce:
WinMain PROC hInstance :HANDLE, hPrevInstance:HANDLE, lpszCmdParam :LPSTR, nCmdShow :WORD WinMain ENDP
Základní instrukce pro naplnění registru se nazývá mov. Zápis této instrukce je následující
mov cíl, zdroj
Pomocí této instrukce můžete naplnit registr číselnou hodnotou, hodnotou uloženou v jiném registru nebo i hodnotou uloženou v paměti. Není možné naplnit registr EIP ani EFLAGS, dále vřele nedoporučuji měnit obsah registru ESP (a to nejen v tomto příkladu, ale i ve všech, které budou následovat). Pomocí instrukce mov není možné kopírovat hodnotu z paměti do paměti ani kopírovat hodnotu mezi registry různé velikosti (např. AL a BX). Zde je příklad programu, používající několika instrukcí mov:
.data dwValue dd 12345678h ; Proměnná o velikosti 32 bitů .code WinMain PROC hInstance :HANDLE, hPrevInstance:HANDLE, lpszCmdParam :LPSTR, nCmdShow :WORD mov eax, 1 ; Naplní registr EAX hodnotou 1 mov ebx, eax ; Zkopíruje obsah registru EAX do registru EBX mov ecx, dword ptr dwValue ; Naplní obsah registru ECX hodnotou uloženou ; v proměnné dwValue mov ah, al mov ch, cl mov bx, ax ret WinMain ENDP
Tento program nevytváří žádný viditelný výstup, spustíme jej tedy v krokovacím režimu (debug mode) klávesou F10. Klávesou Alt+5 zobrazíme okno "Registers", ukazující obsahy registrů. Opakovaným stlačením klávesy F10 projděte program krok po kroku a sledujte, jak se obsahy registrů mění.
Copyright Ladislav Zezula 2003