لغة التجميع
لغة التجميع هي مجموعة من اللغات ذات المستوى المنخفض Low-Level (بمعنى أنها مصممة لتتعامل مع الحاسوب أكثر من كونها مصممة ليتم البرمجة بها) تستخدم في برمجة أجهزة الكمبيوتر، المعالجات الدقيقة Microprocessors، المتحكمات الدقيقة Microcontrollers، وفي برمجة الدوائر المتكاملة Integrated Circuits (IC).وتقوم تلك اللغات بتحويل الكود والثوابت اللازمة لبرمجة بناء معين من وحدات المعالجة المركزية CPU، من شكله المعتمد على الرموز Symbolic إلى شكل آخر رقمي يسمى "كود الآلة" Machine Code.هذا التحويل/التمثيل Representation يتم تعريفه عادة عبر الشركات المصنعة للأجهزة، ويعتمد على مجموعة من الاختصارات التي تساعد المبرمجين على تذكر تعليمات البرمجة والسجلات Registers المستخدمة في عمليات البرمجة بسهولة. وهناك لغة تجميع محددة لكل بناء حاسوبي سواء كان فعليا Physical أو افتراضيا Virtual (بعكس معظم لغات البرمجة عالية المستوى High-Level، التي عادة ما تعمل مع معظم أنظمة الحاسوب).
وتستخدم أداة برمجية تسمى "المجمِع" Assembler في ترجمة السطور والتعليمات Instructions المكودة عبر لغة التجميع إلى "كود الآلة" التي يتم التعامل معها.ويقوم المجمع بتنفيذ ترجمة تماثلية (مثال: سطر مكتوب بلغة التجميع يتحول لسطر مكتوب بلغة الآلة، وهكذا -يسمى One-to-One Mapping) للجمل/السطور المخزنة في ذاكرة الحاسوب ويحولها لتعليمات وبيانات تفهمها الآلة Machine.وهذا يختلف عما يحدث في اللغات عالية المستوى، حيث يتم عادة ترجمة كل جملة إلى عدة أوامر تفهمها الآلة Machine Instructions.
وتقدم العديد من المجمعات المتطورة Assemblers إمكانيات وآليات إضافية تسهل: تطوير البرامج، التحكم في عملية التجميع، والمساعدة في اكتشاف وتصحيح الأخطاء البرمجية Debugging.وعلى وجه الخصوص، فإن معظم المجمعات الحديثة تتضمن مرفق من نوع ماكرو Macro (موصوف أدناه)، وتسمى تلك المجمعات بمجمعات ماكرو Macro Assemblers.
عادة ما يقوم أي مجمع حديث بتكوين كود غرضي/نهائى Object Code عبر ترجمة تعليمات لغة التجميع إلى شفرة تشغيل Opcode (Operation Code)، وعبر تحليل الأسماء الرمزية لمواقع تخزين البيانات بالذاكرة Memory Locations وغيرها من الأشياء.ويعتبر استخدام "الإشارات الرمزية" Symbolic References سمة أساسية من سمات المجمعات، حيث يتم حفظ حسابات طويلة ومملة، وتحديث عناوين الذاكرة بعد تعديلات البرنامج.وتحتوي معظم المجمعات على تسهيلات Facilities من نواع "ماكرو" Macro تقوم بعمليات "استبدال النصوص" Textual Substitution- وعلى سبيل المثال، لتوليد متواليات قصيرة من التعليمات تعمل Inline بدلا من أن تعمل في Subroutine.
وبصفة عامة، فإن كتابة المجمعات -لأن المجمع أساسا عبارة عن برنامج Program يتم كتابته- أسهل من كتابة مترجمات اللغات عالية المستوى Compilers، وقد ظهرت المجمعات منذ خمسينات القرن الماضي.وتقوم المجمعات، وخصوصا تلك المعتمدة على بناء/هندسة حاسوبية Architecture من نوع RISC، مثل نماذج: MIPS وSPARK من شركة "صن مايكروسيستمز"، وPA-RISC من شركة "هيوليت باكارد"، وأيضا معالجات x86(-64), تقوم بالوصول لجدولة التعليمات للدرجة المثلى، من أجل استغلال خط Pipeline وحدة المعالجة المركزية أكفأ استغلال.
وهناك نوعين من المجمعات Assemblers، وتم تقسيم النوعين على أساس عدد مرات المرور Passes خلال الكود المطلوب لإنتاج الكود النهائي، أو البرنامج القابل للتنفيذ Executable بمعنى آخر.النوع الأول، هو المجمع الذي يمر على الكود "مرة واحدة فقط"، مفترضا أن تعريف كل رموز الكود (مثل أسماء المتغيرات) سبق أي تعليمات قد تشير لهذه الرموز.النوع الثاني، وهو المجمع الذي يمر "مرتين" -أو أكثر من مرة- على الكود، ويقوم أثناء المرور الأول بتكوين جدول Table يضع فيه كل الرموز التي لم يتعرف عليها Unresolved، ويستخدم تلك الرموز في المرور الثاني 2nd Pass، كي يقوم بحل تلك العناوين Addresses.أما ميزة المجمع ذو النوع الأول "مرور واحد"، فهي "السرعة" بكل تأكيد- والتي لم تعد مهمة كما كانت يوما ما، بعد أن تطورت سرعات وإمكانيات أجهزة الكمبيوتر.أما ميزة النوع الثاني من المجمعات "تقوم بمرورين فيما فوق" فهي أن رموز البرنامج يمكن أن تعرف في أي مكان بالكود المصدري Source Code للبرنامج.
وكنتيجة لذلك، فيمكن تعريف البرنامج بطريقة أكثر منطقية وذات مغزى -على سبيل المثال، يستطيع المبرمج قراءة برامج زملاءه بسهولة أكثر-.مما يجعل برامج المجمع ثنائي-المرور أسهل في القراءة والصيانة -القيام بتعديلات عليها مثلا-.
أما المجمعات عالية المستوى وذات الإمكانيات الأكثر تعقيدا، فتوفر تجريدا أكثر للغة Abstraction، يمكن توضيحه فيما يلي:
لتفاصيل أخرى، انظر "تصميم اللغة" أدناه.
لاحظ أنه، في حالة الاستخدام المهني العادي، يتم استخدام اللفظ "مجمع" Assembler بشكل غامض: فكثيرا ما يتم استخدامه للإشارة للغة التجميع نفسها، بدلا من الإشارة لـ "أداة التجميع".وبالتالي: فإن عبارة "إن نموذج CP/CMS تم كتابته بلغة التجميع Assembler ذو الاسم S/360" تختلف عن العبارة "إن نموذج ASM-H لهو مجمع Assembler تم استخدامه على نطاق واسع مع S/370".
ويتكون البرنامج المكتوب بلغة التجميع من سلسلة من التعليمات-سهلة الحفظ Instructions—Mnemonics والتي تماثل دفعة من التعليمات التنفيذية Executable، وعندما يتم ترجمة هذا الكود عبر "مجمع" Assmbler"، يمكن هنا تحميل هذا الكود إلى الذاكرة وتنفيذه.
وعلى سبيل المثال، فإن معالجا Processor من نوع x86/IA-32 يمكنه تنفيذ التعليمات التالية والمكتوبة بكود ثنائي Binary يمثل لغة الآلة Machine Language (انظر لغة التجميع الخاصة بمعالج x86):ومع قرائتك للسطر السابق تشعر بأن تمثيل الكود عبر لغة التجميع لهو أسهل للقراءة وللتذكر (مثال باستخدام تراكيب شركة إنتل، انظر استذكار
وتعني هذه التعليمات ما يلي:الأمر "mov" يكتب بكود التشغيل بالشكل 1011, ويقوم بنقل Move القيمة المذكورة بمعامل Operand الأمر الثاني، إلى السجل المذكور عبر المعامل الأول.وقداختار "مصمم مجموعة التعليمات" تلك الحروف الثلاثة mov لتمثيل الأمر، مما يجعل الأمر سهلا على المبرمج لتذكر واستخدام الأمر.ويتم الفصل بين مجموعة والمعطيات التي تتبع شفرة التشغيل عبر فاصلة "،"؛ إن ما سبق لهو نموذج جيد لجملة Statement من جمل لغة التجميع.
وأثناء الممارسة يقوم العديد من المبرمجين بإسقاط الكلمة Mnemonic (أمر سهل التذكر) وإطلاق وصف "كود تشغيلي" Opcode على اللفظة "mov"، وذلك خطأ تقني بكل تأكيد.فعندما يفعلون ذلك، فهم يشيرون إلى الكود الثنائي والذي تمثله لغة التجميع.ولتوضيح الأمر بشكل آخر، إن "الأمر سهل التذكر" Mnemonic مثل الأمر mov ليس كودا تشغيليا Opcode، لكنه يمثل أو يرمز إلى الكود التشغيلي، لذلك فعندما يشير أحدهم إلى "الكود التشغيلي للأمر mov" فهو يقصد إلى الإشارة للكود التشغيلي الثنائي Binary ولا يشير إلى الأمر المكتوب بلغة التجميع.وحاليا، يوجد عدد محدود من المبرمجين الذين يحتاجون للتعامل مع النماذج الثنائية التي تمثل كود التشغيل الخاص بتعليمات معينة، فهذا التمييز لم يعد يحتاجه أحد بين المبرمجين -لم تعد عملية البرمجة التي تطورت إمكانياتها تحتاجه-، لكنه مطلوبا جدا في أوساط مصممي المعالجات Processor Designers.
ويتم تحويل لغة التجميع إلى لغة الآلة عبر "المجمع" Assembler، وتتم العملية العكسية عبر برنامج يدعى "فك التجميع" Disassembler.وبخلاف اللغات عالية المستوى، فدائما ما يكون هناك توافق Correspondence بين التعليمات البسيطة المكتوبة بلغة التجميع وبين التعليمات المكتوبة بلغة الآلة.إلا أنه، وفي بعض الحالات، يمكن للمجمع أن يخرج تعلميات من نوع Pseudoinstructions، والتي يتم تمثيلها عبر "عدة" تعليمات بلغة الآلة، من أجل القيام بوظائف يشيع الاحتياج لها.وعلى سبيل المثال، بفرض أن هناك آلة ينقصها الأمر Branch-if-greater-or-equal "انتقل لمكان آخر إذا تساوت القيمة عن x أو زادت عن x" في مجموعة أوامر المجمع الخاص بها، يمكن لحل هذه المشكلة، أن يقوم المجمع بتوفير تعليمات Pseudoinstructions تجمع بين الأمرين "Set if less than" و"branch if zero" -الأمر الأخير يعمل مع ناتج الأوامر التي تسبقه-.وتوفر معظم المجمعات ذات "المميزات الكاملة" Full-Featured، لغة ماكرو Macro ثرية (والتي يتم مناقشتها أدناه) والتي يتم استخدامها من قبل الشركات Vendors والمبرمجين لإنتاج كود وتسلسل بيانات أكثر تعقيدا.
غني عن الذكر، أن كل بناء حاسوبي وكل معالج له لغة الآلة الخاصة به.
وعلى هذا المستوى، تكون كل تعليمة Instruction ممثلة بشكل بسيط بحيث يتم تنفيذها من خلال عدد صغير نسبيا من الدوائر الإلكترونية Electronic Circuits.وتختلف أجهزة الكمبيوتر باختلاف نوع وعدد العمليات التي تدعمها.وعلى سبيل المثال، فإن آلة جديده من نوع 64 بت تتكون من نوع مختلف من الدوائر التي تمتلكها آلة من نوع 32 بت.وقد يختلفان أيضا في أحجام وأعداد المسجلات Registers في كل منهما، وقد يختلفان أيضا في تمثيل البيانات داخل مخازن البيانات -المخازن مثل: الذاكرة Memory، المسجلات Registers-.وفي حين أن معظم أجهزة الكمبيوتر التي تستخدم في الأغراض العامة قادرة على تنفيذ نفس الوظائف، فإن طريقة أداء كل جهاز تختلف عن بقية الأجهزة؛ وتعكس لغات التجميع الخاصة بكل منهم هذا الاختلاف.
وقد تحتوي مجموعة واحدة من أوامر لغة التجميع "Instruction Set" مجموعات متعددة من التراكيب اللغوية التي تستخدم في كتابة الأوامر Mnemonics. وفي مثل هذه الحالات، فإن المجموعة الأكثر استخداما هي تلك التي توفرها الشركة المصنعة -للنظام الحاسوبي- وتستخدمها في وثائق منتجها Documentation.
تتكون أي لغة تجميع من 3 أنواع من جمل التعليمات Instruction Statements والتي تستخدم في تعريف عمليات البرنامج:عادة ما تكون التعليمات (الجمل) في لغة التجميع بسيطة للغاية، بعكس تلك الموجودة في لغات البرمجة عالية المستوى.وبصفة عامة، فإن "كود التشغيل" هو اسم رمزي لتعليمة واحدة تنفيذية مكتوبة بلغة الآلة، ويوجد على الأقل أمر واحد من الكود التنفيذي محدد لكل تعليمة مكتوبة بلغة الآلة.وكل تعليمة Instruction تتكون عادة من "عملياحد Byte، مكودة داخل التعليمة نفسها)، ويمكن أن تكون "غير مباشرة" وتشير إلى عنوان الذاكرة الذي يتم تخزين البيانات فيه.ويتحدد ذلك عبر البنية الأساسية للمعالج Architecture: فالمجمع يعبر عن كيفية عمل هذه البنية فحسب.
هناك تعليمات تستخدم في تحديد عناصر البيانات Data Elements التي تحمل بيانات وتحمل متغيرات.وتحدد تلك العناصر: نوعية البيانات، طول البيانات، وموائمة البيانات Alignment.ويمكن لتلك التعليمات أيضا أن تحدد إذا ما كانت تلك البيانات متاحة لبرامج خارجية Outside Programs (برامج يتم تجميعها بشكل منفصل عن البرنامج الذي يحتوي البيانات)، أو أنها متاحة فقط للبرنامج الذي يحمل قسما يحتوي تعريف تلك البيانات.
"توجيهات لغة التجميع" Assembly Directives هي تعليمات يتم تنفيذها عن طريق المجمع أثناء وقت التجميع Assembly Time، ولا يتم تنفيذها عبر وحدة المعالجة المركزية CPU في وقت تشغيل البرنامج Run Time.ويمكن لتلك التوجيهات أن تجعل لغة التجميع الخاصة بالبرنامج تعتمد على "معامل" Parameter يتم إدخاله عبر المبرمج، بحيث يمكن تجميع البرنامج الواحد بأكثر من طريقة، وربما من أجل تطبيقات مختلفة -لكل نسخة مجمعة مختلفة-.ويمكن أن تستخدم "التوجيهات" Directives أيضا للتلاعب Manipulate بطريقة عرض البرنامج Presentation، مما يجعل البرنامج أسهل في القراءة والصيانة من ناحية المبرمج.
وتدعم بعض المجمعات أيضا تعليمات من نوع 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، وهي عبارة عن رموز معرفة عن طريق المبرمج وتحوي مجموعة من سطور النص المتسلسلة.هذا التسلسل للسطور النصية، قد يحوي سلسلة من التعليمات، أو سلسلة من تعليمات 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 لغات التجميعات خاصتها، لأنهم جميعا قادرين على معالجة الكود الخاص بهم مثلهم مثل البيانات.
قامت بعض المجمعات بإدماج عناصر البرمجة المهيكلة من أجل تكويد Encode تدفق التنفيذ Execution Flow.وأقرب مثال لهذا النهج كانت مجموعة ماكرو المسماة Concept-14, والتي اقترحت لأول مرة عن طريق الدكتور هـ.د.ميلز(مارس 1970), وتم تنفيذها عبر مارفين كيسلر في قسم الأنظمة الفيدرالية بـ IBM، والتي مددت إمكانيات مجمع الماكرو من نوع S/360 بـ IF/ELSE/ENDIF وبلوكات أخرى للتحكم في التدفق Flow Control.وقد كانت تلك طريقة لخفض أو إزالة استخدام عمليات GOTO في كود التجميع، حيث أن عمليات الـ GOTO من العوامل الرئيسية التي تسبب في ما يسمى بـ "كود الإسباجتي" -الكود المتشابك والمتعقد- في لغة التجميع.وقد كانت هذه الطريقة مستخدمة ومقبولة على نطاق واسع في أوائل الثمانينات (والتي شكلت الأيام الأخيرة لاستخدام لغة التجميع على نطاق واسع، لم يعد الأمر كذلك الآن).
وقد تم تقديم تصميم غريب سمى A-Natural، وهو عبارة عن مجمع من نوع Stream-Oriented يعمل مع معالجات 8080/Z80 وصممته شركة Whitesmiths Ltd. (تلك الشركة التي طورت نظام التشغيل الشبيهة بيونيكس والمسمى Idris، والذي وصف بأنه أول مترجم تجاري للغة السي C).وقد صنفت اللغة كمجمع Assembler، لأنها كانت تعمل مع عناصر الماكينة "الخام" Machine Elements مثل كود التنفيذ Opcodes، المسجلات Registers، ومراجع الذاكرة References؛ ولكنها أدرجت جملا تعبيرية Expression Syntax للإشارة إلى ترتيب التنفيذ.وقد قامت: الأقواس Parentheses، والرموز الخاصة الأخرى، بجانب الـ Constructs الخاصة بالبرمجة المهيكلة المعتمدة على بلوكات Blocks، قام كل ذلك بالتحكم في تتابع توليد التعليمات Instructions.وقد تم بناء لغة A-Natural لتصبح مترجما Compiler خاص بلغة الـ C، أكثر من بنائها لكي يتم استخدامها في البرمجة اليدوية، لكن جملها المنطقية Syntax أعجبت العديد من المبرمجين الذين عملوا بها وكتبوا بها برامج بالفعل.
وقد ظهرت الحاجة والطلب إلى مترجمات أكثر تعقيدا بعد أن انحدر تطوير البرمجيات باستخدام لغات التجميع على نطاق واسع Large-Scale.وعلى الرغم من ذلك، فإن تلك المجمعات لا تزال تستخدم في بعض الحالات، والتي تحوي قيودا مفروضة على الموارد -وقت، نفقات..الخ- أو أن الخصوصيات Peculiarities المتعلقة بهندسة النظام -الخاص بالتطبيق الجاري تطويره- تمنع الاستخدام الكفؤ للغات البرمجة عالية المستوى.
تم تطوير لغة التجميع لأول مرة في الخمسينيات من القرن المنصرم، وقد تم الإشارة لتلك اللغات في هذا الحين على أنها "الجيل الثاني" من لغات البرمجة.وقد محت لغات الجيل الثاني الكثير من مشكلات منح-الأخطاء Error-Prone ومشكلات استهلاك الوقت التي اتصفت بها لغات البرمجة من "الجيل الأول" التي تعاملت مع الأجيال الأولى من أجهزة الكمبيوتر، وقد حررت اللغات الجديدة المبرمجين من الكثير من الأمور المملة مثل تذكر الرموز الرقمية وحساب عناوين الذاكرة.وقد استخدمت تلك اللغات يوما ما وبشكل واسع في جميع أنواع البرمجة.وعلى الرغم من ذلك، فإن مع الثمانينات (ومع التسعينات على الحواسب الصغيرة)، فقد استبدلت تلك اللغات بشكل واسع بلغات البرمجة عالية المستوى high-Level Languages، في البحث عن المزيد من التحسين لـ "إنتاجية" العمل البرمجي.واليوم، تستخدم لغة التجميع بشكل رئيسي في: التحكم المباشر في الأجهزة Hardware، الوصول إلى تعليمات المعالج المتخصصة Processor Instructions، أو لمعالجة مسائل حاسمة تتعلق بالسرعة/الأداء Performance.ومن الأنظمة التي تستخدم عادة لغات التجميع، تجد: مشغلات الأجهزة Device Drivers، النظم المطمرة Embedded Systems منخفضة المستوى، وأنظمة الوقت الحقيقي Real-Time.
وتاريخيا، فقد تم كتابة عدد كبير جدا من البرامج بشكل كلي باستخدام لغة التجميع.وقد تم كتابة بعض أنظمة التشغيل Operating Systems بلغة التجميع وبشكل حصري Exclusively، حتى تم انتشار لغة السي C بشكل واسع في فترة السبعينات وأوائل الثمانينات.وقد تم كتابة العديد من التطبيقات التجارية باستخدام لغة التجميع كذلك، ومنها كميات كبيرة من برمجيات تم كتابتها بواسطة شركات كبرى لتعمل على الحواسب الكبيرة Mainframes الخاصة المصنعة عبر شركة IBM.وعلى الرغم أنه -في نهاية الأمر- قامت لغات "كوبول" COBOL و"فورتران" FORTRAN باستبدال معظم هذا العمل، إلا أن عدد كبير من المنظمات/الشركات حافظت على نظمها وبنيها التحتية Infrastructure المبرمجة عبر لغة التجميع حتى التسعينات، حيث عملت طول هذه الفترة بشكل جيد.
وقد اعتمدت معظم الحواسيب الصغيرة Microcomputers على كود مكتوب يدويا باستخدام لغة التجميع، بما في ذلك نظم التشغيل Operating Systems والتطبيقات الكبيرة.وذلك لعدة أسباب: أولها أن تلك النظم حافظت على قيود شديدة على الموارد، فرضت خصوصية على الذاكرة Memory وعلى عرض بنية التطبيقات Architecture، وخفضت من نسبة الأخطاء Bugs التي تظهر أثناء عمل النظم.وربما كان الأهم من ذلك كله كانت الحاجة لوجود مترجمات للغة عالية المستوى من الدرجة الأولى First-Class، تكون مناسبة لاستخدام الحواسيب الصغيرة Microcomputers.وقد يكون هناك عاملا نفسيا قد لعب دورا أيضا: أن الجيل الأول من مبرمجي الحواسيب الصغيرة ظلوا يحتفظون بموقف الهواة Hobbyists والذي يمكن صياغته في العبارة: "الأسلاك والزرديات" Wires and Pliers -عبارة تشير إلى تمسك أولئك المبرمجين بالأسلوب "الصعب" للغة التجميع على الرغم من توافر أساليب "أسهل" مثل اللغات عالية المستوى-.
وفي اطار تجاري أكثر، فإن الأسباب الرئيسية لاستخدام لغة التجميع كانت: حجم Size أقل، مشكلات Overhead أقل، سرعة أعلى واعتمادية Reliability أعلى.
وكأمثلة نموذجية لبرامج كبرى كتبت بلغة التجميع في ذاك الوقت، تجد نظام التشغيل "مايكروسوفت دوس" MS-DOS، وبرنامج IBM لمعالجة الجداول "لوتس" Lotus 1-2-3, وكذلك معظم الألعاب الشهيرة لعائلة "الأتاري" Atari 800 للحواسب المنزلية.وحتى في التسعينات، معظم ألعاب الفيديو من نوع Console تم كتابتها عبر لغة التجميع، بما في ذلك معظم ألعاب شركات Mega Drive/Gensis وشركة Super Nintendo لأنظمة الترفيه.ووفقا لبعض المطلعين داخل صناعة البرمجيات، فإن لغة التجميع كانت أفضل لغة حوسبة يمكن استخدامها من أجل أداء/سرعة عاليين لأجهزة Sega Saturn -وهي أجهزة Console كانت تشتهر في مجال تطوير وبرمجة الألعاب-.وكذلك لعبة NBA Jam والتي ظهرت عام 1993 كلعبة من نوع Arcade ونالت شعبية كبيرة، تعتبر مثالا آخر.واعتبرت لغة التجميع هي لغة التطوير الأساسية على عدة منصات لوقت طويل، منها: Commodore 64، Atari ST وكذلك حواسب المنزل من نوع ZX Spectrum.وقد تسببت عدم كفاءة لغة الـ BASIC -في ذلك الوقت- في استمرار اعتماد تلك الآلات على لغة التجميع، لقد عاب الـ BASIC سببين: لم يوفر سرعة تنفيذ عالية مع هذه النظم، لم يقدم تسهيلات كافية من أجل أفضل استخدام لإمكانيات العتاد Hardware الخاصة بتلك النظم.بعض الأنظمة، وعلى الأخص Amiga، لديها "بيئة تطوير متكاملة" IDE مع إمكانيات عالية لاكتشاف ومعالجة الأخطاء Debugging وإمكانيات "ماكرو"، مثل المجمع المجاني ASM-One، مقارنة بإمكانيات برنامج Microsoft Visual Studio (على الرغم من أن ASM-One يسبق Microsoft Visual Studio من حيث وقت الإصدار).
وقد تم كتابة المجمع VIC-20 عبر "دون فرينش" ونشرته شركة "فرينش سيلك".وقد تم كتابته في برنامج يبلغ من الحجم 1639 بايتس Bytes فقط، مما يجعل صاحبه يعتقد أنه أصغر مجمع رمزي تم كتابته في التاريخ.ويدعم المجمع نظم العنونة الرمزية والتعريفات الخاصة بسلاسل الحروف وسلاسل الرموز ذات النظام الـHexadecimal.ويسمح المجمع أيضا بتعيرات العناوين Address Expressions والتي يمكن توحيدها Combined مع عمليات: الجمع، الطرح، الضرب، القسمة، Logical AND, Logical OR والمعاملات الأسية Exponentiation Operators.
دائما ما كان هناك جدلا حول فائدة وأداء لغة التجميع بالمقارنة بلغات البرمجة عالية المستوى.ومعروف أن لغة التجميع لها اطار محدد Niche تظهر فيه أهميتها؛ انظر أدناه.ولكن بصفة عامة، تدعي المترجمات Compilers الحديثة المثلى Optimized أنها تستطيع معالجة كود لغات البرمجة عالية المستوى وتستطيع تنفيذه Run بنفس سرعة تنفيذ الكود المكتوب يدويا بلغة التجميع، على الرغم من بعض الأمثلة العكسية Counter-Examples التي يمكن أن تنشأ.وتشكل زيادة تعقيد المعالجات الحديثة صعوبات متزايدة في كتابة كود فعال محسن يدويا Hand-Optimized.وعلاوة على ذلك، ولاستياء عشاق الكفاءة Efficiency، فإن زيادة أداء/سرعة المعالج تعني أن معظم وحدات المعالجة المركزية CPUs تظل خاملة Idle معظم الوقت، بسبب التأخيرات الناجمة عن اختناقات Bottlenecks يمكن التنبؤ بها Predictable مثل عمليات الإدخال/الإخراج I/O وعمليات الـ Paging.ذلك مما جعل العديد من المبرمجين يتوقفون عن اعتبار سرعة تنفيذ الكود الخام أمرا مهما.
وهناك بعض الحالات التي قد يختار فيها الممارسون استخدام لغة التجميع، مثل الحالات التالية:ومع ذلك، فإنه يتم تدريس لغة التجميع حتى يومنا هذا في معظم مناهج الهندسة الإلكترونية وعلوم الحاسب.على الرغم من أن هناك قلة قليلة من المبرمجين اليوم يعملون بشكل منتظم مع لغة التجميع بوصفها أداة تطوير، فإن المفاهيم المرتبطة بلغة التجميع لا تزال مهمة جدا.ومن تلك المواضيع الأساسية: الحساب الثنائي Binary Arithmetic، تخصيص الذاكرة Allocation، معالجة المكدس Stack، تكويد مجموعة الأحرف Character Set، معالجة المقاطعات Interrupts، وتصميم المترجمات Compilers، كل تلك الأشياء سيكون من الصعب جدا فهمها دون فهم كيفية عمل الكمبيوتر على مستوى العتاد Hardware.ولأن سلوك الكمبيوتر يمكن تعريفه عبر مجموعة التعليمات Instruction Set الخاصة به، فإن الطريقة المنطقية لتعلم مجموعة المفاهيم المرتبطة بهذا "السلوك" هي دراسة لغة التجميع.وتمتلك معظم الأجهزة الحديثة مجموعة تعليمات مماثلة.ولذلك، فإن دراسة لغة تجميع واحدة تكفي لتعلم الآتي: (1) المفاهيم الرئيسية, (2) للتعرف على المواقف التي يكون فيها من المناسب استخدام لغة التجميع, (3) لمعرفة كيف يمكن توليد كود تنفيذي كفؤ من اللغات عالية المستوى.
غالبا ما يتم استخدام الكود المكتوب بلغة التجميع في نظام ROM عند تحميل النظام (BIOS على نظم PC المتوافقة مع IBM) - كلمة BIOS اختصارا لـ Basic Input Output System-.ويستخدم هذا الكود المكتوب بلغة منخفضة المستوى، مع أشياء أخرى، في تهيئة واختبار العتاد Hardware قبل تحميل نظام التشغيل OS، ويخزن ذلك الكود في الذاكرة من نوع القراءة فقط ROM -اختصار Read Only Memory-. وحالما تم الوصول لمستوى معين من تهيئة الجهاز، يتم الانتقال إلى تنفيذ كود آخر، وغالبا ما يكون مكتوبا بلغة عالية المستوى؛ لكن الكود الذي يتم تشغيله بعد الضغط على زر تشغيل الكمبيوتر Power Button غالبا ما يكون مكتوب بلغة التجميع.ونطبق نفس الشئ على معظم برامج التحميل Boot Loaders.
وتقوم معظم المترجمات Compilers بمعالجة لغات عالية المستوى إلى لغة تجميع أولا قبل الترجمة النهائية، وبذلك تتيح كود التجميع ليتعرض لعمليات التصحيح Debugging والتحسين Optimization.وتوفر لغات البرمجة منخفضة المستوى نسبيا، مثل لغة السي C، بناء لغويا خاصا Syntax لدمج الكود المكتوب بلغة التجميع مباشرة في كود المصدر الخاص بها.ويمكن للبرامج التي تستخدم مثل هذه التسيهلات، كـ Linux Kernel (نواة لينكس) على سبيل المثال، أن تبني تجريديات Abstractions عبر استخدام عدة لغات تجميع على كل منصة عتادة مختلفة Hardware Platform.ويمكن للكود النقال Portable الخاص بالنظام أن يستخدم المكونات الخاصة بكل معالج -للعمل مع مختلف المنصات- خلال واجهة Interface موحدة.
وتعد لغة التجميع شيئا ذي قيمة كبيرة مع "الهندسة العكسية" Reverse Engineering، لأن العديد من البرامج يتم تداولها في صيغة كود آلة Machine Code، وغالبا ما يكون "كود الآلة" سهلا في الترجمة إلى لغة التجميع ويختبر بعناية في هذا الشكل، أما تحويله إلى لغة عالية المستوى لهو أمر صعب للغاية.وتستخدم أدوات مثل "المفكك التفاعلي" Interactive Disassembler نفس التقنية على شكل واسع من أجل نفس الأهداف.
هناك أيضا الدموسين والذي يجعل من استخدام لغة التجميع حقلا فريدا له.فهناك العديد من المسابقات الخاصة التي تقيد المتسابقين بتقييد إبداعاتهم -من البرامج- إلى حجم صغير جدا (أمثلة: 256 بايت, 1 كيلو بايت, 4 كيلو بايت أو 64 كيلو بايت)، وبالطبع فإن لغة التجميع هي أمثل حل لتحقيق هذا الهدف.وعندما يكون الحفاظ على الموارد Resources، وخاصة وحدة المعالجة المركزية CPU للأنظمة التي تفرض قيودا على المعالجة Processing، مثل النماذج السابقة لأجهزة Amiga وأجهزة Commodore 64, هنا تصبح البرمجة بلغة التجميع أمرا لا بد منه: حيث يتم كتابة كود التجميع "يدويا" ويتم إعداد تسلسل التعليمات عبر المبرمجين في محاولة لخفض عدد دورات الـ CPU المستخدمة؛ لأن القيود المفروضة على الـ CPU غاية في الصرامة، لدرجة أن كل دورة للـ CPU يحب وضعها في الحسبان.ومع ذلك، فإن الفضل يرجع لاستخدام مثل تلك التطبيقات والتي أتاحت نظما مثل Commodore 64 أن ينتج رسوميات ثلاثية الأبعاد 3D Graphics تعمل في نمط "الزمن الحقيقي" Real-Time، مع تأثيرات متقدمة Effects، وهو الإنجاز الذي قد يعتبر تحقيقه بعيد الاحتمال على أجهزة حديثة ومتطورة مع معالج 0.99 ميجا هيرتز.
تحتوي الصفحة التالية على قائمة بأنواع مختلفة من المجمعات التي تعمل مع هندسات/أبنية مختلفة من الحواسب، وتحوي القائمة معلومات مرتبطة بكل نوع من أنواع تلك المجمعات:لقد تم كتابة ما لا يقل عن عشرات من المجمعات لكل كمبيوتر شخصي، حاسب كبير Mainframe، نظام مطمر Embedded System ولعبة كونسول Console Game، في الماضي والحاضر. ولمطالعة بعض الأمثلة، راجع قائمة المجمعات Assemblers.
وعلى أنظمة يونيكس Unix، غالبا ما يطلع على المجمع التقليدي اسم as، على الرغم من أنه ليس كيان واحد من الكود، لأنه يجري عادة كتابة مجمع جديد لكل بورت Port.وهناك العديد من اصدارات يونيكس Unix تستخدم GAS.
لكل مجمع لهجة خاصة Dialect، داخل مجموعة من المجمعات.وأحيانا، تستطيع بعض المجمعات قراءة اللهجة الخاصة بمجمع آخر، وعلى سبيل المثال، يمكن لمجمع TASM من قراءة كود الـ MASM القديم، لكن العكس ليس صحيحا.ويمتلك مجمعي الـ FASM والـ NASM بناء لغوي متشابه Syntax، لكن كلا منهم يدعم مجموعة مختلفة من الماكرو Macro مما يجعل من الصعب الترجمة من أحدهم للآخر.وبالطبع فإن الأساسيات تظل واحدة، لكن المميزات المتقدمة Advanced Features تختلف.
أيضا، يمكن للغة التجميع أن تكون منقولة Portable عبر عدة أنظمة تشغيل، وعلى وحدة معالجة مركزية CPU واحدة. فاصطلاحات Conventions استدعاء الوظائف لا تختلف كثيرا بين أنظمة التشغيل المختلفة وأحيانا لا تختلف على الإطلاق، وببعض الحرص Care، يمكن الحصول على "نقالية" Portability في لغة التجميع، وعادة يتم ذلك عبر الربط مع مكتبة سي C والتي لا تتغير بين نظم التشغيل.
وعلى سبيل المثال، العديد من الأشياء داخل مكتبة لغة السي libc تعتمد على "ما قبل المعالجة" Preprocessor لتقوم بأشياء مرتبطة بنظام التشغيل OS-Specific، واشياء مرتبطة بلغة السي C-Specific، وتقوم بعمل ذلك للبرنامج قبل أن تبدأ في الترجمة Compiling.وفي واقع الأمر، فإن بعض الوظائف والرموز لا يمكن ضمان وجودها خارج الـ Preprocessor.الأسوأ من ذلك، أن حجم وترتيب البنيات Structs، فضلا عن حجم بعض أنواع من تعريف الأنواع typedefs مثل off_t، لا يوجد تعريف مثل هذه الاشياء في لغة التجميع -بدون مساعدة من ملف خارجي لتحديد هذه القيم Configure Script-، وتختلف حتى بين الإصدارات المختلفة من لينكس Linux، مما يجعل من المستحيل أن يتم استدعاء وظائف من مكتبة السي libc بشكل نقال Portable، غير تلك التي تتعامل بشكل بسيط مع القيم الصحيحة Integers والمؤشرات Pointers كمعاملات.ولمعالجة هذه المسألة، يقوم مشروع FASMLIB (مكتبة للمجمع FASM) بتوفير مكتبة نقالة للمجمع تعمل على منصات Win32 ولينكس Linux، لكنها ليست كاملة بشكل كافي حتى الآن.
بعض لغات برمجة الحاسوب عالية المستوى، مثل لغة السي C ولغة "بورلاند باسكال" Borland Pascal، تدعم التجميع الداخلي Inline Assembly حيث يمكن دمج فقرات صغيرة نسبيا من كود التجميع داخل الكود المكتوب باللغة عالية المستوى.وغالبا ما تحتوي لغات البرمجة Forth على مجمعاً يستخدم في كلمات CODE Words.
ويستخدم العديد من الأشخاص نظم "المضاهاة" Emulator من أجل كشف وتصحيح Debug أخطاء البرامج المكتوبة بلغة التجميع.
مثال على مجموعة مختارة من التعليمات (من أجل كمبيوتر افتراضي Virtual Computer)
مع العناوين المقابلة في الذاكرة حيث يتم وضع كل تعليمة.هذه العناوين ليست ثابتة Static، انظر إدارة الذاكرة.
ويقوم بمصاحبة كل تعليمة مولدة (عبر المجمع) الكود النهائي Object Code والذي يتوائم مع هندسة الكمبويتر الافتراضي Virtual Computer's Architecture.