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

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

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
حال مي خواهيم برنامه اي بنويسيم كه يك رجيستر (مثلا در اينجا bh ) را چاپ كنيم.

کد:
.model small
.stack
.code
[color=red]bh_printer proc[/color]
[color=blue]mov bh,7ch[/color]      ; (1) meghdar avalieh be (bh)
mov dl,bh       ; (2) enteghale (bh) be (dl)       
shr dl,4        ; (3) 4 bar shifte (dl)
add dl,30h      ; (4)
cmp dl,3ah      ; (5)
jl lable_1      ; (6)
add dl,7        ; (7)
lable_1:        ; (8)
                call dl_print     ;(9)
mov dl,bh       ; (10)
and dl,0fh      ; (11)
add dl,30h      ; (12)
cmp dl,3ah      ; (13)
jl lable_2      ; (14)
add dl,7        ; (15)
lable_2:        ; (16)
                call dl_print     ; (17)
mov ah,4ch
int 21h
[color=red]bh_printer endp[/color]

[color=red]dl_print proc[/color]
push ax
mov ah,2h
int 21h
pop ax
ret
[color=red]dl_print endp[/color]
                             end [color=red]bh_printer[/color]


اولا بگم كه كار اين برنامه اينه كه هر چي در bh گذاشته بوديم(خط آبي) را چاپ مي كنه. كه با اين كد 7c چاپ ميشه.

دوما چرا به رنگ آبي نشان دادم. چون خطي است كه داره مقدار دهي مي كنه به bh و ميشه بجاش يك رجيستر ديگه را در bh قرار داد. مثلا mov bh,cl و اين جوري cl و به همين ترتيب همه رجيسترها را ميشه چاپ كرد.

سوما نحوه ((كامنت نويسي)) را مي بينيد كه بعد ((سمي كالن ; )) شما هر توضيحي آزاديد كه بنويسيد تا باعث راهنمايي خودتان و ديگر برنامه نويسان بشه.

چهارما بيشتر پستهاي اين تاپيك را من نوشتم تا اين برنامه را بتوانم شرح بدهم. اين برنامه از كتاب پيترنورتون است كه به فارسي ترجمه شده. فكر كنم اكثرا با كتاب سيد رضي كار مي كنند. اين كتاب يك اسمبلي پيشرفته هم داره كه براي ويندوزه و آن را هم من دارم ولي هنوز فرصت نشده با كدهاش تمرين كنم.

پنجما چيزي كه در اين برنامه اصل است همان اضافه كردن 30 در مبناي 16 به عدد است و اگر a يا بعدش بود ( تا f ) باز اضافه كردن 7 در مبناي 16 تا آن عددي كه مي خواهيم بدست بياد كه در چند پست قبل شرح داديم چرا 30 و 7 .
البته مي بينيد كه بعد 7 ، من حرف h كه به معني هگزائي(مبناي 16 ) است را نگذاشته ام چون مي دانيد كه زير 10 مبناي 10 و 16 يكي است.
من يك اشتباهي كردم بعد 4c حرف h را نگذاشتم كه خطا گرفت . چون در مبناي 10 ديگر 4c معنا نداره. كه با گذاشتن حرف h متوجه شد كه مبناي 16 است. يكبار هم حرف h را با فاصله گذاشتم كه فكر كنم باعث خطا ميشه. البته با كامپايلر من يعني tasm . من با masm قبلا كمي كار كردم ولي خيلي خطا مي گرفت كنار گذاشتمش.

ششم شرح چگونگي جدا كردن 7 و c از هم.
باز در پستهاي قبلي اين را به طور مشروح گفتيم ولي باز به طور خلاصه بگيم كه در part اول برنامه ، يعني قبل اولين احضار dl_print آمده ايم 4 بار به راست شيفت داده بوديم. در اين كتاب آمده بود در 4 را در cl گذاشته بود و بعد به اندازه cl شيفت داده بود. ولي من ضرورت اين كار را نفهميدم و حذفش كردم.
اين را هم بگم كه در محيط ديباگ من مجبور شدم 4 بار تك شيفت بدهم و در آنجا فكر كنم نميشه يكباره 4 تا را با هم شيفت داد.
كلا در اين قضيه كه تك تك شيفت بدهيم يا به يكباره فكر كنم بين كامپايلرهاي مختلف ، تفاوتهايي موجود است.
در part دوم يعني قبل احضار دوم dl_print با استفاده از دستور and آمده تكه بالايي را پوشانده و تكه با ارزش كمتر را با f كردن اجازه عبور داده. منظورم 0f است كه در خط 11 روي dl تاثير داده شده.
در هر دو part همان قضيه اضافه كردن 30 و 7 مشاهده ميشه.
البته من يك تغيير ديگر هم در برنامه دادم. دو دستور mov ah,02 و int 21h را كتاب در دو part ، تكرار كرده بود و من با استفاده از زير برنامه هر دو قسمت را خارج كردم و به جاش احضار dl_print را قرار دادم.

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

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
در ديباگ حرف r را بزنيد و اينتر كنيد. شكل زير حاصل ميشه:


e1.gif


اولا فرض ما اينه كه ديباگ فقط فايل com مي سازد و بحث ما در اين پست فقط راجع به فايل com است. بعدا راجع به فايل exe صحبت مي كنيم.

در شكل بالا مي بينيد كه ds و es و ss و cs با هم برابرند.
حالا اينها چي هستند؟
قبلا ما گفتيم كه در Ram مثل آدرس خيابان و كوچه ما آدرس مي دهيم. كه اولي شماره قطعه است و دومي شماره آفست.
وقتي اين 4 تا با هم برابرند، يعني همه اتفاقات در يك خيابان(قطعه) مي افتد.
پس در شكل بالا ، آنهايي كه بيضي آبي رنگ دورش كشيده ايم ، آدرس قطعه است و هر 4 تا با هم يكي است. پس در فايل com ، همه اتفاقات در يك قطعه اتفاق مي افتد.
وقتي خيابان ثابت باشه ، محدوده سير ما در محدوده كوچه هاي همان تك خيابان است. يعني آفست.
آفست ها را با رنگ قهوه اي من دورش بيضي كشده ام. يعني ip و sp و si و di .
و مي بيند كه دو تاي آنها را نشان داده ام كجاي خيابان(قطعه) سير مي كنند.
Ip از 100 شروع ميشه و مي رود بالا.
و sp از ته قطعه مي آيد به سمت پايين. منظور از پايين يعني sp عددش كم ميشه .

راجع به si و di كه با ds و es ميشه با هم كار كرد بعدا برنامه هاي جالبي مي نويسم.
پس si و di آدرس كوچه و ds و es خيابانش است.(براي خواندن و نوشتن Ram ازشان استفاده مي كنيم.)

در مورد cs:ip و ss:sp هم همين طور، يعني با هم كار مي كنند.

ولي در يك فايل com نيازي به ذكر اسم خيابان نيست. چون همه كارها در يك قطعه اتفاق مي افتد.
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
در اين پست مي خواهيم بگوييم كه مي توانيم كدهاي خود را در دو يا بيشتر فايل قرار دهيم. اين كار براي اين است كه محيط كار خلوت تري داشته باشيم.
برنامه اي كه dl را به شكل هگزا چاپ مي كرد را مي خواهيم در فايل ديگري قرار دهيم. همچنين آن زير برنامه كه قبلا ساختيم و دو خط mov ah,2 و int 21h را داشت كه dl را به شكل يك كااراكتر روي صفحه چاپ مي كرد را هم داخل اين فايل قرار مي دهيم.


همين جا خوب است بگوييم كه يك زيربرنامه خوب بايد بالاي برنامه كامنت گذاري مناسبي داشته باشد. چند چيز را بايد بنويسيم كه اينهاست:

اول : اين كه با چه رجيستري ورودي مي گيرد.
دوم : با چه رجيستري خروجي مي دهد.
سوم : اكشن آن زيربرنامه چيست.
چهارم : از چه زيربرنامه هايي استفاده مي كند. Uses

حالا من دو زير برنامه خودمان را آماده مي كنم:

کد:
.model small
.code

Public  bh_printer 
[color=green]; ========================== =
; vorodi : bh
; khoroji : no
; action : print bh in hexa
; uses : dl_print
; ========================== =[/color]
 [color=blue]bh_printer  proc[/color]
push dx
mov dl,bh       
shr dl,4        
add dl,30h      
cmp dl,3ah      
jl lable_1      
add dl,7        
lable_1:        
                call dl_print     
mov dl,bh       
and dl,0fh     
add dl,30h      
cmp dl,3ah      
jl lable_2      
add dl,7        
lable_2:        
                call dl_print     
pop dx
ret
[color=blue]bh_printer endp[/color]

Public  dl_print
[color=green]; ========================== =
; vorodi : dl
; khoroji : no
; action : print dl on screen
; uses : no
; ========================== =[/color]
[color=blue]dl_print proc[/color]
push ax
mov ah,2h
int 21h
pop ax
ret
[color=blue]dl_print endp[/color]
[color=red]end[/color]

اين فايل زير برنامه هاي ما خواهد شد. من با نام print.asm آن را ذخيره كردم.
نكات:
مي بينيد كه end بعدش چيزي نيامده، چون برنامه اصلي ندارد و فقط شامل زير برنامه است.
دستور stack هم ندارد. چون نيازي بهش ندارد.
كلمه public براي اين آمده كه از فايلهاي ديگر بتوان زيربرنامه ها را فراخواند.
همچنين به طرز معرفي در بالاي زيربرنامه ها توجه كنيد. بهتر است چند جمله شرح راجع به برنامه هم نوشته شود.
در زير برنامه ها مي بينيد كه رجيسترهايي كه نبايد تغيير كند و در زير برنامه استفاده شده را push و pop كرده ايم. .
اگر (( آ ايكس)) در زير برنامه ما محافظت نمي شد، آيا نتيجه چاپ آن سالم مي ماند؟ امتحان كنيد.
كلا ما اگر بخواهيم برنامه هاي بزرگ بنويسيم ، مجبوريم در فايلهاي متعدد بنويسيم و گرنه محيط برنامه خيلي شلوغ مي شود.

حالا فايل اصلي:

کد:
.model small
.stack
.code

[color=red]extrn bh_printer : proc[/color]

[color=blue]ax_printer proc[/color]
mov ax,1234h
mov bh,ah
call bh_printer
mov bh,al
call bh_printer

mov ah,4ch
int 21h
[color=blue]ax_printer endp[/color]

                             [color=red]end ax_printer[/color]

يك دستور extrn مخفف خارجي داريم. كه اعلام مي كند كه زيربرنامه اي استفاده شده كه در فايل ديگري است. فرق ديگري ندارد.
شرح برنامه اصلي: من مي خواهم ax را چاپ كنم. ابتدا ah و بعد al را در bh ريخته ام و زير برنامه چاپ bh را فراخوانده ام.

طرز كامپايل:
ابتدا دو فايل با پسوند asm را با tasm كامپايل(تبديل به obj) مي كنيم و بعد با link با دستور زير:

کد:
link ax_pri~1 print

yani:
link file1 file2

دو فايل obj را به فايل exe تبديل مي كنيم.
نتيجه اجرا: همان چاپ ax يعني 1234 است.
.

e2.gif

.
 

saalek

مدیر بازنشسته
تاریخ عضویت
24 می 2005
نوشته‌ها
654
لایک‌ها
53
محل سکونت
در پاي كوهپايه ها
اين هم يك جدول اسكي ، از كتابي كه آقا مهدي در تاپيك ((كتابهاي سي و ويژوال سي)) معرفي كرده بودند.
با تشكر فراوان از ايشان.
.

Write Great Code: Understanding the Machine, Volume I
چون عكس خيلي حجيم و بزرگ بود ، فقط لينكش را مي گذارم.
.
 
بالا