Ugrás a tartalomhoz

Assembly

Ellenőrzött
A Wikipédiából, a szabad enciklopédiából
(Assembly programozási nyelv szócikkből átirányítva)
Assembly kód és a belőle fordított gépi kód

Az assembly (angol: összerakás, összegyűjtés, összeépítés) a gépi kódhoz (a számítógép „anyanyelvéhez”) legközelebb álló, és így helykihasználás és futási idő szempontjából a leghatékonyabb általános célú programozási nyelv.

Habár az egyes architektúrák assembly nyelvei hasonlóak, mégis különböznek annyira, hogy az assembly kód ne legyen hordozható. Az assembly kódot az assembler fordító alakítja gépi kóddá.

Az assembly nyelv nem keverendő össze a gépi kóddal: egy assembly nyelvű program végrehajtható utasításai általában egy gépi kódú utasításnak felelnek meg, tehát az assembly egy programozási nyelv, a gépi kód az a tárgykód, amit csaknem minden programozási nyelv előállít végeredményként. Szimbolikus gépi kódnak is nevezik.

Az utasítások mellett még regisztereket, flageket és memóriacímeket is tartalmaz, egyes kódszakaszok címkézhetők az ugró utasítások számára. A legtöbb assemblyben kifejezések írhatók elnevezett konstansokkal és számokkal. Ezeket memóriacímzésre is fel lehet használni. Sok assembly további eszközöket tartalmaz a fejlesztés megkönnyítésére.

Commodore gépcsaládon vagy Sinclair gépeken három módszerrel lehetett programozni: interpretált BASIC – hátránya: a program futása lassú volt – továbbá gépi kód, illetve assembly. Nem létezett külön tárgykód, a program közvetlenül a memóriába lett fordítva. A gépek memóriamérete, illetve a háttértárak korlátozottsága nem is tette volna lehetővé C nyelv és standard C könyvtár használatát. A Commodore-16 16 KB memóriával rendelkezett, 32 KB ROM-ja – melynek kb. felét a BASIC-interpreter tette ki – tartalmazta az „operációs rendszerét”. Háttértárként egyoldalas floppyt – kétoldalas floppy használatához meg kellett fordítani a lemezt a meghajtóban – vagy magnókazettát használtak.

Régebben szélesebb körben használták, de hatékonysága miatt az assembly megmaradt az operációs rendszerek, illesztőprogramok és hasonlók programozásában.

Eredete

[szerkesztés]

Az első számítógépek programozása úgy történt, hogy a számításokat végző elemek huzalozását változtatták meg.

A számítógépeket a kezdetekben a processzorok utasításaihoz rendelt számok bevitelével (gépi kóddal) lehetett programozni, melyek ábrázolása eleinte bináris, majd később oktális (nyolcas) vagy hexadecimális (tizenhatos) számrendszerben (vagy röviden csak „hexában”) történt.

Az assembly kódhoz tartozó fordítóprogramot assemblernek nevezik. Ez készít a szöveges forrásprogramból egy olyan állományt, amely csaknem teljes egészében megfelel annak a memória képnek, amelyet a processzor végrehajtható programként értelmezni fog.

Az assembler "párja" a disassembler, ami a lefordított bináris kódot értelmezi és assembly forráskódú listává alakítja. Az alacsony szintű programozás további kellékei:

  • memóriatartalom vizsgáló, "dump" program
  • debugger – hibakereső program
  • hexa editor – állományok hexadecimális (16-os számrendszerű), ha szükséges utasításszintű módosítását teszi lehetővé
  • processzor szimulátor – adott processzorra írt programot "szoftveresen" futtat egy másik számítógépen, esetleg a célgép további hardver elemeit is emulálja

Terminológia

[szerkesztés]
  • A makró assembler (macro assembler) makróutasítást tartalmaz, ezzel elnevezhető egy programszakasz, ami a névvel hivatkozható más szakaszokból.
  • A kereszt assembler (cross assembler) keresztfordítást végez, azaz nem arra a gépre készít futtatható programot, amin a program fordul. Az eredménykódot át kell másolni a célrendszerre. A pontos másolást a célrendszer számára csak olvasható média (ROM, EPROM, …) vagy link segítségével. Ilyet nyújt például a Motorola S-record vagy az Intel HEX. Nemcsak kényelmi célokat szolgál, hanem így lehet programot készíteni olyan rendszerekre, ahol nem lehet fordítani, például beágyazott rendszerek.
  • A magas szintű assembler (high-level assembler) strukturált vezérlési (IF/THEN/ELSE, DO CASE, …) és objektumorientált eszközöket (rekordok, uniók, osztályok, halmazok) bocsát a programozó rendelkezésére.
  • A mikroassembler (microassembler) mikroprogramok fejlesztését segíti, amelyek alacsony szinten vezérlik a számítógépet.
  • A meta-assembler (meta-assembler) szintaktikai elemző, ami a nyelv szintaktikai és szemantikus leírása alapján assemblert generál a nyelvhez.

Assembler

[szerkesztés]

Az assembly nyelvű kód fordítóját assemblernek nevezik. A magas szintű nyelvek fordítója is tartalmaz assemblert. Ez hozza létre a végleges bináris kódot, lefordítva a mnenonikonokat, a műveleti szintaxist és a címzéseket bináris megfelelőjükre. Ebben a reprezentációban jelen vannak a műveleti kódok (opcode), más vezérlőbitek és adatok. Az assembler kiszámítja a konstans kifejezéseket, feloldja a szimbolikus neveket.[1] A szimbolikus hivatkozások kulcsfontosságúak az assembler programozásban, megkímélik a programok íróit a hosszas számításoktól és attól, hogy mindig hozzá kelljen igazítani a címeket a program módosításaihoz. A legtöbb assembler makrókat is kezel, ami a C prekompilerjéhez hasonlóan szöveges helyettesítést tesz lehetővé. A hívott szubrutinok helyett a makrók helyben (inline) fejtődnek ki.

Egyes assemblerek még optimalizálni is tudnak. Erre konkrét példa több terjesztő mindenütt jelenlevő x86-assemblerjei. A legtöbbjük át tudja alakítani az ugró utasításokat; kérésre például helyettesítenek egy hosszú ugrás valahány kisebb ugrással. Mások átrendezik az utasításokat, vagy beszúrnak, törölnek, összevonnak, mint például a RISC architektúrák assemblerjei, amelyek érzékenyen ütemeznek is, hogy a program még hatékonyabb legyen.

Az assemblerek voltak az első, valóban használt programozási nyelvek, mivel könnyebb hozzájuk fordítót készíteni, mint a magasabb szintű nyelvekhez, hiszen a kód összes eleme viszonylag egyszerűen továbbalakítható bináris kóddá, és nem igényel alaposabb elemzést. Több fordító és félautomata kódgenerátor létezik, amelyek mind az assemblyre, mind a magasabb szintű nyelvekre hasonlítanak. Ezek közül egy jó példa a speedcode.

A különböző architektúrák assemblerjei hasonlóak, de szintaxisukban különböznek. Például ha az utasításban a memóriában tárolt értéket hozzá kell adni egy regiszter értékéhez, akkor az az x86-os Intel processzorcsaládnál add eax,[ebx]. A Gnu Assembler AT&T szintaxisában ez addl (%ebx),%eax. Különbségeik ellenére általában ugyanazt a gépi kódot generálják. Az assemblernek több különböző módja lehet a különféle szintaxisok támogatására.

Menetszám

[szerkesztés]

Az assemblert meneteinek száma jellemzi, vagyis azt, hogy hányszor olvassa végig a lefordítandó kódot.

  • Az egymenetes assembler egyszer olvassa végig a kódot. A definíció előtt használt szimbólumokat, például ugrási címkéket külön listára gyűjti. A linker vagy a betöltő (loader) ez alapján tudja, hogy vissza kell térnie a definiálás előtti helyre, és ott a fenntartott helyre írni.
  • A többmenetes assembler az összes szimbólumot tartalmazó listát készít az első menet alkalmával, és a további menetekben ezt a listát használja, és bővíti további információkkal.

Az assemblernek ki kell számítania a memóriacímeket is; ehhez a különböző utasítások méreteivel is számolnia kell, mert nem ugyanakkorák. Ha az utasítás mérete függ az operandusok típusától, akkor pesszimista becslést készít. Szükség esetén a fölös helyet kitölti, vagy tár optimalizáció esetén újraszámolja a címeket.

Az egymenetes assembler a korai időkben gyorsabb volt, mivel a kódot mágnesszalag vagy lyukkártyák okozták, és a visszacsévélés vagy a visszalapozás jelentősen több időt igényelt. Ma már ez nem probléma; sőt, most már a többmenetes assemblerek vannak előnyben, mivel gyorsabbá teszik a linkelést vagy a betöltést.[2]

Példa: A következő kódban az egymenetes assembler meg tudja határozni a BKWD referenciát, amikor az S2 utasítást dolgozza fel. Viszont nem tudja az FWD címét, amikor az S1 utasítással foglalkozik, így a FWD felkerül a listájára. A kétmenetes assembler az első menetben meghatározza a címeket, tehát ezek ismeretében generál kódot a második olvasásra.

S1   B    FWD
  ...
FWD   EQU *
  ...
BKWD  EQU *
  ...
S2   B    BKWD

Magas szintű assemblerek

[szerkesztés]

A magas szintű assemblerek további nyelvi absztrakciókat tesznek lehetővé:

  • Függvények és eljárások magas szintű deklarálása és hívása
  • Fejlettebb vezérlési szerkezetek
  • Magasabb szintű absztrakt adattípusok, mint rekordok, uniók, osztályok és halmazok
  • Fejlettebb makrófeldolgozás, bár ezt egyes típusok már az 1950-es évektől is tudták
  • Objektumorientált programozási eszközök, osztályok, objektumok, absztrakt osztályok, öröklődés[3]

Formai jegyek

[szerkesztés]

Az assembly nyelvet utasítások (tényleges kódot hoznak létre) és direktívák, vagy pszeudoutasítások (a fordítás vagy kódgenerálás vezérlése) alkotják. A kód tartalmaz adatokat és lehetnek benne kommentek is.

A különböző processzorcsaládok utasításkészlete bár sokszor jelentősen eltér, de a gyártók által megadott assembly nyelvű szintaxis általában hasonló irányelvekre épül. Az utasítások általában néhány betűs rövidítések, azoknak a gépi utasításoknak a mnemonikjai, amelyek a processzor utasításkészletét alkotják. Az assemblerek közötti különbség tükrözi a gépi kódok közötti különbséget; különböznek a műveletek, a regiszterek száma, mennyisége és típusaik, továbbá az adatok reprezentációja is. Az általános célú számítógépek különböznek abban, hogyan valósítják meg ugyanazt a funkcionalitást. Még ugyanahhoz az utasításkészlethez is létezhet több assembly, amiket különböző assemblerekkel lehet fordítani, de általában a gyártó által szállított a legnépszerűbb.

A direktívákkal vezérelhető a változók és a program elhelyezése, igazítása, a program belépési pontjának meghatározása. A direktívák hatására létrejövő információk egy részét a fordító szintaktikai ellenőrzéshez használja, más részük a szerkesztő (linker) és/vagy a betöltő (loader) program számára ad információt. Ez a két program teszi lehetővé, hogy az assembler által készített kódból futtatható program jöjjön létre.

Az utasítások általában úgy néznek ki, hogy először jön a művelet opkódja (opcode), majd következnek az adatok, paraméterek vagy argumentumok.[4] Az assembly forráskód soronként logikailag egy műveletet tartalmaz, egészében nézve a forrás felépítése a következő:

  • Deklarációs rész: változók, konstansok, makrók definiálása.
  • Végrehajtható, ill kód-rész: utasítások egymásutánja. Egy utasítássorhoz klasszikus esetben egy gépi kódú utasítás (és annak esetleges paraméterei) tartozik, az újabb, úgynevezett makró assemblerekkel definiálhatunk nevesített kódrészleteket is, mintegy „magasabb szintre emelve” ezáltal a nyelvet.
    1. Címke: „megcímkézhetünk” egy utasítást, melyet ugró utasítások célpontjaként, esetleg változók illetve konstansok azonosítására használhatunk.
    2. Az elvégzendő művelet (operátor) megnevezése (mnemonikja)
    3. Egy szóköz után az esetlegesen szükséges operandus(ok) (paraméterek), több operandust hagyományosan vesszővel választunk el. Az operandus(ok) előtt vagy után speciális jelölések mutatják a címzési módot.
    4. Megjegyzések, ezeket szintaxistól függő elválasztó karakter után írva rögzíthetjük.
    • Utasítástípusok

Egy processzornak vagy műveletvégzőnek általában 50-80 mnemonikkal megkülönböztetett végrehajtható utasítása van, de ez nagyon eszközfüggő.

Az assemblyt assembler fordítja. Disassemblerrel elvégezhető a fordított irányú művelet is, mivel a megfeleltetés egyszerű az assembly és a gépi kód között; az utasítások általában egy az egyhez fordulnak. Ezzel szemben vannak például makrók, amelyek bővítik az utasításkészletet. Például, ha nincs a gépi kódban olyan utasítás, hogy "ágazz el, ha nagyobb-egyenlő", akkor ezt nyújthatja az assembler, mint "vond ki belőle" és "ágazz el, ha nulla vagy nagyobb". A legtöbb assembler makrók gazdag készletét bocsátja rendelkezésre, amivel bonyolultabb kód és összetettebb adatszerkezetek hozhatók létre.

Példa

[szerkesztés]

Az alábbi utasítás azt mondja az x86/IA-32 processzornak, hogy mozgasson egy 8 bites értéket egy regiszterbe. Ennek az utasításnak a kódja 10110, amit a regiszter három bites azonosítója követ. Az AL regiszter kódja 000, így a következő gépi kód az AL regiszterbe a 01100001 adatot tölti:[5]

10110000 01100001

Ez a kód ember számára jobban olvasható hexadecimális formában:

B0 61

ahol B0 azt jelenti, hogy mozgasd a következő értéket az AL regiszterbe, és 61 az érték tizenhatos számrendszerben, ami tízes számrendszerben 97. A 8086-os család assemblyje az efféle utasításra a könnyebben megjegyezhető MOV mnenonikot nyújtja. Ezzel a fenti kód assemblerben, és megjegyzéssel:

MOV AL, 61h       ; Az AL regiszterbe a 97 decimális számot tölti (61 hexadecimális)

Egyes assemblyk minden adatmozgatást a MOV utasítással fejeznek ki, míg másoknak erre több is van, attól függően, hogy honnan hová kell másolni. Például L a szóban forgó adat regiszterbe mozgatására, ST regiszterből a memóriába, LR egyik regiszterből a másikba, MVI közvetlenül a memóriába.

Az x86-os 10110000 (B0) opkód egy nyolc bites értéket mozgat az AL regiszterbe, 10110001 (B1) a CL-be, és 10110010 (B2) a DL-be. Assembly nyelvű példák következnek.[5]

MOV AL, 1h        ; Az AL regiszterbe az 1 betöltése
MOV CL, 2h        ; A CL regiszterbe a 2 betöltése
MOV DL, 3h        ; A DL regiszterbe a 3 betöltése

A MOV szintaxisa bonyolultabb is lehet, ahogy a következők mutatják:[6]

MOV EAX, [EBX]	  ; Az EBX tartalma által meghatározott memóriacímről 4 bájtot mozgat az EAX regiszterbe
MOV [ESI+EAX], CL ; A CL tartalmát az ESI+EAX által meghatározott memóriacím 1 bájtjára másolja

Mindezekben az esetekben az assembler a MOV mnemonikot közvetlenül a 88-8E, A0-A3, B0-B8, C6 vagy C7 opkódok valamelyikére fordítja. A program írójának nem kell tudnia, mikor melyiket kell használni.[5]

Jellemző utasítások típusok

[szerkesztés]

Az assemblerek szerzői különféleképpen kategorizálják az utasításokat és különböző elnevezéseket használnak. Vannak, akik a mnemonikokon kívül mindent pszeudooperációnak (pseudo-operation, pseudo-op) neveznek. Egy assembly nyelv tipikusan a következőket tartalmazza:

  • Opkód mnemonikok
  • Adat definíciók
  • Assembly direktívák

Memóriakezelő utasítások

[szerkesztés]

Ezek az utasítások az operatív memóriával közvetlenül kapcsolatos olvasó és/vagy író utasításokat valósítják meg. Minden esetben legalább egy operandusuk van (egy címes gépek esetén), ami az adott memóriacímre hivatkozás (bár ez a cím lehet implicit operandus is, vagyis már adott regiszterben előkészített; nem pedig a műveleti kód adott mezőjében megadott). Az olvasási utasítások a kijelölt memóriacím tartalmat egy kijelölt regiszterbe töltik, míg az írási utasítások a kijelölt regiszter tartalmát tárolják el a kijelölt memóriacímen; továbbá léteznek memória-memória utasítások is, melyekkel egy memóriarekeszt vagy tartományt mozgatnak át (egyes helyeken string-kezelő utasításokként említik őket). Külön utasítások létezhetnek a byte, szó (2 byte) duplaszó (2 szó) stb. tartományok elérésére, de lehetséges, hogy ezt előtéttagok – más néven prefixum – segítségével kell elérni. Ezek – formailag – az utasítás előtt helyezkednek el, és egy utasítás előtt egyszerre több is lehet belőlük (a maximális szám processzorfüggő). Tehát a memóriareferens utasítások kimenetelét illetve lezajlását különböző előtéttagok befolyásolhatják:

  • ismétlő prefix – ismétlés adott feltétel fennállásáig
  • operandusméret prefix – az elérni kívánt memóriarekesz nagyságát befolyásolja
  • címmódosító prefix – az elérni kívánt memóriarekesz címének értelmezését befolyásolja
  • szinkronizációs prefix – a CPU és az FPU közötti szinkronizáció céljára (a 386-os PC-nél már hardveresen működik eme mechanizmus)
  • buszlezárás prefix – az adatmódosítás biztonságát (konzisztencia) növeli, például többprocesszoros rendszerekben

Regiszterkezelő utasítások

[szerkesztés]

A regiszterek között végezhető műveleteket (regiszterek közötti csere, regiszter jobb-bal oldalának cseréje, speciális regiszterekhez való hozzáférés stb.) valósítják meg.

Aritmetikai és logikai utasítások

[szerkesztés]

Ezek az utasítások aritmetikai műveletek (összeadás, kivonás, szorzás, osztás, esetleg ugyanezek lebegőpontos változatai, kiegészítve az ún. normalizáló utasítással), illetve elemi logikai műveletek (és, vagy, nem, kizáró-vagy) végrehajtására szolgálnak.

Általában ide sorolják az ún. léptetési utasításokat is, mivel ezek – a bináris számrendszer speciális esete miatt – épp 2 egész számú hatványaival való szorzás, osztás műveletet valósítanak meg.

Ezen kívül az inkrementáló és dekrementáló utasításokat is ide soroljuk.

Ugró utasítások

[szerkesztés]

Az ugró utasításokkal a program végrehajtásának folyamata vezérelhető. Általában feltétel nélküli és feltételes ugrási utasításokról beszélünk. A feltételek egy regiszter, vagy az úgynevezett program- vagy processzorjelző (flag) adott bitjének/bitjeinek állapotához köthetőek (nulla, nem nulla, pozitív, negatív, kisebb, nagyobb, van túlcsordulás, van átvitel stb.). Az egyes utasítások leírásánál pontosan meg van adva, hogy a processzorjelzőket hogyan módosítják a végrehajtás során. (A módosító hatásúak legtöbbször aritmetikai-logikai műveletek vagy kifejezetten erre a célra szánt utasítások.)

Az utasítások operandusa az a hely (vagyis egy cím), ahol a programot folytatni kell, a feltételtől függően. Ha a feltétel nem teljesül, akkor a program a következő utasítást hajtja végre, tehát a végrehajtás folyamata nem módosul. Maga a címoperandus lehet literális – vagyis címke vagy címke kifejezéssel megadott cím – vagy regiszterben kijelölt, esetleg valamilyen indirekció. Továbbá a feltételes ugrásoknál előfordul implicit operandusú megoldás, vagyis amikor az ugrási címet nem adjuk meg konkrétan. Ilyen elágazó utasítás esetén a végrehajtás mindig a (program)sorban következő vagy a következő utáni utasításra helyeződik át – az elágazástól függően.

Speciális utasítások

[szerkesztés]

Speciális utasítások a megállító (halt, sleep), az üres (nop) utasítás és egyes processzorállapot-kezelő utasítások.

Megállító utasítás
[szerkesztés]

Megállítja a program futását, és csak "külső beavatkozás" (pontosabban interrupt vagy reset) hatására lép tovább. Egyes processzorok ekkor automatikusan energiatakarékos üzemmódba lépnek.

Üres utasítás
[szerkesztés]

Az üres utasítás "nem tesz semmit": a regiszterek tartalma nem változik, az állapotregiszter(ek) jelzőbitjei sem változnak (ha vannak). A üres utasítást általában a NOP vagy NOOP mnemonikkal jelölik, ami az angol no operation rövidítése. A NOP utasítás általában egy operandusok nélküli utasítás, az utasításkészlet alap bithosszának megfelelő kódot kap, pl. a 8 bites Z80 processzornál az egybájtos 0x00 kód, a 32 bites ARM A32 architektúrában a négybájtos 0x00000000 kód, a Motorola 68000-es családban a 2 bájtos 0x4e71 kód reprezentálja. Egyes architektúrákban megvalósítása csak a programszámlálót növeli és ezen kívül semmi más tevékenység nem történik. Végrehajtási ideje lehet az alapvető utasításciklus, de pl. a MOS Technology 65xx processzoroknál két órajelciklusig tart. Ezt a műveletet általában időzítésre használják (valamilyen hardver időzítés miatt, elágazott programszálak futási idejének kiegyenlítésére esetleg hardver diagnosztikai célra → címsín vizsgálatához).

Processzor állapot kezelő utasítások
[szerkesztés]

A megszakítások kezelésére szolgáló, valamint a ki- és beviteli műveletek, illetve egyéb, a számítógép és/vagy a processzor működését vezérlő utasítások tartoznak ebbe a csoportba.

Adat direktívák

[szerkesztés]

Az adat direktívák adatelemeket definiálnak változók és konstansok tárolására. Definiálják az adatok típusát, hosszát és igazítását (alignment). Meghatározzák az adatok láthatóságát is, vagyis azt, hogy kívülről is elérhetők-e, vagy csak abból a kódszakaszból, ahol definiálták őket. Néhány assembler pszeudooperációnak tekinti.

Direktívák

[szerkesztés]

A direktívák az assemblernek szóló utasítások, amelyekből nem keletkezik gépi kód. Pszeudooperációnak is nevezik őket.[1] Az assembler működésének befolyásolásával hatnak a tárgykódra, a szimbólumtáblára, a listákra és az assembler belső paramétereire. Vannak, akik a nyelv részei közül csak azokat nevezik pszeudokódnak, amelyek tárgykódot generálnak, például adatot.[7]

Nevük sokszor ponttal kezdődik, hogy megkülönböztessék őket a gépi utasításoktól. Lehetővé teszik, hogy különböző paraméterekkel máshogy forduljon a program, például különféle célokra. Javíthatják az olvashatóságot és segíthetik a karbantartást. További lehetőség a tárhely fenntartása a futásidejű adatok számára, esetleg még inicializálásuk is.

A szimbolikus assemblerek lehetővé teszik, hogy a programozó neveket használjon, ezzel címkéket vezessen be, vagy változókat és konstansokat definiáljon. Az utasítások ezután használhatják is a neveket, támogatva a kód öndokumentálását. A kódban minden szubrutin nevét a belépési ponttal azonosítják, így azok nevükkel hívhatók. A címkék ugró utasítások céljai lehetnek, és bevezetésük előtt is használhatók. Néhány assembler a címkéket formájuk szerint is lexikálisan elkülöníti a többi szimbólumtól, például 10$.

Egyes assemblerek, mint a NASM rugalmas szimbólumkezelést nyújtanak, így definiálhatók névterek, automatizálható a memóriacímek kiszámítása az adatszerkezetekben, a címkék pedig hivatkozhatnak literális értékekre vagy az assembler által elvégzendő számítások eredményére. A címkék értékül is adhatók változóknak és konstansoknak.

Ahogy a legtöbb programnyelv, az Assembly is lehetővé teszi a kommentelést. A megjegyzéseket az assembler nem fordítja le. Itt le kell írni a kódszakasz jelentését és célját, különben nehéz megérteni, hogy mit csinál a programszakasz. A fordítók és a disassemblerek által generált nyers, megjegyzések nélküli assemblyt nagyon nehéz értelmezni.

A direktívák néhány fontosabb csoportja:

  • listakészítés engedélyezése/tiltása, pl.
PRINT ON           ; /360
  • Program tulajdonságainak megadása, pl.
LOAD cím           ; Z80: program (betöltési) címe
ORG cím            ; Z80: program (futáskori) címe
SEGMENT AT cím     ; x86: memóriaterület címe
END címke          ; Program vége, egyben belépési pont megadása
  • Program szakaszokra bontása, szakaszok tulajdonságainak megadása, pl.
snév SEGMENT CODE  ; x86:  kódszegmens
snév DSECT         ; /360: 'dummy' adatszegmens
snév CSECT READ    ; /360: kódszegmens, írásvédett
snév AMODE 31      ; /370: csak 31 bites módban futtatható
  • Címzéshez használandó regiszterek definiálása, pl.
ASSUME CS:code,DS:data,ES:video ; 8086: definíció
ASSUME ES:nothing               ; 8086: visszavonás
USING code,R12                  ; /360: definíció
DROP R12                        ; /360: visszavonás
  • Szimbólumok exportja/importja, pl.
ENTRY rutin   ; /360
EXTRN valtozo ; /360
  • Változók definíciója
var EQU érték ; általános
var = érték   ; /8086
  • Makrók definíciója és meghívása, illetve a makrókban használható speciális utasítások (pl elágazás)

Makrók

[szerkesztés]

Sok assembler támogat előre definiált makrókat, és vannak, amelyek lehetővé teszik makrók definiálását is. Ezek szövegszerűek, lehetnek bennük utasítások, direktívák, változók és konstansok. Ha az assembler egy makróhoz ér, akkor kifejti, majd folytatja a kifejtett kód feldolgozásával. Egyes makrók több mélységben támogatják a makrók kifejtését. A makrók eben az értelemben az 1950-es évek IBM Autocode Assemblerjeire vezethetők vissza.

Hasonlóan működik a C és a C++ előfeldolgozója, de ott csak egy szint fejtődik ki, továbbá a makrók (többnyire) egy sorosak. Az assembler makrók gyakran hosszabbak, néha hosszú programok, amelyeket az assembler értelmezőként hajt végre. Hasonló a helyzet a PL/I makróival is. Mivel a makrók rendszerint hosszúak, a töredékére tudják rövidíteni a kódot, és a magas szintű nyelvekhez hasonlóvá tudják tenni. Magasabb szintű szerkezetek hozzáadására is alkalmasak.

A makróknak gyakran lehetnek paramétereik is. Némely assembly kifinomult makrónyelvet ágyaz be, magas szintű nyelvi elemekkel, opcionális paraméterekkel, szimbolikus változókkal, feltételekkel, aritmetikával, a környezet elmentésének lehetőségével és információcserével. Az argumentumoktól függően számos assembly utasítássá és adatdefiníciókká fejtődik ki. Implementálhat egész algoritmusokat, rekordszerű adatszerkezeteket, vagy akár vezérlési szerkezeteket. Ha az assemblyt számos ilyen makró bővíti, akkor egy magas szintű nyelvet kapunk, mert a programozók nem közvetlenül a legalacsonyabb szintű fogalmi elemekkel dolgoznak. Makrókkal implementálták a SNOBOL4 egy korai virtuális gépét (1967), amit teljes egészében a SNOBOL Implementation Language (SIL) nyelven írtak, amit makró assemblerekkel írtak át natív assemblerre.[8] Ez hordozhatóvá tette egy hosszabb időre.

Makrókat használtak nagy programrendszerek konfigurálására, például operációs rendszerek vevőre szabott saját verzióihoz is. Például így állították be az IBM rendszerprogramozói is a következőket: Conversational Monitor System / Virtual Machine (VM/CMS), IBM valós idejű tranzakciófolyamatai, Customer Information Control System CICS, ACP/TPF légiforgalmi és pénzügyi rendszer. Ez utóbbi az 1970-es évektől létezik, és nagy lefoglalási rendszereket (CRS) és hitelkártya-rendszert irányít még ma (2017) is.

Lehetséges más nyelveket pusztán assembler makrókkal implementálni, így lehetséges például COBOL programot írni assemblyben. Az IBM OS/360 rendszergenerálásra használja. A felhasználó az opciókat assembler makrók sorozatának kódolásával adja meg. Ezek fordítása a rendszer munkafolyamatai közé tartozik.

Ennek az az oka, hogy a makrók feldolgozása független az assemblytől; az előbbi inkább szövegfeldolgozás, mint kódgenerálás. Hasonlóan működik a C preprocesszora, ahol a makrókkal lehet konstansokat definiálni, és feltételt vizsgálni, de hiányzik belőle a ciklus, a goto és a rekurzió lehetősége, emiatt a C makrók nem alkotnak Turing-teljes nyelvet. A makrók nincsenek tekintettel a nyelvi elemekre, így a legtöbb magas szintű nyelvben nem bátorítják használatukat, mert rendelkezésre állnak más eszközök is, de az assemblyben hasznosságuk miatt megmaradtak. Azonban még az assembler makrók esetén is figyelni kell arra, hogy paraméterként csak név adható meg, és az bemásolódik a paraméter helyére. A kifejezések megadása nevezetes programozási hiba.

Példa:

foo: macro a
load a*b

a makró egy egyszerű nevet vár, és egy globális b változót vagy konstanst, amivel megszorozza az "a"-t. Ha ehelyett a foo makrót az a-c paraméterrel hívják meg, akkor az eredmény load a-c*b lesz. Az efféle félreértések elkerülése érdekében a makrón belül a paramétereket zárójelezni kell.[9]

A strukturált programozás támogatása

[szerkesztés]

Egyes assemblerek beépítetten tartalmazzák a strukturált programozás vezérlőszerkezeteit. Erre a legkorábbi példa a Dr. Harlan Mills által 1970 márciusában javasolt Concept-14 makrókészlet, amit Marvin Kessler implementált az IBM's Federal Systems Divisionnél. Ez az S/360 makró assemblert bővítette.[10] Célja a spagettikód elkerülése, és a GOTO használatának visszaszorítása. A megközelítés az 1980-as évek elején vált általánosan elfogadottá.

A terv egy érdekes megvalósítása volt az A-natural stream-orientált assembly a 8080/Z80 processzorok számára. A Whitesmiths Ltd. fejlesztette ki; az ő termékük volt az Unix-szerű Idris operációs rendszer, és ők készítették az első kereskedelmi C fordítót. A nyelvet assemblyként kategorizálták, mivel nyers gépi elemekkel működött, azonban kifejezésszintaxisa magában foglalta a műveletek sorrendjének meghatározását. Erre zárójelek és más speciális szimbólumok, továbbá blokkos strukturált programszerkezetek szolgáltak. Beépítették a C-fordítóba, kézzel keveset programoztak vele, habár logikus felépítése népszerűvé tette.

Mivel az assemblyt már nem használják széles körben, kevésbé van igény fejlettebb assemblerekre.[11] Ennek ellenére a nyelv nem tűnt el; akkor használják, ha az erőforrások szűkössége vagy a célrendszer jellegzetessége miatt a magasabb szintű nyelvek nem hatékonyak.[12]

A makrókat jól kezelő assemblerek makrók segítségével lehetővé teszik a strukturált programozást, például a Masm32 csomag biztosítja a switch szerkezetet. Egy teljes program:

include \masm32\include\masm32rt.inc	; use the Masm32 library

.code
demomain:
  REPEAT 20
	switch rv(nrandom, 9)	; generate a number between 0 and 8
	mov ecx, 7
	case 0
		print "case 0"
	case ecx				; in contrast to most other programming languages,
		print "case 7"		; the Masm32 switch allows "variable cases"
	case 1 .. 3
		.if eax==1
			print "case 1"
		.elseif eax==2
			print "case 2"
		.else
			print "cases 1 to 3: other"
		.endif
	case 4, 6, 8
		print "cases 4, 6 or 8"
	default
		mov ebx, 19		     ; print 20 stars
		.Repeat
			print "*"
			dec ebx
		.Until Sign?		 ; loop until the sign flag is set
	endsw
	print chr$(13, 10)
  ENDM
  exit
end demomain

Assembly nyelvjárások

[szerkesztés]

A különféle architektúráknak, platformoknak, processzoroknak eltérő, egymással általában semmilyen kompatibilitást nem biztosító assembly nyelvei vannak, bár ezen nyelvek alapszerkezete nagyon hasonló.

Intel x86 (8086 – 80486 – Pentium)

[szerkesztés]
  • Intel szintaxis
    • Microsoft Macro Assembler (MASM, Microsoft) – Ingyenesen hozzáférhető a MASM32 projekt részeként [1]
    • Turbo Assembler (TASM, Borland) [2]
    • Netwide Assembler (NASM, GNU) [3]
    • High Level Assembler (HLA, Public Domain) – Randall Hyde-nak, a The Art of Assembly Language című könyv szerzőjének saját assemblere [4]
    • Flat Assembler (FASM, GNU GPL) [5]

Példa (C eredeti: *p = n):

MOV  EDX,[EBP-16]
MOV  EAX,[EBP-20]
MOV  [EDX],EAX
  • AT&T szintaxis
    • GNU Assembler (GAS, GNU)

Példa (ugyanaz, mint az előbbi):

mov    -16(%ebp),%edx
mov    -20(%ebp),%eax
mov    %eax,(%edx)

MOS-6510

[szerkesztés]

A MOS Technology 6510 (pontosabban, a 65xx, 75xx, 85xx processzorcsalád) a Commodore 64 és társai (mint amilyen a C16, VIC-20 vagy a Commodore 128) processzora. Három általános célú nyolc bites regiszterrel rendelkezik: az A akkumulátorral, valamint az X és Y indexregiszterekkel. Címtartománya 64 kilobyte, de külön címzési módok támogatják az első 256 bájt (00xxH címek, az úgynevezett zero page, nullás lap) elérését, a második 256 bájt (01xxH címek) pedig rögzítetten a verem (stack) helye (ezért az S jelű veremmutató regiszter is csak nyolc bites).

Motorola 68xxx

[szerkesztés]

Ezek a processzorok főként a Commodore Amiga és a korai Apple Macintosh gépekben váltak ismertté.

Az Intel 8080 adaptációjaként a Zilog cég által gyártott, és korának legelterjedtebb processzorának nyelve. Számos összetettebb utasítással is rendelkezik. A Z80 assembly nyelve az Intel 8080-asénak egy kibővített és egyben egyszerűsített változata, például az összes adatmozgató utasítás mnemonikja egységesen LD, szemben a 8080 különféle változataival, például:

 8080            Z80
 -----           -----
 MOV  A,B        LD   A,B
 MOV  A,M        LD   A,(HL)
 MOV  M,A        LD   (HL),A
 LDAX B          LD   A,(BC)
 STAX B          LD   (BC),A
 MVI  A,n        LD   A,n
 LXI  H,nn       LD   HL,nn
 LHLD cím        LD   HL,(cím)

IBM System/360

[szerkesztés]

Az IBM mainframe-ei processzorainak nyelve. Tizenhat általános célú 32 bites regisztere van (R0-R15), a használható címtartomány eredetileg 24 bites volt (16 MiB címtartomány), a System/370-es sorozattól ez 31 bitesre bővült (2 GiB címtartomány). A gépi utasítások 2, 4 vagy 6 byte hosszúak, a használható adattípusok: byte, félszó (16 bit), szó (32 bit), duplaszó (64 bit), pakolt és 'zónázott' decimális szám (1-16 byte), általános memóriaterület (1-256 byte). Kétcímű gép, azaz egy utasításban két memóriaterület is szerepelhet.

Példaprogram (egy eljárás tipikus kezdete/vége/hívása):

RUTIN STM   R14,R12,12(R13) ; regiszterek mentése a hívó
                            ; regisztermentési területére
      BASR  R12,R0          ; bázisregiszter beállítása
      USING *,R12           ; assembly direktíva:
                            ; használd a bázisregisztert
      LA    R14,SAVEA       ; saját mentési területünk
      ST    R13,4(R14)      ; elmentjük a hívóét
      LR    R13,R14         ; használjuk a sajátunkat

      

KILÉP L     R15,visszatérési_érték
      L     R13,4(R13)      ; vissza a hívó mentési területére
      L     R14,12(R13)     ; visszatérési cím
      LM    R0,R12,20(R13)  ; hívó regisztereinek visszatöltése
                            ; kivéve az R15-öt
      BR    R14             ; visszatérés
SAVEA DS    18F             ; regisztermentési terület: 72 byte

      

HÍVÁS L     R15,=A(RUTIN)   ; rutin címe R15-be
      LA    R1,paraméterek_címe
      BASR  R14,R15         ; ugrás R15-re,
                            ; visszatérési cím R14-be
UTÁNA LTR   R15,R15         ; visszaadott érték vizsgálata
      BZ    SIKER           ; tipikusan 0=siker

További részletek

[szerkesztés]

Minden programozható eszközre van assembler, némelyikre akár több tucat.

Unix rendszereken az assembler neve hagyományosan as. Ez nem egyetlen kódtest, hanem minden portra más. Unix változatok sora a GNU Assemblert használja, amit néha a gas névvel illetnek. Ez egy keresztassembler, ami számos gazdagépen számos célgép számára fordít.

Néhány assembler képes más assembler nyelvjárását olvasni, például a TASM a régi MASM-kódot, és abból tud TASM-kódot készíteni, de ezt nem tudja a másik irányba megcsinálni. A FASM és a NASM szintaxisa hasonló, de más makrókat támogatnak, ezért nehéz átírni egyiket a másikra. Az alapok azonosak, de a fejlettebb eszközök eltérnek.[13]

A sok különféle nyelvjárás ellenére néha hordozható az assembly program a különféle operációs rendszerek és az azonos típusú processzorok között. A különféle operációs rendszerek hívási konvenciói gyakran alig vagy egyáltalán nem különböznek. Egy utasításkészlet szimulátor bármely assembler binárisát vagy tárgykódját fel tudja dolgozni, így segít hordozhatóvá tenni a kódot a különféle platformok között, és az időveszteség nem nagyobb, mint egy tipikus bájtkód értelmezőnél. Ez hasonló ahhoz, hogy mikrokódokkal elérni a hordozhatóságot egy processzorcsalád tagjai között.

Egyes magasabb szintű nyelvek, mint a C vagy a Pascal lehetővé teszik assembly kód inline használatát. Az assembly kódszakaszok lehetnek több sorosak, de rendszerint rövidek. A Forth nyelvben ezek CODE szavakban használhatók.

Az assembly nyelvű programok javításához emulátorok használhatók.

A nyelv előnyei és hátrányai

[szerkesztés]

Az összehasonlítást a magas(abb) szintű programozási nyelvekkel szemben kell érteni.

Előnyei

[szerkesztés]
  • Kisebb méretű kód, mert a programozó maga dönti el mely utasítások szükségesek az adott probléma megoldásához.
  • Az esetek többségében gyorsabb futás jellemzi.
  • Könnyebben lehet optimalizálni mind memória használatra, mind futási sebességre.
  • Vannak olyan eszközök (pl. mikrovezérlők), amelyek nagyon kis méretű operatív tárral és memóriával rendelkeznek, és feldolgozási sebességük is igen lassú. A magas szintű nyelvek pedig az assemblyvel szemben többnyire lényegesen nagyobb programkódot állítanak elő, és sem a memória, sem pedig a futási sebességre nem igazán lehet velük optimalizálni.
  • Bitműveletek használata egyszerűbb.
  • Az általunk megírt eljárások pontos működését ismerjük, könnyebben lehet további speciális célokra úgy módosítani, hogy az ne vonjon maga után aránytalanul nagyobb kódot, memória használatot, vagy hosszabb futási időt, sőt az esetek többségében még javíthatunk is rajta!
  • A nyelv határai a rendelkezésre álló hardver(ek) tényleges határáig terjednek, más szóval: a programozó a rendelkezésre álló hardver(ek) összes elérhető funkcióját 100%-ig ki tudja használni.

Hátrányai

[szerkesztés]
  • A komoly számítást igénylő feladatok elvégzése sok munkát és hozzáértést igényel.
  • Vannak olyan eszközök, amelyek olyan alapvető matematikai műveleteket sem tartalmaznak, mint a szorzás vagy az osztás. Assembly nyelven ezeket kézzel kell megvalósítani, ezzel szemben a magas szintű programnyelvek beépített támogatást nyújthatnak hozzájuk.
  • Maga a forrás nehezebben átlátható annak strukturálatlansága és hossza miatt.
  • Platform-függő, azaz szorosan kötődik az adott processzorhoz és/vagy futtató szoftver(ek)hez. Emiatt vagy a szoftver forrásának átírása, vagy emulátorban való futtatása jelenthet megoldást más környezetre való áttéréskor.
  • Az optimalizálási előny csekély olyan rendszerekben, ahol kimagaslóan sok regiszter áll rendelkezésre a futtató processzorban, vagy sok processzor áll rendelkezésre a feladatok megosztására.

Használata

[szerkesztés]

Az assembly egyidős a tárolt programot futtató számítógépekkel. Előnye a gépi kóddal szemben az, hogy könnyebben megjegyezhető, és gyorsabban írhatók vele programok. A programozóknak nem kell számkódokat megjegyezniük és memóriacímeket számolniuk, mert azt az assembler elvégzi. A korai időktől kezdve széles körben használták. Az 1980-as években visszaszorult, de azóta sem tűnt el teljesen. A mikroszámítógépeken az 1990-es években szorult vissza.

Régen (1980-as évek/1990-es évekig)

[szerkesztés]

A történelmi időkben számos program készült csak assemblyben, például operációs rendszerek. Az első más nyelven írt operációs rendszer a Burroughs MCP (1961) volt, ami teljes egészében egy Algol nyelvjárásban, az Executive Systems Problem Oriented Language (ESPOL) nyelven készült. Kereskedelmi programok is készültek assemblyben, például az IBM mainframe szoftver, amit nagy cégek írtak. Nagyobb szervezetek egész sora az 1990-es évekig ragaszkodott az assemblyhez, habár addigra elterjedtek más nyelvek, mint COBOL, FORTRAN és PL/I.

A legkorábbi mikroszámítógépek a kézzel kódolt assemblyre hagyatkoztak, beleértve a legtöbb operációs rendszert és nagy programot. Erre azért volt szükség, mert az erőforrások szűkösek voltak, sajátos típusú memóriájuk és képernyőjük, továbbá rendszerszolgáltatásaik is korlátozottak voltak. Döntőnek bizonyult, hogy nem voltak fordítók a magas szintű nyelvek számára; és ahelyett, hogy írtak volna, inkább maradtak az assemblynél. Emellett a mikroszámítógépek programozóinak első nemzedéke lélekben hobbiprogramozó maradt.

Kereskedelmi szempontból az assembly előnyei voltak a kis méret, a kevés adminisztráció, a gyorsaság és a megbízhatóság.

A korszak jellemző assembly nyelvű programjai voltak az IBM PC DOS operációs rendszerei és a Lotus 1-2-3 táblázatkezelők. Még az 1990-es években is assemblyben íródott a legtöbb videójáték, többek között a Mega Drive/Genesis számára készültek, és a Super Nintendo Entertainment System. Egyes fejlesztők véleménye szerint az assembly volt a leggyorsabb nyelv a Sega Saturn számára, egy konzol, amire kihívás volt programokat, különösen videójátékokat írni.[14] Egy másik példa az NBA Jam (1993) táblajáték.

Sokáig személyi számítógépekre is az assembly maradt a fő nyelv, mivel a BASIC lassú volt, és nem tudta kihasználni a rendszer lehetőségeit. E típusok közé tartozott az MSX, a Sinclair ZX Spectrum, a Commodore 64, a Commodore Amiga, és az Atari ST. Egyes rendszerek beépített assembly fejlesztőkörnyezettel érkeztek, fejlett hibakereséssel és makró rendszerrel.

Napjainkban

[szerkesztés]

Az assembly nem versenyez a magas szintű programozási nyelvekkel sajátos szűk körű alkalmazási területei miatt. A TIOBE index listáján is előkelő helyet foglal el, 2016 novemberében a kilencedik helyen állt, ezzel megelőzve például a Swiftet és a Rubyt.[15]

Az assemblerek a méretre és sebességre optimalizálást hatékonyabban végzik, mint a magasabb szintű nyelvek fordítói,[16][17][18] habár vannak, akik ezt vitatják.[19] A modern eszközök, processzorok és memóriák egyre bonyolultabbá teszik minden fordító számára az optimalizálást.[20][21] A processzorok megnövekedett teljesítőképességük miatt sokszor üresen állnak,[22] vagy várakoznak I/O műveletek vagy memória lapozás miatt. Emiatt a legtöbb programozó keveset törődik az optimalizációval.

Manapság legelterjedtebben mikrovezérlő alapú rendszerekben alkalmazzák, mivel ott sokszor maga a futtató eszköz és/vagy annak környezete nem teszi lehetővé magas szintű nyelvek alkalmazását vagy akár fordítóprogramok létrehozását (túl kevés támogatott utasítás, kis méretű memória illetve stack, stb.). Megjegyzendő azonban, hogy a mikrokontroller architektúrák robbanásszerű fejlődése eredményeképp erősen terjed a C, C++ nyelv használta is e téren.

„Nagyszámítógépes” környezetben (PC-k, munkaállomások stb.) a hardverillesztő szoftvert és az operációs rendszert programozók írnak assembly nyelven, más esetekben használata ritka, csak a nagyon méret- vagy időkritikus feladatoknál alkalmazzák.

A legtöbb informatikai képzésen tanítanak assemblyt. Habár már kevesen használják a gyakorlatban, a legalapvetőbb fogalmak, mint kettes számrendszerbeli aritmetika, memóriafoglalás, stack processing, megszakításfeldolgozás, karakterkódolás és fordítótervezés igazán csak alacsony szinten érthetők meg. Mivel a számítógép viselkedése alapvetően utasításkészletétől függ, logikus ezeket egy assemblyn tanulmányozni.

Tehát az assemblyvel megtanulhatók: az alapfogalmak; annak felismerése, mikor érdemes assemblyt használni; és felmérni a magas szintű nyelvekből fordult kód hatékonyságát.[23] Ez megfelel annak, hogy a gyerekek megtanulnak számolni, habár a számológépeket elterjedten használják.

Tipikusan assemblyben készül:

  • Operációs rendszer boot kódja. Ez egy alacsony szintű kód, ami inicializálja és teszteli a hardvert az operációs rendszer indítása előtt. Gyakran a ROM tárolja.
  • Egyes fordítók először assemblyre fordítanak, majd ezt fordítják tovább. Ez lehetővé teszi, hogy az assemblyt hibakeresés és optimalizáció céljából megtekintsék.
  • Egyes nyelvek, például a C lehetővé teszik az assembly kód közvetlen beágyazását. Ezzel a programok képesek különböző assembly nyelvjárásokkal absztrakciót építeni, aminek segítségével a kód több platformra is lefordítható. Ezt a módszert használja a Linux rendszermag is.
  • Assemblyvel növelhető a futás sebessége, különösen a régi gépeken, ahol korlátozottak az erőforrások.
  • Az assembly hasznos a visszafejtésben és a programok feltörésében is. Sok programot csak futtatható bináris formában terjesztenek. A crackerek disassemblerrel assemblyre tudják visszafejteni, míg a magasabb szintű nyelvekre fordítás nehézkesebb.
  • Assemblyvel a magas szintű nyelveknél gyorsabban generálhatók adatblokkok, amiket más nyelvek is fel tudnak használni.
  • Közvetlenül a hardverrel kapcsolatban álló kód, például eszközmeghajtók és megszakításkezelők.
  • Egy önálló, kompakt alkalmazás, ami nem használhatja a magas szintű nyelvek futásidejű komponenseit vagy könyvtárait. Például telefonok, autók, légkondicionálók, biztonsági eszközök, szenzorok esetén.
  • Beágyazott processzorokban vagy DSP-kben nagyon sok megszakítást kell kezelni, akár másodpercenként 1000 vagy 10000 darabot.
  • Programok, amelyek azokra az utasításokra van szükségük, amiket nem implementál fordító. Erre egy példa a bitenkénti forgatás, egy bájt paritásának lekérdezése, vagy egy 4 bites összeadás átvitelének lekérdezése; ezeket titkosító és hashelő algoritmusok széles körben használják.
  • Vektorizált függvényeket előállító programok. Néha ezeket a magas szintű nyelv fordítója belső függvényekkel végzi, amiket egy az egyben fordít az adott vektorprocesszor számára.
  • Olyan helyzetekben, amikor nem lehet magas szintű nyelvet használni, például egy újfajta processzor esetén.
  • Erős optimalizációt igénylő programok, például egy processzor-intenzív algoritmus ciklusának magja. A hardver képességeinek így nagy hasznát vehetik a játékfejlesztők, ezzel felgyorsítva a játékot. Nagy méretű tudományos programok szintén igényelhetnek erős optimalizációt, például a BLAS lineáris algebrája,[16][24] vagy a diszkrét koszinusz transzformáció.[25]
  • Pontos időzítést igénylő programok, például repülésnavigáció, orvosi eszközök és kriptográfiai algoritmusok.
  • Az IBM mainframe számítógépekre készült legacy kód bővítése és módosítása.
  • A környezet teljes kontroll alatt tartása, például amikor a biztonság forog kockán, és semmit nem lehet biztosra venni.
  • Hardver közeli, vagy az operációs rendszer alacsony szintjéhez tartozó algoritmusok, mint eszközmeghajtók, boot betöltők, és vírusok.
  • Utasításhalmaz szimulátorok, megfigyelők, nyomkövetők, debuggerek, az adminisztrációs idő minimalizálásával.
  • Grafikus számológépekre írt programok
  • Önmódosító kód
  • Kódvisszafejtés és programok módosítása, mint:
    • Videójátékok; gyakran assembly szinten módosítják.
    • Különböző egyéb programok visszafejtése. Ez történhet azért, hogy pótolják az elveszett forráskódot, vagy hogy feltörjék a programot a másolásvédelem kiiktatásával.

Egy példa

[szerkesztés]

Ez a példa (rutin) a Z80-as (Zilog Z80) mikroprocesszor assemblyjében íródott. Bájtok blokkját másolja át a memória (RAM) egyik helyéről (címéről) a másikra. Értelme a Sinclair ZX Spectrum számítógépen az, hogy a másolás a videomemória célterületére történik (a gyakorlatban arra használták, hogy a például egy sok számítást igénylő kép előállítása ezen a számítógépen sokáig tartott, s ha annak folyamatát a felhasználó elől el akarták rejteni, akkor először a memória egy használatlan területén állították elő a képet, majd ez – nagyon rövidke idő alatt – be lett másolva a videomemória területére. A megjegyzések pontosvesszővel vannak elválasztva a programkódtól.

        ld    hl, 16384      ; a hl regiszterpárba a videomemória első bájtjának címe kerül
        ld    bc, 6912       ; a bc regiszterpárba kerül az átmozgatott blokk hossza (a videomemória hossza) bájtban
        ld    de, 40000      ; a de regiszterpárba a forráscím
 loop   ld    a, (de)        ; az a regiszterbe a forrás értéke kerül
        ld    (hl), a        ; a hl regiszterpár értékének a címére a kiolvasott érték kerül
        inc   hl             ; célcím növelése eggyel
        inc   de             ; forráscím növelése eggyel
        dec   bc             ; a hátralévő hossz csökkentése
        ld    a, b           ; ez és a következő sor a vizsgálja, hogy a bc regiszterpár
        or    c              ; értéke 0
        jr    nz, loop       ; ha nem, ugrás vissza (a loop fejlécű sorra)
        ret                  ; visszatérés

Érdekes megfigyelni a tizenhat bites bc regiszterpár nullás értékének vizsgálatát egy nyolcbites regiszterrel, ami két lépésben történik. Először az ld a, b utasítással a b regiszter értéke (mely a bc regiszterpár egyik regisztere) az a regiszterbe töltődik, majd az or c utasítással az a és a c regiszter értékei közt or logikai utasítás hajtódik végre, melynek értéke az a regiszterbe kerül. Ha az eredmény éppen 0, az azt jelenti, hogy a bc regiszterpár értéke is éppen 0 és a jr nz, loop feltételes ugrás nem hajtódik végre (de egyébként igen).

Az Intel 8080-as processzorhoz képest fejlettebb utasításkészletnek köszönhetően az előző példát egyszerűbben is megírhatjuk (és gyorsabb lesz a végrehajtási sebesség is: előző esetben 52 órajel/bájt, következő esetben 21 órajel/bájt):

        ld    bc,6912     ;bc-ben a hossz bájtokban
        ld    de,40000    ;de-ben a forrásterület címe
        ld    hl,16384    ;hl-ben a célterület címe
        ldir              ;blokkmozgató utasítás automata ismétléssel (21 órajel átvitt bájtonként)
        ret

A játékokhoz korábban a végsőkig igénybevették a processzorok számítási teljesítményét. Pl a következő trükkel újabb 25%-nyi időt nyerhetünk (16,5 órajel/bájt):

        ld    b,0         ;számláló (0=256)
        ld    de,40000
        ld    hl,16384
 loop   ldi               ;blokkmozgató utasítás, nem ismétel (16 órajel)
        ldi
        .
        .
        .
        ldi               ;összesen 27 db ldi utasítás egymás után (27*256=6912)
        djnz  loop        ;b-t csökkenti és visszaugrik, ha b<>0 (13 órajel)
        ret

Hello World

[szerkesztés]

Példa "hello.asm" állomány tartalma :

  ORG  100H             ; ez minden COM allomany elejen jelen kell legyen egy
                        ; COM allomany maximum 64 KB meretu, es egyetlen 64 KB-os
                        ; teruleten van jelen az adat, kod es verem szegmens is;
                        ; az elso 256 byte (100h) a DOS szamara van fenntartva;
                        ; mind a negy szegmensregiszter erteke azonos, így nem
                        ; kell ezeket a legtobb esetben valtoztatnunk

start:
  mov  dx, uzenet       ; DS:DX-be helyezzuk a kiirando uzenet kezdocimet; a
                        ; DS-t mar nem kell beallitani, mert COM allomanyban vagyunk
                        ; az uzenet DOS-os formatumu, azaz $ jellel vegzodik (0x24)

                        ; NASM-ban egy valtozo cimere a nevevel (pl. uzenet) hivatkozunk
                        ; a cimen levo ertekre pedig a [nevevel] (pl. [uzenet]) hivatkozunk

  mov  ah, 09h          ; DOS 21h / 09h - DOS-os string kiirasa
  int  21h

  xor  ah, ah           ; egy BIOS megszakitas hivasa: varakozas egy billentyu lenyomasara
  int  16h              ; leirasert lasd Tech Help! 6.0

  int  20h              ; a COM programok vegen a 0x20 megszakitas meghivasaval fejezzuk
                        ; be a program futasat es adjuk vissza a vezerlest az operacios
                        ; rendszernek
  
adatok:
  
  uzenet db "Hello, World!", 0x0D, 0x0A, "$"

Jegyzetek

[szerkesztés]
  1. a b David Salomon (1993). Assemblers and Loaders
  2. Beck, Leland L.. 2, System Software: An Introduction to Systems Programming. Addison Wesley (1996) 
  3. Hyde, Randall. "Chapter 12 – Classes and Objects". The Art of Assembly Language, 2nd Edition. No Starch Press. © 2010.
  4. Intel Architecture Software Developer's Manual, Volume 2: Instruction Set Reference. Intel Corporation (1999). Hozzáférés ideje: 2010. november 18. 
  5. a b c Intel Architecture Software Developer's Manual, Volume 2: Instruction Set Reference. Intel Corporation, 442 and 35. o. (1999). Hozzáférés ideje: 2010. november 18. 
  6. Evans, David: x86 Assembly Guide. University of Virginia, 2006. (Hozzáférés: 2010. november 18.)
  7. Microsoft Corporation: MASM: Directives & Pseudo-Opcodes. [2018. május 17-i dátummal az eredetiből archiválva]. (Hozzáférés: 2011. március 19.)
  8. Griswold, Ralph E. The Macro Implementation of SNOBOL4. San Francisco, CA: W. H. Freeman and Company, 1972 (ISBN 0-7167-0447-1), Chapter 1.
  9. Macros (C/C++), MSDN Library for Visual Studio 2008. Microsoft Corp.. (Hozzáférés: 2010. június 22.)
  10. Concept 14 Macros. MVS Software. (Hozzáférés: 2009. május 25.)[halott link]
  11. Answers.com: assembly language: Definition and Much More from Answers.com. (Hozzáférés: 2008. június 19.)
  12. Provinciano, Brian: NESHLA: The High Level, Open Source, 6502 Assembler for the Nintendo Entertainment System
  13. Randall Hyde: Which Assembler is the Best?. [2007. október 18-i dátummal az eredetiből archiválva]. (Hozzáférés: 2007. október 19.)
  14. Eidolon's Inn: SegaBase Saturn. [2008. július 13-i dátummal az eredetiből archiválva]. (Hozzáférés: 2008. július 25.)
  15. TIOBE Index for November 2016”. [2020. március 24-i dátummal az eredetiből archiválva] (Hozzáférés: 2016. november 11.) 
  16. a b Writing the Fastest Code, by Hand, for Fun: A Human Computer Keeps Speeding Up Chips”, New York Times, John Markoff, 2005. november 28. (Hozzáférés: 2010. március 4.) 
  17. Bit-field-badness. hardwarebug.org, 2010. január 30. [2010. február 5-i dátummal az eredetiből archiválva]. (Hozzáférés: 2010. március 4.)
  18. GCC makes a mess. HardwareBug.org, 2009. május 13. [2010. március 16-i dátummal az eredetiből archiválva]. (Hozzáférés: 2010. március 4.)
  19. Rusling, David A.: The Linux Kernel. (Hozzáférés: 2012. március 11.)
  20. Randall Hyde: The Great Debate. [2008. június 16-i dátummal az eredetiből archiválva]. (Hozzáférés: 2008. július 3.)
  21. Code sourcery fails again. hardwarebug.org, 2010. január 30. [2010. április 2-i dátummal az eredetiből archiválva]. (Hozzáférés: 2010. március 4.)
  22. Click, Cliff: A Crash Course in Modern Hardware. (Hozzáférés: 2014. május 1.)
  23. Hyde, Randall: Foreword ("Why would anyone learn this stuff?"), op. cit.', 1996. szeptember 30. [2010. március 25-i dátummal az eredetiből archiválva]. (Hozzáférés: 2010. március 5.)
  24. BLAS Benchmark-August2008. eigen.tuxfamily.org, 2008. augusztus 1. (Hozzáférés: 2010. március 4.)
  25. x264.git/common/x86/dct-32.asm. git.videolan.org, 2010. szeptember 29. [2012. március 4-i dátummal az eredetiből archiválva]. (Hozzáférés: 2010. szeptember 29.)

Fordítás

[szerkesztés]

Ez a szócikk részben vagy egészben az Assembly language című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.

Kapcsolódó szócikkek

[szerkesztés]