Lai saprastu, kā darbojas datori, ir nepieciešama izpratne par to, kā tie ir organizēti, kā tie šķietami darbojas ļoti zemā līmenī, lai saprastu, kā darbojas programma asemblera valodā. Visvienkāršākajā līmenī datoriem ir trīs galvenās daļas:
- galvenā atmiņa jeb RAM, kurā glabājas dati un instrukcijas,
- procesors, kas apstrādā datus, izpildot instrukcijas, un
- ievade un izvade (dažkārt saīsināti I/O), kas ļauj datoram sazināties ar ārpasauli un uzglabāt datus ārpus galvenās atmiņas, lai vēlāk tos varētu saņemt atpakaļ.
Galvenā atmiņa
Lielākajā daļā datoru atmiņa ir sadalīta baitos. Katrā baitā ir 8 biti. Katram baitam atmiņā ir arī adrese, kas ir skaitlis, kurš norāda, kur atmiņā atrodas baits. Pirmajam baitam atmiņā ir adrese 0, nākamajam ir adrese 1 utt. Atmiņas sadalīšana baitos padara to adresējamu baitos, jo katram baitam ir unikāla adrese. Bajtu atmiņas adreses nevar izmantot, lai atsauktos uz vienu baita bitu. Bajts ir mazākais atmiņas gabals, ko var adresēt.
Lai gan adrese attiecas uz konkrētu atmiņas baitu, procesori ļauj izmantot vairākus atmiņas baitus pēc kārtas. Visbiežāk šī funkcija tiek izmantota, lai izmantotu 2 vai 4 baitus rindā skaitļa, parasti veselā skaitļa, attēlošanai. Dažreiz veselu skaitļu attēlošanai izmanto arī atsevišķus baitus, bet, tā kā tie ir tikai 8 bitu gari, tajos var saglabāt tikai 2 8vai 256 dažādas iespējamās vērtības. Izmantojot 2 vai 4 baitus rindā, dažādu iespējamo vērtību skaits attiecīgi ir 2 16, 65536 vai 2 32, 4294967296.
Kad programma izmanto baitu vai vairākus baitus rindā, lai atveidotu kaut ko, piemēram, burtu, skaitli vai ko citu, šos baitus sauc par objektu, jo tie visi ir daļa no vienas un tās pašas lietas. Lai gan visi objekti tiek glabāti vienādos atmiņas baitos, pret tiem izturas tā, it kā tiem būtu "tips", kas norāda, kā baiti būtu jāsaprot: vai nu kā vesels skaitlis, vai kā rakstzīme, vai kāds cits tips (piemēram, necila vērtība). Mašīnkodu var uzskatīt arī par tipu, ko interpretē kā instrukcijas. Tipa jēdziens ir ļoti, ļoti svarīgs, jo tas nosaka, ko ar objektu drīkst un ko nedrīkst darīt un kā interpretēt objekta baitus. Piemēram, nav atļauts pozitīva skaitļa objektā saglabāt negatīvu skaitli, un nav atļauts veselā skaitlī saglabāt daļu.
Adrese, kas norāda uz (ir daudzbitu objekta adrese), ir šī objekta pirmā baita adrese - baita, kuram ir zemākā adrese. Papildus jāpiebilst, ka pēc adreses nevar noteikt objekta tipu vai pat lielumu. Patiesībā, apskatot objektu, jūs pat nevarat noteikt tā tipu. Asamblēšanas valodas programmai ir jāseko līdzi tam, kurās atmiņas adresēs atrodas kādi objekti un cik lieli ir šie objekti. Programma, kas to dara, ir droša attiecībā uz tipu, jo tā ar objektiem veic tikai tādas darbības, kas ir drošas attiecībā uz to tipu. Programma, kas to nedara, iespējams, nedarbosies pareizi. Ievērojiet, ka vairums programmu patiesībā nepārprotami neuzkrāj objekta tipu, tās tikai konsekventi piekļūst objektiem - viens un tas pats objekts vienmēr tiek uzskatīts par vienu un to pašu tipu.
Procesors
Procesors izpilda (izpilda) instrukcijas, kas kā mašīnkods ir saglabātas galvenajā atmiņā. Lielākajai daļai procesoru ir ne tikai piekļuve atmiņai, bet arī dažas nelielas, ātras, fiksēta lieluma vietas, kurās tiek glabāti objekti, ar kuriem pašlaik tiek strādāts. Šīs vietas sauc par reģistriem. Procesori parasti izpilda trīs veidu instrukcijas, lai gan dažas instrukcijas var būt šo veidu kombinācija. Tālāk ir sniegti daži katra tipa piemēri x86 asamblēšanas valodā.
Instrukcijas, kas lasa vai raksta atmiņā
Šāda x86 asamblēšanas valodas instrukcija nolasa (ielādē) 2 baitu objektu no baita ar adresi 4096 (0x1000 heksadecimālā sistēmā) 16 bitu reģistrā ar nosaukumu 'ax':
mov ax, [1000h]
Šajā asamblēšanas valodā kvadrātiekavas ap skaitli (vai reģistra nosaukumu) nozīmē, ka šis skaitlis ir jāizmanto kā izmantojamo datu adrese. Adreses izmantošanu, lai norādītu uz datiem, sauc par indirekciju. Šajā nākamajā piemērā bez kvadrātiekavām citā reģistrā, bx, faktiski tiek ielādēta vērtība 20.
mov bx, 20
Tā kā netika izmantota indirekcija, reģistrā tika ievietota pati faktiskā vērtība.
Ja operandi (lietas, kas atrodas aiz mnemonikas) parādās apgrieztā secībā, instrukcija, kas ielādē kaut ko no atmiņas, tā vietā to ieraksta atmiņā:
mov [1000h], ax
Šajā gadījumā atmiņa adresē 1000h iegūst vērtību ax. Ja šo piemēru izpilda uzreiz pēc iepriekšējā piemēra, tad 2 baiti adresēs 1000h un 1001h būs 2 baiti veselā skaitļa ar vērtību 20.
Instrukcijas, kas veic matemātiskas vai loģiskas darbības.
Dažas instrukcijas veic tādas darbības kā atņemšana vai loģiskās operācijas, piemēram, ne:
Iepriekš šajā rakstā minētais mašīnkoda piemērs būtu šāds mašīnkoda piemērs asamblēšanas valodā:
pievienot cirvi, 42
Šeit 42 un ax tiek saskaitīti kopā, un rezultāts tiek saglabāts atpakaļ ax. Arī x86 asamblejā ir iespējams šādi apvienot piekļuvi atmiņai un matemātisku darbību:
pievienot ax, [1000h]
Šī instrukcija summē 2 baitu veselā skaitļa vērtību, kas saglabāta 1000h, ar ax un saglabā atbildi ax.
vai ax, bx
Šī instrukcija aprēķina reģistru ax un bx satura vai un saglabā rezultātu atpakaļ reģistrā ax.
Instrukcijas, kas izlemj, kāda būs nākamā instrukcija.
Parasti instrukcijas parasti tiek izpildītas tādā secībā, kādā tās parādās atmiņā, kas ir secība, kādā tās ir ierakstītas asemblera kodā. Procesors tās izpilda vienu pēc otras. Tomēr, lai procesori varētu veikt sarežģītas darbības, tiem ir jāizpilda dažādas instrukcijas atkarībā no tā, kādi dati tiem ir doti. Procesoru spēju izpildīt dažādas instrukcijas atkarībā no kaut kā iznākuma sauc par sazarošanos. Instrukcijas, kas izlemj, kādai jābūt nākamajai instrukcijai, sauc par zaru instrukcijām.
Šajā piemērā pieņemsim, ka kāds vēlas aprēķināt krāsas daudzumu, kas būs nepieciešams, lai nokrāsotu kvadrātu ar noteiktu malas garumu. Tomēr, ņemot vērā apjomradītus ietaupījumus, krāsu veikals nepārdos viņam mazāk krāsas, nekā nepieciešams 100 x 100 kvadrātu krāsošanai.
Lai noskaidrotu, cik daudz krāsas viņiem būs nepieciešams, pamatojoties uz kvadrāta garumu, ko viņi vēlas nokrāsot, viņi izstrādā šo soļu kopumu:
- atņem 100 no malas garuma
- ja atbilde ir mazāka par nulli, iestatiet malas garumu uz 100.
- reizina malas garumu ar sevi
Šo algoritmu var izteikt ar šādu kodu, kur ax ir malas garums.
mov bx, ax sub bx, 100 jge turpināt mov ax, 100 turpināt: mul ax
Šis piemērs ievieš vairākas jaunas lietas, taču pirmie divi norādījumi ir labi pazīstami. Tās kopē ax vērtību bx un pēc tam atņem 100 no bx.
Viens no jaunajiem elementiem šajā piemērā tiek saukts par etiķeti - jēdzienu, kas vispār ir sastopams asamblēšanas valodās. Etiķetes var būt jebkas, ko programmētājs vēlas (ja vien tas nav instrukcijas nosaukums, kas asembleri mulsinātu). Šajā piemērā etiķete ir "continue". Asembleris to interpretē kā instrukcijas adresi. Šajā gadījumā tā ir mult ax adrese.
Vēl viens jauns jēdziens ir karodziņi. Daudzas x86 procesoru instrukcijas procesorā nosaka "karodziņus", kurus nākamā instrukcija var izmantot, lai izlemtu, ko darīt. Šajā gadījumā, ja bx bija mazāks par 100, sub uzstādīs karodziņu, kas norāda, ka rezultāts ir mazāks par nulli.
Nākamā instrukcija ir jge, kas ir saīsinājums no 'Jump if Greater than or Equal to'. Tā ir atzarojuma instrukcija. Ja procesora karodziņi norāda, ka rezultāts ir lielāks vai vienāds ar nulli, tā vietā, lai vienkārši pārietu uz nākamo instrukciju, procesors pāries uz instrukciju ar turpinājuma marķējumu, kas ir mul ax.
Šis piemērs darbojas labi, bet tas nav tas, ko rakstītu vairums programmētāju. Atņemšanas instrukcija pareizi iestatīja karodziņu, bet tā arī maina vērtību, ar kuru tā darbojas, tāpēc bija nepieciešams nokopēt ax uz bx. Lielākā daļa asamblēšanas valodu pieļauj salīdzināšanas instrukcijas, kas nemaina nevienu no tām nodotajiem argumentiem, bet tomēr pareizi iestata karogus, un x86 asemblēšana nav izņēmums.
cmp ax, 100 jge turpināt mov ax, 100 turpināt: mul ax
Tagad tā vietā, lai atņemtu 100 no ax, pārbaudītu, vai šis skaitlis ir mazāks par nulli, un piešķirtu to atpakaļ ax, ax tiek atstāts nemainīgs. Karodziņi joprojām tiek iestatīti tāpat, un lēciens joprojām tiek veikts tajās pašās situācijās.
Ievade un izvade
Lai gan ievade un izvade ir būtiska skaitļošanas procesa daļa, montāžas valodā nav viena veida, kā to izdarīt. Tas ir tāpēc, ka ieejas un izejas darbības veids ir atkarīgs no datora konfigurācijas un tajā izmantotās operētājsistēmas, nevis tikai no tā, kāds tam ir procesors. Šajā sadaļā piemērs Hello World izmanto MS-DOS operētājsistēmas izsaukumus, bet nākamajā piemērā izmantoti BIOS izsaukumi.
Ir iespējams veikt I/O asamblēšanas valodā. Patiesi, asembleru valodā vispār var izteikt visu, ko dators spēj izdarīt. Tomēr, lai gan asamblēšanas valodā ir pievienošanas un sazarošanas instrukcijas, kas vienmēr darīs vienu un to pašu, asamblēšanas valodā nav instrukciju, kas vienmēr veiktu I/O.
Svarīgi ir atzīmēt, ka I/O darbības veids nav asamblēšanas valodas daļa, jo tas nav daļa no procesora darbības veida.