Prolog و Epilog

كل دالة تخصص مساحة مكدس، تستدعى دالات أخرى، تحفظ السجلات الثابتة أو تستتخدم معالجة الاستثناء، يجب أن يكون لها prolog حدود عنوانه موصوفة في البيانات المفككة المقترنة بإدخال جدول الدالة المعنية (راجع معالجة استثناء (x64)). يحفظ prolog سجلات الوسيطات في عناوين المنزل الخاصة بهم إذا لزم الأمر، يدفع السجلات الثابتة للمكدس ، يخصص الجزء الثابت من المكدس للمتغيرات المحلية و المؤقتة، و بشكل اختياري يؤسس مؤشر إطار. البيانات المفككة المقترنة يجب أن تصف إجراء prolog و يجب أن توفر المعلومات الضرورية للتراجع عن تأثير تعليمة prolog البرمجية.

إذا كان التخصيص الثابت في المكدس أكثر من صفحة واحدة (أي، أكبر من 4096 بايت)، إذاً من المحتمل أن يتسع تخصيص المكدس لأكثر من صفحة ذاكرة ظاهرية واحدة، ولذلك، يجب التحقق من التخصيص قبل أن يتم التخصيص بالفعل. يتوفر لهذا الغرض إجراء خاص يمكن استدعاؤه من prolog و لا يتلف أي من سجلات الوسيطة.

الطريقة المفضلة لحفظ السجلات الثابتة هى نقلها إلى مكدس قبل تخصيص مكدس ثابت. إذا تم إجراء تخصيص مكدس ثابت قبل حفظ السجلات الثابتة، فالاحتمال الأكبر أن إزاحة 32-بت ستكون مطلوبة لمعالجة مساحة السجل المحفوظة (طبقا للتقرير، الدفع للسجلات يكون بنفس سرعة الانتقال و يجب أن يظل كذلك فى المستقبل المتوقع بالرغم من الضمانات التبعية بين الدفعات). يمكن حفظ السجلات الثابتة بأي ترتيب. ومع ذلك، يجب أن يكون أول استخدام لسجل ثابت في prolog لحفظه.

التعليمات البرمجية لـ prolog نموذجي قد تكون:

mov       [RSP + 8], RCX
push   R15
push   R14
push   R13
sub      RSP, fixed-allocation-size
lea      R13, 128[RSP]
...

prolog هذا يخزن سجل الوسيطة RCX في موقعه المنزلي, يحفظ سجلات R15 R13 الثابتة, يخصص الجزء الثابت من إطار مكدس و يقوم بتأسيس مؤشر إطار يشير إلى 128 بايت في منطقة التخصيص الثابتة. يسمح استخدام الإزاحة بمعالجة المزيد من منطقة التخصيص الثابتة بإزاحة من بايت واحد.

إذا كان حجم التخصيص الثابت أكبر من أو يساوي صفحة واحدة من الذاكرة، يجب استدعاء دالة مساعدة قبل تعديل RSP. هذا المساعد __chkstk ، مسؤول عن التحقق من نطاق المكدس الذى يُعزم على تخصيصه، للتأكد من توسيع المكدس بشكل صحيح. في هذه الحالة، مثال prolog السابق سيكون بدلاً من ذلك كالأتي:

mov       [RSP + 8], RCX
push   R15
push   R14
push   R13
mov      RAX,  fixed-allocation-size
call   __chkstk
sub      RSP, RAX
lea      R13, 128[RSP]
...

مساعد __chkstk لن يقوم بتعديل أية سجلات غير R10 ،R11 و التعليمات البرمجية الخاصة بالشروط. بشكل خاص، سيتم إرجاع RAX دون تغيير وترك كافة السجلات الثابتة و سجلات تمرير الوسيطة غير معدلة.

تعليمات epilog البرمجية موجودة في كل إنهاء للدالة. بينما يوجد عادةً prolog واحد فقط، يمكن أن يكون هناك العديد من epilogs. تعليمات epilog البرمجية تقوم بحز المكدس إلى حجم التخصيص الثابت الخاص به (إذا كان ذلك ضرورياً) أو إلغاء تخصيص تخصيص المكدس الثابت أو استعادة السجلات الثابتة بواسطة سحب قيمهم المحفوظة من المكدس ثم يقوم بالإرجاع.

يجب أن تتبع تعليمات epilog البرمجية مجموعة من القواعد الصارمة للتعليمات البرمجية المفككة لفكها ببشكل يعتمد عليه خلال الاستثناءات و المقاطعات. هذا يقلل مقدار البيانات المفككة المطلوبة لأنه لا يوجد بيانات إضافية مطلوبة لوصف كل epilog. بدلاً من ذلك، التعليمات البرمجية المفككة يمكنها تحديد أن epilog تم تنفيذه بواسطة التفحص للأمام خلال دفق التعليمات البرمجية للتعرف على epilog.

إذا لم يتم استخدام مؤشر إطار في الدالة، يجب أولاً على epilog إلغاء تخصيص الجزء الثابت من المكدس، و يتم سحب السجلات الثابتة ويتم إرجاع التحكم إلى الدالة المستدعية. على سبيل المثال،

add      RSP, fixed-allocation-size
pop      R13
pop      R14
pop      R15
ret

إذا تم استخدام مؤشر إطار في الدالة ،يجب أن يتم حز المكدس إلى التخصيص الثابت الخاص به قبل تنفيذ epilog. هذا تقنيًا ليس جزءاً من epilog. على سبيل المثال، يمكن استخدام epilog التالي للتراجع عن prolog المستخدم من قبل:

lea      RSP, -128[R13]
; epilogue proper starts here
add      RSP, fixed-allocation-size
pop      R13
pop      R14
pop      R15
ret

في الواقع العملي، عند استخدام مؤشر إطار، لا يوجد سبب جيد لضبط RSP في الخطوتين التاليتين، بحيث يمكن استخدام epilog التالي بدلاً من ذلك:

lea      RSP, fixed-allocation-size – 128[R13]
pop      R13
pop      R14
pop      R15
ret

هذه هي نماذج epilog المشروعة فقط. يجب أن تتكون إما من add RSP,constant أو lea RSP,constant[FPReg] ، متبوعاً بسلسلة من صفر أو أكثر من عمليات سحب من السجل مساحتها 8 بايت ثم إرجاع أو انتقال سريع(jmp). (مجموعة فرعية فقط من عبارات الانتقال السريع (jmp) مسموح بها في epilog. هذه حصرا من فئة jmps مع ModRM ذاكرة تشير إلى مكان متوسط ModRM القيمة الحقل 00. استخدام jmps في epilog مع القيمة حقل mod ModRM 01 أو 10 هو ممنوعة. راجع جدول A-15 في دليل مستخدم مبرمجي بنية AMD x86-64 الإصدار 3: إرشادات النظام و الأغراض العامة، امزيد من المعلومات حول مراجع ModRM المسموح بها.). لا يمكن أن تظهر تعليمة برمجية أخرى. وبشكل خاص، لا يوجد شئ يمكن جدولته ضمن epilog بما في ذلك تحميل قيمة الإرجاع.

لاحظ أنه عند عدم استخدام مؤشر إطار، يجب على epilog أن يستخدم add RSP,constant لإلغاء تخصيص الجزء الثابت من المكدس. قد لا يستخدم lea RSP,constant[RSP] بدلاً من ذلك. يوجد هذا التقييد لذلك فإن التعليمات البرمجية المفككة يكون عليها التعرف على أنماط أقل عند البحث عن epilogs.

اتباع هذه القواعد يسمح للتعليمات البرمجية المفككة بتحديد أنه يتم حالياً تنفيذ epilog و بمحاكاة تنفيذ باقي epilog للسماح بإعادة إنشاء سياق الدالة التي قامت بالاستدعاء.

راجع أيضًا:

المرجع

اصطلاحات برامج x64