HeadlinesBriefing favicon HeadlinesBriefing.com

تحسين مكدس الترامبولين للوظائف المتداخلة GCC

Hacker News •
×

تحسين مكدس الترامبولين للوظائف المتداخلة في GCC. الاستدعاء غير المباشر للوظائف المتداخلة على GCC بدون مكدس قابل للتنفيذ. مارتن أويكر، 2026-08-29. ناقشنا في المرة السابقة كيف يمكن استخدام الوظائف المتداخلة على GCC و Clang للاستدعاءات العكسية دون الحاجة إلى مكدس قابل للتنفيذ. لكن ماذا لو احتاج المرء إلى دعم إصدارات أقدم من GCC؟ بالطبع، يمكن للمرء ببساطة قبول مكدس قابل للتنفيذ، ولكن من الممكن أيضًا تجنب ذلك باستخدام حيلة. GCC: الوظائف المتداخلة والترمبولين. دعنا نناقش أولاً كيف يدعم GCC أخذ عنوان وظيفة متداخلة. مثالنا التجريبي بدون استخدام الماكرو الجديدة موضح أدناه. على x86_64، يضع التجميع المولد ترمبولينًا على المكدس ويستدعيه فورًا عبر الدالة baz المضمنة. الترامبولين هو تسلسل كود قصير يحمل سجل الإطار الثابت إلى هيكل على المكدس يحتوي على المتغيرات الملتقطة من الدالة الأب ثم يقفز إلى الدالة المحلية. إذا قام المرء بترجمة الثوابت -17591، -17847، و -1864106167 مرة أخرى إلى تعليمات التجميع، يحصل على كود x86_64 التالي: movq $bar.0, %r11، movq $frame, %r10، jump *%r11. كل من السلسلة الثابتة وعنوان الكود هما ثوابت فورية تستخدم بواسطة تعليمات النقل في كود الترامبولين. بدلاً من استخدام عنوان الترامبولين لاستدعاء الدالة، يمكننا استخراج عنوان الكود والسلسلة الثابتة من الترامبولين واستخدامهما مع الدالة المضمنة __builtin_call_with_static_chain لاستدعاء الدالة المحلية مباشرة. وبالتالي، يمكننا استخدام قراءة قيمتي المؤشر هاتين من الترامبولين كآلية احتياطية في إصدارات GCC الأقدم. العيوب هي أنه لا يزال يتم إنشاء ترامبولين، ولا يزال المترجم غير قادر على إلغاء تجريد الاستدعاء غير المباشر، وسيظل المكدس مميزًا كقابل للتنفيذ. فما الذي تم اكتسابه؟ نظرًا لأننا لا نستدعي الترامبولين فعليًا، يمكننا جعل المكدس غير قابل للتنفيذ مرة أخرى باستخدام الأمر التالي، الذي يعالج على الأقل المخاوف الأمنية لهذه الميزة. patchelf --clear-execstack program. تم تنفيذ هذه الفكرة في مكتبتي التجريبية، noplate، حيث يتم بناء مؤشر عريض من عنوان الكود والسلسلة الثابتة. الترامبولين كوصف للوظائف. هناك فكرة أخرى أجدها تستحق الاستكشاف: يمكن أيضًا استخدام الترامبولين نفسه كوصف للوظيفة. بدلاً من استخراج السلسلة الثابتة ومؤشر الكود حيث يتم إنشاء الترامبولين، نمرر ببساطة عنوان الترامبولين كالمعتاد. لكن في كل مكان قد نستدعي فيه الترامبولين، نتحقق أولاً مما إذا كان المؤشر يشير إلى ترامبولين، ثم نستخرج عنوان الكود والسلسلة الثابتة لاستدعاء الوظيفة المتداخلة مباشرة باستخدام __builtin_call_with_static_chain. بمعنى ما، يمكننا القول أنه بدلاً من استدعاء الترامبولين، نحن نفسر كود الترامبولين في موقع الاستدعاء باستخدام مفسر فائق البساطة لا يمكنه تفسير تسلسل الكود المحدد هذا فقط وهو بسيط للغاية لدرجة أن...