Gjuha assembler

Në fushën e informatikës, **gjuha assembler** (e njohur edhe si: *kod simbolik i makinës*) është një gjuhë programimi e nivelit të ulët që lidhet ngushtë me udhëzimet e kodit të makinës të arkitekturës përkatëse. Shpesh quhet thjesht *assembly* dhe shkurtohet si **ASM** ose **asm**. Në gjuhën e asamblerit, zakonisht çdo deklaratë përfaqëson një udhëzim të vetëm të kodit të makinës (raporti 1:1). Megjithatë, përveç udhëzimeve, zakonisht mbështeten edhe elementë shtesë si konstante, komente, direktiva të assembler-it, etiketa simbolike për regjistra ose adresa të kujtesës, si dhe makro-udhezime.

Kodi i parë i asamblesë në të cilin një gjuhë përdoret për të përfaqësuar udhëzimet e kodit të makinës gjendet në veprën e Kathleen dhe Andrew Donald Booth të vitit 1947, *Coding for ARC*.  Kodi i asamblesë shndërrohet në kod makine të ekzekutueshëm nga një program i dobishëm i referuar si *asambler*. Termi "asambler" i atribuohet përgjithësisht Wilkes, Wheeler dhe Gill në librin e tyre të vitit 1951 *Përgatitja e Programeve për një Kompjuter Elektronik Dixhital*,  të cilët, megjithatë, e përdorën termin për të nënkuptuar "një program që asamble një program tjetër që përbëhet nga disa seksione në një program të vetëm". Procesi i konvertimit quhet *asamble*, si në *asamblenë* e kodit burimor. Hapi llogaritës kur një asambler po përpunon një program quhet *koha e assemblerit*.

Meqenëse gjuha e asamblerit bazohet drejtpërdrejt në udhëzimet e kodit të makinës, çdo gjuhë e tillë është e lidhur ngushtë me arkitekturën specifike të kompjuterit ku përdoret. Për shembull, ekzistojnë variante të veçanta për arkitektura si **x86** apo **ARM**.

Në disa raste, për të njëjtën arkitekturë ekzistojnë më shumë se një assembler, ndërsa në raste të tjera një assembler mund të jetë i përshtatur posaçërisht për një sistem operativ të caktuar. Shumica e gjuhëve të asamblimit nuk ofrojnë sintaksë të veçantë për thirrjet e sistemit operativ, por mund të përdoren në mënyrë universale me çdo sistem operativ, pasi ato japin qasje të drejtpërdrejtë në funksionet reale të procesorit, mbi të cilat mbështeten mekanizmat e thirrjeve të sistemit. Në kontrast me gjuhët e asamblimit, gjuhët e programimit të nivelit të lartë janë zakonisht të bartshme në arkitektura të ndryshme, por kërkojnë interpretim ose kompilim – procese më të ndërlikuara sesa përpilimi i kodit të asamblimit.

Në dekadat e para të zhvillimit të kompjuterëve, ishte praktikë e zakonshme që si programimi i sistemeve ashtu edhe ai i aplikacioneve të realizoheshin plotësisht në gjuhën e asamblimit. Edhe pse kjo gjuhë mbetet e pazëvendësueshme për disa funksione specifike, sot pjesa më e madhe e programimit kryhet në gjuhë të nivelit më të lartë, të cilat interpretohen ose kompilohen. Në veprën e tij *No Silver Bullet*, Fred Brooks përshkroi ndikimin e kalimit nga programimi në asamblim drejt gjuhëve të nivelit të lartë: sipas tij, përdorimi progresiv i këtyre gjuhëve ka qenë faktori më i fuqishëm për rritjen e produktivitetit, besueshmërisë dhe thjeshtësisë së softuerit. Shumica e studiuesve e vlerësojnë këtë zhvillim si një rritje të produktivitetit të paktën pesëfish, e shoqëruar me përmirësime të dukshme në besueshmëri, thjeshtësi dhe kuptueshmëri.

Në ditët e sotme, përdorimi i gjuhës së asamblimit kufizohet zakonisht në segmente të vogla brenda sistemeve më të mëdha të shkruara në gjuhë të nivelit të lartë. Kjo bëhet kryesisht për arsye performance ose për të komunikuar drejtpërdrejt me pajisjen në mënyra që gjuhët e nivelit të lartë nuk i mbështesin. Si shembull, në versionin 4.9 të kernelit të Linux-it, më pak se 2% e kodit burimor është i shkruar në asamblim, ndërsa mbi 97% është i shkruar në gjuhën **C**.

## Sintaksa e gjuhës së asamblesë 
Gjuha e asamblimit përdor **mnemonikë** për të përfaqësuar udhëzimet e nivelit të ulët të makinës, direktivat, si dhe elementë të tjerë të arkitekturës si regjistrat dhe flamujt. Disa mnemonikë janë të paracaktuar nga sistemi, ndërsa të tjerë mund të përcaktohen nga vetë programuesi. Shumë operacione kërkojnë një ose më shumë **operanda** për të formuar një udhëzim të plotë.                                                                Assemblerët zakonisht lejojnë përdorimin e konstanteve të emërtuara, regjistrave dhe etiketave për programin dhe vendndodhjet e kujtesës, si dhe mund të kryejnë llogaritje për operandët. Kjo i shpëton programuesit nga llogaritjet e përsëritura dhe e bën kodin e asamblimit shumë më të lexueshëm sesa kodi i makinës. Në varësi të arkitekturës, këto elemente mund të kombinohen për udhëzime specifike ose mënyra adresimi, duke përdorur **zhvendosje**, të dhëna shtesë ose adresa fikse. Shumë assemblerë ofrojnë gjithashtu mekanizma shtesë për të lehtësuar zhvillimin e programeve, për të kontrolluar procesin e përpilimit dhe për të ndihmuar në debugim.

Disa gjuhë asamblimi janë të orientuara sipas kolonave, ku fushat vendosen në kolona të caktuara; kjo ishte shumë e zakonshme në makinat që përdornin kartat e shpuara gjatë viteve 1950 dhe fillimit të viteve 1960.                                                                                              Të tjera assemblerë përdorin sintaksë të lirë, ku fushat ndahen me ndarës si shenjat e pikësimit ose hapësirat. Ekzistojnë edhe forma hibride, ku p.sh. . etiketat vendosen në një kolonë të caktuar, ndërsa fushat e tjera ndahen me ndarës. Ky stil u bë më i zakonshëm se sintaksa e orientuar sipas kolonave gjatë viteve 1960.

## Terminologjia 
* Një **makro asembler** është një asembler që përfshin një strukturë makroinstruksionesh në mënyrë që teksti (i parametrizuar) i gjuhës assembler të mund të përfaqësohet nga një emër, dhe ky emër mund të përdoret për të futur tekstin e zgjeruar në kod tjetër.
** **Kodi i hapur** i referohet çdo inputi të assemblerit jashtë një përkufizimi makro.
* Një **cross-assembler** (shih gjithashtu cross compiler ) është një asembler që ekzekutohet në një kompjuter ose sistem operativ (sistemi *pritës* ) të një lloji të ndryshëm nga sistemi në të cilin do të ekzekutohet kodi që rezulton ( *sistemi i synuar* ). Cross-assembler lehtëson zhvillimin e programeve për sisteme që nuk kanë burimet për të mbështetur zhvillimin e softuerit, siç është një sistem i ngulitur ose një mikrokontrollues. Në një rast të tillë, kodi objekt që rezulton duhet të transferohet në sistemin e synuar, nëpërmjet memories vetëm për lexim (ROM, EPROM, etj.), një programuesi (kur memoria vetëm për lexim është e integruar në pajisje, si në mikrokontrollues), ose një lidhjeje të dhënash duke përdorur ose një kopje të saktë bit-për-bit të kodit objekt ose një përfaqësim të bazuar në tekst të atij kodi ( siç është Intel hex ose Motorola S-record ).
* Një **asembler i nivelit të lartë** është një program që ofron abstraksione gjuhësore që më shpesh shoqërohen me gjuhë të nivelit të lartë, siç janë strukturat e kontrollit të avancuara ( IF/THEN/ELSE, DO CASE, etj.) dhe llojet e të dhënave abstrakte të nivelit të lartë, duke përfshirë strukturat/regjistrimet, bashkimet, klasat dhe bashkësitë.
* Një **mikroasembler** është një program që ndihmon në përgatitjen e një mikroprogrami për të kontrolluar funksionimin e nivelit të ulët të një kompjuteri.
* Një **meta-assembler** është "një program që pranon përshkrimin sintaksor dhe semantik të një gjuhe assembler dhe gjeneron një assembler për atë gjuhë", ose që pranon një skedar burimor assembler së bashku me një përshkrim të tillë dhe assembler skedarin burimor në përputhje me atë përshkrim. Assemblerët "Meta-Symbol" për serinë e kompjuterëve SDS 9 dhe SDS Sigma janë meta-assemblerë. Sperry Univac gjithashtu ofroi një Meta-Assembler për serinë UNIVAC 1100/2200 .
* **Asambleri inline** (ose **asambleri i integruar** ) është kodi i asamblerit që përmbahet brenda një programi gjuhësor të nivelit të lartë.  Ky përdoret më shpesh në programet e sistemeve që kanë nevojë për qasje të drejtpërdrejtë në harduer.

## Konceptet kryesore 
### Asambler 
Një program assembler krijon **kod objekt** duke përkthyer kombinimet e mnemonikëve dhe sintaksës për operacionet dhe mënyrat e adresimit në ekuivalentët e tyre numerikë. Ky përfaqësim zakonisht përfshin një **kod operacioni (opcode)** si dhe bitë kontrolli dhe të dhëna të tjera. Assembleri gjithashtu llogarit shprehjet konstante dhe zgjidh emrat simbolikë për vendndodhjet e kujtesës dhe entitete të tjera. Përdorimi i referencave simbolike është një veçori kryesore e assemblerëve, pasi shmang llogaritjet e lodhshme dhe përditësimet manuale të adresave pas ndryshimeve në program.                                                        Shumica e assemblerëve përfshijnë edhe mekanizma të **makrove**, të cilat lejojnë zëvendësimin tekstual – për shembull, për të gjeneruar sekuenca të shkurtra udhëzimesh si kod inline, në vend që të thirren si nënprograme të veçanta.

Disa asemblerë mund të jenë gjithashtu në gjendje të kryejnë disa lloje të thjeshta optimizimesh specifike për setin e udhëzimeve. Një shembull konkret i kësaj mund të jenë asemblerët x86 të kudondodhur nga shitës të ndryshëm. Të quajtur "jump-sizing", shumica e tyre janë në gjendje të kryejnë zëvendësime të instruksioneve "jump-in" (kërcime të gjata të zëvendësuara nga kërcime të shkurtra ose relative) në çdo numër kalimesh, sipas kërkesës. Të tjerë madje mund të bëjnë rirregullim ose futje të thjeshtë të instruksioneve, siç janë disa asemblerë për arkitekturat RISC që mund të ndihmojnë në optimizimin e një planifikimi të arsyeshëm të instruksioneve për të shfrytëzuar tubacionin e CPU-së sa më efikas të jetë e mundur. 

Asamblerët kanë qenë të disponueshëm që nga vitet 1950, si hapi i parë mbi gjuhën e makinës dhe përpara gjuhëve të programimit të nivelit të lartë si Fortran, Algol, COBOL dhe Lisp. Ka pasur gjithashtu disa klasa përkthyesish dhe gjeneratorësh kodi gjysmë-automatikë me veti të ngjashme si me gjuhët e asamblesë ashtu edhe me ato të nivelit të lartë, me Speedcode si ndoshta një nga shembujt më të njohur.

Mund të ketë disa asemblerë me sintaksë të ndryshme për një arkitekturë të caktuar CPU-je ose grupi udhëzimesh. Për shembull, një udhëzim për të shtuar të dhëna memorieje në një regjistër në një procesor të familjes x86 mund të jetë `add eax,[ebx]`, në *sintaksën origjinale të Intel*, ndërsa kjo do të shkruhej `addl (%ebx),%eax` në *sintaksën AT&amp;amp;T* të përdorur nga GNU Assembler. Pavarësisht pamjeve të ndryshme, format e ndryshme sintaksore në përgjithësi gjenerojnë të njëjtin kod numerik makine. Një asembler i vetëm mund të ketë gjithashtu mënyra të ndryshme në mënyrë që të mbështesë variacionet në format sintaksore, si dhe interpretimet e tyre të sakta semantike (si sintaksa FASM, sintaksa TASM, mënyra ideale, etj., në rastin e veçantë të programimit të asamblesë x86 ).

#### Numri i kalimeve 
Ekzistojnë dy lloje asemblerësh bazuar në numrin e kalimeve nëpër burim ( sa herë asembleri e lexon burimin ) për të prodhuar skedarin e objektit.

* **Asamblerët me një kalim të vetëm** e përpunojnë kodin burimor një herë. Për simbolet e përdorura para se të përcaktohen, asambleri do të lëshojë "gabime" pas përkufizimit përfundimtar, duke i thënë lidhësit ose ngarkuesit të shënojë vendet ku janë përdorur simbolet ende të pacaktuara.
* **Asamblerët me shumë kalime** krijojnë një tabelë me të gjitha simbolet dhe vlerat e tyre në kalimet e para, pastaj e përdorin tabelën në kalimet e mëvonshme për të gjeneruar kod.

Në të dyja rastet, asembleri duhet të jetë në gjendje të përcaktojë madhësinë e secilit udhëzim në kalimet fillestare në mënyrë që të llogarisë adresat e simboleve pasuese. Kjo do të thotë që nëse madhësia e një operacioni që i referohet një operandi të përcaktuar më vonë varet nga lloji ose distanca e operandit, asembleri do të bëjë një vlerësim pesimist kur të hasë për herë të parë operacionin dhe, nëse është e nevojshme, do ta mbushë atë me një ose më shumë udhëzime " pa operacion " në një kalim të mëvonshëm ose me gabime. Në një asembler me optimizim të vrimave të shikimit, adresat mund të rillogariten midis kalimeve për të lejuar zëvendësimin e kodit pesimist me kod të përshtatur për distancën e saktë nga objektivi.

Arsyeja origjinale për përdorimin e asamblerëve me një kalim ishte madhësia e memories dhe shpejtësia e asamblesë - shpesh një kalim i dytë do të kërkonte ruajtjen e tabelës së simboleve në memorie ( për të trajtuar referencat përpara ), rikthimin dhe rileximin e burimit të programit në shirit, ose rileximin e një pakete letrash ose shiriti letre të shpuar. Kompjuterët e mëvonshëm me memorie shumë më të mëdha ( sidomos ruajtja e diskut ), kishin hapësirën për të kryer të gjithë përpunimin e nevojshëm pa një rilexim të tillë. Avantazhi i asamblerit me shumë kalime është se mungesa e gabimeve e bën procesin e lidhjes ( ose ngarkimin e programit nëse asambleri prodhon drejtpërdrejt kodin e ekzekutueshëm ) më të shpejtë. 

**Shembull:** në fragmentin e mëposhtëm të kodit, një asambler me një kalim do të ishte në gjendje të përcaktonte adresën e referencës së prapme BKWD kur asamble deklaratën S2, por nuk do të ishte në gjendje të përcaktonte adresën e referencës së përparme FWD kur asamble deklaratën e degës S1; në të vërtetë, FWD mund të jetë i padefinuar. Një asambler me dy kalime do të përcaktonte të dy adresat në kalimin 1, kështu që ato do të njiheshin kur gjeneronte kod në kalimin 2.
 S1   B    FWD
   ...
 FWD   EQU *
   ...
 BKWD  EQU *
   ...
 S2    B   BKWD

#### Montues të nivelit të lartë 
Asamblerët më të sofistikuar të nivelit të lartë ofrojnë abstraksione gjuhësore të tilla si:

* Deklaratat dhe thirrjet e procedurave/funksioneve të nivelit të lartë
* Struktura të avancuara kontrolli ( NËSE/ATËHERË/PËRNDRYSHE, NDËRRO. )
* Llojet e të dhënave abstrakte të nivelit të lartë, duke përfshirë strukturat/regjistrimet, bashkimet, klasat dhe bashkësitë.
* Përpunim i sofistikuar makro ( megjithëse i disponueshëm në montuesit e zakonshëm që nga fundi i viteve 1950 për, p.sh., serinë IBM 700 dhe serinë IBM 7000, dhe që nga vitet 1960 për IBM System/360 ( S/360 ), ndër makina të tjera. )
* Karakteristikat e programimit të orientuar nga objektet, të tilla si klasat, objektet, abstraksioni, polimorfizmi dhe trashëgimia. 

Shihni Dizajnin e Gjuhës më poshtë për më shumë detaje.

### Gjuha e assemblerit 
Një program i shkruar në gjuhën assembly përbëhet nga një seri udhëzimesh mnemonike të procesorit dhe meta-deklaratash ( të njohura ndryshe si operacione deklarative, direktiva, pseudo-udhëzime, pseudo-operacione dhe pseudo-operacione ), komente dhe të dhëna. Udhëzimet në gjuhën assembly zakonisht përbëhen nga një mnemonik i kodit op të ndjekur nga një operand, i cili mund të jetë një listë e të dhënave, argumenteve ose parametrave. Disa udhëzime mund të jenë "të nënkuptuara", që do të thotë se të dhënat mbi të cilat vepron udhëzimi përcaktohen në mënyrë implicite nga vetë udhëzimi - një udhëzim i tillë nuk merr një operand. Deklarata që rezulton përkthehet nga një assembler në udhëzime në gjuhën e makinës që mund të ngarkohen në memorie dhe të ekzekutohen.

Për shembull, udhëzimi më poshtë i tregon një procesori x86 / IA-32 që të zhvendosë menjëherë një vlerë 8-bitëshe në një regjistër. Kodi binar për këtë udhëzim është 10110 i ndjekur nga një identifikues 3-bitësh për të cilin regjistër duhet të përdoret. Identifikuesi për regjistrin *AL* është 000, kështu që kodi i mëposhtëm i makinës ngarkon regjistrin *AL* me të dhënat 01100001. 
 10110000 01100001
Ky kod binar kompjuterik mund të bëhet më i lexueshëm nga njeriu duke e shprehur atë në heksadecimal si më poshtë.
 B0 61
Këtu, `B0` do të thotë "Zhvendos një kopje të vlerës së mëposhtme në *AL* ", dhe `61` është një përfaqësim heksadecimal i vlerës 01100001, e cila është 97 në sistemin dhjetor. Gjuha e asamblesë për familjen 8086 ofron mnemonikën MOV ( një shkurtim i *move* ) për udhëzime të tilla si kjo, kështu që kodi i makinës më sipër mund të shkruhet si më poshtë në gjuhën e asamblesë, i plotësuar me një koment shpjegues nëse kërkohet, pas pikëpresjes. Kjo është shumë më e lehtë për t'u lexuar dhe për t'u mbajtur mend.
```nasm
MOV AL, 61h    ; Load AL with 97 decimal (61 hex)
```
Në disa gjuhë asambleri ( përfshirë këtë ), e njëjta mnemonikë, siç është MOV, mund të përdoret për një familje udhëzimesh të lidhura për ngarkimin, kopjimin dhe zhvendosjen e të dhënave, qofshin këto vlera të menjëhershme, vlera në regjistra ose vendndodhje memorieje të treguara nga vlerat në regjistra ose nga adresa të menjëhershme ( të njohura edhe si adresa të drejtpërdrejta ). Asamblerë të tjerë mund të përdorin mnemonikë të veçantë të opkodit, siç është L për "zhvendos memorien në regjistër", ST për "zhvendos regjistrin në memorie", LR për "zhvendos regjistrin në regjistër", MVI për "zhvendos operandin e menjëhershëm në memorie", etj.

Nëse e njëjta mnemonikë përdoret për udhëzime të ndryshme, kjo do të thotë që mnemonika korrespondon me disa kode të ndryshme binare udhëzimesh, duke përjashtuar të dhënat ( p.sh. `61h` në këtë shembull ), varësisht nga operandët që ndjekin mnemonikën. Për shembull, për CPU-të x86/IA-32, sintaksa e gjuhës së asamblesë Intel `MOV AL, AH` përfaqëson një udhëzim që zhvendos përmbajtjen e regjistrit *AH* në regjistrin *AL*. Forma heksadecimale  e këtij udhëzimi është:
 88 E0
Bajti i parë, 88h, identifikon një lëvizje midis një regjistri me madhësinë e një bajti dhe një regjistri ose memorieje tjetër, dhe bajti i dytë, E0h, është i koduar ( me tre fusha biti ) për të specifikuar që të dy operandët janë regjistra, burimi është *AH* dhe destinacioni është *AL*.

Në një rast si ky, ku e njëjta mnemonikë mund të përfaqësojë më shumë se një udhëzim binar, asembleri përcakton se cilin udhëzim të gjenerojë duke shqyrtuar operandët. Në shembullin e parë, operandi `61h` është një konstante numerike heksadecimale e vlefshme dhe nuk është një emër i vlefshëm regjistri, kështu që vetëm udhëzimi `B0` mund të jetë i zbatueshëm. Në shembullin e dytë, operandi `AH` është një emër i vlefshëm regjistri dhe jo një konstante numerike e vlefshme (heksadecimal, dhjetor, oktal ose binare), kështu që vetëm udhëzimi `88` mund të jetë i zbatueshëm.

Gjuhët e assemblerit janë gjithmonë të dizajnuara në mënyrë që ky lloj mungese paqartësie të zbatohet universalisht nga sintaksa e tyre. Për shembull, në gjuhën e asamblesë Intel x86, një konstante heksadecimale duhet të fillojë me një shifër numerike, në mënyrë që numri heksadecimal 'A' ( i barabartë me dhjetë dhjetore) të shkruhet si `0Ah` ose `0AH`, jo `AH`, konkretisht në mënyrë që të mos duket se është emri i regjistrit *AH*. ( I njëjti rregull parandalon gjithashtu paqartësinë me emrat e regjistrave *BH*, *CH* dhe *DH*, si dhe me çdo simbol të përcaktuar nga përdoruesi që mbaron me shkronjën *H* dhe përndryshe përmban vetëm karaktere që janë shifra heksadecimale, siç është fjala "BEACH". )

Duke u kthyer te shembulli origjinal, ndërsa opcode x86 10110000 ( `B0` ) kopjon një vlerë 8-bitëshe në regjistrin *AL*, 10110001 ( `B1` ) e zhvendos atë në *CL* dhe 10110010 ( `B2` ) e bën këtë në *DL*. Shembuj të gjuhës assembly për këto vijojnë. 
```nasm
MOV AL, 1h    ; Load AL with immediate value 1
MOV CL, 2h    ; Load CL with immediate value 2
MOV DL, 3h    ; Load DL with immediate value 3
```
Sintaksa e MOV mund të jetë gjithashtu më komplekse siç tregojnë shembujt e mëposhtëm. 
```nasm
MOV EAX, [EBX]	 ; Move the 4 bytes in memory at the address contained in EBX into EAX
MOV [ESI+EAX], CL ; Move the contents of CL into the byte at address ESI+EAX
MOV DS, DX    ; Move the contents of DX into segment register DS
```
Në secilin rast, mnemonika MOV përkthehet direkt në një nga opkodet 88-8C, 8E, A0-A3, B0-BF, C6 ose C7 nga një asambler, dhe programuesi normalisht nuk ka nevojë ta dijë ose ta mbajë mend se cilin. 

Transformimi i gjuhës së asamblerit në kod makine është puna e një asambleri, dhe e kundërta mund të arrihet të paktën pjesërisht nga një çmontues. Ndryshe nga gjuhët e nivelit të lartë, ekziston një korrespondencë një-me-një midis shumë deklaratave të thjeshta të asamblerit dhe udhëzimeve të gjuhës së makinës. Megjithatë, në disa raste, një asambler mund të ofrojë *pseudo-udhëzime* ( në thelb makro ) të cilat zgjerohen në disa udhëzime të gjuhës së makinës për të ofruar funksionalitete të nevojshme zakonisht. Për shembull, për një makinë që i mungon një udhëzim "degëzim nëse është më i madh ose i barabartë", një asambler mund të ofrojë një pseudo-udhëzim që zgjerohet në "vendoset nëse është më i vogël se" dhe "degëzim nëse është zero ( në rezultatin e udhëzimit të vendosur )" të makinës. Shumica e asamblerëve me funksione të plota ofrojnë gjithashtu një gjuhë të pasur makro ( të diskutuar më poshtë ) e cila përdoret nga shitësit dhe programuesit për të gjeneruar kod dhe sekuenca të dhënash më komplekse. Meqenëse informacioni në lidhje me pseudoinstruksionet dhe makrot e përcaktuara në mjedisin e asamblerit nuk është i pranishëm në programin e objektit, një çmontues nuk mund të rindërtojë thirrjet e makros dhe pseudoinstruksionit, por mund të çmontojë vetëm udhëzimet aktuale të makinës që asambleri gjeneroi nga ato entitete abstrakte të gjuhës së asamblerit. Po kështu, meqenëse komentet në skedarin burimor të gjuhës së asamblerit injorohen nga asambleri dhe nuk kanë efekt në kodin objektor që gjeneron, një çmontues është gjithmonë plotësisht i paaftë të rikuperojë komentet burimore.

Çdo arkitekturë kompjuteri ka gjuhën e vet të makinës. Kompjuterët ndryshojnë në numrin dhe llojin e operacioneve që mbështesin, në madhësitë dhe numrat e ndryshëm të regjistrave, si dhe në përfaqësimet e të dhënave në memorie. Ndërsa shumica e kompjuterëve me qëllim të përgjithshëm janë në gjendje të kryejnë në thelb të njëjtën funksionalitet, mënyrat se si e bëjnë këtë ndryshojnë; gjuhët përkatëse të asamblesë pasqyrojnë këto ndryshime.

Për një grup të vetëm udhëzimesh mund të ekzistojnë grupe të shumëfishta mnemonikësh ose sintakse në gjuhën assembly, të cilat zakonisht instancohen në programe të ndryshme assembler. Në këto raste, më i popullarizuari është zakonisht ai që ofrohet nga prodhuesi i CPU-së dhe përdoret në dokumentacionin e tij.

Dy shembuj të CPU-ve që kanë dy grupe të ndryshme mnemonikësh janë familja Intel 8080 dhe Intel 8086/8088. Meqenëse Intel pretendoi të drejtat e autorit mbi mnemonikën e gjuhës së saj të asamblesë ( të paktën në secilën faqe të dokumentacionit të tyre të botuar në vitet 1970 dhe në fillim të viteve 1980 ), disa kompani që prodhuan në mënyrë të pavarur CPU të pajtueshme me grupet e udhëzimeve të Intel shpikën mnemonikën e tyre. CPU Zilog Z80, një përmirësim i Intel 8080A, mbështet të gjitha udhëzimet 8080A plus shumë të tjera; Zilog shpiku një gjuhë krejtësisht të re asambleje, jo vetëm për udhëzimet e reja, por edhe për të gjitha udhëzimet 8080A. Për shembull, aty ku Intel përdor mnemonikët *MOV*, *MVI*, *LDA*, *STA*, *LXI*, *LDAX*, *STAX*, *LHLD* dhe *SHLD* për udhëzime të ndryshme të transferimit të të dhënave, gjuha e asamblesë Z80 përdor mnemonikën *LD* për të gjitha ato. Një rast i ngjashëm janë CPU-të NEC V20 dhe V30, kopje të përmirësuara të Intel 8086 dhe 8088, përkatësisht. Ashtu si Zilog me Z80, NEC shpiku mnemonikë të rinj për të gjitha udhëzimet 8086 dhe 8088, për të shmangur akuzat për shkelje të të drejtave të autorit të Intel. ( Është e dyshimtë nëse të drejta të tilla të autorit mund të jenë të vlefshme, dhe më vonë kompanitë e CPU-ve si AMD  dhe Cyrix ribotuan mnemonikën e udhëzimeve x86/IA-32 të Intel pikërisht pa leje dhe as pa dënim ligjor. ) Është e dyshimtë nëse në praktikë shumë njerëz që programuan V20 dhe V30 shkruan në të vërtetë në gjuhën e asamblesë të NEC dhe jo në atë të Intel; meqenëse çdo dy gjuhë asambleje për të njëjtën arkitekturë të grupit të udhëzimeve janë izomorfike (disi si anglishtja dhe latinishtja Pig ), nuk ka kërkesë për të përdorur gjuhën e asamblesë të publikuar nga prodhuesi me produktet e atij prodhuesi.

### "Përshëndetje, botë!" në x86 Linux 
Në gjuhën e asamblesë 32-bit për Linux në një procesor x86, "Përshëndetje, botë!" mund të printohet kështu.
```nasm
section	.text    ; start of the code segment
  global _start  ; declare _start to be visible in the generated object file
	
_start:	    
  mov	edx,len   ; length of string, third argument to write()
  mov	ecx,msg   ; address of string, second argument to write()
  mov	ebx,1    ; file descriptor (standard output), first argument to write()
  mov	eax,4    ; system call number for write()
  int	0x80    ; system call trap
	
  mov	ebx,0    ; exit code, first argument to exit()
  mov	eax,1    ; system call number for exit()
  int	0x80    ; system call trap

section	.data    ; start of data segment
msg db 'Hello, world!', 0xa ; 14 bytes of data
len equ $ - msg   ; the value 14 as a constant calculated at compile time
```

## Dizajni i gjuhës 
### Elementet bazë 
Ekziston një shkallë e madhe diversiteti në mënyrën se si autorët e asamblerëve i kategorizojnë deklaratat dhe në nomenklaturën që përdorin. Në veçanti, disa përshkruajnë çdo gjë tjetër përveç një mnemonike makine ose mnemonike të zgjeruar si një pseudo-operacion ( pseudo-operacion ). Një gjuhë tipike asambleje përbëhet nga 3 lloje deklaratash udhëzimi që përdoren për të përcaktuar operacionet e programit:

* Mnemonikë të kodit të opsionit
* Përkufizimet e të dhënave
* Direktivat e Asamblesë

#### Mnemonikë Opcode dhe mnemonikë e zgjeruar 
Udhëzimet ( deklaratat ) në gjuhën e asamblerit janë përgjithësisht shumë të thjeshta, ndryshe nga ato në gjuhët e nivelit të lartë. Në përgjithësi, një mnemonik është një emër simbolik për një udhëzim të vetëm të ekzekutueshëm në gjuhën e makinës ( një opcode ), dhe ekziston të paktën një mnemonik opcode i përcaktuar për secilin udhëzim në gjuhën e makinës. Çdo udhëzim zakonisht përbëhet nga një *operacion* ose *opcode* plus zero ose më shumë *operandë*. Shumica e udhëzimeve i referohen një vlere të vetme ose një çifti vlerash. Operandet mund të jenë të menjëhershme ( vlera e koduar në vetë udhëzimin ), regjistra të specifikuar në udhëzim ose të nënkuptuar, ose adresat e të dhënave të vendosura diku tjetër në ruajtje. Kjo përcaktohet nga arkitektura themelore e procesorit: asambleri thjesht pasqyron se si funksionon kjo arkitekturë. *Mnemonikët e zgjeruara* përdoren shpesh për të specifikuar një kombinim të një opcode me një operand specifik, p.sh., asamblerët System/360 përdorin  si një mnemonik të zgjeruar për  me një maskë prej 15 dhe  ( "NO OPeration" - mos bëj asgjë për një hap ) për  me një maskë prej 0.

*Mnemonikët e zgjeruara* përdoren shpesh për të mbështetur përdorime të specializuara të instruksioneve, shpesh për qëllime që nuk janë të qarta nga emri i instruksionit. Për shembull, shumë CPU nuk kanë një instruksion të qartë NOP, por kanë instruksione që mund të përdoren për këtë qëllim. Në CPU-të 8086, instruksioni  përdoret për , ku  është një pseudo-opcode për të koduar instruksionin  . Disa çmontues e njohin këtë dhe do ta deshifrojnë  si . Në mënyrë të ngjashme, asamblerët e IBM për System/360 dhe System/370 përdorin mnemonikën e zgjeruar  dhe  për  dhe  me maska zero. Për arkitekturën SPARC, këto njihen si *instruksione sintetike*. 

Disa asemblerë mbështesin gjithashtu makro-instruksione të thjeshta të integruara që gjenerojnë dy ose më shumë udhëzime makine. Për shembull, me disa asemblerë Z80, instruksioni  njihet për të gjeneruar  të ndjekur nga .  Këto nganjëherë njihen si *pseudo-opkode* .

Mnemonikët janë simbole arbitrare; në vitin 1985, IEEE publikoi Standardin 694 për një grup uniform mnemonikësh që do të përdoren nga të gjithë asamblerët.  Standardi është tërhequr që atëherë.

#### Direktivat e të dhënave 
Ekzistojnë udhëzime të përdorura për të përcaktuar elementët e të dhënave për të mbajtur të dhëna dhe variabla. Ato përcaktojnë llojin e të dhënave, gjatësinë dhe rreshtimin e të dhënave. Këto udhëzime gjithashtu mund të përcaktojnë nëse të dhënat janë të disponueshme për programe të jashtme ( të mbledhura veçmas ) apo vetëm për programin në të cilin është përcaktuar seksioni i të dhënave. Disa asemblerë i klasifikojnë këto si pseudo-operacione.

#### Direktivat e Assemblerit 
Direktivat e asamblerit, të quajtura edhe pseudo-opcode, pseudo-operacione ose pseudo-ops, janë komanda të dhëna një asambleri "që e drejtojnë atë të kryejë operacione të tjera përveç udhëzimeve të asamblerit". Direktivat ndikojnë në mënyrën se si funksionon asambleri dhe "mund të ndikojnë në kodin e objektit, tabelën e simboleve, skedarin e listës dhe vlerat e parametrave të brendshëm të asamblerit". Ndonjëherë termi *pseudo-opcode* është i rezervuar për direktivat që gjenerojnë kod objekti, të tilla si ato që gjenerojnë të dhëna. 

Emrat e pseudo-operacioneve shpesh fillojnë me një pikë për t'i dalluar ato nga udhëzimet e makinës. Pseudo-operacionet mund ta bëjnë montimin e programit të varur nga parametrat e futur nga një programues, në mënyrë që një program të mund të montohet në mënyra të ndryshme, ndoshta për aplikacione të ndryshme. Ose, një pseudo-operacion mund të përdoret për të manipuluar prezantimin e një programi për ta bërë më të lehtë leximin dhe mirëmbajtjen. Një përdorim tjetër i zakonshëm i pseudo-operacioneve është rezervimi i zonave të ruajtjes për të dhënat e kohës së ekzekutimit dhe opsionalisht inicializimi i përmbajtjes së tyre në vlera të njohura.

Asamblerët simbolikë i lejojnë programuesit të shoqërojnë emra arbitrarë ( *etiketa* ose *simbole* ) me vendndodhje të memories dhe konstante të ndryshme. Zakonisht, çdo konstante dhe variabël i jepet një emër në mënyrë që udhëzimet të mund t'i referohen këtyre vendndodhjeve me emër, duke promovuar kështu kodin vetë-dokumentues. Në kodin ekzekutues, emri i secilës nënprogram shoqërohet me pikën e saj të hyrjes, kështu që çdo thirrje në një nënprogram mund të përdorë emrin e saj. Brenda nënprogrameve, destinacioneve GOTO u jepen etiketa. Disa asamblerë mbështesin *simbole lokale* të cilat shpesh janë leksikisht të dallueshme nga simbolet normale ( p.sh., përdorimi i "10$" si një destinacion GOTO ).

Disa asemblerë, siç është NASM, ofrojnë menaxhim fleksibël të simboleve, duke i lejuar programuesit të menaxhojnë hapësira të ndryshme emrash, të llogarisin automatikisht zhvendosjet brenda strukturave të të dhënave dhe të caktojnë etiketa që i referohen vlerave literale ose rezultatit të llogaritjeve të thjeshta të kryera nga asembleri. Etiketat mund të përdoren gjithashtu për të inicializuar konstantet dhe variablat me adresa të zhvendosshme.

Gjuhët asamblere, si shumica e gjuhëve të tjera të kompjuterit, lejojnë që në kodin burimor të programit të shtohen komente që do të injorohen gjatë asamblesë. Komentimi i mençur është thelbësor në programet në gjuhën asamblere, pasi kuptimi dhe qëllimi i një sekuence udhëzimesh binare të makinës mund të jetë i vështirë për t'u përcaktuar. Gjuha asamblere "e papërpunuar" ( e pakomente ) e gjeneruar nga kompiluesit ose çmontuesit është mjaft e vështirë për t'u lexuar kur duhet të bëhen ndryshime.

### Makrot 
Shumë asemblerë mbështesin *makro të paracaktuara*, dhe të tjerë mbështesin makro *të përcaktuara nga programuesi* ( dhe të ripërcaktueshme në mënyrë të përsëritur ) që përfshijnë sekuenca rreshtash teksti në të cilat janë të ngulitura variabla dhe konstante. Përkufizimi i makrosë është më së shpeshti  një përzierje e deklaratave të asemblerit, p.sh., direktiva, udhëzime simbolike të makinës dhe shabllone për deklaratat e asemblerit. Kjo sekuencë rreshtash teksti mund të përfshijë opkode ose direktiva. Pasi të jetë përcaktuar një makro, emri i saj mund të përdoret në vend të një mnemonike. Kur asembleri përpunon një deklaratë të tillë, ai e zëvendëson deklaratën me rreshtat e tekstit të shoqëruara me atë makro, pastaj i përpunon ato sikur të ekzistonin në skedarin e kodit burimor ( duke përfshirë, në disa asemblerë, zgjerimin e çdo makroje ekzistuese në tekstin zëvendësues ). Makrot në këtë kuptim datojnë që nga autokoduesit e IBM të viteve 1950. 

**Makro-assemblerët** zakonisht kanë direktiva për të, p.sh., përcaktuar makrot, përcaktuar variablat, vendosur variablat në rezultatin e një shprehjeje aritmetike, logjike ose vargu, përsëritur, gjeneruar kod me kusht. Disa nga këto direktiva mund të kufizohen për përdorim brenda një përkufizimi makro, p.sh., **MEXIT** në HLASM, ndërsa të tjerat mund të lejohen brenda kodit të hapur ( jashtë përkufizimeve të makrove ), p.sh., **AIF** dhe **COPY** në HLASM.

Në gjuhën e asamblerit, termi "makro" përfaqëson një koncept më gjithëpërfshirës sesa në disa kontekste të tjera, siç është para-procesori në gjuhën e programimit C, ku direktiva e tij #define përdoret zakonisht për të krijuar makro të shkurtra me një rresht. Udhëzimet makro të asamblerit, si makrot në PL/I dhe disa gjuhë të tjera, mund të jenë "programe" të gjata më vete, të ekzekutuara me interpretim nga asambleri gjatë asamblesë.

Meqenëse makrot mund të kenë emra 'të shkurtër', por të zgjerohen në disa ose në fakt shumë rreshta kodi, ato mund të përdoren për t'i bërë programet në gjuhën assembly të duken shumë më të shkurtra, duke kërkuar më pak rreshta kodi burimor, si me gjuhët e nivelit më të lartë. Ato gjithashtu mund të përdoren për të shtuar nivele më të larta strukture në programet assembly, duke futur opsionalisht kodin e integruar të debugging-ut nëpërmjet parametrave dhe veçorive të tjera të ngjashme.

Makro-assemblerët shpesh lejojnë që makrot të marrin parametra . Disa asemblerë përfshijnë gjuhë makro mjaft të sofistikuara, duke përfshirë elementë të gjuhës së nivelit të lartë si parametra opsionalë, variabla simbolikë, kushte, manipulim vargjesh dhe operacione aritmetike, të gjitha të përdorshme gjatë ekzekutimit të një makroje të caktuar, dhe duke lejuar makrot të ruajnë kontekstin ose të shkëmbejnë informacion. Kështu, një makro mund të gjenerojë udhëzime të shumta në gjuhën e asamblesë ose përkufizime të të dhënave, bazuar në argumentet e makrove. Kjo mund të përdoret për të gjeneruar struktura të dhënash në stilin e regjistrimit ose sythe " të shpalosura ", për shembull, ose mund të gjenerojë algoritme të tëra bazuar në parametra kompleksë. Për shembull, një makro "sort" mund të pranojë specifikimin e një çelësi kompleks renditjeje dhe të gjenerojë kod të hartuar për atë çelës specifik, pa pasur nevojë për testet në kohë ekzekutimi që do të kërkoheshin për një procedurë të përgjithshme që interpreton specifikimin. Një organizatë që përdor gjuhën e asamblesë që është zgjeruar shumë duke përdorur një suitë të tillë makrosh mund të konsiderohet se po punon në një gjuhë të nivelit më të lartë, pasi programues të tillë nuk po punojnë me elementët konceptualë të nivelit më të ulët të një kompjuteri. Duke nënvizuar këtë pikë, makrot u përdorën për të zbatuar një makinë virtuale të hershme në SNOBOL4 (1967), e cila u shkrua në SNOBOL Implementation Language (SIL), një gjuhë asambleje për një makinë virtuale. Makina e synuar do ta përkthente këtë në kodin e saj vendas duke përdorur një makro asambler. Kjo lejoi një shkallë të lartë transportueshmërie për kohën.

Makrot u përdorën për të përshtatur sisteme softuerike në shkallë të gjerë për klientë specifikë gjatë epokës së mainframe‑ve. Ato u përdorën gjithashtu nga personeli i klientëve për të plotësuar nevojat e punëdhënësve të tyre, duke krijuar versione të veçanta të sistemeve operative të prodhuesve.

Kjo u realizua, për shembull, nga programuesit e sistemeve që punonin me **IBM Conversational Monitor System / Virtual Machine (VM/CMS)** dhe me shtesat e IBM për “përpunim transaksionesh në kohë reale”, si **Customer Information Control System (CICS)** dhe **ACP/TPF**, sistemi i linjave ajrore/financiar që filloi në vitet 1970 dhe që ende përdoret për shumë sisteme të mëdha rezervimi kompjuterik (CRS) dhe sisteme kartash krediti sot.

Është gjithashtu e mundur të përdoren vetëm aftësitë e përpunimit të makrove të një assembleri për të gjeneruar kod të shkruar në gjuhë krejtësisht të ndryshme. Për shembull, mund të gjenerohet një version i një programi në **COBOL** duke përdorur një program të pastër makro‑assembler, i cili përmban rreshta kodi COBOL brenda operatorëve të kohës së montimit që udhëzojnë assemblerin të gjenerojë kod arbitrar.

**IBM OS/360** përdor makro për të kryer gjenerimin e sistemit. Përdoruesi specifikon opsionet duke koduar një seri makrosh assembleri. Montimi i këtyre makrove gjeneron një **rrjedhë pune (job stream)** për ndërtimin e sistemit, duke përfshirë gjuhën e kontrollit të punës (**Job Control Language – JCL**) dhe deklaratat e kontrollit të utiliteteve.

Kjo ndodh sepse, siç u kuptua në vitet 1960, koncepti i **“përpunimit me makro”** është i pavarur nga koncepti i **“asamblimit”**; i pari, në terma modernë, i ngjan më shumë përpunimit të tekstit sesa gjenerimit të kodit objekt.

Koncepti i përpunimit me makro u shfaq, dhe vazhdon të shfaqet, edhe në gjuhën programuese **C**, e cila mbështet **udhëzime para‑procesori** për të caktuar variabla dhe për të kryer teste kushtesh mbi vlerat e tyre. Ndryshe nga disa përpunues makro të mëparshëm brenda assemblerëve, **para‑procesori i C** nuk është **Turing‑i plotë**, pasi i mungon aftësia për të kryer **loop** ose për të përdorur **“go to”**, elementë që do të lejonin programet të përsëriteshin.

Pavarësisht fuqisë së **përpunimit me makro**, ai ra në mospërdorim në shumë gjuhë të nivelit të lartë (përjashtime kryesore janë **C**, **C++** dhe **PL/I**), ndërkohë që mbeti një praktikë e përhershme në assemblerë.

Zëvendësimi i parametrave në makro bëhet rreptësisht sipas emrit: në kohën e përpunimit të makros, vlera e një parametri zëvendësohet tekstualisht në vend të emrit të tij. Klasa më e njohur e gabimeve që rezultuan nga kjo ishte përdorimi i një parametri që vetë ishte një shprehje dhe jo një emër i thjeshtë, në rastet kur autori i makros priste një emër. Në makron:

foo: makro a     

ngarkoni a*b

Qëllimi ishte që thirrësi të jepte emrin e një variabli, dhe variabli ose konstanta “global” **b** të përdorej për të shumëzuar **a**. Nëse funksioni **foo** thirret me parametrin **a‑c**, zgjerimi i makros prodhon udhëzimin `load a-c*b`.

Për të shmangur çdo paqartësi të mundshme, përdoruesit e përpunuesve të makrove mund të vendosin parametra formalë në kllapa brenda përkufizimeve të makros, ose thirrësit mund të vendosin në kllapa parametrat e dhënë si hyrje.

**Mbështetje për programimin e strukturuar   ** 

Paketa makrosh janë shkruar për të ofruar elemente të programimit të strukturuar që kodifikojnë rrjedhën e ekzekutimit. Shembulli më i hershëm i këtij qasjeje ishte **seti i makrove Concept‑14**, i propozuar fillimisht nga **Harlan Mills** (mars 1970) dhe i implementuar nga **Marvin Kessler** në Divizionin e Sistemeve Federale të IBM. Ky set ofronte blloqe kontrolli si **IF/ELSE/ENDIF** dhe struktura të ngjashme për programet assembler të **OS/360**.

Ky ishte një mënyrë për të reduktuar ose eliminuar përdorimin e operacioneve **GOTO** në kodin e asamblimit, një nga faktorët kryesorë që shkaktonin **spaghetti code** në gjuhën e asamblimit. Kjo qasje u pranua gjerësisht në fillim të viteve 1980, në periudhën e fundit të përdorimit në shkallë të gjerë të gjuhës së asamblimit. **IBM High Level Assembler Toolkit** përfshin një paketë të tillë makrosh.

Një tjetër dizajn ishte **A‑Natural**, një assembler “stream‑oriented” për procesorët **8080/Z80**, i zhvilluar nga **Whitesmiths Ltd.** (krijuesit e sistemit operativ **Idris**, i ngjashëm me Unix, dhe asaj që raportohet të ketë qenë kompajleri i parë komercial i gjuhës C).

Gjuha u klasifikua si assembler sepse punonte me elementë të pastër të makinës, si **opcode**, regjistra dhe referenca kujtese; por ajo inkorporonte një sintaksë shprehjesh për të treguar rendin e ekzekutimit. Kllapat dhe simbole të tjera speciale, së bashku me konstruktet e programimit të strukturuar të orientuara në blloqe, kontrollonin sekuencën e udhëzimeve të gjeneruara.

**A‑Natural** u ndërtua si gjuhë objekt e një kompajleri C, dhe jo për kodim manual, por sintaksa e tij logjike fitoi disa mbështetës.

Ka pasur pak kërkesë të dukshme për assemblerë më të sofistikuar që nga rënia e zhvillimit në shkallë të gjerë të gjuhës së asamblimit. Megjithatë, ata vazhdojnë të zhvillohen dhe të përdoren në raste kur kufizimet e burimeve ose veçoritë e veçanta të arkitekturës së sistemit të synuar pengojnë përdorimin efektiv të gjuhëve të nivelit më të lartë.

Assemblerët me motor të fuqishëm makrosh lejojnë programimin e strukturuar përmes makrove, si p.sh. . makroja **switch** e ofruar me paketën **Masm32** (ky kod përbën një program të plotë).

## Shembull kodi 
```asm
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                 ; Masm32 switch allows "variable cases"
        print "case 7"
    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
        .Repeat
            print "*"
            dec ebx
        .Until Sign?
    endsw
    print chr$(13, 10)
  ENDM
  exit
end demomain
```

## **Përdorimi i gjuhës së assemblerit** 
Kur u prezantua kompjuteri me program të ruajtur, programet shkruheshin në **kod makine** dhe ngarkoheshin në kompjuter nga shirita letre të shpuar ose futeshin drejtpërdrejt në kujtesë përmes çelësave të konsolës. [citation needed]

**Kathleen Booth** “i atribuohet shpikja e gjuhës së asamblimit” bazuar në punën teorike që ajo filloi në vitin 1947, ndërsa punonte në **ARC2** në **Birkbeck, University of London**, pas konsultimeve të **Andrew Booth** (më vonë bashkëshorti i saj) me matematicienin **John von Neumann** dhe fizikantin **Herman Goldstine** në **Institute for Advanced Study**.  

Në fund të vitit 1948, kompjuteri **Electronic Delay Storage Automatic Calculator (EDSAC)** kishte një assembler (i quajtur *“initial orders”*) të integruar në programin e nisjes (bootstrap). Ai përdorte mnemonikë me një shkronjë të vetme, të zhvilluara nga **David Wheeler**, i cili njihet nga **IEEE Computer Society** si krijuesi i parë i një “assembleri”.

Raportet mbi **EDSAC** prezantuan termin **“assembly”** për procesin e kombinimit të fushave në një fjalë udhëzimi.

**SOAP (Symbolic Optimal Assembly Program)** ishte një gjuhë asamblimi për kompjuterin **IBM 650**, e shkruar nga **Stan Poley** në vitin 1955.

Gjuhët e asamblimit eliminuan pjesën më të madhe të programimit të gjeneratës së parë, i cili ishte i prirur ndaj gabimeve, i lodhshëm dhe që kërkonte shumë kohë në kompjuterët më të hershëm. Ato i çliruan programuesit nga detyra të mërzitshme si kujtimi i kodeve numerike dhe llogaritja e adresave. Dikur ato përdoroheshin gjerësisht për çdo lloj programimi.

Në fund të viteve 1950, përdorimi i tyre u zëvendësua kryesisht nga gjuhët e nivelit më të lartë, në kërkim të produktivitetit më të madh në programim.

Sot, gjuha e asamblimit vazhdon të përdoret për manipulim të drejtpërdrejtë të harduerit, për qasje në udhëzime të specializuara të procesorit, ose për të adresuar çështje kritike të performancës. Përdorimet tipike përfshijnë **driverët e pajisjeve**, **sistemet e integruara të nivelit të ulët** dhe **sistemet në kohë reale**.

Shumë programe u shkruan plotësisht në gjuhën e asamblimit. **Burroughs MCP (1961)** ishte kompjuteri i parë për të cilin sistemi operativ nuk u zhvillua tërësisht në gjuhën e asamblimit; ai u shkrua në **Executive Systems Problem Oriented Language (ESPOL)**, një dialekt i **Algol**.

Shumë aplikacione komerciale u shkruan gjithashtu në gjuhën e asamblimit, përfshirë një pjesë të madhe të softuerit për **IBM mainframe** të zhvilluar nga korporata të mëdha. **COBOL**, **FORTRAN** dhe disa **PL/I** eventualisht e zëvendësuan gjuhën e asamblimit, megjithatë një numër organizatash të mëdha e ruajtën infrastrukturën e aplikacioneve të shkruara në gjuhën e asamblimit deri në vitet 1990.

Gjuha e assemblerit ishte gjuha kryesore e zhvillimit për kompjuterët personalë 8‑bit, si **Apple II**, **Atari 8‑bit**, **ZX Spectrum** dhe **Commodore 64**. **BASIC** i interpretuar në këto sisteme nuk ofronte shpejtësinë maksimale të ekzekutimit dhe as përdorimin e plotë të kapaciteteve për të shfrytëzuar harduerin e disponueshëm.

Gjuha e assemblerit ishte zgjedhja e paracaktuar për programimin e **konzolave 8‑bit**, si **Atari 2600** dhe **Nintendo Entertainment System (NES)**.

Softueri kryesor për kompjuterët **IBM PC kompatibilë**, si **MS‑DOS**, **Turbo Pascal** dhe tabela elektronike **Lotus 1‑2‑3**, u shkrua në gjuhën e asamblimit. Me rritjen eksponenciale të shpejtësisë së kompjuterëve, gjuha e asamblimit u bë një mjet për përshpejtimin e pjesëve të caktuara të programeve, si p.sh. . **renderimi i lojës Doom**, në vend që të mbetej gjuha dominuese e zhvillimit.

Në vitet 1990, gjuha e assemblerit u përdor për të maksimizuar performancën në sisteme si **Sega Saturn**, dhe si gjuhë kryesore për harduerin e arcade‑ve që përdorte CPU/GPU të integruar **TMS34010**, si në lojërat **Mortal Kombat** dhe **NBA Jam**.

**Përdorimi aktual**

Ka pasur debat mbi dobishmërinë dhe performancën e gjuhës së asamblimit në krahasim me gjuhët e nivelit të lartë.

Megjithëse gjuha e asamblimit ka përdorime të veçanta në fusha të caktuara ku është e rëndësishme (shih më poshtë), ekzistojnë mjete të tjera për optimizim.

Që nga korriku 2017, indeksi **TIOBE** i popullaritetit të gjuhëve programuese e renditi gjuhën e asamblimit në vendin e 11‑të, përpara **Visual Basic**, për shembull.

Assembleri mund të përdoret për optimizim të shpejtësisë ose për optimizim të madhësisë. Në rastin e optimizimit për shpejtësi, pretendohet se kompajlerët modernë optimizues arrijnë të gjenerojnë kod nga gjuhët e nivelit të lartë që mund të ekzekutohet po aq shpejt sa kodi i shkruar me dorë në assembler, megjithëse ekzistojnë disa kundër‑shembuj.

Kompleksiteti i procesorëve modernë dhe i nën‑sistemeve të kujtesës e bën optimizimin efektiv gjithnjë e më të vështirë si për kompajlerët, ashtu edhe për programuesit e assemblerit. Rritja e performancës së procesorëve ka bërë që shumica e CPU‑ve të qëndrojnë të papërdorura për pjesën më të madhe të kohës, me vonesa të shkaktuara nga ngushticat e parashikueshme si **cache misses**, operacionet **I/O** dhe **paging**, duke e bërë shpejtësinë e ekzekutimit të kodit një çështje jo‑kritike për shumë programues.

Ekzistojnë ende disa fusha të programimit kompjuterik ku përdorimi i gjuhës së asamblimit është më i zakonshëm:

Shkrimi i kodit për sisteme me procesorë të vjetër që kanë mundësi të kufizuara për gjuhë të nivelit të lartë, si **Atari 2600**, **Commodore 64** dhe kalkulatorët grafikë. Programet për këto kompjuterë të viteve 1970 dhe 1980 shpesh shkruheshin në kontekstin e **demoscene** ose nënkulturave të **retrogaming**.

Kodi që duhet të ndërveprojë drejtpërdrejt me harduerin, për shembull në **driverë pajisjesh** dhe **interrupt handlers**. Në një procesor të integruar ose **DSP**, ndërprerjet me përsëritje të lartë kërkojnë numrin më të shkurtër të cikleve për ndërprerje, si p.sh. . një ndërprerje që ndodh 1000 ose 10000 herë në sekondë.

Programet që duhet të përdorin udhëzime specifike të procesorit që nuk implementohen nga kompajleri. Një shembull i zakonshëm është udhëzimi i **rotacionit bitwise**, i përdorur në shumë algoritme enkriptimi, si dhe pyetja për paritetin e një byte ose mbartjen 4‑bit të një mbledhjeje.

Ekzekutuesit e pavarur që duhet të funksionojnë pa komponentë të kohës së ekzekutimit ose biblioteka të lidhura me gjuhët e nivelit të lartë, si **firmware** për telefona, sisteme karburanti dhe ndezjeje në automjete, sisteme kontrolli të kondicionimit të ajrit dhe sisteme sigurie.

Programet me **loop‑e të ndjeshme ndaj performancës**, ku gjuha e asamblimit ofron mundësi optimizimi që janë të vështira për t’u arritur në gjuhë të nivelit të lartë. Shembuj tipikë janë **algebra lineare me BLAS** ose transformimi kosinus diskret (p.sh. versioni **SIMD assembly** nga **x264**).

Programet që krijojnë funksione të vektorizuara për gjuhë të nivelit të lartë si **C**. Në gjuhën e nivelit të lartë kjo ndihmohet ndonjëherë nga funksionet intrinseke të kompajlerit që lidhen drejtpërdrejt me mnemonikët **SIMD**, por gjithsesi rezultojnë në një konvertim një‑më‑një në assembler specifik për procesorin e dhënë.

Programet në **kohë reale**, si simulimet, sistemet e navigimit të fluturimit dhe pajisjet mjekësore. Për shembull, në një sistem **fly‑by‑wire**, telemetria duhet të interpretohet dhe të veprohet mbi të brenda kufizimeve të rrepta kohore. Këto sisteme duhet të eliminojnë burimet e vonesave të paparashikueshme, që mund të krijohen nga gjuhët e interpretuara, mbledhja automatike e mbeturinave, operacionet e **paging** ose multitasking‑u parandalues. Zgjedhja e gjuhës së asamblimit ose gjuhëve të tjera të nivelit të ulët u jep programuesve më shumë kontroll mbi detajet e përpunimit.

Algoritmet kriptografike që duhet të ekzekutohen gjithmonë në të njëjtën kohë, për të parandaluar **sulmet e bazuara në kohë**.

**Video encoder‑ët dhe decoder‑ët** si **rav1e** (encoder për **AV1**) dhe **dav1d** (decoder referencë për **AV1**) përmbajnë kod assembler për të shfrytëzuar udhëzimet **AVX2** dhe **ARM Neon** kur janë të disponueshme.

Modifikimi dhe zgjerimi i kodit të trashëguar të shkruar për **IBM mainframe computers**.

Situata ku kërkohet kontroll i plotë mbi mjedisin, në raste me siguri shumë të lartë ku asgjë nuk mund të merret e mirëqenë.

**Viruset kompjuterike**, **bootloader‑ët**, disa **driverë pajisjesh** ose elementë të tjerë shumë pranë harduerit ose sistemit operativ të nivelit të ulët.

**Simulatorët e seteve të udhëzimeve** për monitorim, gjurmim dhe debugging, ku mbingarkesa shtesë mbahet në minimum.

Situata ku nuk ekziston gjuhë e nivelit të lartë, në një procesor të ri ose të specializuar për të cilin nuk ka kompajler të kryqëzuar.

**Reverse engineering** dhe modifikimi i skedarëve të programeve, si:

Binarë ekzistues që mund të jenë ose jo të shkruar fillimisht në gjuhë të nivelit të lartë, për shembull kur tentohet rikrijimi i     p     rogrameve për të cilat kodi burimor nuk është i disponueshëm ose është humbur, ose thyerja e mbrojtjes së kopjimit të softuerit pronësor.

* **Video lojëra (ROM hacking)**, e cila është e mundur përmes disa metodave. Metoda më e përdorur është ndryshimi i kodit të programit në nivelin e gjuhës së asamblimit.
* Gjuha e asamblimit vazhdon të mësohet në shumicën e programeve të shkencave kompjuterike dhe inxhinierisë elektronike. Megjithëse sot pak programues punojnë rregullisht me gjuhën e asamblimit si mjet, konceptet themelore mbeten të rëndësishme. Tema të tilla bazë si **aritmetika binare**, **alokimi i kujtesës**, **përpunimi i stack‑ut**, **kodifikimi i seteve të karaktereve**, **përpunimi i ndërprerjeve** dhe **dizajni i kompajlerëve** do të ishte e vështirë të studioheshin në detaje pa një kuptim të funksionimit të kompjuterit në nivel harduerik.  Meqenëse sjellja e një kompjuteri përcaktohet në mënyrë themelore nga **seti i udhëzimeve**, mënyra logjike për të mësuar këto koncepte është studimi i një gjuhe asamblimi. Shumica e kompjuterëve modernë kanë sete udhëzimesh të ngjashme. Prandaj, studimi i një gjuhe të vetme asamblimi është i mjaftueshëm për të mësuar konceptet bazë, për të njohur situatat ku përdorimi i gjuhës së asamblimit mund të jetë i përshtatshëm, dhe për të parë se si mund të krijohet kod ekzekutues efikas nga gjuhët e nivelit të lartë.

**Aplikime tipike**

Gjuha e assemblerit përdoret zakonisht në **kodin e nisjes së sistemit (boot code)**, kod i nivelit të ulët që inicializon dhe teston harduerin e sistemit para se të nisë sistemi operativ, dhe shpesh ruhet në **ROM**. (**BIOS** në sistemet **IBM‑compatible PC** dhe **CP/M** është një shembull.)

Gjuha e assemblerit përdoret shpesh për **kodin e nivelit të ulët**, për shembull në **kernelët e sistemeve operative**, të cilët nuk mund të mbështeten në thirrje ekzistuese të sistemit dhe duhet t’i implementojnë ato për arkitekturën specifike të procesorit ku do të funksionojë sistemi.

Disa kompajlerë e përkthejnë fillimisht gjuhën e nivelit të lartë në assembler para kompilimit të plotë, duke lejuar që kodi assembler të shihet për **debugging** dhe **optimizim**.

Disa kompajlerë për gjuhë relativisht të nivelit të ulët, si **Pascal** ose **C**, i lejojnë programuesit të fusin gjuhën e asamblimit drejtpërdrejt në kodin burimor (*inline assembly*). Programet që përdorin këto mundësi mund të ndërtojnë abstraksione duke përdorur gjuhë të ndryshme asamblimi në secilën platformë harduerike. Kodi portabël i sistemit mund të përdorë më pas këto komponentë specifikë për procesorin përmes një ndërfaqeje uniforme.

Gjuha e assemblerit është e dobishme në **reverse engineering**. Shumë programe shpërndahen vetëm në formë **machine code**, e cila është e thjeshtë për t’u përkthyer në gjuhën e asamblimit nga një **disassembler**, por më e vështirë për t’u përkthyer në gjuhë të nivelit të lartë përmes një **decompiler**. Mjete si **Interactive Disassembler** përdorin gjerësisht disassembler‑in për këtë qëllim. Kjo teknikë përdoret nga **hackerët** për të thyer softuerin komercial, si dhe nga konkurrentët për të prodhuar softuer me rezultate të ngjashme.

Gjuha e assemblerit përdoret për të rritur **shpejtësinë e ekzekutimit**, veçanërisht në kompjuterët personalë të hershëm me fuqi të kufizuar përpunimi dhe **RAM**.

Assemblerët mund të përdoren për të gjeneruar **blloqe të dhënash**, pa mbingarkesën e gjuhëve të nivelit të lartë, nga kod burimor i formatuar dhe i komentuar, për t’u përdorur nga kode të tjera.

## Shiko edhe 
** **Kompajler** – Softuer që përkthen kodin nga një gjuhë programimi në një tjetër
** **Krahasimi i assemblerëve**
** **Disassembler** – Program kompjuterik që përkthen gjuhën e makinës në gjuhën e asamblimit
** **Heksadecimal** – Paraqitje numerike me bazë 16
** **Gjuha e Përpunimit të Informacionit (Information Processing Language)** – Gjuhë e hershme programimi për lista
** **Arkitektura e setit të udhëzimeve (Instruction set architecture)** – Model që përshkruan ndërfaqen e programueshme të një procesori kompjuterik
** **Kompjuteri “Little man”** – Model instruksional i një kompjuteri
** **Nibble** – Njësi e të dhënave binare me katër bita
** **Gjuha e asamblimit të tipizuar (Typed assembly language)**

## Referime