الجمعة، 4 يناير، 2013

كيف هو تصميم لغة التجميع assembly language



العناصر الأساسية
تتكون أي لغة تجميع من 3 أنواع من جمل التعليمات Instruction Statements والتي تستخدم في تعريف عمليات البرنامج:

أوامر كود التشغيل Opcode
مقاطع البيانات
توجيهات لغة التجميع Directives
[عدل]أوامر كود التشغيل
عادة ما تكون التعليمات (الجمل) في لغة التجميع بسيطة للغاية, بعكس تلك الموجودة في لغات البرمجة عالية المستوى.وبصفة عامة, فإن "كود التشغيل" هو اسم رمزي لتعليمة واحدة تنفيذية مكتوبة بلغة الآلة, ويوجد على الأقل أمر واحد من الكود التنفيذي محدد لكل تعليمة مكتوبة بلغة الآلة.وكل تعليمة Instruction تتكون عادة من "عملياحد Byte, مكودة داخل التعليمة نفسها), ويمكن أن تكون "غير مباشرة" وتشير إلى عنوان الذاكرة الذي يتم تخزين البيانات فيه.ويتحدد ذلك عبر البنية الأساسية للمعالج Architecture: فالمجمع يعبر عن كيفية عمل هذه البنية فحسب.

مقاطع البيانات
هناك تعليمات تستخدم في تحديد عناصر البيانات Data Elements التي تحمل بيانات وتحمل متغيرات.وتحدد تلك العناصر: نوعية البيانات, طول البيانات, وموائمة البيانات Alignment.ويمكن لتلك التعليمات أيضا أن تحدد إذا ما كانت تلك البيانات متاحة لبرامج خارجية Outside Programs (برامج يتم تجميعها بشكل منفصل عن البرنامج الذي يحتوي البيانات), أو أنها متاحة فقط للبرنامج الذي يحمل قسما يحتوي تعريف تلك البيانات.

توجيهات لغة التجميع Assembly Directives/ Pseudo-Ops
"توجيهات لغة التجميع" Assembly Directives هي تعليمات يتم تنفيذها عن طريق المجمع أثناء وقت التجميع Assembly Time, ولا يتم تنفيذها عبر وحدة المعالجة المركزية CPU في وقت تشغيل البرنامج Run Time.ويمكن لتلك التوجيهات أن تجعل لغة التجميع الخاصة بالبرنامج تعتمد على "معامل" Parameter يتم إدخاله عبر المبرمج, بحيث يمكن تجميع البرنامج الواحد بأكثر من طريقة, وربما من أجل تطبيقات مختلفة -لكل نسخة مجمعة مختلفة-.ويمكن أن تستخدم "التوجيهات" Directives أيضا للتلاعب Manipulate بطريقة عرض البرنامج Presentation, مما يجعل البرنامج أسهل في القراءة والصيانة من ناحية المبرمج.

(على سبيل المثال, يمكن استخدام الـ Pseudo-Ops في حجز مساحات تخزين وملأها بقيمها المبدأية بشكل اختياري.)وغالبا ما تبدأ أسماء العمليات من نوع Pseudo-Ops بنقطة Dot لتمييزها عن باقي تعليمات الجهاز.
وتدعم بعض المجمعات أيضا تعليمات من نوع Pseudo-Instructions, والتي تقوم بتوليد تعليمتين أو أكثر من تعليمات الجهاز Machine Instructions.

وتسمح المجمعات الرمزية Symbolic للمبرمجين بتحديد أسماء من اختيارهم (علامات أو رموز) لمواقع الذاكرة Memory Locations.وعادة ما يتم إعطاء كل متغير Variable وكل ثابت Constant اسما, بحيث يمكن الإشارة لتلك العناصر داخل التعليمات بأسمائها, وبالتالي يساعد المبرمج نفسه في توثيق الكود الذي يكتبه Self-Documenting.وفي الكود القابل للتنفيذ, يتم ربط اسم كل "روتين فرعي" Subroutine بـ نقطة دخوله Entry Point, بحيث يتم استدعاء الروتين الفرعي عبر استخدام اسمه.وداخل الروتينات الفرعية, يتم إعطاء علامات Labels لوجهات الأمر GOTO.وتدعم بعض المجمعات "رموزا محلية" Local Symbols والتي تختلف مفرداتها عن الرموز العادية (مثال: استخدام التركيب "10$" كوجهة للأمر GOTO).

وتوفر معظم المجمعات إدارة مرنة للرموز, بحيث تتيح للمبرمجين: إدارة مساحات إسمية مختلفة Namespaces, حساب الإزاحات بشكل آلي داخل هياكل البيانات Data Structures, وتحديد تسميات/علامات Labels تشير إلى قيم حرفية أو إلى ناتج حسابات بسيطة تؤدى عبر المجمع.وتستخدم التسميات/العلامات Labels أيضا لتهيئة الثوابت Constants والمتغيرات Variables مع عناوين قابلة للإعادة التعيين Relocatable Addresses.

ومثلها مثل معظم لغات الكمبيوتر الأخرى, تسمح لغات التجميع بإضافة "تعليقات" Comments إلى كود المصدر, وتتم تجاهل هذه التعليقات عن طريق "المجمع" -أي لا تتم ترجمتها للغة الآلة بالطبع-.ويعد استخدام التعليقات بشكل جيد مع كود لغة التجميع أكثر أهمية من استخدام التعليقات مع اللغات عالية المستوى, لأنه من الصعب استنباط معنى ومغزى سلسلة تعليمات لغة التجميع عبر قراءة الكود فقط -دون تعليقات توضحه-.

ويمكن لحسن استخدام تلك التسهيلات Facilities أن يبسط جدا من مشكلات عمليات التكويد والصيانة الخاصة بكود اللغات منخضفة المستوى Low-Level. وإذا دعت الحاجة لتغييره فإن من الصعب جدا قراءة كود لغة التجميع الخام Raw - والذي يتم توليده عبر مترجمات Compilers أو برامج فك التجميع Disassembler-, حيث يتكون من مجموعة تعليمات متراصة, بدون أي تعليقات, بدون أي رموز لها مغزى, وبدون أي تعريفات للبيانات.

[عدل]وحدات الماكرو Macros
تدعم العديد من المجمعات وحدات الماكرو Macros, وهي عبارة عن رموز معرفة عن طريق المبرمج وتحوي مجموعة من سطور النص المتسلسلة.هذا التسلسل للسطور النصية, قد يحوي سلسلة من التعليمات, أو سلسلة من تعليمات Pseudo-Ops خاصة بالبيانات.وطالما تم تعريف الماكرو عبر استخدام الـ Pseudo-Op المناسب, فإنه من الممكن استخدام اسمه, مثلما يتم استخدام أسماء الأوامر Mnemonic تماما.وعندما يقوم المجمع بمعالجة جملة Statement من تلك النوعية, فإنه يقوم باستبدال الجملة -التي تحوي اسم الماكرو- بالسطور النصية المرتبطة بذلك الماكرو, وبعد ذلك يقوم بمعالجة تلك السطور كما لو أنها قد ظهرت في ملف كود المصدر (متضمنا, كما يحدث مع المجمعات الجيدة, محتويات أي ماكرو قد يظهر في تلك السطور -ماكرو داخل ماكرو-).

وبما أن وحدات الماكرو يمكن أن تحمل أسماء "قصيرة" وفي نفس الوقت تحمل سطورا طويلة من الكود, فإن وحدات الماكرو يمكن أن تستخدم لتجعل البرامج المكتوبة بلغة التجميع تبدو وكأنها أقصر (بمعنى أن يتطلب بناء التطبيق عددا أقل من سطور الكود, كما هو الحال مع لغات البرمجة عالية المستوى).ويمكن أيضا أن يتم استخدامها لإضافة هياكل Structures عالية المستوى إلى البرامج المكتوبة بلغة التجميع, ويمكن أن تقدم -بشكل اختياري- كود يستخدم لإدارة وإصلاح الأخطاء De-Bugging بشكل ضمني, عبر المعاملات Parameters وعبر خصائص أخرى.

معظم المجمعات تمتلك وحدات ماكرو مدمجة Built-in من أجل الاستدعائات عبر النظام System Calls ومن أجل بعض تسلسلات الكود الخاصة.

وغالبا ما تسمح المجمعات لوحدات ماكرو بأن تمتلك معامالات Parameters.وبعض المجمعات تمتلك لغة ماكرو معقدة جدا, وتقوم بدمج عناصر هذه اللغة عالية المستوى للقيام بوظائف متعددة: معاملات اختيارية Optional Parameters, متغيرات رمزية, جمل شرطية, معالجة لسلاسل الحرفية Strings, عمل عمليات حسابية, وجميع تلك الأشياء يمكن إعادة استخدامها أثناء تنفيذ وحدات ماكرو بعينها, وتسمح -تلك المجمعات- لوحدات الماكرو بحفظ السياق Context أو تبادل المعلومات بين بعضها البعض.ولذلك, فإن الماكرو يمكنه توليد عدد ضخم من تعليمات لغة التجميع أو من تعريفات البيانات, استنادا إلى معاملات الماكرو Arguments.ويمكن استخدام ذلك لتوليد هياكل بيانات ذات شكل "سجلي" Record-Style, ويمكن استخدام ذلك أيضا لتولييد دوارات Loops مبسوطة Unrolled, هذا على سبيل المثال, ويمكن أيضا استخدام نفس التقنية في توليد خوارزميات كاملة Algorithms تستند على معاملات معقدة Parameters.ويمكن اعتبار مؤسسة تستخدم هذه النوعية من لغات التجميع والتي تم تمديد قدراتها بشكل مكثف عبر استخدام مجموعة وحدات الماكرو, يمكن اعتبارها وكأنها تستخدم لغة برمجة عالية المستوى, حيث أن مبرمجي الشركة لا يعملون مع عناصر الكمبيوتر المفاهيمية ذات المستوى المنخفض -مثال: لا يعملون مع المسجلات مثلا Registers-.

وقد تم استخدام وحدات الماكرو في عهد الحاسب الكبير Mainframe من أجل تخصيص Customize نظم برمجية واسعة النطاق Large Scale لتلبية طلبات محددة لعملاء معينين, واستخدت أيضا عبر فريق عمل أحد العملاء من أجل تلبية احتياجات موظفيه عبر بناء نسخ محددة من نظم تشغيل مصنع الكمبيوترات Manufacturer-الذي قد اشتراها هذا العميل-, وعلى سبيل المثال, فقد سبق فعل ذلك, مع مبرمجي النظم الذين كانوا يعملون لشركة IBM, وبشكل أكثر تحديدا, كانوا يعملون على نظام مراقبة المحادثات/ النظام الافتراضي CMS/VM, وعلى نظام "معالجة المعاملات بشكل لحظي Real Time", وعلى نظام "التحكم في بيانات العملاء", وعلى ACP/TPF, وهو نظام مالي إداري -خاص بخطوط الطيران- بدأ في السبعينات وما زال يقوم بتشغيل نظم عالمية كبرى للتوزيع GDS ونظم بطاقات الائتمان حتى يومنا هذا.

وكان من الممكن أيضا أن يتم استخدام قدرات الماكرو المعالجة Processing فقط بحيث يقوم المجمع بتوليد كود مكتوب بلغات مختلفة تماما, وعلى سبيل المثال, يمكن استخدام تلك التقنية في توليد نسخة من البرنامج مكتوبة بلغة "كوبول" Cobol عبر استخدام مجمع مزود ببرنامج ماكرو يحتوي على سطور من كود الكوبول, وأثناء وقت التجميع Assembly Time يمكن لمعاملات Operators أن توجه المجمع لتوليد الكود بشكل تحكمي Arbitrary.

ويرجع سبب ذلك, كما تم إدراكه في السبعينات, أن مفهوم "معالجة الماكرو" Macro Processing يختلف عن مفهوم "التجميع" Assembly, حيث يشير المصطلح الأول في لغتنا الحاسوبية الحديثة إلى إمكانيات في برامج معالجة الكلمات, معالجة النصوص, أكثر من إشارته إلى توليد الكود.وحقيقة, فإن مفهوم "معالجة الماكرو" قد ظهر -وما زال يظهر- في لغة البرمجة "سي" C, حيث تدعم "تعليمات ما قبل المعالجة" Preprocessor Instructions من أجل تحديد قيم المتغيرات Set Variables.لاحظ أنه على عكس الأنواع المحددة لمعالجات الماكرو التي تم ذكرها والتي تعمل داخل المجمعات, فإن المعالج القبيل للغة الـ C لم يكن Turing-Complete (متكامل مع معايير تورينج) لأنه كان ينقصه إمكانية "الدوارات" Loops أو الذهاب إلى تعليمة محددة عبر أمر Go To.

وبالرغم من قوة معالجة الماكرو, فقد تم إهمالها في اللغات عالية المستوى, بينما تظل مهمة وموجودة في المجمعات Assemblers.

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

ويتم استبدال معاملات الماكرو Parameter Substitution بشكل صارم عبر الاسم فقط: في وقت معالجة الماكرو, يتم استبدال قيمة المعامل باسم المعامل نصيا.وينتج أشهر صنف من الأخطاء Bugs عبر استخدام المعامل والذي كان يعبر -نفسه- عن Expression وليس عن اسم بسيط, في حين أن كاتب الماكرو يتوقع اسما Name.وفي الماكرو : foo: macro a load a*b القصد هنا هو أن يقوم المنادي Caller بتوفير اسم للمتغير, ويتم ضرب المتغير "العالمي" Global أو الثابت "b" في "a".إذا تم استدعاء foo مع المعامل a-c, سيقوم الماكرو بالتوسع Expand بشكل غير متوقع.

ولتجنب هذا الأمر, تعلم مستخدمو "معالجة الماكرو" أن يقوموا بحصر المعاملات داخل تعريفات الماكرو Macro Definitions, ثم يكون على المناديين Callers أن يفعلوا المثل مع معاملاتهم "الحقيقية" Actual Parameters.

وقد قدمت لغات الـ PL/I و C ميزة الماكرو, لكن تلك التسهيلة Facility كانت خطرة ولم تستخدم بشكل كافي لأنها لم تكن تعالج سوى النصوص Text.ومن ناحية أخرى, حافظ لغات الذكاء الصناعي Homoiconic مثل Lisp و Prolog و Forth على إمكانيات ماكروهات Macros لغات التجميعات خاصتها, لأنهم جميعا قادرين على معالجة الكود الخاص بهم مثلهم مثل البيانات.

ليست هناك تعليقات:

إرسال تعليق