برگزیده های پرشین تولز

دستورات اسمبلي

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
چون تاپيك ((اسمبلي براي سي)) با لينك زير:
http://forum.persiantools.com/showthread.php?t=37385
براي آموزش دستورات اسمبلي در نظر گرفته نشده ،بلكه آن تاپيك براي ((نگاهي اسمبلي وار به سي)) تدارك ديده شده من در اين تاپيك سعي مي كنم مروري بر دستورات اسمبلي داشته باشيم.
.
در تمرينات زير از ديباگ خود ويندوز استفاده شده و از يك اسمبلر ، كه در تاپيك ((اسمبلي براي سي)) كه لينكش در خط بالا هست طرز استفاده از هر دو گفته شده.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
در شكل زير طرز استفاده از دستور shift را من تمرين كردم. اول به dx مقدار 3 را دادم كه در حقيقت 11 است در مبناي 2 و اگر با شيفت به راست هلش بدهيم به سمت راست ميشه 1 در مبناي 2 كه با مبناي 16 فرقي نداره و همونه.


a8000000.gif


در شكل زير طرز استفاده از and را من گفتم. And مثل آبكش مي مونه. ولي برعكس آبكشه. يعني هرجاش پر باشه عبور مي دهد. من بيت دوم را پر تنظيم كردم. 2 يعني 10 در مبناي 2 .
و چون بيت دوم فقط پر بوده ، آن قسمت عبور كرده.


a9000000.gif



يادتان باشد كه دستور t باعث ميشه ip عوض بشه. اگر يكبار از آن استفاده كنيد ، كنترل برنامه رفته جلو . با دستور r ip و اينتر ، دوباره مقدار 100 به آن بدهيد. .



d5000000.gif


همان طور كه بالاي كادر آبي مي بينيد ، ((آي پي)) به ترتيب 103 و 106 و 108 شده.
وقتي ديباگ را تازه باز كرده ايم ، مساوي صد است. ولي دستور تي آن را عوض مي كند. دستور جي كه بعدا مي گوييم ، هيچ تغييري در اينها نمي دهد. البته تغيير مي دهد ولي بازيابي مي كند.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
البته مي دانيد كه در محيط ديباگ اعدادي كه ما وارد مي كنيم در مبناي 16 است.(شكل زير: )


b1000000.gif


ولي چون 2 و 3 كوچكتر از 10 هستند مبناي ((ده)) و ((شانزده)) فرقي نداشت.(منظورم پست قبلي است.)
دستور تي و آ را هم در تاپيك اسمبلي براي سي گفته ام.
ولي همين جا باز تكرار مي كنم. دستور t باعث ميشه كه يك ((تك دستور)) اجرا بشه.
دستور a هم به ما اجازه مي دهد كه به شكل بالا دستوراتي را وارد مي كنيم. كه ما از مكان 100 وارد مي كنيم. چون از اينجا دستورات شروع به اجرا مي كنند. قبل 100 چيزهايي است كه بعدا بحث مي كنيم.
با دستور e هم ميشه دستورها را وارد كرد ولي با اين سينتكس كه در بالا كار شده نيست بلكه دستورات را به شكل اعدادي در مبناي 16 وارد مي كنيم. اگر كسي علاقه داشت در همين شكل بالا مي بينيد كه ديباگ معادل اين جوري دستورات را هم به نمايش مي گذارد، كه مي توانيد همين طوري ياد بگيريد. ولي فكر نكنم كسي دنبال اين نوع دستور نويسي باشه كه ديگه خيلي اعصاب مي خواهد.
.
اگر شما بخواهيد در اديتور كدها را بنويسيد و با اسمبلر ، برنامه اجرايي خود را بسازيد، سينتكس زياد فرقي نداره و به طور كلي قالب كار در تاپيك اسمبلي براي سي گفته شده.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
در برنامه زير مي خواهيم باز هم با دستور shr كار كنيم. مخفف shift to right است.
من 4 بار شيفت به راست داده ام.
مي دانيد كه bx را مي شود دو قسمت كرد. Bh و bl . من از bl استفاده كرده ام اينجا.
در حقيقت bl و bh هر يك شامل يك بايت هستند و روي هم اين دو بايت را يك ((كلمه)) word مي گويند.
اگر bx را به مقدار كافي شيفت به راست بدهيد ، bh مي رود در bl و bl حذف مي شود و اگر مي خواهيد bl از آنطرف برود جاي bh مي توانيد به جاي دستور shift از دستور rotate (يعني چرخش) استفاده كنيد. كه چون زياد استفاده ندارد ، فعلا روي آن بحث نمي كنيم.

اما در تمرين زير ما bl را به سمت راست 4 بار هل داده ايم. قصد من اين بود كه رقم سمت راستي برود جاي سمت چپي. ( من 2f را داشتم كه به 2 رسيدم.)
حالا چرا مي خواستم اين طوري بشه؟ جواب اين كه اين مانور كاربرهايي دارد. و باهاش ميشه مسائلي را حل كرد. فعلا نخواستم مسئله را بگم. ولي ((تمرين)) اين است.
تمرين: محتواي يك رجيستر را به شكل مبناي 16 روي صفحه نمايش چاپ كنيد.


b3000000.gif


b4000000.gif


البته ميشه حلقه هم ساخت كه من نخواستم مسئله را پيچيده كنم. و شيفت 4 تا يكبار هم جاي بحث داره كه ميگذاريم براي بعد.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1

b5000000.gif


در شكل بالا كه خودم الان كشيدم، خواستم بگويم كه 2f كه در پست قبلي باهاش كار كرديم ، چطوري نشسته در رجيستر.
اولا مي بينيد كه bx را به دو قسمت bh و bl تقسيم كرده ايم.
و bl را هم دو تا 4 بيت است.
هر 4 بيت 16 حالت دارد كه 16 حالت آن در مبناي 16 ميشه:
صفر و 1 و 2 و 3 و 4 و 5 و 6 و 7 و 8 و 9 و a و b و c و d و e و f
كه f ميشه 15 و چون از صفر شروع شده ميشه 16 حالت.

در تمرين قبلي با 4 بار شيفت به راست 2 را برديم جاي f .
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1

b6.gif


b7000000.gif



در اينجا به نقش فيلتري and اشاره شده. مي دانيد كه نتيجه and وقتي مثبت است كه هر دو مثبت باشند. يعني وقتي هر دو 1 باشند نتيجه 1 است.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1

c1000000.gif


در شكل بالا دستور dec كه مخفف decrease است را مي بينيد. كه كارش اينه كه يك واحد از رجيستر مورد نظر كم مي كنه. برعكسش increase است كه يك واحد اضافه مي كند.

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

نكته سوم اين كه در شكل به محل نشستن دستورات در Ram تاكيد شده.
من مي خواستم اينجا بگويم كه بعضي دستورات يك بايتي اند(كه اينجا نداريم فعلا) ، و بعضي دستورات دو بايتي اند و بعضي 3 بايتي و ........ و همين طور مي رويم بالا.

دستور dec دو بايتي بوده چون دستور بعدي در آدرس 104 نشسته.
دستور add هم شامل سه بايته .


c2000000.gif


در شكل بالا ، دستور jmp را مي بينيد كه همان jump (پرش) است. و مي بينيد كه آدرس دستور بعدي را هماني كرده كه ما مي خواستيم. يعني 130 . و بعد اجراي اين دستور(jmp ) دستوري كه در آدرس 130 هست اجرا ميشه.

يك توضيح واضحات بدهم كه رجيسترها در cpu هستند ولي دستوراتي كه ما مي نويسيم ، در Ram زندگي مي كنند. و cs و ip ميشه آدرس خيابان و كوچه اين دستور. كه در شكل بالا با فلش آبي نشان داده شده.
ما همان طور كه مي توانستيم bx و ax را تغيير دهيم مي توانيم اين دو (cs و ip ) را هم تغيير دهيم.
ولي اين دو را برخلاف ax تا dx نميشه به دو جز بالا high و پايين low تقسيم كرد.


c3000000.gif


در شكل بالا من مي خواستم يك دستور يك بايتي را نشان دهم. Push كردن. در همان يك بايت دستور انواع رجيسترها را ميشه گفت push بشوند.


c4000000.gif


در شكل بالا مي بينيم كه 53 براي push كردن bx و همچنين 51 براي cx .
و همچنين مي بينيد چون دستوراتي يك بايتي هستند ، ip فقط يك واحد افزايش يافته. افزايش ip كاري اتوماتيك است كه cpu بعد اجراي هر دستور خودش انجام مي دهد ولي ما هم به شكل دستي مي توانيم آن را تغيير دهيم.

اما راجع به push كردن. كه معنايش فرستادن مقدار يك رجيستر به پشته است ، يك شرحي بدهم.
در حقيقت يك كپي از محتواي رجيستر در محلي كه پشته ناميده مي شود ، ذخيره مي شود. اين محل هم در Ram است ولي جايي دور از محل قرار گيري دستورات .
در يك فايل com همه قسمتهاي برنامه در يك قطعه زندگي مي كنند. يك قطعه 64 كيلوبايتي در Ram .
از آدرس 100 اين قطعه دستورات ما مي نشينند و پشته از آخر قطعه شروع ميشود و به سمت اول قطعه رشد مي كند. يعني مثلا اگر 100 بار push كنيد. اولي بلافاصله به سقف قطعه مي چسبد و صدمي 100 آدرس پايين تر.
و اگر بخواهيد چيزي از روي پشته برداريد ، اول بايد صدمي را برداريد و بعد شماره 99 را و بعد 98 تا برسيم به اولي.
حالا چه كاربردي دارد پشته؟ يكي براي ذخيره چيزهايي كه ما داريم. مثلا داريم روي ax كار مي كنيم و مي خواهيم يك بك آپ ازش تهيه كنيم. پس مي گذاريم در پشته. بعد كار روي آن براي بازيابي از پشته با pop برش مي گردانيم. البته ميشه در يك رجيستر ديگه هم ذخيره كرد ولي مثلا اگر بخواهيم ax و bx و cx و dx را با هم ذخيره كنيم چي؟ معلومه كه جا كم مي آوريم.
كلا مي دانيد كه در اسمبلي هم زيربرنامه داريم مثل همه زبانهاي ديگه. بهتره اول زير برنامه ، همه را push كنيم(يعني اونهايي كه دستكاري مي شوند در داخل زير برنامه) و موقع بازگشت از زير برنامه همه pop بشوند.

ولي يادتان باشه ، نميشه در يك زير برنامه push كرد و بعد در زير برنامه بعدي يا برنامه اصلي pop كرد. چون آدرس رفت و برگشت به زير برنامه ها هم در پشته ذخيره ميشه. پس همه push ها و pop هاي خود را در يك زيربرنامه انجام بدهيد.

ولي اگر زير برنامه نداريد ، مثل برنامه هاي ساده بالا ، فعلا آزاديد.
يعني مي توانيد 10 تا را بفرستيد و 3 را پس بگيريد ولي در يك برنامه منظم بايد اينها برابر و حساب شده باشه.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1

c5000000.gif


در شكل بالا اولين برنامه خود را نوشتيم كه كاري براي ما انجام مي دهد.
و كارش اين است كه حرف a را چاپ مي كند.

نكات:
ما با دستور g ، برنامه را اجرا كرديم ، قبلا با دستور t اجرا مي كرديم. فرقشون اينه كه t فقط يك دستور را اجرا مي كنه و تغييرات رجيسترها قابل مشاهده است ولي g تا رسيدن به دستور خاتمه كه در اينجا int 20 است به اجراي دستورات ادامه مي دهد و در آخر هم رجيسترها بي تغييري مشاهده مي شوند.
البته تغيير مي كنند ولي دوباره ريست مي شوند به حالت اول.
يادتان باشد تا كدهاي درستي ننوشته ايد و تا دستور خاتمه را نگذاشته ايد از دستور g استفاده نكنيد چون ممكنه با اجراي دستورات غلط يا پيشروي به بقيه Ram و اجراي آنها باعث قفل كردن سيستم بشه و بايد دستگاه را Reset كنيد.

نكته دوم اين كه ما از دو وقفه اينجا استفاده كرده ايم. وقفه ها مثل توابع حاضر و آماده براي ما كاري انجام مي دهند. اولي همان int 20 بود كه كارش اينه كه كنترل را از برنامه مي گيرد و به سيستم عامل بازمي گرداند. و دومين وقفه int 21 است. البته اين 21 و 20 در مبناي 16 است نه 10 .
وقفه 21 كارهاي بسيار زيادي انجام مي دهد. و اين كارهاي مختلف را با نگاه به ah انجام مي دهد. در اينجا كه ah مساوي 2 است ، مي رود به dl نگاه مي كند و عدد ذخيره شده در آنجا را كد اسكي يك كاراكتر فرض مي كند و آن را چاپ مي كند كه در اينجا حرف a چاپ شده.
.
اين برنامه در برنامه هاي بعدي ما ، يك زيربرنامه خواهد شد كه هميشه ازش براي چاپ استفاده خواهيم كرد.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1

در تاپيك اسمبلي براي سي ، من طرز فايل سازي با ديباگ را گفتم و همچنين طرز فايل سازي با tasm را كه نوعي كامپايلر(اسمبلر) محسوب ميشه.

در اينجا بايد بگم كه با برنامه ديباگ ميشه فايل com ساخت. و با tasm ميشه فايل exe ساخت.
البته با نرم افزارهاي ساده اي اين دو قابل تبديل به همند. يعني exetocom يا comtoexe ولي فرقهاي اين دو نوع فايل را مي گويم.

مهم ترين فرقشون اينه كه فايل com همه اجزايش در يك قطعه در Ram جمع مي شود ولي در فايل exe در قطعه هاي مختلف. كه فعلا زياد باهاش كار نداريم. اگر بعدا نياز شد بيشتر روي آن تمركز مي كنيم.

اما در كدنويسي در ديباگ براي ساختن فايل com ما با دستور int 20 برنامه را خاتمه مي داديم ولي در فايل exe بايستي از سرويسي از وقفه 21 استفاده كنيم. سرويس 4c است اين سرويس. يعني اول مي نويسيم mov ah,4c و بعد مي نويسيم int 21 .

به علاوه در ديباگ فقط دستورات را مي نويسيم

ولي وقتي بخواهيم كدها را براي تحويل به اسمبلر آماده كنيم در اول و آخر كدها در اديتور خود دستوراتي اضافه مي كنيم براي راهنمايي كامپايلر(اسمبلر) tasm . كه بعدا حين كدنويسي هر جا لازم شد معناي آن راهنماها را مي گوييم . ولي فعلا از يك قالب كلي استفاده مي كنيم و شما هر كدي كه در ديباگ مي نوشتيد را درون اين قالب قرار بدهيد.

نكته ديگر در تفاوت كار با ديباگ و اسمبلر اينه كه در jump كردن (كه مثل دستور goto در سي و بيسيك است) در ديباگ بايد آدرس را به شكل شماره خانه بدهيم ، ولي براي راهنمايي اسمبلر ، ما ليبلي در تارگت(محل فرود پرش) قرار مي دهيم. اين قضيه بمراتب كد نويسي را با اسمبلر راحت تر از محيط ديباگ مي كند. چون مثلا اگر قرار باشه يك خط كد بين كدها اضافه بشه ، چون آدرس ها جابجا مي شوند بايد برويم دستور پرش (مثلا jmp 120 ) را تغيير دهيم(مثلا بشه jmp 122 ).

همين طور در مورد زير برنامه هم مثل پرش. در ديباگ بايد آدرس زير برنامه را وارد كنيم ولي در اسمبلر فقط اسم زيربرنامه را مي گوييم. مثلا مي گوييم call 200 در ديباگ و در اسمبلر مي گوييم call mysub كه در اينجا mysub اسمي است كه خودمان روي زير برنامه خود گذاشته ايم و در يك جايي اين زيربرنامه منتظر دريافت كنترل از برنامه مادر است.
.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
حالا همين برنامه چاپ حرف a (دو پست قبل) را هم با ديباگ من مي نويسم و هم در اديتور تا تفاوتها را مقايسه كنيد و براحتي با هر دو كار كنيد.

خط mov dl,41 را در برنامه اصلي نگه مي داريم و بقيه را در زير برنامه قرار مي دهيم.


c6000000.gif


در شكل بالا مي بينيد كه برنامه اصلي را در خانه شماره 100 من شروع كرده ام و زير برنامه را در آدرس شماره 200 شروع كرده ام. با call خط 200 احضار شده و با ret بازگشت كرده.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
برنامه پست قبل را در اين پست با tasm مي خواهيم بسازيم.


.model small
.stack
.code
my_first_program proc
mov dl,41h
call dl_print

mov ah,4ch
int 21h

my_first_program endp

dl_print proc
push ax
mov ah,2h
int 21h
pop ax
ret

dl_print endp
end my_first_program

موقع کپی کردن کد بالا توجه کنید که یک نقطه قبل model small هم باید کپی شود.

خطوط قرمز رنگ همان هاست كه در محيط ديباگ هم نوشتيم. ولي با دو تفاوت. تفاوت اول همان نوع اختتام بود كه قبلا گفتيم . در اينجا با mov ah,4c و int 21 خاتمه داده ايم ، آنجا با int 20 .
خط سبز حكمتش اينه كه مشخص مي كنه برنامه اصلي كدام است. زيرا همان طور كه مي بينيد راهنماها براي برنامه اصلي و زيربرنامه يكي است.

تفاوت دوم اينه كه در زير برنامه خود ، اول و آخر زيربرنامه ، با push و pop آمده ايم ax را از دستبرد زيربرنامه در امان نگه داشته ايم. البته برنامه اصلي در اينجا برايش مهم نبوده كه ax تغيير كند ولي قانون كلي اينه كه زيربرنامه بايد امين باشد و رجيسترها را دست نخورده برگرداند. مگر اينكه زيربرنامه بخواهد توسط يك يا چند رجيستر با برنامه اصلي صحبت كند . كه اينجا بحث ورودي و خروجي مطرحه.
و بهتر است كه بالاي زير برنامه بگيم چه خروجي ئي داره و چه ورودي ئي و با چه رجيسترهايي و همچنين بالاي زيربرنامه بگيم كه اين زيربرنامه چه كاري انجام مي دهد كه اينجا رعايت نشده. بعدا طرز كامنت نويسي در اسمبلي را مي گوييم.
((كامنت)) در همه زبانها هست و توضيحاتي است كه براي راهنمايي خود برنامه نويس و يا برنامه نويس ديگر براي افزايش خوانايي نوشته مي شود ولي توسط كامپايلر ترجمه نمي شود.
.
من كد بالا را با پسوند asm در هارد ذخيره كردم و بعد توسط tasm و link به فايل exe تبديل كردم كه در شكل زير مي بينيد.



c7000000.gif

 
Last edited:

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
حال كمي به برنامه خود شاخ و برگ مي افزاييم.


.model small
.stack
.code

my_second_program proc
mov cx,26
mov dl,41h

my_lable:

call dl_print
inc dl
loop my_lable

mov ah,4ch
int 21h

my_second_program endp


dl_print proc
push ax
mov ah,2h
int 21h
pop ax
ret

dl_print endp
end my_second_program


من يك حلقه ساختم با دستور loop . اين دستور به تعداد cx مي چرخد. و به ليبل خود پرش مي كند. من cx را مساوي 26 گرفتم تا 26 حرف الفباي انگليسي را چاپ كنم. در حقيقت زيربرنامه چاپ dl را 26 بار احضار كرده ام.
دستور inc هم كه باعث يك واحد افزايش است هر بار كه اجرا ميشه.
يك نكته اين كه من جلوي 26 حرف h را نگذاشتم تا اسمبلر بفهمه كه اين عدد در مبناي 10 است نه در مبناي 16 و بقيه اعدادي كه حرف h جلوي آنها گذاشته ام در مبناي 16 است.
و مي دانيد كه در محيط ديباگ هر عددي مي گذاشتيم به طور اتوماتيك در مبناي 16 در نظر گرفته مي شد.
در زير من در همان محيط ms-Dos اجراش كردم ولي البته فايل exe برنامه من هم ساخته شده بود و مي توانم يادگاري براي خود نگه دارم. با حجم 535 بايت كه الان آمادگي بحث بر سر اين كه چرا حجمش اينقدر شده را ندارم.


c8000000.gif

 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1

c9000000.gif


اين هم همان برنامه پست قبل كه در محيط ديباگ نوشتم.
مي بينيد كه از ليبل خبري نيست و بايد ((آدرس حافظه)) بجايش وارد كنيد.
در حقيقت اسمبلر هم همين كار را براي شما مي كند. يعني بجاي ليبل ، ((آدرس حافظه)) قرار مي دهد. در كل از اسمبلر چيزي بيشتر از اين بر نمي آيد. چون در زبان اسمبلي اين شما هستيد كه همه كار را انجام مي دهيد و اسمبلر حكم نظافت چي را دارد ولي در ديگر زبانها ، مثل سي و بيسيك ، كدهايي كه شما مي نويسيد(سورس) خيلي فرق داره با اون چيزي كه كامپايلر بعد كامپايل براي شما مي سازد.

حالا براي اثبات قضيه ، همان فايلي كه در پست قبل گفتم يادگاري نگه مي داريم را با ديباگ باز كنيد. يعني همان فايل exe كه با tasm از كدهاي خود ساختيم.


d1000000.gif


همان طور كه در بالا مي بينيد، من با دستور debug second.exe فايل را باز كردم. بعد با دستور u 00 ليست گرفتم. U برعكس دستور a است. با a دستورات را وارد مي كنيم و با u ليست ومشاهده مي كنيم.

يك نكته جالب اينجاست و آن اينكه كدها از آدرس 100 شروع نشده اند و از آدرس 00 شروع شده اند. اين علتش اينه كه با يك فايل exe طرف هستيم نه يك فايل com . اگر فايل ما com بود ، بايد مي نوشتيم u 100 تا ليست آن را ببينيم.

و نكته جالب ديگه اينه كه اسمبلر موقع ساخت فايل ما ، زيربرنامه را دقيقا چسبانده به برنامه اصلي و مثل من از 100 نرفته به 200 و كلي وسطش خالي بگذاره.

و مي بينيد كه باز ليبل نداريم و loop به يك آدرس داره اشاره مي كنه. همچنين دستور call يك شماره آدرس جلوي آن است.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
پرشهاي شرطي:

قبلا با دستور jmp كار كرديم كه پرشي بي شرط بود. حال به اين دو دستور نگاه كنيد:

کد:
jmp 200
jl 200

يا اگر براي اسمبلر بنويسم:

کد:
jmp my_label
jl my_lable

اين دو دستور كه يكي دستور پرش بي شرط و ديگري دستور پرش شرطي است ، هر دو باعث مي شوند كنترل با جاي ديگري بپرد و از آنجا كدها اجرا شوند.

در نوع بي شرط كه بحثي نيست و همين يكي است.(تا آنجا كه من مي دانم)
ولي در مورد پرشهاي شرطي ، بين 10 تا 20 يا بيشتر حالت دارد. البته كار همه آنها پرش است ولي در حالتهاي مختلفي مي پرند.

حالات مختلف:
منظور از اين حالات ، حالات فلاگها است.
همان طور كه تابحال ديديد ، رجيسترها هر كدام 2 بايت هستند يعني 16 بيت. ولي فلاگها هر كدام يك بيت هستند.
چراغ راهنمايي سر چهار راه را فرض كنيد. سه رنگ قرمز و سبز و زرد دارد. وقتي چراغ قرمز است ماشين ها توقف مي كنند و وقتي سبز است عبور مي كنند. و زرد نشانه عبور با احتياط است.
هر يك از چراغها (مثلا قرمز) دو حالت دارد. يا روشن است و يا خاموش. البته چشمك زن هم دارند كه فرض كنيد ندارند و چشم پوشي مي كنيم.

حالا فلاگها هم مثلا 8 چراغ راهنمايي هستند كه فقط دو حالت دارند(چون يك بيت هستند) ، يا روشن هستند يا خاموش.
و پرشهاي شرطي را مثل ماشين ها در نظر بگيريد. كه به فلاگها نگاه مي كنند كه آيا رد بشوند يا نشوند.

بعضي راننده ها در خيابان عشق رد كردن از چراغ قرمز را دارند، بعضي فلاگها هم برعكس فلاگهاي ديگر عمل مي كنند.
شايد بشود هر دو پرش شرطي را متضاد دانست. يكي با چراغ قرمز رد ميشه و يكي رد نميشه.
من خودم به همه فلاگها و همه پرشهاي شرطي مسلط نيستم بنابراين نمي توانم قانون هاي كلي بگم. و با هم تمرين مي كنيم تا به فلاگها و پرشهاي شرطي مسلط شويم.

حالا يك مثال مي زنم تا قضيه كامل جا بيافته و بعد برويم سراغ تمرين عملي.
فرض كنيد رجيستري را از عدد 5 كم مي كنيد. اگر خود رجيستر هم داخلش از قبل 5 بوده باشد ، نتيجه تفريق صفر ميشه. در اينجا فلاگ صفر مساوي روشن ميشه، و بعد jz كه بياد به اين فلاگ نگاه مي كنه و مي پره. اين دستور jz مخفف jump if zero است و zero يعني صفر.
پس با استفاده از اين فلاگها و دستورات شرطي ما توانستيم يك رجيستر را براحتي بررسي كنيم.
درود.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
امیدوارم تا اینجا مورد استفاده شما قرار گرفته باشد.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
در این پست از سعید smk عزیز و آرش جان به خاطر همراهی من در یاد گیری و یاد دادن سی و اسمبلی و دیگر مباحث تشکر می کنم.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
حالا آستين ها را بالا مي زنيم و باز مي رويم سراغ ديباگ. درسته كه كدنويسي با اسمبلر راحت تره ولي براي كارهاي آزمايشگاهي و آموزشي ديباگ بهتره.

من كد زير را در ديباگ نوشتم:

کد:
mov bl,5
mov al,6
sub bl,5
sub al,5


d2000000.gif


در شكل بالا مي بينيم كه با تفريق اول فلاگ صفر شده ZR . در تفريق اول 5-5 داشتيم. يعني همون bl-5 . حالا هر اسمي مي خواهيد روي ZR بگذاريد. ولي نشون مي دهد كه نتيجه تفريق صفر است.

در تفريق دوم شش منهاي پنج مي بينيم كه به حالت پايه است يعني NZ . ميشه بگيم no zero .

حالا اگر JZ گذرش به اين طرف بيافته سريع مي پره چون چراغ راهنمايي به اون مي گه بپر . و انگار عكسش اين باشه JNZ . اين يكي وقتي اين چراغ روشن نباشه مي پره. ولي بگذاريد هر دو را امتحان كنيم و بعد قبول كنيم.
.

ولي اگر نگاه كنيد ، همان جايي كه با فلش قهوه اي نشان داده ام ، يك فلاگ ديگر هم داره واكنش نشان مي دهد.
كلا جداولي موجود است كه ميگه به هر دستور چه فلاگهايي واكنش نشان مي دهند. ولي من هنوز حوصله ام نيامده برم درست نگاش كنم.
بعدا با تمرين چند تاشون را ياد بگيريم بسه.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
با سلام.
مي دانيد كه رجيسترها يا
Ram
حافظه هايي هستند كه از بيت و بايت تشكيل شده اند.
مثلا رجيستر
ax
دو بايت است.
در داخل اين بايتها يكسري صفر و يك قرار دارد كه ما براي راحتي در مبناي 16 قرائت مي كنيم.

ولي چه در
Ram
و چه در رجيسترها ، ما لازم است با حروف هم كار كنيم. مثلا اسم خود را در حافظه ذخيره كنيم.

اولا به طور كلي مي شود رجيسترها را بندرگاههاي
cpu
ناميد. يعني محموله ها و بارها موقع ورود و خروج به
cpu
در رجيسترها قرار مي گيرند.
ولي محل اصلي قرار گيري اطلاعات روي
Ram
است.
يعني
cpu
اطلاعات را از
Ram
برمي دارد و داخل رجيسترها قرار مي دهد و روي آنها كار مي كند و در جاي مناسب در محل ديگري از
Ram
قرار مي دهد.
رجيسترها را مي شود دستهاي
cpu
دانست . ولي بايد
cpu
را در اين تشبيه صاحب دستهاي بيشتري دانست.
ما در محيط ديباگ بالاي 10 رجيستر را ديديم ولي بيش از اين هاست .

حال پس ديگه راجع به رجيسترها حرف نمي زنيم. چون آنها محلهاي ورود و خروج هستند و راجع به اطلاعات موجود در
Ram
حالا حرف مي زنيم.

در فايلهاي
com
گفتيم كه دستورهايي كه ما مي نويسيم تا اجرا بشه ، از آدرس 100 بايد وارد شود. البته اين 100 مي دانيد كه در مبناي 16 است و در مبناي 10 ميشه 256 .
در اين 256 آدرس چه چيزهايي قرار دارد؟
جواب اينكه چيزهاي مختلفي هست ولي يك قسمت اعظم آن به عنوان (( قسمت نگهداري داده ها)) نگهداري ميشه. فرض كنيد بخواهيد به كاربر بگوييد
. Ok. Thank you.
، براي اينكار اين جمله را ميشه در اين قسمت نگهداري كرد.

بهتره حالا بحث را كمي گسترده كنيم.
ما بايد 3 قسمت مهم را در هم
com
و هم
exe
نام بريم.
اول – قسمت دستورات
دوم – قسمت پشته
سوم – قسمت داده

در فايلهاي
com
هر سه قسمت در يك قطعه قرار دارد. همين جا گفتيم كه آن 256 بايت براي نگهداري داده ها بود. قسمت پشته در فايلهاي
com
هم از انتهاي قطعه به سمت پايين پر مي شود. و قسمت دستورات هم كه از آدرس 100 شروع مي شد.

اما در فايلهاي
exe
، قطعات جدا از هم براي اين سه قسمت در نظر گرفته شده. البته وابسته به مدلهاي انتخاب شده توسط ما هم دارد. در برنامه هايي كه من براي اسمبلر نوشتم ، ديديد كه
model small
نوشتم. در اين مدل دو تا از قطعه ها مثلا روي هم قرار دارند. يعني اشتراكي از يك قطعه استفاده مي كنند. من چون برنامه هاي ما آموزشي بود ، نيازي به تعريف برنامه هاي
large
و غيره نداشتم.


ماهيت بايتها:

حال كه فهميديم در
Ram
ميشه چيزهاي مختلفي نگهداشت ، به ماهيت بايتها مي پردازيم.
اول – دستور
دوم – داده ،،،،،، كه خود داده مي تواند عدد يا حرف(كاراكتر) باشد.

به شكل زير نگاه كنيد.


d3000000.gif


در سمت راست دستورات را به شكل قابل فهم تري براي انسان مي بينم ولي در سمت چپ به همان ترتيب كه در
Ram
نشسته اند. مي بينيد كه اعداد همان ها هستند و همچنين دستورات هم به شكل اعداد(مبناي 16) نمايش داده شده اند.
البته يك بيت از لحاظ سخت افزاري چيزي بيش از يك چراغ روشن يا خاموش نيست ، و اين ما هستيم كه چند تاي آنها را يك عدد (حالا به هر مبنايي ) فرض مي كنيم.
حالا از حالا فرض مي كنيم كه
Ram
پر از اعداد است.
بعضي از اين اعداد را
cpu
دستور فرض مي كند. اگر شما با دستور
jmp 700
كنترل
cpu
را به اين منطقه بياندازيد ، هر عددي آنجا باشد را
cpu
براي خود به دستوري تفسير كرده و همين طوري مي رود جلو و همه اعداد را دستور فرض مي كند. و يا با اجراهاي نامناسب كامپيوتر از كار مي افتد و يا اينكه جايي به شكل تصادفي اين اعداد دستور اختتام را به
cpu
مي دهند و كار فيصله مي يابد.

اما كجا
، cpu
عددي را واقعا عدد مي خواند؟ جواب با دستور قبلي. در شكل بالا چون
cpu
با دستور
add
مواجه شده مي فهمد كه بايد بايت هاي بعدي را عدد فرض كند و عدد بخواند. چون مي داند كه يك عدد بايد
add
بشود و
add
خالي معني ندارد.

در مورد كاراكتر هم همين طور است. با دستورات است كه
cpu
مي فهمد بايد برود اعدادي را كاراكتر فرض كند و آنها را به شكل حروف الفبا براي خود تفسير كند.

جدول اسكي:

اينجاست كه جدول اسكي معني پيدا مي كند. يعني ما بايد طبق جداولي اعداد را به كاراكترها نسبت دهيم . مثلا 41 (در مبناي 16) را مساوي حرف
a
بگيريم.

اين جدول در انتهاي تمام كتابهاي اسمبلي و سي و بقيه زبانها هست و استاندارد است. و در اينترنت هم با يك سرچ كوچك پيدا ميشه.

حالا فرض كنيد كه در رجيسري عدد 3 وجود دارد. و ما مي خواهيم دستوري بنويسيم كه محتواي اين رجيستر را چاپ كند بر روي صفحه.

اگر در
Ram
در خانه اي عدد 33 ذخيره شده باشد و ما به
cpu
بگوييم برو آن را كاراكتر فرض كن ،
cpu
آن را كاراكتر 3 مي داند. و اگر بخواهيم چاپش كند هم 3 را روي صفحه مونيتور چاپ مي كند.

حالا كه ما مي خواهيم محتواي رجيستر ما كه 3 است ،، به شكل 3 روي صفحه چاپ بشود بايد به
cpu
33 (در مبناي 16) بدهيم. پس مي آييم 30 تا به آن اضافه مي كنيم. (30 در مبناي 16 ميشه 48 در مبناي 10)

حال فرض كنيد در رجيستري
a
باشد. (يعني همان 10 در مبناي ده) ، موقعي كامپيوتر حرف
a
را بر صفحه نمايش چاپ مي كند كه عدد 41 را به آن بدهيم . يعني بايد 31 تا(در مبناي 16) بهش اضافه كنيم تا اين حرف
(a)
چاپ شود.
 

saalek110

Registered User
تاریخ عضویت
10 آپریل 2007
نوشته‌ها
212
لایک‌ها
1
تا اينجا دانستيم كه فلاگها چون آينه اي از وقايع اتفاق افتاده هستند ، يعني هر عملياتي انجام دهيم باعث تغيير آنها مي تواند باشد. كه ممكن است يكي از آنها يا چند تا تغيير كنند.

حال فرض كنيد كه در دو رجيستر دو عدد داريم و مي خواهيم ببينيم كه آيا مساوي هستند يا نه.
راه حل اين است كه اين دو عدد را از هم كم مي كنيم . اگر فلاگ صفر ، صفر شد يعني اينكه دو عدد مساوي اند.
ولي مشكل اينجاست كه بعد مقايسه ما اعداد از بين رفته اند. پس به جاي sub كه تفريق معمولي است از cmp استفاده مي كنيم.
اين دستور فلاگها را تغيير مي دهد ولي اعداد داخل رجيسترها را تغيير نمي دهد و ما مي توانيم بعد مقايسه ، به دنبال استفاده از اعداد خود باشيم. پس ميشه بهش گفت يك نوع ((تفريق خيالي)) .
حالا دو عدد مساوي در دو رجيستر مختلف مي گذاريم و با cmp فلاگها را تست مي كنيم.


d4000000.gif


من به دنبال اين آزمايش ، آزمايش ديگري كردم ، اين بار عدد بزرگي را از عدد كوچكي كم كردم. اين فلاگ واكنش نشان نداد.
ولي خودتان برويد يك تست بكنيد، آيا فلاگ صفر وقتي صفر را نشان مي دهد ، اگر عملياتي انجام بدهيم كه باز باعث صفر شدن فلاگ بشه چي ميشه؟صفر مي ماند يا غير صفر ميشه؟
 
بالا