לדלג לתוכן

מה זה syscall - קריאת מערכת, ולמה תוכנית לא יכולה לעשות הכל לבד

בכל פעם שתוכנית פותחת קובץ, שולחת בקשה ברשת, או אפילו רק מבקשת עוד קצת זיכרון, קורה משהו שרוב המתכנתים אף פעם לא עוצרים לחשוב עליו. התוכנית לא עושה את זה לבד. היא פונה למערכת ההפעלה ומבקשת ממנה לעשות את זה בשבילה. הפנייה הזו נקראת syscall, קריאת מערכת, וזה אחד המושגים הכי בסיסיים - והכי לא מובנים - בעולם ה-Low Level.

אז מה זה בעצם syscall

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

ה-syscall הוא בדיוק הגשר בין השניים - זו הדרך היחידה שבה תוכנית ב-user mode יכולה לבקש ממערכת ההפעלה לבצע בשבילה פעולה שדורשת הרשאות. פתיחת קובץ, קריאה מהרשת, הקצאת זיכרון, יצירת תהליך חדש - כל אלה הן פעולות שהתוכנית לא יכולה לעשות בעצמה, והיא חייבת לבקש אותן מהקרנל.

למה בעצם צריך את כל ההפרדה הזו

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

המעבר למצב קרנל - trap

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

הטבלה שמחליטה מה להריץ - syscall table

התוכנית לא שולחת לקרנל "תפתח לי קובץ" במילים. היא שולחת מספר, syscall number, שמייצג בדיוק איזו פעולה מבוקשת. הקרנל מחזיק טבלה שממפה כל מספר כזה לפונקציה הפנימית שמטפלת בו. הקרנל מסתכל בטבלה, מריץ את הפעולה המבוקשת עם ההרשאות שלו, ומחזיר תוצאה - ורק אז שליטה חוזרת לתוכנית, שממשיכה לרוץ ב-user mode כאילו כלום לא קרה.

השכבה שרוב המתכנתים בכלל לא רואים - libc

כאן חשוב לפרק מיתוס נפוץ - רוב המתכנתים בכלל לא כותבים syscall ידנית. כשכותבים בשפת C פונקציות כמו read, write או open, בעצם קוראים לפונקציות של libc, ספריית השפה הסטנדרטית, שעוטפות את מנגנון ה-syscall בשבילכם ומטפלות בכל הפרטים הטכניים הנמוכים. זו הסיבה שכתיבת קוד שמדבר עם מערכת ההפעלה מרגישה פשוטה כל כך - כל המורכבות שקורית ברמת החומרה מוסתרת מתחת לפונקציה נוחה.

הכלי שהופך את זה ממופשט למוחשי - strace

אם אתם רוצים לראות את כל זה קורה בעיניים, יש כלי מדהים בלינוקס בשם strace. הוא מריץ תוכנית ומדפיס בזמן אמת כל syscall בודד שהיא מבצעת - כל פתיחת קובץ, כל קריאה מהרשת, כל הקצאת זיכרון. פתאום, במקום מושג מופשט, אתם רואים ממש מול העיניים איך אפילו תוכנית "הלו וורלד" הכי פשוטה מבצעת עשרות קריאות מערכת לפני שהיא בכלל מדפיסה תו אחד. זו אחת הדרכים הכי טובות להבין את המושג הזה באמת, ולא רק בתיאוריה.

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

לסיכום

ה-syscall הוא לא מושג מסובך ברגע שמבינים את הרעיון הבסיסי - זו הדרך היחידה שתוכנית רגילה יכולה לבקש ממערכת ההפעלה לעשות בשבילה משהו שדורש הרשאות. התוכנית עוברת ל-kernel mode לרגע קצר, מבקשת שירות ספציפי דרך מספר בטבלה, ומקבלת בחזרה תוצאה. רוב הזמן זה קורה מתחת לפני השטח דרך libc, אבל עם strace אתם יכולים לראות את זה קורה בזמן אמת. וברגע שראיתם את זה פעם אחת, קשה שלא להתרגש מכמות הפעולות הקטנות שקורות מאחורי כל שורת קוד פשוטה.

בואו תמשיכו את הלמידה עם קהילה שכבר שם.

הצטרפו לקהילה בדיסקורד