Ľudmila Jánošíková

Programovanie v jazyku symbolických adries

pre 32-bitové procesory Intel
Obsah Index
Procedúry

Procedúry deklarujeme pomocou direktívy PROC. Jej syntax v zjednodušenej podobe môžeme popísať takto:

meno_procedúry PROC [jazyk] [uses registre] [parameter1[,parameter2]…]

Potom nasleduje telo procedúry. Deklarácia procedúry končí direktívou ENDP:

meno_procedúry ENDP

Meno procedúry je symbolická adresa prvej inštrukcie v procedúre. O položkách [jazyk] a [uses] a o parametroch v direktíve PROC budeme hovoriť neskôr.

Procedúru vyvoláme pomocou príkazu

call meno_procedúry (call procedure)

OF SF ZF AF PF CF
- - - - - -

Inštrukcia call uloží do zásobníka návratovú adresu a vykoná skok na prvú inštrukciu procedúry. Návratovou adresou je aktuálna hodnota čítača inštrukcií EIP, t.j. offset inštrukcie, ktorá nasleduje za inštrukciou call. Volanie procedúry môže byť priame a nepriame (podobne ako nepodmienený skok). Pri priamom volaní je operandom inštrukcie call meno procedúry, pri nepriamom volaní register alebo pamäťový operand. Inštrukcia call sa prekladá rovnako ako inštrukcia jmp: pri priamom volaní je operandom displacement, ktorý sa pripočíta k aktuálnej hodnote čítača inštrukcií.

Návrat z procedúry vykonáva inštrukcia

ret [číslo] (return from procedure)

OF SF ZF AF PF CF
- - - - - -

Inštrukcia ret vyberie zo zásobníka návratovú adresu a uloží ju do registra EIP. Inštrukcia ret môže mať priamy operand, ktorý sa po výbere návratovej adresy pripočíta k ukazovateľu zásobníka ESP. To znamená, že po výbere návratovej adresy sa v zásobníku preskočí toľko bajtov, koľko udáva operand inštrukcie. Inštrukcia ret s operandom sa používa vtedy, keď sa do procedúry odovzdávajú parametre cez zásobník. O parametroch procedúry bude reč onedlho.

Nasleduje krátky program, ktorý ilustruje použitie inštrukcií call a ret. Vedľa zdrojového textu je uvedený jeho preklad spolu s adresou inštrukcie Všimnite si, že operandom inštrukcie call v preloženom kóde je 0FFFFFFF9h = -7, čo je vzdialenosť medzi inštrukciou nasledujúcou za call a prvou inštrukciou procedúry. Na obr. 15 zároveň môžete sledovať, ako sa mení obsah registrov EIP a ESP a obsah zásobníka.

                  .code
                  Nic PROC
004033F0 90             nop
004033F1 C3             ret
                  Nic ENDP
                  main PROC
004033F2 E8 F9 FF FF FF call Nic
004033F7 33 C0          xor eax,eax

Zásobník
Na začiatku hlavného programu:
EIP
ESP
004033F2
0018FF8C

0018FF88
0018FF8C

?
?


Po call Nic:
EIP
ESP
004033F0
0018FF88
0018FF88
0018FF8C

004033F7
?


Po nop:
EIP
ESP
004033F1
0018FF88
0018FF88
0018FF8C

004033F7
?


Po ret:
EIP
ESP
004033F7
0018FF8C

004033F7
0018FF8C

004033F7
?

Obr. 15. Registre EIP, ESP a zásobník pri volaní procedúry

Parametre sa do procedúry môžu odovzdávať:

  • v registroch;
  • v zásobníku.

Prvý spôsob sa používa pri čistých assemblerovských programoch, druhý najmä vtedy, keď je assemblerovský program volaný z programu vo vyššom jazyku. Samozrejme, nič vám nebráni, aby ste parametre odovzdávali v zásobníku, aj keď je celý program v JSA. K odovzdávaniu parametrov v registroch niet čo dodať, preto sa v ďalšom výklade zameriame na parametre v zásobníku.

Parametre musíme do zásobníka uložiť predtým, ako vyvoláme procedúru. V procedúre potom parametre sprístupníme pomocou nepriameho adresovania s použitím bázového registra EBP. Sledujte nasledujúci príklad:

Úloha

Napíšte procedúru, ktorá ku všetkým prvkom poľa typu byte pripočíta zadanú hodnotu. Parametrami procedúry budú:

  • adresa poľa
  • dĺžka poľa v bajtoch
  • číslo, ktoré sa má pripočítať
Riešenie

Zostavíme nielen procedúru, ale aj hlavný program, aby ste videli celý postup odovzdávania parametrov.

TITLE MASM Procedury
INCLUDE Irvine32.inc
.data
Pole DB 0,1,2,3,4
Dlzka DW $-Pole
Cislo EQU 1
.CODE
Pripocitaj PROC
        mov ebp,esp
        mov ebx,[ebp+12]; offset
        mov ecx,[ebp+8]; Dlzka
        mov al,[ebp+4]; Cislo
Cyklus: add [ebx],al
        inc ebx
        loop Cyklus
        ret 12; zo zásobníka vyberie návratovú adresu a parametre (12 bajtov)
Pripocitaj ENDP
main PROC   
        push offset Pole
        push Dlzka
        push Cislo
        call Pripocitaj
exit
main ENP
END Zac

Na obr. 16 vidíme stav zásobníka po inštrukcii call Pripocitaj.


ESP : návratová adresa
ESP + 4: Cislo
ESP + 8: Dlzka
ESP + 12: offset Pole

Obr. 16. Zásobník po inštrukcii call Pripocitaj

Pri deklarácii procedúry v direktíve PROC môžeme parametrom procedúry priradiť symbolické mená. Potom sa na parametre môžeme odvolávať pomocou týchto mien, a nie cez nepriamu adresu s registrom EBP. Procedúra sa stáva čitateľnejšou a nemusíme si pamätať vzdialenosť parametrov od vrcholu zásobníka. Tým, že parametrom priradíme symbolické mená, stávajú sa z nich formálne parametre procedúry. Každému formálnemu parametru môžeme predpísať typ. Ak neuvedieme typ parametra, predpokladá sa dword.

Teraz sa dostávame k špecifikácii jazyka v deklarácii procedúry. Táto informuje prekladač o poradí ukladania parametrov do zásobníka pri volaní procedúry a o tom, kto ich zo zásobníka odstráni. Ak definujeme jazyk Pascal, Basic alebo Fortran, budú sa parametre ukladať zľava doprava a prekladač bude generovať inštrukciu ret so správnym operandom. Okrem toho prekladač automaticky v procedúre generuje inštrukcie pre nastavenie EBP a ESP. V jazyku C a Prolog sa parametre ukladajú sprava doľava a prekladač predpokladá, že parametre odstráni volajúci program. V  32-bitových aplikáciách určených pre operačný systém Windows treba zadať jazyk stdcall. Táto konvencia je zmiešaninou C a Pascalu. Parametre sa ukladajú do zásobníka sprava doľava a zo zásobníka ich odstraňuje volaná procedúra.

Konvenciu jazyka môžeme určiť pri definovaní modelu pamäti na začiatku programu. Táto potom platí pre všetky procedúry a netreba ju definovať v každej procedúre zvlášť. V súbore Irvine32.inc je vložený súbor SmallWin.inc, kde je definovaný model pamäti spolu so špecifikáciou stdcall takto:
.MODEL flat,stdcall

Procedúra Pripocitaj s formálnymi parametrami bude vyzerať takto:

Pripocitaj PROC paOffset, paDlzka, paCislo:byte
        mov ebx,paOffset
        mov ecx,paDlzka
        mov al,paCislo
Cyklus: add [ebx],al
        inc ebx
        loop Cyklus
        ret
Pripocitaj ENDP

Prekladač automaticky doplní na začiatku procedúry príkazy

push ebp
mov ebp,esp

ktoré slúžia na zachovanie obsahu registra EBP z volajúceho programu. Na konci procedúry automaticky vloží príkazy

leave
ret 0Ch

pre obnovenie regitra EBP a návrat z procedúry do volajúceho programu. Inštrukcia leave vykoná to isté ako

mov esp,ebp
pop ebp

V hlavnom programe sa formálne parametre nahradia skutočnými parametrami takto:

main PROC
        INVOKE Pripocitaj, offset Pole, Dlzka, Cislo
        exit
        mov al,paCislo
main ENDP

Direktíva INVOKE vykoná to isté ako

        push offset Pole
        push Dlzka
        push Cislo
        call Pripocitaj

Špecifikácia uses v direktíve PROC definuje registre (maximálne 8 položiek oddelených medzerami), ktorých obsahy budú automaticky na začiatku procedúry uložené do zásobníka a pred návratom z procedúry opäť automaticky obnovené, aby sa zachovali ich hodnoty z volajúceho programu. Ak nie je špecifikovaný jazyk, direktíva uses sa ignoruje.

Procedúra Pripocitaj modifikuje registre EAX, EBX a ECX, preto by jej deklarácia mala vyzerať takto:

Pripocitaj PROC USES eax ebx ecx paOffset, paDlzka, paCislo:byte
        mov ebx,paOffset
        mov ecx,paDlzka
        mov al,paCislo
Cyklus: add [ebx],al
        inc ebx
        loop Cyklus
        ret
Pripocitaj ENDP

Prekladač automaticky doplní na začiatku procedúry príkazy

push ebp
mov ebp,esp
push eax
push ebx
push ecx

a na konci procedúry:

pop ecx
pop ebx
pop eax
leave
ret 0Ch

Procedúry majú často lokálne premenné. Lokálne premenné sú pamäťové miesta v zásobníku nad návratovou adresou a odloženým registrom EBP. Miesto na lokálne premenné sa vyhradzuje v procedúre tak, že sa od ukazovateľa zásobníka ESP odčíta počet bajtov, ktoré lokálne premenné zaberajú. K lokálnym premenným pristupujeme v procedúre podobne ako k parametrom (pomocou nepriameho adresovania s registrom EBP), ale posunutie oproti báze je záporné. Lokálne premenné sa deklarujú pomocou direktívy

LOCAL premenná1[,premenná2]…[=symbol]

Premennej môžeme priradiť typ (implicitne word) a počet položiek, napr.

LOCAL Sucet:byte
LOCAL Retazec[8]:byte

Úloha

Upravte procedúru Pripocitaj tak, že v nej spočítate všetky prvky poľa a súčet uložíte do lokálnej premennej Sucet.

Riešenie

Do procedúry doplníme lokálnu premennú Sucet typu byte.

Pripocitaj PROC USES eax ebx ecx paOffset, paDlzka, paCislo:byte
LOCAL Sucet:byte
        mov ebx,paOffset
        mov ecx,paDlzka
        mov al,paCislo
        mov Sucet,0
Cyklus: add [ebx],al
        mov ah,[ebx]
        add Sucet,ah
        inc ebx
        loop Cyklus
        ret
Pripocitaj ENDP

Prekladač automaticky doplní na začiatku procedúry príkazy

push ebp
mov ebp,esp
add esp,0FFFFFFCh; -4
push eax
push ebx
push ecx

a na konci procedúry:

pop ecx
pop ebx
pop eax
leave
ret 0Ch

Na obr. 17 vidíme stav zásobníka po inštrukcii add esp,-4.

miesto, ktoré sa môže používať v procedúre
ESP : Sucet
EBP : EBP z hl. programu
EBP + 4: návratová adresa
EBP + 8: offset Pole
EBP + 12: Dlzka
EBP + 16: Cislo

Obr. 17. Zásobník po inštrukcii add esp,-4

Na záver kapitoly o procedúrach upozorňujeme na dobrý zvyk: komentovať zdrojový text! V záhlaví každej procedúry by sa mala objaviť informácia o tom,

  • čo procedúra robí,
  • aké sú vstupné a výstupné parametre procedúry, vrátane spôsobu ich odovzdávania (v registroch alebo v zásobníku),
  • ktoré registre procedúra mení.

Tieto komentáre vám v prvom rade uľahčia orientáciu v programe. Oceníte ich však najmä vtedy, keď budete chcieť neskôr procedúru modifikovať alebo využívať v inom programe. Bez popisu procedúry by ste znovu prácne museli študovať jej zdrojový text. Procedúry je nevyhnutné komentovať tiež v prípade, keď ich chcete poskytnúť inému programátorovi.

Hore

Načo je vám jazyk symbolických adries?

Architektúra moderných procesorov

Registre

Spôsoby adresovania

Premenné a návestia

Symbolické konštanty

Inštrukčný súbor

Segmentové direktívy

Moduly

Služby operačného systému MS-DOS

Služby operačného systému Windows 95/98/NT/XP

Systémová úroveň vstupu a výstupu

Prostriedky pre prípravu programu

Inštrukcie pre prácu so zásobníkom | Inštrukcie pre nastavenie príznakových bitov
Vydala Žilinská univerzita v Žiline, 2000. ISBN 80-7100-723-4.
Otázky a pripomienky môžete poslať autorke.
Naposledy upravené 19.10.2015.