Ga naar hoofdinhoud

De basis

Hoe computers zijn ontworpen

De centrale verwerkingsunit (CPU) van een computer is verantwoordelijk voor alle berekeningen. Het is de baas. Het begint direct met het uitvoeren, instructie na instructie, zodra je je computer aanzet.

De eerste massaproductie CPU was de Intel 4004, ontworpen in de late jaren zestig door een Italiaanse fysicus en ingenieur genaamd Federico Faggin. Het was een 4-bits architectuur in plaats van de 64-bits systemen die we vandaag de dag gebruiken, en het was aanzienlijk minder complex dan moderne processors, maar veel van zijn eenvoud is nog steeds aanwezig.

De “instructies” die CPUs uitvoeren zijn gewoon binaire data: een byte of twee om aan te geven welke instructie wordt uitgevoerd (de opcode), gevolgd door de data die nodig is om de instructie uit te voeren. Wat we “machine code” noemen, is niets meer dan een reeks van deze binaire instructies achter elkaar. Assembly is een handige syntax voor het lezen en schrijven van machine code die gemakkelijker te lezen en te schrijven is voor mensen dan ruwe bits; het wordt altijd gecompileerd naar de binaire code die je CPU kan lezen.

notitie

Een apart punt: instructies worden niet altijd 1:1 weergegeven in machine code, zoals in het bovenstaande voorbeeld. Zo vertaalt add eax, 512 zich naar 05 00 02 00 00.

De eerste byte (05) is een opcode die specifiek het toevoegen van de EAX register aan een 32-bits getal representeert. De overige bytes zijn 512 (0x200) in little-endian byte volgorde.

Defuse Security heeft een handig hulpmiddel gemaakt voor het experimenteren met de vertaling tussen assembly en machine code.

RAM is je computers hoofdgeheugenbank, een grote, veelzijdige ruimte die alle data opslaat die door programma’s wordt gebruikt die op je computer draaien. Dat omvat de programmeercode zelf, evenals de code in het hart van het besturingssysteem. De CPU leest machinecode altijd direct uit RAM, en code kan niet worden uitgevoerd als deze niet in RAM is geladen.

De CPU slaat een instructiepointer op, die wijst naar de locatie in RAM waaruit het de volgende instructie ophaalt. Na het uitvoeren van elke instructie, verplaatst de CPU de pointer en herhaalt dit. Dit is de fetch-execute cyclus.

Na het uitvoeren van een instructie, verplaatst de pointer naar direct na de instructie in RAM, zodat deze nu wijst naar de volgende instructie. Dat is waarom code draait! De instructiepointer blijft gewoon vooruit schieten, waarbij machinecode wordt uitgevoerd in de volgorde waarin deze in het geheugen is opgeslagen. Sommige instructies kunnen de instructiepointer naar een andere locatie laten springen, of naar verschillende locaties springen, afhankelijk van een bepaalde voorwaarde; dit maakt herbruikbare code en conditionele logica mogelijk.

Deze instructiepointer wordt opgeslagen in een register. Registers zijn kleine opslagbakken die extreem snel zijn voor de CPU om te lezen en te schrijven. Elke CPU-architectuur heeft een vaste set registers, die wordt gebruikt voor alles, van het opslaan van tijdelijke waarden tijdens berekeningen tot het configureren van de processor.

Sommige registers zijn direct toegankelijk vanuit machinecode, zoals ebx in het eerdere diagram.

Andere registers worden alleen intern door de CPU gebruikt, maar kunnen vaak worden bijgewerkt of gelezen met behulp van gespecialiseerde instructies. Een voorbeeld hiervan is de instructiepointer, die niet direct kan worden gelezen, maar wel kan worden bijgewerkt met, bijvoorbeeld, een springinstructie.