מערכים באסמבלי¶
מערך (Array) הוא רצף של ערכים בזיכרון, אחד אחרי השני. כל איבר במערך מוקצה בזיכרון בכתובת עוקבת, כך שהמעבד יכול לגשת לכל איבר על פי מיקום התחלתי (offset) בתוספת היסט (index * גודל איבר).
מבנה מערך בזיכרון¶
כדי ליצור מערך של 5 תווים (8 ביט כל אחד):
כתבו את זה באזור המשתנים, (איפה שמוגדר המשתנים בdata segement)
אם נניח שהמערך מתחיל בכתובת 0x1000, אז מיקומי האיברים יהיו:
| אינדקס | ערך | כתובת בזיכרון |
|---|---|---|
| 0 | 1 | 0x1000 |
| 1 | 2 | 0x1001 |
| 2 | 3 | 0x1002 |
| 3 | 4 | 0x1003 |
| 4 | 5 | 0x1004 |
כלומר:
הoffset של איבר = כתובת התחלתית של המערך + אינדקס × גודל איבר
מה זה offset?¶
המילה offset באסמבלי מתארת את המרחק מהתחלת הסגמנט (DS, ES וכו') לכתובת בזיכרון.
כאשר נרשום:
אנחנו בעצם מכניסים לרגיסטר SI את הכתובת שבה מתחיל המערך בזיכרון (בתוך הסגמנט DS).
כלומר, לSI יהיה את הכתובת של תחילת המערך, אשר מוגדר בds.
כלומר:
[si]יתייחס ל־array[0],[si+1]יתייחס ל־array[1] וכן הלאה.
דוגמה 1: סכימת מערך של מספרים בגודל 8 ביט¶
נניח:
mov cx, 10 ; 10 איברים
mov si, offset array ; כתובת התחלתית
xor ax, ax ; איפוס AX, AH יכיל את הסכום
sum_loop:
lodsb ; טען AL ← [DS:SI], הגדל SI
add ah, al ; הסכום ב-AH (היזהר: Overflow!)
loop sum_loop ; CX -= 1, המשך אם CX ≠ 0
ניתוח הקוד:¶
-
ה
lodsbגורם לכך ש־AL = array[i], SI++ -
ה
add ah, alמוסיף את AL לסכום (שמוחזק ב־AH) -
ה
loopמפעיל את הלולאה CX פעמים
דוגמה 2: העתקת מערך של מספרים בגודל 16 ביט¶
נניח:
כל ערך כאן תופס 2 בייטים (כי זה dw ולא db)
mov cx, 5 ; 5 איברים
mov si, offset src
mov di, offset dst
copy_loop:
mov ax, [si] ; טען את הערך בכתובת src[i] אל AX
mov [di], ax ; כתוב את AX ל־dst[i]
add si, 2 ; הגדל SI ב-2 כדי לעבור לאיבר הבא
add di, 2 ; הגדל DI ב-2 ביעד
loop copy_loop
ניתוח הקוד:¶
-
[si]ניגש לכתובת המקור הנוכחית (src) -
[di]ניגש לכתובת היעד הנוכחית (dst) -
צריך להגדיל כל פעם ב־2 כי כל איבר הוא 16 ביט = 2 בייט
-
loopחוזר 5 פעמים
דוגמה 3: גישה לאיבר מסוים לפי אינדקס¶
נניח שיש לנו מערך array db 10, 20, 30, 40, 50 ואנחנו רוצים לגשת לאיבר מס' 3 (האיבר הרביעי – כלומר 40)
אם המערך הוא של 16 ביט (כל איבר 2 בייט):
מחרוזות באסמבלי¶
מחרוזת (string) באסמבלי היא פשוט מערך של תווים, שכל תו הוא בית אחד (db),
ובסוף המחרוזת, נשים את המספר 0.
"h", "e", "l", "l", "o", 0
תו הסיום של המחרוזת (0) נמצא כדי שהתוכנית תדע מתי המחרוזת נגמרת.
דוגמה:¶
המחרוזת הזו תיראה בזיכרון כך:
| תו | קוד ASCII |
|---|---|
| H | 72 |
| e | 101 |
| l | 108 |
| l | 108 |
| o | 111 |
| , | 44 |
| 32 | |
| w | 119 |
| o | 111 |
| r | 114 |
| l | 108 |
| d | 100 |
| ! | 33 |
| \0 | 0 |
למה להוסיף 0 בסוף?¶
כקונבנציה, תמיד נדאג שמחרוזות יסתיימו ב0- זה מאפשר לנו- מתכנתים באסמבלי לכתוב פונקציות שמסתמכות על כך שהמחרוזת מסתיימת ב0.
למשל, אם תרצו לכתוב פונקציה שסופרת את כמות התווים של מחרוזת, תוכלו לכתוב פונקציה שעוברת על כל התווים עד שהיא מגיעה ל0.
לכן כלל ברזל: מחרוזת = רצף תווים שמסתיים ב־0, המספר הזה מכונה גם ה
null terminator.
עוד דוגמה:¶
עבודה עם מחרוזות ועם מערכים במעבד 8086¶
במעבד 8086 קיימות פקודות ייעודיות לעבודה עם מחרוזות ומערכים – שנועדו לייעל העתקות, השוואות ופעולות על נתונים עוקבים בזיכרון (כמו תווים של מחרוזת או איברי מערך).
רגיסטרים רלוונטיים¶
SI (Source Index)¶
-
רגיסטר שמצביע על מקור הנתונים בזיכרון. (כתובת מקור)
-
נחשב אוטומטית כיחסי ל־
DS(Data Segment) כברירת מחדל.
כלומר, אם תשתמשו בו, הוא אוטמטית יוסיף את הכתובת של הDS להתחלתו אלא אם תסמנו אחרת
DI (Destination Index)¶
-
רגיסטר שמצביע על יעד הנתונים בזיכרון. (כתובת יעד)
-
נחשב אוטומטית כיחסי ל־
ES(Extra Segment) כברירת מחדל.
כלומר, אם תשתמשו בו, הוא אוטמטית יוסיף את הכתובת של הES להתחלתו אלא אם תסמנו אחרת
CX (Counter Register)¶
- משמש כסופר לולאות או חזרות – בפרט עם הפקודה
REP. (נציג בהמשך)
פעולות בסיסיות על מחרוזות/מערכים¶
MOVSB – העתקת בתים ממקור ליעד¶
מעתיקה בית אחד מהכתובת [DS:SI] אל [ES:DI].
ולאחר ההעתקה הSI גדל ב1, והDI גדל ב1.
LODSB – Load String Byte¶
טועו בית מהכתובת [DS:SI] לתוך AL.
ולאחר הטעינה, הSI גדל ב1.
STOSB – Store String Byte¶
שומר את AL לתוך [ES:DI].
ולאחר השמירה, הDI גדל ב1.
השוואת מחרוזות¶
CMPSB – Compare String Bytes¶
משווה את [DS:SI] ל־[ES:DI] (בית מול בית), ומשנה דגלים (Flags) בהתאם.
-
מבצע:
[DS:SI] - [ES:DI](בדומה לcmp) -
הדגלים מתעדכנים, כמו בcmp שאנחנו מכירם (ZF, SF וכו')
-
הSI גדל ב1, והDI גדל ב1.
SCASB – Scan String Byte¶
מעתיק את AL ל־[ES:DI].
ולאחר ההעתקה, הDI גדל ב1.
הפקודה REP – Repeat¶
הפקודה REP חוזרת על הפקודה שאחריה CX פעמים, עד ש־CX = 0.
- תבצע
movsb CX פעמים- ואחרי כל פעולה: תחסיר את cx ב1, עד שcx 0.
פקודות נוספות:¶
-
REPE/REPZ– Repeat While Equal / Zero
חוזר כל עוד ZF = 1 -
REPNE/REPNZ– Repeat While Not Equal / Not Zero
חוזר כל עוד ZF = 0
דוגמאות מפורטות¶
דוגמה 1 – העתקת מחרוזת של 10 בתים:¶
mov cx, 10 ; מספר התווים
mov si, offset src
mov di, offset dst
rep movsb ; העתקה מ־[DS:SI] ל־[ES:DI]
דוגמה 2 – העמסת מחרוזת לתוך AL בלולאה¶
דוגמה 3 – השוואת מחרוזות¶
mov cx, 10
mov si, offset str1
mov di, offset str2
repe cmpsb ; חזור כל עוד תווים שווים
; אם CX = 0 → המחרוזות שוות
; אם ZF = 0 → נמצא הבדל מוקדם