GammaCyber

Assembly x86

Low-Level: C, Assembly ו-RE · 5–6 שעות

// סקירה

Assembly x86 — רגיסטרים ופקודות בסיס

Assembly היא שכבת הביניים בין C לקוד מכונה. כל מנתח אבטחה, חוקר חולשות ושחקן CTF חייב לקרוא Assembly. זה השיעור שפותח את הדלת.

✓נושאי השיעור
  • שרשרת הקומפילציה: C → Assembly → קוד מכונה
  • מחזור CPU: Fetch-Decode-Execute
  • 8 רגיסטרים כלליים + EIP + FLAGS
  • חלוקת רגיסטרים: 32b / 16b / 8b (EAX → AX → AH/AL)
  • פקודות: MOV, ADD, SUB, INC, DEC, MUL, DIV, PUSH, POP
  • Addressing Modes: Immediate, Register, Direct, Indirect
  • Intel Syntax לעומת AT&T Syntax
  • C↔Assembly: if, for, function call — כל תבנית
  • שיטת Dry Run — עוקבים שורה-שורה
// פרק 1

למה Assembly? — מ-C לקוד מכונה

כשכותבים C, המעבד לא מבין — הוא מבין רק 0 ו-1. התרגום עובר 4 שלבים, וה-Assembly הוא שכבת ביניים טקסטואלית.

שלבקלטפלטכלי
1. Preprocessingcode.ccode.i (אחרי #include, #define)cpp
2. Compilationcode.icode.s — Assembly טקסטואליcc1
3. Assemblycode.scode.o — Object Fileas
4. Linkingcode.o + libsexecutableld
תחוםמה עושיםלמה Assembly
Reverse Engineeringניתוח תוכנות ללא קוד מקורקובץ exe הוא Assembly — אין מקור
Exploit Developmentכתיבת ShellcodeShellcode הוא Assembly גולמי
Malware Analysisהבנת וירוס/טרויאניMalware קומפל ל-ASM
CTF — Pwnפיצוח Binaryקריאת ASM של היעד
מחשבון קרב גאמאשאלות Assembly בכנסקריטי ביותר ←
🔑 Assembly במיון גאמא — 3 פורמטים
1. Dry Run: מה ערך EAX לאחר פקודות אלו? (עוקבים שורה-שורה)
2. זיהוי Pattern: מה עושה קטע ה-Assembly? (if/loop/function call)
3. הפיכה: כתבו ב-C את המקבילה לקוד ASM
אין צורך לשנן Opcodes — צריך להבין מה כל פקודה עושה.
✏תרגול — שרשרת קומפילציה2 שאלות
שאלה 1.1
איזה שלב בשרשרת הקומפילציה מתרגם C ל-Assembly טקסטואלי?
✓ תשובה: ד. שלב 2 (cc1) לוקח קוד C ומייצר קובץ .s — Assembly טקסטואלי. שלב 3 (as) הופך את ה-Assembly לקוד מכונה בינארי (Object File). שלב 4 (ld) מקשר הכל ל-executable.
שאלה 1.2
מה מבצע מחזור Fetch-Decode-Execute?
✓ תשובה: א. זה המחזור הבלתי נפסק של כל מעבד: Fetch = קרא פקודה מ-EIP, Decode = פענח מה לעשות, Execute = בצע, Update EIP = עבור לבאה. כ-3 מיליארד פעמים בשנייה.
// פרק 2

רגיסטרים — 8 תאי הזיכרון של המעבד

רגיסטרים הם תאי האחסון המהירים ביותר — ממש בתוך המעבד. ב-x86 יש 8 רגיסטרים כלליים של 32 ביט, בנוסף ל-EIP ו-FLAGS.

32b64bשם מלאתפקיד מסורתי
EAXRAXAccumulatorתוצאות חישוב, ערך החזרה מפונקציות
EBXRBXBaseבסיס לכתובות — General purpose בפועל
ECXRCXCounterמונה לולאות ו-REP
EDXRDXDataנתונים, זוג עם EAX ב-MUL/DIV
ESIRSISource Indexמקור בפעולות מחרוזת
EDIRDIDestination Indexיעד בפעולות מחרוזת
ESPRSPStack Pointerראש ה-Stack — אסור לשנות ידנית!
EBPRBPBase Pointerבסיס Stack Frame — גישה ל-locals וargs

חלוקת רגיסטרים: 32b / 16b / 8b

; רגיסטר EAX — ניתן לגשת לחלקים שלו: ; ┌──────────────── EAX (32 bits) ──────────────────┐ ; │ ┌──── AX (16 bits) ────┐ │ ; │ │ ┌──AH──┐ ┌──AL──┐ │ │ ; │ │ │ 8bit │ │ 8bit │ │ │ ; └──────────────┴──┴──────┴─┴──────┴──┴────────────┘ mov eax, 0x12345678 ; AX = 0x5678 (16 ביטים תחתונים) ; AH = 0x56 (8 ביטים עליונים של AX) ; AL = 0x78 (8 ביטים תחתונים של AX) ; למה זה חשוב? ; כשרואים 'al', 'cx', 'dx' ב-Assembly — ; אלה חלקים מרגיסטרים שכבר מכירים!

EIP ו-FLAGS — רגיסטרים מיוחדים

רגיסטרשםמה מכילמי משנה
EIPInstruction Pointerכתובת הפקודה הבאהכל פקודה (אוטומטית) + JMP/CALL
EFLAGSFlags Registerביטים שמתעדים תוצאת פקודותADD, SUB, CMP...
Flagשםמתי מדלקדוגמה
ZFZero Flagתוצאה = 0SUB EAX,EAX → ZF=1
SFSign Flagתוצאה שליליתSUB 5 מ-3 → SF=1
CFCarry FlagOverflow חסר-סימןADD גדול מ-FFFFFFFF → CF=1
OFOverflow FlagOverflow עם-סימן127+1 ב-int8 → OF=1
🔑 הכי חשוב: ZF ו-SF
ZF דולק אחרי CMP a,b כאשר a==b (CMP = a−b, ואם תוצאה=0 → שווים).
SF דולק כאשר התוצאה שלילית — a < b.
JE בודק ZF. JL בודק SF. אחרי CMP EAX,5 כשEAX=5: ZF=1, SF=0.
✏תרגול — רגיסטרים3 שאלות
שאלה 2.1
מה ערך AL לאחר: mov eax, 0xABCD1234?
✓ תשובה: ב) 0x34. AL = 8 ביטים תחתונים של AX = 8 ביטים תחתונים של EAX. בערך 0xABCD1234: AL = 0x34 (הבית הנמוך ביותר).
שאלה 2.2
מה ערך ZF אחרי: mov eax, 0?
✓ תשובה: ד. MOV לא משנה FLAGS כלל. גם MOV EAX,0 לא תגרום ל-ZF=1. רק פקודות חישוב (ADD, SUB, CMP...) משנות FLAGS.
שאלה 2.3
מה תפקיד EIP בסייבר?
✓ תשובה: ג. EIP = Instruction Pointer — מחליט מה יבוצע אחר כך. Buffer Overflow המפורסם הוא שכתוב EIP בזיכרון לשינוי לאן התוכנית קופצת (נלמד בשיעור 45).
// פרק 3

פקודות בסיסיות — MOV, ADD, SUB ועוד

90% מהקוד שתראו משתמש ב-15–20 פקודות בלבד. נלמד כל אחת עם דוגמאות וכשלים נפוצים.

MOV — הפקודה הכי נפוצה

; תחביר Intel: פקודה יעד, מקור (dst תמיד ראשון!) ; MOV dst, src → dst = src mov eax, 42 ; EAX = 42 (Immediate) mov ebx, eax ; EBX = EAX (רגיסטר לרגיסטר) mov ecx, [0x1000] ; ECX = RAM[0x1000] (מהזיכרון) mov [0x2000], eax ; RAM[0x2000] = EAX (לזיכרון) mov [ebx], ecx ; RAM[EBX] = ECX (עקיף) ; ❌ אי אפשר: ; mov [0x1000], [0x2000] ; זיכרון→זיכרון ישיר — אסור! ; ⚠️ חשוב: MOV לא משנה FLAGS! ; mov eax, 0 — ZF עדיין לא השתנה

ADD, SUB, INC, DEC

mov eax, 10 mov ebx, 3 add eax, ebx ; EAX = 13, ZF=0, SF=0 sub eax, 13 ; EAX = 0, ZF=1 (!) inc eax ; EAX = 1, ZF=0, SF=0 dec eax ; EAX = 0, ZF=1 ; ⚠️ INC/DEC לא משנות CF — הבדל מ-ADD/SUB!

MUL ו-DIV

; MUL src → EAX = EAX * src ; תוצאה: EDX:EAX (64 ביטים!) mov eax, 5 mov ebx, 6 mul ebx ; EAX = 30, EDX = 0 ; DIV src → חלק EDX:EAX ב-src ; מנה → EAX, שארית → EDX ; ⚠️ חובה לאפס EDX לפני DIV! mov eax, 17 mov edx, 0 ; חובה! mov ebx, 5 div ebx ; EAX = 3 (מנה), EDX = 2 (שארית)

PUSH ו-POP

; PUSH src → ESP -= 4; [ESP] = src (Stack גדל למטה!) ; POP dst → dst = [ESP]; ESP += 4 push eax ; שמור EAX push ebx ; שמור EBX ; ... משהו ששינה EAX, EBX ... pop ebx ; שחזר EBX (LIFO!) pop eax ; שחזר EAX
✏תרגול — פקודות בסיסיות3 שאלות
שאלה 3.1
מה ערכי EAX ו-EDX אחרי: mov eax,17; mov edx,0; mov ebx,5; div ebx?
✓ תשובה: ב. DIV: מנה→EAX, שארית→EDX. 17÷5=3 שארית 2. אפסנו EDX לפני כן — תקין!
שאלה 3.2
מה קורה אם שוכחים mov edx,0 לפני DIV?
✓ תשובה: ג. DIV מחלק EDX:EAX (64 ביט) ב-src. אם EDX מכיל זבל, המספר שמחלקים בו ענק → תוצאה חורגת מ-32 ביט → DIV Exception (קריסה).
שאלה 3.3
אחרי push eax; push ebx; pop eax; pop ebx — מה קרה?
✓ תשובה: ג. Stack = LIFO. PUSH EAX, PUSH EBX → Stack מכיל [EBX_val, EAX_val]. POP EAX → EAX = EBX_val. POP EBX → EBX = EAX_val. הערכים הוחלפו!
// פרק 4

Addressing Modes — מאיפה האופרנד?

מצב מיעון מגדיר מאיפה מגיע הערך — מספר ישיר, רגיסטר, כתובת זיכרון, או שילוב. הבנת זה היא הבסיס לקריאת כל קטע Assembly.

מצבדוגמהמה קורה
Immediatemov eax, 42EAX = 42 (הערך עצמו)
Registermov eax, ebxEAX = ערך EBX
Direct Memorymov eax, [0x4000]EAX = RAM[0x4000]
Indirectmov eax, [ebx]EAX = RAM[EBX]
Indirect+Dispmov eax, [ebp-4]EAX = RAM[EBP-4] — משתנה מקומי!
Indexed*Scalemov eax, [ebx+ecx*4]EAX = arr[ecx] כשאיברים = 4B
; [base + displacement] — הנפוץ ביותר! mov eax, [ebp - 4] ; ebp-4 = Variable מקומי ראשון mov eax, [ebp - 8] ; ebp-8 = Variable מקומי שני mov eax, [ebp + 8] ; ebp+8 = ארגומנט ראשון לפונקציה ; [base + index*scale] — גישה למערך mov eax, [ebx + ecx*4] ; arr[ecx] כשint=4 bytes ; מה שהקומפיילר מייצר ל: int arr[5]; arr[i] = 10; mov [ebx + ecx*4], 10 ; EBX=&arr[0], ECX=i
🔑 שלט זהב לסוגריים מרובעים
אין [] → הערך הישיר (מספר או רגיסטר)
יש [] → זו כתובת! לך ל-RAM לכתובת הזו וקרא מה שם
[ebp - 4] = לך לכתובת שהיא EBP-4, קרא מה שם — לא חישוב מספרי!

Intel Syntax לעומת AT&T Syntax

מהIntel SyntaxAT&T Syntaxהערה
סדר אופרנדיםdst, srcsrc, dstהפוך לחלוטין!
Immediatemov eax, 5movl $5, %eax$ לפני מיידי, % לפני רגיסטר
זיכרון[ebx](%ebx)סוגריים עגולים
גודל פקודהמהקשרmovl/movw/movbl=32b, w=16b, b=8b
כליםNASM, IDAgcc -S, GDBשני הסביבות
✏תרגול — Addressing Modes3 שאלות
שאלה 4.1
מה עושה: mov eax, [ebx + ecx*4] ?
✓ תשובה: א. הסוגריים = כתובת זיכרון. חשב EBX+ECX*4, לך לכתובת הזו ב-RAM, קרא את הערך ושים ב-EAX. זה בדיוק arr[ecx] כש-EBX=&arr ו-sizeof(arr[0])=4.
שאלה 4.2
מה ההבדל בין Intel ל-AT&T Syntax?
✓ תשובה: ד. הפקודות זהות לחלוטין — רק הכתיב שונה. Intel: mov eax, 5. AT&T: movl $5, %eax. סדר הפוך! Intel = IDA/NASM, AT&T = GCC/GDB.
שאלה 4.3
מה מכיל [ebp+8] בתוך פונקציה (cdecl)?
✓ תשובה: ב. מבנה Stack אחרי PUSH EBP + MOV EBP,ESP: [EBP+0]=EBP ישן, [EBP+4]=כתובת חזרה, [EBP+8]=arg1, [EBP+12]=arg2. משתנים מקומיים ב-[EBP-4], [EBP-8]...
// פרק 5

C↔Assembly ו-Dry Run

הדרך הכי טובה להבין Assembly היא לראות מה הקומפיילר מייצר לקוד C שאנחנו מכירים. ו-Dry Run הוא הכלי לענות על שאלות מיון.

if/else ב-Assembly

; C: if (eax > 0) { ebx = 1; } else { ebx = -1; } cmp eax, 0 ; חישוב eax-0, עדכן FLAGS jle .else_branch ; אם eax <= 0 → קפוץ ל-else ; ── then: ── mov ebx, 1 jmp .end ; ── else: ── .else_branch: mov ebx, -1 .end: ; ⚠️ הקפיצה היא ה-OPPOSITE של התנאי! ; if (a>b) → JLE (קפוץ לעקוף אם לא גדול)

לולאת for

; C: int sum=0; for(int i=0; i<10; i++) { sum += i; } mov eax, 0 ; sum = 0 mov ecx, 0 ; i = 0 .loop_start: cmp ecx, 10 jge .loop_end ; אם i >= 10 → יצא add eax, ecx ; sum += i inc ecx ; i++ jmp .loop_start .loop_end: ; EAX = 0+1+2+...+9 = 45

שיטת Dry Run

; מה ערך EAX בסוף? mov eax, 10 ; (1) mov ebx, 3 ; (2) sub eax, ebx ; (3) mov ecx, eax ; (4) imul ecx, 2 ; (5) add eax, ecx ; (6)
// TRACE TABLE — Dry Run
#פקודהEAXEBXECXהסבר
1mov eax, 1010??EAX=10
2mov ebx, 3103?EBX=3
3sub eax, ebx73?10-3=7
4mov ecx, eax737ECX=7
5imul ecx, 273147×2=14
6add eax, ecx213147+14=21 ✓
✏תרגול — Dry Run ו-C↔ASM3 שאלות
שאלה 5.1 — Dry Run
מה ערך EAX בסוף?
mov eax,15; mov ebx,4; mov ecx,0; add ecx,eax; div ebx; sub ecx,edx
✓ תשובה: ג. ECX=15. div ebx: EAX=15÷4=3(מנה), EDX=15%4=3(שארית). sub ecx,edx: ECX=15-3=12. EAX=3, ECX=12.
שאלה 5.2 — זיהוי Pattern
מה מבנה C מייצג הקוד: CMP + JLE(.else) + [code] + JMP(.end) + .else: [code] + .end:?
✓ תשובה: ג) if-else. Pattern: CMP → Jcc(else) → [then] → JMP(.end) → .else: [else code] → .end. זה ה-Template שהקומפיילר תמיד מייצר לif-else.
שאלה 5.3
מה ערך EAX ב-return value של הפונקציה: push 7; push 3; call add_func כשadd_func מחשבת a+b?
✓ תשובה: א. ב-x86 cdecl: ערך החזרה מפונקציה תמיד ב-EAX. זהו חוק ה-Calling Convention. לכן אחרי CALL, ה-Caller בודק EAX לתוצאה.
// תרגול נוסף

תרגול נוסף — Assembly: אריתמטיקה ו-Stack Frame

שאלות העשרה נוספות לחיזוק החומר של השיעור — באותו פורמט בחירה של הקורס.

✏תרגול נוסף3 שאלות
שאלה 6.1 [קל]
מה ערך EAX אחרי הרצת הקוד?
mov eax, 10
mov ebx, 3
sub eax, ebx
add eax, ebx
imul eax, ebx
✓ תשובה נכונה: ב — EAX=10 → sub: 10-3=7 → add: 7+3=10 → imul: 10×3=30. הרצף sub/add מבטל את עצמו, imul קובע. עקיבת אוגרים היא לב ה-RE.
שאלה 6.2 [בינוני]
מה מבצע xor eax, eax ולמה הוא עדיף על mov eax, 0?
✓ תשובה נכונה: ד — xor eax,eax = 2 בתים (31 C0), לעומת mov eax,0 = 5 בתים (B8 00000000). ב-Shellcode בתי NULL חותכים strcpy — לכן xor עדיף.
שאלה 6.3 [בינוני]
מה נמצא ב-[ebp+8] וב-[ebp-4] בתוך פונקציה?
✓ תשובה נכונה: ג — כלל הזהב ב-RE: [ebp+] = ארגומנטים (מעל ה-Return Address), [ebp-] = משתנים מקומיים (מתחת). [ebp+8]=arg1, [ebp-4]=local1.
// אתגר מעשי

אתגר מעשי — Assembly — Dry-Run

שיא השיעור: לרדת לרמת-המכונה — C, אסמבלי, היפוך. ההגשה נבדקת אוטומטית.

T3 · בינוני300 נק'~15 דק'analysis
Dry-Run של Assembly
עקבו ידנית אחר קטע ה-Assembly ומצאו את הערך הסופי ב-rax. הגישו את המספר בלבד (עשרוני). mov rax, 7 shl rax, 2 ; rax = 28 add rax, 5 ; rax = 33 mov rbx, rax ; rbx = 33 add rax, rbx ; rax = ?
דוגמאות
(פורמט התשובה) → מספר, למשל 66
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס Dry-Run של Assembly ›
7 → shl 2 = 28 → +5 = 33 → rbx=33 → rax=33+33 = 66
// סיכום

סיכום — שיעור 26

✓מה למדנו בשיעור 26
  • שרשרת קומפילציה: C → Preprocessing → Assembly → Object → Executable
  • מחזור CPU: Fetch-Decode-Execute — 3 מיליארד פעמים בשנייה
  • 8 רגיסטרים: EAX/EBX/ECX/EDX (נתונים), ESI/EDI, ESP/EBP (Stack)
  • EAX → AX → AH/AL — חלקים שונים של אותו רגיסטר
  • EIP: מצביע ההוראות. Buffer Overflow = שכתוב EIP
  • FLAGS: ZF (=0), SF (שלילי), CF (Unsigned overflow), OF (Signed overflow)
  • MOV: לא משנה FLAGS. dst תמיד ראשון ב-Intel Syntax
  • MUL: תוצאה ב-EDX:EAX. DIV: מנה ב-EAX, שארית ב-EDX — חובה לאפס EDX!
  • Addressing Modes: [], [reg+disp], [reg+reg*scale] — הסוגריים = זיכרון
  • if → CMP+Jcc(הפוך), for → init+CMP+Jcc+inc+JMP, CALL → return ב-EAX
  • Dry Run: עקיבה שורה-שורה עם טבלת רגיסטרים — הכלי לשאלות מיון
לפני שיעור 27 (Jumps, FLAGS ולולאות):
1. כתבו Assembly ל-swap(a,b) ללא משתנה זמני — רמז: XCHG
2. Dry Run: מה EAX אחרי MOV EAX,7 / ADD EAX,EAX / IMUL EAX,3 / SUB EAX,5?
3. שיעור 27: FLAGS, קפיצות מותנות, לולאות — הלב של זרימת תוכנית
שאלות תרגול ותשובות (10)

שאלה 1 · איזה שלב בשרשרת הבנייה מתרגם קוד C ל-Assembly טקסטואלי?

  • א. הקומפיילר
  • ב. האסמבלר
  • ג. הלינקר
  • ד. הטוען (Loader)
תשובה: א

הקומפיילר מייצר Assembly, האסמבלר הופך אותו לקוד מכונה (Object), והלינקר מחבר את הקבצים לתוכנית אחת.

שאלה 2 · מה יהיה ערך AL אחרי הפקודה?

mov eax, 0xABCD1234
  • א. 0x34
  • ב. 0x12
  • ג. 0xAB
  • ד. 0x1234
תשובה: א

🎯 דגש למבחן — EAX/AX/AL: EAX הוא 32 ביט, AX הם 16 הביטים הנמוכים, AL הבית הנמוך ביותר ו-AH הבית שמעליו. לכן AL=0x34 ו-AH=0x12. שימו לב שזה חיתוך לוגי של הרגיסטר — לא קשור לסדר האחסון בזיכרון, שם נכנס Endianness: אותו ערך שנשמר ל-RAM ב-Little Endian ייכתב כ-34 12 CD AB.

שאלה 3 · מה עושה הפקודה?

lea eax, [ebx + ecx*4 + 8]
  • א. מחשבת את הכתובת ומכניסה אותה ל-EAX בלי לגשת לזיכרון
  • ב. טוענת את הערך שנמצא בכתובת הזו
  • ג. כותבת את EAX לכתובת שחושבה
  • ד. מקצה 8 בתים על המחסנית
תשובה: א

🎯 דגש למבחן — LEA: הפקודה משתמשת ביחידת חישוב הכתובות (AGU) כדי לבצע כפל וחיבור בפעולה אחת מהירה, ומחזירה את התוצאה עצמה — בלי גישה ל-RAM. לכן קומפיילרים משתמשים בה כקיצור אריתמטי. ההבדל מ-MOV: mov eax, [..] היה טוען את התוכן שבכתובת.

שאלה 4 · מה עושה מצב הכתובוּת הבא?

mov eax, [ebx + ecx*4]
  • א. גישה לאיבר במערך של int — EBX בסיס, ECX אינדקס, 4 גודל האיבר
  • ב. מחבר את EBX ל-ECX פי 4
  • ג. מזיז את ECX שמאלה פי 4
  • ד. שומר את EAX למערך
תשובה: א

זהו Scaled Index Addressing — התבנית הקלאסית של arr[i] בשפת C, כאשר הסקאלה שווה לגודל האיבר.

שאלה 5 · מדוע רושמים mov edx, 0 לפני DIV?

mov eax, 17
mov edx, 0
mov ebx, 5
div ebx
  • א. DIV מחלקת את הזוג EDX:EAX — זבל ב-EDX יגרום לתוצאה שגויה או לחריגה
  • ב. זו דרישה תחבירית של האסמבלר בלבד
  • ג. EDX מאחסן את התוצאה ולכן צריך לאפס
  • ד. כדי לאפס את דגל הקרי
תשובה: א

DIV מחלקת מספר בן 64 ביט (EDX:EAX). כאן התוצאה: EAX=3 (מנה) ו-EDX=2 (שארית). EDX מלוכלך עלול לגרום ל-Divide Error.

שאלה 6 · מה מצב הרגיסטרים אחרי הקוד?

push eax
push ebx
pop eax
pop ebx
  • א. הערכים של EAX ו-EBX התחלפו
  • ב. שניהם מתאפסים
  • ג. שום דבר לא השתנה
  • ד. המחסנית נשארת לא מאוזנת
תשובה: א

המחסנית היא LIFO: הערך האחרון שנדחף (EBX) יוצא ראשון ונכנס ל-EAX. זהו טריק סטנדרטי להחלפת ערכים.

שאלה 7 · למה xor eax, eax עדיף על mov eax, 0?

xor eax, eax
  • א. שתי הפקודות מאפסות, אבל XOR קצרה יותר בבתים ומהירה יותר
  • ב. XOR מאפס גם את הזיכרון
  • ג. MOV לא באמת מאפס את הרגיסטר
  • ד. XOR משמר את הדגלים
תשובה: א

כל ערך ב-XOR עם עצמו נותן 0. הפקודה תופסת 2 בתים לעומת 5, ולכן זהו האידיום המקובל לאיפוס (הוא כן משנה דגלים, למשל ZF=1).

שאלה 8 · מה מכיל [ebp+8] בתוך פונקציה במוסכמת cdecl?

  • א. הפרמטר הראשון שהועבר לפונקציה
  • ב. המשתנה המקומי הראשון
  • ג. כתובת החזרה
  • ד. הערך המוחזר מהפונקציה
תשובה: א

ביחס ל-EBP: ‎[ebp] הוא ה-EBP השמור, ‎[ebp+4] כתובת החזרה, ‎[ebp+8] הפרמטר הראשון. המשתנים המקומיים יושבים מתחת — ‎[ebp-4] וכן הלאה.

שאלה 9 · איזה מבנה בשפת C מייצגת התבנית הבאה?

cmp eax, 0
jle .else
  mov ebx, 1
  jmp .end
.else:
  mov ebx, -1
.end:
  • א. if / else
  • ב. לולאת while
  • ג. קריאה לפונקציה
  • ד. משפט switch עם טבלת קפיצה
תשובה: א

השוואה, קפיצה מותנית לענף השני, ובסוף הענף הראשון קפיצה בלתי-מותנית מעל ה-else — זו החתימה הקלאסית של if/else.

שאלה 10 · Dry Run — מה ערך EAX ו-EDX בסוף?

mov eax, 15
mov ebx, 4
mov edx, 0
div ebx
  • א. EAX = 3, EDX = 3
  • ב. EAX = 4, EDX = 0
  • ג. EAX = 3, EDX = 4
  • ד. EAX = 60, EDX = 0
תשובה: א

15 חלקי 4 = מנה 3 עם שארית 3. המנה נכנסת ל-EAX והשארית ל-EDX. טיפ ל-Dry Run: נהלו טבלת רגיסטרים ומחקו בקו במקום למחוק ערכים — כך תוכלו לחזור אחורה ולאתר טעות.