حتما با ثابتها در زبانهائي مثل پاسكال آشنائي داريد . بعنوان مثال با جمله ے 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 از قسمت تعريف داده ها پرش كرده ايم .
در اين قسمت يك تمرين جديد انجام داده و بوسيله آن تجربيات خودمان را افزايش ميدهيم . اين تمرين اولين برنامه ما هست يك عمليات سطح پائين سيستم ، يعني دسترسي به ديسك ، را انجام ميدهد . تابع شماره 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
عملگرهاي بيتي عملگرهاي بيتي مانند عملوندهاي حسابي هستند با اين تفاوت كه روي بيت ها كار ميكنند. اين عملگرها عبارتند از : ... 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 انتقال
در قسمت قبلي چند عملگر بيتي را ديديم . در اين قسمت هم اين مبحص را دنبال ميكنيم . عملگر 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
ضرب و تقسيم با 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 تمرين : همين عمل را براي تقسيم نيز با ديباگ انجام بدهيد .
برنامه نويسي صفحه كليد دريافت رشته كاراكتري نوشتن رويه اي كه با استفاده از توابع دريافت كاراكتر ، رشته اي كاراكتري را دريافت كند مشكل است . مخصوصا اگر بخواهيم بوسيله كليد BackSpace اشتباهات را هم جبران كنيم . خود Dos تابعي براي دريافت رشته كاراكتري دارد: تابع شماره 0Ah از وقفه 21h ورودي خروجي AH=0Ah كليد هاي تايپ شده در بافري كه با DSX Dsx طول بافر مشخص ميشود قرار ميگيرند. كليد هاي تايپ شده در صفحه نمايش ديده ميشوند . و ميتوان با كليد Ctrl-C به عمل ريافت رشته كاراكتري بطور غير نرمال پايان داد. براي دريافت رشته كاراكتري بوسيله اين تابع ، ابتدا AH را برابر 0Ah قرار ميدهيم بايتي كه DSX به آن اشاره ميكند ( اولين بايت بافر) برابر بيشترين كاراكتر مجاز است . مثلا اگر بخواهيم طول رشته كاراكتري از 100 حرف تجاوز نكند بايد اين بايت را با 100 پر كنيم . مانند اينكه در زبان پاسكال يك متغير را به شكل String[100] تعريف كنيم . بايت دوم بعد از اينكه عمل دريافت رشته را با Enter پايان داديم پر ميشود. به اين صورت كه تعداد كاراكتر هاي تايپ شده در آن بايت قرار ميگيرند. مثلا اگر كلمه تايپ شده ALI باشد ، بايتي كه در DSX+1 قرار دارد برابر 3 ميشود . هنگام دريافت رشته ، ميتوان با كليد BackSpace كاراكترهاي قبلي را پاك كرد . كاراكترهاي تايپ شده از اينجا در بافر قرار ميگيرند DSX | | |1|2|3| .................................... | | | | | | | DSX به اين بايت اشاره ميكند و(حداكثر طول باف ) | تعداد كاراكترهائي كه كاربر تايپ كرده مثال : برنامه زير يك بافر 100 حرفي بنام BUF تعريف كرده و با استفاده از اين تابع ، يك رشته كاراكتري را دريافت ميكند تمرين : به همين برنامه قسمتي اضافه كنيد كه رشته كاراكتري دريافت شده را چاپ كند راهنمائي : بعد از دريافت رشته كاراكتري بايد به انتهاي آن يك كاراكتر $ اضافه كنيد تا قابل چاپ توسط تابع 9 از وقفه 21h بشود . همچنين آفست شروع رشته كه در DSX قرار دارد را به DSX+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