limbaj de asamblare
Asamblare limbaj de programare | |
---|---|
Cod de asamblare pentru procesor Motorola 6800 | |
Data de origine | datează de la primele computere program stocate |
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 de asamblare [2] sau pur și simplu asamblarea ) este un limbaj de programare foarte similar cu limbajul mașinii , deși este 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, adresele de date și 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
Din cauza 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ă purtați un program scris în asamblare pe mașini cu procesoare diferite sau cu arhitecturi diferite: aproape întotdeauna înseamnă că trebuie 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).
Față de aceste 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 mai rapide care pot fi scrise pe o mașină dată.
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 un răspuns puternic în practica din ultimii treizeci de ani, să funcționăm în principal sau exclusiv în asamblare pe vasta piață a sistemelor încorporate , pentru programarea microcontrolerelor și a 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ă, creșterea, de asemenea, fiabilitatea (mai mulți procesoare „învechite” au o capacitate de netrecut) avantaj în termeni de milioane de ore de testare și funcționare pe teren, care este de departe cea mai valoroasă „marfă” pentru sisteme încorporate diferite în mod critic) și optimizarea 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-urile 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
STIV 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 altele, î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 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 flagul 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 se efectuează la sfârșitul buclei, instrucțiunile secvențiate sunt încă executate cel puțin o dată, chiar dacă condiția 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 echivalentul timpului (condiție) {secvență} a lui C. în asamblare:
start_cycle: Starea JNcycle end 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ă folosiț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ă
- ^ Tanenbaum 2006 .
- ^ limbaj asamblator , în Treccani.it - Enciclopedii online , Institutul Enciclopediei Italiene.
Bibliografie
- Andrew Stuart Tanenbaum , nivel de limbaj de asamblare , în Arhitectura computerelor. O abordare structurală , Milano, Pearson Education, 2006, pp. 491-528, ISBN 978-88-7192-271-3 .
- Alain Pinaud, Programare în asamblare , Jackson Publishing Group, 1982, ISBN 88-7056-105-4 .
- (EN) Randall Hyde, The Art of Assembly Language , No Starch Press, 2010, ISBN 978-1-59327-301-9 .
Elemente conexe
Alte proiecte
-
Wikibooks conține texte de asamblare sau manuale
-
Wikimedia Commons conține imagini sau alte fișiere despre Assembly
linkuri externe
- Ghidul limbajului de asamblare MIPS / SPIM Arhitecturi R2000 / R3000
- Aflați asamblarea cu Visual C ++
- ( EN , IT , FR , ES , DE , ZH ) Limbajul de asamblare pentru PC , tutorial de Paul Carter despre asamblarea x86
- Programare Intel x86
Controlul autorității | Tezaur BNCF 45031 · LCCN (EN) sh85008765 · GND (DE) 4003255-3 · BNF (FR) cb11961749m (data) |
---|