Assemblagetaal

Een assembleertaal is een programmeertaal die gebruikt kan worden om de computer direct te vertellen wat hij moet doen. Een assembleertaal is bijna precies zoals de machinecode die een computer kan begrijpen, behalve dat hij woorden gebruikt in plaats van getallen. Een computer kan een assemblageprogramma niet echt direct begrijpen. Hij kan echter gemakkelijk het programma in machinecode veranderen door de woorden van het programma te vervangen door de getallen waar ze voor staan. Een programma dat dat doet wordt een assembler genoemd.

Programma's die in assembleertaal zijn geschreven zijn meestal gemaakt van instructies, wat kleine taken zijn die de computer uitvoert als hij het programma uitvoert. Ze worden instructies genoemd omdat de programmeur ze gebruikt om de computer te instrueren wat hij moet doen. Het deel van de computer dat de instructies volgt is de processor.

De assembleertaal van een computer is een laagdrempelige taal, wat betekent dat deze alleen kan worden gebruikt om de eenvoudige taken uit te voeren die een computer direct kan begrijpen. Om complexere taken uit te voeren, moet men de computer elk van de eenvoudige taken vertellen die deel uitmaken van de complexe taak. Een computer begrijpt bijvoorbeeld niet hoe hij een zin op zijn scherm moet afdrukken. In plaats daarvan moet een programma dat in de assemblage is geschreven, hem vertellen hoe hij alle kleine stappen moet uitvoeren die bij het afdrukken van de zin komen kijken.

Zo'n montageprogramma zou bestaan uit vele, vele instructies, die samen iets doen wat voor een mens heel eenvoudig en basaal lijkt. Dit maakt het moeilijk voor de mens om een montageprogramma te lezen. Een programmeertaal op hoog niveau kan daarentegen een enkele instructie hebben, zoals PRINT "Hallo, wereld!", die de computer vertelt om alle kleine taken voor u uit te voeren.

Ontwikkeling van de assembleertaal

Toen computerwetenschappers voor het eerst programmeerbare machines bouwden, programmeerden ze deze direct in machinecode, wat een reeks getallen is die de computer instrueerde wat hij moest doen. Het schrijven van machinetaal was erg moeilijk en duurde lang, dus uiteindelijk werd er assemblagetaal gemaakt. Assemblagetaal is makkelijker te lezen voor een mens en kan sneller worden geschreven, maar het is nog steeds veel moeilijker voor een mens om te gebruiken dan een programmeertaal op hoog niveau die probeert de menselijke taal na te bootsen.

Programmering in machinecode

Om te programmeren in machine code, moet de programmeur weten hoe elke instructie er in binair (of hexadecimaal) uit ziet. Hoewel het voor een computer gemakkelijk is om snel uit te vinden wat machinecode betekent, is het voor een programmeur moeilijk. Elke instructie kan verschillende vormen hebben, die er voor mensen gewoon allemaal uitzien als een stelletje getallen. Elke fout die iemand maakt tijdens het schrijven van machine code zal alleen worden opgemerkt wanneer de computer de verkeerde dingen doet. Het uitzoeken van de fout is moeilijk omdat de meeste mensen niet kunnen zien wat machinecode betekent door er naar te kijken. Een voorbeeld van hoe de machinecode eruit ziet:

05 2A 00

Deze hexadecimale machinecode vertelt een x86-computerprocessor om 42 toe te voegen aan de accumulator. Het is erg moeilijk voor een persoon om het te lezen en te begrijpen, zelfs als die persoon de machinecode kent.

Gebruik van assemblagetaal in plaats daarvan

Met assembleertaal kan elke instructie worden geschreven als een kort woord, een mnemotechnisch woord genaamd, gevolgd door andere zaken zoals nummers of andere korte woorden. De mnemotechniek wordt gebruikt zodat de programmeur niet de exacte getallen in de machinecode hoeft te onthouden die nodig zijn om de computer te vertellen dat hij iets moet doen. Voorbeelden van mnemonica in assembleertaal zijn add, die gegevens toevoegt, en mov, die gegevens van de ene plaats naar de andere verplaatst. Omdat 'mnemonic' een ongewoon woord is, wordt soms het woord instructietype of gewoon instructie gebruikt, vaak ten onrechte. De woorden en cijfers na het eerste woord geven meer informatie over wat te doen. Bijvoorbeeld, dingen na een optelling kunnen wat twee dingen zijn om op te tellen en de dingen na een beweging zeggen wat er moet worden verplaatst en waar het moet worden geplaatst.

Zo kan bijvoorbeeld de machinecode in de vorige paragraaf (05 2A 00) in de assemblage worden geschreven als:

 Bijl toevoegen,42

De assembleertaal stelt programmeurs ook in staat om de eigenlijke gegevens die het programma gebruikt op een eenvoudigere manier te schrijven. De meeste assembleertalen hebben ondersteuning voor het eenvoudig maken van getallen en tekst. In de machinecode zou elk type getal, zoals positief, negatief of decimaal, handmatig moeten worden omgezet in binair en tekst zou één letter per keer moeten worden gedefinieerd, als getallen.

De assembleertaal zorgt voor wat men noemt een abstractie van de machinecode. Bij het gebruik van assemblage hoeven programmeurs niet te weten wat de details van de getallen voor de computer betekenen, de assembler figureert dat in plaats daarvan. De assembleertaal laat de programmeur eigenlijk nog steeds alle mogelijkheden van de processor gebruiken die hij met machinecode zou kunnen hebben. In die zin heeft assembleertaal een zeer goede, zeldzame eigenschap: het heeft dezelfde mogelijkheid om dingen uit te drukken als het ding dat het abstracteert (machinecode), terwijl het veel gemakkelijker te gebruiken is. Hierdoor wordt machinecode bijna nooit gebruikt als programmeertaal.

Demontage en debugging

Als programma's klaar zijn, zijn ze al omgezet in machinecode, zodat de processor ze daadwerkelijk kan uitvoeren. Soms echter, als het programma een bug (fout) in zich heeft, zullen programmeurs willen weten wat elk onderdeel van de machinecode doet. Disassemblers zijn programma's die programmeurs helpen dat te doen door de machinecode van het programma weer om te zetten in assemblagetaal, wat veel makkelijker te begrijpen is. Disassemblers, die de machinecode omzetten in assemblagetaal, doen het tegenovergestelde van assemblers, die de assemblagetaal omzetten in machinecode.

Computer Organisatie

Een begrip van hoe computers zijn georganiseerd, hoe ze lijken te werken op een zeer laag niveau, is nodig om te begrijpen hoe een assembleertaalprogramma werkt. Op het meest simplistische niveau hebben computers drie hoofdonderdelen:

  1. hoofdgeheugen of RAM dat gegevens en instructies bevat,
  2. een verwerker, die de gegevens verwerkt door de instructies uit te voeren, en
  3. invoer en uitvoer (soms ingekort tot I/O), waardoor de computer met de buitenwereld kan communiceren en gegevens buiten het hoofdgeheugen kan opslaan, zodat hij de gegevens later weer terug kan krijgen.

Hoofdgeheugen

In de meeste computers is het geheugen opgedeeld in bytes. Elke byte bevat 8 bits. Elke byte in het geheugen heeft ook een adres dat een getal is dat aangeeft waar de byte zich in het geheugen bevindt. De eerste byte in het geheugen heeft een adres van 0, de volgende heeft een adres van 1, enzovoort. Door het geheugen op te delen in bytes wordt het byte-adres mogelijk, omdat elk byte een uniek adres krijgt. Adressen van byte-geheugens kunnen niet worden gebruikt om te verwijzen naar een enkel bit van een byte. Een byte is het kleinste stukje geheugen dat kan worden aangesproken.

Hoewel een adres verwijst naar een bepaalde byte in het geheugen, maken processoren het mogelijk om meerdere bytes geheugen achter elkaar te gebruiken. Het meest voorkomende gebruik van deze functie is het gebruik van 2 of 4 bytes op een rij om een getal, meestal een geheel getal, weer te geven. Enkele bytes worden soms ook gebruikt om gehele getallen weer te geven, maar omdat ze slechts 8 bits lang zijn, kunnen ze slechts 28 of 256 verschillende mogelijke waarden bevatten. Het gebruik van 2 of 4 bytes op een rij verhoogt het aantal verschillende mogelijke waarden tot respectievelijk 216, 65536 of 232, 4294967296.

Wanneer een programma een byte of een aantal bytes op een rij gebruikt om iets als een letter, nummer of iets anders weer te geven, worden die bytes een object genoemd omdat ze allemaal deel uitmaken van hetzelfde ding. Hoewel objecten allemaal in identieke bytes van het geheugen zijn opgeslagen, worden ze behandeld alsof ze een 'type' hebben, dat zegt hoe de bytes moeten worden begrepen: als een geheel getal of een teken of een ander type (zoals een niet-gehele waarde). De machinecode kan ook worden beschouwd als een type dat wordt geïnterpreteerd als een instructie. Het begrip 'type' is zeer, zeer belangrijk omdat het definieert wat er wel en niet met het object gedaan kan worden en hoe de bytes van het object geïnterpreteerd moeten worden. Het is bijvoorbeeld niet geldig om een negatief getal in een positief getal object op te slaan en het is niet geldig om een breuk in een geheel getal op te slaan.

Een adres dat wijst naar (is het adres van) een multi-byte object is het adres van de eerste byte van dat object - de byte die het laagste adres heeft. Terzijde, een belangrijk punt om op te merken is dat je aan het adres van een object niet kunt zien wat het type object is - of zelfs niet de grootte ervan. In feite kun je niet eens zeggen wat voor type een object is door er naar te kijken. Een assembleertaalprogramma moet bijhouden welke geheugenadressen welke objecten bevatten, en hoe groot die objecten zijn. Een programma dat dat doet is type veilig omdat het alleen dingen doet met objecten die veilig zijn om op hun type te doen. Een programma dat dat niet doet zal waarschijnlijk niet goed werken. Merk op dat de meeste programma's eigenlijk niet expliciet opslaan wat het type van een object is, ze benaderen gewoon consequent objecten - hetzelfde object wordt altijd als hetzelfde type behandeld.

De Verwerker

De processor draait (voert) instructies uit, die als machinecode in het hoofdgeheugen worden opgeslagen. De meeste processoren hebben niet alleen toegang tot het geheugen voor opslag, maar hebben ook een paar kleine, snelle, vaste ruimtes voor het vasthouden van objecten waarmee op dit moment wordt gewerkt. Deze ruimtes worden registers genoemd. Processoren voeren meestal drie soorten instructies uit, hoewel sommige instructies een combinatie van deze soorten kunnen zijn. Hieronder staan enkele voorbeelden van elk type in x86 assembleertaal.

Instructies die het geheugen lezen of schrijven

De volgende x86 assemblagetaalinstructie leest (laadt) een 2-byte object uit de byte op adres 4096 (0x1000 in hexadecimaal) in een 16-bits register met de naam 'ax':

        mov ax, [1000h]

In deze assembleertaal betekenen vierkante haakjes rond een nummer (of een registratienaam) dat het nummer moet worden gebruikt als adres voor de gegevens die moeten worden gebruikt. Het gebruik van een adres om naar gegevens te verwijzen wordt indirectie genoemd. In dit volgende voorbeeld, zonder de vierkante haken, krijgt een ander register, bx, in feite de waarde 20 geladen.

        mov bx, 20

Omdat er geen gebruik werd gemaakt van indirectie, werd de werkelijke waarde zelf in het register opgenomen.

Als de operanden (de dingen die na de mnemotechniek komen), verschijnen in omgekeerde volgorde, een instructie die iets uit het geheugen laadt in plaats daarvan schrijft het in het geheugen:

        mov [1000h], ax

Hier krijgt het geheugen op adres 1000h de waarde van de as. Als dit voorbeeld direct na de vorige wordt uitgevoerd, zullen de 2 bytes bij 1000h en 1001h een 2 byte geheel getal zijn met de waarde 20.

Instructies die wiskundige of logische bewerkingen uitvoeren

Sommige instructies doen dingen zoals aftrekken of logische bewerkingen zoals niet:

Het voorbeeld van de machinecode eerder in dit artikel is deze in assembleertaal:

        bijl toevoegen, 42

Hier worden 42 en as bij elkaar opgeteld en wordt het resultaat weer in de as opgeslagen. In x86 assemblage is het ook mogelijk om een geheugentoegang en een wiskundige bewerking als deze te combineren:

        bijl toevoegen, [1000h]

Deze instructie voegt de waarde van de 2 byte integer opgeslagen op 1000h aan de as toe en slaat het antwoord op in de as.

        of bijl, bx

Deze instructie berekent de of van de inhoud van de registers bijl en bx en slaat het resultaat weer op in de bijl.

Instructies die beslissen wat de volgende instructie zal zijn

Meestal worden instructies uitgevoerd in de volgorde waarin ze in het geheugen verschijnen, dat is de volgorde waarin ze in de montagecode worden getypt. De processor voert ze gewoon achter elkaar uit. Echter, om processoren gecompliceerde dingen te laten doen, moeten ze verschillende instructies uitvoeren op basis van de gegevens die ze hebben gekregen. Het vermogen van processoren om verschillende instructies uit te voeren, afhankelijk van de uitkomst van iets, wordt vertakking genoemd. Instructies die bepalen wat de volgende instructie moet zijn, worden vertakkingsinstructies genoemd.

Stel dat iemand in dit voorbeeld de hoeveelheid verf wil berekenen die hij nodig heeft om een vierkant met een bepaalde zijlengte te schilderen. Echter, als gevolg van de schaalvergroting zal de verfwinkel ze niet minder verkopen dan de hoeveelheid verf die nodig is om een vierkant van 100 x 100 te schilderen.

Om de hoeveelheid verf die ze nodig hebben te krijgen op basis van de lengte van het vierkant dat ze willen schilderen, komen ze met deze set van stappen:

  • Trek 100 af van de lengte van de zijkant
  • als het antwoord minder dan nul is, stel dan de zijlengte in op 100
  • de zijlengte zelf te vermenigvuldigen

Dat algoritme kan worden uitgedrukt in de volgende code waarbij de as de zijlengte is.

        mov bx, bijl   sub bx, 100    jge gaan verder        mov ax, 100 verder:         mull-as

Dit voorbeeld introduceert een aantal nieuwe dingen, maar de eerste twee instructies zijn bekend. Ze kopiëren de waarde van de bijl in bx en trekken dan 100 af van bx.

Een van de nieuwe dingen in dit voorbeeld wordt een label genoemd, een concept dat in assemblagetalen in het algemeen wordt aangetroffen. Labels kunnen alles zijn wat de programmeur wil (tenzij het de naam van een instructie is, wat de monteur in verwarring zou brengen). In dit voorbeeld is het label 'doorgaan'. Het wordt door de assembler geïnterpreteerd als het adres van een instructie. In dit geval is het het adres van de multas.

Een ander nieuw concept is dat van de vlaggen. Op x86-processoren zetten veel instructies 'vlaggen' in de processor die bij de volgende instructie kunnen worden gebruikt om te beslissen wat er moet gebeuren. In dit geval, als bx minder dan 100 was, zal sub een vlag instellen die zegt dat het resultaat minder dan nul was.

De volgende instructie is jge die kort is voor 'Springen als groter dan of gelijk aan'. Het is een vertakkingsinstructie. Als de vlaggen in de processor aangeven dat het resultaat groter dan of gelijk aan nul was, in plaats van alleen naar de volgende instructie te gaan, zal de processor naar de instructie op het vervolglabel springen, dat is mul ax.

Dit voorbeeld werkt prima, maar het is niet wat de meeste programmeurs zouden schrijven. De aftrek-instructie stelt de vlag correct in, maar het verandert ook de waarde waarop het werkt, waardoor de as naar bx gekopieerd moest worden. De meeste assembleertalen staan vergelijkingsinstructies toe die geen van de argumenten die ze passeren veranderen, maar toch de vlaggen goed instellen en x86assemblage is geen uitzondering.

        cmp-as, 100    jge gaan verder        mov ax, 100 verder:    mull-as

Nu, in plaats van 100 af te trekken van de as, om te zien of dat getal minder dan nul is, en het weer toe te wijzen aan de as, wordt de as ongewijzigd gelaten. De vlaggen zijn nog steeds op dezelfde manier ingesteld, en de sprong wordt nog steeds in dezelfde situaties genomen.

In- en uitvoer

Hoewel input en output een fundamenteel onderdeel zijn van de informatica, is er geen enkele manier waarop ze in assembleertaal worden uitgevoerd. Dit komt omdat de manier waarop I/O werkt afhankelijk is van de opzet van de computer en het besturingssysteem, en niet alleen van het soort processor dat hij heeft. In het voorbeeldgedeelte gebruikt het Hello World-voorbeeld MS-DOS-besturingssysteem-aanroepen en het voorbeeld na het gebruik van BIOS-aanroepen.

Het is mogelijk om I/O in assemblagetaal te doen. Inderdaad, assemblagetaal kan over het algemeen alles uitdrukken wat een computer kan doen. Echter, hoewel er instructies zijn om toe te voegen en te vertakken in assembleertaal die altijd hetzelfde zullen doen, zijn er geen instructies in assembleertaal die altijd I/O doen.

Het belangrijkste om op te merken is dat de manier waarop I/O werkt geen deel uitmaakt van een assemblagetaal, omdat het geen deel uitmaakt van de manier waarop de processor werkt.

Assemblagetaal en draagbaarheid

Ook al wordt de assembleertaal niet direct door de processor uitgevoerd - machinecode wel, het heeft er toch veel mee te maken. Elke processorfamilie ondersteunt verschillende functies, instructies, regels voor wat de instructies kunnen doen, en regels voor welke combinatie van instructies waar zijn toegestaan. Daarom hebben verschillende soorten processoren nog steeds verschillende montagetalen nodig.

Omdat elke versie van de assemblagetaal gebonden is aan een processorfamilie, ontbreekt het aan iets wat portabiliteit wordt genoemd. Iets dat draagbaar is of draagbaar is, kan gemakkelijk van het ene type computer naar het andere worden overgebracht. Terwijl andere soorten programmeertalen draagbaar zijn, is assemblagetaal dat in het algemeen niet.

Assemblagetaal en talen op hoog niveau

Hoewel de assembleertaal een eenvoudige manier biedt om alle functies van de processor te gebruiken, wordt deze om verschillende redenen niet gebruikt voor moderne softwareprojecten:

  • Het kost veel moeite om een eenvoudig programma uit te drukken in de montage.
  • Hoewel niet zo foutgevoelig als de machinecode, biedt de assemblagetaal nog steeds zeer weinig bescherming tegen fouten. Bijna alle montagetalen dwingen geen typeveiligheid af.
  • Assemblagetaal bevordert geen goede programmeringspraktijken zoals modulariteit.
  • Hoewel elke individuele assemblagetaal instructie gemakkelijk te begrijpen is, is het moeilijk te zeggen wat de bedoeling was van de programmeur die het heeft geschreven. In feite is de assembleertaal van een programma zo moeilijk te begrijpen dat bedrijven zich geen zorgen maken over mensen die hun programma's (laten) assembleren.

Als gevolg van deze nadelen worden voor de meeste projecten talen van hoog niveau zoals Pascal, C en C++ gebruikt. Ze stellen programmeurs in staat om hun ideeën directer uit te drukken in plaats van zich zorgen te maken over het vertellen van de processor wat hij of zij moet doen. Ze worden high-level genoemd omdat de ideeën die de programmeur kan uitdrukken in dezelfde hoeveelheid code ingewikkelder zijn.

Programmeurs die code schrijven in gecompileerde talen op hoog niveau gebruiken een programma dat een compiler wordt genoemd om hun code om te zetten in assemblagetaal. Compilers zijn veel moeilijker te schrijven dan assemblers. Ook staan talen op hoog niveau niet altijd toe dat programmeurs alle functies van de processor gebruiken. Dit komt omdat high-level talen zijn ontworpen om alle processorfamilies te ondersteunen. In tegenstelling tot assembleertalen, die slechts één type processor ondersteunen, zijn high-level talen draagbaar.

Hoewel compilers gecompliceerder zijn dan assemblagebedrijven, zijn ze door tientallen jaren van maken en onderzoeken van compilers zeer goed geworden. Nu is er niet veel reden meer om assemblagetaal te gebruiken voor de meeste projecten, omdat compilers meestal ook in assemblagetaal kunnen uitdrukken of beter dan programmeurs.

Voorbeeldprogramma's

Een Hallo Wereld Programma geschreven in x86 Assembly:

adosseg .model small .stack 100h .data hello_message db 'Hello, World! ',0dh,0ah,'$' .code main proc mov ax,@data mov ds,ax mov ah,9 mov dx,offset hello_message int 21h mov ax,4C00h int 21h main end main

Een functie die een nummer afdrukt naar het scherm met behulp van BIOS interrupts geschreven in NASM x86 assemblage. Modulaire code is mogelijk om te schrijven in de assemblage, maar het kost extra moeite. Merk op dat alles wat na een puntkomma op een regel komt, een commentaar is en wordt genegeerd door de assembler. Het plaatsen van commentaar in assembly-taalcode is erg belangrijk omdat grote assembly-taalprogramma's zo moeilijk te begrijpen zijn.

; nietig printnummer (int. nummer, int. basis); printn:      druk op bp      verhuizing        bp, sp druk op bijl    druk op        bx      druk op cx      druk op dx      druk op      si      verhuizing     si, 0   verhuizing     bijl, [bp + 4] aantal verhuizing        cx, [bp + 6]   basis gloop:   inc     si             lengte van de snaar         verhuizing     dx, 0          nul dx div     cx             delen door de basis         cmp     dx, 10         Is het ge 10? jge     num     voeg  toe      dx, '0'         ; voeg nul toe aan dx jmp     anum num:      voeg  toe      dx, ('A'- 10)  ; hex-waarde, voeg 'A' toe aan dx - 10. anum:   druk op dx             ; zet dx op stapel.         cmp     bijl, 0        Moeten we doorgaan?    jne     gloop   verhuizing     bx, 7u             voor het onderbreken van de tloop:    pop     bijl           ; krijg de waarde ervan   verhuizing     ah, 0eh        voor het onderbreken   int     10h             schrijf karakter       dec     si             ; zich ontdoen van karakter    jnz        tloop  pop     si      pop     dx      pop     cx      pop     bx      pop     bijl         pop     bp      ret     4
AlegsaOnline.com - 2020 - License CC3