Språkinstruksjoner for første forsamling (2023)

Jeg begynner å introdusere instruksjoner i denne delen. De vil bli introdusert etter hvert som vi trenger dem, og jeg vil ikke gi alle detaljene i instruksjonen. For å se detaljene, må du lese ARM-manualene,ARM Architecture Reference Manual ARMv7-A og ARMv7-R utgave[1]for 32-bit ogReferansehåndbok for arkitektur ARMv8, for ARMv8-A arkitekturprofil[2]for 64-bit. Når jeg skal beskrive en instruksjon, vil jeg i hovedsak bruke samme notasjon som i manualene for å gjøre det lettere for deg å lære å lese manualene. Notasjonen i ARMs manualer har en tendens til å variere litt mellom manualene. En forskjell er at jeg vil bruke '%' for å legge til kommentarene mine. Jeg utelater også noen av de detaljerte alternativene for mange av instruksjonene fordi de ikke gjelder for programmeringen som brukes i denne boken.

ARM gir faktisk et andre instruksjonssett kalt "Thumb." Det gir mulighet for enten 16-biters eller 32-biters instruksjoner. Det kan brukes til å forbedre effektiviteten. Å bruke Thumb er utenfor omfanget av denne boken, men du vil se det nevnt i beskrivelsen av noen instruksjoner i ARM-manualene.

Underseksjon 9.2.1 Noen notasjon

Syntaksen som ARM bruker for sitt assemblerspråk kallesUnified Assembler Language(UAL). Vår montør,som, gjenkjenner UAL-syntaksen hvis du bruker assembler-direktivene jeg brukte iOppføring 9.1.3for å identifisere ARM-modellen. Dessverre er versjonen avgccfor øyeblikket (august 2016) som kjører på Raspbian bruker pre-UAL syntaks. Forskjellene er små. For eksempel, det kompilatorgenererte assemblyspråket (Oppføring 9.1.2) bruker en '#’ tegn for å prefiksere hver bokstavelig verdi:

str fp, [sp, #-4]!

Men UAL-syntaksen spesifiserer at#' tegnet er valgfritt, så iOppføring 9.1.3Jeg skrev:

str fp, [sp, -4]! @ lagre innringerrammepekeren

Jeg vil ikke bruke '#’ karakter for umiddelbare verdier i eksemplene mine i denne boken. Jegsterkt oppfordrerdu kan bruke UAL-syntaksen når du skriver dine egne assembly-språkprogrammer. Dette blir veldig viktig når vi kommer til flyttallinstruksjonene iAvsnitt 16.7. Det er der du vil se de største forskjellene mellom UAL- og pre-UAL-syntaksene.

Den generelle notasjonen som brukes til å forklare instruksjoner er:

  • Store bokstaver representerer tegnene du må bruke, selv om du kan skrive dem med små bokstaver.

  • Små bokstaver representerer steder der du må oppgi den aktuelle teksten.

  • Vinkelparenteser, <...>, er steder der du må oppgi riktig verdi (uten «<» og «>».

  • Krøllete klammeparenteser, {...} representerer valgfrie elementer (uten '{' og '}').

  • den '#’ prefiks for konstante verdier vises, men det er valgfritt når du bruker.syntax unifieddirektiv.

Underseksjon 9.2.2 Tilstandskoder

Som nevnt iAvsnitt 8.2, de fleste AARCH32 ARM-instruksjoner har et alternativ som lar deg spesifisere at det bare vil bli utført hvis det finnes en spesifikk innstilling av tilstandsflaggene. Disse innstillingene uttrykkes ved å legge til en mnemonikkTilstandskodetil instruksjonen mnemonic. Disse kodene vises iTabell 9.2.1. «kond”-kolonnen viser maskinkodedelen av instruksjonen, som vil bli beskrevet iAvsnitt 11.3.3.

kondMnemonicHeltallFlyteTilstand Flagg
\(\binær{0000}\)EQLikLikZ == 1
\(\binær{0001}\)NEIIkke likIkke likZ == 0
\(\binær{0010}\)CSBæresettStørre enn, lik eller uordnetC == 1
\(\binær{0011}\)CCBær klartMindre ennC == 0
\(\binær{0100}\)MINegativMindre ennN == 1
\(\binær{0101}\)PLPositiv, eller nullStørre enn, lik eller uordnetN == 0
\(\binær{0110}\)VSFlyteUordnetV == 1
\(\binær{0111}\)VCIngen overløpIkke uordnetV == 0
\(\binær{1000}\)HIUsignert høyereStørre enn, eller uordnetC == 1 OG Z == 0
\(\binær{1001}\)LSUsignert lavere eller sammeMindre enn eller likC == 0 ELLER Z == 1
\(\binær{1010}\)GESignert større enn eller likStørre enn eller likN == V
\(\binær{1011}\)LTSignert mindre ennMindre enn, eller uordnetN != V
\(\binær{1100}\)GTSignert større ennStørre ennZ == 0 OG N == V
\(\binær{1101}\)DESignert mindre enn eller likMindre enn, lik eller uordnetZ == 1 ELLER N != V
\(\binær{1110}\)ingen (AL)AlltidAlltidNoen

Underseksjon 9.2.3 Skiftalternativer

Mange ARM-instruksjoner inkluderer et alternativ for å skifte en av dataverdiene under operasjonen som instruksjonen utfører.Tabell 9.2.2viser mnemonkodene som brukes og deres respektive effekt.

KonstantVariabelEffekt
LSL #LSL Logisk skift venstre \(n\) biter. \(1 \le n \le 31\text{.}\)
LSR #LSR Logisk skift høyre \(n\) biter. \(1 \le n \le 32\text{.}\)
ASR#ASR Aritmetisk skift høyre \(n\) biter. \(1 \le n \le 32\text{.}\)
ROR #ROR Roter høyre \(n\) biter. \(1 \le n \le 31\text{.}\)
RRXRoter en bit til høyre, med forleng. Bits [\(31:1\)] forskyves én bit til høyre, og bæreflagget blir forskjøvet til bit [\(31\)].

hvor:

Logisk skifte

Nuller skrives inn i de ledige bitposisjonene.

Aritmetisk skift til høyre

Verdien i høyordensbiten, \(\binær{0}\) eller \(\binær{1}\tekst{,}\) kopieres til hver av de ledige bitposisjonene, og bevarer dermed tegnet til verdien blir forskjøvet.

Roter til høyre

Ettersom bitene av lav orden renner fra høyre side (laverekkelige posisjoner), roteres de rundt for å flyte inn i høyordensposisjonene når verdien roteres.

De fleste instruksjoner som tillater skiftalternativet lar deg spesifisere skiftbeløpet, \(n\tekst{,}\) enten som en konstant eller som en variabel i et register. DeRRXoperasjonen er alltid en bit.

Som et eksempel på hvordan skiftende syntaks brukes, de tre instruksjonene:

mov r0, 12mov r1, 60add r2, r0, r1, lsl 2

ville lagre \(252\) ir2. De to første instruksjonene lagrer \(12\) ir0og \(60\) inr1. Delsl #2i den tredje instruksjonen skifter verdien innr1to bitposisjoner til venstre, multipliser det med \(4\tekst{.}\) Dette resultatet, \(240\text{,}\) legges til verdien ir0, og resultatet lagres ir2. Som du vil se i beskrivelsen avLegg tilnedenfor, verdiene ir0ogr1forbli uendret.

Hvis algoritmen din krever at mengden av skiftet er under programkontroll, vil du først lagre skiftbeløpet i et register. For eksempel:

mov r0, 12mov r1, 60mov r3, 2add r2, r0, r1, lsl r3

ville gi samme resultatr2som ovenfor. Men programmet ditt kan endre verdien ir3for å oppnå et annet skiftbeløp.

Underseksjon 9.2.4 Første instruksjoner

Selv om programmet iOppføring 9.1.1gjør ingenting, det krever seks instruksjoner.

MOV

Kopierer (flytter) en verdi inn i et register.

MOV{S}{} , # % immediateMOV{S}{} ,  % register
  • Hvis 'S' er tilstede, oppdateres tilstandsflaggene i henhold til verdien som flyttes. Hvis fraværende, endres ikke tilstandsflaggene.

  • er tilstandskoden,Tabell 9.2.1.

  • spesifiserer destinasjonsregisteret, oger kilderegisteret.

  • \(-257 \le const \le +256\text{,}\) eller \(const = +256, +260, +264, \ldots, +65280\text{,}\) eller \(const = - 261, -265, \ldots, -65281\text{.}\) Denne odde sekvensen av verdier vil bli forklart iAvsnitt 11.3.3.

I "umiddelbar" form, verdien aver lagret i. I "register"-skjemaet, verdien ier kopiert til. Det er også en skiftversjon, som vil bli forklart iAvsnitt 14.3.

Faktisk bruker ikke montørenmovinstruksjon for negative verdier i umiddelbar form. Hvis du bruker en negativ konstant, trekker assembleren \(1\) fra den absolutte verdien, bruker resultatet som konstanten og erstattermvninstruksjon. Hvis du bruker en negativ konstant for den umiddelbare formen avmvninstruksjon, utfører assembleren den samme beregningen og erstattermovinstruksjon.

Så følgende to instruksjoner:

mov r3, 1mov r4, -2

gjør det samme som:

mov r3, 1mvn r4, 1

Og følgende to instruksjoner:

mvn r5, 1mvn r6, -2

er de samme som:

mov r5, -2mov r6, 1

Resultatet er at du ganske enkelt kan bruke både positive og negative konstanter medmovinstruksjon, som jegoppfordrer deg sterkt til å gjøre, og montøren vil gjøre det riktige. Men hvis du leser kompilator-generert assembly-språk, eller du brukerdemonterekommando inngdb, kan du semvninstruksjonen brukes, så jeg vil beskrive den her.

MVN

Kopierer (flytter) komplementet (bitvis IKKE) av en verdi inn i et register.

MVN{S}{} , # % immediateMVN{S}{} , {, } % registerMVN(S}{} , ,   % registerforskyvet register
  • Hvis 'S' er tilstede, oppdateres tilstandsflaggene i henhold til verdien som flyttes. Hvis fraværende, endres ikke tilstandsflaggene.

  • er tilstandskoden,Tabell 9.2.1.

  • spesifiserer destinasjonsregisteret, oger kilderegisteret.inneholder skiftbeløpet i skjemaet «registerflyttet register».

  • \(-257 \le const \le +256\text{,}\) eller \(const = +256, +260, +264, \ldots, +65280\text{,}\) eller \(const = - 261, -265, \ldots, -65281\text{.}\) Denne odde sekvensen av verdier vil bli forklart iAvsnitt 11.3.3

  • oger forklart iAvsnitt 9.2.3

I "umiddelbar" form, en kopi av bitvise IKKE aver lagret i. I "register" og "register-forskyvde register"-formene, er bitvis IKKE av verdien ier kopiert til. Hvis et skifte er spesifisert, vil verdien iforskyves med den angitte mengden før bitvis NOT beregnes, og resultatet lagres i. Verdiene ioger uendret.

LEGG TIL

Legger til to heltall.

ADD{S}{} {,} , # % immediateADD{S}{} {,} , {, } % registerADD{S}{} {,} , ,   % registerforskyvet register
  • Hvis 'S' er tilstede, oppdateres tilstandsflaggene i henhold til verdien som flyttes. Hvis fraværende, endres ikke tilstandsflaggene.

  • er tilstandskoden,Tabell 9.2.1.

  • spesifiserer destinasjonsregisteret, ogoger kilderegistrene.inneholder skiftbeløpet i skjemaet «registerflyttet register».

  • \(-257 \le const \le +256\text{,}\) eller \(const = +256, +260, +264, \ldots, +65280\text{,}\) eller \(const = - 261, -265, \ldots, -65281\text{.}\) Denne odde sekvensen av verdier vil bli forklart iAvsnitt 11.3.3

  • oger forklart iAvsnitt 9.2.3

I "umiddelbar" form,legges til verdien i. I skjemaene "register" og "registerforskyvet register" vises verdien ilegges til verdien i. Hvis et skifte er spesifisert, vil verdien iforskyves med spesifisert mengde før tilsetningen utføres. Hviser tilstede resultatet lagres der oger uendret. Hvis ikke, lagres resultatet i. Verdiene ioger uendret.

UNDER

Trekker fra to heltall.

SUB{S}{} {,} , # % immediateSUB{S}{} {,} , {, } % registerSUB{S}{} {,} , ,   % registerforskyvet register
  • Hvis 'S' er tilstede, oppdateres tilstandsflaggene i henhold til resultatene av subtraksjonen. Hvis fraværende, endres ikke tilstandsflaggene.

  • er tilstandskoden,Tabell 9.2.1.

  • spesifiserer destinasjonsregisteret, ogoger kilderegistrene.inneholder skiftbeløpet i skjemaet «registerflyttet register».

  • \(-257 \le const \le +256\text{,}\) eller \(const = +256, +260, +264, \ldots, +65280\text{,}\) eller \(const = - 261, -265, \ldots, -65281\text{.}\) Denne odde sekvensen av verdier vil bli forklart iAvsnitt 11.3.3.

  • oger forklart iAvsnitt 9.2.3

I den "umiddelbare" formentrekkes fra verdien i. Hviser fraværende, lagres forskjellen i. Hviser tilstede, lagres forskjellen der ogforblir uendret.

I skjemaene "register" og "registerforskyvet register" vises verdien itrekkes fra verdien i. Hviser fraværende, lagres forskjellen i. HvisRder tilstede, lagres forskjellen der ogforblir uendret. Hvis et skifte er spesifisert, vil verdien iforskyves med det angitte beløpet før det trekkes fra verdien i, og resultatet lagres i.

BX

Forgreninger til et annet sted i programmet. Adressen til stedet er i et register. Tillater også bytte mellom ARM- og Thumb-instruksjonssett.

BX{} 

Verdien iRmregister flyttes tilpc, og får dermed programkjøring til å forgrene seg til det stedet. Bit \(0\) spesifiserer instruksjonssettet: \(\binær{0}\) for ARM, \(\binær{1}\) for Thumb. Verdien iRmendres ikke.

LDR

Laster et ord fra minnet inn i et register.

LDR , 
  • er tilstandskoden,Tabell 9.2.1.

  • er destinasjonsregisteret, oger basisregisteret.

  • er en merket minneadresse.

  • er et fortegnet heltall i området \(-2048 \ldots +2047\text{.}\)

Minneadressen for å laste ordet fra bestemmes på følgende måte (nærmere forklart iAvsnitt 11.1):

  • Etikettskjemaet bruker adressen som tilsvarer.

  • I Offset-skjemaet, det signerte heltall,, legges til verdien i basisregisteret,, er verdien på denne adressen lastet inn, men basisregisteret endres ikke.

  • I det forhåndsindekserte skjemaet legges det signerte heltall til verdien i basisregisteret,, oppdateres basisregisteret til den nye adressen, og deretter lastes verdien på denne nye adressen inn.

  • I etterindeksert skjema, verdien i basisregisteret,, brukes som en adresse, og verdien på den adressen lastes inn. Deretter legges det signerte heltall til verdien i basisregisteret.

STR

Lagrer et ord fra et register i minnet.

STR , 
  • er tilstandskoden,Tabell 9.2.1.

  • er kilderegisteret, oger basisregisteret.

  • er en merket minneadresse.

  • er et fortegnet heltall i området \(-2048 \ldots +2047\text{.}\)

Minneadressen for å lagre ordet på bestemmes på følgende måte (nærmere forklart iAvsnitt 11.1):

  • Etikettskjemaet bruker adressen som tilsvarer.

  • I Offset-skjemaet, det signerte heltall,, legges til verdien i basisregisteret,, verdien ier lagret på denne adressen, men baseregisteret endres ikke..

  • I det forhåndsindekserte skjemaet legges det signerte heltall til verdien i basisregisteret,, oppdateres basisregisteret til den nye adressen, og deretter verdien inner lagret på denne adressen.

  • I etterindeksert skjema, verdien i basisregisteret,, brukes som adresse, og verdien ier lagret på den adressen. Deretter legges det signerte heltall til verdien i basisregisteret.

Underseksjon 9.2.5 Kodegjennomgang

Vi kan nå gå gjennom koden innOppføring 9.1.3og forklar formålet med hver instruksjon. De to linjene:

hoved: str fp, [sp, -4]! @ lagre innringerrammepekeren

er bare én instruksjon. Plassering av etiketten på sin egen (ellers blank) linje knytter etiketten til neste instruksjon. Dette gjør det lettere å bruke lengre etiketter, noe som ofte forbedrer kodens lesbarhet.

Fra beskrivelsen avstr, bestemmer denne instruksjonen først en minneadresse ved å trekke \(4\) fra adressen ispregistrere og oppdaterespregistrere deg på denne nye adressen. Den lagrer deretter adressen ifpregistrere deg i minnet på denne nye adressen.

den '!’ karakter etter[sp, -4]konstruksjon forårsaker verdien ispregister som skal endres med den numeriske verdien (\(-4\)). Så verdien isper \(4\) mindre etter at denne instruksjonen er utført. Årsakene til dette vil bli forklart iAvsnitt 10.2–10.3.

Programmer som kjøres i C-runtime-miljøet, gjør omfattende bruk av stabelen. Hver funksjon i programmet har sitt eget område av stabelen, kjent som enStabelramme. Funksjonen holder styr på hvor rammen er ved å opprettholde minneadressen ifpregistrere. Du vil lære alt om stabler og stablerammer iAvsnitt 10.2, men foreløpig er det viktige å vite at denne instruksjonen lagrer den anropende funksjonens rammepeker og etablerer sin egen rammepeker.

Du vil lære iAvsnitt 10.3at hver funksjon skal ha et område på stabelen til eget bruk. Funksjonen trenger et referansepunkt til det området, som er en adresse som er lagret iRammepekerregistrere. Den forrige instruksjonen lagret anropsfunksjonens rammepeker på stabelen, og denne instruksjonen,

legg til fp, sp, 0 @ etablere vår rammepeker

etablerer en rammepeker for denne funksjonen. Ja,mov fp,spville gi nøyaktig de samme resultatene, men de fleste meningsfulle funksjoner vil lagre andre elementer på stabelen, og rammepekeren må stilles inn tilsvarende. Igjen vil du se hvordan dette fungererAvsnitt 10.3.

Denne funksjonen returnerer \(0\) til den kallende funksjonen (som er i operativsystemet), og den bruker et register,r3, som en lokal variabel for å holde denne verdien:

mov r3, 0 @ return 0;

Operativsystemet krever at en returverdi er i registeretr0, så programmet flytter det dit:

mov r0, r3 @ returverdier går i r0

Som du vil lære iAvsnitt 10.2, er det viktig å rydde opp i all bruk av stabelen før du går tilbake til ringefunksjonen. Husk at programmet opprettet en rammepeker i forhold til stabelpekeren da funksjonen først startet. Den må flytte stabelpekeren tilbake til der den var da funksjonen begynte:

sub sp, fp, 0 @ restore stack pointer

Den neste oppryddingsoperasjonen er å gjenopprette rammepekeren til den som brukes av den anropende funksjonen:

ldr fp, [sp], 4 @ gjenopprett innringerens rammepeker

Se nøye på instruksjonen i begynnelsen av funksjonen som lagret den anropende funksjonens rammepeker:

str fp, [sp, -4]! @ lagre innringerrammepekeren

Når du sammenligner den med den som gjenoppretter den, kan du se at du lagrer denforhåndsnedsettelserstabelpekeren før du lagrer den, og gjenoppretting av rammepekeren gjøres ved å hente adressen og deretteretterøkningstabelpekeren. Jeg tenker på disse to operasjonene som litt som parenteser som omgir et begrep i en algebraisk ligning.

Nå som stabelen er ryddet opp, går funksjonen tilbake til kallefunksjonen. Instruksjonen som kalte denne plasserte returadressen i lenkeregisteret,lr. Så alt denne funksjonen trenger å gjøre er å forgrene seg til adressen ilrregistrere:

bx lr @ tilbake til den som ringer

Du vil lære hvordan dette fungererKapittel 13.

Top Articles
Latest Posts
Article information

Author: Geoffrey Lueilwitz

Last Updated: 24/05/2023

Views: 5305

Rating: 5 / 5 (80 voted)

Reviews: 87% of readers found this page helpful

Author information

Name: Geoffrey Lueilwitz

Birthday: 1997-03-23

Address: 74183 Thomas Course, Port Micheal, OK 55446-1529

Phone: +13408645881558

Job: Global Representative

Hobby: Sailing, Vehicle restoration, Rowing, Ghost hunting, Scrapbooking, Rugby, Board sports

Introduction: My name is Geoffrey Lueilwitz, I am a zealous, encouraging, sparkling, enchanting, graceful, faithful, nice person who loves writing and wants to share my knowledge and understanding with you.