( Chain-Q | 2016. 12. 14., sze – 10:54 )

Az assembler nem is igazan az utasitasok megfeleltetese miatt kell. Van egy csomo dolog alacsonyi szintu programozaskor is, amit emberi aggyal nehez lekepezni, es az assembler megcsinalja neked, foleg bonyolultabb architekturakon.

Pl. egy 6502 (8 bites processzor) eseten meg lattam elo embert gepi kodban progamozni, mivel a gepi kodja baromi egyszeru, 1, 2 v. 3 byteos utasitasok vannak, ahol az elso az opkod, a masodik es harmadik pedig altalaban egy cim, semmi cico. Ott viszonylag atlagos kepessegu humanoidok (mint en) is fel tudjak fogni hogy melyik szam mit jelent a processzornak, es ha nagyon akarod el lehet lenni assembler nelkul is.

Ellenben egy bonyolultabb architekturan, az utasitasok bitfieldekkel vannak encode-olva, szoval ha megvaltoztatod hogy az utasitas egy melyik regisztert hasznalja, akkor egy 32bites szam kozepen kell modositani egy 4 bites, neha hatulrol-elore encodeolt bitfieldet. Hat koszi. Vagy pl. az assembler szinten az utasitasok egysegesek, mindig azt irhatod le, hogy add reg1,reg2, de a gepi kodban tobbfele add utasitas van, attol fuggoen hogy melyik regisztereket adod ossze. Ezt is megcsinalja neked az assembler, kivalasztja h. melyik add kell neked a tobbfelebol. Nyilvan a gepi kod ugy van megcsinalva, hogy a processzort konnyu legyen implementalni, es/vagy kompatibilis legyen, az assembly pedig egy vekony reteg rajta, ami szoftveres aggyal is ertelmezhetove teszi a rengeteg bitet es szamot amivel dolgozik.

De ezeknel sokkal jelentosebb, hogy az assember, architekturaktol teljesen fuggetlenul:

- Valtozo <-> Cim megfeleltetest csinalni. Nem kell emlekezned, hogy a $8534 offset az vezetek_nev, valtozo, hanem forditaskor az assember behelyettesiti a valtozot a cimevel.

- Cimkeket hasznalni, a belepesi pontokhoz, az ugro utasitasokhoz. Ha ez nem lenne minden ugro utasitashoz neked kene kiszamolni kezzel, hogy az vagy milyen messze van a jelenlegi cimtol, vagy fix offsetre bedrotozni a kododban. Ha modositod a kodot, az osszes cimet az osszes ugro utasitasban at kene irnod kezzel... Ez mar csak azert is fontos, mert pl. rengeteg architakturan attol fuggoen hogy az ugras celpontja milyen messze van a jelenlegi poziciotol, masfele ugro utasitast hasznalhatsz, ami adott esetben rovidebb (optimalisabb) opkodra fordulhat. Ezt is jo, ha nem neked kell kezzel kiszamolni a cim tavolsagat, majd kezzel kivalasztani az utasitast (opkodot).

- Alignment. Bizonyos architekturak megkovetelik, hogy byte-nal nagyobb ertekek igazitva legyenek paros, neggyel oszthato stb. cimekre. Vagy optimalizacional sokszor elkerulethetetlen, hogy a kodot is igazitsd, pl. cache-line merettel oszthato cimre (pl. ciklusoknal, amik sokszor vegrehajtodnak). Az assemblerek tartalmaznak direktivakat es makrokat, amikkel elkerulheto, hogy ezt neked kelljen kezzel megtenni, es utana karbantartani a megfelelo mennyisegu NOP utasitassal, stb.

- Ezek fentiek annyira fontos muveletek, hogy egy rakas magas szintu fordito szimplan az alatta levo assemblerre bizza, es egyaltalan nem foglalkozik a magas szintu kod forditasakor ilyesmivel! Ergo assemblyre forditanak, nem gepi kodra! (A legtobb fordito ezt az assembly kodot le is tudja neked menteni, pl. a GCC a -save-temps parameterrel, Free Pascal -al parameterrel, stb...)

- Szintaxis ellenorzest vegezni. Ennek az elonye egyertelmu, meg a gepi kod, a szamok szintjen is van olyan hogy hibas utasitas, vagy az adott processzor altal nem tamogatott utasitas. Ha megmondod egy assemblernek mi a celprocesszor, megmondja hogy a kod amit irtal, fog-e rajta futni.

- Makrozni. Kezi programozaskor nem kell magyarazni a hasznukat, a sokszor ismetelt utasitas-mintakat makrokba rakhatod, amiket az assembly fordito megismetel neked. Sokszor meg magasabb szintu nyelvek is hasznalnak assembly makrokat. Bizonyos processzorokon (pl. PowerPC) az utasitasok egy resze szimplan "makro" vagy egyeb syntax sugar, amelyek csak egyszerusitett parameterezesei valamely joval bonyolultabb utasitasnak.

- Binary encapsulation. Az assembler ismeri a kimeneti formatumokat amiket a linker vagy az operacios rendszered linkere elvar. Ergo nem kell neked kezzel irni objektum es exe fejlecet.

Es meg tudnek egy rakas dolgot ideirni, amit az assembler csinal. A legtobb ember ugy kepzeli a forditas muveletet, hogy megirom X magas szintu nyelven -> kod es exe file, kesz.

Ehelyett altalaban az van, meg forditott (nem VM/interpretalt/JIT) nyelveknel is hogy:

- megirod a magas szintu kodot, OOP, funkcionalis, whatever...
- a magas szintu fordito kihajigalja az OOP, funkcionalis egyeb dolgokat es sima proceduralis/strukturalt kodot csinal belole, mert azt lehet megfeleltetni aztan legegyszerubben a kesobbi assembly kodnak. Kiszorjak a syntax sugart, a bonyolultabb nyelvi strukturak kezelesehez tablazatokat es segedfuggvenyhivasokat (a runtime library-ba (pl. libc)) generalnak.
- a proceduralis/strukturalis kod, vagy annak valamely belso reprezentacioja vegul assemblyre fordul.
- az assembler leforditja az assemblyt gepi kodda es objektum fajlokka (.o fajlok). Altalaban ezen a szinten meg megfelel, hogy 1db. .c, .cpp, .pas, .m, akarmi fajlbol 1db .o fajl lesz a vegen.
- es ezutan jon a linkelesi szakasz, amikor a linker a rengeteg forrasfajlod leforditasa vegen nyert rengeteg .o fajlbol gyart egy futtathato allomanyt (vagy .dll-t, vagy .so-t vagy akarmit), olyan allomanyt, amit aztan egy oprendszer is ertelmezni tud.

Nagyon nagy vonalakban, es pongyolan... :)

-=- Mire a programozó: "Na és szerintetek ki csinálta a káoszt?" -=-