Dette er mange spørsmål samtidig, jeg vil svare på minst noen av dem. Men vær så snill å ikke, med mindre du selv skriver en monterings- eller demonteringsenhet, bør du egentlig ikke gå inn på de blodige detaljene til hver eneste bit. Og med mindre du har gjort mye programmering i assembler, og lest og forstå demontert kode, bør du ikke engang prøve å skrive en assembler eller demonterer selv.
Ikke misforstå meg, skriv din egen assembler. kan være en interessant og lærerik opplevelse. Men de blodige detaljene er ikke det første du bør lære å forstå konseptet med en prosessor og dens monteringsspråk.
Det ut av veien:
Det spiller ingen rolle om 16-biters forskyvning er signert eller usignert. Hvis det renner over, renner det over, og det er alltid kuttet til 16 bit. Så hvis du legger til offset 0xfff0
til adressen 0x1234
, får du 0x1224
som resultat. Det spiller ingen rolle om du tolker dette som at 0xfff0
er lik -0x0010
, så vi trekker 0x10
fra 0x1234
"eller" legg til 0xfff0
til 0x1234
, få 0x11224
, og fjern overløpsbiten ". Eller hvis du legger til 0x89ab
og 0x89ab
, får du 0x1356
. 0x11356
med overløpsbit fjernet, for å være nøyaktig. Det spiller ingen rolle om du tar 0x89ab
som (desimal) 35243
, eller -30293
. De mulige resultatene - 35243 + 35243 = 70486
, 35243-30293 = 4950
, -30293-30293 = -60586
- har alle det samme representasjon - 0x1356
- i 16 biters heks.
Ja, mod = 0b00
og R / M = 0b110
er bare en indirekte adresse. mov cx, [1234h]
og mov cx, WORD PTR ds: 0x1234
er to måter å skrive det samme på. Merk jeg korrigerte cl
til cx
; om du bruker et 8-biters eller 16-biters register er en del av instruksjonen, ikke av adresseringsmodus. Hvis du har et register, er størrelsen tydelig fra registernavnet, men i en instruksjon som mov [1234h], 5
, vet du ikke om 5 er en byte, ord eller dword verdi. mov word ptr ds: 1234h, 5
gjør dette klart.
Ja, alle adresser er i forhold til det valgte segmentet - ds
i de fleste tilfeller, ss hvis du bruker bp
, og det gitte registeret hvis du bruker et eksplisitt overstyringsprefiks. Merk at det ikke var noen måte å indeksere i forhold til sp
i 16-bits modus, og bp
, hvis det i det hele tatt ble brukt, var alltid det første registret i R1 + R2
kombinasjoner, som tvinger ss
til å brukes med bp
. I 32-biters modus er flere kombinasjoner mulig, og [ebp + ebx]
bruker ss
, mens [ebx + ebp]
bruker ds. (Imidlertid betyr 32-biters modus også beskyttet modus, og i alle tilfeller unntatt de mest patologiske tilfellene bruker operativsystemene de samme velgerverdiene for ss
og ds
og cs
også. Se nedenfor).
Så [BP + SI + 10h]
betyr [SS: BP + SI + 10h]
, som betyr (SS<<4 + BP + SI + 10h)
på adressebusslinjene. Merk at disse 16-biters prosessorene hadde 20 bits på adressebussen, noe som betyr at overløp kan oppstå, og overløpsbiten ble også kuttet av. Så, FFF0: 0010 og 0000: 0000 er faktisk den samme adressen på en 8086 - 00000
- siden bit 20 fra 100000
ble avskåret. På en 32-biters prosessor eksisterer denne biten 20 faktisk. Noe som betyr at noen programmer, som brukte den mekanismen for å tilsløre kopibeskyttelsen, sluttet å virke da 80386 ble introdusert. Eller ville hatt, hvis IBM ikke hadde oppfunnet en mekanisme rundt den - den skumle A20-porten. Google for det hvis du er tilbøyelig til å gjøre det.
Prefikser 66h
og 67h
- spør noen andre. Selv om jeg har lest og skrevet samlerkode i mer enn 20 år, hadde jeg aldri grunn til å lære forholdet mellom hex-byte og prosessorinstruksjoner. Se ovenfor. Jeg antar at det er to unntak: 90h
er NOP
, og cch
er INT3
. Og bytesekvenser som PQRST
, 50h 51h 52h 53h 54h
er push-register-instruksjoner, noe som gjør dem nyttige for å finne prosedyren starter.
I 32 bit modus, er forskyvningene like "signerte" eller "usignerte" som i 16-biters modus. Bare behandle dem som 32-biters verdier som blir lagt til, noe som kan resultere i et overløp som blir kastet.
Og selvfølgelig blir disse verdiene også vurdert i forhold til "segmentet". Bare den 32 biten innebærer beskyttet modus, som betyr at segmentene kalles selektorer, har forskjellig semantikk og blir generelt ignorert av de fleste applikasjonsprogrammerere.
Et ord til segmenter, hvorfor de hadde betydning, og ikke gjør det ( normalt) betyr noe mer:
Først, da 8086 ble introdusert, var det ment å erstatte den eldre 8080-prosessoren (og Z80, som var fra et annet selskap, kompatibel med 8080, men bedre og mer vellykket). 8080 hadde 64 kB maksimalt helt, så programmerere måtte presse alt - kode, data, stabling - inn i de 64 kB, og mesteparten av tiden ble en del av disse 64 kB brukt av maskinvare, så du hadde enda mindre .
Da 8086 og segmentregistrene ble designet, tenkte nok noen på intel "Vi gir folk mye mer plass - 64 kb kode OG 64 kb data OG 64 kb stabel, slik at programmer kan være mye større; vi kan multitaske mellom flere programmer, operativsystemet vil administrere segmentregistrene for å tildele plass til hvert program, og hvert program kan være så mye større enn i dag ".
Men faktisk, programmer ble raskt mye større, så ideen "segmentregister skal bare vedrøre operativsystemet" ble aldri brukt. I stedet måtte programmene sjonglere med seg selv, noe som var en viktig PITA for alle fra kompilatørbyggere til applikasjonsprogrammerere, og alle måtte lære - og vite - om dem for å få gjort noe.
Da 32-biters prosessorer startet, med 4 GB adresserbar på en lineær måte, ble segmenter plutselig store nok til at applikasjonsprogrammerere ikke lenger måtte bry seg om dem. I disse dager er det bare operativsystemets oppgave å sjonglere segmenter og tildele dem til minnekart, og på grunn av beskyttet modus kunne ikke programmene endre dem selv om de ville. Det som de fleste operativsystemer gjør, er å gi en enkelt flat minneblokk til programmet, og ha cs
, ds
, es
og ss
kart til den blokken identisk. Søknaden din ser bare 4 GB adresserbart minne (ikke alt dette trenger imidlertid å være virkelig kartlagt til fysisk minne), og det betyr ikke noe for applikasjonen lenger hvilket segmentregister det bruker - [DS: 1234]
er det samme som [ES: 1234]
er det samme som [SS: 1234]
er det samme som [CS: 1234]
.
Unntaket fra dette er de nye registrene FS
og GS
, for eksempel bruker Windows FS
for Strukturert unntakshåndtering, og Linux bruker GS
for Tråd lokal lagring. Disse segmentene er IKKE tilordnet standard 4 GB-blokken, men et program vil ikke legge merke til det, siden ingen av disse registrene noen gang blir brukt uten et eksplisitt prefiks. (Merk ES
kan ikke brukes på samme måte, siden instruksjoner som stos [bwd]
og movs [bwd]
bruker ES : EDI
som standard).