الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

البدء بكتابة أول برنامج بالاسمبلي

مغلق
بدأه Xacker في 11 نوفمبر 2005 · 10 رد · 13,442 مشاهدة · في المواضيع المميزة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

اعتذر عن التاخر الواضح في طرح هذا المقال حيث انشغلت مؤخرا بامور كثيرة جدا جدا نحن في غنى عن اضاعة الوقت لذكرها.

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

المعاملات الفورية:

ما هي المعاملات الفورية؟ هي عبارة عن بيانات لا نقوم بتعريفها بشكل مسبق في بنية البرنامج وبالتحديد في مقطع البيانات .data وانما نقوم باستخدامها بشكل مباشر في البرنامج لغرض معين لا نحتاجها فيه لاحقا.

مثال على هذا النوع من المعاملات الشكل التالي في نقل احدى القيم الى احد المسجلات:

mov      ax, 0123h

حيث يتم تحميل الثابت الفوري 123 الست عشري في المسجل AX؟ تمثل التعليمة السابقة بشفرة الهدف على النحو B8321, حيث B8 هي شفرة تعليمة MOV اما البايتان التاليان فيمثلان القيمة الفورية نفسها لكن بشكل معكوس والسبب موضح في مقالات سابقة.

اذن نلاحظ في حالة المعاملات الفورية اننا لسنا بحاجة الى تعريفها في مقطع المعطيات لاننا لا نحتاج الى استخدامها اكثر من مرة واحدة مثلا, اما في حال كنا بحاجة الى استخدامها بشكل مطترد فانه يفضل ان نقوم بتعريف هذه المعطيات في مقطع المعطيات بالشكل المناسب, كما في الحالة التالية:

immediate      dw   0123h
....
mov            ax, immediate

طول المعاملات الفورية:

بشكل بديهي يجب الا يتجاوز طول المعاملات الفورية طول المعامل الهدفي destinition, اي لا يجوز لنا ان نقوم بمحاولة اسناد قيمة بطول 32بت الى مسجل بطول 16بت مثلا, وكما في مثالنا السابق, لا يجوز لنا ان نقوم بمحاولة اسناد القيمة 0123h الست عشرية الى مسجل AL لان الاخير بطول 8بت اي انه لن يتسع لاكثر من رقمين ست عشريين.

هذا الامر بالطبع معاكس في حال اردنا ان نسند قيمة بطول اقصر من طول المعامل الهدف اليه, اي انه يمكننا ان نقوم بمحاولة اسناد قيمة بطول 8بت الى مسجل بطول 16بت مثلا دون الحاجة الى القلق من ظهور اي خطا.

انماط العنونة:

العنونة باستخدام المسجلات:

تعتبر معالجة المعطيات بين المسجلات اسرع انواع المعالجة لعدم استخدام الذاكرة, وفيما يلي امثلة على هذا النمط من العنونة:

mov      cl, ah
add      ax, bx

العنونة الفورية Immediate Addressing:

يحتوي المعامل الثاني (المعامل المصدري source operand) قيمة ثابتة في نمط العنونة الفورية, في حين يحتوي المعامل الاول (الهدفي destinition operand) على احد المسجلات او مواقع الذاكرة, وفيما يلي بعض الامثلة:

save      db ?
....
add       cx, 12
mov       save, 25
mov       bx, OFFSET save

حيث تقوم التعليمة الاخيرة بتهيئة عنوان الازاحة الخاص بعنصر المعطيات save في المسجل bx تحضيرا لاستخدامه فيما بعد, وكما هو معروف فان رقم الازاحة يدل على عنوان التعليمة المطلوبة ابتداء من عنوان مقطع الشفرة code section وبالتالي لنصل اليها فيما بعد يكفي ان نقوم بتحميل عنوان مقطع الشفرة في احد المسجلات وليكن SI ونقوم باستخدام الشكل [sI+BX] مثلا.. سيتم توضيحها فيما يلي تحت العنونة الدليلية.

العنونة المباشرة للذاكرة Direct Memory Addressing:

ينشا هذا النمط من العنونة باستخدام احد المعاملين لموقع ذاكرة واستخدام الاخر لاحد المسجلات, امثلة:

word1      dw 0
byte1      db 0
....
mov        ax, word1
add        byte1, cl

العنونة الدليلية Indexed Addressing:

تعتبر العنونة الدليلية تقنية اكثر تعقيدا توفر امكانية اكبر في القدرة على العنونة باستخدام قيمة مسجل المقطع وقيمة الازاحة. يستخدم المعالجان 86 و 286 لهذا الغرض المسجلات BX, SI, DI, BP على ان توضع اسماؤها ضمن قوسين مربعين تمييزا لعملية العنونة الدليلية.

ترتبط المسجلات BX, DI, SI مع مسجل مقطع المعطيات DS, في حين يرتبط المسجل BP مع مسجل مقطع المكدس SS.

يمكن ان يحتوي معامل التعليمة على عنوان دليلي وسيحتوي عندئذ المعامل الاخر على قيمة فورية او مسجل ما, ويقصد بالعنوان الدليلي عنوانا مثل [bX] الذي يخبر المجمع باستخدام عنوان ذاكرة توجد قيمته في المسجل BX.

تهيئ التعليمة MOV في المثال التالي المسجل BX بعنوان ازاحة عنصر المعطيات DATAFLD في حين تهيئ تعليمة MOV الثانية موقع الذاكرة المشار اليه DATAFLD بالقيمة 0 باستخدام عنوانه الدليلي الموجود في المسجل BX:

DATAFLD      db ?
....
mov          bx, OFFSET DATAFLD
mov          [bx], 0

وعمليا فان التعليمتين السابقتين لهما نفس تاثير التعليمة MOV DATAFLD, 0.

يسمح هذا النمط من العنونة بربط مجموعة من المسجلات لتشكيل عنوان دليلي, وهذا ما يجعل النمط الدليلي في العنونة مفيدا كثيرا كما في المثالين التاليين:

[BX+SI]; تمثل عنوانا يساوي حاصل جمع قيم المسجلين SI و BX
[BX+2]; تمثل عنوانا يساوي حاصل جمع قيمة المسجل BX مع الرقم 2

العنونة الدليلية في المعالجين 486/386:

يسمح المعالجان 486/386 بتوليد عنوان دليلي ينشا عن اجتماع احد المسجلات العامة على الاقل مع قيمة ازاحة وعامل مقياس scaling factor (وهو احد القيم 1, 2, 3, 4) فالتعليمة التالية على سبيل المثال:

mov      ebx, [ecx*2+esp+4]

تنقل محتويات العنوان المشار اليه بقية ECX المضروبة بالعدد 2 والمضاف اليها القيمة المخزنة في المسجل ESP مضافا اليه الرقم 4.

سنتابع بعد قليل

تم تعديل هذه المشاركة بواسطة Xacker في 12 نوفمبر 2005 في 05:50

1

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#2

مرحباااااااااااااااااااااااااا كيف الحال شباب

و الله المراجعة حلوة مرة مرة ممتاز ياريت تستمر اصلى بدور على كدة حاجات قوية من الاول

1
خطاء برمجى+مبرمج php+معرفة كاملة بى my sql+كتابة استمار صحيح===؟؟؟؟؟؟؟؟ اكتشاف ثغرة جديدة ؟؟؟؟؟؟؟
#3

والله انا الكلام النظري مش كتير استوعبته بس الاكواد فهمتها ...

كل الشكر للاستاذ xacker على دروسه الرائعة...وبانتظار عودتك بعد الفاصل!!!

#4

نتابع ما بدأناه:

اذن في هذا الدرس سنقوم بكتابة اول برنامج اسمبلي لنا, كنت اناقش الاخ احمد بهذا الموضوع وارتاينا ان نقوم بتوضيح كيفية كتابة التطبيق الذي سنتناوله اليوم ببيئتي 16bit و 32bit لكن قبل ان نبدا دعونا في البداية ناخذ بعض المعلومات الضرورية حول ما سنواجهه اثناء كتابة التطبيق تحت بيئة 16بت..

ماذا يعني ان نقوم بكتابة التطبيق تحت بيئة 16بت؟

تفرض علينا بيئة 16بت بعض الامور التي قد يجدها البعض لا تصب في صالح المبرمج حيث ان هناك بعض التعقيدات في الاستخدام نتيجة عدم توازن هذه البيئة تحت مختلف انظمة التشغيل المستخدمة.

سنقوم فيما يخص بيئتي البرمجة باستخدام برنامجي masm16 وتجدونه في المرفقات و masm32 ويمكن الحصول عليه من موقع www.masm32.com لكني ساقوم باستخدام برنامج masm32 المعدّل من قبل Hutch ويمكن الحصول عليه من موقع Iczelion http://win32asm.cjb.net.

اذن ماذا نحتاج الى معرفته قبل البدء؟

يولّد برنامج الربط Linker بشكل آلي تصميما خاصا للبرنامج exe ويخزن قبله مباشرة على القرص ويسمى هذا التصميم بكتلة الترويسة او header block التي يتالف طولها من 512 بايت كحد ادنى. نستطيع توليد برامج تنفيذية من نوع اخر اصغر حجما من برامج exe وتعتبر اكثر مرونة كبرامج مقيمة في الذاكرة resident programs ولعل اهم مثال على هذه البرامج هو برنامج command.com.

الاختلاف بين برامج EXE و COM:

تتمثل الاختلافات بين برامج exe و com في عدة امور منها:

- الحجم: لا يوجد لبرنامج exe حد اقصى لحجمه, في حين يقتصر برنامج com على مقطع segment واحد يبلغ حجمه كحد اقصى 64k بما فيها منطقة بادئة مقطع البرامج PSP حيث تشكل الاخيرة كتلة مؤلفة من 256 بايت يضعها نظام التشغيل قبل البرنامج EXE او COM عندما يقوم بتحميله الى الذاكرة. يعتبر برنامج com دوما اصغر من نظيره واحد الاسباب هو وجود كتلة مقدمة برنامج exe ذات الحجم 512 بايت على الاقل والتي تقع قبل البرنامج مباشرة على القرص المخزن فيه في حين لا تتواجد هذه الكتلة في برامج com عند تخزينها على القرص. ووما يجدر به الذكر هو ان برنامج COM المخزن على القرص يعتبر صورة طبق الاصل عن نفسه عند تحميله الى الذاكرة, خلافا للبرنامج exe الذي لا تعرف شفرته الا عند تحميله الى الذاكرة.

- المقاطع: يجب على البرمج ان يقوم بتعريف مقطع المكدس في برامج exe في حين ان برامج com تولد بشكل الي مكدس البرنامج وهذا هو سبب اهمال تعرييف المكدس عند كتابة برنامج باللغة التجميعية بغرض تحويله فيما بعد الى com -- يحتاج برنامج exe عادة الى تعريف مقطع منفصل للمعطيات وتهيئة المسجل DS في البداية بعنوان بدايته في حين ان برنامج com يعرف معطياته ضمن مقطع التعليمات -- يتالف كامل برنامج com من مقطع تعليمات واحد يبلغ حجمه كحد اقصى 64k بما فيها PSP والمكدس والمعطيات.

- التهيئة: يهيئ نظام التشغيل كافة مسجلات المقاطع بعنوان بداية منطقة بادئة مقطع البرنامج PSP عند تحميل البرنامج com الى الذاكرة بغية تنفيذه. اذ ان المنطقة PSP التي طولها 100 بايت تقع قبل البرنامج مباشرة. ولما كانت معطيات برنامج com وتعليماته غير منفصلة وتقع بعد PSP مباشرة فانه لا داع لتحميل المسجلين DS و CS بقيم جديدة وعوضا عن ذلك يكفي اضافة القيمة 100h لعناوين ازاحة المعطيات والتعليمات لعنونتها بالشكل السليم او جعل الحسابات تبدا بالعنونة ابتداء من 100h في برامج com (هذا هو سبب استخدامنا للامر org 100h في بداية برامج com والذي يعني origin 100h).

البدء بكتابة اول برنامج اسمبلي:

قد يجد البعض البرنامج الذي سنقوم بكتابته بسيطا لكن الغاية من هذه البرامج البسيطة في البداية هو التعريف باهم التعليمات التي سنقوم باستخدامها فيما بعد لذا وجب التنبيه.

برنامجنا الذي سنقوم بكتابته سيقوم بتنفيذ العمليات الحسابية الاربعة على قيم عددية (معطيات) ثابتة ولتكن على الشكل التالي:

A=15 / B=37 / C=3 / D=22

حيث سنقوم بتطبيق بعض العمليات الحسابية الموضحة ضمن شفرة البرنامج, وهي التالية:

.model small  ; selects a model type for memory (small is more than enough)
.code
    org    100h    ; starts addressing @ 100h
    jmp    main    ; jump past data
; in here you see that we include the data we need inside the .code section of the app
; and we simply use a jmp command to pass them avoiding errors
A    db    15
B    db    37
C    db    3
D    db    22
    main    PROC    near
    ; let's first try to add a number to another, say B to A
  mov    al, A; copy the content of 'A' into register AL
  add    al, B; now add the value stored in 'B' to the value copied to AL
;---------------
    ; now let's try to subtract some number from another, say A from B
  mov    ah, B; copy the contents of 'B' into AL
  sub    ah, A; now subtract 'A' from 'B' and keep the results in AH
;---------------
    ; this is quite simple & gr8 :) -- let's play with AL & AH abit..
    ; we will now multiply the value of AL with the value of AH and store
    ; the results in AL
  mul    ah
    ; now let's divide the value of AX by the value of AL and store the 
    ; results in AX
  div    al
    main    endp
end main

ناتي الان الى شرح الكود السابق, في البداية دعونا نتعرف على تعريف MOV وما تقوم به.

- MOV:

تنقل (تنسخ) هذه التعليمة المعطيات بين مسجلين اثنين او بين الذاكرة والمسجل, كما تنقل المعطيات الفورية immediate الى الذاكرة او المسجل. تحدد المعطيات المستخدمة عدد البايتات المرسلة (بايت, كلمة, كلمة مضاعفة) على ان يتفق معامل المصدر مع معامل الهدف في الحجم (اي لا يمكن ان نقوم مثلا بنقل كلمة الى مسجل بطول حرف!).

لا تستطيع MOV نقل المعطيات بين موقعي ذاكرة مباشرة (mov A, B) (سنقوم لحل هذه المشكلة باستخدام MOVS وسياتي شرحها لاحقا), او نقل قيمة فورية الى احد مسجلات المقاطع (mov cs, 15), او نقل مسجل مقطع الى مسجل مقطع اخر (mov cs, ds).

بالتالي نرى ان استخدامات MOV واشكالها محصورة بالخيارات التالية:

MOV    (reg/mem), (reg,mem,immediate)
;-------------------------------------
MOV    imm, imm    ; << ×
MOV    seg_reg, imm    ; << ×
MOV    seg_reg, seg_reg; << ×

وهذه بعض الامثلة على استخدام تعليمة MOV:

.model    small
.code
    org    100h
    jmp    main
;-- DATA GOES HERE
aByte    db    15  ; decimal byte
aWord    dw    F015h  ; hexa word
aDword    dd    456FD690h    ; hexa dword
uData    db    ?  ; uninitilized byte
;-- ENDS HERE
    main    proc    near
  mov    ax, aWord; mov  reg, mem
  mov    bx, ax    ; mov    reg, reg
  mov    uData, bl; mov    mem, reg
  mov    bl, 07h    ; mov    reg, imm
  mov    aDword, 0h; mov    mem, imm << replaces least significant byte with 00h
    main    endp
end main

لكن ماذا بشان نقل القيم بين مواقع الذاكرة مباشرة؟

- MOVS:

تمثل هذه التعليمة اختصارا للتعبير MOVe String حيث تنقل (تنسخ) هذه التعليمة المعطيات بين مواقع الذاكرة وتستخدم عادة مع التعليمة REP على ان يوضع طول سلسلة المعطيات المنقولة في CX (باعتبار انه العداد الافتراضي). تاخذ هذه التعليمة العديد من الاشكال منها MOVSB / MOVSW / MOVSD حيث كما يظهر واضحا تقوم الاولى بنقل سلسلة من البايتات اما الثانية الكلمات والاخيرة تقوم بنقل الكلمات المضاعفة مباشرة.

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

.data
arr	   db	 "dynamic bytes array just for example",0
arr_len  dw	$-arr

حينها سيحمل المتغير arr_len طول السلسلة arr المشار إليها مع الـ terminating null فلا تنسى هذا.

وطريقة أخرى

.data
arr		 db	"dynamic bytes array just for example",0
arrend:

mov   cx,offset (arrend-arr)

كلا الطريقتين صحيحتين، في الطريقة الثانية يتم حساب الطول داخل البرنامج بشكل ديناميكي بينما في الطريقة الأولى يتم حفظ الطول داخل البرنامج لكن حسابه يتم من قبل المجمع بشكل تلقائي أثناء ربط وتجميع البرنامج.

يشير زوج المسجلات DS:SI الى عنوان بداية السلسلة المراد نقل معطياتها وزوج المسجلات ES:DI الى مكان توضع المعطيات المنقولة. تنقل التعليمة المعطيات من اليسار الى اليمين وذلك بزيادة SI و DI في كل مرة بقيمة 1 للبايت, 2 للكلمات, 4 للكلمات المضاعفة, وذلك اذا كانت قيمة الراية DF تساوي 0. اما اذا كانت قيمة الراية السابقة تساوي 1 فان التعليمة تقوم بنقل المعطيات من اليمين الى اليسار بانقاص SI و DI بنفس القيم في كل مرة. تقوم تعليمة REP بانقاص قيمة CX بمقدار 1 لدى كل تكرار وينتهي التنفيذ عندما تصل القيمة الى الصفر علما انه في هذه الحالة وعند وصول CX الى الصفر فان كلا من SI و DI سيشير الى عنصر المعطيات الواقع بعد نهاية السلسلة مباشرة.

الان وبعد ان ادركنا طريقة استخدام تعليمة MOV ننتقل الى التعليمات الخاصة بالعمليات الحسابية ADD / SUB / MUL / DIV.

فيما يخص تعليمتي الجمع والطرح لا يوجد اي اشكال بالنسبة لهما لكن هناك بعض الاختلاف البسيط فيما يخص تعليمتي الضرب والقسمة وسنناقش كل شئ في اوانه.

- ADD:

تضيف هذه التعليمة القيم الموجودة على شكل معامل فوري او في مسجل او احد مواقع الذاكرة الى مسجل ما, او قيما موجودة في مسجل او على شكل معامل فوري الى احد مواقع الذاكرة. حيث ان القيم تكون بطول بايت او كلمة او كلمة مضاعفة. بالتالي نصل الى اشكال التعليمة ADD بالصورة التالية:

ADD    (reg/mem), (reg/mem/imm)

وهذه بعض الامثلة على الاستخدام:

.model    small
.code
    org    100h
    jmp    main
aByte    db    15  ; decimal byte
aWord    dw    F015h  ; hexa word
aDword    dd    456FD690h    ; hexa dword
uData    db    ?  ; uninitilized byte
    main    proc    near
  add    ax, bx    ; add    reg, reg
  add    al, aByte; add    reg, mem
  add    ah, 0Dh    ; add    reg, imm
  add    aWord, ax; add    mem, reg
  add    aByte, aByte; add    mem, mem
  add    aDword, 80808080h; add    mem, imm
    main    endp
end main

- SUB:

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

SUB    (reg/mem), (reg/mem/imm)

بالنسبة للامثلة فكما ترون الامر مشابه لتعليمة ADD لذلك سنقوم بتخطي هذه النقطة.

- MUL:

الاختلاف الذي تحدثت عنه سابقا بخصوص تعليمتي الضرب والقسمة هو انه عند التعامل مع المعطيات فاننا نتعامل مع القيمة الثنائية لها وبالتالي نقف عند موضوع طرحناه سابقا وهو مسالة المعطيات المؤشرة وغير المؤشرة signed & unsigned data, ففي حالة المعطيات غير المؤشرة يكون ناتج ضرب عدد باخر قيمة مغلوطة نوعا ما لاننا لو حاولنا ضرب عددين احدهما سالب فان تعليمة مثل تعليمة MUL (الخاصة بالمعطيات غير المؤشرة) ستقوم بتجاهل الاشارة وتعطي الناتج بالقيمة المطلقة وبالتالي لا يكون هذا الامر صحيحا في معظم الحالات التي قد نضطر لاستخدام هذه التعليمة فما الحل؟ نقوم في هذه الحالة باستخدام الشكل الاخر لتعليمة MUL وهو IMUL حيث تقوم الاخيرة باعطاء القيمة الفعلية للمعطيات باشارتها وبالتالي يجب ان نكون على حذر عند استخدام هاتين التعليمتين وتعليمتي القسمة DIV و IDIV واللتان سنوضح الية عملهما بعد قليل.

اذن ماذا بشان MUL الان؟

بالنسبة لهذه التعليمة فانها تقوم باجراء عملية جداء المضروب بالمضروب فيه :p دون اخذ اشارتيهما بعين الاعتبار. حيث ان MUL تعامل الخانة الثنائية الاخيرة (في اقصى اليسار most significant bit) كخانة معطيات وليست كخانة اشارة, بالتالي فان جداء العددين (-15) × (30) سيعطي القيمة (1C2) بينما تكون القيمة الصحيحة لو اردنا الحصول على الجداء باستخدام الالة الحاسبة هي (1C3E) لذا يجب الانتباه الى نوع المعطيات التي نتعامل معها.. تذكروا ان مثل هذا الخطا في برنامج ما على بساطته قد يؤدي الى حصول BOF ويسمح لامثال Qnix بالسيطرة على اجهزة البشر :D

MUL    (reg/mem):src

اما بالنسبة لشكل الاستخدام فهناك بعض الاختلاف كما راينا في المثال من قبل ويتمثل هذا الاختلاف في ان عملية الضرب تتم بين (المسجل AL في حالة الضرب ببايت, AX في حالة الضرب بكلمة, EAX في حالة الضرب بكلمة مضاعفة) حيث تكون القيمة المخزنة في احد المسجلات السابقة هي قيمة المضروب (المعامل الاول) اما قيمة المعامل الثاني (المضروب فيه) فتكتب بعد تعليمة MUL وتكون اما مسجل او عنوان ذاكرة. ففي الحالة التي يتم ضرب فيها القيم الموجودة في AL و معامل اخر فان الناتج يخزن في المسجل AX بكامله اي انه حتى لو كانت القيم المضروبة لا تزيد في طولها عن بايت فان القيمة النهائية في هذه الحالة تكون 00 في المسجل AH -- الاختلاف بالنسبة للضرب بكلمة او كلمة مضاعفة هو ان الناتج يوضع في المسجل DX:AX و EDX:EAX. يمثل الامر كما في الشكل التالي:

.model    small
.code
    org    100h
    jmp    main
aByte    db    15  ; decimal byte
aWord    dw    F015h  ; hexa word
aDword    dd    456FD690h    ; hexa dword
uData    db    ?  ; uninitilized byte
    main    proc    near
  mov    al, aByte; copy aByte -> AL
  mul    bh    ; multiply the value of AL with the value of BH and store it in AX
  mul    aByte    ; multiply the value of AL with the value of aByte and store it in AX
    main    endp
end main

الان بالنسبة للمعطيات المؤشرة, ماذا تختلف IMUL في استخدامها عن MUL ؟

الاختلاف يكون بشكل الاستخدام حيث تملك IMUL 3 اشكال اخرى للاستخدام بالاضافة الى ما تم ذكره بالنسبة لـ MUL وهذه الاشكال هي:

IMUL    reg, mem    ; on all processors
; the following are only supported by i186 and later
IMUL    reg, imm
IMUL    reg, reg, imm
; the following are only supported by i386 and later
IMUL    reg, (reg/mem)

- DIV:

تجري هذه التعليمة عملية قسمة للمقسوم على المقسوم عليه وذلك دون اعتبار الاشارة. حيث ان DIV كما في MUL تعامل الخانة الثنائية الاخيرة (most significant bit) كخانة معطيات, وليست كخانة اشارة. بالنسبة لطريقة الاستخدام فانها مشابهة تماما لـ MUL.

- IDIV:

تجري هذه التعليمة عملية قسمة للمقسوم على المقسوم عليه وذلك بعد اخذ الاشارة بعين الاعتبار. يجدر الاشارة هنا الى ان هذه التعليمة لا تملك الشكل الموسع الذي رايناه فيما يخص تعليمة IMUL اما بالنسبة لطريقة الاستخدام فهي نفسها كما في DIV و MUL.

اذن نلاحظ ان هذا التطبيق البسيط الذي اخذناه يحوي على الكثير من المعلومات الهامة في طرق استخدام التعليمات والملاحظات المتعلقة بها والتي يجب على من يريد تعلم الاسمبلي ان ينتبه اليها جيدا كي لا يقع في اخطاء لا تحمد عقباها.

- ماذا بشان العمل تحت بيئة 32بت؟

في الواقع فيما يخص التطبيق الذي تناولناه وغيره الكثير مما سنتناوله لاحقا فلن يكون هناك اي اختلاف بين البيئتين لاننا في النهاية نتعامل مع المسجلات وقيم معنونة في الذاكرة او فورية وبالتالي لم نتناول بعد موضوع الواجهات المرئية او تعليمات الادخال (المقاطعات) -- الاختلافات غير مذكورة وتتمثل فيما ناقشناه في بداية هذا الموضوع حول الفروق بين ملفي COM و EXE وفي كيفية تمثيل كل كتلة ملف وتعريفه للمجمع -- هذا الامر سنقوم بتغطيته لاحقا.

- حاولت استخدام الشفرات الموضحة في هذا المقال لكن الملف الناتج بصيغة EXE!

نعم لا باس, هذا الامر يعود الى حقيقة ان masm16 يفترض انك تقوم بكتابة ملف EXE لذلك تلاحظ ظهور عبارة warning: no stack segment وفي حال اردت تحويل الملف الى ملف COM بدون اي مشاكل يمكن استخدام برنامج مثل EXE2BIN الذي سيقوم بتحويل الملف الناتج الى صيغة COM.

green.png نصيحة برمجية: قم دوما بتبسيط اجرائيات برنامجك -- اعتمد مبدأ "فرّق تسد" فيما يخص كتابة التطبيقات -- على سبيل المثال لنفرض انك تريد كتابة برنامج يقوم بقراءة الملفات والكتابة فيها و و و.. -- نصيحتي لك ان تقوم بكتابة برنامجك كاجرائيات وان تقوم بتنقيح عمل كل اجرائية على حدة كي تضمن انه لا يوجد اي خطا فيها وتجنب ان تترك التنقيح للبرامج الكبيرة نسبيا الى ما بعد الانتهاء من كتابة البرنامج لان هذا سيؤدي الى ضياع وقت كبير في محاولتك تحديد سبب الخطا الفلاني وهذا الامر غير مستحب من وجهة نظرنا كمبرمجي اسمبلي <_>

أسئلة؟

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#5

درس رائع...تقبل خالص تحياتي يا xacker

بخصوص الـ MUL

هل هذا الكود صحيح ؟( unsigned)

;BYTE  X  BYTE

first       db 10
second  db 20

mov al,first
mov bh,second

mul bh                  ;the result is in bh

;WORD  X  WORD

first       dw 1000
second  dw 2000

mov ax,first
mov bx,second

mul bx                  ;the result is in dx:bx

تم تعديل هذه المشاركة بواسطة allko في 13 نوفمبر 2005 في 23:24

#6
اقتباس
بالنسبة لشكل الاستخدام فهناك بعض الاختلاف كما راينا في المثال من قبل ويتمثل هذا الاختلاف في ان عملية الضرب تتم بين (المسجل AL في حالة الضرب ببايت, AX في حالة الضرب بكلمة, EAX في حالة الضرب بكلمة مضاعفة) حيث تكون القيمة المخزنة في احد المسجلات السابقة هي قيمة المضروب (المعامل الاول) اما قيمة المعامل الثاني (المضروب فيه) فتكتب بعد تعليمة MUL وتكون اما مسجل او عنوان ذاكرة. ففي الحالة التي يتم ضرب فيها القيم الموجودة في AL و معامل اخر فان الناتج يخزن في المسجل AX بكامله اي انه حتى لو كانت القيم المضروبة لا تزيد في طولها عن بايت فان القيمة النهائية في هذه الحالة تكون 00 في المسجل AH -- الاختلاف بالنسبة للضرب بكلمة او كلمة مضاعفة هو ان الناتج يوضع في المسجل DX:AX و EDX:EAX.

لا يمكنك ان تنفذ عملية الضرب وان تجعل الناتج يظهر في مسجل اخر -- يجب ان يستخدم AX دوما في الضرب والقسمة -- اعتقد اني غفلت عن توضيح هذه النقطة بالشكل الكامل :P

تم تعديل هذه المشاركة بواسطة Xacker في 14 نوفمبر 2005 في 03:01

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#7

راجعت احد دروس الاخ afeef فانتعشت ذاكرتي قليلا...

اعتقد ان الكود هذا صحيح...

mov al,10
mov cl,-5
imul cl
now ax = 50

mov ax,10000
mov bx,9
mul bx
now dx:ax = 90000

mov al,9
mov cl,7
div cl
now al = 1 , ah = 2

mov dx,0
mov ax,-1948
mov cx,1967
idiv cx
now al = 1 , ah = 19

سؤال صغير...في حالة القسمة( word) فان

AX: يحتوي على الناتج الصحيح

DX:يحتوي على الباقي الصحيح

ماذا عن حالة الضرب(word) ؟

اعتقد ان

AX: يحتوي على اول 8bits

DX:يحتوي على اخر 8bits

هل هذا صحيح؟

تم تعديل هذه المشاركة بواسطة allko في 16 نوفمبر 2005 في 16:19

#8

صحيح :D

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#9

تخيل !

كنت اود البدأ في طرح اسئلتي الغبية لاجد ان الموضوع قد طرح في 2005 !!

توقيع : الاحمق الوحيد الدي يريد تعلم assembly

#10
jamesbond86 كتب:
توقيع : الاحمق الوحيد الدي يريد تعلم assembly

هههه

لكنها حماقة تستحق...

تذكرني بصعاليك لكن ظرفاء!

قطرة الماء تـثـقب الحجر.. لا بالعنف. لكن بتكرار المحاولة

at4re.gif

منتديات الفريق العربي للهندسة العكسية 不喜欢的勿入! www.at4re.com

#11

شكرا على التشجيع و شكرا على المجاملة !

تم تعديل هذه المشاركة بواسطة jamesbond86 في 25 سبتمبر 2007 في 22:43

هذا الموضوع مغلق.

مواضيع مشابهة