Εισαγωγή στην Assembly

 

Περιεχόμενα:

1.  Εισαγωγή

a.     Τι είναι η Assembly

b.   Πλεονεκτήματα / Μειονεκτήματα

2.  Συστήματα αρίθμησης

a.     Δεκαδικό

b.     Δυαδικό

c.     Δεκαεξαδικό

3.  Οργάνωση της μνήμης

a.     Bit , Nibble , Byte , Word , Double word

b.     Η στοίβα

c.   Διευθυνσιοδότηση

4.    Ο επεξεργαστής x86 της intel

a.     Εισαγωγή

b.     Καταχωρητές

                                                              i.      Γενικού σκοπού καταχωρητές

                                                           ii.      Καταχωρητές τμήματος

                                                         iii.      Καταχωρητές index

                                                          iv.      Καταχωρητές στοίβας

                                                            v.      Σημαίες

c.     Οι κυριότερες εντολές

d.     Interrupts

5.  Το πρώτο μας πρόγραμμα

a.     Εισαγωγή

b.     Το debug και η χρήση του

c.     Γράφοντας το πρόγραμμα

d.   Αποθήκευση του προγράμματος στο δίσκο

6.    Επίλογος


ΚΕΦΑΛΑΙΟ 1: Εισαγωγή

Τι είναι η  Assembly

H Assembly είναι μια γλώσσα προγραμματισμού υπολογιστών . Είναι μια γλώσσα πολύ χαμηλού επιπέδου , αφού επιτρέπει πρόσβαση στις λειτουργίες  του επεξεργαστή . Αυτό σημαίνει ότι υπάρχουν πολλές διαφορετικές γλώσσες Assembly , μια για κάθε είδος επεξεργαστή . Στο κείμενο αυτό θα μας απασχολήσει η Assembly του επεξεργαστή x86 της intel , που είναι σήμερα ο πιο διαδεδομένος επεξεργαστής . Αν έχετε 286 , 386 ή ακόμα και 8086 (γενικώς ότι τελειώνει σε 86) ή ακόμη και Pentim , τότε ο επεξεργαστής σας υποστηρίζει τις εντολές που θα αναφερθούν εδώ .

 

Η Assembly λέγεται αλλιώς και συμβολική γλώσσα , αφού στην ουσία τα προγράμματα σε αυτή είναι συμβολικές ονομασίες εντολών , που αποτελούν μνημονικά ονόματα (στην Αγγλική γλώσσα) κάθε λειτουργίας του επεξεργαστή.

 

Βέβαια , όπως είναι γνωστό , οι υπολογιστές καταλαβαίνουν μόνο το 0 και το1 , οπότε τα σύμβολα της γλώσσας Assembly πρέπει να μεταφραστούν σε 0 και 1 (δηλαδή σε γλώσσα μηχανής) από ένα πρόγραμμα που καλείται συμβολομεταφραστής  (Assembler) , κατά τρόπο ανάλογο με τη μετάφραση προγραμμάτων γλωσσών υψηλού επιπέδου από μεταγλωτιστές και διερμηνείς .

 

Για να ακολουθήσετε το κείμενο αυτό δεν χρειάζεται να προμηθευτείτε κανένα συμβολομεταφραστή , αφού αυτός υπάρχει ήδη στο σύστημά σας και λέγεται debug . Για την ακρίβεια δεν είναι ακριβώς συμβολομεταφραστής , αλλά μπορούμε να τον χρησιμοποιήσουμε σαν τέτοιο . Θα εξετάσουμε αναλυτικά το debug στο κεφάλαιο 5.

 

Πλεονεκτήματα / Μειονεκτήματα

Το βασικότερο πλεονέκτημα της Assembly είναι η ταχύτητα των προγραμμάτων που γράφονται σε αυτή . Πραγματικά τα προγράμματα αυτά είναι ταχύτατα και μπορούν να αποδειχθούν εξαιρετικά χρήσιμα σε εφαρμογές όπου η ταχύτητα παίζει σημαντικό ρόλο , όπως πχ στα γραφικά .

 

Ένα επιπλέον πλεονέκτημα είναι ότι ο προγραμματιστής σε Assembly καταλαβαίνει ακριβώς πως λειτουργεί ο υπολογιστής του . Καταλαβαίνει τον τρόπο σκέψης του και τον προγραμματίζει με τέτοιο τρόπο , ώστε τα προγράμματά του να είναι πιο γρήγορα και σωστά δομημένα , ακόμα και όταν χρησιμοποιεί γλώσσα υψηλότερου επιπέδου από την Assembly . H Assembly είναι μια γλώσσα ιδανική για αυτούς που ενδιαφέρονται να μάθουν πώς ακριβώς λειτουργούν τα πράγματα .

 

Υπάρχουν όμως και σοβαρά μειονεκτήματα . Ένα από αυτά είναι η αργή συγγραφή προγραμμάτων . Για παράδειγμα χρειαζόμαστε ένα πρόγραμμα 10 γραμμών για να εκτυπώσουμε ένα αλφαριθμητικό στην οθόνη , πράγμα που σε BASIC γίνεται με μια και μόνο εντολή . Ένα άλλο μειονέκτημα είναι ότι η γλώσσα Assembly δεν διαθέτει καμία μέριμνα αποφυγής σφαλμάτων και καμία λογική δόμησης , οπότε μπορούν να προκύψουν προγράμματα με σφάλματα και με κώδικα «σπαγγέτι» πολύ εύκολα . Η μέριμνα σε αυτή την περίπτωση αφήνεται εξολοκλήρου στον προγραμματιστή για καθαρό κώδικα και αποφυγή σφαλμάτων . Αυτός είναι και ο κύριος λόγος που η Assembly δεν συνίσταται για αρχάριους προγραμματιστές .

 

Παρόλα αυτά τα μειονεκτήματα μπορούν να παρακαμφθούν με διάφορες προσεγγίσεις :

  1. Με τη χρήση κανόνων ευταξίας και δόμησης προγραμμάτων , οι οποίοι και θα ακολουθούνται αυστηρά .
  2. Με την ενσωμάτωση κώδικα Assembly σε προγράμματα γλωσσών υψηλότερου επιπέδου , ώστε να επιταχύνονται οι αργές διαδικασίες (πχ γραφικά) , ενώ παράλληλα οι συνηθισμένες , μη απαιτητικές διαδικασίες (όπως η εκτύπωση αλφαριθμητικών) να γίνονται εύκολα με τις τυποποιημένες εντολές της κάθε γλώσσας .

 

ΠΕΡΙΕΧΟΜΕΝΑ


ΚΕΦΑΛΑΙΟ 2: Συστήματα αρίθμησης

 

Οι άνθρωποι , για να μπορούν να συννενοούνται σε σχέση με τις διάφορες ποσότητες χρησιμοποιούν το δεκαδικό σύστημα αρίθμησης . Οι αριθμοί δηλαδή που χρησιμοποιούν οι άνθρωποι αποτελούνται από 10 ψηφία (0-9) βαλμένα στη σωστή σειρά . Όπως όμως αναφέραμε , ο υπολογιστής καταλαβαίνει μόνο το 0 και το 1 . Δηλαδή μπορεί να εργαστεί μόνο με δύο ψηφία . Αυτό επίσης σημαίνει ότι όλοι οι αριθμοί που καταλαβαίνει ο υπολογιστής κωδικοποιούνται σε ένα σύστημα αρίθμησης που ονομάζεται δυαδικό (με 2 ψηφία 0 και 1 βαλμένα στη σωστή σειρά) , και που αν θυμάστε είχαμε διδαχθεί στο δημοτικό . Για όσους δεν θυμούνται γίνεται εδώ μια αναφορά στα διάφορα συστήματα αρίθμησης , αφού είναι βασικής σημασίας στον προγραμματισμό σε  Assembly . Όσοι θυμούνται μπορούν να το παρακάμψουν .

 

Δεκαδικό

Ξεκινάμε λοιπόν με το δεκαδικό , μιας και το χρησιμοποιούμε καθημερινά .

 

Ένας αριθμός στο δεκαδικό σύστημα κωδικοποιείται με τα δέκα γνωστά μας ψηφία 0-9 ως εξής:

 

Το πρώτο από τα δεξιά ψηφίο είναι ο αριθμός των μονάδων . Έτσι ο αριθμός 7 σημαίνει «7 μονάδες» . Το δεύτερο ψηφίο είναι οι 10δες . Δηλαδή ο αριθμός 37 σημαίνει «3 δεκάδες και 7 μονάδες» . Το τρίτο ψηφίο είναι των εκατοντάδων , το τέταρτο των χιλιάδων κοκ .

 

Παρατηρούμε εδώ ότι αν χρησιμοποιήουμε δυνάμεις , οι μονάδες παριστάνονται σαν (10^0) , οι δεκάδες σαν (10^1) , οι εκατοντάδες σαν (10^2) κοκ . Η βάση λοιπόν του συστήματος είναι το 10 και το σύστημα καλείται «δεκαδικό» ή «Decimal» . Ο αριθμός 1234 σημαίνει λοιπόν :

1 x 10^3 +2 x 10^2 + 3 x 10^2 +4 x 10^0.

 

Δυαδικό

Το δυαδικό σύστημα , αν και διαθέτει μόνο 2 ψηφία , δεν έχει τίποτα να ζηλέψει από το δεκαδικό , αφού σε δυαδικό συμβολισμό μπορούμε να αναπαραστήσουμε οποιονδήποτε αριθμό .

 

Αν θυμηθούμε τη λογική του δεκαδικού , είναι εύκολο να καταλάβουμε πώς λειτουργεί και το δυαδικό . Έτσι το πρώτο ψηφίο από δεξιά είναι οι μονάδες (2^0) . Το δεύτερο είναι οι δυάδες (2^1) , το τρίτο οι τετράδες (2^2) κοκ . Η βάση είναι το 2 και γι αυτό το σύστημα λέγεται δυαδικό (Binary) .

 

Παράδειγμα:

Ο αριθμός 10 του δεκαδικού μπορεί να παρασταθεί σαν δυαδικός ως εξής :

Παρατηρούμε ότι το 10 έχει μια οκτάδα (2^3) , καμία τετράδα , μια δυάδα και καμία μονάδα . Έτσι γράφουμε :

10 = 1 x (2^3) + 0 x (2^2) +1 x (2^1) +0 x (2^0)

 

οπότε ο δυαδικός συμβολισμός του 10 είναι 1010b . Το b χρησιμεύει για να μας δείξει ότι ο αριθμός είναι δυαδικός και να μην συγχέεται με το χίλια-δέκα του δεκαδικού .

 

Αντίστροφα , ο αριθμός 1111b σε δεκαδικό συμβολισμό παριστάνεται ως εξής :

 

1111b = 1 x (2^3) + 1 x (2^2) +1 x (2^1) +1 x (2^0) =8+4+2+1 =15

 

Δεκαεξαδικό

Βεβαίως η ενασχόληση του ανθρώπου με το δυαδικό σύστημα είναι επίπονη . Η χρήση δε του δεκαδικού είναι και αυτή δύσκολη , αφού απαιτείται μετατροπή από το δεκαδικό στο δυαδικό . Η λύση είναι το δεκαεξαδικό σύστημα .

 

Από την περιγραφή των 2 προηγούμενων συστημάτων θα έχετε ήδη καταλάβει τι συμβαίνει με το δεκαεξαδικο (hexadecimal) σύστημα . Είναι ένα σύστημα με βάση το 16 , όπου το πρώτο ψηφίο δηλώνει τις μονάδες (16^0) , το δεύτερο τις δεκαεξάδες (16^1) , το τρίτο τις 256άδες (16^2) και πάει λέγοντας …

 

Αυτό που ίσως δεν συμπεράνατε είναι το ποια ψηφία χρησιμοποιούνται . Όπως το δυαδικό χρειάζεται 2 και το δεκαδικό 10 ψηφία , έτσι και το 16δικό χρειάζεται 16 ψηφία . Ποια είναι αυτά ?

 

Τα πρώτα 10 ψηφία είναι τα γνωστά 0-9 του δεκαδικού . Τα υπόλοιπα 6 είναι τα A,B,C,D,E,F του αγγλικού αλφαβήτου . Για να γίνει κατανοητό πως δουλεύει αυτό το σύστημα ρίξτε μια ματιά στον παρακάτω πίνακα :

 

Δεκαεξαδικό

Δυαδικό

Δεκαδικό

0

0000

0

1

0001

1

2

0010

2

3

0011

3

4

0100

4

5

0101

5

6

0110

6

7

0111

7

8

1000

8

9

1001

9

Α

1010

10

B

1011

11

C

1100

12

D

1101

13

E

1110

14

F

1111

15

 

Αυτό που πρέπει να παρατηρήσουμε είναι ότι 4 ψηφία του δυαδικού συστήματος αντιστοιχούν σε 1 του δεκαεξαδικού . Έτσι όταν έχουμε ένα μεγάλο δυαδικό αριθμό όπως ο 11010101001011101010b , μπορούμε να τον χωρίσουμε σε τετράδες , δηλαδή :

 

1101  0101  0010  1110  1010b

 

και μετά , σύμφωνα με τον παραπάνω πίνακα να βρούμε ποιο δεκαεξαδικό ψηφίο αντιστοιχεί σε κάθε τετράδα :

 

1101 0101  0010  1110  1010b =  D52EΑh  (To h χρησιμοποιείται για να δηλώσει δεκαεξαδικό συμβολισμό )

 

Φαίνονται λοιπόν τα πλεονεκτήματα του δεκαεξαδικού συμβολισμού . Είναι πολύ πιο συμπαγής τρόπος για να γράφουμε αριθμούς και μετατρέπεται πολύ εύκολα στο δυαδικό σύστημα (και αντίστροφα) . Επιπλέον είναι πολύ ευκολότερο να μετατρέψουμε το D52EΑh  σε δεκαδικό συμβολισμό , παρά το 11010101001011101010b . Έτσι το δεκαεξαδικό σύστημα αρίθμησης είναι μια πολύτιμη «γέφυρα» ανάμεσα στη λογική του ανθρώπου και του υπολογιστή .

 

ΑΣΚΗΣΗ:  Γράψτε σε τρία χαρτιά τυχαίους δεκαδικούς , δεκαεξαδικούς και δυαδικούς αριθμούς αντίστοιχα  , και μετατρέψτε τους αριθμούς στα άλλα δύο συστήματα .

 

ΠΕΡΙΕΧΟΜΕΝΑ


Κεφάλαιο 3 : Οργάνωση της μνήμης

 

Bit , Nibble , Byte , Word , Double word

Και αφού λοιπόν ο υπολογιστής καταλαβαίνει και «θυμάται» μόνο αλληλουχίες από 0 και 1 , έπεται ότι η βασική μονάδα μνήμης του υπολογιστή είναι το δυαδικό ψηφίο . Στα αγγλικά αυτό μεταφράζεται Bainary Digit , ή πιο σύντομα bit . Βέβαια , ένα bit μόνο του δεν σημαίνει και πολλά . Με πολλά bits στη σειρά όμως μπορούμε να κάνουμε τα πάντα! Να αποθηκεύσουμε ένα μουσικό κομμάτι σε CD , να φτιάξουμε όλα τα γραφικά σαν αυτά τα φοβερά της ταινίας Final Fantasy ή να γράψουμε ένα κείμενο , όπως κάνω εγώ αυτή τη στιγμή …

 

…βέβαια για να γίνουν όλα αυτά απαιτείται και κάποια οργάνωση . Αν τα bits τοποθετούνταν απλώς στη σειρά , και χρειαζόμασταν 1 MB δεδομένων θα επικρατούσε ένα χάος . Έτσι υπάρχει ένα σύστημα με το οποίο τα bits ομαδοποιούνται .

 

Καταρχήν τα bits χωρίζονται σε τετράδες . Οι τετράδες αυτές λέγονται Nibbles . Όπως είδαμε και πριν , ένα nibble μπορεί να παρασταθεί με ένα δεκαεξαδικό ψηφίο . Τα bits μέσα σε ένα nibble αριθμούνται ως εξής :

 

Bit #3 ή υψηλής τάξης bit

#2

#1

Bit #0 ή χαμηλής τάξης bit

 

Αν συνδυάσουμε 8 bits μαζί (ή 2 nibbles) , παίρνουμε 1 byte . Τα bits μέσα σε ένα byte αριθμούνται με παρόμοιο τρόπο:

 

Bit #7 ή υψηλής τάξης bit

#6

#5

#4

#3

#2

#1

Bit #0 ή χαμηλής τάξης bit

 

To byte αποτελείται από 2 nibbles που λέγονται υψηλής και χαμηλής τάξης nibbles

Nibble υψηλής τάξης (high order nibble)

Nibble χαμηλής τάξης (low order nibble)

 

Και φυσικά αφού το nibble αναπαρίσταται με ένα δεκαεξαδικό ψηφίο , to byte αναπαρίσταται με δύο .

 

Το byte είναι μια πολύ βασική μονάδα μνήμης , αφού ο κώδικας ASCIL είναι κώδικας του 1 byte . Ο κώδικας αυτός αντιστοιχίζει δυαδικούς αριθμούς του ενός byte σε αλφαριθμητικούς χαρακτήρες . Με 8 bits (1 byte) , μπορούμε να αναπαραστήσουμε αριθμούς από το 00000000b ως το 11111111b . Δηλαδή από το 0 ως το 255 . Ο κώδικας ASCLIL έχει 256 χαρακτήρες . Από αυτούς οι 128 είναι αλφαριθμητικοί χαρακτήρες  της Αγγλικής γλώσσας , ενώ οι υπόλοιποι 128 χρησιμοποιούνται για διάφορους λόγους (όπως για υποστήριξη Ελληνικών στο MS DOS) . Πρόσφατα έχει δημιουργηθεί μια νέα τυποποίηση που λέγεται Unicode . Ο κώδικας αυτός είναι 16μπιτος και μπορεί να αναπαραστήσει 65536 χαρακτήρες (πολύ περισσότεροι από τους 256 του ASCIL) , που περιλαμβάνουν όλες τις γλώσσες! Παρόλα αυτά , ο παλιός καλός ASCIL κώδικας δεν έχει αντικατασταθεί πλήρως και αυτόν θα χρησιμοποιούμε στα προγράμματα σε Assembly .

 

Μιλώντας για τον 16μπιτό κώδικα Unicode , η μονάδα που αποτελείται από 16 bits ονομάζεται word (λέξη) . Μια λέξη ως εκ τούτο αποτελείται από 2 bytes . Ένα υψηλής και ένα χαμηλής τάξης , κάθε ένα από τα οποία έχει τα δικά του υψηλής και χαμηλής τάξης nibbles .

 

Επίσης υπάρχει και μια μονάδα μνήμης των 32 bits , που λέγεται Double word ή Dword και περιλαμβάνει μια υψηλής και μια χαμηλής τάξης λέξη , καθεμιά από τις οποίες έχει ένα υψηλής και ένα χαμηλής τάξης byte κοκ …

 

Η στοίβα

Η στοίβα (stack) είναι ένας χαρακτηριστικός τρόπος αποθήκευσης των δεδομένων , που πρόκειται να μας λύσει τα χέρια στον προγραμματισμό σε Assembly .

 

Η στοίβα συμπεριφερεται ακριβώς όπως μια στοίβα από δίσκους σερβιρίσματος σε μια καφετέρια . Αν πάνω στη στοίβα τοποθετηθεί ένας δίσκος αυτός θα είναι και ο πρώτος δίσκος που θα πάρουμε από αυτή ,όταν τον χρειαστούμε.

 

Η στοίβα λοιπόν ακολουθεί τη λογική LIFO (Last In , First Out) . Θα μας φανεί ιδιαίτερα χρήσιμη όταν θα χρειάζεται σε ένα πρόγραμμα να αποθηκεύσουμε κάποιον (ή όλους) τους καταχωρητές . Περισσότερα για τις εντολές στοίβας θα δούμε στο επόμενο κεφάλαιο .

 

Διευθυνσιοδότηση

Η μνήμη του υπολογιστή μας μπορεί να θεωρηθεί σαν ένα μεγάλο «σωληνάριο» που περιέχει «καραμέλες» τη μία μετά την άλλη . Κάθε καραμέλα είναι ένα byte .

 

Ο επεξεργαστής μας , μπορεί να διαβάζει και να γράφει bytes στη μνήμη . Αυτό μπορεί να το κάνει με 2 τρόπους :

 

 

Μιας και ο προγραμματισμός σε protected mode γίνεται στα windows και εμείς θα ασχοληθούμε με το MS DOS , μπορούμε να τον αγνοήσουμε (προς το παρόν) .

 

Ο προγραμματισμός σε real mode βασίζεται στη λογική Segment:Offset . Δηλαδή μια διεύθυνση μνήμης αντιστοιχίζεται σε ένα ζεύγος αριθμών των 32 bit . Αυτοί λέγονται Segment και Offset . To Segment είναι ο αριθμός του «τμήματος» της μνήμης , ενώ το offset είναι η σχετική διεύθυνση της μνήμης μέσα σε ένα ορισμένο τμήμα .

 

Ένα τμήμα μνήμης , είναι μια περιοχή της μνήμης που περιλαμβάνει FFFFh bytes (ή 64 K) . Τα τμήματα δεν είναι αυτόνομα . Δηλαδή μια περιοχή της μνήμης μεγέθους 64 K δεν αντιστοιχεί μόνο σε ένα τμήμα . Αντίθετα τα τμήματα είναι επικαλυπτόμενα . Ρίξτε μια ματιά στο παρακάτω σχήμα για να καταλάβετε.

 

__________________________________________________

._________   ___

.|Τμήμα 1 |   |

.|        |  16 bytes

.|        |   |                       Κάθε τμήμα έχει την αρχή του

.| __________---  ___                 στο 16ο byte του προηγούμενου

.| | Τμήμα 2 |     |                  τμήματος

.| |         |   16 bytes

.| |         |     |

.| | __________   ---

.| | | Τμήμα 3 | 

.| | |         |  κοκ …

.| | |         |

.| | |  …κοκ…  |

 

Για να βρούμε την φυσική διεύθυνση που αντιστοιχεί σε μια δυάδα Segment:Offset κάνουμε τον ακόλουθο υπολογισμό:

 

Διεύθυνση = Segment*16 +Offset

Ή

Διεύθυνση=Segment*10h + Offset

 

Μπορούμε λοιπόν σε Real mode να αναφερθούμε σε FFFFh τμήματα , κάθε ένα από τα οποία έχει FFFFh Offsets . Άρα η μέγιστη διεύθυνση που μπορούμε να έχουμε σε real mode είναι:

 

FFFFh *10h +FFFFh

 

Μπορούμε λοιπόν να αναφερθούμε μόνο σε 1 MB μνήμης , αλλά αυτό δεν είναι και μεγάλο μειονέκτημα , γιατί τα προγράμματά μας δεν θα ξεπεράσουν τα μερικά KiloBytes . Από ην άλλη όποιος μπορεί να γράψει ένα τόσο μεγάλο πρόγραμμα σε Assembly , μάλλον δε θα δυσκολευτεί να μάθει και τον proteceted mode

 

ΠΕΡΙΕΧΟΜΕΝΑ

 

 

ΚΕΦΑΛΑΙΟ 4 : Ο επεξεργαστής x86 της intel

 

Εισαγωγή

Ο επεξεργαστής (συχνά αναφέρεται και ως Κεντρική Μονάδα Επεξεργασίας – ΚΜΕ ή Central Prossessing Unit - CPU) αποτελεί το «νοήμον» τμήμα του υπολογιστή μας . Εκεί γίνονται όλες οι διεργασίας – αριθμητικές πράξεις – επαναλήψεις – λήψεις αποφάσεων , που κάνουν το μηχάνημά μας τόσο έξυπνο . Κάθε επεξεργαστής έχει τη δική του αρχιτεκτονική και το δικό του σετ εντολών . Στοιχεία αυτών των δύο θα καλύψουμε για τον επεξεργαστή x86 της intel . Για πιο εκτενή κάλυψη των θεμάτων αυτών ανατρέξτε σε ένα εγχειρίδιο αναφοράς του x86 , που μπορείτε να βρείτε στο internet .

 

Καταχωρητές

Βασικό στοιχείο της αρχιτεκτονικής ενός επεξεργαστή είναι οι καταχωρητές του . Οι καταχωρητές είναι θέσεις μνήμης του επεξεργαστή , που μοιάζουν κάπως με τις μεταβλητές της BASIC , με μόνη διαφορά ότι δεν ορίζονται από το χρήστη , αφού είναι ενσωματωμένοι με τον επεξεργαστή και δεν αποτελούν μέρος της κάρτας μνήμης του υπολογιστή , αλλά βρίσκονται «μέσα» στον επεξεργαστή .

 

Ο επεξεργαστης έχει την «εξυπνάδα» να μην «πελαγώνει» από τις σύνθετες διαδικασίες , γιατί κάνει μια δουλειά κάθε φορά . Αθροίζοντας τις στοιχειώδεις αυτές διαδικασίες (πχ προσθέσεις , λήψεις αποφάσεων , εκχωρήσεις τιμών)  ολοκληρώνονται πιο πολύπλοκες . Οι καταχωρητές λοιπόν είναι το μόνο μέρος στο οποίο μπορεί ο επεξεργαστής να επιδράσει δραστικά (πχ να κάνει μαθηματικές πράξεις με αυτούς κλπ) . Στην υπόλοιπη μνήμη και στους δίσκους μπορεί απλώς να διαβάζει και να γράφει .

 

Ο επεξεργαστής x86 έχει διαφόρων ειδών καταχωρητές ,οι οποίοι παρουσιάζονται συνοπτικά παρακάτω .

 

Ι. Γενικού σκοπού καταχωρητές

Καταχωρητής

Όνομα

Περιγραφή

AX

Accumulator

Συνήθως χρησιμεύει στις πράξεις αριθμητικής , σε διαδικασίες εισόδου/εξόδου και στην κλήση των ρουτίνων του MS DOS .

BX

Base

Δείκτης .

CX

Counter

Ότι λέει και η λέξη . χρησιμοποιείται σαν μια μεταβλητή καταμέτρησης στις επαναλληπτικές διαδικασίες (όπως το FORNEXT της BASIC).

DX

Displacement

Συνήθως χρησιμεύει στην έξοδο δεδομένων από το πρόγραμμα , όπως στην έξοδο χαρακτήρων στην οθόνη .

 

Βεβαίως δεν είναι μόνο αυτές οι χρήσεις τους . Ονομάζονται γενικοί καταχωρητές , αφού ο προγραμματιστής έχει τη δυνατότητα να τους αλλάξει κατά βούληση και να τους χρησιμοποιήσει όπως θέλει . Όλοι οι γενικοί καταχωρητές μπορούν να «σπάσουν» σε δύο δεκαεξάμπιτους καταχωρητές . Πχ Ο AX αποτελείται από τον AH και τον AL , όπου ο AH αποτελεί την υψηλής τάξης λέξη (H.O.  ή  High Order)  και ο AL τη χαμηλής τάξης λέξη (L.O. ή Low Order) , οπότε μην τρομάξετε αν δείτε έναν καταχωρητή BO , αφού είναι απλώς ο μισός καταχωρητής BX .

 

ΙΙ. Καταχωρητές τμήματος

Καταχωρητής

Όνομα

Περιγραφή

CS

Code Segment

Δείκτης στο τμήμα κώδικα του προγράμματός μας (εκεί δηλαδή που μπαίνουν οι εντολές)  .

DS

Data Segment

Δείκτης στο τμήμα δεδομένων . πχ εκεί αποθηκεύουμε τις μεταβλητές μας .

ES

Extra Segment

Μας χρησιμεύει στα γραφικά .

SS

Stack Segment

Δείκτης τμήματος στοίβας .

 

ΙΙΙ. Καταχωρητές Index

Καταχωρητής

Όνομα

Περιγραφή

SI

Source index

Δείχνει το Offset ενός αλφαριθμητικού ή πίνακα .

DI

Destination index

Δείχνει το offset προορισμού ενός αλφαριθμητικού ή πίνακα .

IP

Instruction Pointer

Δείχνει το offset της επόμενης εντολής που πρέπει να εκτελέσει ο επεξεργαστής .

 

IV. Καταχωρητές στοίβας

Καταχωρητής

Όνομα

Περιγραφή

BP

Base Pointer

Συνδυάζοντάς τον με τον δείκτη τμήματος στοίβας , μπορεί να χρησιμοποιηθεί για διαδικασίες στοίβας .

SP

Stack Pointer

Το offset της στοίβας .

 

V. Σημαίες

Ενώ όλοι οι υπόλοιποι καταχωρητές του x86 είναι καταχωρητές των 32 bit , οι σημαίες είναι καταχωρητές του 1 bit . Δηλαδή μπορεί να έχουν την τιμή 1 (true) ή 0 (false) . Οι κυριότερες σημαίες είναι οι Carry Flag , Zero Flag , Overflow Flag κλπ . Θα μας χρησιμεύσουν στη διακλάδωση υπό συνθήκη στα προγράμματά μας .

 

Οι κυριότερες εντολές

Οι εντολές του x86 που θα μας φανούν χρήσιμες εδώ είναι οι εξής :

Εντολή

Χρήση

Παράδειγμα

MOV

Εκχώρηση τιμής σε ένα καταχωρητή . Μπορεί να είναι μια οποιαδήποτε τιμή ή η τιμή ενός άλλου καταχωρητή

MOV   AX,1

MOV   AH,1

MOV {Καταχωρητής},{τιμή}

 

MOV   AX,BX

MOV {destination},{source}

ADD

Προσθέτει μια τιμή σε έναν καταχωρητή ή την τιμή ενός καταχωρητή σε έναν άλλο

ADD   AX,1

(Η τιμή του AX αυξάνει κατά 1)

 

ADD   AX,BX

(Η τιμή του ΑΧ Αυξάνει κατά την τιμή του ΒΧ)

SUB

Αφαιρεί μια τιμή από έναν κταχωρητή ή την τιμή ενός κατάχωρητή από έναν άλλο

SUB   AX,1

(Η τιμή του ΑΧ ελαττώνεται κατά 1)

 

SUB   AX,BX

(Η τιμή του ΑΧ ελαττώνεται κατά την τιμή του ΒΧ)

CALL / RET

Η εντολή CALL ακολουθούμενη από μια διεύθυνση , έχει σαν αποτέλεσμα την κλήση μιας υπορουτίνας . Η διεύθυνση που δίνουμε είναι η διεύθυνση της υπορουτίνας . Η εντολή RET τερματίζει την υπορουτίνα και επιστρέφει στη διεύθυνση από όπου είχε κληθεί .

CALL 150

….. υπόλοιπο πρόγραμμα…

<διεύθυνση 150>

…εντολές υπορουτίνας…

RET  (επιστροφή μετά την εντολή CALL και κανονική εκτέλεση του υπόλοιπου προγράμματος)

PUSH/POP

Χρησιμεύουν για τη διαχείριση των δεδομένων της στοίβας . Η εντολή PUSH εισάγει ένα καταχωρητή στη στοίβα και η POP τον ανακαλεί. Θυμηθείτε τη LIFO λογική της στοίβας

ΠΑΡΑΔΕΙΓΜΑ 1

MOV   AX,12     ;AX=12h

MOV   BX,23     ;BX=23h

PUSH   AX       :AX Πάνω στη στοίβα

PUSH    BX      ;BX πάνω από το ΑΧ

MOV     AX,0   ;

MOV     BX,0    ;AX=BX=0

POP       BX       ;

POP       AX       ;Επαναφορά ΑΧ,ΒΧ

ΠΑΡΑΔΕΙΓΜΑ 2

MOV   AX,12

MOV   BX,23

PUSH   AX

PUSH   BX

POP     AX

POP     BX

 

(Έγινε ανταλλαγή των τιμών των καταχωρητών ΑΧ και ΒΧ – LIFO λογική)

INT

Κλήση μιας διακοπής (βλ. παρακάτω)

INT   20

(έξοδος από το πρόγραμμα)

Χρησιμοποιήστε τον πίνακα απλώς σαν αναφορά . Μην τον αποστηθίσετε προς το παρόν .

 

Interrupts

Οι interrupts (διακοπές) είναι ό,τι ακριβώς λέει και η λέξη . Το πρόγραμμά μας διακόπτεται και συμβαίνει κάποια διαδικασία .Κατόπιν το πρόγραμμα συνεχίζει να εκτελείται κανονικά από το σημείο που έγινε η διακοπή . Μπορούμε να θεωρήσουμε μια διακοπή σαν μια υπορουτίνα , μόνο που οι διακοπές είναι ήδη καθορισμένες και δεν τις προγραμματίζουμε εμείς .

 

Οι διακοπές κάνουν δουλειές ρουτίνας , όπως τοποθέτηση αλφαριθμητικών στην οθόνη , καθορισμός της κατάστασης της οθόνης , pixel plotting κλπ . Μερικές σημαντικές interrupts είναι οι παρακάτω .

 

Interrupt

Λειτουργία

Περιγραφή

Χρήση

INT   20h

-

Έξοδος στο DOS (Μόνο για προγράμματα COM)

INT 20

INT   21h

1

Είσοδος ενός χαρακτήρα από το πληκτρολόγιο . Ο χαρακτήρας επιστρέφεται στον καταχωρητή AL

MOV AH,1

INT 21

INT   21h

2

Εμφανίζει ένα χαρακτήρα στην οθόνη . Ο κωδικός ASCIL του χαρακτήρα πρέπει να είναι στον καταχωρητή DL

MOV AH,2

MOV DL, {ASCIL}

INT 21

INT   21h

9

Εμφανίζει ένα αλφαριθμητικό στην οθόνη . Η διεύθυνση όπου είναι αποθηκευμένο το αλφαριθμητικό πρέπει να είναι στον καταχωρητή DX .

MOV AH,9

MOV DX,{String adress}

INT 21

 

ΠΕΡΙΕΧΟΜΕΝΑ


ΚΕΦΑΛΑΙΟ 5 : Το πρώτο μας πρόγραμμα

 

Εισαγωγή

Και μετά όλο το ομολογουμένως βαρετό υπόβαθρο , έφτασε η ώρα να γράψουμε ένα πρόγραμμα σε γλώσσα Assembly . Συνήθως το πρώτο πρόγραμμα που γράφουμε όταν μαθαίνουμε μια γλώσσα είναι το γνωστό “Hello , world!” . Αυτό θα κάνουμε κι εδώ .

 

 Όπως είπαμε και πριν , για να μεταφράσουμε τα περίεργα σύμβολα της Assembly σε εκτελέσιμο κώδικα , χρειαζόμαστε ένα πρόγραμμα που λέγεται συμβολομεταφραστής . Προς το παρόν όμως δε θα χρειαστεί να κατεβάσετε και να εγκαταστήσετε κανέναν συμβολομεταφραστή , αφού το σύστημά σας περιέχει ήδη ένα πρόγραμμα που μπορούμε να χρησιμοποιήσουμε για το σκοπό αυτό . Λέγεται debug (απεντόμωση) και βρίσκεται σε όλα τα συστήματα DOS (και WINDOWS) . Ας δούμε λοιπόν λίγα πράγματα για τη χρήση του …

 

Το Debug και η χρήση του

Με το debug θα γράψουμε προγράμματα .COM . Για να ξεκινήσουμε το Debug , ανοίγουμε ένα κέλυφος MS DOS (StartMS DOS Prompt) και γράφουμε DEBUG

 

Για να φορτώσουμε ένα αρχείο COM που έχουμε ήδη φτιάξει χρησιμοποιούμε την ακόλουθη σύνταξη :

 

C:> DEBUG FILENAME.COM

 

Όταν έχουμε ανοίξει το debug , βλέπουμε μια παύλα , που είναι το προτρεπτικό σήμα για διαταγές . Οι κυριότετρες διαταγές του Debug είναι οι εξής :

Διαταγή

Λειτουργία

-q

Έξοδος (quit)

-r

Προβολή όλων των καταχωρητών και των τιμών τους

-r {register}

Αλλαγή της τιμής του καταχωρητή {register} πχ –r ax για να αλλάξετε τον AX

-a {adress}

Εκχώρηση των εντολών που θέλουμε στην διεύθυνση {asress}

-u {adress}

Προβολή στην οθόνη των εντολών που υπάρχουν στη διεύθυνση {adress}

-e {adress}

Αλλαγή του byte που βρίσκεται στη διεύθυνση {adress} . Μπορούμε να αλλάξουμε και τα επόμενα bytes , πατώντας το SPACE

-d {adress}

Εμφανίζει τα περιεχόμενα της διεύθυνσης {adress} στην οθόνη

-n {name}

Ονομάζει το πρόγραμμά μας με το όνομα {name}

-w

Αποθηκεύει το πρόγραμμά μας στο δίσκο , με filename αυτό που δηλώσαμε παραπάνω στην εντολή –n . Πρέπει δηλαδή η εντολή –n να προηγείται της –w . Ακόμη πριν αποθηκεύσουμε το πρόγραμμά μας πρέπει να πούμε στο debug πόσο μεγάλο είναι σε bytes , πράγμα που γίνεται με τους καταχωρητές BX:CX . Βάζουμε δηλαδή στους καταχωρητές αυτούς την τιμή που αντιστοιχεί στο πόσα bytes είναι το πρόγραμμά μας (χρησιμοποιούμε την εντολή -r) , και κατόπιν αποθηκεύουμε το πρόγραμμα στο δίσκο

 

Γράφοντας το πρόγραμμα

Για να εκτυπώσουμε ένα αλφαριθμητικό στην οθόνη θα χρησιμοποιήσουμε την interrupt 21h , λειτουργία 9 του DOS .

 

Για να δηλώσουμε ότι θέλουμε τη λειτουργία 9 , βάζουμε το 9 στον καταχωρητή AH :

 

MOV AH,9

 

O καταχωρητής DX πρέπει να δείχνει τη σχετική διεύθυνση του μηνύματος . Αυτή είναι η 109h :

 

MOV DX,109

 

Πώς μαντέψαμε ότι η σχετική διεύθυνση είναι η 109h ?  Απλώς γράφουμε πρώτα όλο το πρόγραμμα και μετά κοιτάμε σε ποια διεύθυνση τελειώνει . Εκεί ακριβώς θα τοποθετήσουμε και το αλφαριθμητικό μας . Θα μπορούσαμε βέβαια να το τοποθετήσουμε και σε μια διεύθυνση πολύ μακριά πχ 200h , ώστε να μην μας απασχολέι που τελειώνει ο κώδικας . Στην περίπτωση αυτή όμως όλα τα δεδομένα μεταξύ 109h-200h θα γραφτούν στο δίσκο σαν σκουπίδια (αν και το πρόγραμμά μας θα τρέξει κανονικά ) , πράγμα που είναι λάθος και πρέπει να το αποφύγουμε . Ούτως ή άλλως όμως το σημείο αυτό λίγο μας ενδιαφέρει , αφού όταν θα δουλέψουμε με το συμβολομεταφραστή , δεν θα ανησυχούμε για τις διευθύνσεις μνήμης , αφού αυτός θα αναλαμβάνει να τις καθορίζει για μας .

 

Για να εκτελεστεί η interrupt 21h , δίνουμε την εντολή :

 

INT 21

 

Και τέλος για να τελειώσει το πρόγραμμα :

 

ΙΝΤ 20

 

Όλο το πρόγραμμα λοιπόν είναι :

 

MOV  AH,9

MOV  DX,109

INT 21

INT 20

 

Θα το γράψουμε με την εντολή a (assemble)

 

(Debug Prompt) – a 100

(δώστε μια-μια τις εντολές και πατήστε ENTER . Όταν τελειώσετε πατήστε 2 φορές ENTER)

 

Τώρα    το πρόγραμμα που είδαμε συν κάποιες ακατανόητες εντολές που βρίσκονται μετά την τελευταία μας εντολή MOV 20 . Αυτά είναι τα περιεχόμενα που είχε η μνήμη μας . Παρατηρούμε ότι η αμέσως επόμενη εντολή από την τελευταία που δώσαμε βρίσκεται στη διεύθυνση 109h.

 

Σε αυτή τη διεύθυνση λοιπόν θα πρέπει να βάλουμε και το αλφαριθμητικό μας , ώστε να μην υπάρχει άχρηστος χώρος μεταξύ του κώδικα και του αλφαριθμητικού και το πρόγραμμά μας να είναι μικρό και συμπαγές .

 

Για να βάλουμε ένα αλφαριθμητικό στη μνήμη πρέπει να εισάγουμε έναν έναν τους κωδικούς ASCIL του αλφαριθμητικού , με την εντολή e του debug .

 

(Debug prompt)- e 109   (αφού θέλουμε το αλφαριθμητικό να αρχίζει στη διεύθυνση 109)

(δώστε τους αριθμούς 48 , 65 , 6c , 6c , 6f , 20 , 77 , 6f , 72 , 6c , 64 , 21 , 24 χωρισμένους με κενά . Όταν τελειώσετε πατήστε ENTER)

 

Οι αριθμοί μπορούν πολύ εύκολα να βρεθούν από οποιονδήποτε πίνακα ASCIL . Εναλλακτικά μπορείτε να χρησιμοποιήσετε το πρόγραμμα str2asc.exe που σας δίνω στο αρχείο zip .

 

Ο τελευταίος χαρακτήρας είναι ο 24h , δηλαδή το σήμα του δολαρίου . Αυτό χρησιμεύει για να δείξει το τέλος του αλφαριθμητικού και δεν εκτυπώνεται στην οθόνη .

 

Τώρα αν τρέξουμε το πρόγραμμά μας`(εντολή -g) θα εμφανιστεί στην οθόνη ένα μήνυμα (αν όλα πήγαν καλά , αν όχι , διπλοτσεκάρετε ότι κάνατε όλα τα προηγούμενα σωστά) .

 

Αν όλα πήγαν καλά το πρόγραμμά μας είναι έτοιμο και μένει μόνο να το γράψουμε στο δίσκο …

 

Αποθήκευση του προγράμματος στο δίσκο

Όταν γράφουμε το πρόγραμμά μας στο δίσκο , το debug απλώς παίρνει μια περιοχή της μνήμης και την αποθηκεύει σε ένα αρχείο . Καταρχήν πρέπει να του πούμε πόσο μεγάλο είναι το πρόγραμμά μας . Αν κάνουμε τους υπολογισμούς , προκύπτει ότι το πρόγραμμά μας (κώδικας + δεδομένα αλφαριθμητικού) είναι όλο 16h bytes . Για να πούμε στο debug ότι το πρόγραμμά μας είναι 16h bytes βάζουμε στον καταχωρητή CΧ , την τιμή 16h . Δηλαδή:

 

(Debug prompt) – r cx

(εισάγετε 16 - ENTER)

 

(Αν ο καταχωρητής BX δεν είναι 0 , κάντε τον 0 με την ίδια εντολή , αφού ο αριθμός των bytes κρατιέται από τον συνδυασμό BX:CX που είναι ένας 64μπιτος αριθμός) .

 

Κατόπιν πρέπει να δώσουμε ένα όνομα στο αρχείο μας . Έστω HELLO.COM

 

(Debug prompt) – n HELLO.COM

 

Τέλος γράφουμε το αρχείο μας στο δίσκο :

 

(Debug prompt) –w

 

Βγαίνουμε από το Debug:

 

(Debug prompt)-q

 

Και εκτελούμε το πρόγραμμά μας από το DOS:

 

C:>HELLO.COM

 

ΠΕΡΙΕΧΟΜΕΝΑ


Επίλογος

 

Το κείμενο αυτό σε καμία περίπτωση δεν αποτελεί ένα ολοκληρωμένο εισαγωγικό tutorial για την Assembly του x86 . Αντίθετα καλύπτει τα ελάχιστα μόνο σημεία που απαιτούνται για την κατασκευή ενός πολύ απλού προγράμματος σε Assembly . Σκοπός του κειμένου αυτού είναι να «ξύσουμε» λίγο την επιφάνεια της πολύ ισχυρής αυτής γλώσσας , και να γνωρίσουμε έννοιες και εργαλεία χρήσιμα για το coding σε αυτή .

 

Βέβαια , θα υπάρξουν και επόμενα κείμενα που θα καλύπτουν πιο πολύπλοκα θέματα , αλλά θα τα γράψω μόνο αν εκδηλωθεί αντίστοιχο ενδιαφέρον από τους αναγνώστες του code . Επικοινωνήστε μαζί μου στο msamurai@freemail.gr .