#Klooienmetcomputers

It is I, Leclerc

Arnout van Kempen over rommelen in een digitale wereld.

Vorige keer zagen we een probleem als gevolg van de vaste opcode lengte van 32 bits: immediate waarden zijn altijd 16 bits. Met MOVZ en MOVK en maar liefst vier instructies konden we toch een 64 bits register vullen met een 64 bits waarde. Ingewikkeld? Best wel.

Ook spronginstructies hebben hier 'last' van. Alle sprongen, conditioneel of niet, met of zonder return adres, zijn altijd relatief en altijd naar een adres dat een veelvoud van 4 is. Dat betekent dat het adresbereik ten opzichte van de pc altijd 128MB voorwaarts of achterwaarts is. Met een moderne computer met minstens 16G geheugen is dat dus wel iets om rekening mee te houden. Toch zitten er aardige voordelen hier. Door altijd relatief te springen, zijn programma's altijd op een willekeurige plek in het geheugen te plaatsen door het operating system. En de adressering met veelvoud 4 zorgt er voor dat je altijd aan het begin van een instructie uitkomt. Een instructie is immers altijd 32 bits, dus 4 bytes.

Ik noemde een tweede gevolg van de vaste lengte van opcodes. De ARM kan niet onbeperkt veel instructies aan. De bouwers hebben moeten woekeren en dat doen ze door aliassen te gebruiken.

Bij veel CPU's, zoals ook de 8086, is er een één-op-één verband tussen assemblerinstructie en opcode. Iedere instructie heeft een eigen opcode, iedere opcode heeft een eigen instructie. Dat betekent dat assembler en disassembler simpelweg hetzelfde doen in omgekeerde richtingen. ARM doet dat anders. In assembly bestaan verschillende instructies die dezelfde opcode hebben, als die instructies functioneel toch hetzelfde doen. En dankzij het zero register, XZR/WZR, zijn dat er best een aantal.

Laten we een eenvoudig voorbeeld nemen. De volgende instructies hebben de volgende opcodes: 

CMP X0, X1               EB 01 00 1F
SUB XZR, X0, X1          EB 01 00 1F

Als je de werking van het zero register goed hebt begrepen en je snapt wat de compare-instructie doet, dan zie je dat beide instructies exact hetzelfde doen. Er is dan ook geen enkele reden om hiervoor twee verschillende opcodes te hebben.

Er zijn verschillende implementaties van de ARM-architectuur. In een aantal ontbreekt niet alleen de CMP instructie, maar ook de MOV. Immers, het effect van MOV X0, X1 en van ADD X0, XZR, X1 is exact hetzelfde, dus waarom zou je een aparte MOV hebben?

Er is echter wel een verschil. De ALU moet bij de CMP en de SUB XZR precies hetzelfde doen. Maar een MOV kan uitgevoerd worden zonder de ALU een optelling te laten doen, terwijl de ADD weliswaar hetzelfde resultaat geeft, maar wel nog een optelling moet uitvoeren. Hier betekent een instructieset zonder echte MOV een versimpeling in de opcodes, maar een iets minder efficiënte uitvoering. Het hangt dan ook af van de exacte implementatie of hier met een alias of met een eigen opcode wordt gewerkt.

Zolang we in assembly programmeren, is er geen reden ons hier druk over te maken. De assembler lost alles keurig op. Maar als we een disassembler gaan gebruiken om opcodes naar assembly te vertalen, is het handig voorbereid te zijn op dit soort aliassen.

Wie mee wil doen met #klooienmetcomputers kan dat doen via GitHub. Maak een account op github.com en zoek naar Abmvk/kmc. Het account Abmvk volgen kan ook. Lezers zijn vrij te gebruiken wat ze willen en om zelf zaken toe te voegen of aan te passen, vragen te stellen of commentaar te leveren.

Arnout van Kempen di CCO CISA is directeur compliance & risk bij aaff, de fusieorganisatie van Alfa en ABAB. Hij schrijft op persoonlijke titel.

Gerelateerd

reacties

Reageer op dit artikel

Spelregels debat

    Aanmelden nieuwsbrief

    Ontvang elke werkdag (maandag t/m vrijdag) de laatste nieuwsberichten, opinies en artikelen in uw mailbox.

    Bent u NBA-lid? Dan kunt u zich ook aanmelden via uw ledenprofiel op MijnNBA.nl.