limbaj de asamblare

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare
Notă despre dezambiguizare.svg Dezambiguizare - "Asamblare" se referă aici. Dacă căutați alte semnificații, consultați Asamblare (dezambiguizare) .
Asamblare
limbaj de programare
Motorola 6800 Assembly Language.png
Cod de asamblare pentru procesor Motorola 6800
Data de origine datează de la primele computere program memorate
Utilizare limbaj de uz general
Paradigme programare generică
Tastare nici unul
Extensii comune .asm .s

Limbajul de asamblare (numit și limbajul de asamblare [1] sau limbajul asamblator [2] sau pur și simplu asamblarea ) este un limbaj de programare foarte asemănător cu limbajul mașinii , deși diferit de cel din urmă. Acesta este în mod eronat adesea menționată ca „ asamblare “, dar acesta din urmă termenul identifică doar „asamblare“ programul care convertește limbaj de asamblare în limbaj mașină.

Descriere

RISC și CISC

Limbajul de asamblare este așa-numitul ISA ( Instruction Set Architecture ) al unui procesor. Diferitele ISA pot fi împărțite în două grupuri mari: RISC ( Reduced Instruction Set Computer ) și CISC ( Complex Instruction Set Computer ). Primul grup tinde să aibă operații simple și rapide, cu o abundență mare de registre pentru a stoca rezultate intermediare. Al doilea oferă programatorului instrucțiuni mai complexe, care uneori imită pe cele ale limbajelor de nivel superior (de exemplu, copierea șirurilor în procesoare x86). În ambele cazuri, cele mai bune seturi de instrucțiuni tind să fie așa-numitele ortogonale , unde diferitele metode de adresare și diferitele registre pot fi utilizate în mod alternativ în toate instrucțiunile. Seturi de instrucțiuni ortogonale celebre sunt cele ale Motorola 68000 (CISC) și MIPS (RISC). ISA a procesoarelor Intel x86 a fost inițial foarte puțin ortogonală și a fost din ce în ce mai bună.

Distincția dintre seturile de instrucțiuni RISC și CISC este oarecum estompată astăzi, deoarece majoritatea procesoarelor de consum astăzi sunt CRISP , adică un amestec al celor două. De asemenea, unele procesoare traduc ISA-ul original într-un set de instrucțiuni interne, din diferite motive și în moduri diferite:

  • în cazul Intel Pentium 4 și AMD Athlon , este vorba de a scăpa de limitările cauzate de un ISA acum arhaic compatibil înapoi, iar conversia este realizată direct de hardware dedicat care efectuează decodarea necesară;
  • în cazul procesoarelor Transmeta , trebuie să puteți „traduce” ISA-ul altor procesoare existente ca și cum ar fi propriile lor, iar traducerea se face prin ceva conceptual similar cu rutinele firmware (numite microcod ) stocate într-un ROM suprafață obținută pe siliciul microprocesorului.

Domeniul de aplicare

Asamblarea are scopul general de a permite programatorului să ignore formatul binar al limbajului mașinii. Fiecare cod de operare al limbajului mașinii este înlocuit, în ansamblu, de o secvență de caractere care îl reprezintă sub formă mnemonică ; de exemplu, codul op pentru sumă ar putea fi transcris ca ADD și ADD pentru salt ca JMP . În al doilea rând, datele și adresele de memorie manipulate de program pot fi scrise, în asamblare, în cea mai potrivită bază numerică din acest moment: hexazecimal , binar , zecimal , octal dar și în formă simbolică, folosind șiruri de text (identificatori). Programul de asamblare este astfel relativ mai lizibil decât cel din limbajul mașinii, cu care totuși menține un izomorfism total (sau aproape total). Programul scris în asamblare nu poate fi rulat direct de procesor; trebuie tradus în limbajul corespunzător (binar) al mașinii, utilizând un program compilator numit asamblor .

Nu unicitate

Datorită acestei „apropieri” de hardware, nu există un singur limbaj de asamblare. În schimb, fiecare CPU sau familie de CPU are propriul ansamblu, diferit de celelalte. De exemplu, limbile de asamblare pentru procesoarele Intel x86 , Motorola 68000s și Dec Alpha sunt destul de diferite . Aceasta înseamnă că cunoașterea unui anumit limbaj de asamblare înseamnă a putea scrie programe numai pe un anumit procesor sau o anumită familie de CPU. Cu toate acestea, trecerea la alte procesoare este relativ ușoară, deoarece multe mecanisme sunt similare sau complet identice, deci tranziția se limitează la învățarea de noi coduri mnemonice, noi metode de adresare și alte particularități ale noului procesor.

Este mult mai puțin ușor să transportați un program scris în asamblare pe mașini cu procesoare diferite sau cu arhitecturi diferite: aproape întotdeauna înseamnă a fi nevoit să rescrieți programul de sus în jos, deoarece limbajele de asamblare depind complet de platforma pentru care au fost scris. Multe compilatoare de asamblare acceptă sisteme macro care ar putea fi utilizate pentru a rezolva parțial această problemă, dar aceasta nu este o soluție eficientă.

Mai mult, ansamblul nu oferă niciun „ control asupra tipurilor ” (nu există nimic similar similar cu conceptul de „ tip ” în programarea de nivel scăzut ), dar lasă programatorul responsabil pentru îngrijirea fiecărui detaliu al gestionării mașinii și necesită multă disciplină și comentarii extinse lucrează pentru a evita scrierea unui cod care este absolut ilizibil (pentru alți programatori, precum și pentru ei înșiși după un timp).

În fața acestor dezavantaje, asamblarea oferă o eficiență de neegalat și un control complet și absolut asupra hardware-ului: programele de asamblare sunt, în principiu, cele mai mici și rapide care pot fi scrise pe o anumită mașină.

Scrierea codului (bun) în asamblare este consumatoare de timp, dificilă și, prin urmare, foarte costisitoare, mai ales în perspectivă (modificări viitoare): din acest motiv, asamblarea este rareori singurul limbaj utilizat într-un proiect de masă, cu excepția cazului în care acesta are o dimensiune și un domeniu limitat . Este utilizat în general în combinație cu alte limbi: cea mai mare parte a codului este scrisă într-un limbaj la nivel înalt, în timp ce părțile cele mai critice (din motive de performanță, precizie de sincronizare sau fiabilitate) sunt scrise în asamblare.

Aceste probleme se găsesc în principal pe platforme precum computerele personale actuale, unde vastitatea cantitativă și gama enormă calitativă a hardware-ului disponibil creează o problemă obiectivă niciodată rezolvată (și probabil nu poate fi rezolvată) la nivel de unificare și standard pentru aplicații de nivel scăzut. . La aceasta se adaugă evoluția constantă către o stratificare din ce în ce mai mare a sistemelor de operare comune, caracterizată prin numeroase constrângeri și virtualizări ale perifericelor fizice și ale canalelor de comunicații, care nu facilitează dezvoltarea unui software care interacționează direct cu hardware-ul de bază. gestionează caracteristicile sale.

Cu toate acestea, putem cita două exemple, oricât de legate ar fi, de inversare totală a acestei paradigme generale:

  • Este destul de logic să creăm programe în întregime asamblate destinate hardware-ului caracterizat arhitectural prin documentare exhaustivă, predictibilitate mare, stabilitate și variabilitate temporală redusă a proiectării: de exemplu, putem menționa computerele de acasă din anii optzeci , cum ar fi Commodore Vic- 20 și C64 sau Sinclair ZX Spectrum .
  • De asemenea, are sens și o confirmare puternică în practica din ultimii treizeci de ani, să funcționeze în principal sau exclusiv în asamblare pe vasta piață a sistemelor încorporate , pentru programarea microcontrolerelor și DSP-urilor , posibil și sub formă de nuclee implementate prin ASIC , CPLD și FPGA. , Pentru a maximiza performanța și respectarea constrângerilor de timp, reducând în același timp amprenta . Acest lucru se reflectă la toate nivelurile lanțului de producție, începând de la proiectarea cipurilor și a limbajului aferent utilizând ISA de tip RISC și puternic ortogonale, a căror optimizare (în spațiu sau în performanță) este extrem de simplificată. Această abordare este fundamentală, deoarece permite economii mari de scară în proiecte tipice lumii încorporate , caracterizate prin capacitatea de a absorbi chiar și costuri inițiale ridicate ( NRE, costuri de inginerie non-recurente ), cu condiția ca acestea să vizeze o compresie puternică a unității costul produsului final.de asemenea pentru volumele mediu-mici.

Prin urmare, posibilitatea utilizării unui microcontroler cu resurse de memorie ROM și RAM foarte limitate prin scrierea firmware - ului în întregime în asamblare devine esențială pentru a minimiza costurile, greutatea în placă, susceptibilitatea electromagnetică, de asemenea, creșterea fiabilității (mai „învechite” au un avantaj de netrecut) în ceea ce privește milioane de ore de testare și funcționare pe teren, care este de departe cea mai valoroasă „marfă” pentru sisteme încorporate în mod critic critice) și optimizarea a altor factori.

Structura

Structura unei listări tipice de asamblare x86 pentru PC este structurată în general, după cum urmează:

  • antet, în care putem insera, prin comentarii, numele și funcția programului.
  • segment de date, în care declarăm formal variabilele utilizate de program (în practică alocăm zone de memorie în segmentul care indică din segmentul de date DS)
  • segmentul stivei, în care definim structura stivei asociată programului (vom vorbi despre stivă mai târziu)
  • segment de cod, în care este prezent codul programului
  • închidere

Merită să reiterăm faptul că această structură, în general, depinde aproape în totalitate de platformă și, de asemenea, de ansamblul utilizat și, prin urmare, nu poate fi universalizată în niciun fel. Diferite arhitecturi, de la mainframe la microcontrolere, cu asamblori și asamblori încrucișați, impun structuri sursă care sunt uneori clar diferite de exemplul simplu ilustrat, referitor la PC-uri comune. Pentru un contraexemplu banal, în arhitecturile Harvard utilizate de aproape toate microcontrolerele și multe arhitecturi de supercomputere:

  • segmentul de cod nu se poate scrie în timpul procesării normale: urmează, printre altele, imposibilitatea absolută de a crea cod de auto-transformare (auto-modificare), dar și un mod în general diferit de referențiere a variabilelor (strict vorbind, etichete corespunzătoare unuia sau mai multe locații în memoria de date) și cod în sursă;
  • datele, la rândul lor, se află în amintiri separate fizic, uneori dotate și cu persistență între sesiuni (EPROM, Flash EEPROM, RAM „tamponată”, adică echipată cu o baterie de rezervă ...), iar toate acestea se reflectă în mod explicit și omniprezent în sintaxa susținută de asamblor, în directivele specifice și în structura reală a unei surse de asamblare;
  • nu în ultimul rând: registrele precum DS și SS (segmentul stivei) sunt alte particularități ale platformei x86, adesea stiva de apeluri nici măcar nu este accesibilă direct în cele mai populare nuclee MCU.

Eșantion de cod

Exemplu de program „ Hello world ” în ansamblul Intel x86 cu sintaxă Intel (profită de apelurile către sistemul de operare DOS). Nu este compatibil cu versiunile UNIX GNU Assembly

 MODEL MIC
STACK 100 H
.DATA
    HW DB  salut , lume  , 13 , 10 ,  $ 
.COD
.LANSARE
    MOV AX , @ date
    MOV DS , AX
    MOV DX , OFFSET HW
    MOV AH , 09 H
    INT 21 H
    MOV AX , 4 C00H
    INT 21 H
SFÂRȘIT

Acesta este în schimb exemplul programului scris pentru sintaxa AT&T (pentru arhitecturile UNIX GNU )

 .secțiunea .date

	Buna ziua:
		.ascii "hello hello world! \ n"

	salut_len:
		.lung . - salut # lungimea șirului în octeți

.secțiune .text

	_start .global

_start:
	movl $ 4 , % eax # 4 corespunde apelului de sistem „scrie”
	movl $ 1 , % ebx # print la ieșirea standard (ecran)
	leal salut,% ECx # char pointer la ceea ce doriți să imprimați
	
	movl hello_len , % edx # copiați conținutul variabilei. încarcă lungimea variabilei

	int $ 0x80 # apel de sistem (int ar fi „întrerupere”); cu 0x80 se lansează o interacțiune generală
                                # declarat (pe baza valorilor încărcate anterior în registre)
				
	movl $ 1 , % eax # 1 corespunde apelului de sistem „exit”

	xorl % ebx , % ebx #zero EBX; movl $ 0,% ebx poate fi, de asemenea, scris, dar este mai puțin eficient

	int 0x80 $

Microinstrucțiuni

Când se execută o instrucțiune de asamblare, procesorul (conform arhitecturii luate în considerare) efectuează o serie de operații numite „Microinstrucțiuni de asamblare”, adică operații hardware care sunt utilizate pentru a configura registrele și operatorii procesorului astfel încât să poată ca instrucțiunea să fie executată.

Acest proces este împărțit, în cazul procesoarelor Intel x86 și alții, în 3 părți:

  • Fetch: faza de încărcare în care registrul PC-ului este mărit și CPU-ul este pregătit pentru a efectua operația;
  • Decodează: multiplexerele din interiorul procesorului sunt configurate și se efectuează o codificare a instrucțiunii dacă este necesar (adresare indirectă, deplasare, etc ...)
  • Executați: timpul în care operația este efectiv efectuată

De aici și abrevierea FDE, Fetch-Decode-Execute, raportată în textele arhitecturale și în fișele tehnice.

Pentru a da un exemplu pentru arhitectura Intel 80x86 cu un singur BUS, în sintaxa AT&T, această instrucțiune:

 ADĂUGAȚI % EBX , % EAX

în care conținutul registrului EAX este adăugat la conținutul registrului EBX și rezultatul va fi salvat în EAX, aceste micro-operațiuni sunt efectuate:

 1. PCout , SELECT [ 4 ], ADD , Zin , MARin , READ ; PC-ul este incrementat pentru a efectua următoarea operație
2. Zout , PCin , WMFC ; se așteaptă ca citirea memoriei să aibă loc
3. MDRout , IRin , se trimite următoarea instrucțiune în IR
4. EAXout , Vin ; conținutul EAX este trimis într-un jurnal temporar
5. EBXout , SELECT [ V ], ADD , Zin ; conținutul EBX este adăugat prin ALU cu EAX
6. Zout , EAXin , END , rezultatul este copiat în EAX

Pe unele arhitecturi, aceste faze se dovedesc a fi patru (de exemplu, în microcipurile PIC, în Intel 8051 și în multe nuclee similare), care arată, de asemenea, raportul real între viteza de ceas sau frecvența cristalului extern (de exemplu, 10 MHz) ) și numărul instrucțiunilor efectiv executate într-o secundă. Pentru PIC-uri (în special familiile de bază și midrange ) acest raport este egal cu 1/4, deoarece la fiecare ciclu de ceas nucleul efectuează de fapt o singură fază Fetch-Decode-Execute-Write și, prin urmare, sunt necesare patru cicluri ale ceasului extern pentru a finaliza o singură instrucțiune. Pe microcontrolerele de proiectare și arhitecturile de bază mai arhaice sau altfel diferite, sunt necesare și mai multe cicluri de ceas pentru fiecare fază (de exemplu, trei sau patru), de unde raportul diferit între ceas și MIPS, care, în cazul designului original 8051, necesită de exemplu 12 cicluri de ceas pentru fiecare instrucțiune. În cele din urmă, trebuie amintit faptul că unele instrucțiuni, inclusiv salturi necondiționate, necesită pe un număr considerabil de platforme (atât RISC, cât și CISC, concepute în diferite epoci) un număr mai mare de cicluri decât celelalte, datorită operațiilor accesorii (nu paralelizabile) ) necesar prin actualizarea registrului IP și a oricăror cozi de preluare interne.

C-asm

Uneori, în programarea la nivel înalt în medii precum DOS, este nevoie de efectuarea unor operații care sunt mult mai rapide folosind instrucțiuni din limbaje de nivel scăzut (în Windows, pe de altă parte, datorită protecției memoriei, Apelurile WINAPI , L / M sunt utilizate mai ales pentru proceduri matematice accelerate sau de către conducători auto ). Printre limbajele de nivel înalt care permit acest lucru se numără C și C ++ , în care părțile scrise în asamblare pot fi inserate în sursele lor care, în timpul compilării, vor fi traduse cu o procedură cunoscută sub numele de asamblare inline . Un exemplu de cod scris în C-asm (folosind ansamblul Intel x86), care afișează un număr dat în binar ca intrare, este următorul exemplu care folosește directiva stdio.h care gestionează operațiunile de intrare / ieșire, directiva iostream. h care are aceleași funcții ca și precedentul, dar care garantează compatibilitatea cu compilatoarele mai vechi și în cele din urmă directiva conio.h responsabilă de crearea interfețelor textuale.

 #include <stdio.h>
#include <iostream.h>
#include <conio.h>
int main () 
{
    int a ;

    / * Achiziționarea valorii numerice * /
    printf ( „Introduceți o valoare între -32768 și 32768”);
    scanf ( " % d " , & a ) ;

    / * Afișarea mesajului de răspuns * /
    printf ( „Valoarea corespunzătoare în binar este:“);
    
    / * Cuvânt cheie pentru a delimita secțiunile codului de asamblare * /
    asm 
    { 
        / * Afișarea șirului de biți corespunzător * /
        MOV BX , WORD PTR a
        MOV CX , 00 Ah
    }

    / * Etichetă externă * /
    Ciclu: 
        asm
        {
            / * Extragerea unui pic * /
            MOV DL , 00 H
            RCL BX , 1 / * Valoarea bitului este plasată în steagul de transport * /
            ADC DL , ' 0 ' / * Determinați caracterul de afișat * /
            MOV AH , 02 H / * Afișaj * /
            INT 21 h
            Ciclu de buclă
        } 
    retur 0 ;
}

Pentru majoritatea aplicațiilor de masă , acum este o credință comună în comunitatea programatorilor de aplicații că factori precum optimizările generate automat de compilatoare în limbaje de nivel superior, evoluția bibliotecilor care sunt ele însele tot mai optimizate (cel puțin în principiu) și puterea de procesare crescândă a platformelor utilizate în mod obișnuit face mai puțin necesară decât în ​​trecut recurgerea la verticalizare prin ansambluri în linie sau module de asamblare, de asemenea în favoarea portabilității și lizibilității codului. Cu toate acestea, există numeroase excepții în contrast total cu această concepție larg răspândită: în special în lumea sistemelor dedicate, bazate aproape prin definiție pe o paradigmă foarte diferită, așa cum se menționează în paragraful „Nu există o singură asamblare”, ci și în numeroase nișe de specialitate la marginea mainstream - ului , de la sisteme CAD / CAM la calcul numeric, la diverse aplicații științifice, până la dezvoltarea driverelor și a altor software-uri de sistem.

Structuri de control în ansamblul x86

Procesorul execută instrucțiunile pe măsură ce apar, una după alta. Cu toate acestea, prin anumite structuri, este posibil să se controleze fluxul executiv pe baza unei anumite condiții. În acest fel este posibil să se creeze structuri de selecție simplă sau de tip iterativ (cicluri). Instrucțiunile de asamblare care sunt utilizate în acest scop sunt în principal de două tipuri: salt și comparare.

Salturile pot fi necondiționate sau condiționate. JMP face un salt necondiționat. Adresa de referință este de obicei o etichetă. Condiția de salt este întotdeauna dictată de valorile registrului steagului. Cele mai utilizate steaguri pentru salturi sunt:

  • ZF (flag zero) indică dacă ultima instrucțiune a dus la 0
  • SF (semn de semnalizare) indică dacă ultima instrucțiune a generat un rezultat de semn negativ
  • OF (flag overflow) indică dacă ultima instrucțiune a generat un overflow (cu trunchierea celui mai semnificativ bit al rezultatului)

Construcția de selecție (dacă, altfel)

Selecția este o structură care vă permite să executați un bloc de instrucțiuni sau altul bazat pe apariția unei condiții.

 de sine
     blocul de instrucțiuni 1
 in caz contrar
    blocul de instrucțiuni 2
 bine dacă

în asamblare, prin logica salturilor, este reprezentat după cum urmează:

 de sine:
   JNcondiționează altfel
   blocul de instrucțiuni 1
   JMP end_se
 in caz contrar:
   blocul de instrucțiuni 2
 end_if:

Bucla de control în coadă (faceți ... în timp ce)

Iterația este o structură care vă permite să repetați de mai multe ori o instrucțiune sub controlul unei afecțiuni.

 repeta
     instrucțiuni
 atâta timp cât starea 

în asamblare, prin logica salturilor, este reprezentat după cum urmează:

 start_cycle:
   instrucțiuni
 Starea de pornire Jcycle 

exemplu:

 MOV AX, 0000h
 start_cycle:
   INC AX
   CMP AX, 000Ah; comparați AX și valoarea 0Ah (10d)
 JNE start_cycle; săriți la început (și repetați ciclul) dacă este diferit 

Deoarece verificarea stării este efectuată la sfârșitul buclei, instrucțiunile secvențiate sunt încă executate cel puțin o dată, chiar dacă starea a fost deja verificată la început. Practic:

 MOV AX, 000Ah
 start_cycle:
   INC AX
   CMP AX, 000Ah
 JNE start_cycle 

Acest fragment de cod ar trebui să verifice dacă AX = 10d și, dacă nu, crește AX. Dacă da, părăsiți ciclul. Cu toate acestea, vedem că AX valorează deja 10d, totuși acest registru este oricum incrementat (în final va valora 000Bh). Mai mult, în acest program special, ciclul nu se va termina niciodată: AX va valora 11, apoi 12, apoi 13 și nu va deveni niciodată egal cu 10. Ar fi o idee bună, în condiții, să eviți să exprimi o egalitate:

 MOV AX, 000Ah
  start_cycle:
    INC AX
    CMP AX, 000Ah
  JB start_cycle; săriți dacă este mai mic (în loc de săriți dacă nu este egal) 

În acest fel am rezolvat problema buclei infinite. Cu toate acestea, datorită faptului că secvența rulează cel puțin o dată, de obicei evitați bucla de control a cozii și utilizați în schimb bucla de verificare a capului.

Bucla de control aerian (în timp ce)

O structură iterativă cu control aerian poate fi descrisă, la un nivel ridicat, după cum urmează:

 în timp ce starea
   instrucțiuni
 sfârșitul ciclului 

Acesta este același lucru cu timpul (condiția) {secvența} lui C. în asamblare:

 start_cycle:
   Stare JN end_cycle
       secvenţă
   JMP start_cycle
 sfârșitul ciclului 

exemplu:

 start_cycle:
   CMP AX, 0Ah; comparați AX cu 10d
   JNE end_cycle; săriți dacă este diferit
       INC AX; crește AX
   JMP start_cycle
 sfârșitul ciclului 

Diferența dintre această structură și structura de control în coadă este că, dacă condiția este inițial adevărată, succesiunea instrucțiunilor nu se execută nici măcar o dată.

Bucla contra (pentru)

Ciclul contorului are o structură de acest tip:

 CONTOR = 0
 în timp ce CONTOR <N
   secvenţă
   creștere CONTOR
 sfârșitul ciclului

O buclă de contor poate fi utilizată dacă vrem să repetăm ​​un bloc de instrucțiuni de mai multe ori cunoscute a priori. buclele în asamblare sunt în general descrescătoare:

 CONTOR = N
 repeta
   secvenţă
   scade CONTOR
 până la CONTOR n> 0

Ca contor, de obicei folosim registrul CX (registrul contorului, de fapt), deoarece există o instrucțiune care execută automat ultimele două instrucțiuni: instrucțiunea LOOP: diminuează CX și, dacă CX nu este 0, sare la eticheta specificată .

 MOV CX, 0
 start_cycle:
   CMP CX, N
   JGE end_cycle
   secvenţă
 JMP start_cycle
 sfârșitul ciclului:

Datorită instrucțiunilor LOOP devine ușor să scrieți o buclă de contor în asamblare:

 MOV CX, <N>; unde N este numărul de repetări de efectuat
 start_cycle:
   secvenţă
 LOOP start_cycle

Trebuie subliniat faptul că în primul exemplu există un ciclu cu control la cap, în timp ce în al doilea cu control în coadă și că, deși al doilea este mai compact și mai rapid de scris, poate genera erori, ca menționat deja mai sus, dacă nu aveți grijă la modul în care îl utilizați, de fapt în el instrucțiunile sunt executate cel puțin o dată, deci dacă nu sunteți sigur că numărul de repetări nu poate fi niciodată zero, este mai puțin riscant să folosiți prima.

Intrare / ieșire prin DOS INT 21h

Ansamblul, în special în lumea computerelor, nu include funcții de intrare / ieșire gata pregătite. Prin urmare, programatorul trebuie să își creeze propriile rutine sau să se bazeze pe cele create de terți. În mediile DOS este suficient să plasați codul de serviciu necesar în AX și să utilizați instrucțiunea INT 21h pentru a apela întreruperea software-ului aferent, una dintre cele mai specifice caracteristici ale procesorelor Intel x86. Printre cele mai comune funcții pentru intrarea / ieșirea tastaturii:

  • service 01h ==> Achiziționarea unui caracter de la tastatură cu ecou pe ecran. Așteptă apăsarea unei taste și returnează codul ASCII al tastei apăsate
  • service 02h ==> Afișarea unui caracter pe ecran. Tipărește caracterul al cărui cod ASCII este conținut în DL
  • service 07h ==> Achiziționarea unui caracter de la tastatură fără ecou pe ecran. La fel ca serviciul 01h, dar nu afișează fontul pe ecran
  • service 09h ==> Afișarea unui șir pe ecran. Imprimați șirul indicat de adresa de memorie conținută în DX
  • Serviciu 4Ch ==> Reveniți la sistemul de operare. Încheie programul.

Deci, pentru a dobândi un personaj (ecou pe videoclip):

 MOV AH, 01h; serviciu 01h
 INT 21h; dacă AX = 0001h, atunci codul ASCII al tastei apăsate merge la AL

Și apoi dorind să-l tipăriți:

 MOV DL, AL; Copiez codul ASCII al cheii citit DL
 MOV AH, 02h; serviciu 02h
 INT 21h; dacă AX = 0002h, atunci tipăriți caracterul codului ASCII în D 

După cum puteți vedea, atât operațiile de captare, cât și cele de tipărire se referă la coduri de caractere ASCII. Dacă doriți să citiți o cifră numerică ca intrare, pentru a reveni la valoarea numerică, scădeți doar valoarea 30h (48 în zecimal) din codul ASCII. De fapt, 30 de ore în ASCII corespund caracterului "0", 31 de ore (49 în zecimal) la "1" și așa mai departe ...

În cazul în care doriți să imprimați un șir:

 Șir DB 13,10, „acesta este un șir”, „$”; Aloc o variabilă de un octet pe care o numesc șir și în care salvez o secvență de caractere (un șir de fapt)
 LEA DX, șir; Copiez adresa de memorie care indică șirul în DX
 MOV AH, 09h; serviciu 09h
 INT 21h; dacă AX = 0009h, atunci imprimă șirul indicat de adresa de memorie conținută în DX

Asamblare X86

Asamblarea x86 este o familie de limbaje de asamblare, utilizată pentru a crea coduri obiect pentru procesoarele Intel X86 . Ca toate limbajele de asamblare, folosește cuvinte scurte pentru a crea instrucțiuni CPU .

Notă

  1. ^ Tanenbaum 2006 .
  2. ^ limbaj asamblator , în Treccani.it - ​​Enciclopedii online , Institutul Enciclopediei Italiene.

Bibliografie

Elemente conexe

Alte proiecte

linkuri externe

Controlul autorității Tezaur BNCF 45031 · LCCN (EN) sh85008765 · GND (DE) 4003255-3 · BNF (FR) cb11961749m (data)
Informatică Portal IT : accesați intrările Wikipedia care se ocupă cu IT