Nízkoúrovňový programovací jazyk - Low-level programming language

Nižší programovací jazyk je programovací jazyk , který poskytuje malou nebo žádnou abstrakci z počítače v instrukční sady architektury -commands nebo funkce v jazyka mapy, které jsou strukturálně podobné instrukce procesoru. Obecně se to týká buď strojového kódu, nebo montážního jazyka . Kvůli nízké (odtud slovo) abstrakci mezi jazykem a strojovým jazykem jsou jazyky nízké úrovně někdy popisovány jako „blízké hardwaru“. Programy napsané v jazycích nízké úrovně bývají relativně nepřenosné , protože jsou optimalizovány pro určitý typ systémové architektury.

Nízkoúrovňové jazyky lze převést na strojový kód bez kompilátoru nebo tlumočníka -programovací jazyky druhé generace používají jednodušší procesor nazývaný assembler -a výsledný kód běží přímo na procesoru. Program napsaný v nízkoúrovňovém jazyce lze spustit velmi rychle a s malou paměťovou stopou . Ekvivalentní program v jazyce na vysoké úrovni může být méně účinný a využívat více paměti. Nízkoúrovňové jazyky jsou jednoduché, ale vzhledem k četným technickým detailům, které si programátor musí pamatovat, se považují za obtížně použitelné. Pro srovnání, programovací jazyk na vysoké úrovni izoluje sémantiku provádění počítačové architektury od specifikace programu, což zjednodušuje vývoj.

Strojový kód

Přední panel minipočítače PDP-8/E. Řadu přepínačů ve spodní části lze použít k přepínání v programu strojového jazyka.

Strojový kód je jediný jazyk, který může počítač zpracovávat přímo bez předchozí transformace. V současné době programátoři téměř nikdy nepíší programy přímo ve strojovém kódu, protože to vyžaduje pozornost mnoha detailům, které jazyk na vysoké úrovni zpracovává automaticky. Kromě toho vyžaduje zapamatování nebo vyhledání číselných kódů pro každou instrukci a je velmi obtížné jej upravit.

Skutečný strojový kód je proud nezpracovaných, obvykle binárních , dat. Programátor kódující „strojový kód“ normálně kóduje pokyny a data v čitelnější podobě, jako je desítková , osmičková nebo šestnáctková, která je do interního formátu přeložena programem nazývaným zavaděč nebo přepnut do paměti počítače z předního panelu .

Přestože je ve strojovém jazyce napsáno jen málo programů, programátoři se často stanou zběhlými ve čtení pomocí práce s jádrovými skládkami nebo laděním z předního panelu.

Příklad: Funkce v hexadecimální reprezentaci 32bitové x 86 strojového kódu pro výpočet n th Fibonacci číslo :

8B542408 83FA0077 06B80000 0000C383
FA027706 B8010000 00C353BB 01000000
B9010000 008D0419 83FA0376 078BD989
C14AEBF1 5BC3

Jazyk montáže

Jazyky druhé generace poskytují jednu úroveň abstrakce nad strojovým kódem. V počátcích kódování na počítačích jako TX-0 a PDP-1 byla první věcí, kterou hackeři MIT udělali, napsání assemblerů. Jazyk sestavení má malou sémantiku nebo formální specifikaci, protože je pouze mapováním symbolů čitelných pro člověka, včetně symbolických adres, na operační kódy , adresy , číselné konstanty, řetězce atd. Jedna strojová instrukce je obvykle reprezentována jako jeden řádek kódu sestavy. Assemblery produkují soubory objektů, které lze propojit s jinými soubory objektů nebo je lze načíst samostatně.

Většina assemblerů poskytuje makra ke generování běžných sekvencí pokynů.

Příklad: Stejná kalkulačka Fibonacciho čísel jako výše, ale v jazyce sestavení x86-64 pomocí syntaxe 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

V tomto příkladu kódu jsou hardwarové funkce procesoru x86-64 (jeho registry ) pojmenovány a manipulovány přímo. Funkce načte svůj vstup z %edi podle System V ABI a provede svůj výpočet manipulací s hodnotami v registrech EAX , EBX a ECX, dokud nedokončí a nevrátí se. Všimněte si, že v tomto jazyce sestavení neexistuje koncept vrácení hodnoty. Výsledek, který byl uložen do registru EAX , příkaz RET jednoduše přesune zpracování kódu do umístění kódu uloženého v zásobníku (obvykle instrukce bezprostředně za tím, který volal tuto funkci) a je na autorovi volacího kódu, aby vědět, že tato funkce ukládá svůj výsledek do EAX a získává jej odtud. Jazyk sestavení x86-64 neukládá žádný standard pro vrácení hodnot z funkce (a ve skutečnosti tedy nemá žádnou funkci); je na volajícím kódu, aby zkontroloval stav po návratu procedury, pokud potřebuje extrahovat hodnotu.

Porovnejte to se stejnou funkcí v 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;
       }
   }
}

Tento kód je svou strukturou velmi podobný příkladu sestavovacího jazyka, ale pokud jde o abstrakci, existují značné rozdíly:

  • Vstup (parametr n ) je abstrakcí, která neurčuje žádné umístění úložiště na hardwaru. V praxi kompilátor C dodržuje jednu z mnoha možných konvencí volání a určuje umístění úložiště pro vstup.
  • Jazyková verze sestavení načte vstupní parametr ze zásobníku do registru a v každé iteraci smyčky sníží hodnotu v registru, přičemž nikdy nezmění hodnotu v umístění paměti v zásobníku. Kompilátor C by mohl načíst parametr do registru a provést totéž nebo by mohl aktualizovat hodnotu kdekoli je uložen. Který z nich zvolí, je rozhodnutí o implementaci zcela skryté před autorem kódu (a to bez vedlejších účinků , díky standardům jazyka C).
  • Místní proměnné a, b a c jsou abstrakce, které neurčují žádné konkrétní umístění úložiště na hardwaru. Kompilátor C rozhodne, jak je ve skutečnosti uložit pro cílovou architekturu.
  • Funkce vrácení určuje hodnotu, která se má vrátit, ale nediktuje, jak je vrácena. Kompilátor C pro jakoukoli konkrétní architekturu implementuje standardní mechanismus pro vrácení hodnoty. Kompilátory pro architekturu x86 obvykle (ale ne vždy) používají k vrácení hodnoty registr EAX, jako v příkladu jazyka sestavení (autor příkladu jazyka sestavení se rozhodl zkopírovat konvenci C, ale jazyk sestavení to nevyžaduje).

Tyto abstrakce umožňují kompilaci kódu C bez úprav na jakékoli architektuře, pro kterou byl kompilátor C napsán. Kód jazyka sestavení x86 je specifický pro architekturu x86.

Programování na nízké úrovni v jazycích na vysoké úrovni

Koncem 60. let 20. století jazyky vyšší úrovně , jako PL/S , BLISS , BCPL , rozšířený ALGOL (pro velké systémy Burroughs ) a C, zahrnovaly určitý stupeň přístupu k programovacím funkcím nízké úrovně. Jednou z metod je Inline assembly , ve které je kód sestavení vložen do jazyka na vysoké úrovni, který tuto funkci podporuje. Některé z těchto jazyků také umožňují směrnicím optimalizace kompilátoru závislých na architektuře upravit způsob, jakým kompilátor používá cílovou architekturu procesoru.

Reference