آموزش اسمبلی از پایه تا پیشرفته - صفحه 2 - تالار گفتمان آذر فروم





دعوت به همکاری با آذر فروم

 

آموزش اسمبلی از پایه تا پیشرفته
زمان کنونی: 18-09-1395،07:36 ق.ظ
کاربران در حال بازدید این موضوع: 1 مهمان
نویسنده: Friga
آخرین ارسال: Friga
پاسخ: 17
بازدید: 887

 
 
رتبه موضوع:
  • 0 رای - 0 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5

موضوع: آموزش اسمبلی از پایه تا پیشرفته
ارسال: #11
RE: آموزش اسمبلی از پایه تا پیشرفته
پست‌ها: 11,943
تاریخ عضویت: 20 اردیبهشت 1390
اعتبار: 288
حالت من: Shad
در اين قسمت يك تمرين ديگر با هم انجام ميدهيم و برنامه اي مينويسيم كه تعداد 200
رنگ از 256 رنگ موجود در حالت 320x200 گرافيكي را نمايش دهد .
تابع شماره 00h از وقفه 10h مربوط به تعيين حالت نمايش است . كد مربوط به
حالت صفحه نمايش در ثبات AL قرار گرفته و وقفه فراخواني ميشود:

شماره تابع برابر AH=00h
حالت صفحه نمايش با استفاده از جدول AL= INT 10h




حالت صفحه نمايش در AL از جدول مخصوص موجود در كتابهاي اسمبلي بدست مي آيد.
كد مربوط به حالت 256C َ320x200 برابر 13h است بنا براين AL را برابر 13h قرار
ميدهيم .
براي نمايش و روشن كردن يك نقطه (Pixel) در حالت گرافيكي از تابع 0Ch همين
وقفه استفاده ميكنيم . يعني شماره ستون را در CX ، سماره سطر را در DX و شماره
رنگ را در AL قرار داده و وقفه را اجرا ميكنيم . براي اينكه از ستون 199 تا ستون
شماره صفر نقطه روشن كنيم ، CX را برابر 319 قرار داده و با دستور LOOP نقاط را
در يك سطر روشن ميكنيم .


MOV CX/319 ; COLUMN 319 = START COLUMN
COL:
INT 10H ; CALL INTERRUPT 10H
LOOP COL
سپس DX يا همان شماره سطر را يكواحد افزايش ميدهيم و مقدار آن را با 199 مقايسه
ميكنيم (چون از 0 تا 199 سطر داريم ) و اگر برابر نبود دوباره عمليات بالا را
انجام ميدهيم .

بعد از اينكه اين عمليات انجام شد، تابع 00h از INT 16h را فراخواني ميكنيم تا
منتظر دريافت يك كليد از صفحه كليد شود . به اين ترتيب ميتوانيم نتيجه برنامه
را مشاهده كنيم و كليدي را براي اتمام برنامه بزنيم .
در نهايت بايد حالت صفحه نمايش را به مود متني برگردانيم .
براي اينكار از همان تابع تعيين مود نمايشي استفاده ميكنيم و حالت صفحه نمايش
كه با AL مشخص ميشود را برابر 3 قرار ميدهيم .
برنامه را با روش گفته شده تايپ و كامپايل كنيد . اگر از توربو اسمبلر استفاده
ميكنيد با فرمان ASM/T.َTASM VGA256 آن را به فرم COM. ترجمه كنيد.


. MODEL SMALL
. CODE
ORG 100H
START :
MOV AH/00H
MOV AL/13H
MOV BX/00H ; PAGE NUMBER
INT 10H ; SET TO 320x200 256 COLORS

MOV AH/0CH ; PUTPIXEL FUNCTION
MOV AL/25 ; COLOR #25
MOV DX/0 ; ROW 0
ROW :
MOV CX/319 ; COLUMN 319 = START COLUMN
COL :
INT 10H ; CALL INTERRUPT 10H
LOOP COL ; DOWN TO CX=0
INC DX ; DX=DX+1
INC AL ; AL=AL+1( COLOR NUMBER )
CMP DX/199 ; IF DX=199
JNZ ROW ; ELSE JUMP TO ROW

MOV AH/00H
INT 16H

MOV AH/00H ; VIDEO MODE SET
MOV AL/03H ; 80x25 16 COLORS
INT 10H ; CALL INT .10H
INT 20H ; TERMINATE PROGRAM
END START

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
















دورمچم به جای ساعت یکنوار مشکی بستم
تا همه بفهمن من از همه هر چه زمانو متعلق به زمان است بیزارم
من هم روزی قلبی داشتم
که توسط مردمانی ازمیان شما شکست و شکست تا سنگی شد
واکنون روزگاریست که شیطان فریاد میزند..
انسان پیدا کنید سجده خواهم کرد...


=====ஜ۩۞۩ஜ=====

18-05-1391 12:28 ق.ظ
 
ارسال: #12
RE: آموزش اسمبلی از پایه تا پیشرفته
پست‌ها: 11,943
تاریخ عضویت: 20 اردیبهشت 1390
اعتبار: 288
حالت من: Shad
حتما با ثابتها در زبانهائي مثل پاسكال آشنائي داريد . بعنوان مثال با جمله
ے Const MaxLen=1024; ، ثابتي بنام MaxLen تعريف شده و مقدار آن برابر 1024 قرار
ے قرار ميگيرد . پس از آن كامپايلر در هرجا كه MaxLen را مشاهده كند عدد 1024 را
بجاي آن قرار ميدهد .
در زبان اسمبلي براي تعريف يك ثابت از معرفه EQU به شكل زير استفاده ميكنيم

مقدار EQU نام ثابت
مثلا : MaxLen EQU 1024
ے به اين ترتيب اسمبلر هميشه بجاي MaxLen عدد 1024 را قرار ميدهد . بهمين دليل
ثابتهاي برنامه را بايد قبل از جمله CODE. بنويسيم . مثال :


. MODEL SMALL
SECTORS EQU 18
SIDES EQU 2
. CODE
:
:


ے به اين خاطر ثابتها را قبل از CODE. تعريف ميكنيم كه در برنامه كامپايل شده اثري
از نام ثابت نبوده بلكه مقدار هر ثابت در جاي لازم قرار گرفته است .
مثال :

. MODEL SMALL
BELL EQU 7
. CODE
ORG 100H
MOV AH/0EH
MOV AL/BELL
INT 10H
INT 20H
END



متغيرها

ے از متغيرها براي نگهداري موقتي داده ها استفاده ميكنيم . مثلا در زبان پاسكال
ے ميتوانيم با عبارت Var يك متغير تعريف كنيم مثل Var Buffer:Byte; و در زبان
سي مثل unsigned char Buffer; .
ے متغيرها در زبان اسمبلي بايد حتما در داخل قطعه داده (DS) تعريف بشوند و در
ے برنامه هاي COM. هم از آنجائي كه قطعه داده ها و كد يكي است ميتوانيم در قطعه كد
نيز تعريف كنيم .
ے براي تعريف يك متغير بايد بعد از نام آن يكي از عبارات ..DB/DW/DD/ را
ے بياوريم . DB مشخصه نوع بايت ،DW مشخصه نوع Word (دوبايتي ) و DD مشخصه نوع
(Double Word) 4 بايتي است .
مثلا :

. CODE
SIZE DW 1024
BELL DB 7


ے در اين مثال Size يك متغير دو بايتي بوده و مقدار اوليه ان 1024 است و BELL نيز
يك متغير تك بايتي با مقدار 7 ميباشد .
ے اگر نميخواهيم به متغير مقدار اوليه بدهيم ، ميتوانيم از علامت (?) بجاي مقدار
استفاده كنيم مانند : MaxLen DW ?

ے براي تعريف يك رشته كاراكتري از معرفه DB استفاده كرده و محتواي رشته را داخل
('') يا ("") قرار ميدهيم . مثلا :

MSG DB "ASSEMBLY / A QUICK LOOK ! "


ے در اين مثال MSG يك متغير كاراكتري است . در اسمبلي ميتوانيم از كد اسكي
ے كاراكتر ها نيز استفاده كنيم . مثلا اگر در تعريف DB بخواهيم كدهاي اسكي 13و 10
را به MSG اضافه كنيم ميتوانيم با كاما اين كار را انجام دهيم :


MSG DB "ASSEMBLY / A QUICK LOOK ! "/13/10


يا : MSG DB "ASSEMBLY / A QUICK LOOK ! "/0Ah/0Dh

يا حتي : MSG DB "ASSEMBLY / A QUICK LOOK ! "/0Ah/0Dh/'$'


اين تركيبها همه يك رشته كاراكتري معرفي ميكنند .

براي تعريف آرايه ها نيز از روشي مشابه و به شكل زير استفاده ميكنيم :

(مقدار اوليه )DUP تعداد عناصر DB/DW/DD نام متغير
مانند: BUFFER DB 1024 DUP(0 )

كه ارايه اي يك كيلوبايتي تعريف كرده و همه عناصر آن را با 0 پر ميكند.
اگر نخواهيم مقدار اوليه اي در نظر گرفته شود از ? استفاده ميكنيم .
مانند: BUFFER DB 1024 DUP(? )

و براي تعريف يك آرايه حرفي بايد با يك حرف يا عبارت آن را پر كنيم : BUFFER DB 1024 DUP("A" )

و حتي : BUFFER DB 1024 DUP("STACK" )


ے گفتيم كه متغيرها هميشه (در برنامه هاي COM.) در قطعه كد و بعد از CODE. نوشته
ے ميشوند ، بنا براين اسمبلر هميشه سعي خواهد كرد كه آنها را بصورت يك كدماشين
ے قابل اجرا تفسير كند. به همين دليل هميشه بايك دستور JMP از روي آنها پرش
ميكنيم . مثال :


. MODEL SMALL
RDISK EQU 2
. CODE
ORG1 100H
START :
JMP MAIN
BUFFER DB 512 DUP(0 )
MSG DB "DISK DUP."/13/10/'$'
MAIN :


مجموعه كدهاي اجرايي برنامه :
: END START

همانطور كه ميبينيد با دستور JMP MAIN از قسمت تعريف داده ها پرش كرده ايم .
















دورمچم به جای ساعت یکنوار مشکی بستم
تا همه بفهمن من از همه هر چه زمانو متعلق به زمان است بیزارم
من هم روزی قلبی داشتم
که توسط مردمانی ازمیان شما شکست و شکست تا سنگی شد
واکنون روزگاریست که شیطان فریاد میزند..
انسان پیدا کنید سجده خواهم کرد...


=====ஜ۩۞۩ஜ=====

18-05-1391 12:28 ق.ظ
 
ارسال: #13
RE: آموزش اسمبلی از پایه تا پیشرفته
پست‌ها: 11,943
تاریخ عضویت: 20 اردیبهشت 1390
اعتبار: 288
حالت من: Shad
در اين قسمت يك تمرين جديد انجام داده و بوسيله آن تجربيات خودمان را افزايش
ميدهيم . اين تمرين اولين برنامه ما هست يك عمليات سطح پائين سيستم ، يعني
دسترسي به ديسك ، را انجام ميدهد .

تابع شماره 2(AH=2() از وقفه 13h كه وقفه ديسك ميباشد ، براي خواندن سكتورهاي
ديسك بكار ميرود . وقتي شماره هد، شيار،سكتور و ... را مشخص كرده و وقفه را
فراخواني نموديم ، محتواي قطاع خوانده شده در محلي كه با جفت ثبات ES:BX مشخص
ميشود قرار ميگيرد. به همين دليل ما يك آرايه تعريف ميكنيم وآدرس آن را در ES:BX
قرار ميدهيم تا اطلاعات خوانده شده در آن قرار بگيرد. BUF DB 512 DUP(0)

در اين مثال ما ميخواهيم برنامه اي بنويسيم كه محتواي قطاع بوت كننده ديسكي را
خوانده و نمايش دهد . چون ميخواهيم يك سكتور را بخوانيم و اندزه هر قطاع 512
بايت است ، پس آرايه اي با 512 عنصر تك بايتي تعريف كرده ايم .
در قدم بعدي شماره شيار (0-79) را در CH، شماره قطاع (1-18) را در CL، شماره
درايو را در DL(.../.:0=A ) ، رويه ديسك را در DH(0=1st Side() و تعداد قطاعهائي
كه بايد خوانده شوند را در AL قرار ميدهيم .

MOV AX/0201H
MOV CH/0 ;TRACK NUMBER
MOV CL/1 ;SECTOR NUMBER
MOV DH/0 ; SIDE #1
MOV DL/0 ; 0=A / 1=B /( ...DRIVE NUMBER )



حالا بايد آدرس بافر تعريف شده (BUF) را به ES:BX منتقل كنيم . گفتيم كه براي
بدست آوردن شماره سگمنت هر متغير از Seg و براي بدست آوردن مقدار آفست از Offset
استفاده ميكنيم . چون برنامه ما COM. است ، پس عدد سگمنت بطور خودكار در
ثبات DS هست و احتياجي به يافتن آن نداريم . بلكه فقط بايد آن را به ES منتقل
كنيم .
گفتيم كه نميتوانيم ثبات ESو DSو را مستقيما و با MOV به هم منتقل كنيم ، بلكه
بايد از يك ثبات همه منظوره مثل AX كمك بگيريم . بنا براين و براي اينكه مقدار
فعلي ثبات AX از بين نرود، ابتدا AX را در Stack قرار داده و مقدار DS را در آن
قرار ميدهيم : PUSH AX ; SAVE AX
MOV AX/DS

و پس از آن محتواي AX را به ES داده و دوباره مقدار AX را از پشته POP ميكنيم : MOV ES/AX
POP AX

پس از آن با دستور LEA مقدار آفست BUF را بدست مي آوريم : LEA BX/BUF

و در نهايت فراخواني اينتراپت 13h. INT 13H


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


MOV AL/BUF[BX]
CMP AL/32
JB SKIP
:
:
SKIP :
MOV AL/'.'
INT 10H
:
:


ليست كامل :

.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
BUF DB 512 DUP(0)
MAIN:
MOV AX/0201H
MOV CH/0 ;TRACK NUMBER
MOV CL/1 ;SECTOR NUMBER
MOV DH/0 ; SIDE #1
MOV DL/0 ; 0=A / 1=B /( ...DRIVE NUMBER)
PUSH AX ; SAVE AX
MOV AX/DS
MOV ES/AX
POP AX
LEA BX/BUF
INT 13H

MOV BX/1
MOV AH/0EH ; WRITE CHAR.
PRINT:
MOV AL/BUF[BX]
CMP AL/32
JB SKIP
INT 10H
JMP CONT
SKIP:
MOV AL/'.'
INT 10H
CONT:
INC BX
CMP BX/513
JNZ PRINT
INT 20H
END START
















دورمچم به جای ساعت یکنوار مشکی بستم
تا همه بفهمن من از همه هر چه زمانو متعلق به زمان است بیزارم
من هم روزی قلبی داشتم
که توسط مردمانی ازمیان شما شکست و شکست تا سنگی شد
واکنون روزگاریست که شیطان فریاد میزند..
انسان پیدا کنید سجده خواهم کرد...


=====ஜ۩۞۩ஜ=====

18-05-1391 12:28 ق.ظ
 
ارسال: #14
RE: آموزش اسمبلی از پایه تا پیشرفته
پست‌ها: 11,943
تاریخ عضویت: 20 اردیبهشت 1390
اعتبار: 288
حالت من: Shad
عملگرهاي بيتي

عملگرهاي بيتي مانند عملوندهاي حسابي هستند با اين تفاوت كه روي بيت ها كار
ميكنند. اين عملگرها عبارتند از : ... AND/OR/XOR/SHR/SHL/RCL/RCR/ .

عملگر AND : اين اپراتور بيتهاي دو عدد(متغير) را با هم AND كرده و حاصل را در
متغير (يا ثبات ) سمت چپ قرار ميدهد . اگر فرض كنيم كه هميشه 1 بودن بيت به
معناي Trueو 0و بودن آن به معناي False است ، AND هميشه در صورتيكه هر دوبيت
مقايسه شونده 1 باشند، حاصل 1يا Trueا را بر ميگرداند .
جدول ارزشي AND :
X | Y | X and Y |

1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |


پس وقتي ما عملوند AND را با دو رجيستر بكار ميبريم ، بصورتي كه گفته شد بيتها
با هم مقايسه شده و حاصل مقايسه در محل متناظر بيتها در ثبات سمت چپ قرار
ميگيرند . مثلا اگر دستور AND Ah/Dh را اجرا كنيم ، حالتي نظير شكل زير را داريم :
AH : 01101010
DH : 01111101

AH :AH AND DH : 01101000


به نتيجه بدست آمده توجه كنيد .
هر وقت كه بخواهيم بيت هاي خاصي از يك رجيستر را 0 كنيم ، يك عدد باينري كه
همه بيتهاي آن ، بجز بيتهاي مورد نظر 1 هستند را در نظر گرفته با رجيستر مورد نظرAND
ميكنيم .مثلا اگر بخواهيم بيتهاي دوم و سوم ثبات AX را صفر كنيم : AND AX/11111001b

عملگر OR :
اين عملوند بيتهاي دو عدد را با هم مقايسه كرده و اگر يكي از آن دو 1 بود ، بيت
متناظر در ثبات سمت چپ را 1 ميكند . مثلا با دستور OR AH/DH بيتهاي AHبا DHا
مقايسه شده و هر دو بيت متناظر كه با هم 0 بودند ، بيت تناظر در AHهم 0 ميشود
AH : 01101010
DH : 01111100

AH : AH OR DH : 01111110


هرگاه كه بخواهيم بيت هاي خاصي از يك متغير يا رجيستر را 1 كنيم ، يك عدد
باينري كه همه بيتهاي آن غير از بيتهاي مورد نظر 0 هستند در نظر گرفته و با ثبات
مورد نظر OR ميكنيم . مثلا اگر بخواهيم دو بيت پائين AHرا 1ا كنيم منويسيم : OR AH/00000011b


عملگر : XOR
عملوند XOR تنها در صورتي نتيجه 1 ميدهد كه دو بيت مقايسه شونده غيرهم ارزش
باشند . يعني يكي 1 و ديگري 0 باشد .
بعنوان مثال با اجراي XOR AH/DH اين عمليات روي بيتها انجام ميشود
AH : 01101010
DH : 01111100

AH : AH XOR DH : 11101001


وقتي بخواهيم يك مقدار ثبات را برابر صفر قرار بدهيم ، معمولا از آن را با خودش XOR
ميكنيم . مثلا XOR CX/CX محتواي ثبات CX را برابر 0 قرار ميدهد .

عملگرهاي SHRو SHLو :

اين عملگرها، بيتها را به راست و چپ شيفت ( انتقال ) ميدهند .
SHR Reg.nnum و SHL Reg.nnum
.Reg اسم يك ثبات است مثلا AXو numو معلوم ميكند كه چند بيت بايد به طرف
راست يا چپ انتقال پيدا كند . مثلا SHR AX/6 بيتهاي AXرا 6ا واحد به راست
انتقال داده و بيتهاي چپ را با 0 پر ميكند . AX :10100010
AX :SHR AX/4 : 00001010

SHL
هم عكس اين عمل را انجام ميدهد . يعني بيتها را به چپ شيفت داده و از
طرف راست با 0 پر ميكند . AX :10100010
AX :SHR AX/4 : 00100000

مثال : اگر بخواهيم كه محتواي نيم ثبات CL را به نيم ثبات CH منتقل كنيم ،
كافيت كه CXرا 8ا بيت به سمت چپ شيفت بدهيم . يعني SHL CX/8

CL CH | 10110100 | 00101101 |


محتواي اوليه CX CX

CL CH | 00101101 | 00000000 |


محتواي CX بعد از SHL CX/8
انتقال
















دورمچم به جای ساعت یکنوار مشکی بستم
تا همه بفهمن من از همه هر چه زمانو متعلق به زمان است بیزارم
من هم روزی قلبی داشتم
که توسط مردمانی ازمیان شما شکست و شکست تا سنگی شد
واکنون روزگاریست که شیطان فریاد میزند..
انسان پیدا کنید سجده خواهم کرد...


=====ஜ۩۞۩ஜ=====

18-05-1391 12:29 ق.ظ
 
ارسال: #15
RE: آموزش اسمبلی از پایه تا پیشرفته
پست‌ها: 11,943
تاریخ عضویت: 20 اردیبهشت 1390
اعتبار: 288
حالت من: Shad
در قسمت قبلي چند عملگر بيتي را ديديم . در اين قسمت هم اين مبحص را دنبال
ميكنيم .
عملگر Not : عملوند Not ارزش همه بيتهاي يك بايت يا كلمه را برعكس ميكند .
يعني تمام بيتهاي 1را 0ا و تمام بيتهاي 0را 1ا ميكند . بعنوان مثال اگر AH حاوي
مقدار 10101101 باشد، بعد از اجراي Not Al ، محتواي AL بصورت 01010010 خواهد
بود.

جدول ارزشي Not Not X X N
F | T
T | F



عملگر Neg . اين اپراتور معمولا با Not اشتباه ميشود در صورتي كه كمتر شباهتي بين
آنها وجود دارد . Neg ارزش عددي يك عدد علامتدار را برعكس ميكند . يعني يك عدد
منفي را مثبت ميكند و برعكس . در اعداد علامتدار ( همانطور كه بعدا هم خواهيم
ديد )، اولين بيت سمت چپ ( بيت هشتم ) بيت علامت است . 1 بودن آن نشاندهنده
منفي بودن و 0 بودن آن نشان دهنده مثبت بودن است .
عملگر Neg با عكس كردن بيت علامت ، ارزش عدد را عكس ميكند .
اين عملوند را در مبحث اعداد علامتدار مفصلا ميخوانيم .
مثال : ميخواهيم برنامه اي بنويسيم كه تمام حروف كوچك يك عبارت را به حروف
بزرگ تبديل كند . از نظر مقدار عددي ، تفاوت حروف كوچك و بزرگ در اينست كه
بيت پنجم در حروف بزرگ برابر 0 و در حروف كوچك 1 است . مثلا كداسكي حرف a
به باينري برابر 01100001 و كد A برابر 01000001 است . پس برنامه اي مينويسيم
كه تمام كاراكترهاي رشته كاراكتري مورد نظر را خوانده و بيت پنچم آنها را 0 كند
. در قسمت قبلي ديديم كه براي 0 كردن يك بيت ، يك عدد باينري كه تمام بيتهاي
آن 1 ، و بيت مورد نظر (براي 0 كردن ) 0 باشد را با عدد مورد نظر AND ميكنيم .


. MODEL SMALL
. CODE
ORG 100H
START :
JMP MAIN
MSG DB ' this is an example/ ..$'
MAIN :


بدست آوردن آدرس رشته ; LEA BX/MSG LOOP :_

قرار دادن كاركتر در AL ; MOV AL/[BX]
آيا كاراكتر $ است ? ; CMP AL/'$'
بله ، به MAIN برو ; _JZ END
بيت پنجم را صفر كن ; AND [BX]/11011111B
يكواحد به BX اضافه كن - كاراكتر بعدي ; INC BX JMP LOOP _;
END :_

قرار دادن آفست رشته در DX ; MOV DX/BX
تابع 9 براي نمايش رشته ; MOV AH/9
قفه 21h ; INT 21H
پايان برنامه ; INT 20H END START


معمولا برنامه هائي كه پيغامهاي خود را كد ميكنند ( مثل ويروسها ) از اين روش يا
روشي مشابه براي Decode كردن پيغامها استفاده ميكنند .

مثال :
بايت وضعيت صفحه كليد كه مربوط به وضعيت كليد هاي كنترلي CapsLock/NumLock
در بايوس هاي AT/PS2 در آدرس 0017h:0040h قرار دارد.
بيتهاي اين بايت نشان ميدهد كه كدام كليد فعال است . 1 بودن به معني روشن بودن
و 0 به معني خاموش بودن آن است . در مثال زير بيت ششم براي كليد CapsLockرا 1ا
ميكنيم تا Capslock روشن شود .


.MODEL SMALL
.CODE
ORG 100h
START:
PUSH ES
MOV AX/0040h
MOV ES/AX
MOV AL/ES:[17h]
OR AL/32
MOV BYTE PTR ES:[17h]/AL
POP ES
MOV AH/1
INT
















دورمچم به جای ساعت یکنوار مشکی بستم
تا همه بفهمن من از همه هر چه زمانو متعلق به زمان است بیزارم
من هم روزی قلبی داشتم
که توسط مردمانی ازمیان شما شکست و شکست تا سنگی شد
واکنون روزگاریست که شیطان فریاد میزند..
انسان پیدا کنید سجده خواهم کرد...


=====ஜ۩۞۩ஜ=====

18-05-1391 12:29 ق.ظ
 
ارسال: #16
RE: آموزش اسمبلی از پایه تا پیشرفته
پست‌ها: 11,943
تاریخ عضویت: 20 اردیبهشت 1390
اعتبار: 288
حالت من: Shad
ضرب و تقسيم با 8088
8088
براي ضرب دو عدد از دستورالعمل MUL با كد ماشين F7h استفاده ميكند .
اين دستورالعمل روي كلمه ها ( دوبايتي ها) كار ميكند . بنا براين حاصلضرب دو عدد16
بيتي ميتواند 32 بيتي يا 2 كلمه اي باشد . به همين دليل براي ذخيره نتيجه ضرب
يك ثبات تنها كافي نيست . MUL
هميشه محتواي يك ثبات را در محتواي ثبات AX ضرب كرده و حاصلضرب را در
جفت ثبات DX:AX ذخيره ميكند . به اينصورت كه دوبايت بالا را در DX و كلمه
پائين را در AX قرار ميدهد. وقتي از حساب 8088 صحبت ميكنيم ، نوشتن DX:AX به
معني نگهداري عدد 32 بيتي در آن جفت ثبات است نه محلي از حافظه كه با DX:AX
مشخص ميشود.
براي ضرب محتواي يك رجيستر در AX ( هميشه در AX ضرب ميشود) از MUL بصورت زير
استفاده ميكنيم : MUL Register


كه منظور از رجيستر يك ثبات مانند DXيا BXا است .
چون هميشه محتواي رجيستر مورد نظر در AX ضرب ميشود، نيازي به نوشتن AX نداريم .

بعنوان مثال اگر AX برابر 100hو BXو برابر 7C4Bh باشد ، حاصل MUL BX برابر 7C4B00h
ميشود و چون اين مقدار يك عدد 32 بيتي است ، در جفت ثبات DX:AX
نگهداري ميشود به شكلي كه DX=7C4Bhو AXو برابر 0000h باشد.

عمل تقسيم هم به شيوه مشابهي انجام ميشود.
وقتي كه دوعدد را به هم تقسيم ميكنيم حاصل تقسيم ( قسمت صحيح يا خارج قسمت ) در AX
و باقيمانده در DX قرار ميگيرد.

براي تقسيم كردن دو ثبات به هم ، از دستور DIV استفاده ميكنيم . وقتي از DIV براي
تقسيم استفاده ميكنيم ، CPU محتواي جفت ثبات DX:AX را بر محتواي ثبات ذكر
شده تقسيم ميكند بنا براين در هنگام استفاده از DIV فقط نام همان ثبات را ذكر
ميكنيم . مثلا اگر بخواهيم ( برعكس ضربي كه در بالا انجام داديم ) عدد 7CB400h را
بر 100h تقسيم كنيم ، BX را برابر 100h و جفت ثبات Dx:Ax را برابر 7CB4100h
قرار ميدهيم . براي اينكار عدد 7CB4100h را به دو نيمه 007Ch و 4100h تقسيم كرده
و در DXو AXو قرار ميدهيم . (/ DX:007Ch AX=4100h) . در نهايت با DIV BX عمل
تقسيم را انجام ميدهيم .
بعد از انجام تقسيم 7C4Bhدر AXر و 0000hدر DXر قرار ميگيرد.

مثال براي ضرب

براي ديدن مطالب گفته شده ، همان دو عدد 100hو 4CBhو را با ديباگ در هم ضرب
ميكنيم .
بنا براين Debug را اجرا كرده و سطرهاي زير را وارد ميكنيم .


17AA:0100 mov ax/100
17AA:0103 mov bx/4cb
17AA:0106 mul bx
17AA:0108 int 20
17AA:010A
- t


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

در اين سطر محتواي AX برابر 0100 است


AX=0100 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=17AA ES=17AA SS=17AA CS=17AA IP=0103 NV UP EI PL NZ NA PO NC
17AA:0103 BBCB04 MOV BX/04CB
- t


محتواي BX برابر 0$CB شده ...

AX=0100 BX=04CB CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=17AA ES=17AA SS=17AA CS=17AA IP=0106 NV UP EI PL NZ NA PO NC
17AA:0106 F7E3 MUL BX
- t


بعد از انجام ضرب ، محتواي DX برابر 4 و محتواي AX برابر CB00 شد ه . بنابراين
جفت ثبات DX:AX مقدار 4CB00 را نشان ميدهد . يعني همان عددي كه قبلا هم بدست
آورده بوديم .


AX=CB00 BX=04CB CX=0000 DX=0004 SP=FFEE BP=0000 SI=0000 DI=0000
DS=17AA ES=17AA SS=17AA CS=17AA IP=0108 OV UP EI PL NZ NA PO CY
17AA:0108 CD20 INT 20
- t
- q



تمرين :

همين عمل را براي تقسيم نيز با ديباگ انجام بدهيد .
















دورمچم به جای ساعت یکنوار مشکی بستم
تا همه بفهمن من از همه هر چه زمانو متعلق به زمان است بیزارم
من هم روزی قلبی داشتم
که توسط مردمانی ازمیان شما شکست و شکست تا سنگی شد
واکنون روزگاریست که شیطان فریاد میزند..
انسان پیدا کنید سجده خواهم کرد...


=====ஜ۩۞۩ஜ=====

18-05-1391 12:29 ق.ظ
 
ارسال: #17
RE: آموزش اسمبلی از پایه تا پیشرفته
پست‌ها: 11,943
تاریخ عضویت: 20 اردیبهشت 1390
اعتبار: 288
حالت من: Shad
برنامه نويسي صفحه كليد
دريافت رشته كاراكتري

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

خود Dos تابعي براي دريافت رشته كاراكتري دارد: تابع شماره 0Ah از وقفه 21h

ورودي خروجي
AH=0Ah
كليد هاي تايپ شده در بافري كه با DS:DX Ds:Dx
طول بافر مشخص ميشود قرار ميگيرند.

كليد هاي تايپ شده در صفحه نمايش ديده ميشوند . و ميتوان با كليد Ctrl-C به عمل
ريافت رشته كاراكتري بطور غير نرمال پايان داد.

براي دريافت رشته كاراكتري بوسيله اين تابع ، ابتدا AH را برابر 0Ah قرار ميدهيم
بايتي كه DS:DX به آن اشاره ميكند ( اولين بايت بافر) برابر بيشترين كاراكتر
مجاز است . مثلا اگر بخواهيم طول رشته كاراكتري از 100 حرف تجاوز نكند بايد
اين بايت را با 100 پر كنيم . مانند اينكه در زبان پاسكال يك متغير را به شكل String[100]
تعريف كنيم .
بايت دوم بعد از اينكه عمل دريافت رشته را با Enter پايان داديم پر ميشود.
به اين صورت كه تعداد كاراكتر هاي تايپ شده در آن بايت قرار ميگيرند.
مثلا اگر كلمه تايپ شده ALI باشد ، بايتي كه در DS:DX+1 قرار دارد برابر 3
ميشود . هنگام دريافت رشته ، ميتوان با كليد BackSpace كاراكترهاي قبلي را پاك
كرد .

كاراكترهاي تايپ شده از اينجا در بافر قرار ميگيرند DS:DX | |

|1|2|3| .................................... | | | | |

| |
DS:DX
به اين بايت اشاره ميكند و(حداكثر طول باف ) |

تعداد كاراكترهائي كه كاربر تايپ كرده

مثال :
برنامه زير يك بافر 100 حرفي بنام BUF تعريف كرده و با استفاده از اين
تابع ، يك رشته كاراكتري را دريافت ميكند
تمرين :
به همين برنامه قسمتي اضافه كنيد كه رشته كاراكتري دريافت شده را چاپ
كند
راهنمائي :
بعد از دريافت رشته كاراكتري بايد به انتهاي آن يك كاراكتر $ اضافه
كنيد تا قابل چاپ توسط تابع 9 از وقفه 21h بشود . همچنين آفست شروع رشته كه در DS:DX
قرار دارد را به DS:DX+2 تبديل كنيد تا بايتهاي اول و دوم كه مربوط به طول
شته و تعداد كاراكتر ها هستند چاپ نشوند.

.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
BUF DB 101 DUP(0)/'$'

MAIN:
LEA DX/BUF
MOV BX/DX
MOV AL/100
MOV [BX]/AL
MOV A
















دورمچم به جای ساعت یکنوار مشکی بستم
تا همه بفهمن من از همه هر چه زمانو متعلق به زمان است بیزارم
من هم روزی قلبی داشتم
که توسط مردمانی ازمیان شما شکست و شکست تا سنگی شد
واکنون روزگاریست که شیطان فریاد میزند..
انسان پیدا کنید سجده خواهم کرد...


=====ஜ۩۞۩ஜ=====

18-05-1391 12:30 ق.ظ
 


[-]
پاسخ سریع
پیام
پاسخ خود را برای این پیام در اینجا بنویسید.


کد تصویری
royalfuns
(غیر حساس به بزرگی و کوچکی حروف)
لطفاً کد نشان داده شده در تصویر را وارد نمایید. این اقدام جهت جلوگیری از ارسال‌های خودکار ضروری می‌باشد.

موضوعات مشابه ...
موضوع: نویسنده پاسخ: بازدید: آخرین ارسال
  دانلود فیلم آموزشی زبان اسمبلی Friga 0 279 18-05-1391 12:23 ق.ظ
آخرین ارسال: Friga
  اسمبلی movs Friga 0 232 18-05-1391 12:17 ق.ظ
آخرین ارسال: Friga
  آموزش زبان برنامه نويسي Assembly Friga 0 227 21-04-1391 01:03 ق.ظ
آخرین ارسال: Friga
  برنامه هایی با اسمبلی Friga 1 355 21-04-1391 12:54 ق.ظ
آخرین ارسال: Friga

پرش به انجمن:


کاربران در حال بازدید این موضوع: 1 مهمان