8086 Assembler Tutorial for Beginners (Part 3) Variables |
הדרכה בתכנות אסמבלר 8086 למתחילים (חלק 3) משתנים |
Variable is a memory location. For a programmer it is much easier to have some
value be kept in a variable named "var1" then at the address 5A73:235B,
especially when you have 10 or more variables.
Our compiler supports two types of variables: BYTE and WORD. |
משתנה הוא מיקום של זיכרון
מוגדר על ידי שם.
|
Syntax for a variable declaration: name DB value name DW value DB - stays for Define Byte. DW - stays for Define Word. name - can be any letter or digit combination, though it should start with a letter. It's possible to declare unnamed variables by not specifying the name (this variable will have an address but no name). value - can be any numeric value in any supported numbering system (hexadecimal, binary, or decimal), or "?" symbol for variables that are not initialized. |
תחביר להגדרת משתנה:
DB - פירושו הגדרת משתנה בגודל בית. |
As you probably know from part 2 of this tutorial,
MOV instruction is used to copy values from source to destination.
Let's see another example with MOV instruction: |
כפי שאתה כבר יודע מ-
חלק 2 של הדרכה זו,
משתמשים בפקודת ה- MOV
להעתקת ערכים ממקור ליעד. |
|
Copy the above code to Emu8086 source editor, and press F5 key to compile and load it in the emulator. You should get something like: |
העתק
את הצופן הרשום למעלה לתוך העורך של תוכנת Emu8086, לחץ
על כפתור F5
להידור וטען את התוכנית לתוך האמולטור. |
As you see this looks a lot like our example, except that variables are replaced
with actual memory locations. When compiler makes machine code, it automatically
replaces all variable names with their offsets. By default segment is
loaded in DS register (when COM files is loaded the value
of DS register is set to the same value as CS register - code segment).
In memory list first row is an offset, second row is a hexadecimal value, third row is decimal value, and last row is an ASCII character value. Compiler is not case sensitive, so "VAR1" and "var1" refer to the same variable. The offset of VAR1 is 0108h, and full address is 0B56:0108. The offset of var2 is 0109h, and full address is 0B56:0109, this variable is a WORD so it occupies 2 BYTES. It is assumed that low byte is stored at lower address, so 34h is located before 12h. You can see that there are some other instructions after the RET instruction, this happens because disassembler has no idea about where the data starts, it just processes the values in memory and it understands them as valid 8086 instructions (we will learn them later). You can even write the same program using DB directive only: |
כפי שאתה רואה התמונה הקודמת היא כמו
הדוגמה שלנו, פרט משמות המשתנים שהוחלפו במקומות זיכרון ממשיים. כאשר
המהדר מבצע את תרגום הפקודות לשפת מכונה, הוא מחליף באופן אוטומטי את שמות
כל המשתנים עם האופרנדים (כתובות לוגיות) שלהם. כברירת מחדל
המקטע נטען עם הערך של האוגר DS.
בזמן שקבצים מסוג COM
נטענים, ערך האוגר DS
מוגדר עם אותו ערך של אוגר CS
(מקטע של תוכנית). |
|
Copy the above code to Emu8086 source editor, and press F5 key to
compile and load it in the emulator. You should get the same disassembled code,
and the same functionality!
As you may guess, the compiler just converts the program source to the set of bytes, this set is called machine code, processor understands the machine code and executes it. ORG 100h is a compiler directive (it tells compiler how to handle the source code). This directive is very important when you work with variables. It tells compiler that the executable file will be loaded at the offset of 100h (256 bytes), so compiler should calculate the correct address for all variables when it replaces the variable names with their offsets. Directives are never converted to any real machine code. Why executable file is loaded at offset of 100h? Operating system keeps some data about the program in the first 256 bytes of the CS (code segment), such as command line parameters and etc. Though this is true for COM files only, EXE files are loaded at offset of 0000, and generally use special segment for variables. Maybe we'll talk more about EXE files later. |
העתק את התוכנית הנ"ל לתוך האמולאטור
Emu8086 ולחץ על כפתור F5
לביצוע הידור וטעינה בתוכנת ההדמיה. |
Copyright 2002-2003 - Emu8086, Inc. All rights reserved. - Portions Copyright 1997-2003 Barry Allyn. All rights reserved.
Hebrew Version Copyright COVAL Computer Software - Copyright © 2003 R&D Private Advisers All rights reserved.
Arrays
Arrays can be seen as chains of variables. A text string is an example of a byte array, each character is presented as an ASCII code value (0..255). Here are some array definition examples: a DB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h b DB 'Hello', 0 b is an exact copy of the a array, when compiler sees a string inside quotes it automatically converts it to set of bytes. This chart shows a part of the memory where these arrays are declared: |
מערכים |
You can access the value of any element in array using square brackets,
for example: MOV AL, a[3] You can also use any of the memory index registers BX, SI, DI, BP, for example: MOV SI, 3 MOV AL, a[SI] If you need to declare a large array you can use DUP operator. The syntax for DUP: number DUP ( value(s) ) number - number of duplicate to make (any constant value). value - expression that DUP will duplicate. for example: c DB 5 DUP(9) is an alternative way of declaring: c DB 9, 9, 9, 9, 9 one more example: d DB 5 DUP(1, 2) is an alternative way of declaring: d DB 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 Of course, you can use DW instead of DB if it's required to keep values larger then 255, or smaller then -128. DW cannot be used to declare strings! The expansion of DUP operand should not be over 1020 characters! (the expansion of last example is 13 chars), if you need to declare huge array divide declaration it in two lines (you will get a single huge array in the memory). |
אתה יכול לגשת לכל איבר של המערך באמצאות
סוגרים מרובעים לאחר שם המערך, למשל:
מספר: מספר העתקים לביצוע (כל ערך
קבוע). |
Getting the Address of a Variable
There is LEA (Load Effective Address) instruction and alternative OFFSET operator. Both OFFSET and LEA can be used to get the offset address of the variable. LEA is more powerful because it also allows you to get the address of an indexed variables. Getting the address of the variable can be very useful in some situations, for example when you need to pass parameters to a procedure. |
קבלת כתובת של משתנה |
Reminder: BYTE PTR - for byte. WORD PTR - for word (two bytes). For example: BYTE PTR [BX] ; byte access. or WORD PTR [BX] ; word access. Emu8086 supports shorter prefixes as well:
sometimes compiler can calculate the data type automatically, but you may not and should not rely on that when one of the operands is an immediate value. |
תזכורת:
האמולטור Emu8086 תומך גם בקיצורים:
לפעמים המהדר יכול לחשב בעצמו את סוג הנתונים באופן אוטומטי, אבל לא צריכים לסמוך על כך כאשר משתמשים בערכים במעון מיידי. |
Here is first example: |
להלן דוגמה ראשונה: |
ORG 100h MOV AL, VAR1 ; check value of VAR1 by moving it to AL. ; Var1 בדיקת ערך של LEA BX, VAR1 ; get address of VAR1 in BX. ; VAR1 קבל כתובת של MOV BYTE PTR [BX], 44h ; modify the contents of VAR1. ; VAR1 הכנס ערך מספרי חדש בתוך MOV AL, VAR1 ; check value of VAR1 by moving it to AL. ; Var1 בדיקת ערך של RET VAR1 DB 22h END |
Here is another example, that uses OFFSET instead of LEA: | להלן דוגמה נוספת, המשתמשת בפקודה OFFSET במקום פקודת LEA. |
ORG 100h MOV AL, VAR1 ; check value of VAR1 by moving it to AL. ; Var1 בדיקת ערך של MOV BX, OFFSET VAR1 ; get address of VAR1 in BX. ; VAR1 קבל כתובת של MOV BYTE PTR [BX], 44h ; modify the contents of VAR1. ; VAR1 הכנס ערך מספרי חדש בתוך MOV AL, VAR1 ; check value of VAR1 by moving it to AL. ; Var1 בדיקת ערך של RET VAR1 DB 22h END |
Both examples have the same functionality. These lines: LEA BX, VAR1 MOV BX, OFFSET VAR1 are even compiled into the same machine code: MOV BX, num num is a 16 bit value of the variable offset. Please note that only these registers can be used inside square brackets (as memory pointers): BX, SI, DI, BP! (see previous part of the tutorial). |
שתי הדוגמאות בעלות אותה פונקציונאליות
(מביאות אותנו לאותה תוצאה). |
Constants
For example: |
קבועים לדוגמה: |
k EQU 5 MOV AX, k |
The above example is functionally identical to code: | הדוגמה הקודמת גורמת לאותו ביצוע של השורה שבהמשך: |
MOV AX, 5 |
You can view variables while your program executes by selecting "Variables" from the "View" menu of emulator. | ניתן לעקוב אחרי המשתנים בזמן ריצת התוכנית. זאת ניתן לבצע על ידי בחירת "משתנים" מתפריט "מראה" של האמולטור. |
To view arrays you should click on a variable and set Elements property
to array size. In assembly language there are not strict data types, so any variable
can be presented as an array.
You can edit a variable's value when your program is running, simply double click it,
or select it and click Edit button.
|
אם ברצונך לראות את המערכים, עליך להקיש על שם
המשתנה ולהגדיר בהתאם את ה"מרכיבים" לגודל המערך. בשפת אסמבלר אין
חוקים נוקשים לגבי סוגי נתונים, על כן כל משתנה ניתן להגדיר כמשתנה. ניתן לראות משתנים בכל שיטת ספירה:
אתה יכול לבצע עריכה של ערך המשתנים בזמן ריצת
התוכנית באמולטור, יש לבצע הקשה כפולה מעל שם המשתנה, או לסמן אותו
ולהקיש על כפתור "עריכה". |
Copyright 2002-2003 - Emu8086, Inc. All rights reserved. - Portions Copyright 1997-2003 Barry Allyn. All rights reserved.
Hebrew Version Copyright COVAL Computer Software - Copyright © 2003 R&D Private Advisers All rights reserved.