Assemblersprog

Assemblersprog (eller assembler-kode, assembly-kode) er i praksis en symbolsk måde at udtrykke maskinkode på, eventuelt kombineret med et simpelt makrosystem. Oversættelsen fra assemblersprog til maskinkode varetages af en assembler. Da maskinkoden og dermed assemblersproget afhænger af CPU'en, taler man eksempelvis om x86-assembler, PowerPC-assembler, etc. Assemblersprogets muligheder er også afhængigt af, hvilket styresystem, der bruges. Man taler også tit om forskellige dialekter af assemblersprog, tit defineret af den benyttede assembler. Der findes flere forskellige assembler som eksempelvis FASM, TASM, MASM, og GAS mm.

Assemblersprog benævnes som et 2. niveau programmeringssprog, altså et lav-niveau sprog som ikke direkte understøtter abstrakte syntaks-konstruktioner som eksempelvis IF/ELSE- og SWITCH-forgreninger, FOR- og WHILE/DOWHILE-løkker og ikke mindst variabler, som alle er understøttet af syntaksen i langt de fleste høj-niveau sprog, som eksempelvis C, C++ og Java. Man kan sige at dette niveau beskriver et sprogs abstraktion-niveau. Et sprogs abstraktions-niveau betegner hvor langt væk syntaksen i et programmeringsprog gør det muligt for programmøren at abstrahere væk fra den underliggende hardware-nære logik. Jo mere dette er muligt, jo mere abstrakt er sproget og jo højere niveau kan et programmeringssprog siges at have. Assemblersprog har en lav abstraktion og maskinkode kan siges at have en endnu lavere abstraktion.

Den primære fordel ved assemblersproget er, at man kan lave hardware-nære optimeringer, der ikke er mulige i langt de fleste høj-niveau sprog. Ulempen er at det kan synes besværligt at skrive i, grundet sprogets lave abstraktions-niveau. En assembler-programmør skal have en dybdegående teknisk forståelse for hvordan den benyttede CPU fungerer internt, samt hvordan problemet der forsøges løst, bedst kan udtrykkes som små bider af meget specifik logik. Assemblersprogets opbygning vil for det meste have den effekt at den skrevne kode vil fylde betydelig mere i antal linjer, end kode med samme funktionalitet, skrevet i eksempelvis C, C++ eller Pascal. Typisk skrives de fleste applikationers kode i et høj-niveau sprog, og hvis det derefter er nødvendigt, kan kritiske dele omskrives i assemblersprog.

Assemblersproget er i dag ikke så meget anvendt på PC, men anvendes stadig i mikrocontrollere. Men da computerne var ganske små, brugte man det, da man ikke forventede at portere det til andre processorarkitekturer. Når det stadig bruges, er det fordi det giver direkte adgang til hardware-chipsene. Man er ikke bundet til et højere sprogs compiler eller fortolker, men til systemets hardware-arkitektur og dermed CPU’en og chipsene. I undervisningsøjemed og selvlæring giver assemblerprogrammering et godt indblik i, hvordan et computersystem virker.

To slags instruktioner 
Assemblersproget kan siges at omfatte mindst to primære typer af instruktioner. Den ene type er CPU-specifikke instruktioner og hver enkelt af disse kan typisk oversættes direkte til en underliggende maskinkode-instruktion. Den anden type er pseudo-instruktioner som er specifikke til den benyttede assembler. Man kan blandt andet bruge pseudo-instruktioner til at definere visse konstruktioner fra høj-niveau sprog (såsom IF/ELSE-forgreninger), og på denne måde genbruge kode skrevet tidligere.

Eksempler 
Her ses nogle korte eksempler på hvordan kode skrevet i assemblersprog typisk ser ud. Disse eksempler er ikke specifikke til nogen assembler eller CPU. Nærmere forklaring følger hvert eksempel.

Eksempel 1 
Først et eksempel på flytning af data:
MOV X, Y
Dette er et generelt eksempel på benyttelsen af assembler-instruktionen MOV (kommer fra det engelske ord MOVE som betyder FLYT) som har den effekt at flytte (typisk en kopiering) hvad der eksisterer i X over i Y, eller omvendt: hvad eksisterer i Y over i X. Her kaldes MOV for assembler-instruktionens navn (kaldes også for en mnemonic) og beskriver unikt den fundamentale funktionalitet i instruktionen. I eksemplet bruges de to abstrakte navne X og Y. Disse kan typisk være enten navne på CPU'ens interne registre (se forneden), eller specifikke hukommelses-adresser. Udover dette, kunne den ene af de to, X eller Y, være en skalar-værdi. Dette er dog specifikt til den benyttede assembler.

Eksempel 2 
Et eksempel på addition af data:
ADD X, Y
Eksemplet viser brugen af instruktionen ADD med to parametre: X og Y. Her lagres resultatet af X + Y i enten X eller Y. Igen kan X og Y være enten navne på interne registre (begge), hukommelses-adresser (begge), eller en skalar-værdi (en enkelt).

Eksempel 3 
Et tredje eksempel viser en kombination af assembler-instruktioner:
MOV 10, X
MOV 20, Y
ADD X, Y
ADD X, Y
I dette generelle eksempel bruges MOV i første linje til, at flytte (kopiere) skalar-værdien 10 over i X. I anden linje flyttes 20 over i Y. Her kan X og Y betragtes som værende navne på interne CPU-registre, altså som små interne hukommelses-celler i den benyttede CPU (se mere om registre forneden). I linje 3 gemmes resultatet X + Y = 10 + 20 = 30 i enten register X eller Y. Gemmes resultatet i X, vil register X og Y, efter linje 3, indeholde henholdsvis værdierne 30 og 20. I linje 4 sker der det samme som i linje 3, dog vil resultatet være anderledes da register X nu indeholder værdien 30 og ikke 10 som tidligere. Dette betyder at register X og Y vil, efter linje 4, indeholde henholdsvis værdierne 50 og 20.

Segment og registrene 

Registrene: i de fleste computere, (de har pt.2006 typisk 32-36 bit adressebus) er der registrene eax, ebx, ecx og edx. Deres bitfunktioner kan deles op i mindre dele,
eax kan deles op i ax, som så kan deles op i ah og al. sådan gælder det alle registrene.
Ebx kan deles op i bx og derefter op i bh og bl. Bogstavet "h" betyder high, og i denne sammenhæng er det i CPU'en. hvorimod bogstav "L" betyder low. Når man fx siger AX, så er det kun 16 bit (2 bytes), og EAX 32 bit(4 bytes), men man kan IKKE dele EAX op i en "høj" og "lav" del, kun en lav del(AX). Der er også 64 bit register, men de anvendes ikke ret meget, da det ikke er ret meget udbredt, og mange compilere ikke bruger det. Eax bliver således til Rax, som ligesom EAX kun kan deles op i en lav del, hvor at man ikke kan tilgå den "højere" del alene.

Segment: segment er noget der ligner et register, men den kan ikke gøre de samme ting. Segmenterne bruges til at holde informationer i.
De tilgængelige segment-registre er:
CS (Code Segment), DS (Data Segment), SS (Stack Segment), samt ES, FS og GS (Ekstra Segmentregistre)
Disse registre bruges når man skal tilgå hukommelsen i 16 bit tilstand ( som betegnes "real mode"), hvilket betyder at vi har med en hukommelsesmodel at gøre, som lyder således: ( kaldes også "indirekte hukommelsesadressering")

 segment:offset
 
Dette bruges ikke rigtigt med mindre man programmerer et styresystem, eller programmerer til dos. Windows arbejder i 32 bit, hvor at hukommelsesmodellen ser meget mere simple ud: ( kaldes også "direkte hukommelsesadressering")

 selector:offset
 
her er segement registrene "selectore", hvilket betyder at de "vælger" en placering i en tabel. ( den hedder GDT [global descriptor table] , og bruges ikke under normale omstændigheder, da det styres af Windows.)

Hvis man endelig bruger 16 bit, så skal der en mindre forklaring til:
i 16 bit kan man MAKS tilgå 1 MB, hvis man vil tilgå mere, skal man over i noget helt andet, indenfor 16 bit.
men helt normalt, så virker segment sammen med offset.
hvis vi nu siger at vi har en adresse der er på 20000 Hex lineær ( altså blot offset(i denne sammenhæng er det mere end 16 bit), men stadig under 1 MB, så hvordan får vi tilgang, når at offset maks kan være "FFFF" Hex, svaret er brugen af segment.
hvis vi nu stadig tager udgangspunkt i 20000 Hex lineær, så mangler vi blot at vide, hvordan vi regner segment:offset ud til lineær:

 linær = segment*16 + offset

Dette er meget simpelt, så for at tilgå 20000 Hex, så skal segment fx være 2000 hex, og offset 0000 hex.

Hvis det er 32 bit, så kan vi tilgå helt op til 4 GB, så hvis vi har mere, skal vi ind i 64 bit, som er helt anderledes fra 32 og 16.

Nogle Instruktioner 

Asm-instruktioner:
Den vigtigste er MOV-instruktionen, Dens syntaks er:
MOV register, tal/register/segment
Med MOV-instruktionen kan du gøre næsten alt, men det tager meget tid. Så man skal være glad for at CPUer i dag understøtter mange flere kommandoer.
En anden vigtig instruktionstype, er de matematiske, som består af: inc = læg til(+) dec = at trække fra(-) mul = gange(*) og til sidst div = dividere(:)
syntaksen for disse instruktioner er:
(eks) inc register/tal/segment. 
En anden vigtig instruktion er INT, INT betyder interrupt, som på dansk betyder afbrydelse. Den skal forstået som en handle, men som bruges af systemet, (en handle er faktisk det samme som en INT, bare hvor den ikke er defineret) en god liste over INT-instruktionens effekt (i real-mode) er her.

En anden type instruktion, der er god at kunne, er CMP = compare, som oversat betyder, at sammenligne.
Den syntaks er CMP register, register/tal
(et eks.) CMP AX,CX
Derefter er der mange ting man kan gøre, eks jne, som betyder jump if not equal, "hop hvis ?? ikke er lig" man kan også bruge dens modsætning, nemlig je=hop hvis lig
syntaksen for disse "hop" er jne/ placering den skal hoppe til.
Med disse kommandoer kan man lave mange sjove programmer. Du kan lave ét, der kigger om du taster enter eller mellemrum.

Men der er stadig en formue af andre instruktioner, men det kræver at man har erfaring med de andre.

Kodninger
Programmeringssprog