Asamblator | ||
Data primei versiuni | 1949 | |
---|---|---|
Extensie de fișier | asm și s | |
Un limbaj de asamblare sau un limbaj de asamblare este, în programarea computerului , limbajul de nivel inferior care reprezintă limbajul mașinii într-o formă lizibilă de om. Combinațiile de biți ai limbajului mașinii sunt reprezentate prin așa-numitele simboluri „ mnemonice ” , adică ușor de reținut. Programul de asamblare convertește aceste mnemonice în limbajul mașinii, precum și valorile (scrise în zecimal) în binare și etichetele locațiilor în adrese, în vederea creării, de exemplu, a unui fișier obiect sau a unui fișier executabil .
În practica actuală, același termen asamblor este utilizat atât pentru a desemna limbajul de asamblare, cât și programul de asamblare care îl traduce. Vorbim astfel de „programare în asamblare”.
Traducerea o dată pentru totdeauna de către mulți interpreți a fiecărui nume de variabilă întâlnită într-o instrucțiune (avansată) după poziția memoriei asociate și a fiecărei constante (scrisă de utilizator în zecimal) în binar este tipică pentru o operație d. asamblatorul de nume nu este frecvent utilizat în acest caz particular.
Programele EDSAC (1949), primul computer cu programe înregistrate , au fost scrise folosind mnemonica alfabetică a unei litere pentru fiecare instrucțiune. Traducerea a fost apoi făcută manual de către programatori, o operație lungă, plictisitoare și predispusă la erori.
Primul program de asamblare a fost scris de Nathaniel Rochester pentru IBM 701 (primul computer lansat de IBM ) în 1954.
Limbajele de asamblare au eliminat multe dintre erorile făcute de programatorii din prima generație de computere, renunțând la necesitatea memorării codurilor numerice ale instrucțiunilor și a efectuării calculelor adreselor. Programarea asamblării a fost apoi utilizată pentru a scrie tot felul de programe.
În anii 1970 și 1980, utilizarea asamblorului pentru a scrie aplicații a fost în mare parte înlocuită de utilizarea limbajelor de programare la nivel înalt: Fortran , COBOL , PL / I etc. : puterea mașinilor i-a permis-o și a dedica câteva minute de timp calculatorului unei compilații pentru a economisi câteva ore de timp de programare a fost o operațiune profitabilă, chiar dacă compilatorii timpului au furnizat cod mai puțin eficient (mai mare și adesea mai lent). În plus, aceste limbaje la nivel înalt au făcut posibilă depășirea dependenței de o singură arhitectură hardware.
Sistemele de operare au fost scrise în limbaj de asamblare până la introducerea MCP în Burroughs în 1961, care a fost scrisă în ESPOL, un dialect al Algolului .
Asamblatorul s-a întors oarecum în favoarea primelor microcomputere, unde caracteristicile tehnice (dimensiunea redusă a memoriei, puterea de calcul redusă, arhitectura specifică a memoriei etc.) au impus constrângeri puternice, la care se adaugă un factor psihologic important, atitudinea „hobbyist” dintre primii utilizatori de microcomputere, care nu au fost mulțumiți de încetineala programelor scrise cu BASIC interpretat furnizat în general cu computerul.
Programe mari au fost scrise în întregime în asamblare pentru microcomputere, cum ar fi sistemul de operare DOS al computerului IBM (aproximativ 4000 de linii de cod) și foaia de calcul Lotus 1-2-3 (rivalul său Multiplan, care exista deja sub CP / M , era scris în C ). În anii 1990, acesta a fost și cazul majorității jocurilor pentru console video (de exemplu pentru Mega Drive sau Super Nintendo ).
Limba mașină este singura limbă pe care un procesor poate executa. Cu toate acestea, fiecare familie de procesoare utilizează un set diferit de instrucțiuni .
De exemplu, un procesor din familia x86 recunoaște o instrucțiune de tipul:
10110000 01100001În limbajul de asamblare, această instrucțiune este reprezentată de un echivalent mai ușor de înțeles pentru programator:
movb $0x61,%al(10110000 = movb% al
01100001 = 0x61 $)
Ceea ce înseamnă: „scrieți numărul 97 (valoarea este dată în hexazecimal : 61 16 = 97 10 ) în registrul AL”.
Astfel, limbajul de asamblare, o reprezentare exactă a limbajului mașinii, este specific fiecărei arhitecturi de procesor . În plus, pot exista mai multe grupuri de mnemonice sau sintaxe ale limbajului de asamblare pentru un singur set de instrucțiuni, creând astfel macroinstrucțiuni .
Transformarea codului de asamblare în limbajul mașinii este realizată de un program numit program de asamblare . Operația inversă , și anume găsirea ansamblului echivalent cu o bucată de cod de mașină, are un nume: este dezasamblare .
Contrar a ceea ce s-ar putea crede, nu există întotdeauna o corespondență unu-la-unu (o bijecție ) între codul de asamblare și limbajul mașinii. Prin urmare, pe unele procesoare, dezasamblarea poate duce la un cod care este foarte greu de înțeles pentru un om, rămânând însă perfect compilabil de către un computer. Imposibilitatea unei dezasamblări poate avea diverse motive: utilizarea codului auto-modificat, instrucțiuni de dimensiuni variabile, imposibilitatea de a face distincția între cod și date etc. ( cod impenetrabil )
Mai mult, multe elemente prezente în codul de asamblare se pierd în timpul traducerii sale în limbajul mașinii. La crearea codului în asamblare, programatorul poate atribui nume pozițiilor din memorie, poate comenta codul său , poate utiliza instrucțiuni macro sau poate utiliza codul generat în condiții în momentul asamblării. Toate aceste elemente sunt reduse în timpul asamblării la ceea ce este strict necesar pentru mașină și, prin urmare, nu apar clar în timpul demontării: de exemplu, o poziție în memorie este marcată doar de adresa sa numerică sau de un offset .
Unele operații fundamentale sunt disponibile în majoritatea seturilor de instrucțiuni.
Și există instrucțiuni specifice cu una sau câteva instrucțiuni pentru operațiuni care ar fi trebuit să ia o mulțime. Exemple:
În plus față de codificarea instrucțiunilor mașinii, limbajele de asamblare au directive suplimentare pentru asamblarea blocurilor de date și atribuirea adreselor instrucțiunilor prin definirea etichetelor sau etichetelor.
Sunt capabili să definească expresii simbolice care sunt evaluate la fiecare ansamblu, făcând codul și mai ușor de citit și de înțeles.
De obicei au un limbaj macro încorporat pentru a facilita generarea de coduri complexe sau blocuri de date.
Iată câteva exemple simple:
(Comentariile sunt după punct și virgulă)
str: .ascii "Bonjour\n" .global _start _start: movl $4, %eax movl $1, %ebx movl $str, %ecx movl $8, %edx int $0x80 movl $1, %eax movl $0, %ebx int $0x80 ;Compilation: ;as code.s -o code.o ;ld code.o -o code ;Execution: ;./codeIată aceleași exemple, cu câteva diferențe:
(Comentariile sunt după punct și virgulă)
section .data ; Variables initialisées Buffer: db 'Bonsoir', 10 ; En ascii, 10 = '\n'. La virgule sert à concaténer les chaines BufferSize: equ $-Buffer ; Taille de la chaine section .text ; Le code source est écrit dans cette section global _start ; Définition de l'entrée du programme _start: ; Entrée du programme mov eax, 4 ; Appel de sys_write mov ebx, 1 ; Sortie standard STDOUT mov ecx, Buffer ; Chaine à afficher mov edx, BufferSize ; Taille de la chaine int 80h ; Interruption du kernel mov eax, 1 ; Appel de sys_exit mov ebx, 0 ; Code de retour int 80h ; Interruption du kernelExistă dezbateri despre utilitatea limbajului de asamblare. În multe cazuri, compilatoarele - optimizatorii pot transforma limbajul la nivel înalt în cod care rulează la fel de eficient ca codul de asamblare scris de mână de un programator foarte bun, fiind totuși mult mai ușor, mai rapid (și, prin urmare, mai puțin eficient). Scump) de scris, citit și întreținut. .
Eficiența era deja o preocupare în anii 1950, găsim o urmă a acesteia în manualul de limbă Fortran (lansat în 1956) pentru computerul IBM 704 : Programele obiecte produse de Fortran vor fi aproape la fel de eficiente ca cele scrise de buni programatori .
Compilatorii care au realizat între timp progrese enorme, este, prin urmare, evident că marea majoritate a programelor sunt acum scrise în limbaje la nivel înalt din motive economice, costul suplimentar al programării depășind câștigul rezultat din îmbunătățirea așteptată a performanței.
Cu toate acestea, există încă câteva cazuri foarte specifice în care utilizarea asamblorului este încă justificată:
Unele compilatoare transformă, atunci când cea mai mare opțiune de optimizare nu este activată , programele scrise în limbaj de nivel înalt în cod de asamblare, fiecare instrucțiune de nivel înalt rezultând într-o serie de instrucțiuni de asamblare riguros echivalente și folosind aceleași simboluri; acest lucru vă permite să vedeți codul în scopuri de depanare și profilare , care uneori pot economisi mult mai mult timp prin revizuirea unui algoritm . În nici un caz aceste tehnici nu pot fi păstrate pentru optimizarea finală.
Programarea sistemelor încorporate , adesea bazată pe microcontrolere , este o „nișă” tradițională pentru programarea ansamblului. De fapt, aceste sisteme sunt adesea foarte limitate în resurse (de exemplu, un microcontroler PIC 16F84 este limitat la 1.024 de instrucțiuni de 14 biți și RAM-ul său conține 136 de octeți) și, prin urmare, necesită o programare de nivel scăzut foarte optimizată pentru a-și exploata posibilitățile. Cu toate acestea, evoluția hardware-ului face ca componentele acestor sisteme să devină din ce în ce mai puternice la un cost constant și cu un consum constant de energie, investiția într-un programare „orice asamblator” mult mai scump în ore de lucru devine apoi o problemă prostii din punct de vedere al efortului. De obicei, programarea asamblării este mult mai lungă, mai delicată (deoarece programatorul trebuie să ia în considerare toate micro-detaliile de dezvoltare de la care se abține într-un limbaj de nivel înalt) și, prin urmare, considerabil mai scumpă decât programarea de limbaj de nivel înalt. Prin urmare, ar trebui rezervat doar pentru situații pentru care nu putem face altfel.
Mulți asamblori acceptă un limbaj de macrocomenzi . Este vorba de gruparea mai multor instrucțiuni pentru a avea o secvență mai logică și mai puțin plictisitoare.
De exemplu (în ansamblorul Microsoft MASM ):
este o macro care afișează un caracter sub MS-DOS . Acesta va fi folosit, de exemplu, după cum urmează:
Și va genera:
mov dl,"X" mov ah,2 int 21hO pseudoinstrucțiune este un tip special de instrucțiuni macro. Este predefinit de editorul software-ului de asamblare și funcția sa este de a emula o instrucțiune de procesor lipsă sau de a facilita utilizarea unei instrucțiuni existente. Deoarece pseudo-instrucțiunea are un nume foarte asemănător cu cel al unei instrucțiuni de procesor reale, este posibil la prima vedere să o confundați cu una dintre acestea din urmă. De exemplu, un procesor RISC poate să nu aibă o instrucțiune JMP, care vă permite să treceți la un anumit punct al programului și să continuați executarea acestuia în ordine. În acest caz, editorul software va fi creat pentru programator o pseudo-instrucțiune „JMP <parameter>”, care va fi înlocuită în timpul asamblării cu o instrucțiune „mov pc , <parameter>”, pc fiind instrucțiunea pointer care urmează să fie executat. Un alt exemplu, o pseudoinstrucțiune „PUSH <parameter>” va fi înlocuită cu o stocare a <parameter> la adresa indicată de sp cu pre-decrementare a acestuia din urmă, sp fiind indicatorul de stivă al procesorului.
Pe microprocesoarele sau microcontrolerele RISC precum cele din familia ARM , nu există instrucțiuni de asamblare care să permită încărcarea vreunei constante imediate într-un registru, indiferent de valoarea sa. Majoritatea asamblatoarelor au o pseudo-instrucțiune care permite o astfel de încărcare în cel mai eficient mod posibil în ceea ce privește timpul de execuție, economisind această sarcină pentru programator.
Suport pentru programare structurată : unele elemente ale programării structurate au fost integrate pentru a codifica fluxul de execuție de către Dr. HD Mills (Martie 1970), și implementat de Marvin Kessler care a extins ansamblorul de macrocomenzi S / 360 cu blocuri if / else / endif și chiar de control al fluxului. Aceasta a fost o modalitate de a reduce sau elimina utilizarea operațiunilor de salt în codul de asamblare.