Асемблерен език

от Уикипедия, свободната енциклопедия
Направо към навигацията Направо към търсенето
Емблема за пояснителна страница Тази статия е за програмния език. За системния софтуер вижте Асемблер.

Асемблерен език
Motorola 6800 Assembly Language.png
Motorola MC6800 асемблерен файл, показва оригиналния асемблерен език
Парадигма императивно програмиране
Реализиране през 1949 (преди 69 г.)
Асемблерен език в Общомедия

Асемблерен език е език за програмиране от ниско ниво, предназначен за компютри или други програмируеми устройства, при които има много строго (обикновено едно към едно) съответствие между езика и машинните кодови инструкции на процесорната архитектура. Всяка процесорна архитектура има свой собствен специфичен асемблерен език, за разлика от повечето езици за програмиране от високо ниво, които са съвместими с различни процесорни архитектури, но изискват превеждане или компилиране.

Асемблерният език се преобразува в изпълним от процесора код чрез помощна програма позната като асемблер. Процесът на преобразуване е познат като асемблиране на кода.

В асемблерния език се използват мнемонични изрази, за да представи всяка процесорна операция или инструкция от ниско ниво. Типичните операции изискват един или повече операнди, за да образуват цялостна инструкция и повечето асемблери за целта може да приемат етикети, символи и изрази като операнди, за да представят адреси и други константи, освобождавайки програмиста от досадните изчисления на ръка. Макро-асемблерите съдържат улесняващи макро инструкции, такива че текстът на асемблерния език да може да се представи чрез име и това име да може да си използва за вмъкване на разширения текст в друг код. Много асемблери предоставят допълнителни механизми за улесняване на разработката на програми, за контролиране на процеса на асемблиране и за подпомагане на дебъгването.

Вижте долу раздела с терминология за информация относно непоследователната употреба на термините асемблерен език и асемблер

Основна концепция[редактиране | редактиране на кода]

Асемблер[редактиране | редактиране на кода]

Асемблер е програма, която създава обектен код като превръща комбинации от мнемонични изрази и синтаксис за операции и адресни режими в техните цифрови еквиваленти. Това представяне обикновено включва операционен код, както и други контролни битове.[1] Също така асемблерът изчислява константни изрази и определя мястото в паметта на символни имена и други обекти.[2] Използването на символни референции е отличителна особеност на асемблерите, запазването на досадни изчисления и ръчно актуализиране на адресите след направени промени по програмата. Повечето асемблери също така включват улесняващи макро инструкции за извършване на текстови замествания, за генериране на често срещани кратки поредици от инструкции вътре в кода, вместо извикване на подпрограми.

Освен това за някои асемблери е възможно да извършват някои несложни типове оптимизации на групи от специфични инструкции. Един конкретен пример за това са срещащите се навсякъде x86 асемблери от различни производители. Много от тях имат опция да извършват замествания на инструкции за преход (дълги преходи се заместват от къси или подобни такива) независимо от броя им. Други могат дори да извършват несложно преподреждане или вмъкване на инструкции, каквито са някои асемблери за RISC процесорни архитектури, които могат да подпомагат оптимизирането на сложни списъци от инструкции, така че да се използва процесора най-ефективно.

Подобно на началните езици за програмиране като Fortran, Algol, Cobol и Lisp, асемблерите след 1950 година разполагат и с първите поколения текст базирани компютърни интерфейси. Като първо появили се, асемблерите се пишат доста по-лесно отколкото компилаторите за езиците от високо ниво. Това е така, защото всеки мнемоничен израз заедно с адресните режими и операндите на дадена инструкция се преобразуват почти директно в цифровия вид на съответната инструкция, без много връзки и анализи. Съществуват и няколко класа преобразуващи програми (транслатори), както и полуавтоматични генератори на код с характеристики подобни едновременно на асемблерите и на езиците от високо ниво, като добре познат пример за такава програма е Speedcode.

Може да съществуват няколко асемблера с различен синтаксис за определен процесор или друга програмируема архитектура. Например, инструкция за добавяне на данни за запаметяване в регистрите на x86 процесор може да е add eax,[ebx], на оригинален ''синтаксис на Intel'' . От друга страна тази инструкция може да бъде написана като addl (%ebx),%eax на ''синтаксиса на AT&T'', който се използва от GNU Assembler. Въпреки различния външен вид, различните синтактични форми общо взето генерират същия цифров машинен код, както ще видим по-долу. Определен асемблер може да има различни режими, за да може да поддържа разновидности от синтактични форми, както и техните точни семантични преводи (каквито са FASM-синтаксисът, TASM-синтаксисът и т.н.т., в конкретния случай програмирането на x86 асемблер).

Брой на преходите[редактиране | редактиране на кода]

Съществуват два вида асемблери, според това колко прехода през сорс кода са необходими, за да се произведе изпълнимата програма.

  • Еднопреходните асемблери преминават само веднъж през сорс кода. Всеки символ, който е използван преди да бъде дефиниран, бива локализиран и в края на обектния код (или не по-рано от мястото, където символът бива дефиниран) се подава инструкция да бъде записана стойност в плейсхолдъра, който е оставен на мястото, където все още недефинирания символ е бил използван.
  • Многопреходните асемблери създават таблица с всички символи и техните стойности при първия преход, след което използват таблицата в следващите преходи за генериране на код.

И в двата случая, асемблерът трябва да е способен да определи големината на всяка инструкция при първия преход, за да изчисли местоположението на следващите символи.

Първоначалното основание за използване на еднопреходните асемблери е била бързината на асемблиране – често повторния преход би изисквал пренавиване и повторно четене на лентата или повторно преглеждане на тесте карти. С модерните компютри това престана да бъде проблем, което дава предимство на многопреходните асемблери.

Асемблери от високо ниво[редактиране | редактиране на кода]

По-усъвършенстваните асемблери от високо ниво осигуряват програмни езикови абстракции като:

Асемблерен език[редактиране | редактиране на кода]

Написаната на асемблер програма се състои от серии от (мнемонични) процесорни инструкции и мета изрази (познати още като директиви или псевдо инструкции), коментари и данни. Инструкциите на асемблерния език обикновено се състоят от мнемоничен код следван от списък от данни, аргументи или параметри. Тези инструкции се преобразуват от асемблер до инструкции на машинен език, които могат да бъдат прехвърлени в паметта и изпълнени.

Например инструкцията по-долу казва на един x86/IA-32 процесор да прехвърли една пряка 8-битова стойност (01100001) в регистър (временна клетка от паметта, която се намира в ядрото на процесора). Бинарният код на тази инструкция е 10110 последван от 3-битов идентификатор за регистъра, който да се използва. Идентификаторът за регистър AL е 000, така че следния машинен код прехвърля в регистър AL стойността 01100001:[4] 10110000 01100001

Този бинарен компютърен код може да бъде направен по-лесно четим, ако бъде представен в шестнадесетичен формат както следва:

B0 61

Тук B0 означава 'Прехвърли копие на следната стойност в регистър AL', а 61 е шестнадесетичното представяне на стойността 01100001, която в десетичен формат е числото 97. Асемблерният език за процесори от фамилия 8086 въвежда мнемоничния код MOV (абревиатура на move – местя) за инструкции като тази, така че машинният код по-горе може да бъде записан по следния начин на асемблерен език, допълнен от обяснителен коментар след точка и запетая, ако се изисква такъв. Това е много по-лесно за прочитане и запаметяване:

MOV AL, 61h ; Зарежда регистъра  AL с десетично 97 (шестнадесетично 61)

В някои асемблерни езици същият мнемоничен код като MOV може да бъде използван за фамилия от близки инструкции за зареждане, копиране и прехвърляне на данни, независимо дали стойностите са преки (кодирани в самата инструкция), стойности в регистри или места в паметта, към които сочат стойности в регистри. Други асемблери може да използват отделни операционни мнемонични кодове, като например L за „прехвърли памет в регистър“, ST за „прехвърли регистър в памет“, LR за „прехвърли регистър в регистър“, MVI за „прехвърли пряк операнд в памет“ и т.н.т.

При x86 асемблерите операционният код 10110000 (B0) копира една 8-битова стойност в регистъра AL, докато 10110001 (B1) я прехвърля в регистъра CL, а 10110010 (B2) я прехвърля в регистъра DL. Примери от езика асемблер са дадени по-долу:[5]

MOV AL, 1h ; Зарежда регистъра  AL с пряка стойност  1
MOV CL, 2h ; Зарежда регистъра  CL с пряка стойност  2
MOV DL, 3h ; Зарежда регистъра  DL с пряка стойност  3

Синтаксисът на MOV може също да бъде по-комплексен, както показват следните примери:[5]

MOV EAX, [EBX]; 4 байта от паметта на адреса, съдържащ се в EBX прехвърли в EAX
MOV [ESI+EAX], CL ; Прехвърли  съдържанието на CL в байта на адрес ESI+EAX

При всички случаи, мнемоничният код MOV се преобразува директно в операционен код в интервалите 88-8E, A0-A3, B0-B8, C6 или C7 от един асемблер и не е нужно програмистът да ги знае или запомня.[4]

Преобразуването на асемблерен език в машинен код се извършва от асемблер, а обратният процес на деасемблиране (преобразуването на команди от машинен език в асемблерни инструкции) поне частично може да бъде постигнато с дизасемблер. За разлика от програмните езици от високо ниво при асемблерните езици обикновено има пълно съответствие между езиковия израз и процесорните инструкции. Понякога даден асемблер може да притежава псевдоинструкции (основно макроси), които обхващат няколко процесорни инструкции, за да осигурят желаната функционалност. Например за процесор, при който липсва инструкцията „ако е по-голямо или равно“, един асемблер може да предостави псевдоинструкция, която се разширява до процесорните инструкции „ако не е по-малко“ и „ако е равно“. Повечето напълно оборудвани асемблери осигуряват богат макро език, който се използва от производителите и програмистите за генериране на по-комплексен код и последователности от данни.

Всяка компютърна архитектура притежава свой собствен машинен език. Компютрите се различават по броя и типа на операциите, които поддържат, по различния размер и брой на регистрите и представянето на съхраняваните данни. Докато повечето компютри с обща употреба са способни да изпълняват по същество еднаква функционалност, начините, по които правят това се различават. Съответстващите асемблерни езици отразяват тези разлики.

Множество групи от мнемонични кодове или асемблерни езикови синтаксиси може да съществуват за определена група инструкции, типично използвани в различни асемблерни програми. В тези случаи, обикновено най-разпространеният от тях се доставя от производителя и се използва в неговата документация.

Дизайн на езика[редактиране | редактиране на кода]

Основни елементи[редактиране | редактиране на кода]

Съществува голяма степен от различия в начина, по които авторите на асемблери категоризират инструкциите и номенклатурата, която използват. В частност, някои не описват нищо повече от машинни мнемонични кодове или разширени мнемонични кодове като псевдо операции. Един типичен асемблерен език се състои от три типа инструкции, които се използват за дефиниране на програмните операции:

  • Операционни мнемонични кодове
  • Дефиниции на данни
  • Асемблерни директиви

Операционни мнемонични кодове и разширени мнемонични кодове[редактиране | редактиране на кода]

Инструкциите в асемблерния език в повечето случаи са доста опростени, за разлика от същите в езиците от високо ниво. Обикновено мнемоничният код представлява символно наименование на една изпълнима на машинен език инструкция (операционен код) и съществува поне по един операционен мнемоничен код, дефиниран за всяка инструкция на машинен език. Всяка инструкция обикновено се състои от операция или операционен код плюс нула или повече операнди. Повечето инструкции се отнасят към единична стойност или двойка стойности. Операндите могат да бъдат преки (със стойност, кодирана в самата инструкция), регистрово определени в инструкцията или съдържащи се в нея, или могат да бъдат адреси на данни, които се съхраняват някъде другаде. Това се определя от скритата процесорна архитектура. Асемблерът просто отразява как тази архитектура работи. Разширените мнемонични кодове често се използват, за да определят комбинации от операционни кодове и специфични операнди. Например System/360 асемблерите използват В като разширен мнемоничен код за BC с маска 15 и NOP („NO OPeration“ – не прави нищо една стъпка) за BC с маска 0.

Разширените мнемонични кодове често се използват, за да поддържат специализирани употреби на инструкции, често за цели, които не са разбираеми от името на инструкцията. Например, много процесори не притежават експлицитна NOP инструкция, но имат инструкции, които могат да се използват за целта. В 8086 процесорите инструкцията xchg ax,ax е била използвана вместо NOP, след като NOP е бил псевдо операционен код за декодиране на инструкцията xchg ax,ax. Някои дизасемблери разпознават това и биха декодирали xchg ax,ax инструкцията като nop. По подобен начин IBM асемблерите за System/360 и System/370 използват разширените мнемонични кодове NOP и NOPR за BC и BCR с маски 0. За SPARC архитектурата, тези кодове са познати като синтетични инструкции.[6]

Освен това някои асемблери поддържат несложни вградени макро инструкции, които генерират две или повече машинни инструкции. Например, при някои Z80 асемблери инструкцията ld hl,bc е прието да генерира ld l,c последвана от ld h,b.[7] Тези са познати още като псевдооперационни кодове.

Мнемоничните кодове са произволни символи. IEEE публикува Standard 694 през 1985 г. на постоянен набор от мнемонични кодове, които да се използват от всички асемблери. Впоследствие този стандарт е бил отменен.

Директиви за данни[редактиране | редактиране на кода]

Съществуват инструкции, които се използват, за да определят елементи на данни да съдържат данни и променливи. Те определят типа от данни, дължината и подреждането на тези данни. Тези инструкции могат също да определят дали тези данни да са на разположение на външни програми (програми, които са асемблирани отделно) или да са на разположение само на програмата, в която сегментът от данни е дефиниран. Някои асемблери класифицират тези инструкции като псевдооперации.

Асемблерни директиви[редактиране | редактиране на кода]

Асемблерните директиви, наричани още псевдооперационни кодове или псевдооперации, представляват инструкции, които се изпълняват от асемблера по време на асемблиране, а не от процесора по време на действие. Имената на псевдооперациите често започват с точка, за да бъдат разграничавани от машинните инструкции. Псевдо-операциите могат да направят асемблирането на програмата зависимо от параметрите, които се въвеждат от програмиста, така че една програма може да бъде асемблирана по различни начини, евентуално за различни приложения. Или пък, псевдооперациите могат да бъдат използвани, за да се промени представянето на дадена програма, за да бъде направена тя по лесна за четене и поддръжка. Друго обичайно приложение на псевдооперациите е да запазват място за съхранение на работните данни и като опция – да инициализират тяхното съдържание с известни стойности.

Символните асемблери позволяват на програмистите да обединяват произволни имена (етикети или символи) с места в паметта и различни константи. В един изпълним код, името на всяка подпрограма се свързва с нейната входна точка, така че всяко извикване на една подпрограма може да използва нейното име. Вътре в подпрограмите, на GOTO командите се дават етикети. Някои асемблери поддържат локални символи, които са лексикално различни от нормалните символи (например, използването на „10$“ като GOTO команда).

Някои асемблери като NASM осигуряват гъвкаво боравене със символите, позволявайки на програмистите да си служат с различни неймспейси, да изчисляват автоматично отместванията в структури от данни, и да поставят етикети, отнасящи се до буквени стойности или резултата от несложни изчисления, извършвани от асемблера. Етикетите също може да бъдат използвани за инициализиране на константи и променливи с преместваеми адреси.

Асемблерните езици, както повечето компютърни езици, позволяват да бъдат добавени коментари към програмния сорс код, които по време на асемблирането биват игнорирани. Разумното коментиране е съществено при програмите на асемблерен език, тъй като значението и целта на поредицата от бинарни машинни инструкции трудно могат да бъдат определени. „Суровият“ (не коментиран) асемблерен език, генериран от компилаторите или дизасемблерите, е доста труден за четене, когато трябва да се правят промени по него.

Макроси[редактиране | редактиране на кода]

Много асемблери поддържат предефинирани макроси, а други поддържат макроси, които се дефинират от програмиста (поддаващи се на повторно дефиниране), включващи поредици от текстови редове, в които променливите и константите са запечатани. Тази поредица от текстови редове може да включва операционни кодове или директиви. Веднъж щом макросът е бил дефиниран, неговото име би могло да се използва на мястото на мнемоничен код. Когато асемблерът обработва такава инструкция, той замества инструкцията с текстовите редове, свързани с този макрос, след което ги обработва както, ако бяха съществували във файла на сорс кода. Макроси от такъв вид е имало в програмите за автоматично кодиране на IBM още през 50-те години на миналия век.

Тази дефиниция за „макрос“ малко се различава от употребата на този термин в други контексти. Например макроси в програмният език C, създадени чрез #директивата за дефиниране, обикновено са само на един ред, или най-много на няколко реда. Асемблерните макро инструкции може да са с дължината на програма, която се изпълнява при преобразуване от асемблера по време на асемблирането.

При положение, че макросите могат да имат кратки имена, но да се разширяват до няколко или всъщност множество редове код, те могат да направят програмите на асемблерен език да изглеждат доста по-къси, изискващи по-малко редове сорс код, както е при езиците от високо ниво. Освен това те могат да бъдат използвани, за да се добавят структури от по-високо ниво към асемблерните програми, като опция да въвеждат запечатан код за дебъгване посредством параметри и други подобни свойства.

Макро асемблерите често позволяват макросите да приемат параметри. Някои асемблери включват доста усъвършенствани макро езици, като съчетават такива елементи на езиците от високо ниво, като незадължителни параметри, символни променливи, условности, обработка на символни низове и аритметични операции, които се използват при изпълнение на даден макрос и позволяващи на макроса да запазва конкретна или променяща се информация. По този начин един макрос може да генерира множество инструкции на асемблерен език или дефиниции на данни въз основа на параметрите на макросите.

Поддържане на структурно програмиране[редактиране | редактиране на кода]

Някои асемблери имат включени елементи на структурно програмиране за декодиране на потока на изпълнение. Най-ранният пример за такава разработка е бил в набора от макроси Concept-14, първоначално разработен от д-р H.D. Mills (Март 1970) и осъществен на практика от Marvin Kessler (IBM Federal Systems Division), който разширил макрос асемблера S/360 с IF/ELSE/ENDIF и подобни блокове за контрол на потока.[6] Това е бил начин за намаляване или елиминиране на употребата на GOTO операциите в асемблерния код – една от основните причини за образуване на спагети код в асемблерния език. Тази разработка е намерила широко приложение в началото на 80-те години на миналия век (последните времена на широко използване на асемблерния език). 

Любопитна е постройката на A-natural – ориентиран към потока асемблер за процесорите 8080/Z80 от Whitesmiths Ltd. (разработчиците на подобната на Unix операционна система Idris и на обявения като първи комерсиален С компилатор). Езикът бе класифициран като асемблер, защото работеше със сурови машинни елементи като операционни кодове, регистри и референции към паметта, но включваше и изразителен синтаксис, за да показва реда на изпълнение. Кръгли скоби и други специални символи, заедно с понятия на блоково ориентираното структурно програмиране, контролират последователността на генерираните инструкции. A-natural бе създаден по-скоро като обектен език за C компилатор, отколкото за набиране на код на ръка, но неговия логически синтаксис му спечели доста фенове. 

Съществувало е известно търсене на по-усъвършенствани асемблери преди залеза на широката употреба на асемблерния език. Въпреки това, те все още се разработват и прилагат в случаи на ограничени ресурси или специфики на системната архитектура, които възпрепятстват ефективното използване на езици от високо ниво.

Използване на асемблерния език[редактиране | редактиране на кода]

История[редактиране | редактиране на кода]

Асемблерният език датира от въвеждането на програмируемия компютър. Компютъра EDSAC в Кеймбридж (1949) е имал асемблер наречен първоначални заповеди (initial orders).[7] Натаниел Рочестър написал асемблера на IBM 701. SOAP (Оптимално Символно Сглобяваща Програма – Symbolic Optimal Assembly Program) (1955) асемблера е бил написан от Стан Полей за IBM 650.[8]

Асемблерните езици елиминират много от склонните към грешки и време отнемащи нужди в първото поколение програмни езици при ранните компютри, освобождавайки програмистите от скучни неща като помнене на цифрови кодове и пресмятане на адреси. Някога те са били широко използвани за всички видове програмиране. Въпреки това, през 80-те (90-те в микрокомпютрите), тяхната употреба е до голяма степен изместена от използване на езици от по-високо ниво, в търсене на подобрена производителност в програмирането. В днешни дни асемблерният език все още се използва за директна манипулация на хардуера, достъп до специализиране процесорни инструкции или до критични проблеми с производителността. Типичната употреба са драйвери за устройствата, вградени системи, както и системи в реално време.

Исторически погледнато, множество програми са написани на асемблерни езици. Операционните системи са били изцяло написани на асемблерен език до въвеждането на Главната Контролна Програма на Burroughs Corporation (Burroughs MCP) (1961), която е била написана на Executive Systems Problem Oriented Language (ESPOL), диалект на ALGOL. Също и много комерсиални приложения са били написани на асемблерни езици, включително голямо количество от софтуера за компютри c архитектура от вида IBM System/360, 370, 390, zSeries написан от големи компании. COBOL, FORTRAIN и някои PL/I, в крайна сметка те биват изместени, въпреки че редица големи организации, задържат голяма част от инфраструктурата на приложенията си на асемблер и през 90-те.

Повечето от ранните микрокомпютри разчитат на ръчно кодирания асемблерен език, включително и повечето операционни системи и големи приложения. Това е така, защото тези системи са имали сериозни ограничения с ресурсите, наложена характерна архитектура на паметта и дисплея, и предоставяли ограничени, и неработещи правилно системни услуги. Може би по-важна, е била липсата на първокласни компилатори от високо ниво, подходящи за използване в микрокомпютър. Може би роля е изиграл и психологическия фактор: първото поколение от микрокомпютърни програмисти са били с любителската нагласа „тел и клечи“.

В по-търговски контекст, най-големите причини за използване на асемблерен език са били минималното нарастване на размера, по-високата скорост и надеждността.

Типични примери за големи програми на асемблер от това време са IBM PC DOS операционна система и ранните приложения като програмата за електронни таблици Lotos 1-2-3. Дори през 90-те години, повечето конзолни видео игри са написани на асемблер, включително повечето игри за Mega Drive/Genesis и Super Nintendo Entertainment System. Според някои хора запознати с производството, асемблер е бил най-подходящия компютърен език за извличане на най-доброто представяне от Sega Saturn, конзола за която е пословично трудно да се разработи игра.[9] Аркадната игра NBA Jam (1993) е друг пример.

Асемблер е бил дълго време основен език за разработка за много популярни домашни компютри от 80-те и 90-те (като Sinclair ZX Spectrum, Commodore 64, Commodore Amiga и Atari ST). Това до голяма степен се дължи на интерпретаторите ОСНОВНИ диалекти на тези системи, предлагащи недостатъчна скорост на изпълнение, както и недостатъчни инструменти за да се възползват напълно от наличния хардуер за тези системи. Някои системи дори имат интегрирана среда за разработка (IDE) с много напреднало отстраняване на грешки (debugging) и макро инструменти.

Асемблер за VIC-20 е бил написан от Дон Фенч и публикуван от French Silk. В 1 639 байта дължина, неговият автор смята, че то е най-малкото символно асембли, писано някога. Асемблер поддържа стандартното символно адресиране и дефиницията на символен низ или шестнайсетичен низ. Той също позволява адресни изключения, които могат да бъдат комбинирани със събиране, изваждане, умножение, деление, логическо И, логическо ИЛИ и експоненти оператори.[10]

Употреба в днешно време[редактиране | редактиране на кода]

Винаги е имало дебати за полезността и ефективността на асемблер в сравнение с езици от по-високо ниво. Асемблер има приложение в специфична ниша, където е важно (виж по-долу). Асемблер може да се използва, за оптимизиране на скоростта или за оптимизиране на размер. В случай на оптимизация на скоростта, модерни оптимизиращи компилатори са направени[11], за да преработват езици с високо ниво в код, който може да работи толкова бързо, колкото като написан на ръка, въпреки контра-примери, които могат да бъдат намерени.[12][13][14] Сложността на съвременните процесори и подсистеми на паметта прави ефективната оптимизация все по-трудна за компилаторите, както и за програмисти на асемблер.[15][16] Освен това, увеличаването на производителността на процесора означава, че повечето процесори бездействат голямата част от времето,[17] със забавяне, причинено от предвидими ботълнек места като липса на кеш, I/O операции и виртуална памет. Това прави скоростта на изпълнение на кода безпроблемна за много програмисти.

Има някои ситуации, в които разработчиците могат да изберат да използват асемблер:

  • Самостоятелно изпълняващ се и с компактен размер код е необходимо да се изпълни, без да се прибягва до допълнителни компоненти за стартиране или библиотеки, свързани с езици на високо ниво; това е може би най-често срещаната ситуация. Например, фърмуер за телефони, разход на гориво на колите и стартиращи системи, системи за контрол на климатични, системи за сигурност, както и сензори.
  • Код, който трябва да си взаимодейства директно с хардуера, например в драйверите на устройствата и прекъсващите рутинни услуги.
  • Програми, които имат нужда да използват процесорни специфични инструкции, не изпълнявани в компилатор. Типичен пример е ротацията на инструкция в основата на много алгоритми за криптиране.
  • Програми, които създават векторни функции за езици от по-високо ниво, като например C. При езиците от по-високо ниво това понякога е подпомогнато от компилаторно присъщи функции, които директно картографират на SIMD мнемоника, но въпреки това резултата е едно-към-едно асембли преобразование за специфичния векторен процесор.
  • Програми, изискващи изключителна оптимизация, например вътрешна линия в процесорно-интензивен алгоритъм. Програмисти на игри се възползват от възможностите на хардуерните характеристики на системи, позволяващи игрите да работят по-бързо. Също големи научни симулации изискват силно оптимизирани алгоритми, например линейна алгебра с BLAS[12][18] или дискретна косинусова трансформация (например SIMD сглобяване версия от x264.[19]
  • Ситуации, в които не съществува език на високо ниво, при нов или специализиран процесор, например.
  • Програми, които се нуждаят от точен график като:
    • Програми в реално време, като примерно симулации на полет, навигационни системи и медицинско оборудване. Например, в една система за автопилот, телеметрията трябва да се интерпретира и да се предприемат действия в строги времеви ограничения. Тези системи трябва да елиминират източници на непредвидими закъснения, които могат да бъдат създадени от (някои) интерпретиращи езици, garbage collector, пейджинг операции, или превантивен мултитаскинг. Въпреки това, някои езици от по-високо ниво включват компоненти при стартиране и интерфейс на операционна система, които могат да въведат такива закъснения. Изборът на асемблер или езици от по-ниско ниво за такива системи дава на програмистите по-голяма видимост и контрол върху обработката на детайли.
    • Криптографски алгоритми, които винаги трябва да вземат стриктно същото време за да се изпълнят, предотвратява времеви атаки.
  • Ситуации, при които се изисква пълен контрол върху околната среда, в ситуации изискващи изключително висока сигурност, където нищо не може да се приема за даденост.
  • Компютърни вируси, bootloaders, някои драйвери на устройства, или други ситуации, които са много близо до хардуера или операционна система на ниско ниво.
  • Симулатори на набор от инструкции за наблюдение, проследяване и отстраняване на грешки, където допълнителното натоварване се свежда до минимум,
  • Обратно инженерство и промяна на програмни файлове, като например
    • Съществуващите бинарни файлове, без значение първоначално на какъв език са написани, например, когато се опитва да пресъздаде програми, за които изходния код не е в наличност или е бил загубен, или кракване на защитата на софтуера.
    • Видеоигри (наричано още ROM хакване), което е възможно чрез няколко метода. Най-широко използван е промяна на програмния код на ниво асемблер.
    • Само-модифициращ се код, към който асемблер се поддава.
    • Игри и друг софтуер – графични калкулатори.[20]

Асемблер все още се преподава в повечето компютърни науки и в програмата на електронните инженери. Въпреки че все по-малко програмисти днес редовно работят с асемблер като инструмент, базисните концепции остават много важни. Такива основни теми като двоична аритметика, заделяне на памет, обработка на стака, кодиране на набор от символи, прекъсване на обработка и дизайн на компилатора ще бъдат трудни да се изучават в детайли, без възможността за разбиране на това как един компютър работи на хардуерно ниво. Тъй като поведението на компютъра е фундаментално определен от неговия набор инструкции, логичният път за да се научат тези понятия е да се учи на асемблер. Повечето съвременни компютри имат подобни комплекти с инструкции. Затова изучаването на езика асемблер е достатъчно, за да научи:

  1. Основните понятия;
  2. Да се определи правилните ситуации, в които използването на асемблер може да е подходящо;
  3. За да видите колко ефективен може да бъде код създаден на езици от високо ниво.[21] Това е аналогично на деца, които трябва да научат основните аритметични операции (например делене на големи числа), въпреки че калкулаторите са широко използвани за всичко, с изключение на най-незначителните изчисления.

Типични приложения[редактиране | редактиране на кода]

  • Типично приложение на асемблер е стартиращия код на системата (system’s boot code), кода на ниско ниво, инициализиращ и тестващ системния хардуер преди зареждане на операционната система и често се съхранява в ROM паметта.(BIOS в IBM съвместимите PC системи и CP/M например.)
  • Някои компилатори превеждат езиците от високо ниво до асемблер преди да ги сглобят напълно, позволявайки отстраняване на грешките (debugging) и оптимизиране на асемблерния код.
  • Езиците от сравнително ниско ниво, като C, позволяват на програмиста да вгради асемблер директно в изходния код. Програми, които използват такива инструменти, като например Линукс ядрото, впоследствие това позволява да се създадат абстракции използвайки различен асемблерен език за всяка хардуерна платформа. Тогава системния преносим код може да използва тези специфични процесорни компоненти чрез единен интерфейс.
  • Асемблерния език е полезен и при обратното инженерство. Много програми се разпространяват само в машинен код, от който е лесно да се превърне в асемблерен код, но по-трудно е да се преведе на език от високо ниво. Инструменти като Interactive Disassembler правят широко използването на декомпилирането за такива цели.
  • Асеблерните езици могат да бъдат използвани за генериране на блокове от данни, без излишъците на език от високо ниво, от форматиран и коментиран изходящ код, да бъдат използвани от друг код.

Свързана терминология[редактиране | редактиране на кода]

  • Асемблерния език обичайно е наричан асембли, асемблер, ASM, или символен машинен код. Поколението на IBM mainframe програмисти го наричат ALC или Асембли езиков код (Assembly Language Code) или BAL[22] Наричането на езика асемблер може да се счита за потенциално двусмислено и объркващо, тъй като това е името на програмата, която превежда асемблерния език на машинен код. Въпреки това, тази употреба е била често срещана сред специалисти и в литературата в продължение на десетилетия.[23] По същия начин, някои ранни компютри наричали техния асемблер тяхна асембли програма.[24]
  • Изчислителната стъпка, когато асемблера работи, включително цялата макро обработка, се нарича време за асемблиране. На асемблера се казва да асемблира изходящия код.
  • Използването на думата асембли датира от ранните години на компютрите.
  • Кръстосан асемблер (виж също и кръстосано компилиране) е асемблер, който работи на компютър или операционна система от различен тип от този, на който изходящия код трябва да работи (целева система). Кръстосаното асемблиране е необходимо, ако целевата система не може да стартира асемблер сама, какъвто обикновено е случаят с малките вградени системи. Компютърът, на който се провежда кръстосаното асемблиране трябва да има някои средства за прехвърляне (транспортиране) на получения машинен код на целевата система. Честите методи включват прехвърляне на байт-по-байт на машинния код или на ASCII представен машинен код в преносим формат (като Motorola SREC или Intel hexadecimal) чрез съвместим интерфейс към целевата система за изпълнение.
  • Асемблерна директива или псевдо операционен код (pseudo-opcode) е команда давана на асемблер „насочвайки я да извърши операции, различни от асемблерните инструкции.“ The assembler also calculates constant expressions and resolves symbolic names for memory locations and other entities.[2] Директивите влияят на това как асемблер работи и „може да влияе на обектния код, символната таблица (symbol table), регистрационния файл (listing fail), и на стойностите на вътрешните асемблерни параметри.“ Понякога терминът псевдо операционен код е запазен за директивите, които създават обектен код, като например тези, които генерират данни.[25]
  • Мета-асемблер (meta-assembler) е „програма, която приема синтактично и семантично описание на асемблерния език, и създава асемблер за този език.“[26]

Списък на асемблерите за различните компютърни архитектури[редактиране | редактиране на кода]

Основното заглавие: Списък на асемблерите

Допълнителни подробности[редактиране | редактиране на кода]

За всеки даден персонален компютър, мейнфрейм компютър, вградена система и игрова конзола, както в миналото така и в настоящето, има поне една дузина подходящи асемблера, които са били написани. За няколко примера виж списъка с асемблери.

На Unix системите, асемблер обичайно се нарича As, въпреки че не е едно тяло от код, обикновено се пишат на ново за всеки порт. Много от Unix вариантите използват GAS.

В рамките на процесорните групи, всеки асемблер има собствен диалект. Понякога, някои асемблери могат да четат други асемблерни диалекти, например, TASM може да чете стария MASM код, но не и обратното. FASM и NASM имат подобен синтаксис, но всеки поддържа различни макроси това ги прави трудно преводими един към друг. Основите са едни и същи, но разширените функции се различават.[27]

Също така, понякога асемблито може да бъде преносимо между различните операционни системи на един и същ тип CPU. Извикването на конвенциите между операционните системи, често се различават малко или въобще не се различават, и е възможно с малка промяна да се постигне преносимост на асемблерния език, обикновено чрез свързване с C библиотека, която не се променя между операционните системи. Симулатор на набор от инструкции може да обработва обектния код/двоично от някой асемблер за да постигне преносимост дори между различните платформи с излишък не по-голям от типичен bytecode преводач. Това е подобно на използването на микрокод за постигане на съвместимост в една фамилия процесори.

Някой програмни езици от високо ниво, като C или Borland Pascal, поддържат вградено асембли като има секции от асемблерен код, обикновено на практика съкратено, може да се вгради в кода на езиците от високо ниво. Езикът Forth често съдържа асемблер използван в CODE думи.

Емулатор може да бъде използван за отстраняване на грешките в асемблерна програма.

Примерен списък на асемблерен програмен код[редактиране | редактиране на кода]

Следното е частичен списък генериран от NASM, на асемблер за 32-битови процесори Intel x86. Кодът е за подпрограма, не за завършена програма.

100 ;-----------------------------------------------------------
101                      ; zstr_count:
102                      ; Броя на zero-terminated ASCII символни низове за определяне на техния размер
103                      ; in:   eax = начален адрес на zero terminated string
104                      ; out:  ecx = брой = дължина на символния низ
105 
106                      zstr_count:                   ; Начало
107 00000030 B9FFFFFFFF mov ecx, -1 ; Инициализиране на брояча, предекремент
108                                                    ;  за да компенсира инкремента
109                      .loop:
110 00000035 41 inc ecx ; Добавяне на 1 към брояча
111 00000036 803C0800 cmp byte [eax + ecx], 0 ; Сравняване на стойността на символните низове
112                                                    ;  [начален адрес в паметта Плюс
113                                                    ;  отместването на цикъла], от нула
114 0000003A 75F9 jne .loop ; Ако стойността на паметта не е нулаI,
115                                                    ;  тогава прескача до етикет '.loop',
116                                                    ;  в противен слушай продължава към следващия ред
117                      .done:
118                                                    ; Не извършваме последно увеличаване на стойността (инкрементация),
119                                                    ;  въпреки че броят е с основа 1,
120                                                    ;  не сме включили нулевия terminator в
121                                                    ;  дължината на символния низ
122 0000003C C3 ret ; Връщане в извикващата програма

Първата колана (отляво) е просто номера на реда в списъка и не носи друг смисъл. Втората колона е относителния адрес, в шестнайсетичен код, къде кода ще бъде поставен в паметта. Третата колона е действителния компилаторен код. За инстанцията, B9 e x86 операционен код за MOV ECX инструкция; FFFFFFFF е стойност -1 в допълнена с два символа двоична форма.

Наставката на имената с двоеточие (:) са символни етикети; етикетите не създават код, те са просто начин да се каже на асемблера, че тези места са символни имена. Етикета .done присъства само за яснота къде приключва програмата, тя няма друга цел. Представката точка (.) върху етикет е функция на асемблер, за деклариране на етикета като локален за подпрограмата.

Вижте също[редактиране | редактиране на кода]

Използвана литература[редактиране | редактиране на кода]

  1. Whether these bitgroups are orthogonal, or to what extent they are, depends on the CPU and instruction set design at hand.
  2. а б David Salomon (1993). Assemblers and Loaders
  3. Hyde, Randall. „Chapter 12 – Classes and Objects“. The Art of Assembly Language, 2nd Edition. No Starch Press. © 2010.
  4. а б Intel Architecture Software Developer's Manual, Volume 2: Instruction Set Reference. Intel Corporation, 1999. с. 442 and 35. Посетен на 18 November 2010.
  5. Evans, David. x86 Assembly Guide. // University of Virginia, 2006. Посетен на 18 November 2010.
  6. Concept 14 Macros. // MVS Software. Посетен на May 25, 2009.
  7. Assemblers and Loaders. с. 7. Посетен на 2012-01-17.
  8. The IBM 650 Magnetic Drum Calculator. // Посетен на 2012-01-17.
  9. Eidolon's Inn: SegaBase Saturn
  10. Jim Lawless. Speaking with Don French: The Man Behind the French Silk Assembler Tools. // 2004-05-21. Архив на оригинала от 21 August 2008. Посетен на 2008-07-25.
  11. Rusling, David A.. The Linux Kernel. // Посетен на Mar 11, 2012.
  12. а б Writing the Fastest Code, by Hand, for Fun: A Human Computer Keeps Speeding Up Chips. // New York Times, John Markoff, 2005-11-28. Посетен на 2010-03-04.
  13. Bit-field-badness. // hardwarebug.org, 2010-01-30. Архив на оригинала от 5 February 2010. Посетен на 2010-03-04.
  14. GCC makes a mess. // HardwareBug.org, 2009-05-13. Архив на оригинала от 16 March 2010. Посетен на 2010-03-04.
  15. Randall Hyde. The Great Debate. // Архив на оригинала от 16 June 2008. Посетен на 2008-07-03.
  16. Code sourcery fails again. // hardwarebug.org, 2010-01-30. Архив на оригинала от 2 April 2010. Посетен на 2010-03-04.
  17. Click, Cliff. A Crash Course in Modern Hardware. // Посетен на May 1, 2014.
  18. BLAS Benchmark-August2008. // eigen.tuxfamily.org, 2008-08-01. Посетен на 2010-03-04.
  19. x264.git/common/x86/dct-32.asm. // git.videolan.org, 2010-09-29. Посетен на 2010-09-29.
  20. 68K Programming in Fargo II. // Архив на оригинала от 2 July 2008. Посетен на 2008-07-03.
  21. Hyde, Randall. Foreword („Why would anyone learn this stuff?“), op. cit.. // 1996-09-30. Архив на оригинала от 25 March 2010. Посетен на 2010-03-05.
  22. Technically BAL was only the assembler for BPS; the others were macro assemblers.
  23. Stroustrup, Bjarne. The C++ Programming Language. Addison-Wesley, 1986. ISBN 0-201-12078-X. C++ was primarily designed so that the author and his friends would not have to program in assembler, C, or various modern high-level languages. [use of the term assembler to mean assembly language]
  24. Programming the IBM 1401. // Prentice-Hall, 1962.
  25. Microsoft Corporation. MASM: Directives & Pseudo-Opcodes. // Посетен на March 19, 2011.
  26. (John Daintith, ed.) A Dictionary of Computing: „meta-assembler“
  27. Randall Hyde. Which Assembler is the Best?. // Архив на оригинала от 18 October 2007. Посетен на 2007-10-19.
Криейтив Комънс - Признание - Споделяне на споделеното Лиценз за свободна документация на ГНУ Тази страница частично или изцяло представлява превод на страницата „Assembly language“ в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс - Признание - Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година — от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница. Вижте източниците на оригиналната статия, състоянието ѝ при превода, и списъка на съавторите.