اللازانيا

اللازانيا

تمرين تعلّمي

مقدمة

الأساسيات

التعليقات

يستخدم مسار x86-64 في Exercism المُجمِّع NASM (The Netwide Assembler). في NASM، تُسبق التعليقات بفاصلة منقوطة (;).

يمكن وضع التعليقات في أي مكان في البرنامج، وكل ما يأتي بعد ; يتجاهله المُجمِّع.

الثوابت

يمكن تعريف ثابت زمن التجميع في NASM باستخدام equ. على سبيل المثال، هذا يعرّف ثابتًا اسمه UNIVERSE وقيمته 42:

UNIVERSE equ 42

تُقيَّم الثوابت مرة واحدة عند تعريفها، ولا يمكن إعادة تعريفها لاحقًا.

السجلات العامة (GPRs)

في لغة التجميع، نستخدم السجلات عادةً لتخزين القيم بدلًا من المتغيرات. سجل المعالج هو قطعة ذاكرة سريعة داخل معالج الحاسوب. وتُجرى معظم العمليات الحسابية في سجلات المعالج.

تُستخدم بعض السجلات في مجموعة متنوعة من العمليات المختلفة وتُسمى السجلات العامة (GPRs). ولسجلات أخرى أغراض خاصة أو مخصصة.

في x86-64، هناك 16 سجلًا عامًا (GPR) بعرض 64 بت، ويمكن الوصول إليها أيضًا بعرض 32 بت أو 16 بت أو 8 بت. تُوصف السجلات العامة أدناه، حيث يتراوح n في rn من 8 إلى 15: r8 وr9 وr10 وr11 وr12 وr13 وr14 وr15.

64-bit 32-bit 16-bit 8-bit
rax eax ax ah/al
rbx ebx bx bh/bl
rcx ecx cx ch/cl
rdx edx dx dh/dl
rsi esi si sil
rdi edi di dil
rbp ebp bp bpl
rsp esp sp spl
rn rnd rnw rnb

عند استخدام أقل من 64 بت، تكون البتات التي يتم الوصول إليها عادةً من الجزء السفلي من السجل. والاستثناء من هذه القاعدة هو ah وbh وch وdh، فهي تصل إلى البتات الثمانية العليا من الجزء المكوّن من 16 بت في السجل.

توضيح لكيفية الوصول إلى البتات في سجل rax:

+--------+---------------------------------------+
| 64-bit |                  rax                  |
+--------+-------------------+-------------------+
| 32-bit |                   |        eax        |
+--------+-------------------+---------+---------+
| 16-bit |                             |    ax   |
+--------+-----------------------------+----+----+
| 8-bit  |                             | ah | al |
+--------+-----------------------------+----+----+

يجب الحفاظ على بعض هذه السجلات عبر استدعاءات الدوال: rbp وrsp وrbx وr12 وr13 وr14 وr15. وقد يؤدي عدم الحفاظ عليها إلى حدوث خطأ أو إلى سلوك غير معرّف.

أما السجلات الأخرى فلا يُحافظ عليها ويمكن استخدامها بحرية: rax وrcx وrdx وrdi وrsi وr8 وr9 وr10 وr11.

Caution

لاحقًا في المنهج الدراسي، ستتعلم كيفية الحفاظ على السجلات. في الوقت الحالي، استخدم فقط النوع الثاني من السجلات: rax وrcx وrdx وrdi وrsi وr8 وr9 وr10 وr11.

التعليمات

التعليمات هي أجزاء من العمليات الحسابية التي يستطيع المعالج تنفيذها. وعادةً ما تكون بالشكل التالي:

name destination, source

إذن، يوضع اسم التعليمة أولًا، ثم مسافة بيضاء واحدة على الأقل، يليها المعامل الوجهة، ثم فاصلة (,)، وأخيرًا المعامل المصدر. ولا يُعدَّل المعامل المصدر عادةً بواسطة التعليمة، بل المعامل الوجهة فقط.

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

على سبيل المثال، لتخزين قيمة في سجل، يمكننا استخدام التعليمة mov:

mov rax, rdx  ; rax = rdx
              ; mov is the name, rax is the destination operand and rdx is the source operand

ينسخ المقطع أعلاه محتوى البتات الـ64 كلها من rdx، وهو المعامل المصدر، إلى البتات الـ64 كلها من rax، وهو المعامل الوجهة للتعليمة.

من الممكن استخدام أعداد صحيحة ثابتة كمعاملات مصدر (وليس كمعاملات وجهة) في معظم التعليمات:

mov rcx, 42 ; rcx = 42
            ; rcx is the destination operand and 42 is the source operand

لاحظ أن الكتابة إلى سجل بعرض 32 بت تمسح البتات العليا أيضًا، لذا فإن mov eax, 42 مكافئة لـ mov rax, 42. وهذا لا ينطبق على السجلات بعرض 16 بت و8 بت.

بالنسبة للعمليات الحسابية: الجمع والطرح والضرب، يمكننا استخدام التعليمات add وsub وimul:

add rax, rsi ; rax = rax + rsi
imul rax, rdi ; rax = rax * rdi
sub rax, r8 ; rax = rax - r8

الدوال

تُنظَّم التعليمات في دوال. وتوضع جميع الدوال في section .text من ملف المصدر.

يتكوّن تعريف الدالة من:

  1. تسمية باسم الدالة، تليها :.
  2. التعليمات التي تعرّف الدالة.
  3. تعليمة الإرجاع، ret.

يستخدم هذا المسار اتفاقية الاستدعاء System V AMD64 ABI، وتُمرَّر أول ست وسائط صحيحة إلى الدالة في السجلات. وتُمرَّر بالترتيب التالي: rdi وrsi وrdx وrcx وr8 وr9.

وتُرجَع القيمة الصحيحة من الدالة في السجل rax.

لاستدعاء دالة، نستخدم التعليمة call. ويمكن استدعاء الدالة من أي مكان في ملف المصدر نفسه. ولجعل الدالة مرئية لملفات مصدر أخرى، يجب استخدام التوجيه global.

على سبيل المثال، هذا يعرّف دالة sum:

section .text ; functions are placed here

global sum ; sum is visible to other source files

sum:
    ; first argument is passed in rdi
    ; second argument is passed in rsi
    ; return value is placed in rax

    mov rax, rdi ; rax is now equal to rdi
    add rax, rsi ; rax = rax + rsi

    ret ; function return

وهذا يستدعي دالة sum بالوسيطين 3 و5:

mov rdi, 3  ; First argument in rdi
mov rsi, 5  ; Second argument in rsi
call sum

; The rax register now contains the value 8 (3 + 5), after sum returns

التعليمات

في هذا التمرين ستكتب بعض الكود لمساعدتك على طهي لازانيا رائعة من كتاب الطبخ المفضل لديك.

لديك أربع مهام، وكلها تتعلق بالوقت المستغرق في طهي اللازانيا.

Note

هذه هي التعليمات المذكورة في هذا المفهوم:

التعليمة الوصف
mov a, b تنسخ المحتوى من b إلى a
add a, b a = a + b
sub a, b a = a - b
imul a, b a = a * b
call a تستدعي الدالة a
ret تعود من الدالة

1. حدّد زمن الفرن المتوقع بالدقائق

عرّف الدالة expected_minutes_in_oven التي لا تأخذ أي معاملات وتُرجع عدد الدقائق التي ينبغي أن تبقى فيها اللازانيا في الفرن. وفقًا لكتاب الطبخ، فإن زمن الفرن المتوقع بالدقائق هو 40:

expected_minutes_in_oven();
// => 40

2. احسب زمن الفرن المتبقي بالدقائق

عرّف الدالة remaining_minutes_in_oven التي تأخذ عدد الدقائق الفعلية التي قضتها اللازانيا في الفرن كمعامل وتُرجع عدد الدقائق التي لا يزال يتعين على اللازانيا أن تبقى فيها في الفرن، بناءً على زمن الفرن المتوقع بالدقائق من المهمة السابقة.

remaining_minutes_in_oven(30);
// => 10

3. احسب زمن التحضير بالدقائق

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

preparation_time_in_minutes(2);
// => 4

4. احسب الزمن المنقضي بالدقائق

عرّف الدالة elapsed_time_in_minutes التي تأخذ معاملين، بهذا الترتيب:

  1. عدد الطبقات التي أضفتها إلى اللازانيا.
  2. عدد الدقائق التي قضتها اللازانيا في الفرن.

ينبغي أن تُرجع الدالة عدد الدقائق التي عملتها في طهي اللازانيا. وهذا هو مجموع زمن التحضير بالدقائق، والزمن بالدقائق الذي قضته اللازانيا في الفرن في تلك اللحظة.

elapsed_time_in_minutes(3, 20);
// => 26
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
x86-64 Assembly Exercism

مستعد لبدء اللازانيا؟

سجّل في Exercism لتتعلّم وتتقن x86-64 Assembly عبر 22 مفهومًا130 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.