לדלג לתוכן

10.1 אסמבלי בתוך C תרגול

תרגול - אסמבלי בתוך C - inline assembly

תרגול 1 - קריאת TSC ומדידת ביצועים

  1. כתבו פונקציה read_tsc() שמשתמשת ב-inline assembly עם הפקודה rdtsc כדי לקרוא את מונה הזמן של המעבד.
  2. השתמשו בפונקציה כדי למדוד כמה מחזורי שעון לוקחת כל אחת מהפעולות הבאות:
  3. חיבור שני מספרים (a + b)
  4. קריאה ל-printf
  5. לולאה שרצה 1000 פעמים ועושה חיבור
  6. הדפיסו את מספר המחזורים של כל פעולה.

רמז: הפקודה rdtsc שמה את 32 הביטים הנמוכים ב-eax ואת הגבוהים ב-edx. השתמשו ב-"=a" ו-"=d" כדי לקרוא אותם.


תרגול 2 - זיהוי יצרן המעבד עם CPUID

  1. כתבו פונקציה get_cpu_vendor(char *vendor) שמשתמשת ב-cpuid עם eax=0 כדי לקבל את מחרוזת היצרן.
  2. כתבו פונקציה get_cpu_brand(char *brand) שמשתמשת ב-cpuid עם eax=0x80000002, 0x80000003, ו-0x80000004 (שלוש קריאות) כדי לקבל את השם המלא של המעבד (48 תווים).
  3. הדפיסו את שני הערכים.

רמז: בכל קריאה של cpuid עם function 0x8000000x, ארבעת הרגיסטרים eax, ebx, ecx, edx מחזירים 16 תווים (4 בכל רגיסטר). שלוש קריאות נותנות 48 תווים.


תרגול 3 - חיבור וחיסור עם inline asm

  1. כתבו פונקציה int asm_add(int a, int b) שמבצעת חיבור באמצעות הפקודה addl ב-inline assembly.
  2. כתבו פונקציה int asm_sub(int a, int b) שמבצעת חיסור באמצעות subl.
  3. כתבו פונקציה int asm_mul(int a, int b) שמבצעת כפל באמצעות imull.
  4. בדקו שהפונקציות עובדות נכון עם מספרים חיוביים, שליליים, ואפס.

רמז: השתמשו ב-constraint "=r" לפלט ו-"r" לקלט.


תרגול 4 - קריאת מערכת ישירה - write

  1. כתבו פונקציה my_write(int fd, const char *buf, int len) שמבצעת את הsyscall write באמצעות inline assembly, ללא שימוש בlibc.
  2. הsyscall number של write הוא 1 (ב-x86_64).
  3. השתמשו בפונקציה כדי להדפיס הודעה ל-stdout (fd=1).
  4. השתמשו בפונקציה כדי לכתוב הודעה לקובץ (פתחו קובץ עם open רגיל, ואז כתבו אליו עם my_write).

רמז: ב-x86_64, הconvention הוא: מספר syscall ב-rax, ארגומנטים ב-rdi, rsi, rdx. הפקודה syscall מבצעת את הקריאה. אל תשכחו clobbers על "rcx" ו-"r11".


תרגול 5 - compare-and-swap

  1. ממשו פונקציה int cas(int *ptr, int expected, int desired) שמבצעת compare-and-swap אטומי באמצעות הפקודה lock cmpxchgl.
  2. הפונקציה מחזירה 1 אם ההחלפה הצליחה, 0 אם לא.
  3. כתבו תוכנית שמדגימה את השימוש: נסו לעשות CAS עם הערך הנכון (צריך להצליח), ואז נסו שוב עם ערך לא נכון (צריך להיכשל).
  4. בונוס: השתמשו בCAS כדי לממש מונה אטומי - פונקציה atomic_increment(int *counter) שמגדילה את המונה ב-1 באופן אטומי, באמצעות לולאת CAS (נסה, ואם נכשלת - קרא את הערך החדש ונסה שוב).