פתרון מוסכמת הקריאה של Windows¶
בכניסה ל־sum5, לפני שינוי RSP, המפה היא ארבעת הרגיסטרים RCX, RDX, R8 ו־R9 עבור 11, 22, 33 ו־44. הערך 55 נמצא אחרי כתובת החזרה ואזור ה־shadow space, ולכן ההיסט הצפוי הוא 40 בתים מראש המחסנית בנקודה הזו.
ה־shadow space אינו כולל את כתובת החזרה. אם הפונקציה מפחיתה בהמשך 56 בתים מ־RSP, מיקום אותו ארגומנט יחסית ל־RSP החדש זז ב־56 בתים. הערך לא חייב לזוז בזיכרון; רק נקודת הייחוס השתנתה.
| פרמטר | מיקום בחוזה הרגיל של x64 |
|---|---|
| הערך השלם הראשון של mixed | הרגיסטר RCX |
| הערך double השני | הרגיסטר XMM1 |
| הערך השלם השלישי | הרגיסטר R8 |
| הערך float הרביעי | הרגיסטר XMM3 |
| הערך השלם החמישי | המחסנית אחרי shadow space |
הפרמטר השני משתמש ב־XMM1 כי מספר המיקום הוא אחד בספירה מאפס. רשימת ערכי הנקודה הצפה אינה נספרת בנפרד ממיקומי הארגומנטים.
ב־make_triple הקורא מקצה מקום למבנה ומעביר את כתובתו כארגומנט נסתר. בחתימה הזו המצביע נמצא ב־RCX וה־seed ב־RDX. בגוף הפונקציה צפויות כתיבות לאחסון שקיבלנו, ובחזרה הכתובת יכולה להופיע ב־RAX לפי החוזה. יש לאמת מול הכלי והארכיטקטורה שנבחרו.
שמירת RBX נובעת מכך שהפונקציה משתמשת ברגיסטר nonvolatile. היא חייבת להחזיר לקורא את הערך שהיה בו. רגיסטר כזה יכול להחזיק ערך מקומי שחי מעבר לקריאה פנימית, ולכן המהדר בוחר לשלם על שמירה פעם אחת במקום לשמור את אותו משתנה שוב ושוב.
ה־typedef השגוי משנה את הדרך שבה הקורא מכין את הרגיסטרים. המימוש עדיין קורא אותם לפי החתימה המקורית. אין במעבר הזה פעולה שממירה אוטומטית את הערכים למיקומים הנכונים, ולכן שני הצדדים יכולים לקרוא מידע שונה מתוך אותו מצב מכונה.
ה־ABI מגדיר את הגבול, אך אינו מחייב מימוש פנימי יחיד. אופטימיזציה יכולה לשנות שמירות זמניות, סידור הוראות ופריסת מחסנית. לכן דוח שמציג רק שרטוט כללי בלי הוראת עצירה ובלי flags אינו מספיק לתחקיר.