الدرس 2 من 8
اصطلاح الاستدعاء وإطار المكدّس
- 16 دقيقة
- 5 فحوص
- 3 تلميحات
- إلى المطلوب
هدف الدرس
أين تدخل الوسائط وأين يخرج الناتج
الشرح
حين تستدعي دالةٌ دالةً أخرى يجب أن تتّفقا على مكان الوسائط ومكان الناتج، وهذا الاتّفاق اسمه اصطلاح الاستدعاء (calling convention). والبرامج على x86-64 في لينكس وماك تتبع اصطلاح System V:
- الوسائط الستّة الأوّلى في المسجّلات بهذا الترتيب:
rdiثمrsiثمrdxثمrcxثمr8ثمr9. - ما زاد على ستّة وسائط يمرّ على المكدّس.
- الناتج يعود في
rax.
أمّا ويندوز فله اصطلاح آخر يبدأ بـ rcx، فاعرف أوّلًا لأي نظام بُني البرنامج الذي تقرؤه.
والمكدّس (stack) ذاكرة تنمو نحو العناوين الأدنى، وتحجز فيه كل دالة إطارًا (stack frame) لمتغيّراتها المحلّية. والمترجِم بلا تحسين يبدأ الدالة عادةً بأمرين: الأمر push rbp يحفظ قاعدة إطار الدالة التي استدعتها، والأمر mov rbp, rsp يجعل القمّة الحالية قاعدةً للإطار الجديد. بعدها تُقرأ المتغيّرات المحلّية بإزاحة سالبة من rbp مثل [rbp-4]، والقوسان المربّعان يعنيان القيمة المخزّنة في ذلك العنوان.
العنوان الأعلى
+----------------+
| return address | [rbp+8]
+----------------+
| saved rbp | [rbp]
+----------------+
| a | [rbp-4]
| b | [rbp-8]
+----------------+
العنوان الأدنى
- في
[rbp+8]عنوان العودة الذي وضعه الأمرcall. - في
[rbp]قاعدة إطار الدالة التي استدعتها. - في
[rbp-4]و[rbp-8]الوسيطان a وb بعد أن نسختهما الدالة منediوesi.
وهذه دالة الإطار المرسوم أعلاه كما يُخرجها المترجِم بلا تحسين. نسخت وسيطيها من المسجّلين إلى إطارها ثم قرأتهما منه، والأمر pop rbp في آخرها يُرجع قاعدة الإطار السابق قبل أن يعود ret إلى عنوان العودة:
g: push rbp mov rbp, rsp mov [rbp-4], edi ; a mov [rbp-8], esi ; b mov eax, [rbp-4] ; eax = a sub eax, [rbp-8] ; eax = a - b pop rbp ret
ولاحظ أنها كتبت في [rbp-4] و[rbp-8] دون أن تحجز مكانًا بالأمر sub rsp, N أوّلًا. والسبب أن لينكس يمنح الدالة التي لا تنادي غيرها (leaf) مئةً وثمانية وعشرين بايتًا تحت قمّة المكدّس تسمّى المنطقة الحمراء (red zone)، تستعملها بلا حجز. أمّا الدالة التي تنادي غيرها فتحجز إطارها بـ sub rsp, N، وويندوز لا منطقة حمراء فيه بل يحجز المنادي اثنين وثلاثين بايتًا تسمّى مساحة الظلّ (shadow space).
المطلوب
اكتب الدالة g(a, b) التي تكافئ دالة الأسمبلي أعلاه، والدالة arg_register(n) التي تُرجع اسم المسجّل الذي يحمل الوسيط رقم n في اصطلاح System V (من 1 إلى 6)، والمتغيّر return_register وفيه اسم مسجّل الناتج. اكتب أسماء المسجّلات الكاملة بحروف صغيرة، مثل "rdi".
الفحوص
5 فحوص- الدالة g تطرح الوسيط الثاني من الأوّل
- الدالة g تكافئ دالة الأسمبلي على قيم أخرى
- الوسيط الأوّل في rdi
- الوسائط الستّة بترتيبها
- الناتج في rax