Мова праграмавання нізкага ўзроўню
Нізкаўзроўневая мова праграмавання — гэта мова праграмавання, якая практычна не абстрагуецца ад архітэктуры набору інструкцый камп’ютара: каманды ці функцыі ў моўнай карце структурна падобныя з інструкцыямі працэсара. Звычайна гэта адносіцца альбо да машыннага кода, альбо да мовы асэмблера. З-за нізкай (адсюль і слова) абстракцыі паміж мовай і машыннай мовай мовы нізкага ўзроўню часам называюць «блізкімі да апаратуры». Праграмы, напісаныя на нізкаўзроўневых мовах, як правіла, адносна не партатыўныя, паколькі аптымізаваны пад пэўны тып сістэмнай архітэктуры[1].
Мовы нізкага ўзроўню могуць пераўтварацца ў машынны код без кампілятара ці інтэрпрэтатара — у мовах праграмавання другога пакалення выкарыстоўваецца прасцейшы працэсар, званы асэмблерам. У выніку код выконваецца непасрэдна на працэсары. Праграма, напісаная на мове нізкага ўзроўню, можа выконвацца вельмі хутка і займаць мала месца ў памяці. Аналагічная праграма на мове высокага ўзроўню можа быць менш эфектыўнай і займаць больш памяці. Мовы нізкага ўзроўню простыя, але лічацца складанымі ў выкарыстанні з прычыны вялікай колькасці тэхнічных дэталяў, якія праграміст павінен памятаць. Для параўнання, мова праграмавання высокага ўзроўня ізалюе семантыку выканання архітэктуры камп’ютара ад спецыфікацыі праграмы, што спрашчае распрацоўку[1].
Машынны код
[правіць | правіць зыходнік]Машынны код — гэта адзіная мова, якую камп’ютар можа апрацоўваць наўпрост, без папярэдняга пераўтварання. У цяперашні час праграмісты практычна ніколі не пішуць праграмы непасрэдна на машынным кодзе, паколькі гэта патрабуе ўвагі да шматлікіх дэталяў, якія мова высокага ўзроўню апрацоўвае аўтаматычна[1]. Акрамя таго, ён патрабуе запамінання ці пошуку лічбавых кодаў для кожнай інструкцыі і вельмі складаны для мадыфікацыі.
Сапраўдны машынны код уяўляе сабой паток неапрацаваных, як правіла, бінарных даных. Праграміст машыннага кода звычайна праграмуе інструкцыі і даныя ў больш чытэльнай форме, напрыклад у дзесятковай, васьмярковай ці шаснаццатковай сістэме, якія перакладаюцца ва ўнутраны фармат праграмай, званай загрузчыкам, ці ўводзяцца ў памяць камп’ютара з пярэдней панэлі[1].
Хоць толькі нешматлікія праграмы пішуцца на машыннай мове, праграмісты часта набываюць навык яго чытання, працуючы з дампамі ядра ці адладжваючы яго з пярэдней панэлі.
Прыклад функцыі ў шаснаццатковым уяўленні 32-разраднага машыннага кода x86 для вылічэння n-ай лічбы Фібаначы:
8B542408 83FA0077 06B80000 0000C383 FA027706 B8010000 00C353BB 01000000 B9010000 008D0419 83FA0376 078BD989 C14AEBF1 5BC3
Мова асэмблера
[правіць | правіць зыходнік]Мовы другога пакалення забяспечваюць адзін узровень абстракцыі па-над машынным кодам. На світанку кадавання на такіх камп’ютарах, як TX-0 і PDP-1, першае, што рабілі хакеры з Масачусецкага тэхналагічнага інстытута — гэта пісалі асэмблеры. Мова асэмблера мае мала семантыкі і фармальных спецыфікацый, з’яўляючыся адлюстраваннем чалавекачытальных сімвалаў, уключаючы сімвальныя адрасы, кады аперацый, адрасы, лічбавыя канстанты, радкі і г.д. Як правіла, адна машынная інструкцыя прадстаўлена адным радком асэмблернага кода. Асэмблеры ствараюць аб’ектныя файлы, якія могуць звязвацца з іншымі аб’ектнымі файламі ці загружацца самастойна.
Большасць асэмблераў прадстаўляюць макрасы для генерацыі агульных паслядоўнасцяў інструкцый.
Прыклад: Той жа калькулятар лічбы Фібаначы, што і вышэй, але на мове асэмблера x86-64 з выкарыстаннем сінтаксісу AT&T:
_fib:
movl $1, %eax
xorl %ebx, %ebx
.fib_loop:
cmpl $1, %edi
jbe .fib_done
movl %eax, %ecx
addl %ebx, %eax
movl %ecx, %ebx
subl $1, %edi
jmp .fib_loop
.fib_done:
ret
У гэтым прыкладзе кода рэгістры працэсара x86-64 названы і маніпулююцца непасрэдна. Функцыя загружае свае ўваходныя даныя з %edi ў адпаведнасці з System V ABI і выконвае разлік, маніпулюючы значэннямі ў рэгістрах EAX, EBX і ECX, пакуль не скончыцца і не вернецца. Звярніце ўвагу, што ў гэтай мове асэмблера няма канцэпцыі вяртання значэння. Калі вынік быў захаваны ў рэгістры EAX, каманда RET проста перамяшчае апрацоўку кода ў месца, якое захоўваецца ў стэку (звычайна інструкцыя адразу пасля той, якая выклікала гэту функцыю), і гэта залежыць ад аўтара кода выкліку. ведаць, што гэтая функцыя захоўвае свой вынік у EAX і можа атрымаць яго адтуль. Мова асэмблера x86-64 не навязвае стандарт для вяртання значэнняў з функцыі (і фактычна не мае паняцця функцыі); код выкліку павінен праверыць стан пасля вяртання працэдуры, калі яму трэба атрымаць значэнне.
Параўнайце з той жа функцыяй на Cі:
unsigned int fib(unsigned int n) {
if (!n)
return 0;
else if (n <= 2)
return 1;
else {
unsigned int a, c;
for (a = c = 1; ; --n) {
c += a;
if (n <= 2) return c;
a = c - a;
}
}
}
Нізкаўзроўневае праграмаванне ў мовах высокага ўзроўню
[правіць | правіць зыходнік]У канцы 1960-х гадоў мовы высокага ўзроўню, такія як PL/S, BLISS, BCPL, пашыраны ALGOL (для вялікіх сістэм Burroughs) і C, прадугледжвалі пэўную ступень доступу да функцый нізкаўзроўневага праграмавання. Адным з метадаў такога доступу з’яўляецца ўбудаваны асэмблер, пры якім асэмблерны код убудоўваецца ў мову высокага ўзроўню, які падтрымлівае гэтую магчымасць. Некаторыя з гэтых моў таксама дазваляюць выкарыстоўваць архітэктурна-залежныя дырэктывы аптымізацыі кампілятара, каб наладзіць кампілятар на выкарыстанне архітэктуры мэтавага працэсара.
Зноскі
- ↑ а б в г 3.1: Structure of low-level programs (англ.). Workforce LibreTexts (5 сакавіка 2021). Праверана 3 красавіка 2023.