لغة التجميع x86

لغة التجميع x86 هي عائلة من لغات البرمجة منخفضة المستوى تُستخدم لإنتاج التعليمات البرمجية للكائنات لمعالجات x86 . توفر الإصدارات السابقة من هذه العائلة من اللغات توافقًا رجعيًا مع وحدات المعالجة المركزية التي يعود تاريخها إلى معالج Intel 8008 ، الذي طُرح في أبريل 1972. [ 1 ] [ 2 ] وباعتبارها لغات تجميع ، فهي مرتبطة ارتباطًا وثيقًا بتعليمات لغة الآلة الخاصة بالمعمارية، مما يسمح بتحكم دقيق في المكونات المادية.

في لغات التجميع x86، تُستخدم الرموز المختصرة لتمثيل تعليمات وحدة المعالجة المركزية الأساسية، مما يجعل الكود أكثر قابلية للقراءة البشرية مقارنةً بشفرة الآلة الخام . كل تعليمة في شفرة الآلة هي رمز عملية ، والذي يُستبدل في لغة التجميع برمز مختصر. [ 3 ] يتوافق كل رمز مختصر مع عملية أساسية يُنفذها المعالج، مثل العمليات الحسابية، أو نقل البيانات، أو قرارات التحكم في تدفق البيانات. تُستخدم لغات التجميع بشكل شائع في التطبيقات التي يكون فيها الأداء والكفاءة أمرين حاسمين. يشمل ذلك الأنظمة المدمجة في الوقت الحقيقي ، ونواة أنظمة التشغيل ، وبرامج تشغيل الأجهزة ، والتي قد تتطلب جميعها معالجة مباشرة لموارد الأجهزة.

بالإضافة إلى ذلك، تقوم مُجمِّعات لغات البرمجة عالية المستوى أحيانًا بتوليد كود التجميع كخطوة وسيطة أثناء عملية التجميع. وهذا يسمح بإجراء تحسينات على مستوى التجميع قبل إنتاج كود الآلة النهائي الذي يُنفِّذه المعالج.

أساليب التذكر ورموز العمليات

تُمثَّل كل تعليمة في لغة التجميع x86 برمز تذكيري ، غالبًا ما يُدمج مع مُعامل واحد أو أكثر لترجمتها إلى بايت واحد أو أكثر يُعرف برمز العملية (opcode) . على سبيل المثال، تُترجم تعليمة NOP إلى رمز العملية 0x90، وتُترجم تعليمة HLT إلى 0xF4. [ 3 ] توجد رموز عمليات محتملة بدون رموز تذكيرية موثقة، والتي قد تُفسِّرها المعالجات المختلفة بشكل مختلف. قد يؤدي استخدام هذه الرموز إلى سلوك غير متسق للبرنامج أو حتى توليد استثناءات على بعض المعالجات.

بناء الجملة

تتضمن لغة التجميع x86 فرعين رئيسيين من حيث بناء الجملة : بناء جملة Intel وبناء جملة AT & T . [ 4 ] يسود بناء جملة Intel في بيئتي DOS و Windows ، بينما يسود بناء جملة AT & T في الأنظمة الشبيهة بنظام Unix ، حيث طُوّر نظام Unix في الأصل في مختبرات AT&T Bell . [ 5 ] فيما يلي ملخص لأهم الفروقات بين بناء جملة Intel وبناء جملة AT & T :

شركة AT & Tإنتل
ترتيب المعلمات
movl $5 , %eax
المصدر قبل الوجهة.
mov eax , 5
الوجهة قبل المصدر.
حجم المعلمة
addl $0x24 , %esp movslq %ecx , %rax paddd %xmm1 , %xmm2
تُلحق الرموز المختصرة بحرف يشير إلى حجم المعاملات: q لـ qword (64 بت)، وl لـ long (dword، 32 بت)، وw لـ word (16 بت)، و b لـ byte (8 بت). [ 4 ]
أضف esp ، 24h movsxd rax ، ecx paddd xmm2 ، xmm1
يُستمدّ حجم المعامل من اسم السجل المستخدم (على سبيل المثال ، rax وeax وax وal تشير إلى q وl وw وb على التوالي). إذا لم يكن المصدر أو الوجهة سجلاً، فلا يمكن استنتاج حجم المعامل ويجب تحديده صراحةً.
sub byte ptr [ esi ], 20 h

قد تظهر الأسماء المستندة إلى العرض في التعليمات حتى عندما تحدد عملية مختلفة.

  • يشير MOVSXD إلى امتداد الإشارة مع إدخال كلمة مزدوجة، على عكس MOVSX.
  • تحتوي سجلات SIMD على تعليمات تحمل أسماءً تحدد كيفية تقسيم السجل. تميل شركة AT&T إلى الإبقاء على الأسماء دون تغيير، لذلك لم يتم تغيير اسم PADDD إلى "paddl".
الرموزالقيم الفورية مسبوقة بعلامة "$"، والسجلات مسبوقة بعلامة "%". [ 4 ]يقوم المجمع تلقائيًا باكتشاف نوع الرموز؛ أي ما إذا كانت سجلات أو ثوابت أو شيء آخر.
عناوين فعالة
movl offset ( %ebx , %ecx , 4 ), %eax
الصيغة العامة لـ .displacement(base, index, scale)
mov eax , [ ebx + ecx * 4 + offset ]
التعبيرات الحسابية بين قوسين مربعين؛ بالإضافة إلى ذلك، يجب استخدام كلمات مفتاحية للحجم مثل byte أو word أو dword إذا تعذر تحديد الحجم من المعاملات. [ 4 ]

تستخدم العديد من مُجمِّعات x86 صيغة Intel ، بما في ذلك FASM و MASM و NASM و TASM و YASM . يدعم مُجمِّع GNU ، الذي كان يستخدم في الأصل صيغة AT &.intel_syntax T، كلا الصيغتين منذ الإصدار 2.10 عبر التوجيه. [ 4 ] [ 6 ] [ 7 ] من خصائص صيغة AT & T لـ x86 عكس معاملات الفاصلة العائمة x87 ، وهو خطأ موروث من مُجمِّع AT&T الأصلي. [ 8 ]

تُعدّ صيغة AT&T شبه عالمية في مختلف البنى المعمارية (مع الحفاظ على ترتيب المعاملات نفسه للتعليمات mov)؛ وقد صُممت في الأصل للغة التجميع PDP-11 ، ثمّ وُرثت في الأنظمة الشبيهة بنظام يونكس . في المقابل، تُعدّ صيغة إنتل خاصة ببنية x86 ، وهي الصيغة المستخدمة في الوثائق الرسمية لمنصة x86. كما يستخدم معالج إنتل 8080 ، الذي يسبق بنية x86، ترتيب "الوجهة أولاً" movللتعليمات. [ 9 ]

الكلمات المحجوزة

في معظم لغات التجميع x86، تتكون الكلمات المحجوزة من جزأين: رموز مختصرة تُترجم إلى رموز عمليات، وتوجيهات (أو "عمليات زائفة") تُتيح الوصول إلى ميزات في برنامج المُجمِّع تتجاوز مجرد ترجمة رموز العمليات. للاطلاع على قائمة بالجزء الأول، راجع قوائم تعليمات x86 . أما الجزء الثاني، فهو يعتمد بشكل كبير على المُجمِّع، ولا يوجد معيار موحد بين مُجمِّعات Intel. [ 10 ] تشترك مُجمِّعات AT&T في طريقة تسمية مشتركة للتوجيهات (تبدأ جميع التوجيهات بنقطة، مثل .ascii[ 11 ] كما أن عددًا من التوجيهات الأساسية مثل .asciiو .stringمدعومة على نطاق واسع. [ 12 ] [ 13 ]

السجلات

تتميز معالجات x86 بمجموعة من المسجلات التي تُستخدم لتخزين البيانات الثنائية والعناوين أثناء تنفيذ البرنامج. تُصنف هذه المسجلات إلى مسجلات للأغراض العامة ، ومسجلات القطاعات، ومؤشر التعليمات، ومسجل FLAGS، ومسجلات امتداد متنوعة أُضيفت في نماذج المعالجات اللاحقة. لكل مسجل وظائف محددة بالإضافة إلى قدراته العامة: [ 3 ]

سجلات الأغراض العامة

لهذه السجلات أدوار تقليدية، لكن استخدامها ليس إلزاميًا بشكل صارم. بشكل عام، يُسمح للبرامج باستخدامها لأغراض أخرى.

  • سجل المُراكم (AX): يُستخدم بشكل أساسي في العمليات الحسابية والمنطقية ونقل البيانات. يُفضّل استخدامه في تعليمات الضرب والقسمة، وعمليات تحميل وتخزين السلاسل النصية. كما يُمكن ترميز عمليات وحدة الحساب والمنطق (ALU) وعمليات التبادل مع سجل المُراكم (AX) بشكل أكثر اختصارًا.
  • BX (سجل القاعدة): مؤشر القاعدة للوصول إلى الذاكرة. يمكنه تخزين عنوان القاعدة لهياكل البيانات، وهو مفيد في أنماط العنونة المفهرسة. يُستخدم مع XLAT...
  • CX (مسجل العد): يُستخدم كعداد في تعليمات التكرار، والسلاسل النصية، والإزاحة/التدوير. غالبًا ما تستخدم العمليات التكرارية CX لتحديد عدد مرات تنفيذ حلقة أو عملية معينة.
  • DX (سجل البيانات): يُستخدم بالتزامن مع AX لعمليات الضرب والقسمة التي تُنتج نتائج أكبر من 16 بت. كما أنه يحتوي على عناوين منافذ الإدخال/الإخراج INللتعليمات OUT.
  • مؤشر المكدس (SP): يشير إلى أعلى المكدس في الذاكرة. يتم تحديثه تلقائيًا أثناء PUSHالعمليات POP.
  • BP (المؤشر الأساسي): يشير إلى أعلى مكدس الاستدعاءات . ويُستخدم بشكل أساسي للوصول إلى معلمات الدالة والمتغيرات المحلية داخل مكدس الاستدعاءات.
  • مؤشر المصدر (SI): يُستخدم كمؤشر إلى المصدر في عمليات السلاسل النصية ومصفوفات الذاكرة. MOVSتستخدم تعليمات مثل (move string) مؤشر المصدر لقراءة البيانات من الذاكرة. ومثل BX، يمكن استخدامه للفهرسة. ويمكن إضافته إلى BP أو BX للفهرسة المزدوجة.
  • مؤشر الوجهة (DI): يُستخدم كمؤشر إلى الوجهة في عمليات السلاسل النصية ومصفوفات الذاكرة. ويعمل جنبًا إلى جنب مع مؤشر التسلسل (SI) في التعليمات التي تنسخ البيانات أو تقارنها، وتكتب النتائج في الذاكرة. ومثل BX، يمكن استخدامه للفهرسة. ويمكن إضافته إلى BP أو BX للفهرسة المزدوجة.

إلى جانب السجلات العامة، توجد أيضًا ما يلي:

  • مؤشر التعليمات (IP): يحتوي على عنوان الإزاحة للتعليمات التالية المراد تنفيذها ضمن مقطع التعليمات البرمجية (CS). ويشير إلى البايت الأول من التعليمات التالية. على الرغم من أن المبرمجين لا يستطيعون قراءة سجل IP مباشرةً، إلا أن قيمته تتغير من خلال تعليمات التحكم في التدفق، مثل القفزات والاستدعاءات والمقاطعات، التي تُغير مسار التنفيذ.
  • سجل FLAGS : يحتوي على مجموعة من علامات الحالة والتحكم والنظام التي تعكس نتيجة العمليات وتتحكم في عمليات المعالج.
  • سجلات القطاعات (CS، DS، ES، SS): تحدد مكان بدء قطاع 64 كيلوبايت (تمت إضافة FS وGS إلى 80386 وما بعده)
  • سجلات التمديد الإضافية ( MMX ، 3DNow!، SSE ، إلخ) (Pentium والإصدارات الأحدث فقط).

يمكن استخدام سجلات x86 بواسطة معظم التعليمات. على سبيل المثال، في صيغة Intel:

mov ax , 1234h ; ينسخ القيمة 1234hex (4660d) إلى المسجل AX
mov bx , ax ; ينسخ قيمة المسجل AX إلى المسجل BX

العنونة المجزأة

تستخدم بنية x86، في الوضعين الحقيقي والافتراضي 8086، عملية تُعرف بالتجزئة لعنونة الذاكرة، وليس نموذج الذاكرة المسطحة المستخدم في العديد من البيئات الأخرى. تتضمن التجزئة تكوين عنوان الذاكرة من جزأين: مقطع وإزاحة ؛ يشير المقطع إلى بداية مجموعة عناوين بحجم 64 كيلوبايت (64 × 2^ 10 )، بينما تحدد الإزاحة مدى بُعد العنوان المطلوب عن عنوان البداية. في عنونة التجزئة، يلزم وجود سجلين للحصول على عنوان ذاكرة كامل: أحدهما لتخزين المقطع، والآخر لتخزين الإزاحة. ولتحويل العنوان إلى عنوان مسطح، تُزاح قيمة المقطع أربع بتات إلى اليسار (ما يعادل الضرب في 2^ 4 أو 16)، ثم تُضاف إلى الإزاحة لتكوين العنوان الكامل، مما يسمح بتجاوز حاجز 64 كيلوبايت من خلال اختيار عناوين ذكية، على الرغم من أن ذلك يزيد من تعقيد البرمجة بشكل ملحوظ.

في الوضع الحقيقي /المحمي فقط، على سبيل المثال، إذا احتوى DS على الرقم الست عشري 0xDEAD واحتوى DX على الرقم 0xCAFE ، فإنهما يشيران معًا إلى عنوان الذاكرة . وبالتالي، يمكن لوحدة المعالجة المركزية عنونة ما يصل إلى 1,048,576 بايت (1 ميجابايت) في الوضع الحقيقي. ومن خلال دمج قيم القطاعات والإزاحات ، نحصل على عنوان مكون من 20 بت.0xDEAD * 0x10 + 0xCAFE == 0xEB5CE

كان جهاز IBM PC الأصلي يقيد البرامج بـ 640 كيلوبايت، ولكن تم استخدام مواصفات ذاكرة موسعة لتنفيذ مخطط تبديل البنوك الذي توقف استخدامه عندما استخدمت أنظمة التشغيل اللاحقة، مثل Windows، نطاقات العناوين الأكبر للمعالجات الأحدث ونفذت مخططات الذاكرة الافتراضية الخاصة بها.

استُخدم الوضع المحمي، بدءًا من معالج Intel 80286، في نظام التشغيل OS/2 . إلا أن العديد من أوجه القصور، مثل عدم إمكانية الوصول إلى نظام الإدخال والإخراج الأساسي (BIOS) وعدم إمكانية العودة إلى الوضع الحقيقي دون إعادة تشغيل المعالج، حالت دون انتشاره على نطاق واسع. [ 14 ] كما كان معالج 80286 لا يزال محدودًا بعنونة الذاكرة في مقاطع 16 بت، مما يعني إمكانية الوصول إلى 2 ^16 بايت (64 كيلوبايت ) فقط في المرة الواحدة. وللوصول إلى الوظائف الموسعة لمعالج 80286، كان نظام التشغيل يُفعّل الوضع المحمي، مما يُتيح عنونة 24 بت، وبالتالي الوصول إلى 2^ 24 بايت من الذاكرة (16 ميجابايت ).

في الوضع المحمي ، يمكن تقسيم محدد القطاع إلى ثلاثة أجزاء: فهرس 13 بت، وبت مؤشر الجدول الذي يحدد ما إذا كان الإدخال موجودًا في GDT أو LDT ، ومستوى الامتياز المطلوب 2 بت ؛ انظر تجزئة ذاكرة x86 .

عند الإشارة إلى عنوان يحتوي على مقطع وإزاحة، يتم استخدام تدوين المقطع:الإزاحة ، لذلك في المثال أعلاه يمكن كتابة العنوان المسطح 0xEB5CE على النحو التالي: 0xDEAD:0xCAFE أو كزوج من سجلات المقطع والإزاحة؛ DS:DX.

توجد بعض التركيبات الخاصة من سجلات القطاعات والسجلات العامة التي تشير إلى عناوين مهمة:

  • يشير CS:IP (CS هو مقطع التعليمات البرمجية ، و IP هو مؤشر التعليمات ) إلى العنوان الذي سيجلب منه المعالج البايت التالي من التعليمات البرمجية.
  • يشير SS:SP (SS هو مقطع المكدس ، SP هو مؤشر المكدس ) إلى عنوان أعلى المكدس، أي البايت الذي تم دفعه مؤخرًا.
  • يشير SS:BP (SS هو مقطع المكدس ، BP هو مؤشر إطار المكدس ) إلى عنوان أعلى إطار المكدس، أي قاعدة منطقة البيانات في مكدس الاستدعاءات للبرنامج الفرعي النشط حاليًا.
  • غالبًا ما يتم استخدام DS:SI (DS هو Data Segment ، SI هو Source Index ) للإشارة إلى بيانات السلسلة التي سيتم نسخها إلى ES:DI.
  • ES:DI (ES هو Extra Segment ، DI هو Destination Index ) يستخدم عادة للإشارة إلى وجهة نسخ السلسلة، كما ذكر أعلاه.

احتوى معالج إنتل 80386 على ثلاثة أوضاع تشغيل: الوضع الحقيقي، والوضع المحمي، والوضع الافتراضي. تم توسيع الوضع المحمي ، الذي ظهر لأول مرة في معالج 80286، ليسمح لمعالج 80386 بالوصول إلى ذاكرة تصل إلى 4 جيجابايت . أما الوضع الافتراضي الجديد كليًا 8086 ( VM86 )، فقد مكّن من تشغيل برنامج واحد أو أكثر من برامج الوضع الحقيقي في بيئة محمية تحاكي الوضع الحقيقي إلى حد كبير، على الرغم من أن بعض البرامج لم تكن متوافقة (عادةً نتيجة لحيل في عنونة الذاكرة أو استخدام رموز عمليات غير محددة).

قد يكون نموذج الذاكرة المسطحة 32 بت للوضع المحمي الممتد لمعالج 80386 هو أهم تغيير في الميزات لعائلة معالجات x86 حتى أصدرت AMD معالج x86-64 في عام 2003، حيث ساعد ذلك في دفع اعتماد واسع النطاق لنظام التشغيل Windows 3.1 (الذي اعتمد على الوضع المحمي) حيث أصبح بإمكان Windows الآن تشغيل العديد من التطبيقات في وقت واحد، بما في ذلك تطبيقات DOS، باستخدام الذاكرة الافتراضية وتعدد المهام البسيط.

أوضاع التنفيذ

تدعم معالجات x86 خمسة أنماط تشغيل لبرامج x86، وهي: النمط الحقيقي ، والنمط المحمي ، والنمط الطويل ، والنمط الافتراضي 86 ، ونمط إدارة النظام ، حيث تتوفر بعض التعليمات بينما لا تتوفر أخرى. تتوفر مجموعة فرعية من التعليمات ذات 16 بت على معالجات x86 ذات 16 بت، وهي 8086 و8088 و80186 و80188 و80286. هذه التعليمات متاحة في النمط الحقيقي على جميع معالجات x86، وفي النمط المحمي 16 بت (من 80286 فصاعدًا)، تتوفر تعليمات إضافية متعلقة بالنمط المحمي. في معالج 80386 والإصدارات الأحدث، تتوفر أيضًا تعليمات 32 بت (بما في ذلك الامتدادات اللاحقة) في جميع الأنماط، بما في ذلك النمط الحقيقي؛ على هذه المعالجات، يُضاف نمط V86 والنمط المحمي 32 بت، مع توفير تعليمات إضافية في هذه الأنماط لإدارة خصائصها. تتوفر تقنية إدارة الذاكرة المفردة (SMM)، مع بعض تعليماتها الخاصة، على بعض معالجات Intel i386SL وi486 والإصدارات الأحدث. وأخيرًا، في الوضع الطويل (بدءًا من AMD Opteron )، تتوفر أيضًا تعليمات 64 بت، بالإضافة إلى المزيد من المسجلات. تتشابه مجموعة التعليمات في كلا الوضعين، لكن عناوين الذاكرة وحجم الكلمات يختلفان، مما يستلزم استراتيجيات برمجة مختلفة.

الأوضاع التي يمكن من خلالها تنفيذ كود x86 هي:

  • الوضع الحقيقي (16 بت)
    • مساحة عناوين ذاكرة مجزأة 20 بت (مما يعني أنه لا يمكن الوصول إلا إلى 1 ميجابايت من الذاكرة - في الواقع، منذ معالج 80286، يمكن الوصول إلى مساحة أكبر قليلاً عبر HMA )، ووصول برمجي مباشر إلى الأجهزة الطرفية، وعدم وجود مفهوم لحماية الذاكرة أو تعدد المهام على مستوى الأجهزة. تبدأ أجهزة الكمبيوتر التي تستخدم BIOS بالعمل في هذا الوضع.
  • الوضع المحمي (16 بت و 32 بت)
  • الوضع الطويل (64 بت)
    • هي في الغالب امتداد لمجموعة تعليمات 32 بت (الوضع المحمي)، ولكن على عكس الانتقال من 16 إلى 32 بت، تم حذف العديد من التعليمات في وضع 64 بت. رائدة في هذا المجال شركة AMD .
  • وضع 8086 الافتراضي (16 بت)
    • وضع تشغيل هجين خاص يسمح بتشغيل برامج الوضع الحقيقي وأنظمة التشغيل أثناء خضوعها لسيطرة نظام تشغيل مشرف الوضع المحمي
  • وضع إدارة النظام (16 بت)

تبديل الأوضاع

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

أمثلة

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

مع جهاز كمبيوتر يعمل بنظام UEFI ، فإن البرامج الثابتة UEFI (باستثناء CSM و Option ROM القديمة)، ومحمل التمهيد UEFI، ونواة نظام التشغيل UEFI تعمل جميعها في الوضع الطويل.

أنواع التعليمات

بشكل عام، تتمثل سمات مجموعة تعليمات x86 الحديثة فيما يلي:

  • ترميز مضغوط
    • طول متغير ومحاذاة مستقلة (مشفرة كـ little endian ، كما هو الحال مع جميع البيانات في بنية x86)
    • بشكل أساسي تعليمات العنوان الواحد والعنوانين، أي أن المعامل الأول هو الوجهة أيضًا.
    • يتم دعم معاملات الذاكرة كمصدر ووجهة (يتم استخدامها بشكل متكرر لقراءة/كتابة عناصر المكدس التي يتم الوصول إليها باستخدام إزاحات فورية صغيرة).
    • استخدام السجلات العامة والضمنية ؛ على الرغم من أنه يمكن استخدام جميع ebpالسجلات العامة السبعة (بما في ذلك العد) في وضع 32 بت، وجميع السجلات العامة الخمسة عشر (بما في ذلك العد ) في وضع 64 بت، بحرية كمراكم أو للعنونة، إلا أن معظمها يستخدم ضمنيًا أيضًا بواسطة تعليمات خاصة معينة (بدرجات متفاوتة)؛ لذلك يجب الاحتفاظ بالسجلات المتأثرة مؤقتًا (عادةً ما يتم تكديسها)، إذا كانت نشطة أثناء تسلسلات التعليمات هذه.rbp
  • ينتج علامات شرطية ضمنيًا من خلال معظم تعليمات وحدة الحساب والمنطق للأعداد الصحيحة.
  • يدعم أوضاع عنونة متنوعة بما في ذلك الوضع الفوري، والإزاحة، والفهرس المقياس، ولكن ليس الوضع النسبي لعداد البرنامج، باستثناء القفزات (التي تم تقديمها كتحسين في بنية x86-64 ).
  • يتضمن ذلك حساب الفاصلة العائمة لمجموعة من السجلات.
  • يحتوي على دعم خاص لتعليمات القراءة والتعديل والكتابة الذرية ( xchg، cmpxchg/ cmpxchg8b، xaddو، وتعليمات الأعداد الصحيحة التي تتحد مع lockالبادئة)
  • تعليمات SIMD (تعليمات تقوم بتنفيذ تعليمات فردية متوازية ومتزامنة على العديد من المعاملات المشفرة في خلايا متجاورة من سجلات أوسع).

تعليمات التكديس

تدعم بنية x86 آلية مكدس التنفيذ على مستوى العتاد . تُستخدم تعليمات مثل push`size` popو` callsize` و`size` retمع المكدس المُهيأ بشكل صحيح لتمرير المعاملات، وتخصيص مساحة للبيانات المحلية، وحفظ نقاط العودة من الاستدعاء واستعادتها. تُعد تعليمة ret`size` مفيدة جدًا لتنفيذ اصطلاحات استدعاء فعالة من حيث المساحة (وسريعة)، حيث يكون المُستدعى مسؤولاً عن استعادة مساحة المكدس التي تشغلها المعاملات.

عند إعداد إطار مكدس لتخزين البيانات المحلية لإجراء تكراري ، تتوفر عدة خيارات؛ إذ enterتأخذ التعليمات عالية المستوى (التي ظهرت مع معالج 80186) وسيطًا لعمق تداخل الإجراء، بالإضافة إلى وسيط لحجم البيانات المحلية ، وقد تكون أسرع من المعالجة الصريحة للسجلات (مثل push bp ; mov bp, sp ; ). ويعتمد ما إذا كانت أسرع أو أبطأ على تنفيذ معالج x86 المحدد، بالإضافة إلى اصطلاح الاستدعاء الذي يستخدمه المترجم أو المبرمج أو رمز البرنامج المحدد؛ فمعظم أكواد x86 مصممة للتشغيل على معالجات x86 من عدة مصنعين وعلى أجيال تقنية مختلفة من المعالجات، مما يعني وجود اختلافات كبيرة في البنى الدقيقة وحلول التعليمات البرمجية الدقيقة، بالإضافة إلى اختلاف خيارات التصميم على مستوى البوابات والترانزستورات .sub sp, size

إن النطاق الكامل لأنماط العنونة (بما في ذلك العنونة الفورية والأساس + الإزاحة ) حتى بالنسبة للتعليمات مثل pushو pop، يجعل الاستخدام المباشر للمكدس لبيانات الأعداد الصحيحة والفاصلة العائمة وبيانات العناوين أمرًا بسيطًا، بالإضافة إلى الحفاظ على مواصفات وآليات ABI بسيطة نسبيًا مقارنة ببعض معمارية RISC (التي تتطلب تفاصيل أكثر وضوحًا لمكدس الاستدعاءات).

تعليمات وحدة الحساب والمنطق للأعداد الصحيحة

تحتوي لغة التجميع x86 على العمليات الحسابية القياسية، وهي: add، sub، ، neg، imulو idiv(للأعداد الصحيحة الموقعة)، مع mulو div(للأعداد الصحيحة غير الموقعة)؛ والمعاملات المنطقيةand : or، ، xor، not؛ وعمليات الإزاحة الثنائية ، والحسابية والمنطقية: sal/ sar(للأعداد الصحيحة الموقعة)، shl/ shr(للأعداد الصحيحة غير الموقعة)؛ والتدوير مع وبدون حمل: rcl/ rcr، rol/ ror، ومجموعة من تعليمات حساب BCDaaa : ، ، aad، daa. تقوم تعليمات مثل cmpو testبتعيين العلامات دون تغيير المعاملات.

تعليمات الفاصلة العائمة

تتضمن لغة التجميع x86 تعليمات لوحدة الفاصلة العائمة (FPU) القائمة على المكدس. كانت وحدة الفاصلة العائمة معالجًا مساعدًا اختياريًا منفصلاً للمعالجات من 8086 إلى 80386، وكانت خيارًا مدمجًا في سلسلة 80486، وهي ميزة قياسية في جميع معالجات Intel x86 منذ 80486، بدءًا من Pentium. تشمل تعليمات وحدة الفاصلة العائمة الجمع والطرح والنفي والضرب والقسمة والباقي والجذور التربيعية وتقريب الأعداد الصحيحة وتقريب الكسور والضرب في قوى العدد اثنين. كما تشمل العمليات تعليمات التحويل، التي يمكنها تحميل أو تخزين قيمة من الذاكرة بأي من التنسيقات التالية: النظام العشري المشفر ثنائيًا، أو عدد صحيح 32 بت، أو عدد صحيح 64 بت، أو عدد عشري 32 بت، أو عدد عشري 64 بت، أو عدد عشري 80 بت (عند التحميل، يتم تحويل القيمة إلى وضع الفاصلة العائمة المستخدم حاليًا). يتضمن x86 أيضًا عددًا من الدوال المتسامية ، بما في ذلك الجيب، وجيب التمام، والظل، وظل الزاوية، والأسس ذات الأساس 2 واللوغاريتمات ذات الأساس 2 أو 10 أو e .

عادةً ما يكون تنسيق تعليمات الجمع والطرح والضرب والقسمة والتخزين والمقارنة بين سجلات المكدس على النحو التالي: أو ، حيث يُعادل ، و هو أحد سجلات المكدس الثمانية ( , ، ، ..., ). وكما هو الحال مع الأعداد الصحيحة، فإن المعامل الأول هو معامل المصدر ومعامل الوجهة في آنٍ واحد. ويجب تمييز و لأنهما يقومان أولاً بتبديل معاملات المصدر قبل إجراء عملية الطرح أو القسمة. تتضمن تعليمات الجمع والطرح والضرب والقسمة والتخزين والمقارنة أنماط تعليمات تقوم بإزالة أعلى المكدس بعد اكتمال العملية. فعلى سبيل المثال، تُجري العملية الحسابية ، ثم تُزيل من أعلى المكدس، مما يجعل النتيجة الموجودة في أعلى المكدس هي .fop st, st(n)fop st(n), ststst(0)st(n)st(0)st(1)st(7)fsubrfdivrfaddp st(1), stst(1) = st(1) + st(0)st(0)st(1)st(0)

تعليمات SIMD

تحتوي وحدات المعالجة المركزية الحديثة x86 على تعليمات SIMD ، التي تُنفذ في الغالب نفس العملية بالتوازي على العديد من القيم المُخزنة في سجل SIMD واسع. تدعم تقنيات التعليمات المختلفة عمليات متنوعة على مجموعات سجلات مختلفة، ولكن عند النظر إليها ككل (من MMX إلى SSE4.2 )، فإنها تشمل عمليات حسابية عامة على الأعداد الصحيحة أو الأعداد العشرية (الجمع، الطرح، الضرب، الإزاحة، التصغير، التكبير، المقارنة، القسمة، أو الجذر التربيعي). على سبيل المثال، paddw mm0, mm1تُنفذ أربع عمليات wجمع متوازية للأعداد الصحيحة (يُشار إليها بـ padd) من mm0القيم إلى ، mm1وتُخزن النتيجة في mm0. تتضمن امتدادات SIMD المتدفقة أو SSE أيضًا وضعًا للأعداد العشرية حيث يتم تعديل القيمة الأولى فقط من السجلات (مُوسع في SSE2 ). أُضيفت بعض التعليمات غير المألوفة الأخرى، بما في ذلك مجموع الفروق المطلقة (المستخدمة لتقدير الحركة في ضغط الفيديو ، كما هو الحال في MPEG ) وتعليمات الضرب والتجميع ذات 16 بت (المفيدة لمزج ألفا البرمجي والترشيح الرقمي ). تتضمن امتدادات SSE (منذ SSE3 ) و 3DNow! تعليمات الجمع والطرح للتعامل مع قيم الفاصلة العائمة المزدوجة كأعداد مركبة.

تتضمن مجموعات التعليمات هذه أيضًا العديد من تعليمات الكلمات الفرعية الثابتة لخلط القيم وإدراجها واستخراجها داخل المسجلات. بالإضافة إلى ذلك، توجد تعليمات لنقل البيانات بين مسجلات الأعداد الصحيحة ومسجلات XMM (المستخدمة في SSE)/FPU (المستخدمة في MMX).

تعليمات الذاكرة

يتضمن معالج x86 أيضًا أنماط عنونة معقدة لعنونة الذاكرة باستخدام إزاحة فورية، أو سجل، أو سجل مع إزاحة، أو سجل مُقاس مع أو بدون إزاحة، أو سجل مع إزاحة اختيارية وسجل مُقاس آخر. على سبيل المثال، يمكن ترميز mov eax, [Table + ebx + esi*4]تعليمة واحدة لتحميل 32 بت من البيانات من العنوان المحسوب (Table + ebx + esi * 4)كإزاحة من dsالمُحدِّد، وتخزينها في eaxالسجل. بشكل عام، يمكن لمعالجات x86 تحميل واستخدام ذاكرة تتناسب مع حجم أي سجل تعمل عليه. (تتضمن تعليمات SIMD أيضًا تعليمات التحميل الجزئي).

تستخدم معظم تعليمات x86 ذات المعاملين، بما في ذلك تعليمات وحدة الحساب والمنطق للأعداد الصحيحة، بايتًا قياسيًا لنمط العنونة [ 15 ] يُسمى غالبًا بايت MOD-REG-R/M . [ 16 ] [ 17 ] [ 18 ] كما تحتوي العديد من تعليمات x86 ذات 32 بت على بايت نمط عنونة SIB يلي بايت MOD-REG-R/M. [ 19 ] [ 20 ] [ 21 ] [ 22 ] [ 23 ]

من حيث المبدأ، ولأن رمز العملية (opcode) منفصل عن بايت نمط العنونة، فإن هذه التعليمات متعامدة ، إذ يمكن دمج أي من هذه الرموز مع أي نمط عنونة. مع ذلك، تُعتبر مجموعة تعليمات x86 عمومًا غير متعامدة، لأن معظم العمليات الثنائية لا يمكنها العمل من ذاكرة إلى ذاكرة، ولأن بعض الرموز لها نمط عنونة ثابت (لا يوجد لها بايت نمط عنونة)، ولكل مسجل استخدام مفضل. [ 23 ] [ 24 ]

تتضمن مجموعة تعليمات x86 تعليمات تحميل وتخزين ونقل ومسح ومقارنة السلاسل النصية ( ) lods، stosو، movsو، scasو cmps) التي تُنفذ كل عملية منها بحجم مُحدد ( b8 بت للبايت، wو16 بت للكلمة، dو32 بت للكلمة المزدوجة)، ثم تُزيد/تُنقص (بحسب علامة الاتجاه DF) مُسجل العنوان الضمني ( siلـ lods، diو stosو scas، وكلاهما لـ movsو cmps). بالنسبة لعمليات التحميل والتخزين والمسح، يكون مُسجل الهدف/المصدر/المقارنة الضمني في al، axأو eaxالمُسجل (بحسب الحجم). مُسجلات القطاعات الضمنية المُستخدمة هي dsو siلـ . يُستخدم المُسجل أو كعداد مُتناقص، وتتوقف العملية عندما يصل العداد إلى الصفر es، أو، بالنسبة لعمليات المسح والمقارنة، عند اكتشاف المساواة أو عدم المساواة. لسوء الحظ، أُهمل أداء بعض هذه التعليمات على مر السنين، وفي بعض الحالات، يُمكن الحصول على نتائج أسرع باستخدام تعليمات أبسط. مع ذلك، قامت شركتا إنتل وإيه إم دي بتحديث بعض هذه التعليمات، واعتبارًا من عام 2025dicxecxبعضها يتمتع بأداء محترم للغاية.

المكدس عبارة عن منطقة في الذاكرة ومؤشر مكدس مرتبط بها ، يشير إلى آخر عنصر تم إضافته إلى المكدس. يتم إنقاص قيمة مؤشر المكدس قبل إضافة العناصر، pushوزيادتها بعد إزالتها pop. في وضع 16 بت، يُشار إلى مؤشر المكدس الضمني هذا بالرمز SS:[SP]، وفي وضع 32 بت بالرمز SS:[ESP]، وفي وضع 64 بت بالرمز [RSP]. يشير مؤشر المكدس إلى آخر قيمة تم تخزينها، بافتراض أن حجمه يتطابق مع وضع تشغيل المعالج (أي 16 أو 32 أو 64 بت) ليتوافق مع العرض الافتراضي لتعليمات push/ pop/ call/ ret. تتضمن هذه التعليمات أيضًا تعليمات enterأخرى leaveلحجز البيانات وإزالتها من أعلى المكدس مع إعداد مؤشر إطار المكدس في bp/ ebp/ rbp. ومع ذلك، فإن التعيين المباشر، أو الجمع والطرح من سجل sp/ esp/ rspمدعوم أيضًا، لذا فإن تعليمات enter/ leaveغير ضرورية بشكل عام.

هذا الكود هو بداية دالة نموذجية للغة عالية المستوى عندما يتم إيقاف تشغيل تحسين المُصرّف لتسهيل عملية تصحيح الأخطاء:

push rbp ; حفظ مؤشر إطار مكدس الدالة المستدعِية (سجل rbp) mov rbp , rsp ; إنشاء إطار مكدس جديد أسفل مكدس الدالة المستدعِية sub rsp , 32 ; حجز 32 بايت من مساحة المكدس للمتغيرات المحلية لهذه الدالة. ; ستكون المتغيرات المحلية أسفل rbp ويمكن الإشارة إليها بالنسبة إلى rbp، ; وهذا أفضل لتسهيل عملية تصحيح الأخطاء، ولكن للحصول على أفضل أداء، لن يتم استخدام rbp على الإطلاق، وسيتم الإشارة إلى المتغيرات المحلية بالنسبة إلى rsp ، ; لأنه، بصرف النظر عن حفظ الكود، يصبح rbp متاحًا للاستخدامات الأخرى. ; ومع ذلك، إذا تم تغيير rbp هنا، فيجب الاحتفاظ بقيمته للدالة المستدعِية. mov [ rbp - 8 ], rdx ; مثال على الكتابة إلى متغير محلي (بحسب موقعه في الذاكرة) من السجل rdx

...يعادل وظيفيًا ما يلي:

أدخل 32 ، 0

تتضمن التعليمات الأخرى لمعالجة المكدس pushfd(32 بت) / pushfq(64 بت) popfd/popfqولتخزين واسترجاع سجل EFLAGS (32 بت) / RFLAGS (64 بت).

تُفترض قيم عمليات التحميل أو التخزين في SIMD مُرتبة في مواقع متجاورة في سجل SIMD، ويتم محاذاتها بترتيب تسلسلي صغير النهاية. تتطلب بعض تعليمات التحميل والتخزين في SSE محاذاة 16 بايت لتعمل بشكل صحيح. تتضمن مجموعات تعليمات SIMD أيضًا تعليمات "الجلب المسبق" التي تُنفذ عملية التحميل دون استهداف أي سجل، وتُستخدم لتحميل البيانات من الذاكرة المؤقتة. كما تتضمن مجموعات تعليمات SSE تعليمات تخزين غير مؤقتة تُنفذ عمليات التخزين مباشرةً في الذاكرة دون تخصيص ذاكرة مؤقتة إذا لم تكن الوجهة مُخزنة مؤقتًا بالفعل (وإلا ستعمل كعملية تخزين عادية).

تستطيع معظم تعليمات الأعداد الصحيحة والعشرية العامة (باستثناء تعليمات SIMD) استخدام مُعامل واحد كعنوان مُركب كمُعامل مصدر ثانٍ. كما تستطيع تعليمات الأعداد الصحيحة قبول مُعامل ذاكرة واحد كمُعامل وجهة.

تدفق البرنامج

تحتوي لغة التجميع x86 على عملية قفز غير مشروطة، jmpوالتي يمكن أن تأخذ عنوانًا فوريًا أو سجلًا أو عنوانًا غير مباشر كمعامل (لاحظ أن معظم معالجات RISC تدعم فقط سجل الارتباط أو الإزاحة الفورية القصيرة للقفز).

يدعم النظام أيضًا العديد من عمليات القفز الشرطية، بما في ذلك jzالقفز عند الصفر، jnzوالقفز عند قيمة غير صفرية، jgوالقفز عند أكبر من (مُوَقَّع)، jlوالقفز عند أصغر من (مُوَقَّع)، jaوالقفز عند أكبر من/أعلى من (غير مُوَقَّع)، jbوالقفز عند أصغر من/أسفل من (غير مُوَقَّع). تعتمد هذه العمليات الشرطية على حالة بتات مُحدَّدة في سجل (E)FLAGS . تقوم العديد من العمليات الحسابية والمنطقية بتعيين هذه العلامات أو مسحها أو عكسها بناءً على نتائجها. تقوم تعليمات المقارنة cmp(compare) testبتعيين العلامات كما لو كانت قد أجرت عملية طرح أو عملية AND منطقية، على التوالي، دون تغيير قيم المعاملات. توجد أيضًا تعليمات مثل clcمسح علامة الحمل وعكس cmcعلامة الحمل التي تعمل على العلامات مباشرةً. تُجرى مقارنات الأعداد العشرية عبر تعليمات fcomor ficomالتي يجب تحويلها في النهاية إلى علامات أعداد صحيحة.

لكل عملية قفز ثلاثة أشكال مختلفة، بحسب حجم المعامل. يستخدم القفز القصير معاملًا مُوَقَّعًا من 8 بت، وهو إزاحة نسبية من التعليمات الحالية. يشبه القفز القريب القفز القصير، لكنه يستخدم معاملًا مُوَقَّعًا من 16 بت (في الوضع الحقيقي أو المحمي) أو معاملًا مُوَقَّعًا من 32 بت (في الوضع المحمي 32 بت فقط). أما القفز البعيد ، فيستخدم قيمة قاعدة المقطع الكاملة: الإزاحة كعنوان مطلق. يوجد أيضًا شكلان غير مباشر ومفهرس لكل من هذه العمليات.

بالإضافة إلى عمليات القفز البسيطة، توجد تعليمات callاستدعاء روتين فرعي retوالعودة منه. قبل نقل التحكم إلى الروتين الفرعي، callتُدفع قيمة الإزاحة للتعليمة التالية callإلى المكدس، ثم retتُسحب هذه القيمة من المكدس، ويُقفز إليها، مما يُعيد التحكم إلى ذلك الجزء من البرنامج. في حالة استدعاء far callروتين فرعي، تُدفع قيمة الإزاحة إلى المكدس، far retثم تُسحب قيمة الإزاحة، ثم ...

توجد أيضًا تعليمتان متشابهتان، الأولى int( interrupt )، التي تحفظ قيمة سجل (E)FLAGS الحالية في المكدس، ثم تُنفذ عملية أخرى ، إلا أنها تستخدم متجه مقاطعةfar call بدلاً من عنوان، وهو فهرس في جدول عناوين معالجات المقاطعات. عادةً، يحفظ معالج المقاطعة جميع سجلات وحدة المعالجة المركزية الأخرى التي يستخدمها، ما لم تُستخدم لإعادة نتيجة عملية إلى البرنامج المُستدعي (تُسمى في البرمجيات بالمقاطعات). تعليمة الإرجاع المطابقة من تعليمة المقاطعة هي (return) ، التي تُعيد العلامات بعد الإرجاع. تُستخدم المقاطعات البرمجية من النوع الموصوف أعلاه بواسطة بعض أنظمة التشغيل لاستدعاءات النظام ، ويمكن استخدامها أيضًا في تصحيح أخطاء معالجات المقاطعات الصلبة. تُفعّل المقاطعات الصلبة بواسطة أحداث أجهزة خارجية، ويجب أن تحافظ على جميع قيم السجلات لأن حالة البرنامج قيد التنفيذ غير معروفة. في الوضع المحمي، قد يُهيئ نظام التشغيل المقاطعات لتفعيل تبديل المهام، مما سيؤدي تلقائيًا إلى حفظ جميع سجلات المهمة النشطة.iret

أمثلة

تستخدم الأمثلة التالية ما يُعرف بصيغة Intel، كما هو مستخدم في مُجمّعات Microsoft MASM وNASM وغيرها الكثير. (ملاحظة: توجد أيضًا صيغة AT&T بديلة حيث يتم تبديل ترتيب معاملات المصدر والوجهة، بالإضافة إلى العديد من الاختلافات الأخرى.) [ 25 ]

برنامج "مرحباً بالعالم!" بدون نظام تشغيل

يمكن إخراج عبارة "Hello, world!" بسهولة من نظام التشغيل. يستدعي الأمر "Call outchr" آليةً ما لطباعة حرف بلغة AL على وحدة التحكم. يجب إنهاء أي سلسلة نصية غير صفرية ببايت قيمته صفر. لاحظ أن هذا المثال خاص بمعالج Intel 8086 ذي 16 بت.

hello: mov si , msg ; عنوان السلسلة في SI cld ; مسح اتجاه زيادة SI lodsb ; تحميل الحرف الأول في AL، وزيادة SI chrlp: call outchr ; طباعة الحرف في AL lodsb ; تحميل الحرف التالي في AL، وزيادة SI or al , al ; هل هو حرف إنهاء السلسلة؟ jnz chrlp ; إذا لم يكن كذلك، فتابع ret ; العودة إلى المُستدعيmsg: db 'Hello, world!' , 0xa , 0x0 ; سلسلة نصية للطباعة

برنامج "مرحباً بالعالم!" لنظام التشغيل MS-DOS مكتوب بلغة التجميع MASM

باستخدام تعليمة المقاطعة البرمجية 21h لاستدعاء نظام التشغيل MS-DOS لعرض المخرجات على الشاشة  ، تستخدم أمثلة أخرى روتين printf() الخاص بلغة C من مكتبة libc للكتابة إلى stdout . لاحظ أن هذا المثال يستخدم وضع 16 بت كما هو الحال في معالج Intel 8086. المثال التالي هو كود Intel 386 في وضع 32 بت. أما الأكواد الحديثة فستكون في وضع 64 بت. [ 26 ]

.model small .stack 100h.data msg db 'Hello world!$'بداية الكود : mov ah , 09h ; يُعيّن هذا الأمر قيمة البايت الأعلى من السجل ax، وهو سجل 8 بت، إلى 9. يُحدد هذا الأمر رقم وظيفة فرعية لروتين MS-DOS يتم استدعاؤه أدناه . يتم ذلك عبر مقاطعة البرنامج int 21h لعرض رسالة . يأخذ هذا الأمر عنوان الرسالة msg ويخزنه في السجل dx ذي 16 بت. يمكن استدعاء العديد من إجراءات MS-DOS بواسطة مقاطعة البرنامج 21h . تم تعيين الوظيفة الفرعية المطلوبة في السجل ah أعلاه.mov ax , 4C00h ; يُعيّن هذا الأمر قيمة السجل ax إلى رقم الوظيفة الفرعية لبرنامج MS-DOS . المقاطعة int 21h لخدمة "إنهاء البرنامج". int 21h ; لا تُعيد هذه الخدمة أي قيمة، لأنها تُنهي البرنامج.نهاية البداية

برنامج "مرحباً بالعالم!" لنظام التشغيل ويندوز بلغة التجميع MASM و NASM

! MASMالأكاديمية الوطنية للطب الرياضيوصف
يتطلب مفتاح /coff في الإصدار 6.15 والإصدارات الأقدم . .386 .model small , c .stack 1000h
; قاعدة الصورة = 0x00400000 %define RVA(x) (x-0x00400000)
مقدمة. يتطلب MASM تحديد نموذج العنوان وحجم المكدس.
.data msg db "مرحباً بالعالم!" ، 0
section .data msg db "Hello world!"
قسم البيانات. نستخدم العملية الزائفة db (تعريف البايت) لتعريف سلسلة نصية.
.code includelib libcmt.lib includelib libvcruntime.lib includelib libucrt.lib includelib legacy_stdio_definitions.libextrn printf : قريب extrn exit : قريبpublic main main proc push offset msg call printf push 0 call exit main endp end
section.text push dword msg call dword [ printf ] push byte + 0 call dword [ exit ] retsection .idata dd RVA ( msvcrt_LookupTable ) dd - 1 dd 0 dd RVA ( msvcrt_string ) dd RVA ( msvcrt_imports ) times 5 dd 0 ; ينهي جدول الواصفاتmsvcrt_string dd "msvcrt.dll" , 0 msvcrt_LookupTable: dd RVA ( msvcrt_printf ) dd RVA ( msvcrt_exit ) dd 0msvcrt_imports: printf dd RVA ( msvcrt_printf ) exit dd RVA ( msvcrt_exit ) dd 0msvcrt_printf: dw 1 dw "printf" , 0msvcrt_exit: dw 2 dw "exit" , 0 dd 0
الكود (قسم .text) وجدول الاستيراد. في NASM، يتم إنشاء جدول الاستيراد يدويًا، بينما في MASM، تُستخدم توجيهات المثال لتبسيط العملية.

برنامج "Hello world!" لنظام لينكس بلغة التجميع AT&T وNASM

AT&T (GNU as)إنتل (NASM)وصف
.بيانات
القسم .البيانات
كما هو الحال في مثال ويندوز، .dataهذا هو قسم البيانات المهيأة.
str: .ascii "Hello, world!\n"
str: db 'Hello world!' , 0Ah
عرّف سلسلة نصية تحتوي على "Hello, world!" ثم سطر جديد ( \n, وهو 0x0A). اربط التسمية "str" ​​بعنوان السلسلة النصية المعرّفة.
طول_السلسلة = . - السلسلة
str_len: equ $ - str
احسب طول السلسلة str. .تعني كلمة "هنا" في لغة gas، $وتعني الشيء نفسه في لغة nasm. بطرح "str" ​​من "هنا"، نحصل على طول السلسلة المحددة سابقًا.
.نص
نص القسم
كما هو الحال في مثال ويندوز، .textهذا هو قسم كود البرنامج.
.globl _start
global _start
قم بتصدير الدالة _start إلى النطاق العام لكي يتمكن الرابط من رؤيتها.
_يبدأ:
_يبدأ:
عرّف تسمية باسم _start، سنكتب عليها روتيننا الفرعي. الاسم _start، وفقًا لاتفاقية لينكس، يحدد نقطة الدخول.
movl $4 , %eax movl $1 , %ebx movl $str , %ecx movl $str_len , %edx
mov eax ، 4 mov ebx ، 1 mov ecx ، str mov edx ، str_len
قم بإعداد استدعاء نظام. EAX=4 يطلب استدعاء "sys_write" على نظام Linux x86. EBX=1 يعني "stdout" لـ sys_write. يحتوي ECX على السلسلة المراد كتابتها، بينما يحتوي EDX على عدد البايتات المراد كتابتها. هذا مكافئ للإصدار المُغلّف بـ libc write(1, str, str_len).
int $0x80
int 80h
في x86، يتم استخدام مقاطعة النظام "80h" لاستدعاء استدعاء النظام وفقًا لقيم eax و ebx و ecx و edx.
movl $1 , %eax movl $0 , %ebx int $0x80
mov eax , 1 mov ebx , 0 int 80h
قم بتحميل استدعاء نظام آخر، ثم استدعه باستخدام INT 80h: EAX=1 تعني sys_exit، وEBX تعني sys_exit وتحمل قيمة الإرجاع. قيمة الإرجاع 0 تعني خروجًا عاديًا. في صيغة لغة C، _exit(0);.

ملاحظة للأكاديمية الوطنية للطب الرياضي (NASM):

يعمل هذا البرنامج في وضع الحماية 32 بت. البناء: nasm -f elf -F stabs name.asm الربط: ld -o name name.o في وضع 64 بت الطويل، يمكنك استخدام سجلات 64 بت (مثل rax بدلاً من eax، وrbx بدلاً من ebx، إلخ) . غيّر أيضًا "-f elf" إلى "-f elf64" في أمر البناء. في وضع 64 بت الطويل، سيكون "lea rcx, str" هو عنوان الرسالة، لاحظ أن سجل rcx هو سجل 64 بت.

برنامج "مرحباً بالعالم!" لنظام لينكس مكتوب بلغة التجميع بنمط NASM باستخدام مكتبة C القياسية

يعمل هذا البرنامج في وضع الحماية 32 بت. يقوم gcc بربط مكتبة لغة C القياسية افتراضيًا .; build: nasm -f elf -F stabs name.asm ; link: gcc -o name name.o ; ; في وضع 64 بت الطويل، يمكنك استخدام سجلات 64 بت (مثل rax بدلاً من eax، وrbx بدلاً من ebx، إلخ..) ; غيّر أيضًا "-f elf " إلى "-f elf64" في أمر build. ; global main ; يجب تعريف 'main'، لأنه يتم تجميعه ; مقابل مكتبة C القياسية extern printf ; يُعلن عن استخدام رمز خارجي، حيث أن printf ; مُعلن عنه في وحدة كائن مختلفة. ; يقوم الرابط بحل هذا الرمز لاحقًا.segment .data ; قسم لسلسلة البيانات المُهيأة db 'Hello world!' , 0Ah , 0 ; سلسلة الرسالة التي تنتهي بحرف سطر جديد (10 ; عشري) وحرف إنهاء البايت الصفري 'NUL' ; تشير 'string' الآن إلى عنوان البداية ; حيث يتم تخزين 'Hello, World'.segment.text main: push string ; دفع عنوان 'string' إلى المكدس. ; هذا يقلل حجم esp بمقدار 4 بايت قبل تخزين ; عنوان 'string' المكون من 4 بايت في الذاكرة عند ; esp الجديد، أسفل المكدس الجديد. ; سيكون هذا وسيطًا للدالة printf()استدعاء دالة printf ؛ يستدعي دالة printf() في لغة C. إضافة esp ، 4 ؛ يزيد مؤشر المكدس بمقدار 4 لإعادته ؛ إلى موضعه قبل عملية الدفع، التي ؛ قلّصته بمقدار 4 بايت. إرجاع ؛ العودة إلى الدالة المستدعِية.

بما أننا نستخدم بيئة تشغيل لغة C، فإننا نُعرّف دالة main() كما تتوقعها بيئة تشغيل لغة C. وبدلاً من استدعاء دالة exit، نعود ببساطة من دالة main() ليقوم وقت التشغيل بتنفيذ عملية التنظيف.

برنامج "مرحباً بالعالم!" لنظام لينكس 64 بت مكتوب بلغة التجميع بنمط NASM

هذا المثال يعمل بنظام 64 بت الحديث.

; بناء: nasm -f elf64 -F dwarf hello.asm ; ربط: ld -o hello hello.oDEFAULT REL ; استخدم أوضاع العنونة النسبية لـ RIP بشكل افتراضي، لذا [foo] = [rel foo]القسم .rodata ؛ يجب وضع البيانات للقراءة فقط في قسم .rodata على نظام GNU/Linux، كما هو الحال مع .rdata على نظام Windows. Hello: db "Hello world!" , 10 ؛ ينتهي بالبايت 10 = سطر جديد (ASCII LF). len_Hello: equ $ - Hello ؛ اجعل NASM يحسب الطول كثابت وقت التجميع ؛ يرمز الرمز '$' إلى 'هنا'. تأخذ الدالة write() طولًا، لذا ؛ لا حاجة لسلسلة نصية منتهية بصفر على نمط لغة C.؛ سيكون ذلك ضروريًا للغة C. puts()القسم .نصglobal _start _start: mov eax , 1 ; __NR_write رقم استدعاء النظام من Linux asm/unistd_64.h (x86_64) mov edi , 1 ; int fd = STDOUT_FILENO lea rsi , [ rel Hello ] ; يستخدم x86-64 LEA النسبي لـ RIP لوضع العناوين الثابتة في السجلات mov rdx , len_Hello ; size_t count = len_Hello syscall ; write(1, Hello, len_Hello); استدعاء في النواة لتنفيذ استدعاء النظام فعليًا ;; القيمة المرجعة في RAX. يتم أيضًا استبدال RCX وR11 بواسطة استدعاء النظامmov eax , 60 ; يتم تخزين رقم استدعاء __NR_exit (x86_64) في المسجل eax. xor edi , edi ; هذا يُصفّر edi وrdi أيضًا. تُعدّ حيلة xor-self هذه الطريقة الشائعة والمفضلة لتصفير المسجل، وهي دائمًا الأسرع. عند تخزين قيمة 32 بت في edx مثلاً، يتم تصفير البتات العليا 63:32 تلقائيًا في جميع الحالات. هذا يوفر عليك عناء تعيين البتات بتعليمات إضافية، حيث إن هذه حالة شائعة جدًا ، لملء مسجل 64 بت بالكامل بقيمة 32 بت. هذا يُعيّن حالة خروج روتيننا = 0 (خروج طبيعي) syscall ; _exit(0)

يُتيح تشغيل البرنامج straceالتحقق من عدم إجراء أي استدعاءات نظام إضافية أثناء العملية. سيُجري إصدار printf استدعاءات نظام أكثر بكثير لتهيئة مكتبة libc وإجراء الربط الديناميكي . لكن هذا ملف تنفيذي ثابت لأننا ربطنا باستخدام ld بدون -pie أو أي مكتبات مشتركة؛ التعليمات الوحيدة التي تُنفذ في مساحة المستخدم هي تلك التي تُقدمها أنت.

$ strace ./hello > /dev/null # بدون إعادة توجيه، يتم خلط مخرجات برنامجك القياسية مع سجلات strace على الخطأ القياسي. وهذا أمر طبيعي عادةً. execve("./hello", ["./hello"], 0x7ffc8b0b3570 /* 51 متغيرًا */) = 0 write(1, "Hello world!\n", 13) = 13 exit(0) = ? +++ تم الخروج بنجاح (0) +++

استخدام سجل العلامات

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

cmp eax , ebx jne do_something ; ... do_something: ; نفّذ شيئًا هنا

إلى جانب تعليمات المقارنة، توجد العديد من التعليمات الحسابية وغيرها التي تُفعّل بتات في سجل العلامات. ومن الأمثلة الأخرى تعليمات الطرح والاختبار والجمع، وغيرها الكثير. تُدمج التركيبات الشائعة، مثل المقارنة مع القفزة الشرطية، داخليًا ( دمج الماكرو ) في تعليمة دقيقة واحدة ، وتكون سريعة شريطة أن يتمكن المعالج من تحديد اتجاه القفزة الشرطية، سواءً كانت قفزة أو استمرار.

تُستخدم سجلات العلامات أيضًا في بنية x86 لتفعيل وإيقاف بعض الميزات أو أوضاع التنفيذ. على سبيل المثال، لتعطيل جميع المقاطعات القابلة للإخفاء، يمكنك استخدام التعليمة التالية:

cli

يمكن الوصول مباشرةً إلى سجل الأعلام. ويمكن تحميل البتات الثمانية الأدنى من سجل الأعلام باستخدام ahالتعليمة lahf. كما يمكن نقل سجل الأعلام بالكامل من وإلى المكدس باستخدام التعليمات pushfd/pushfq( بما في ذلك ) و .popfd/popfqintintoiret

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

باستخدام سجل مؤشر التعليمات

يُستدعى مؤشر التعليماتip في وضع 16 بت، eipووضع 32 بت، ripووضع 64 بت. يشير سجل مؤشر التعليمات إلى عنوان التعليمات التالية التي سيحاول المعالج تنفيذها. لا يمكن الوصول إليه مباشرةً في وضع 16 بت أو 32 بت، ولكن يمكن كتابة تسلسل مثل التالي لوضع العنوان next_lineفي eax(كود 32 بت):

استدعاء next_line next_line: pop eax

الكتابة إلى مؤشر التعليمات أمر بسيط  - jmpتقوم التعليمات بتخزين عنوان الهدف المحدد في مؤشر التعليمات، لذلك، على سبيل المثال، سيضع تسلسل مثل التالي محتويات raxفي rip(رمز 64 بت):

jmp rax

في وضع 64 بت، يمكن للتعليمات الإشارة إلى البيانات بالنسبة لمؤشر التعليمات، لذلك تقل الحاجة إلى نسخ قيمة مؤشر التعليمات إلى سجل آخر.

انظر أيضاً

مراجع

  1. "عائلة معالجات Intel 8008 (i8008) الدقيقة" . www.cpu-world.com . مؤرشف من الأصل بتاريخ 17 أبريل 2021. تم الاطلاع عليه بتاريخ 25 مارس 2021 .
  2. "إنتل 8008" . متحف وحدة المعالجة المركزية - متحف المعالجات الدقيقة وتصوير الرقائق . مؤرشف من الأصل بتاريخ 1 أبريل 2021. تم الاطلاع عليه بتاريخ 25 مارس 2021 .
  3. 1 2 3 "خريطة رمز العملية 8086" . موطن المليلتر . مؤرشف من الأصل بتاريخ 23 يناير 2026. تم الاطلاع عليه بتاريخ 22 ديسمبر 2025 .
  4. 1 2 3 4 5 نارايام، رام (17 أكتوبر 2007). "مجمعات لينكس: مقارنة بين GAS وNASM" . آي بي إم . مؤرشف من الأصل في 3 أكتوبر 2013. تم الاطلاع عليه في 2 يوليو 2008 .
  5. "نشأة نظام يونكس" . مؤرشف من الأصل في 2 أبريل 2014.
  6. هايد، راندال. "أي مُجمِّع هو الأفضل؟" . مؤرشف من الأصل بتاريخ 18-10-2007 . تم الاطلاع عليه بتاريخ 18-05-2008 .
  7. "أخبار مُجمِّع جنو، الإصدار 2.1 يدعم صيغة إنتل" . 2008-04-04 . تم الاطلاع عليه بتاريخ 2008-07-02 .
  8. "أخطاء i386 (استخدام as)" . وثائق Binutils . مؤرشف من الأصل في 15 يناير 2020. تم الاطلاع عليه في 15 يناير 2020 .
  9. "دليل برمجة لغة التجميع لمعالج إنتل 8080" (ملف PDF) . مؤرشف من النسخة الأصلية (ملف PDF) بتاريخ 12 مايو 2023. تم الاطلاع عليه بتاريخ 12 مايو 2023 .
  10. "NASM - The Netwide Assembler" . www.nasm.us. مؤرشف من الأصل بتاريخ 14 أغسطس 2025. تم الاطلاع عليه بتاريخ 9 مايو 2025 .
  11. "البيانات (باستخدام as)" . sourceware.org . مؤرشف من الأصل بتاريخ 10-05-2025 . تم الاطلاع عليه بتاريخ 09-05-2025 .
  12. "عمليات زائفة (باستخدام as) :: توجيهات المُجمِّع" . sourceware.org . مؤرشف من الأصل بتاريخ 17-05-2025 . تم الاطلاع عليه بتاريخ 09-05-2025 . 
  13. "توجيهات المُجمِّع - دليل مرجعي للغة التجميع x86" . docs.oracle.com . مؤرشف من الأصل بتاريخ 14 أغسطس 2025. تم الاطلاع عليه بتاريخ 9 مايو 2025 .
  14. مولر، سكوت (24 مارس 2006). "معالجات الجيل الثاني P2 (286)" . ترقية وإصلاح أجهزة الكمبيوتر الشخصية، الطبعة السابعة عشرة (كتاب) (الطبعة 17 ). Que. ISBN  0-7897-3404-4تم الاطلاع عليه بتاريخ 2017-12-06 .
  15. كورتيس ميدو. "ترميز تعليمات 8086" مؤرشف بتاريخ 2022-07-06 في آلة Wayback .
  16. إيغور خولودوف. "6. ترميز معاملات تعليمات x86، بايت MOD-REG-R/M" مؤرشف في 2022-03-31 في Wayback Machine .
  17. "ترميز تعليمات x86" مؤرشف بتاريخ 2022-03-31 في Wayback Machine .
  18. مايكل أبرش. "مبادئ لغة التجميع: المجلد الأول، المعرفة". "الفصل 7: عنونة الذاكرة". قسم "عنونة mod-reg-rm". مؤرشف بتاريخ 4 مارس 2022 في أرشيف الإنترنت (Wayback Machine) .
  19. دليل مبرمج Intel 80386 المرجعي. "17.2.1 بايتات ModR/M وSIB" مؤرشف بتاريخ 20 ديسمبر 2021 في Wayback Machine
  20. ""ترميز تعليمات X86-64: بايتات ModR/M و SIB"تمت أرشفة هذا النص من المصدر الأصلي بتاريخ 4 مارس 2022. تم الاطلاع عليه بتاريخ 4 مارس 2022 .
  21. "الشكل 2-1. تنسيق تعليمات معمارية Intel 64 و IA-32" مؤرشف في 2022-03-04 في Wayback Machine .
  22. "معالجة عناوين x86 من الداخل" مؤرشف بتاريخ 2022-03-04 في Wayback Machine .
  23. 1 2 ستيفن ماكامانت. "الهندسة العكسية الثنائية اليدوية والآلية" مؤرشفة في 2022-03-04 في Wayback Machine .
  24. "قائمة أمنيات تعليمات X86" مؤرشفة بتاريخ 2022-03-04 في Wayback Machine .
  25. بيتر كوردس (18 ديسمبر 2011). "NASM (إنتل) مقابل AT&T Syntax: ما هي المزايا؟" . ستاك أوفرفلو . مؤرشف من الأصل في 13 فبراير 2023. تم الاطلاع عليه في 13 فبراير 2023 .
  26. "لقد بدأتُ للتو بتعلم لغة التجميع" . daniweb.com . 2008. مؤرشف من الأصل بتاريخ 29-01-2019 . تم الاطلاع عليه بتاريخ 29-01-2019 .

للمزيد من القراءة

كتيبات

الكتب