Inline assembler
Inline assembler är möjligheten att i ett programspråk på hög eller medelhög nivå, kunna infoga assemblerinstruktioner - mnemotekniska koder - direkt i källkoden. Man måste då dock ta hänsyn till den arkitektur (till exempel x86) programmet skall tillämpas på, då dessa instruktioner är processorspecifika, och alltså inte portabla.
Nedan visar hur man med inline assembler i C flyttar en konstant till låga 16-bitars ackumulatorregistret (al) 8-bitars, och sedan flyttar innehållet i detta register till minnesadressen där c finns (c som är 8 bitar skrivs över). Observera att man inte hade behövt utnyttja ah registret för detta enkla ändamål, exemplet är dock gjort för att visa syntaxen för direkt- och registeradressering.
Exempel i programspråket C (Intel syntax):
#include <stdio.h>
main()
{
char c=0;
__asm {
mov al, 65 /* Flytta värdet 65 till de lägre 8-bitarna på 16-bitars
dataregistret AX (ackumulatorn) */
mov c, al /* Eller [c] */
}
putchar(c);
getchar();
}
Om du har en annan datatyp (till exempel int) så måste du göra en typomvandling, till exempel:
main()
{
int c=65;
__asm {
mov al, byte ptr [c] /* Ta endast 8 bitar */
mov byte ptr [c], al /* Samma här */
}
putchar(c);
getchar();
}
Även ett exempel där videoavbrott 10h används för utmatning av ett tecken (TTY):
main()
{
char c=0;
/* Skriver ut ett versalt A på bildskärmen */
__asm {
mov ah, 0ah
mov al, 65 /* 65 är den decimala ASCII-koden för symbolen A */
mov bh, 0
int 10h
}
}
Syntaxen är kompilatorberoende, men i grunden finns två metoder. AT&T samt Intels syntax.
Notering:
En del kompilatorer vill att man refererar till variabeln c som _c (understreck före), och ibland [_c], detta tvistas det dock om. Enligt Intel skall man använda _c för att ladda in adressen till variabeln, och [_c] för att ladda in värdet. Vanligast är dock att man vid Intels syntax helt enkelt skriver till exempel mov 8var, 8reg. 8var står för 8-bitars variabel och 8reg står för 8-bitars register (till exempel låga ackumulatorregistret). Observera att variabeltyperna måste stämma överens, det går till exempel inte att flytta värden mellan register och variabler utan korrekt typ.
Exempel:
mov <typ> ptr [operand], operand
mov operand, <typ> ptr [operand]
Ibland måste man även deklarera den som static, då ett annourlunda minnesschema används.
Hur man använder inline assembler är kompilator- och språkberoende och man får vända sig till manualen för närmare beskrivning.
Det finns även andra sätt att mata ut tecken i ett konsolfönster (med rättigheter beroende på läge).
Se Real Mode, Unreal mode, Protected mode, Long mode och Virtual 8086 mode.
Man kan till exempel skriva direkt till videominnet med början på adress 0xb8000 (hexadecimalt). Jämn adress är tecken, udda är attribut:
main()
{
unsigned char *vidmem = (unsigned char *)0xb8000;
*vidmem = 'T'; /* Tecken */
*(vidmem++) = 0xF; /* Attribut - svart bakgrund, vit text */
}
Man kan även använda inline assembler för detta ändamål. Det skulle se ut ungefär så här:
main()
{
__asm {
mov bx, 0B800h /* 0:an behövs för tolkning som konstant
(annars tolkas B800h som variabel) */
mov es, bx /* Flyttar till segmentregister es
(tillhör adressregistren) via bx */
mov byte ptr es:0, 'T' /* Tecken */
mov byte ptr es:1, 1Fh /* Attribut */
}
/* OBSERVERA
En del kompilatorer vill ha syntaxen
mov byte [es:0], 'T' istället, eller
mov es:0, 'T'
*/
}
OBSERVERA!
Alla programexempel ovan kommer att generera felmeddelanden av typen "Access violation" eller "Privileged instruction" om du inte kör i rätt läge eller har tillräckliga rättigheter (se ovan).