8086 Assembler Tutorial for Beginners (Part 8)

Procedures

הדרכה בתכנות אסמבלר 8086 למתחילים (חלק 8)  

פרוצדורות (שגרות)

Procedure is a part of code that can be called from your program in order to make some specific task. Procedures make program more structural and easier to understand. Generally procedure returns to the same point from where it was called.

The syntax for procedure declaration:

פרוצדורה היא חלק של תוכנית שיכולים להפעיל מתוך התוכנית הכוללת לצורך ביצוע משימה (או פונקציה) ספציפית. הפרוצדורות עושות את התוכנית יותר מובנה ויותר קל להבנה.  בדרך כלל בסיום ביצוע הפרוצדורה בקרת התוכנית חוזרת לנקודה המיידית לאחר זה שהזמין את תחילת הביצוע.

התחביר של הגדרת הפרוצדורה הוא:

name PROC

      ; here goes the code
      ; of the procedure ...

RET
name ENDP

שם  PROC

     ;כאן רושמים את  הפקודות
     ;          .....של הפרוצדורה

RET
שם ENDP

name - is the procedure name, the same name should be in the top and the bottom, this is used to check correct closing of procedures.

Probably, you already know that RET instruction is used to return to operating system. The same instruction is used to return from procedure (actually operating system sees your program as a special procedure).

PROC and ENDP are compiler directives, so they are not assembled into any real machine code. Compiler just remembers the address of procedure.

CALL instruction is used to call a procedure.

Here is an example:

שם - הוא השם של הפרוצדורה, אותו שם חייב להיות בחלק העליון ובסיום של הפרוצדורה, המהדר משתמש בזה לבדיקת גבולות הפרוצדורה.


כפי שאתה כבר יודע הפקודה RET מיועדת לחזרה למערכת ההפעלה. אותה פקודה משתמשים לחזרה מפרוצדורה לתוכנית שהזמין אותה. בתוכנה Emu8086, המערכת מתייחסת לתוכנית שלך כפרוצדורה מיוחדת.

הפקודות PROC ו- ENDP הם הנחיות עבור המהדר, כלומר הם לא הופכות לחלק של שפת המכונה. המהדר רק זוכר את הכתובות של הפרוצדורה.

פקודת CALL מיועדת לקריא לפרוצדורה


 דוגמה  בהמשך:

ORG    100h

CALL   m1

MOV    AX, 2

RET                   ; return to operating system.
                      ; חזרה למערכת ההפעלה
m1     PROC
MOV    BX, 5
RET                   ; return to caller.
                      ; חזרה למי שהזמין את הפרוצדורה
m1     ENDP

END

The above example calls procedure m1, does MOV BX, 5, and returns to the next instruction after CALL: MOV AX, 2.

There are several ways to pass parameters to procedure, the easiest way to pass parameters is by using registers, here is another example of a procedure that receives two parameters in AL and BL registers, multiplies these parameters and returns the result in AX register:

הדוגמה הקודמת קוראת לפרוצדורה m1, מבצעת הפקודה: MOV Bx, 5, וחוזר לפקודה הבא לאחר ה- Call , כלומר:  MOV AX,2 .

יש כמה דרכים לעברת נתונים לפרוצדורה, הדרך הכי קלה היא לעביר פרמטרים על ידי שימוש באוגרים. בהמשך דוגמה נוספת של פרוצדורה שמקבלת שני פרמטרים באורגרים AL ו- BL , מכפיל את הפרמטרים ומחזיר את התוצאה באוגר AX. הפעולה חוזרת על עצמה מספר פעמים.


ORG    100h

MOV    AL, 1
MOV    BL, 2

CALL   m2
CALL   m2
CALL   m2
CALL   m2

RET                   ; return to operating system.
                      ; חזרה למערכת ההפעלה
m2     PROC
MUL    BL             ; AX = AL * BL.
RET                   ; return to caller.
                      ; חזרה למי שהזמין את הפרוצדורה
m2     ENDP

END

In the above example value of AL register is update every time the procedure is called, BL register stays unchanged, so this algorithm calculates 2 in power of 4,
so final result in AX register is 16 (or 10h).
 

Here goes another example,
that uses a procedure to print a Hello World! message:

בדוגמה הקודמת, הערך של אוגר AL מתעדכן כל פעם שנקראת הפרוצדורה, האוגר BL נשאר ללא שינוי, כך האלגוריתם הזה מחשב הערך 2 בחזקת הערך 4 .
בסיום הערך של
AX הוא 16 (10h)

 

כאן דוגמה נוספת, המשתמשת בפרוצדורה להדפסת מסר על המסך "Hello World" :

ORG    100h

LEA    SI, msg        ; load address of msg to SI.
                      ; SI קבל כתובת של הודעה לאוגר
CALL   print_me

RET                   ; return to operating system.
                      ; חזרה למערכת ההפעלה

; ==========================================================
; this procedure prints a string, the string should be null
; terminated (have zero in the end),
; the string address should be in SI register:
; המחרוזת חייבת להסתיים עם הערך אפס
; SI כתובת התחלה של המחרוזת שמורה באוגר

print_me     PROC

next_char:
    CMP  b.[SI], 0    ; check for zero to stop
    JE   stop         ; בדוק קיום של אפס לעצירה

    MOV  AL, [SI]     ; next get ASCII char.
                      ; ASCII קבל נתון חדש מסוג
    MOV  AH, 0Eh      ; teletype function number.
                      ; פונקציה של הדפסה במסך
 INT  10h          ; using interrupt to print a char in AL.
                      ; AL תוך שימוש בפסיקות, הדפס את תוכן
    ADD  SI, 1        ; advance index of string array.
                      ; קדם המצביע של מערך המחרוזת
    JMP  next_char    ; go back, and type another char.
                      ; חזור והקש עוד סימן במקלדת
stop:
RET                   ; return to caller.
                      ; חזרה למי שהזמין את הפרוצדורה
print_me     ENDP
; ==========================================================

msg    DB  'Hello World!', 0   ; null terminated string.
                               ; אפס כסימן לסיום מחרוזת
END

b." - prefix before [SI] means that we need to compare bytes, not words. When you need to compare words add "w." prefix instead. When one of the compared operands is a register it's not required because compiler knows the size of each register.
 
הסימן ".b " שרשום לפני [Si] אומר שאנחנו צריכים להשוות סיביות (כמו לרשום הפקודה Byte Ptr).
 עם צריכים לעבוד עם מילים אז רושמים "
.w " (כמו לרשום הפקודה Word Ptr).
כאשר אחד האופרנדים הוא אוגר אין צורך לרשום הפקודות המקדימות, המהדר יודע הגודל של כל אוגר.
 

<<< to Part 7 <<   >> to Part 9 >>>

<<< לחלק 9 <<   >> לחלק 7 >>>