P01NT
0x2 03/08

بنية مجموعة التعليمات (ISA)

مدخل إلى بنية مجموعة التعليمات ISA: خصائص تعليمات الآلة وصيغتها وطولها في x86، أنواع المعاملات، أنواع البيانات من Byte إلى QuadWord، وأنواع العمليات الحسابية والمنطقية ونقل البيانات والتحكم.

· 5 دقائق قراءة · 913 كلمة
المحتويات

بسم الله الرحمن الرحيم.

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

بنية مجموعة التعليمات (Instruction Set Architecture)

بنية مجموعة التعليمات (ISA) هي الأساس النظري الذي يربط بين الـ Machine Code والتعليمات التي ينفذها الـ CPU:

طبقات التجريد: البرمجيات فوق الـ ISA والعتاد تحته شكل (1): موقع الـ ISA بين البرمجيات والعتاد

وتحدد بنية ISA: التعليمات المدعومة من المعالج، وأنواع البيانات (Data Types)، والسجلات (Registers)، وطريقة الوصول إلى الذاكرة (Memory Access)، ونماذج العنونة (Addressing Modes)، وغيرها من التفاصيل الأساسية.

بمعنى آخر: الـ ISA هي لغة التواصل بين البرمجيات Software والعتاد Hardware — دون الدخول في التفاصيل الدقيقة للتصميم الداخلي (Microarchitecture).

خصائص تعليمات الآلة (Machine Instruction Characteristics)

تتكوّن تعليمة الآلة من جزأين:

• رمز العملية (Opcode): الذي يحدد نوع الإجراء المراد تنفيذه، أي الأمر نفسه (مثل mov، add… إلخ).

• المعاملات (Operands): التي تشير إلى البيانات المستهدفة التي سيطرأ عليها الإجراء. وتخزن كل تعليمة في الذاكرة كسلسلة من البايتات.

معلومات أساسية

صيغة التعليمة وطولها: كما ذكرنا، تتكون كل تعليمة من Opcode وOperands، وفي معمارية x86 يختلف طول التعليمات من 1 إلى 15 بايتاً.

عدد المعاملات: تسمح تعليمات x86 بوجود صفر إلى ثلاثة معاملات، ومعظم Opcodes ذات معاملين: المصدر (Source) والوجهة (Destination). وفي صيغة Intel تأتي الوجهة أولاً ثم المصدر. على سبيل المثال:

mov  eax, ebx

تحتوي على معاملين: المسجل eax وهو الوجهة (Destination) التي ستستقبل القيمة، والمسجل ebx وهو المصدر (Source) الذي ستُقرأ منه القيمة.

ترتيب البايتات (Endianness): تستخدم معمارية x86 الترتيب الصغير (Little Endian)، أي أن البايت الأقل أهمية يخزن أولاً في الذاكرة؛ فالقيمة 0x12345678 تخزن في الذاكرة بالترتيب: 78 56 34 12.

مثال:

mov  eax, [a]     ; نقل قيمة المتغير a إلى المسجل EAX
add  eax, [b]     ; أصبحت قيمة a في EAX فأضفنا إليها قيمة المتغير b
mov  [sum], eax   ; نقل القيمة الناتجة من EAX إلى المتغير sum

أنواع المعاملات (Types of Operands)

المعامل في الـ Machine Code هو ما يشير إلى البيانات الجاري معالجتها، ويمكن أن يكون أحد الأنواع التالية:

1. قيمة ثابتة (Immediate): قيمة عددية مباشرة مضمنة في التعليمة نفسها. مثل:

mov  ebx, 5       ; نقل العدد الثابت 5 إلى المسجل EBX

2. مسجل (Register): قد يكون المعامل مسجلاً من وحدة المعالجة. مثل:

mov  eax, ebx     ; نقل محتوى السجل EBX إلى السجل EAX

3. موقع في الذاكرة (Memory Address): قد يكون المعامل عنواناً في الذاكرة. مثل:

mov  eax, [ebx]   ; نقل القيمة المخزنة في العنوان المحفوظ في EBX إلى EAX

مثال جامع:

mov  eax, [a]     ; هنا a (ذاكرة) و eax (مسجل)
add  eax, [b]     ; b (ذاكرة)
mov  [sum], eax   ; sum (ذاكرة)

أنواع البيانات في معمارية x86 (x86 Data Types)

يدعم معالج x86 أنواعاً مختلفة من البيانات، أهمها:

  • Byte: الوحدة الأساسية للبيانات، وتساوي 8 بتات.
  • Word: 16 بتاً.
  • DoubleWord: 32 بتاً.
  • QuadWord: 64 بتاً.

مثال: لنفرض أن لدينا هذا الكود بلغة C:

char c = 'A';
short s = 1000;
int i = 100000;

فهذه هي طريقة التعامل مع أحجامها في Assembly:

mov  al, 'A'       ; المسجل AL هو قسم من AX بحجم 8 بتات
mov  ax, 1000      ; المسجل AX هو نصف المسجل EAX بحجم 16 بتاً
mov  eax, 100000   ; المسجل EAX كاملاً بحجم 32 بتاً

أنواع العمليات (Types of Operations)

بشكل عام هناك عمليات رئيسية يتألف منها أي كود تقريباً — يمكن القول إن 90% من أي برنامج يتكون من هذه الـ Opcodes:

• العمليات الحسابية والمنطقية (Arithmetic & Logic): وتشمل تعليمات الجمع add والطرح sub والضرب mul والقسمة div، والعمليات المنطقية not وand وor وxor. تستخدم هذه التعليمات لتعديل القيم في المسجلات أو الذاكرة.

• نقل البيانات (Data Transfer): تعليمات لنقل البيانات بين المسجلات والذاكرة أو المداخل والمخارج. أشهرها أمر mov الذي ينقل قيمة من المصدر (مسجل أو ذاكرة أو قيمة ثابتة) إلى الوجهة (مسجل أو ذاكرة). ولدينا أيضاً push وpop أوامر التعديل على الستاك.

• التحكم بمسار التنفيذ (Control Flow): تعليمات التحكم بسير البرنامج: القفز غير المشروط jmp، والقفز المشروط بناءً على مقارنة مثل cmp مع je/jne/jle… إلخ، بالإضافة إلى تعليمات استدعاء الدوال call وret. وتعتمد هذه التعليمات على مقارنة القيم وتغيير قيمة مؤشر التعليمات (Instruction Pointer).

• الإدخال والإخراج (I/O): في x86 توجد تعليمات خاصة للتعامل مع أجهزة الدخل والخرج مثل in وout، وهي تسمح بالقراءة والكتابة إلى المنافذ (Ports) الخاصة بالأجهزة.

مثال: لنفرض أن لدينا هذا الكود بلغة C:

int a = 10, b = 3, c;                 // تعريف المتغيرات a وb وc
if (a > b) c = a - b; else c = 0;     // إذا كان a أكبر من b فإن c = a - b، وإلا فإن c = 0

فهذا تمثيله في Assembly:

mov  eax, [a]
cmp  eax, [b]      ; مقارنة a مع b
jle  L_else        ; إذا كانت a <= b انتقل إلى فرع else
sub  eax, [b]      ; وإلا نفّذ: a = a - b
mov  [c], eax
jmp  L_end         ; تجاوز فرع else بعد إتمام الفرع الشرطي
L_else:
mov  dword [c], 0  ; حالة else: c = 0
L_end:

لاحظ كيف تحول شرط if إلى تعليمة cmp تضبط الأعلام، ثم قفزة مشروطة jle تفحص هذه الأعلام: إذا لم يتحقق الشرط (أي a <= b) يقفز التنفيذ إلى فرع else، وإذا تحقق يستمر تنفيذ الطرح ثم يقفز فوق فرع else بتعليمة jmp غير مشروطة.

الخلاصة

من خلال فهمك لبنية مجموعة التعليمات (ISA) — ومعرفة أن تعليمة الآلة تتكون من Opcode وOperands وأنواع كلٍّ منهما — تصبح قادراً على ترجمة الكود الثنائي إلى Assembly وفهم كيف يسير البرنامج خطوة بخطوة.

لا تنسونا من صالح دعائكم.