[Contents][Art of Assembly][Randall Hyde]

Art of Assembly Language: Κεφαλαιο 5


ΚΕΦΑΛΑΙΟ 5  ΜΕΤΑΒΛΗΤΕΣ ΚΑΙ ΔΟΜΕΣ     ΔΕΔΟΜΕΝΩΝ

5.0. Περίληψη
5.1. Κάποιες επιπρόσθετες εντολές : LEA, LES, ADD και MUL.
5.2. Δήλωση Μεταβλητών στο πρόγραμμα Assembly
5.3 Δήλωση και Προσπέλαση Βαθμωτών Μεταβλητών
5.3.1.Δήλωση και Χρήση Μεταβλητών Byte
5.3.2.Δήλωση και Χρήση Μεταβλητών WORD
5.3.3.Δήλωση και Χρήση DWORD Μεταβλητές .
5.3.4.Δήλωση και Χρήση FWORD, QWORD και TBYTE Μεταβλητές.
5.3.5.Δήλωση Κινητής Υποδιαστολής Μεταβλητών με REAL4, REAL8 και REAL10.
5.4.Δημιουργώντας τα δικά σου ονόματα τύπων με το TYPEDEF.
5.5.Τύποι Δεδομένων Δεικτών.
 


Copyright 1996 by Randall Hyde

All rights reserved.

Duplication other than for immediate display through a browser is prohibited by U.S. Copyright Law.

This material is provided on-line as a beta-test of this text. It is for the personal use of the reader only. If you are interested in using this material as part of a course, please contact

rhyde@cs.ucr.edu

Supporting software and other materials are available via anonymous ftp from ftp.cs.ucr.edu. See the "/pub/pc/ibmpcdir" directory for details. You may also download the material from "Randall Hyde's Assembly Language Page" at URL:

http://webster.ucr.edu

Notes:

This document does not contain the laboratory exercises, programming assignments, exercises, or chapter summary. These portions were omitted for several reasons: either they wouldn't format properly, they contained hyperlinks that were too much work to resolve, they were under constant revision, or they were not included for security reasons. Such omission should have very little impact on the reader interested in learning this material or evaluating this document.

This document was prepared using Harlequin's Web Maker 2.2 and Quadralay's Webworks Publisher. Since HTML does not support the rich formatting options available in Framemaker, this document is only an approximation of the actual chapter from the textbook.

If you are absolutely dying to get your hands on a version other than HTML, you might consider having the UCR Printing a Reprographics Department run you off a copy on their Xerox machines. For details, please read the following EMAIL message I received from the Printing and Reprographics Department:

Hello Again Professor Hyde,

Dallas gave me permission to take orders for the Computer Science 13 Manuals. We would need to take charge card orders. The only cards we take are: Master Card, Visa, and Discover. They would need to send the name, numbers, expiration date, type of card, and authorization to charge $95.00 for the manual and shipping, also we should have their phone number in case the company has any trouble delivery. They can use my e-mail address for the orders and I will process them as soon as possible. I would assume that two weeks would be sufficient for printing, packages and delivery time.

I am open to suggestions if you can think of any to make this as easy as possible.

Thank You for your business,

Kathy Chapman, Assistant
Printing and Reprographics
University of California
Riverside
(909) 787-4443/4444

We are currently working on ways to publish this text in a form other than HTML (e.g., Postscript, PDF, Frameviewer, hard copy, etc.). This, however, is a low-priority project. Please do not contact Randall Hyde concerning this effort. When something happens, an announcement will appear on "Randall Hyde's Assembly Language Page." Please visit this WEB site at http://webster.ucr.edu for the latest scoop.






ΚΕΦΑΛΑΙΟ 5

ΜΕΤΑΒΛΗΤΕΣ ΚΑΙ ΔΟΜΕΣ ΔΕΔΟΜΕΝΩΝ

Το κεφάλαιο 3 καλύπτει το πώς ένα σύστημα Η/Υ οργανώνει φυσικά τα δεδομένα. Αυτό το κεφάλαιο ολοκληρώνει αυτή την συζήτηση, συνδέοντας την γενική ιδέα απεικόνισης των δεδομένων με την πραγματική φυσική τους απεικόνιση. Όπως δηλώνει και η επικεφαλίδα, το κεφ. 5 ασχολείται με δυο βασικά θέματα: με τις μεταβλητές και την δομή δεδομένων.


5.0. Περίληψη

Αυτό το κεφάλαιο ασχολείται με το πώς δηλώνονται και προσπελαύνονται οι βαθμωτές μεταβλητές , οι ακέραιοι αριθμοί (integer), οι πραγματικοί (real), οι τύποι δεδομένων, οι δείκτες, οι πίνακες και οι δομές. Πρέπει να γίνεις ειδικός σ’ αυτά τα θέματα, για να μπορέσεις να συνεχίσεις παραπέρα. Η δήλωση και η προσπέλαση πίνακα συγκεκριμένα, φαίνεται να παρουσιάζει ένα μεγάλο αριθμό προβλημάτων για τους αρχάριους προγραμματιστές γλώσσας assembly.
 
 


5.1. Κάποιες επιπρόσθετες εντολές : LEA, LES, ADD και MUL.
 

Ο σκοπός αυτού του κεφαλαίου δεν είναι να παρουσιάσουμε όλη την ομάδα εντολών του 80χ86. Υπάρχουν όμως αυτές οι τέσσερις εντολές, οι οποίες θα φανούν χρήσιμες αργότερα. Αυτές είναι : η τελική διεύθυνση φόρτωσης (load effective address - lea), load es  και ο γενικής χρήσης καταχωρητής (les), πρόσθεση (add) και πολλαπλασιασμός (mul).

Η εντολή lea έχει την εξής μορφή :
       Lea    reg16, memory

Reg16 είναι ένας 16-bit καταχωρητής. Memory είναι η θέση μνήμης, εκφραζόμενη ως mod/reg/rm byte(εκτός του ότι πρέπει να είναι θέση μνήμης, δεν μπορεί να είναι καταχωρητής).

Αυτή η εντολή γεμίζει τον 16-bit καταχωρητή με μια απόσταση της θέσης , η οποία καθορίζεται από την λειτουργία της μνήμης. Η Lea    ax, 1000h[bx] [si],  για παράδειγμα, θα φορτώσει το ax με την διεύθυνση της θέσης μνήμης δεικτοδοτούμενη από 1000h[bx] [si]. Αυτό εννοείται, είναι η τιμή 1000h+bx+si. Η εντολή lea είναι επίσης, αρκετά χρήσιμη για να κρατάει την διεύθυνση μιας μεταβλητής. Αν υπάρχει μια μεταβλητή I κάπου στη μνήμη η lea   bx,iθα φορτώσει στο καταχωρητή bx την διεύθυνση της απόστασης του i.

Η εντολή les παίρνει την μορφή
       Les   reg16, memory32

Αυτή η εντολή φορτώνει τον καταχωρητή es καθώς και ένα από τους 16-bit καταχωρητές γενικής χρήσης από την καθορισμένη διεύθυνση μνήμης. Σημείωσε ότι μπορείς και είναι έγκυρο να ορίσεις οποιαδήποτε διεύθυνση μνήμης μ’ ένα mod/reg/rm byte αλλά όπως και στην εντολή lea, πρέπει να είναι  θέση μνήμης και όχι καταχωρητής.

Η εντολή les φορτώνει τον καθορισμένο καταχωρητή γενικής χρήσης από την λέξη στην δοσμένη διεύθυνση και φορτώνει τον καταχωρητή es από την ακόλουθη λέξη στην μνήμη.
Η εντολή add, προσθέτει δυο τιμές στον 80x86. Αυτή η εντολή παίρνει διάφορες μορφές. Παρακάτω υπάρχουν πέντε από τις μορφές του :

Add       reg,   reg
Add       reg,   memory
Add       memory,   reg
Add       reg,   constant
Add       memory,   constant

Όλες αυτές οι εντολές προσθέτουν το δεύτερο τελούμενο στο πρώτο και αφήνουν το άθροισμα στο πρώτο τελούμενο. Π.χ. add   bx,   5   έχουμε  bx:=bx+5.

Η εντολή mul έχει ένα μοναδικό τελούμενο και παίρνει την μορφή :
        Mul     reg/memory
Δεν θα ασχοληθούμε πολύ μ’ αυτή. Απλά θεώρησε ότι ο καταχωρητής και η θέση μνήμης είναι 16-bit έκαστος. Έτσι η εντολή αυτή έχει ως αποτέλεσμα dx:ax:=ax*reg/mem.
 
 


5.2. Δήλωση Μεταβλητών στο πρόγραμμα Assembly

Αν και πιθανότατα έχεις κάνει την υπόθεση ότι η θέση μνήμης και οι μεταβλητές είναι κάπως συσχετιζόμενες, σ’ αυτό το κεφάλαιο θα διορθώσουμε την κατάσταση. Δες το παρακάτω μικρό (και χρήσιμο) πρόγραμμά σε Pascal.

Progam useless(input,output);
Var i,j:integer;
Begin

          i:=10;
          Write(‘Enter a value for j:’);
          Readln(j);
          i:=i*j+j*j;
          Writeln(‘the result is’,i);
End.

Όταν ο υπολογιστής εκτελεί την εντολή i:=10; φτιάχνει ένα αντίγραφο της τιμής 10 και κάπως θυμάται αυτή την τιμή για να την χρησιμοποιήσει αργότερα. Για να το κατορθώσει, ο μεταγλωττιστής βάζει στην άκρη μια θέση μνήμης καθορισμένη για την αποκλειστική χρήση από την μεταβλητή i. Ας υποθέσουμε ότι ο compiler αυθαίρετα αναθέτει στην θέση DS:10h αυτό το σκοπό, τότε για να το πραγματοποιήσει θα μπορούσε να χρησιμοποιήσει την εντολή mov  ds:[10h],10. Αν το i είναι μια 16-bit λέξη, ο μεταγλωττιστής θα εκχωρούσε την μεταβλητή j στην λέξη που αρχίζει από την θέση 12h και η δεύτερη δήλωση εκχώρησης στο πρόγραμμα θα κατέληγε να μοιάζει με το ακόλουθο.

Mov      ax,   ds:[10h]    ; ταίριαξε την τιμή i
Mul      ds:[12h]             ; πολλαπλασίασε  με το j
mov      ds:[10h], ax       ; αποθήκευσε το στο i (αγνόησε την υπερχείλιση)
mov      ax,   ds:[12h]     ; ταίριαξε το j
mul       ds:[12h]             ; υπολόγισε j*j
add      ds:[10h],   ax     ; πρόσθεσε i*j+j*j, αποθήκευσε το στο i.

Τώρα σκέψου ένα πρόγραμμα των 5000 γραμμών όπως το παραπάνω, όπου θα χρησιμοποιεί μεταβλητές όπως ds:[10h], ds:[12h], ds:[14h] κτλ. Είναι λογικό να ξαναγράψεις  το παραπάνω κώδικα ως εξής :

Mov      ax,   i
Mul       j
Mov      i,   ax
Mov      ax,   j
Mul       j
Add       i, ax

Φυσικά μπορείς να το κάνεις  αυτό στην γλώσσα assembly. Αυτή είναι η πρωταρχική δουλειά ενός assembler, όπως ο MASM. Σου δίνουν την δυνατότητα να χρησιμοποιείς συμβολικά ονόματα για τις θέσεις μνήμης. Επιπλέον ο assembler θα δώσει ακόμη και τις θέσεις στα ονόματα, αυτόματα .
 
 
 
 


5.3 Δήλωση και Προσπέλαση Βαθμωτών Μεταβλητών
 

Οι βαθμωτές μεταβλητές κρατάνε μοναδικές τιμές. Οι μεταβλητές i και j στην προηγούμενη ενότητα είναι παραδείγματα βαθμωτών μεταβλητών. Παράδειγμα δομών δεδομένων τα οποία δεν είναι βαθμωτά, περιέχουν οι πίνακες, οι εγγραφές , τα σύνολα και οι λίστες. Αυτοί οι τελευταίοι τύποι δεδομένων προέκυψαν από βαθμωτές τιμές. Είναι οι σύνθετοι τύποι.

Για να δηλώσεις μια μεταβλητή στο τμήμα δεδομένων, θα χρησιμοποιούσες κάτι τέτοιο :
ByteVar     byte

ByteVar είναι μια ετικέτα. Θα πρέπει να αρχίζει στην στήλη 1, στην γράμμη κάπου στo τμήμα δεδομένων ( αυτό είναι μεταξύ των δηλώσεων dseg segment και  dseg ends). Μπορείς να συμπεράνεις ότι τα περισσότερα αναγνωριστικά στην Pascal/C/Ada είναι έγκυρες ετικέτες της assembly.

Αν χρειάζεσαι παραπάνω από μια μεταβλητή στο πρόγραμμα σου, απλά τοποθέτησε επιπρόσθετες γραμμές στο τμήμα δεδομένων, δηλώνοντας αυτές τις μεταβλητές. Ο assembler MASM αυτόματα κατανέμει μια μοναδική θέση αποθήκευσης για την μεταβλητή. Αφού έχεις δηλώσει την μεταβλητή, ο MASM σου δίνει την δυνατότητα να αναφέρεσαι σ’ αυτή την μεταβλητή με το όνομα της και όχι με την θέση της μέσα στο πρόγραμμα.
 


5.3.1. Δήλωση και Χρήση Μεταβλητών Byte

Το σίγουρο είναι ότι μπορείς να αναπαραστήσεις οποιοδήποτε τύπο δεδομένων που έχει λιγότερες από 256 διαφορετικές τιμές μ’ ένα μοναδικό byte. Αυτό περιλαμβάνει μερικούς σημαντικούς τύπους δεδομένων, οι οποίοι χρησιμοποιούνται συχνά, όπως οι χαρακτήρες οι boolean, οι απαριθμητικοί τύποι δεδομένων και οι μικροί integer.

Οι χαρακτήρες σ’ ένα τυπικό IBM συμβατό σύστημα, χρησιμοποιούν την 8-bit ομάδα χαρακτήρων ASCII.

Τα δεδομένα boolean αναπαριστούν δυο τιμές:true/false.  Έτσι αναπαριστά μόνο ένα μοναδικό bit για να αναπαραστήσει μια τιμή boolean. Ο 80x86 θέλει να εργάζεται με δεδομένα μεγέθους τουλάχιστον 8-bits. Παίρνει επιπλέον κώδικα για να χειριστεί ένα μοναδικό bit απ’ ότι ένα ολόκληρο byte. Όμως, θα πρέπει να χρησιμοποιείς ένα ολόκληρο byte για να αναπαραστήσεις μια τιμή boolean. Συνήθως δίνουν την τιμή 0 για να αναπαραστήσουν το false και οποιοδήποτε άλλο (τυπικά το 1) για το true.

Οι περισσότερες υψηλού επιπέδου γλώσσες που υποστηρίζουν τους απαριθμητούς τύπους δεδομένων, τους μετατρέπουν σε μη-προσημασμένους ακέραιους. Το πρώτο στοιχείο της λίστας είναι το στοιχείο 0, το δεύτερο είναι το στοιχείο 1, το τρίτο το στοιχείο 2 κοκ. Παρατηρήστε  τον ακόλουθο Pascal απαριθμητικό τύπο δεδομένων

Colors=(red, blue, green, purple)
Red=0  ,  blue=1  ,  green=2   κοκ.

Υπάρχουν τρείς βασικοί τύποι για να δηλώσεις μεταβλητές byte σε ένα πρόγραμμα . Αυτές είναι :

Identifier         db       ?
Identifier         byte    ?
Identifier         sbyte  ?
 

Ο identifier αναπαριστά το όνομα της byte μεταβλητής x. Η «db» είναι ένας παλαιότερος όρος. Η δήλωση «byte» δηλώνει μη-προσημασμένες μεταβλητές byte. Πρέπει να χρησιμοποιείς αυτή την δήλωση για όλες τις byte μεταβλητές εκτός των μικρών προσημασμένων ακεραίων. Για προσημασμένες ακέραιες τιμές, χρησιμοποίησε την sbyte - προσημασμένη byte εντολή.

Αν μια φορά δηλώσεις κάποιες μεταβλητές byte μ’ αυτό τον τρόπο, μπορείς να αναφέρεσαι σ’ αυτές τις μεταβλητές με τα ονόματα τους μέσα στο πρόγραμμα.
 
 

i        db            ?
j        byte         ?
k      sbyte       ?
            .
            .
          mov         i,   0
          mov         j,   245
          mov         k,   -5
          mov         al,   i
          mov         j,   al
           κτλ.
 


5.3.2. Δήλωση και Χρήση Μεταβλητών WORD
 

Τα περισσότερα 80χ86 προγράμματα χρησιμοποιούν word τιμές για τρία πράγματα: 16-bit προσημασμένους ακέραιους, 16-bit μη-προσημασμένους ακέραιους  και δείκτες απόστασης. Από την στιγμή που οι μεταβλητές word είναι ο μεγαλύτερος τύπος δεδομένων που ο 8086,8088,80186,80188 και ο 80286 μπορούν να χειριστούν, θα ανακαλύψεις ότι για τα περισσότερα προγράμματα, η μεταβλητή word είναι η βάση για τους περισσότερους υπολογισμούς.

Χρησιμοποιείς τις dw, word και sword δηλώσεις για να ορίσεις μεταβλητές word. Τα ακόλουθα παραδείγματα αποκαλύπτουν την χρήση τους.

NoSignedWord dw ?
UnSignedWord word ?
SignedWord  sword ?
Initialized0  word 0
InitializedM1  sword -1
InitializedBig  word 65535
InitializedOfs  dw NoSignedWord

Οι περισσότερες από αυτές τις δηλώσεις είναι μικρές τροποποιήσεις των δηλώσεων byte. Φυσικά, μπορείς να αρχίσεις οποιαδήποτε μεταβλητή word από μια τιμή μέσα στο εύρος 32768…65535. Αυτή η δήλωση είναι καινούργια. Σ’ αυτήν την περίπτωση μια ετικέτα εμφανίζεται στο τελούμενο πεδίο. Όταν συμβαίνει αυτό, ο assembler υποκαθιστά την απόσταση με αυτή την ετικέτα. Αν αυτές είναι οι μόνες δηλώσεις στο τμήμα δεδομένων και εμφανίζονται με αυτή τη σειρά, η τελευταία παραπάνω δήλωση θα ξεκινήσει το InitializedOfs με την τιμή 0 μέχρι η απόσταση του NoSignedWord γίνει 0 μέσα στο τμήμα δεδομένων.
 
 


5.3.3. Δήλωση και Χρήση DWORD Μεταβλητές .

Μπορείς να χρησιμοποιείς τις εντολές add, dword και sdword για να δηλώσεις τεσσάρων byte integer, δείκτες και άλλους τύπους μεταβλητών. Τέτοιες μεταβλητές θα επιτρέπουν τιμές μέσα στο πεδίο 2,147,483,648…4,294,967,295. Χρησιμοποιεί αυτές τις δηλώσεις word :

NoSignedDWord                  dd               ?
UnSignedDWord                  dword         ?
SignedDWord                       sdword       ?
InitBig                                   dword         4000000000
InitBig                                   sdword        -1
InitPtr                                    dd                InitBig
 

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

Είναι αξιοσημείωτο, ότι ο assembler δεν ελέγχει τους τύπους αυτών των μεταβλητών, όταν κοιτάει τις μηδενισμένες τιμές . Αν η τιμή χωράει σε 32 bits , ο assembler θα το δεχθεί. Ο έλεγχος μεγέθους όμως, επιβάλλεται αυστηρά. Εφόσον οι μόνες 32-bit mov εντολές στους προηγούμενους του 80386 επεξεργαστές είναι οι les και lds , θα προκύψει λάθος αν προσπαθήσεις να προσπελάσεις μεταβλητές dword με εντολή mov σ’ αυτούς τους επεξεργαστές. Φυσικά, ακόμη και στον 80386 δεν μπορείς να μεταφέρεις μια 32-bit μεταβλητή, σ’ ένα 16-bit καταχωρητή. Πρέπει να χρησιμοποιήσεις ένα καταχωρητή 32-bit.
 
 


5.3.4. Δήλωση και Χρήση FWORD, QWORD και TBYTE Μεταβλητές.

Ο assembler MASM 6.x σου επιτρέπει να δηλώνεις 6-byte, 8-byte και 10-byte μεταβλητές, χρησιμοποιώντας τις δηλώσεις df/fword, dq/qword και dt/tbyte. Τέτοιου είδους δηλώσεις προορίζονται αρχικά για μετακινούμενους δείκτες και BCD τιμές.

Η κύρια σκοπιμότητα της δήλωσης df/fword είναι να δηλώνει 48-bit δείκτες για χρήση σε 32-bit προστατευόμενο τύπο στον 80386 και στους μετέπειτα. Η dq/qword σου επιτρέπει να δηλώνεις qword(quadword-8 bytes) μεταβλητές . Ο κύριος σκοπός αυτής της εντολής ήταν να σου δίνει την δυνατότητα να δημιουργείς διπλής ακρίβειας δείκτες κινητής υποδιαστολής των 64-bit και μεταβλητές integer  64-bit.

H εντολή dt/tbyte κατανέμει 10bytes αποθήκευσης.
 


5.3.5. Δήλωση Κινητής Υποδιαστολής Μεταβλητών με REAL4, REAL8 και REAL10.

Αυτές είναι οι εντολές που πρέπει να χρησιμοποιείς όταν δηλώνεις μεταβλητές κινητής υποδιαστολής. Όπως η add, dq και dt, αυτές οι δηλώσεις κρατάνε 4,8 και 10bytes. Τα τελούμενα πεδία σ’ αυτές τις δηλώσεις μπορεί να περιέχουν ένα ερωτηματικό ή μια αρχική τιμή στον τύπο της κινητής υποδιαστολής. Τα παρακάτω παραδείγματα δείχνουν την χρήση τους:

X          real4     1.5
Y          real8     1.0e-25
Z          real10    -1.2594e+10

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

X      real4      1

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


5.4. Δημιουργώντας τα δικά σου ονόματα τύπων με το TYPEDEF.

Έστω ότι απλά δεν σου αρέσουν τα ονόματα που η Microsoft αποφασίζει να δώσει στις δηλώσεις byte, word, dword, real και άλλων μεταβλητών. Θέλεις να χρησιμοποιήσεις όρους όπως integer, float, char, boolean ή οτιδήποτε άλλο. Λοιπόν, ο assembler MASM 6.x έχει την δικιά του δήλωση typedef που σου επιτρέπει, επίσης , να δημιουργείς ψευδώνυμα απ’ αυτά τα ονόματα. Τα επόμενα παραδείγματα σου δείχνουν πώς να ενεργοποιήσεις κάποια συμβατά ονόματα της Pascal μέσα στο πρόγραμμα της assembly:

Integer  typedef sword
Char  typedef byte
Boolean typedef byte
Float  typedef real4
Colors  typedef byte

Τώρα μπορείς να δηλώσεις τις μεταβλητές σου με δηλώσεις με μεγαλύτερη σημασία , όπως :

i  ineger  ?
ch  char  ?
foundIt boolean ?
x  float  ?
houseColor colors  ?

5.5. Τύποι Δεδομένων Δεικτών.

Φυσικά , το σημείο από το οποίο πρέπει να αρχίσουμε είναι η ερώτηση «Τι είναι ένας δείκτης;». Πολλοί είναι αυτοί που είχαν κακή εμπειρία με τους δείκτες, όταν τους συνάντησαν σε υψηλού επιπέδου γλώσσες. Είναι πολύ πιο εύκολο να χειρίζεσαι δείκτες στην assembly. Οι δείκτες έχουν πολλές χρήσεις στην γλώσσα assembly που δεν έχουν να κάνουν με συνδεδεμένες λίστες, δένδρα και τέτοιου είδους δομές. Αντίθετα, απλές δομές δεδομένων όπως πίνακες και εγγραφές συχνά απασχολούν τους δείκτες.

Αν φοβάσαι τους δείκτες, άφησε το στην άκρη προς το παρόν και ας δουλέψουμε μ’ ένα πίνακα. Θεώρησε την ακόλουθη δήλωση πίνακα στην Pascal
             M:array[0..1023] of integer;
 
Ο Μ είναι πίνακας με 1024 ακέραιους δεικτοδοτούμενους από το Μ[0] ως το Μ[1023].

Αν συναντήσεις ένα πρόγραμμα με την δήλωση Μ[0]:=100 θα καταλάβαινες αμέσως ότι αποθηκεύει την τιμή 100 στο πρώτο στοιχείο του πίνακα Μ. Τώρα θεώρησε τις δυο επόμενες δηλώσεις :

i:=0; (*θεώρησε το «i» ως ακέραιη μεταβλητή *)
M [i] :=100;

Αυτές οι δυο δηλώσεις κάνουν ακριβώς την ίδια δουλειά με την Μ[0]:=100;

Θα σκεφτείς «Δηλαδή οτιδήποτε παράγει έναν ακέραιο μέσα στα όρια 0..1023 θα είναι έγκυρο;». Τι γίνεται με το παρακάτω ;

M[1]:=0;
M[M[1]]:=100;

Αυτό απαιτεί λίγο χρόνο για να το χωνέψουμε. Με μια πιο προσεχτική ματιά θα ανακαλύψεις ότι και αυτή εκτελεί την ίδια διαδικασία.

Αν μπορέσεις να κατανοήσεις το παραπάνω, τότε δεν θα έχεις κανένα πρόβλημα με τους δείκτες. Γιατί ο Μ[1] είναι δείκτης. Όχι ακριβώς, αλλά αν άλλαζες το «Μ» με το «memory» και χειριστείς τον πίνακα ως μνήμη, έχεις βρει τον ακριβή ορισμό των δεικτών .

Ένας δείκτης είναι απλά μια θέση μνήμης, της οποίας η τιμή είναι η διεύθυνση (ή index) κάποιων άλλων θέσεων μνήμης. Οι δείκτες δηλώνονται και χρησιμοποιούνται πολύ εύκολα στην assembly. Η μόνη πολυπλοκότητα στους δείκτες είναι ότι ο 80x86 υποστηρίζει δυο είδη δεικτών. Τους near pointers και τους far pointers.

Ένας κοντινός δείκτης είναι μια 16-bit τιμή που δίνει ένα offset σ’ ένα τμήμα. Θα μπορούσε να είναι οποιοδήποτε τμήμα, αλλά γενικώς χρησιμοποιεί το τμήμα δεδομένων. Αν έχουμε μια word μεταβλητή p που περιέχει 1000h, τότε η p «δείχνει» στην θέση μνήμης 1000h στο dseg(τμήμα δεδομένων). Για να προσπελάσεις την λέξη που η p δείχνει, μπορείς να χρησιμοποιήσεις κώδικα όπως τον παρακάτω:

Mov  bx,  p       :γέμισε τον BX με το δείκτη
Mov  ax,  [bx]   :ταίριαξε τα δεδομένα που ο p δείχνει.

Φορτώνοντας την τιμή του p στο bx, αυτός ο κωδικός φορτώνει την τιμή 1000h στον bx (το p περιέχει 1000h). Η δεύτερη παραπάνω εντολή φορτώνει στον καταχωρητή ax την λέξη που αρχίζει από την θέση, της οποίας η απόσταση εμφανίζεται στον bx. Εφόσον ο bx τώρα περιέχει 1000h, αυτό θα φορτώσει τον ax από την θέση DS:1000 και DS:1001.

Θεώρησε τις παρακάτω εντολές :
 
 

                lea     bx, i           ;This can actually be done with
                mov     p, bx           ; a single instruction as you'll
                 .                      ; see in Chapter Eight.
                 .
        < Some code that skips over the next two instructions >

                lea     bx, j           ;Assume the above code skips these
                mov     p, bx           ; two instructions, that you get
                 .                      ; here by jumping to this point from
                 .                      ; somewhere else.
                mov     bx, p           ;Assume both code paths above wind
                mov     ax, [bx]        ; up down here.
Αυτό το μικρό παράδειγμα παρουσιάζει δυο μονοπάτια εκτέλεσης μέσα στο πρόγραμμα. Το πρώτο
 μονοπάτι φορτώνει την μεταβλητή p με την διεύθυνση της μεταβλητής i. Το δεύτερο μονοπάτι
μέσα στον κωδικό, φορτώνει την p με την διεύθυνση της μεταβλητής j. Και τα δυο μονοπάτια
εκτέλεσης συγκλίνουν στις δυο τελευταίες εντολές mov οι οποίες φορτώνουν τον ax με I ή j,
 ανάλογα με το ποιο μονοπάτι εκτέλεσης έχει ακολουθηθεί. Από πολλές απόψεις, αυτό είναι
 όπως μια παράμετρος σε μια διαδικασία σε γλώσσα υψηλού επιπέδου όπως Pascal.

Υπάρχουν κάποια μειονεκτήματα όσον αφορά τους near pointers. Μπορείς να προσπελάσεις μόνο
 64Κ δεδομένων (ένα τμήμα ) όταν τους χρησιμοποιείς. Οι far pointers ξεπερνούν αυτόν τον
περιορισμό, λόγω του ότι έχουν 32-bits μήκος . Σου επιτρέπουν να προσπελάσεις οποιοδήποτε
κομμάτι δεδομένων, οπουδήποτε στην μνήμη. Γι’ αυτό το λόγο θα χρησιμοποιήσουμε περισσότερο
τους far pointers. Να γνωρίζεις όμως ότι ο κώδικας που χρησιμοποιεί near pointers και όχι
 far pointers είναι μικρότερος και γρηγορότερος.

Για να προσπελάσεις δεδομένα που δεικτοδοτούνται από δείκτη 32-bit, θα χρειαστεί να φορτώσεις
το τμήμα της  απόστασης (LO-χαμηλής τάξης) του δείκτη στο bx, bp, si ή di και την περιοχή του
τμήματος στο τμήμα καταχωρητή( τυπικά es). Μετά μπορείς να προσπελάσεις το αντικείμενο,
χρησιμοποιώντας τον register indirect addressing mode. Από την στιγμή που η εντολή les είναι
τόσο κατάλληλη για αυτήν την διαδικασία, είναι η τέλεια επιλογή για να φορτώσεις τον es και ένα
από τους παραπάνω τέσσερις καταχωρητές  με μια τιμή δείκτη. Το ακόλουθο δείγμα δείκτη αποθηκεύει
 την τιμή του al στο byte που δεικτοδοτείται από τον far pointer p:

Les     bx,   p             ;φόρτωσε τον p στον ES:BX
Mov     es:[bx],   al    ;αποθήκευσε κάπου  την AL

Εφόσον οι near pointers είναι 16bits και οι far pointers 32-bits, θα μπορούσες απλά να
χρησιμοποιήσεις τις εντολές dw/word και dd/dword για να κατανέμεις τον χώρο αποθήκευσης
 για τους δείκτες σου. Όμως υπάρχει ένας πολύ καλύτερος τρόπος για να το πετύχεις αυτό,
χρησιμοποιώντας την δήλωση typedef. Δες τις παρακάτω γενικές μορφές:

Typename        typedef near ptr basetype
Typename        typedef far ptr basetype

Σ’ αυτά τα δυο παραδείγματα τα typename αναπαριστούν τα ονόματα των νέων τύπων που δημιουργείς
 και basetype είναι το όνομα του τύπου για το οποίο θες να δημιουργήσεις δείκτη. Ας δούμε κάποια
ειδικά παραδείγματα :

Nbytptr typedef near ptr byte
Fbytptr           typedef far ptr byte
Colorsptr        typedef far ptr colors
Wptr               typedef near ptr word
IntHandle      typedef near ptr intptr

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

Οι δηλώσεις typedef με τους τελούμενους near pointers παράγουν 16bit near pointers. Οι δηλώσεις
με τους τελούμενους far pointers παράγουν 32bit far pointers.

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

Με τους παραπάνω τύπους, μπορείς να γενικεύσεις τις μεταβλητές δεικτών ως εξής:

Bytestr nbytptr ?
Bytestr2        fbytptr         ?
CurrentColor    colorsptr       ?
CurrentItem   intptr            ?

 
 

5.0. Περίληψη
5.1. Κάποιες επιπρόσθετες εντολές : LEA, LES, ADD και MUL.
5.2. Δήλωση Μεταβλητών στο πρόγραμμα Assembly
5.3 Δήλωση και Προσπέλαση Βαθμωτών Μεταβλητών
5.3.1.Δήλωση και Χρήση Μεταβλητών Byte
5.3.2.Δήλωση και Χρήση Μεταβλητών WORD
5.3.3.Δήλωση και Χρήση DWORD Μεταβλητές .
5.3.4.Δήλωση και Χρήση FWORD, QWORD και TBYTE Μεταβλητές.
5.3.5.Δήλωση Κινητής Υποδιαστολής Μεταβλητών με REAL4, REAL8 και REAL10.
5.4.Δημιουργώντας τα δικά σου ονόματα τύπων με το TYPEDEF.
5.5.Τύποι Δεδομένων Δεικτών.
 


Art of Assembly: Κεφαλαιο 5 - 26 SEP 1996

[Contents] [Art of Assembly][Randall Hyde]