Εισαγωγή στην 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. iv. Καταχωρητές τµήµατος Καταχωρητές index Καταχωρητές στοίβας v. Σηµαίες
c. Οι κυριότερες εντολές d. Interrupts 5. Το πρώτο µας πρόγραµµα a. Εισαγωγή b. Το debug και η χρήση του c. Γράφοντας το πρόγραµµα d. Αποθήκευση του προγράµµατος στο δίσκο 6. Επίλογος Τι είναι η Assembly ΚΕΦΑΛΑΙΟ 1: Εισαγωγή H Assembly είναι µια γλώσσα προγραµµατισµού υπολογιστών. Είναι µια γλώσσα πολύ χαµηλού επιπέδου, αφού επιτρέπει πρόσβαση στις λειτουργίες του επεξεργαστή. Αυτό σηµαίνει ότι υπάρχουν πολλές διαφορετικές γλώσσες Assembly, µια για κάθε είδος επεξεργαστή. Στο κείµενο αυτό θα µας απασχολήσει η Assembly του επεξεργαστή x86 της intel, που είναι σήµερα ο πιο διαδεδοµένος επεξεργαστής. Αν έχετε 286, 386 ή ακόµα και 8086 (γενικώς ότι τελειώνει σε 86) ή ακόµη και Pentium, τότε ο επεξεργαστής σας υποστηρίζει τις εντολές που θα αναφερθούν εδώ. Η 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 (από 286 και πάνω) Σε real mode Μιας και ο προγραµµατισµός σε protected mode γίνεται στα windows και εµείς θα ασχοληθούµε µε το MS DOS, µπορούµε να τον αγνοήσουµε (προς το παρόν). Ο προγραµµατισµός σε real mode βασίζεται στη λογική Segment:Offset. ηλαδή µια διεύθυνση µνήµης αντιστοιχίζεται σε ένα ζεύγος αριθµών των 32 bit. Αυτοί λέγονται
Segment και Offset. To Segment είναι ο αριθµός του «τµήµατος» της µνήµης, ενώ το offset είναι η σχετική διεύθυνση της µνήµης µέσα σε ένα ορισµένο τµήµα. Ένα τµήµα µνήµης, είναι µια περιοχή της µνήµης που περιλαµβάνει FFFFh bytes (ή 64 K). Τα τµήµατα δεν είναι αυτόνοµα. ηλαδή µια περιοχή της µνήµης µεγέθους 64 K δεν αντιστοιχεί µόνο σε ένα τµήµα. Αντίθετα τα τµήµατα είναι επικαλυπτόµενα. Ρίξτε µια µατιά στο παρακάτω σχήµα για να καταλάβετε. Για να βρούµε την φυσική διεύθυνση που αντιστοιχεί σε µια δυάδα 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 Ότι λέει και η λέξη. χρησιµοποιείται σαν µια µεταβλητή καταµέτρησης στις επαναλληπτικές διαδικασίες (όπως το FOR NEXT της 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 ADD Προσθέτει µια τιµή σε έναν καταχωρητή ή την τιµή ενός καταχωρητή σε έναν άλλο MOV {destination},{source} ADD AX,1 (Η τιµή του AX αυξάνει κατά 1) SUB Αφαιρεί µια τιµή από έναν κταχωρητή ή την τιµή ενός κατάχωρητή από έναν άλλο ADD AX,BX (Η τιµή του ΑΧ Αυξάνει κατά την τιµή του ΒΧ) SUB AX,1 (Η τιµή του ΑΧ ελαττώνεται κατά 1)
CALL / RET PUSH/POP Η εντολή CALL ακολουθούµενη από µια διεύθυνση, έχει σαν αποτέλεσµα την κλήση µιας υπορουτίνας. Η διεύθυνση που δίνουµε είναι η διεύθυνση της υπορουτίνας. Η εντολή RET τερµατίζει την υπορουτίνα και επιστρέφει στη διεύθυνση από όπου είχε κληθεί. Χρησιµεύουν για τη διαχείριση των δεδοµένων της στοίβας. Η εντολή PUSH εισάγει ένα καταχωρητή στη στοίβα και η POP τον ανακαλεί. Θυµηθείτε τη LIFO λογική της στοίβας SUB AX,BX (Η τιµή του ΑΧ ελαττώνεται κατά την τιµή του ΒΧ) CALL 150.. υπόλοιπο πρόγραµµα <διεύθυνση 150> εντολές υπορουτίνας RET (επιστροφή µετά την εντολή CALL και κανονική εκτέλεση του υπόλοιπου προγράµµατος) ΠΑΡΑ ΕΙΓΜΑ 1 MOV AX,12 MOV BX,23 PUSH AX στοίβα ;AX=12h ;BX=23h :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 POP AX BX
INT Κλήση µιας διακοπής (βλ. παρακάτω) (Έγινε ανταλλαγή των τιµών των καταχωρητών ΑΧ και ΒΧ LIFO λογική) INT 20 (έξοδος από το πρόγραµµα) Χρησιµοποιήστε τον πίνακα απλώς σαν αναφορά. Μην τον αποστηθίσετε προς το παρόν. Interrupts Οι interrupts (διακοπές) είναι ό,τι ακριβώς λέει και η λέξη. Το πρόγραµµά µας διακόπτεται και συµβαίνει κάποια διαδικασία.κατόπιν το πρόγραµµα συνεχίζει να εκτελείται κανονικά από το σηµείο που έγινε η διακοπή. Μπορούµε να θεωρήσουµε µια διακοπή σαν µια υπορουτίνα, µόνο που οι διακοπές είναι ήδη καθορισµένες και δεν τις προγραµµατίζουµε εµείς. Οι διακοπές κάνουν δουλειές ρουτίνας, όπως τοποθέτηση αλφαριθµητικών στην οθόνη, καθορισµός της κατάστασης της οθόνης, pixel plotting κλπ. Μερικές σηµαντικές interrupts είναι οι παρακάτω. Interrupt Λειτουργία Περιγραφή Χρήση INT 20h - Έξοδος στο DOS (Μόνο για INT 20 προγράµµατα COM) INT 21h 1 Είσοδος ενός χαρακτήρα από το πληκτρολόγιο. Ο χαρακτήρας επιστρέφεται MOV AH,1 INT 21 στον καταχωρητή AL 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 (Start MS 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.