Maskinkode: Hvad er maskinsprog, instruktionssæt og native kode

Lær alt om maskinkode: hvad maskinsprog, instruktionssæt og native kode betyder, hvordan de fungerer og hvorfor de styrer computerens laveste niveau.

Forfatter: Leandro Alegsa

Maskinkode er et computerprogram skrevet i maskinsprog, det vil sige den binære kode, en processor direkte kan forstå og udføre. Maskinkode følger instruktionssættet for en bestemt computerarkitektur og er typisk repræsenteret i binær form (bits og bytes). I praksis opbevares maskinkode ofte i eksekverbare filer eller i hukommelsen som sekvenser af bytes — for mennesker vises den ofte i hexadecimalt format for at gøre den mere læsbar. Maskinkode er det laveste niveau af software, og alle højere programmeringssprog må på et tidspunkt oversættes eller fortolkes til maskinkode, for at CPU’en kan afvikle instruktionerne.

Hvordan en instruktion er opbygget

En enkelt maskininstruktion fortæller processoren, hvilken operation den skal udføre. Hver instruktion består typisk af en opcode (operationskode) og en eller flere operander. Operanderne kan være:

  • værdier (immediate) indlejret i instruktionen,
  • registernavne (processorens interne registre),
  • eller hukommelsesadresser, som peger på data i RAM.

Instruktionsformatet varierer mellem arkitekturer: nogle bruger faste længder for alle instruktioner, andre har variable længder. Der findes også forskellige adressing modes (måder at finde operandens adresse på), fx direkte, indirekte, indeksbaseret eller relativ adressering.

Hvad et instruktionssæt definerer

Et instruktionssæt er en formel beskrivelse af alle opkoder, tilgængelige registre, dataformater og hukommelsesmodel for en given computer. Instruktionssættet bestemmer altså, hvilke operationer CPU’en kan udføre, hvordan data flyttes, og hvordan kontrolflytning (betingede hop, funktionopkald osv.) foretages. Kendte forskelle mellem instruktionssæt er fx CISC (komplekse, ofte variable-længde instruktioner) versus RISC (enkle, ofte faste-længde instruktioner), hvilket påvirker både hardwaredesign og kompilatorstrategier.

Fra kildekode til maskinkode

Programmer skrevet i højniveausprog bliver normalt ikke skrevet direkte i maskinkode. I stedet benyttes værktøjer, som omdanner koden:

  • Kompilere oversætter højniveausprog til maskinkode eller objektfiler (binære moduler).
  • En assembler oversætter samlekode (assembly) — en menneskelæselig repræsentation af maskininstruktioner — direkte til maskinkode.
  • Programbuildere (build tools) og linkere samler objektfiler, løser symboler og producerer eksekverbare filer eller biblioteker, som operativsystemets loader kan indlæse i hukommelsen.
  • Fortolkere og JIT-kompilatorer (just-in-time) kan oversætte eller generere maskinkode ved køretid i stedet for ved bygge-/kompileringstid.

Der findes også mellemformater som bytecode (fx Java eller .NET), der kræver en virtuel maskine eller JIT for at blive til maskinkode på den konkrete platform.

Native kode og bærbarhed

Maskinkode omtales ofte som native kode, når den er lavet til og kan afvikles direkte på en bestemt CPU-arkitektur. Native kode er typisk hurtigere, fordi den kører direkte på hardware uden mellemlag, men den er også bundet til det specifikke instruktionssæt og kan ikke køre på en anden arkitektur uden emulering eller genkompilering. Derfor taler man om, at native kode "kun fungerer på nogle computere" — eksempelvis vil x86-nativ kode ikke køre på en ARM-processor uden en kompatibilitetsløsning.

Samlet set er maskinkode den endelige form for instruktioner, en processor kan udføre. Forståelse af opcodes, operander, instruktionssæt og byggefaserne (kompilering/assembling/linking) er centralt for både systemnær programmering, optimering og portering mellem platforme.

Skrivning af maskinkode

Maskinkode kan skrives i forskellige former:

  • Brug af en række kontakter. Dette genererer en sekvens af 1 og 0. Dette blev brugt i de tidlige dage af computerne. Siden 1970'erne er det ikke længere blevet brugt.
  • Brug af en Hex-editor. Dette gør det muligt at bruge opkoder i stedet for kommandonummeret.
  • Brug af en assembler. Assembler-sprog er enklere end opkoder. Deres syntaks er lettere at forstå end maskinsprog, men sværere end højniveausprog. Assembleren oversætter selv kildekoden til maskinkode.
  • Ved at bruge et programmeringssprog på højt niveau kan programmerne bruge kode, der er lettere at læse og skrive. Disse programmer oversættes til maskinkode. Oversættelsen kan ske i mange trin. Java-programmer optimeres først til bytekode. Derefter oversættes det til maskinsprog, når det bruges.
Frontpanel på en tidlig minicomputer med kontakter til indtastning af maskinkodeZoom
Frontpanel på en tidlig minicomputer med kontakter til indtastning af maskinkode

Typiske instruktioner i maskinkode

Der findes mange slags instruktioner, som normalt findes i et instruktionssæt:

  • Aritmetiske operationer: Addition, subtraktion, multiplikation, division.
  • Logiske operationer: Konjunktion, disjunktion, negation.
  • Operationer, der virker på enkelte bits: Skift af bits til venstre eller højre.
  • Operationer, der virker på hukommelsen: kopiering af en værdi fra et register til et andet.
  • Operationer, der sammenligner to værdier: større end, mindre end, lig med.
  • Operationer, der kombinerer andre operationer: addere, sammenligne og kopiere, hvis det er lig med en værdi (som én operation), springe til et punkt i programmet, hvis et register er nul.
  • Operationer, der virker på programflowet: spring til en bestemt adresse.
  • Operationer, der konverterer datatyper: f.eks. konverter et 32-bit heltal til et 64-bit heltal, konverter en floating point-værdi til et heltal (ved at afkortning).

Mange moderne processorer bruger mikrokode til nogle af kommandoerne. Mere komplekse kommandoer har en tendens til at bruge den. Dette sker ofte med CISC-arkitekturer.

Instruktioner

Hver processor eller processorfamilie har sit eget instruktionssæt. Instruktioner er mønstre af bits, der svarer til forskellige kommandoer, som kan gives til maskinen. Instruktionsmængden er således specifik for en klasse af processorer, der (for det meste) anvender den samme arkitektur.

Nyere processordesigns indeholder ofte alle instruktionerne fra en forgænger og kan tilføje yderligere instruktioner. Nogle gange vil et nyere design afbryde eller ændre betydningen af en instruktionskode (typisk fordi den er nødvendig til nye formål), hvilket påvirker kodekompatibiliteten; selv næsten fuldstændig kompatible processorer kan udvise en lidt anderledes adfærd for nogle instruktioner, men det er sjældent et problem.

Systemerne kan også afvige fra hinanden på andre punkter, f.eks. med hensyn til hukommelse, operativsystemer eller perifere enheder. Da et program normalt er afhængigt af sådanne faktorer, vil forskellige systemer typisk ikke køre den samme maskinkode, selv når der anvendes den samme type processor.

De fleste instruktioner har et eller flere opkodefelter. De angiver den grundlæggende instruktionstype. Andre felter kan angive operandernes type, adresseringsmåde osv. Der kan også være særlige instruktioner, som er indeholdt i selve opkoden. Disse instruktioner kaldes immediates.

Processordesigns kan være anderledes på andre måder. Forskellige instruktioner kan have forskellige længder. De kan også have den samme længde. Hvis alle instruktioner har samme længde, kan det forenkle designet.

Eksempel

MIPS-arkitekturen har instruktioner, der er 32 bit lange. Dette afsnit indeholder eksempler på kode. Den generelle type instruktion er i op-feltet (operation). Det er de højeste 6 bit. J-type (jump) og I-type (immediate) instruktioner er fuldt ud angivet ved op. R-type (register)-instruktioner omfatter feltet funct. Det bestemmer den nøjagtige operation af koden. De felter, der anvendes i disse typer, er:

      6 5 5 5 5 5 5 5 6 bits [ op | rs | rt | rd | rd |shamt| funct] R-type [ op | rs | rt | address/immediate] I-type [ op | target address ] J-type

rs, rt og rd angiver registeroperander. shamt angiver et forskydningsbeløb. Adresse- eller immediate-felterne indeholder en operand direkte.

Eksempel: Tilføj registrene 1 og 2. Placer resultatet i register 6. Det er kodet:

[ op | rs | rt | rd | rd |shamt| funct] 0 1 1 2 6 0 32 decimal 000000 00001 00010 00010 00110 00000 100000 100000 binært

Indlæs en værdi i register 8. Tag den fra hukommelsescellen 68 celler efter den placering, der er angivet i register 3:

[ op | rs | rt | address/immediate] 35 3 8 68 decimal 100011 00011 01000 00000 00000 00001 000100 binært

Spring til adressen 1024:

[ op | måladresse ] 2 1024 decimal 000010 00000 00000 00000 00000 00000 10000 000000 binært

Relaterede sider

  • Binært talsystem
  • Kvantecomputere
  • Instruktionssæt
  • Computer med reduceret instruktionssæt

Spørgsmål og svar

Q: Hvad er maskinkode?


A: Maskinkode er et computerprogram skrevet i maskinsprog, der bruger instruktionssættet for en bestemt computerarkitektur og normalt er skrevet binært.

Q: Hvad er det laveste niveau af software?


A: Maskinkode er det laveste niveau af software.

Q: Hvordan udføres andre programmeringssprog af computere?


A: Andre programmeringssprog oversættes til maskinkode, som computeren kan udføre.

Q: Hvad består en instruktion i maskinkode af?


A: En instruktion i maskinkode består af en opcode (operationskode) og operand(er). Operanderne er som regel hukommelsesadresser eller data.

Q: Hvad er et instruktionssæt?


A: Et instruktionssæt er en liste over de operationskoder, der er tilgængelige for en computer.

Q: Hvad gør programudviklere med kode?


A: Programudviklere omdanner kode til et andet sprog eller maskinkode.

Q: Hvad er et andet navn for maskinkode?


A: Maskinkode kaldes nogle gange native code, når man taler om ting, der kun virker på nogle computere.


Søge
AlegsaOnline.com - 2020 / 2025 - License CC3