الغوص في الأنظمة › 10. أبرز خلاصات لغة التجميع 11 / 18 السابق التالي

10. خلاصات أساسية في لغة التجميع

غطّى هذا الجزء من الكتاب أساسيات لغة التجميع (assembly). ومع أن معظم الناس اليوم يبرمجون بلغة عالية المستوى، فإن فهم لغة التجميع يزيد قدرة المبرمج على إدراك ما تفعله برامجه والمصرّفات (compilers) بشكل أفضل. ومعرفة لغة التجميع ضرورية أيضًا لكل من يصمّم البرمجيات للأنظمة المدمجة (embedded systems) والبيئات الأخرى المحدودة الموارد، ولمن يعمل في تحليل الثغرات. وقد امتدّت فصول جزء لغة التجميع في هذا الكتاب عبر تجميع Intel بستة وستين بتًا (x86-64)، وتجميع Intel باثنين وثلاثين بتًا (IA32)، وتجميع ARM بستة وستين بتًا (ARMv8-A).

سمات مشتركة

أيًا كانت لغة التجميع المحددة التي يتعلمها المرء، ثمة سمات مشتركة بين جميع لغات التجميع تستحق الإبراز.

تعريف معمارية مجموعة التعليمات

تُحدَّد لغة التجميع المحددة المتاحة على آلة ما بواسطة معمارية مجموعة التعليمات (ISA) لتلك الآلة. لتحديد المعمارية الكامنة وراء آلة Linux معينة، استخدم الأمر uname -m.

السجلات تحمل البيانات

تعرّف كل معمارية ISA مجموعة من السجلات (registers) الأساسية التي يستخدمها المعالج (CPU) للعمل على البيانات. بعض السجلات عامة الغرض (general purpose) ويمكنها حمل أي نوع من البيانات، بينما بعضها الآخر خاص الغرض (special purpose) ويحتفظ به المصرّف عادةً لاستخدامات محددة (مثل مؤشر المكدّس، ومؤشر القاعدة). وبينما يمكن القراءة من السجلات عامة الغرض والكتابة فيها، فإن بعض السجلات خاصة الغرض للقراءة فقط (مثل مؤشر التعليمة).

التعليمات تحدد ما يمكن للمعالج فعله

تعرّف معمارية ISA أيضًا سلسلة من التعليمات (instructions) التي تحدد العمليات التي يمكن للمعالج تنفيذها. ولكل تعليمة رمز عملية (operation code, opcode) يحدد ما تفعله التعليمة، ومُعامِل واحد أو أكثر (operand) يحدد البيانات المستخدمة. وتوثّق معمارية ISA تعليمات محددة لنقل البيانات والعمليات الحسابية والشروط والتفرعات والوصول إلى الذاكرة. وغالبًا ما تُدمج هذه التعليمات الأساسية لتمثيل بنى بيانات أكثر تعقيدًا مثل المصفوفات والبنى (structs) والمصفوفات الرياضية (matrices).

مكدّس البرنامج يحمل المتغيرات المحلية المرتبطة بدالة معينة

يستخدم المصرّف مكدّس (أو ذاكرة مكدّس) فضاء العنوان الافتراضي للعملية لتخزين بيانات مؤقتة. وفي جميع الأنظمة الحديثة، ينمو مكدّس البرنامج نحو عناوين ذاكرة أدنى. ويستخدم المصرّف مؤشر المكدّس ومؤشر القاعدة لتحديد إطار المكدّس (stack frame) الذي يعرّف منطقة المكدّس المرتبطة بدالة أو إجراء معين. ويُضاف إطار مكدّس جديد إلى المكدّس مع كل نداء دالة، ويحدد منطقة المكدّس المرتبطة بالدالة المستدعاة. ويُزال إطار المكدّس المرتبط بدالة معينة من المكدّس عند عودة تلك الدالة. وعادةً يعود مؤشرا المكدّس والقاعدة إلى قيمتيهما الأصلية عند انتهاء الدالة. ومع أن هذه المسكّات الحسابية توحي بأن المتغيرات المحلية «تُنظَّف» من المكدّس، فإن البيانات القديمة تبقى غالبًا على شكل قيم نفايات، وهو ما قد يؤدي أحيانًا إلى سلوكيات عسيرة التنقيح. ويمكن للفاعلين الخبثاء أيضًا استخدام معرفة بمسكّات حساب المكدّس في معمارية ISA لإنشاء استغلالات أمنية خطيرة، مثل فيض المكدّس (buffer overflows).

الأمن

مع أن جميع الأنظمة عرضة لثغرات أمنية مثل فيض المكدّس، فقد أتيح لمعمارية ARMv8-A الأحدث نسبيًا أن تتعلم من بعض العيوب الأمنية التي أصابت معماريات Intel الأقدم. لكن خط الدفاع الأول هو المبرمج دائمًا. وحتى مع حمايات إضافية، لا توجد معمارية ISA محصّنة ضد العيوب الأمنية المحتملة. وعند البرمجة بلغة C، ينبغي للمبرمجين استخدام محدِّدات الطول (length specifiers) كلما أمكن لتقليل احتمال الثغرات الأمنية الناتجة عن تجاوز الحدود (انظر الجدول 1).

بدلًا من: استخدم:
gets(buf) fgets(buf, 12, stdin)
scanf("%s", buf) scanf("%12s", buf)
strcpy(buf2, buf) strncpy(buf2, buf, 12)
strcat(buf2, buf) strncat(buf2, buf, 12)
sprintf(buf, "%d", num) snprintf(buf, 12, "%d", num)

قراءة إضافية

يقدّم هذا الكتاب مجرد تذوّق لبعض أشهر لغات التجميع المستخدمة. ولمزيد من الفهم المتعمق للغة التجميع، نشجعك على الاطلاع على مواصفات معماريات ISA:

وقد تفيد المصادر المجانية التالية أيضًا من يرغبون في تعلم التجميع باثنين وثلاثين بتًا:

كما تتضمن الكتب التالية مناقشات متعمقة للغة التجميع؛ وهي ليست مجانية، لكنها مصادر ممتازة لمزيد من القراءة: