Operand – het object waarop het machinecommando wordt uitgevoerd.
Operanden in assembleertaal worden beschreven door uitdrukkingen met numerieke en tekstconstanten, labels en variabele-identificatoren met behulp van operatortekens en enkele gereserveerde woorden.
Operanden kunnen worden gecombineerd met rekenkundige, logische, bitsgewijze en attribuutoperatoren om een bepaalde waarde te berekenen of de te beïnvloeden geheugenlocatie te bepalen deze opdracht of richtlijn.
Methoden voor operandadressering
Adresseringsmethoden verwijzen naar bestaande methoden voor het specificeren van het opslagadres van operanden:
De operand is ingesteld op firmwareniveau (standaard operand): In dit geval bevat de opdracht niet expliciet een operand; het algoritme voor opdrachtuitvoering gebruikt enkele standaardobjecten (registers, attributen, enz.).
mul ebx ; eax = eax*ebx, gebruikt impliciet het eax-register
De operand wordt gespecificeerd in de instructie zelf (onmiddellijke operand): De operand maakt deel uit van de instructiecode. Om een dergelijke operand op te slaan, wordt in de opdracht een veld van maximaal 32 bits toegewezen. De onmiddellijke operand kan alleen de tweede operand (bron) zijn. De bestemmingoperand kan zich in het geheugen of in een register bevinden.
verplaats eax, 5; eax = 5;
ebx, 2 toevoegen; ebx = ebx + 2;
De operand bevindt zich in een van de registers (registeroperand): In de code worden opdrachten aangegeven met registernamen. De volgende registers kunnen worden gebruikt:
- 32-bits registers EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP;
- 16-bits registers AX, BX, CX, DX, SI, DI, SP, BP;
- 8-bits registers AN, AL, BH, BL, CH, CL, DH, DL;
- segmentregisters CS, DS, SS, ES, FS, GS.
eax, ebx toevoegen; eax = eax + ebх
december esi ; esi = esi - 1
De operand bevindt zich in het geheugen. Met deze methode kunt u twee hoofdtypen adressering implementeren:
- directe adressering;
- indirecte adressering.
Directe adressering : Het effectieve adres wordt rechtstreeks bepaald door het offsetveld van de machine-instructie, dat 8, 16 of 32 bits groot kan zijn.
verplaats eax, som ; eax = som
De assembler vervangt sum door het overeenkomstige adres dat is opgeslagen in het datasegment (standaard geadresseerd door het ds-register) en plaatst de waarde die is opgeslagen bij sum in het eax-register.
Indirecte adressering
heeft op zijn beurt de volgende typen:
- indirecte basis(register)adressering;
- indirecte basisadressering (registeradressering) met offset;
- indirecte indexadressering;
- indirecte basisindexadressering.
Indirecte basisadressering (register). Met deze adressering kan het effectieve adres van de operand zich in elk register voor algemene doeleinden bevinden, behalve sp/esp en bp/ebp (dit zijn specifieke registers voor het werken met het stapelsegment). Syntactisch in een commando wordt deze adresseringsmodus uitgedrukt door de registernaam tussen vierkante haken te plaatsen.
verplaats eax ; eax = *esi; *esi-waarde op adres esi
Met deze adresseringsmethode kunt u dynamisch een operandadres toewijzen aan een bepaalde machine-instructie en wordt gebruikt bij het organiseren van cyclische berekeningen en bij het werken met datastructuren en arrays.
Indirecte basisadressering (registeradressering) met offset ontworpen om toegang te krijgen tot gegevens met een bekende offset ten opzichte van sommige basis adres, wordt gebruikt om toegang te krijgen tot elementen van structuren wanneer de offset van de elementen vooraf bekend is, in de ontwikkelingsfase van het programma, en het basisadres (start) van de structuur dynamisch moet worden berekend in de fase van programma-uitvoering. Door de inhoud van het basisregister te wijzigen, kunt u toegang krijgen tot elementen met dezelfde naam in verschillende exemplaren van hetzelfde type datastructuren.
verplaats eax, ; eax = *(esi+4)
Indirecte indexadressering. Om een effectief adres te vormen, wordt een van de registers voor algemene doeleinden gebruikt, maar deze heeft de mogelijkheid om de inhoud van het indexregister te schalen.
verplaats eax, mas
Het effectieve adres van de tweede operand wordt berekend door mas+(esi *4) en is de offset vanaf het begin van het datasegment.
De mogelijkheid om te schalen helpt enorm bij het oplossen van het indexeringsprobleem, op voorwaarde dat de grootte van de array-elementen constant is en 1, 2, 4 of 8 bytes bedraagt.
Dit type adressering kan ook met een offset worden gebruikt.
Indirecte basisindexadressering. Het effectieve adres wordt gevormd als de som van de inhoud van twee registers voor algemene doeleinden: basis en index. Deze registers kunnen alle registers voor algemene doeleinden zijn en vaak de inhoud van het indexregister schalen.
verplaats eax
Het effectieve adres van de tweede operand wordt gevormd als esi+edx. De waarde op dit adres wordt in het eax-register geplaatst.
Wanneer indirecte basisindexadressering met een offset wordt gebruikt, wordt het effectieve adres gevormd als de som van drie componenten: de inhoud van het basisregister, de inhoud van het indexregister en de waarde van het offsetveld in de instructie.
De operand is de I/O-poort.
Naast de adresruimte RAM De microprocessor onderhoudt een I/O-adresruimte, die wordt gebruikt om toegang te krijgen tot I/O-apparaten. De I/O-adresruimte is 64 KB. Adressen worden toegewezen voor elk computerapparaat in deze ruimte. De specifieke adreswaarde binnen deze ruimte wordt een I/O-poort genoemd. Fysiek komt de I/O-poort overeen met een hardwareregister (niet te verwarren met een microprocessorregister), waartoe toegang wordt verkregen via speciale elftallen monteur in en uit.
in al, 60 uur ; voeg een byte in van poort 60h
Registers die door een I/O-poort worden geadresseerd, kunnen 8, 16 of 32 bits breed zijn, maar de registerbreedte ligt vast voor een bepaalde poort. Accumulatorregisters eax, ax, al worden gebruikt als informatiebron of ontvanger. De keuze van het register wordt bepaald door de bitgrootte van de poort. Het poortnummer kan worden opgegeven als een directe operand in de in- en uit-instructies of als een waarde in het dx-register. Laatste methode Hiermee kunt u het poortnummer in het programma dynamisch bepalen.
mov dx, 20 uur ; schrijf poortnummer 20h naar dx register
verplaats ,21u ; schrijf de waarde 21h naar het al-register
uit dx, al ; voer de waarde 21h uit naar poort 20h
Adres teller– een specifiek type operand. Dit wordt aangegeven door het $-teken. De specificiteit van deze operand is dat wanneer de assembler-vertaler tegenkomt origineel programma dit teken vervangt het in plaats daarvan de huidige waarde van de adresteller (EIP-register). De adrestellerwaarde vertegenwoordigt de offset van de huidige machine-instructie ten opzichte van het begin van het codesegment dat door het CS-segmentregister wordt geadresseerd. Wanneer de vertaler de volgende assembler-instructie verwerkt, wordt de adresteller verhoogd met de lengte van de gegenereerde machine-instructie. Het verwerken van assembler-richtlijnen verandert de teller niet. Een voorbeeld van het gebruik van een adrestellerwaarde in een opdracht is het volgende fragment:
jmp$+3 ;onvoorwaardelijke sprong naar het mov-commando
nee ; nop-opdrachtlengte is 1 byte
beweeg al, 1
Wanneer je een dergelijke uitdrukking voor springen gebruikt, mag je de lengte van de instructie zelf waarin deze uitdrukking wordt gebruikt niet vergeten, aangezien de waarde van de adresteller overeenkomt met de offset in het codesegment hiervan, en niet met de volgende instructie. In het bovenstaande voorbeeld neemt de jmp-opdracht 2 bytes in beslag. De lengte van deze en enkele andere instructies kan afhangen van welke operanden worden gebruikt. Een instructie met registeroperands zal korter zijn dan een instructie waarbij een van de operanden zich in het geheugen bevindt. In de meeste gevallen kan deze informatie worden verkregen door het formaat van de machine-instructie te kennen.
Structurele operanden gebruikt om toegang te krijgen specifiek onderdeel complex gegevenstype dat een structuur wordt genoemd.
Berichten(vergelijkbaar met structureel type) worden gebruikt om toegang te krijgen beetje veld wat opname. Om toegang te krijgen tot het bitveld van een record, gebruikt u de RECORD-instructie.
Operatoren in assembleertaal
Operanden zijn de elementaire componenten die deel uitmaken van een machine-instructie die de objecten aanduidt waarop een bewerking wordt uitgevoerd. In een algemener geval kunnen operanden worden opgenomen als componenten in complexere formaties uitdrukkingen
. Expressies zijn combinaties van operanden en exploitanten
, als geheel beschouwd. Het resultaat van het evalueren van een uitdrukking kan het adres zijn van een geheugencel of een constante (absolute) waarde.
De uitvoering van assembler-operatoren bij het evalueren van expressies wordt uitgevoerd in overeenstemming met hun prioriteiten. Bewerkingen met dezelfde prioriteiten worden opeenvolgend van links naar rechts uitgevoerd. Het wijzigen van de volgorde van uitvoering is mogelijk door haakjes te plaatsen die de hoogste prioriteit hebben.
Prioriteit | Exploitant |
1 | lengte, grootte, breedte, masker, (), ,< > |
2 | . |
3 | : |
4 | ptr, offset, seg, dit |
5 | hoog, laag |
6 | +, — (unair) |
7 | *, /, mod, shl, shr |
8 | +, -, (binair) |
9 | eq, ne, lt, le, gt, ge |
10 | niet |
11 | En |
12 | of, xor |
13 | kort, typ |
Kenmerken van de belangrijkste operators.
Rekenkundige operatoren. Deze omvatten unaire operatoren + En — , binair + En — , vermenigvuldigingsoperatoren * , gehele deling / , het verkrijgen van de rest van de divisie mod. Bijvoorbeeld,
maat gelijkwaardig 48 ;arraygrootte in bytes
el eq 4 ;elementgrootte
;het aantal elementen wordt berekend
mov ecx, grootte / el; operator /
Shift-operatoren verschuif de uitdrukking met het opgegeven aantal bits. Bijvoorbeeld,
msk equ 10111011; constante
mov al, msk shr 3; al=00010111 /
Vergelijkingsoperatoren (retourwaarde WAAR of leugen) zijn bedoeld om te vormen logische uitdrukkingen. Booleaanse waarde WAAR komt overeen met een logische, en leugen– logische nul. Logische één is een bitwaarde gelijk aan 1, logische nul is een bitwaarde gelijk aan 0.
maat equ 30; tafelgrootte
…
mov al , tab_size ge 50 ;al = 0
cmp al , 0 ;if grootte< 50, то
je m1 ;ga naar m1
…
m1: ...
Als de waarde van size groter is dan of gelijk is aan 50, dan is het resultaat in al 1, anders is het 0. Het cmp-commando vergelijkt de waarde van al met nul en stelt de juiste vlaggen in EFLAGS in. Het je-commando, gebaseerd op de analyse van deze vlaggen, draagt de controle wel of niet over aan het m1-label.
Het doel van vergelijkingsoperatoren wordt gegeven in de tabel
Exploitant | Voorwaarde |
gelijk | == |
ne | != |
Het | < |
le | <= |
GT | > |
ge | >= |
Logische operatoren voer bitsgewijze bewerkingen uit op expressies. Uitdrukkingen moeten constant zijn. Bijvoorbeeld,
L1 gelijk aan 10010011
…
beweeg al, L1
xor al , 01h ;al=10010010
Index-operator. De vertaler interpreteert de aanwezigheid van vierkante haken als een instructie om de waarde toe te voegen uitdrukkingen voor met betekenis uitdrukkingen, tussen haakjes. Bijvoorbeeld,
mov eax , mas ;eax=*(mas+(esi))
De aanwezigheid van de indexoperator geeft aan de vertaler aan dat hij de waarde op het berekende adres moet verkrijgen.
Operator voor herdefinitie typen ptr gebruikt om het type label of variabele dat door een expressie wordt gedefinieerd, opnieuw te definiëren of te kwalificeren. Het type kan een van de volgende waarden aannemen.
Type | Uitleg | Doel |
byte | 1 byte | variabel |
woord | 2 bytes | variabel |
dwoord | 4 bytes | variabel |
qwoord | 8 bytes | variabel |
seconde | 10 bytes | variabel |
in de buurt van | nabij wijzer | functie |
ver | verre wijzer | functie |
Bijvoorbeeld,
str1 db "Hallo", 0
lea esi, str1
cmp-byte ptr, 0; ==0?
Als u in het voorbeeld een waarde op adres esi wilt vergelijken met een constante, moet u expliciet aangeven welk type gegevens zal worden vergeleken.
Operator voor segmentoverschrijving : (dubbele punt) berekent fysiek adres met betrekking tot een specifiek gespecificeerde segmentcomponent, die kan zijn:
- segmentregisternaam,
- segmentnaam uit de overeenkomstige SEGMENT-richtlijn
- groepsnaam.
Om te selecteren of de volgende instructie moet worden uitgevoerd, analyseert de microprocessor de inhoud van het segmentregister CS, dat het fysieke adres van het begin van het codesegment bevat. Om het adres van een specifieke instructie te verkrijgen, telt de microprocessor de geschaalde (vermenigvuldigd met 16) waarde van het CS-segmentregister op met de inhoud van het EIP-register. De CS:EIP-invoer bevat het adres van de momenteel uitgevoerde opdracht. Operanden in machine-instructies worden op dezelfde manier verwerkt.
Naamgevingsoperator voor structuurtype . (dot) zorgt er ook voor dat de compiler bepaalde berekeningen uitvoert als dit in een expressie voorkomt.
Operator voor het verkrijgen van de segmentcomponent van een expressieadres bijv retourneert het fysieke adres van het segment voor een expressie, wat een label, een variabele, een segmentnaam, een groepsnaam of een symbolische naam kan zijn.
Expressie-offsetoperator gecompenseerd Hiermee kunt u de offsetwaarde van een expressie in bytes verkrijgen ten opzichte van het begin van het segment waarin de expressie is gedefinieerd. Bijvoorbeeld,
Gegevens
str1 db "Hallo" ,0
.code
mov esi, offset str1
beweeg al, ; al = 'P'
Operator voor arraylengte lengte retourneert het aantal elementen dat is opgegeven door de dup-operand. Als er geen dup-operand is, retourneert de lengte-operator de waarde 1. Bijvoorbeeld:
tabl dw 10 dup (?)
…
mov edx, lengtetabel; edx=10
Exploitant type retourneert het aantal bytes dat overeenkomt met de definitie van de opgegeven variabele:
fldb db?
tabl dw 10 dup (?)
…
verplaats eax, typ fldb;eax = 1
mov eax , typ tabel ;eax = 2
Exploitant
maat geeft het product van lengte en terug soort soort en wordt gebruikt bij het verwijzen naar een variabele met een dup-operand.
Voor het vorige voorbeeld
mov edx , groottetabel ;edx = 20 bytes
Exploitant kort– wijziging van het near-attribuut in het jmp-commando als de overgang de grenzen van +127 en -128 bytes niet overschrijdt. Bijvoorbeeld,
jmp kort label
Als gevolg hiervan reduceert de assembler de machinecode van de operand van twee naar één byte. Deze functie is handig voor korte voorwaartse sprongen, omdat in dit geval de assembler niet zelf de afstand tot het sprongadres kan bepalen en twee bytes reserveert bij afwezigheid van de korte operator.
Exploitant breedte retourneert de grootte in bits van een RECORD-object of zijn veld.
Doelen:
kennis consolideren van registers voor algemene doeleinden van 32-bit INTEL-processors;
leer indirecte adressering gebruiken om met RAM te werken;
Leer de commando's gebruiken om gehele getallen te vermenigvuldigen en te delen.
De belangrijkste belasting bij het bedienen van een computer valt op de processor en het geheugen. De processor voert instructies uit die in het geheugen zijn opgeslagen. Gegevens worden ook in het geheugen opgeslagen. Er is een continue uitwisseling van informatie tussen de processor en het geheugen. De processor heeft een eigen klein geheugen bestaande uit registreert. Een processoropdracht die gegevens in registers gebruikt, wordt veel sneller uitgevoerd dan vergelijkbare opdrachten op gegevens in het geheugen. Om een opdracht uit te voeren, worden daarom vaak eerst de gegevens daarvoor in registers geplaatst. Het resultaat van de opdracht kan indien nodig weer in het geheugen worden geplaatst. Er vindt gegevensuitwisseling tussen geheugen en registers plaats opdrachten doorsturen. Bovendien kunt u gegevens uitwisselen tussen kassa's, gegevens verzenden en ontvangen van externe apparaten. U kunt ook een direct bericht naar een register- en geheugencel sturen. operand- nummer. Daarnaast zijn er opdrachten die kunnen worden gebruikt om gegevens in te voegen en op te halen stapel – speciaal gebied geheugen dat wordt gebruikt om retouradressen op te slaan van functies die aan de functie zijn doorgegeven voor parameters en lokale variabelen.
Adressering en geheugentoewijzing
Voor de processor bestaat al het geheugen uit een reeks cellen van één byte, die elk hun eigen adres hebben. Om met grote getallen te kunnen werken, worden paren cellen gecombineerd tot woorden, paren woorden tot dubbele woorden, paren dubbele woorden tot viervoudige woorden. Meestal werken de programma's bytes, woorden En dubbele woorden(volgens processorregisters van één, twee en vier bytes). Het adres van een woord en dubbelwoord is het adres van zijn lage byte.
Lijst 1 toont een voorbeeld van geheugentoegang met behulp van indirecte adressering. Laten we het in detail bekijken. Merk allereerst op dat het programma een headerbestand bevat
_get() ;
) Lijst 1. Dit maakt gebruik van variabele toegang zoals BYTE per index - structuur
BYTE PTR
. Even later zullen we zien hoe deze techniek wordt gebruikt bij het schrijven van programma's. Opdrachten. Probeer naar het variabele adres te schrijven A, opgeslagen in het register 260 EAH
, nummer . Welk antwoord heb je gekregen? Waarom? Variabele instellen B type WOORD Variabele instellen DWORD en een variabele 1023 En 70000 C
. Gebruik indirecte adressering om getallen naar deze variabelen te schrijven respectievelijk. Plaats het in een variabele 70000 Met Lijst 1.:
, met behulp van een typeaanwijzer B.
LEA EAX, c; MOV-BYTE PTR [EAX], 70000; Leg uw resultaat uit (onthoud dat het adres van een woord of dubbelwoord het adres van de lage byte is). Doe hetzelfde met behulp van een typeaanwijzer Listing 2 is een programma dat illustreert hoe toegang te krijgen tot variabelen met behulp van pointers. Typ dit programma. Sorteer de opmerkingen. Probeer de elementen van de array te wijzigen. Probeer resultaten uit te voeren in hexadecimaal (in plaats van%u in de functieopmaakregel).
printf(
"tweede element van array (basisadressering) a4 = %u \n ", a4) ; printf("tweede element van array (basisadres - op een andere manier) a5 = %u \n "
, a5) ; printf( "1, 2 elementen van array b1 = %u \n ", b1) ; printf("3, 4 elementen van array b2 = %u \n " , b2) ; printf( "3, 4, 5, 6 elementen van array c = %u \n ", C) ; _get() ; ) Lijst 2. Toegang tot een variabele via een pointer ook gebruikt in talen hoog niveau(heel vaak bij het maken van dynamische arrays). * Wijzer is een variabele die het adres van een andere variabele bevat (een pointer wijst naar een variabele van het type waarvan hij het adres bevat). Er is een één-plaats (unair, dat wil zeggen voor één operand) bewerking waarbij het adres van een variabele wordt overgenomen hoog niveau& (ampersand, zoals in de titel van de Tom&Jerry-tekenfilm). Als we een advertentie hebben * int een , dan kunnen we het bepalen adres
< тип переменной> * < имя указателя>Dit is de regel voor het declareren van een pointer: een pointer naar een variabele van een bepaald type is een variabele die, wanneer hierop wordt gereageerd door een dereferentiebewerking, de waarde verkrijgt van een variabele van hetzelfde type. Lijst 3 toont een voorbeeld van het gebruik van een aanwijzer in C.
/* het adres van een variabele verkrijgen - C en Assembler vergelijken */ #erbij betrekken, asmAddr);
printf( "C: adres van a is %u\n ", cAddr);
printf("C: waarde van a is %u #erbij betrekkenptrMasKort = masKort;
ptrMasBYTE = masBYTE; printf("matrix van int);
voor (int i= 0; ik #erbij betrekkenLijst 5.
Oefening. Geef de adressen weer van de elementen van de array die is gemaakt in het programma dat wordt weergegeven in Lijst 5. Probeer een dynamische array te maken zoals dubbele, vul het in, druk de array-elementen en hun adressen af.
Rekenkundige bewerkingen op gehele getallen
Optellen en aftrekken van gehele getallen
Laten we eens kijken naar 3 basiscommando's voor optellen. Team INC voert een verhoging uit, d.w.z. verhoog de inhoud van de operand met 1, bijvoorbeeld INC EAX. Team INC zet vlaggen OF, SF, ZF, AF, PF afhankelijk van de resultaten van de toevoeging. Team TOEVOEGEN voert de optelling van twee operanden uit. Het resultaat wordt naar de eerste operand (ontvanger) geschreven. De eerste operand kan een register of een variabele zijn. De tweede operand is een register, variabele of getal. Het is echter onmogelijk om de optelling op twee variabelen tegelijk uit te voeren. Commando werkt op vlaggen CF, OF, SF, ZF, AF, PF. Het kan worden gebruikt voor ondertekende en niet-ondertekende nummers. Team ADC voert de optelling van twee operanden uit als een commando TOEVOEGEN en een carry-vlag (bit). Met zijn hulp kunt u getallen toevoegen waarvan de grootte groter is dan 32 bits of waarvan de oorspronkelijke lengte van operanden groter is dan 32 bits.
/* gehele getallen optellen */ #erbij betrekken"som van de laagste 4 bytes = %x\n "
, N) ; printf( #erbij betrekken// trek de hoogste 4 bytes af van de hoogste 4 bytes van het getal i
// cijfers j, evenals de CF-vlag
MOV DWORD PTR k, EAX; // plaats de onderste 4 bytes van het resultaat in het geheugen MOV DWORD PTR k+ 4, EDX; // plaats de bovenste 4 bytes van het resultaat in het geheugen); printf("c=a+b=%d, C) ; printf("k=i-j=%I64x , k) ;); _get() ;) // plaats de bovenste 4 bytes van het resultaat in het geheugen Lijst 7.
Gehele getallen vermenigvuldigen In tegenstelling tot optellen en aftrekken vermenigvuldiging is gevoelig voor het teken van het getal, dus er zijn twee vermenigvuldigingsopdrachten: MUL – voor vermenigvuldiging niet ondertekend cijfers, En IMUL zal gelijk zijn aan 0, anders – 1.
Gehele getallen vermenigvuldigen dubbel-byte vermenigvuldiging – voor vermenigvuldiging, en het resultaat wordt in een aantal registers geplaatst DX:AX(niet erin EAX, wat misschien logisch lijkt). Dienovereenkomstig, als het resultaat er volledig in past – voor vermenigvuldiging, d.w.z. inhoud DX gelijk is aan 0, dan zijn de vlaggen ook gelijk aan nul IMUL En cijfers,.
Ten slotte, als de broninstructie de lengte heeft vier bytes vermenigvuldiging EAX, en het resultaat moet in een paar registers worden geplaatst EDX:EAX. Als de inhoud EDX na vermenigvuldiging zal dan gelijk zijn aan nul nulwaarde de vlaggen zullen het ook hebben IMUL En cijfers,.
Team , k) ; heeft er 3 verschillende formaten. Het eerste formaat is vergelijkbaar met de opdracht // plaats de bovenste 4 bytes van het resultaat in het geheugen. Laten we eens kijken naar de andere twee formaten.
IMUL-operand1, operand2
operand1 er moet een register zijn operand2 kan een getal, een register of een variabele zijn. Als resultaat van het uitvoeren van de vermenigvuldiging ( operand1 vermenigvuldigd met operand2 en het resultaat wordt erin geplaatst operand1) kan resulteren in een getal dat niet in de ontvanger past. In dit geval de vlaggen IMUL En AF zal gelijk zijn aan 1 (anders 0).
IMUL-operand1, operand2, operand3
In dit geval operand2(register of variabele) vermenigvuldigd met operand3(getal) en het resultaat wordt ingevoerd operand1(register). Als er tijdens de vermenigvuldiging een overloop optreedt, d.w.z. Als het resultaat niet in de ontvanger past, worden de vlaggen ingesteld IMUL En cijfers,. Het gebruik van vermenigvuldigingscommando's wordt getoond in Lijst 8.
#erbij betrekkenprintf("a*100000 = %I64d
, B) ;
// interpreteer het uitvoernummer als __int64 printf("e = %d , e) ; _get() ;
) 1 byte Lijst 8. Vermenigvuldigingscommando's gebruiken – voor vermenigvuldiging is gevoelig voor het teken van het getal, dus er zijn twee vermenigvuldigingsopdrachten: Deling van gehele getallen Divisie niet-ondertekende nummers worden gedaan met behulp van de opdracht
) 2 bytes DX:AX DIV – voor vermenigvuldiging Deling van gehele getallen DX niet-ondertekende nummers worden gedaan met behulp van de opdracht
) 4 bytes. Het commando heeft slechts één operand: dit is de deler. De deler kan een register of een geheugenlocatie zijn. Afhankelijk van de grootte van de deler wordt het dividend gekozen. EDX:EAX DIV EAX Deling van gehele getallen EDX niet-ondertekende nummers worden gedaan met behulp van de opdracht
Ondertekend divisiecommando IDIV volledig vergelijkbaar met de opdracht , e) ;. Het is belangrijk dat voor delingsinstructies de waarden van de rekenkundige bewerkingsvlaggen niet zijn gedefinieerd. De deling kan resulteren in een overflow of een deling door 0. Het besturingssysteem moet de uitzondering afhandelen.
#erbij betrekken- // plaats het quotiënt in b
- NASM/YASM vereist een woord wanneer de grootte van de operand niet wordt geïmpliceerd door de andere operand. (Anders oké).
MASM/TASM vereist woord ptr wanneer de grootte van de operand niet wordt geïmpliceerd door de andere operand. (Anders oké).
Elk ervan wordt verstikt door een andere syntaxis.
WAARSCHUWING: Dit is een heel vreemd gebied zonder enige ISO-standaard of direct beschikbare BNF-tabellen; en ik ben geen expert in het navigeren door de mijnenvelden van de propriëtaire MASM-syntaxis.
Over het algemeen wordt een PTR-operatorexpressie gedwongen te worden behandeld als een aanwijzer van het opgegeven type:In uw geval maakt het misschien geen verschil, maar de PTR-operator kan in andere gevallen het volgende bedoelen:
.DATA num DWORD 0 .CODE mov ax, WORD PTR ; Laad een woordgroottewaarde uit een DWORD Ik denk dat die er ook zijn specifieke vereisten
voor assembler (nasm/tasm/andere asm), en het gebruik van "byte ptr" is draagbaarder.
Controleer ook sectie 4.2.16 in het boek uit India en secties 8.12.3 (en 8.11.3 "Soorten conflicten") in "Programming Language Programming Program".
UPDATE: Dankzij Frank Kotler lijkt het erop dat NASM "een variant van de Intel Assembly-syntaxis gebruikt" (wiki) die de PTR-bewerking niet bevat.
MOV WORD PTR , 5 ;ingesteld woord waarnaar wordt verwezen door BX = 5 INC DS:BYTE PTR 10 ;byte verhogen bij offset 10 ;vanaf DSUPDATE1: Er is een originele "ASM86 TAALREFERENTIEHANDLEIDING" van Intel, 1981-1983, PTR-operator gedefinieerd op pagina 4-15
PTR-operator
Syntaxis: Voer de PTR-naam in Beschrijving: De PTR-operator wordt gebruikt om een geheugenreferentie te definiëren bepaald soort . De assembler definieert juiste instructies voor montage op basis van het type operanden in de instructie. Er zijn bepaalde gevallen
MOV CL, BYTE PTR AWORD ;haal eerste byte MOV CL, BYTE PTR AWORD + 1 ;haal tweede byteDit formulier kan ook worden gebruikt om het typeattribuut van een variabele of label te overschrijven. Als u bijvoorbeeld toegang wilt krijgen tot een reeds gedefinieerde woordvariabele als twee bytes, kunt u het volgende coderen:
Veldwaarden:
type Dit veld kan een van de volgende waarden hebben: BYTE, WORD, DWORD, QWORD, TBYTE, NEAR, FAR
naam Dit veld kan de volgende zijn: 1. Variabelenaam. 2. Labelnaam. 3. Adres of register. 4. Een geheel getal dat de offset vertegenwoordigt.
UPDATE2: Met dank aan Uni van Bitrader uit Stuttgart! Er is een originele MACRO-86 handleiding van Microsoft (1981). Pagina 3-7:
MOV, FOODe PTR-operator kan op een andere manier worden gebruikt om een byte op te slaan bij gebruik van voorwaartse referenties. Als u FOO als een persistente constante hebt gedefinieerd, kunt u de volgende instructie invoeren:
MOV BYTE PTR, FOO MOV, BYTE PTR FOOU kunt FOO onmiddellijk een byte noemen. In dit geval kunt u een van de operatoren invoeren (ze zijn gelijkwaardig):
Deze uitspraken geven aan MACRO-86 aan dat FOO onmiddellijk een byte is. Er wordt een kleiner team gevormd.
En pagina 3-16:
Operators overschrijven
Deze operators worden gebruikt om het segment, de offset, het type of de afstand tussen variabelen en labels opnieuw te definiëren.
Index (PTR)
BEL WORD PTR MOV BYTE PTR ARRAY, (iets) VOEG BYTE PTR FOO,9 toeDe PTR-operator overschrijft het type (BYTE, WORD, DWORD) of de afstand (NEAR, FAR) van de operand.
- nieuw attribuut; nieuw type of nieuwe afstand.
is de operand waarvan het attribuut moet worden overschreven. Het belangrijkste en meest voorkomende gebruik van PTR is ervoor te zorgen dat MACRO-86 begrijpt welk kenmerk een expressie zou moeten hebben. Dit geldt vooral voor het type attribuut. Telkens wanneer u links in uw programma plaatst, wist PTR het afstands- of expressietype. Zo voorkom je fasefouten.
Het tweede gebruik van PTR is het verkrijgen van toegang tot gegevens van een ander type dan het type in de variabelendefinitie. Meestal gebeurt dit in structuren. Als de structuur als WORD is gedefinieerd, maar u het element als byte wilt benaderen, is PTR hiervoor de operator. Een veel eenvoudigere manier is echter om een tweede operator te introduceren die ook de bytestructuur definieert. Dit elimineert de noodzaak om PTR te gebruiken voor elke structuurreferentie. Zie LABEL-richtlijn in paragraaf 4.2.1 Geheugenrichtlijnen.
Nadat ik dit heb gelezen en enkele syntaxisdefinities uit deze documenten heb doorzocht, geloof ik dat PTR-notatie een must is. Het gebruik van mov BYTE , 0 is onjuist volgens de MACRO-86-handleiding.
Peter, 2003. - 629 d.
Downloaden(directe link) :
assembler2003.djvu Vorige 1 .. 40 > .. >> Volgende
O De operator ptr type redefinition wordt gebruikt om het type label of variabele dat door een expressie wordt gedefinieerd, opnieuw te definiëren of te verduidelijken (Figuur 5.10). Het type kan een van de volgende waarden aannemen: byte, word, dword, qword, tbyte, near, far. Wat deze waarden betekenen, leer je later in deze les. Bijvoorbeeld:
d wrd dd 0 * * *
pyu al.byte ptr d_wrd+l ;stuur tweede byte van dubbel
;woorden Laten we dit fragment van het programma uitleggen. De djwrd-variabele is van het type doubleword. Wat moet u doen als u niet toegang wilt hebben tot de volledige waarde van een variabele, maar tot slechts één van de bytes die erin zijn opgenomen (bijvoorbeeld de tweede)? Als je dit probeert te doen met het commando mov al. d_wrd+l, dan zal de vertaler een bericht weergeven over een verkeerde combinatie van operandtypen. Met de ptr-operator kunt u het type rechtstreeks in een opdracht overschrijven en de opdracht uitvoeren.
HTType!-(ptr)-Expressie -
Rijst. 5.10. Typ de syntaxis van de operator negeren
O Operator voor segmentoverschrijving: (dubbele punt) dwingt het berekenen van het fysieke adres relatief aan een specifiek gespecificeerde segmentcomponent: “segmentregisternaam”, “segmentnaam” uit de overeenkomstige SEGMENT-instructie of “groepsnaam” (Fig. 5.11).
Dit punt is erg belangrijk, dus laten we het in meer detail uitleggen. Bij het bespreken van segmentatie hadden we het over het feit dat de microprocessor dat wel is hardwareniveau ondersteunt drie soorten segmenten: code, stapel en data. Wat is deze hardwareondersteuning? Om bijvoorbeeld te selecteren of de volgende opdracht moet worden uitgevoerd, moet de microprocessor alleen naar de inhoud van het segmentregister es kijken. En dit register bevat, zoals we weten, het (nog niet verschoven) fysieke adres van het begin van het commandosegment. Om het adres van een specifieke instructie te verkrijgen, moet de microprocessor de inhoud van es met 16 vermenigvuldigen (wat een verschuiving met vier bits betekent) en de resulterende 20-bits waarde optellen bij de 16-bits inhoud van het ip-register. Ongeveer hetzelfde gebeurt wanneer een microprocessor operanden in een machine-instructie verwerkt. Als het ziet dat de operand een adres is (het effectieve adres, dat slechts een deel van het fysieke adres is), dan weet het in welk segment het moet zoeken - standaard is dit het segment waarvan het startadres in het ds-segment is geschreven register.
Hoe zit het met het stapelsegment? Zie les 2 waar we het doel van registers voor algemene doeleinden hebben beschreven. In de context van onze overweging zijn we geïnteresseerd in de sp- en bp-registers. Als de microprocessor een van deze registers als een operand ziet (of een deel ervan, als de operand een uitdrukking is), genereert hij standaard het fysieke adres van de operand, waarbij hij de inhoud van het ss-register als segmentcomponent gebruikt. Wat betekent de term ‘standaard’? Denk aan de ‘reflexen’ waar we het in les 1 over hadden. Dit is een reeks microprogramma’s in de microprogrammabesturingseenheid, die elk een van de commando’s in het machine-instructiesysteem van de microprocessor uitvoeren. Elke firmware werkt volgens zijn eigen algoritme. Je kunt het natuurlijk niet veranderen, maar je kunt het wel een beetje aanpassen. Dit wordt gedaan met behulp van het optionele machineopdrachtvoorvoegselveld (zie opdrachtformat in les* 2). Als we het eens zijn over hoe de opdracht werkt, ontbreekt dit veld. Als we een wijziging willen aanbrengen (als dit uiteraard is toegestaan voor een specifiek commando) in het werkingsalgoritme van het commando, dan is het noodzakelijk om een passend voorvoegsel te vormen. Een voorvoegsel is een waarde van één byte, waarvan de numerieke waarde het doel ervan bepaalt. De microprocessor herkent gespecificeerde waarde dat deze byte een voorvoegsel is, en verder werk Het microprogramma wordt uitgevoerd rekening houdend met de ontvangen instructies om de werking ervan te corrigeren. Terwijl we de stof in het boek bespreken, zullen we bekend raken met de meeste mogelijke voorvoegsels. Nu zijn we geïnteresseerd in een van hen: het voorvoegsel voor segmentvervanging (herdefinitie). Het doel ervan is om aan de microprocessor (en in wezen aan de firmware) aan te geven dat we het standaardsegment niet willen gebruiken. De ruimte voor een dergelijke herdefinitie is uiteraard beperkt. Het commandosegment kan niet opnieuw worden gedefinieerd, het adres is het volgende uitvoerbare opdracht wordt uniek bepaald door het paar cs: i р. Maar de stack- en datasegmenten zijn mogelijk. Dit is waar de “:” operator voor bedoeld is. De assembler-vertaler, die deze operator verwerkt, genereert het overeenkomstige segmentvervangingsvoorvoegsel van één byte. Bijvoorbeeld:
jmp metl ;bypass is vereist, anders wordt het ind-veld behandeld als een ander commando ind db 5 ;beschrijving van het gegevensveld in het commandosegment
mov al,cs:ind !Door het segment opnieuw te definiëren, kan het werken
;met gegevens gedefinieerd binnen een codesegment
Laten we doorgaan met het vermelden van de operators.
O Naamgevingsoperator voor structuurtype. (dot) zorgt er ook voor dat de compiler bepaalde berekeningen uitvoert als dit in een expressie voorkomt. We zullen deze operator in detail bespreken wanneer we het concept van complexe gegevenstypen introduceren in les 12.
O De operator voor het ontvangen van de segmentcomponent van het adres van een expressie, seg, retourneert het fysieke adres van het segment voor de expressie (Figuur 5.12), wat een label, een variabele, een segmentnaam, een groepsnaam of een symbolische naam.
Rekenkundige bewerkingen- TOEVOEGEN, SUB, MUL, DIV. Veel opcodes voeren berekeningen uit. Je kunt veel ervan herkennen aan hun naam: optellen (optellen), sub (aftrekken), mul (vermenigvuldigen), div (delen).
De add-opcode heeft de volgende syntaxis:
Bestemming, bron toevoegen
Voert de berekening uit: sink = sink + source.
Er zijn ook andere vormen:
ontvanger | bron | voorbeeld |
register | register | voeg ecx, edx toe |
register | geheugen | ecx toevoegen, dword ptr / ecx toevoegen, |
register | betekenis | voeg ea toe, 102 |
geheugen | betekenis | voeg dword ptr, 80 toe |
geheugen | register | voeg dword ptr, edx toe |
Deze opdracht is heel eenvoudig. Het voegt de bronwaarde toe aan de bestemmingswaarde en plaatst het resultaat in de bestemming. Andere wiskundige commando's:
Subontvanger, bron (ontvanger = ontvanger - bron)
mul vermenigvuldiger, vermenigvuldiger (vermenigvuldiger = vermenigvuldiger * vermenigvuldiger)
div deler (eax = eax/deler, edx = rest)
Omdat registers alleen gehele waarden kunnen bevatten (dat wil zeggen getallen, en geen drijvende komma), wordt het resultaat van de deling opgesplitst in een quotiënt en een rest. Afhankelijk van de grootte van de bron wordt het quotiënt nu opgeslagen in eax en de rest in edx:
* = Bijvoorbeeld: als dx = 2030h en ax = 0040h, dx: ax = 20300040h. Dx:ax is de waarde van dword, waarbij dx het hoge woord vertegenwoordigt en ax het lage woord. Edx:eax - quadword-waarde (64 bits), waarbij het hoogste dword in edx staat en het laagste dword in eax.
De bron van de splitsingsoperatie kan zijn:
- 8-bits register (al, ah, cl,...)
- 16-bits register (ax, dx, ...)
- 32-bits register (eax, edx, ecx...)
- 8-bits waarde uit geheugen (byte ptr)
- 16-bits waarde uit geheugen (woord ptr)
- 6a 32-bits geheugenwaarde (dword ptr)
De bron kan geen onmiddellijke waarde zijn, omdat de processor dan niet in staat zou zijn de grootte van de bronoperand te bepalen.
Logische bewerkingen met bits - OR, XOR, AND, NOT. Deze opdrachten werken met de bestemming en bron, met uitzondering van de opdracht "NOT". Elke bit in de bestemming wordt vergeleken met dezelfde bit in de bron, en afhankelijk van het commando wordt er een 0 of 1 in de bestemmingsbit geplaatst:
EN(logische AND) stelt de resultaatbit in op 1 als zowel de bronbit als de bestemmingsbit zijn ingesteld op 1.
OF(logische OR) stelt de resultaatbit in op 1 als een van de bits, de bronbit of de bestemmingsbit, is ingesteld op 1.
XOR(NOT OR) stelt de resultaatbit in op 1 als de bronbit verschilt van de bestemmingsbit.
NIET keert de bronbit om.
Voorbeeld:
Verplaatsingsbijl, 3406d
mov dx, 13EAh
xor bijl, dx
Ax = 3406 (decimaal), in binair getal - 0000110101001110.
Dx = 13EA (hexadecimaal), in binair getal - 0001001111101010.
Uitvoering XOR-operaties op deze stukjes:
Bron = 0001001111101010 (dx)
Ontvanger = 0000110101001110 (bijl)
Resultaat = 0001111010100101 (nieuwe waarde in ax)
De nieuwe waarde in ax na het uitvoeren van de opdracht is 0001111010100101 (7845 in decimaal, 1EA5 in hexadecimaal).
Nog een voorbeeld:
Verplaats ecx, FFFF0000h
niet exx
FFFF0000 in binair getal is -
Als je elk bit omkeert, krijg je:
, in hexadecimaal is dit 0000FFFF
Dit betekent dat ecx na de NOT-bewerking 0000FFFFh zal bevatten.
Verhogen/verlagen - INC/DEC. Er zijn 2 zeer eenvoudige commando's, DEC en INC. Deze instructies verhogen of verlagen de inhoud van het geheugen of een register met één. Zet gewoon:
Inc. registreren; registreren = registreren + 1
december register; registreren = registreren - 1
incl. dword ptr; de waarde in wordt met 1 verhoogd.
december dword ptr; de waarde in wordt met 1 verlaagd.
Een ander vergelijkingscommando is test. De Testinstructie voert een EN-bewerking uit op twee operanden en stelt de corresponderende vlaggen in of wist deze, afhankelijk van het resultaat. Het resultaat wordt niet opgeslagen. Test wordt gebruikt om bits te testen, bijvoorbeeld in een register:
Test eex, 100b
jnz-compensatie
Het jnz-commando springt als de derde bit van rechts in het eax-register is ingesteld. Heel vaak wordt het testcommando gebruikt om te controleren of een register nul is:
Test ecx, ecx
jz-compensatie
Het jz-commando springt als ecx = 0.
Een commando dat niets doet is nop. Deze opdracht doet absoluut niets (lege opdracht). Het kost alleen maar ruimte en tijd. Wordt gebruikt om ruimte in een codesegment te reserveren of om een programmavertraging te organiseren.
Uitwisseling van waarden - XCHG. Het XCHG-commando is ook vrij eenvoudig. Doel: uitwisseling van twee waarden tussen registers of tussen registers en geheugen:
Verplaats eax, 237 uur
mov ecx, 978 uur
xchg eax, ecx
als resultaat:
eax = 978 uur
ecx = 237 uur
Dat is het einde van de les. Ik hoop dat deze niet saai was. De volgende les gaat over subroutines.